intel_extreme: Set mode and pll via pipe-aware class functions

This commit is contained in:
Alexander von Gluck IV
2015-11-08 23:14:46 -06:00
parent 72cecf8765
commit 61fbdb0667
6 changed files with 227 additions and 245 deletions
@@ -445,7 +445,6 @@ struct intel_free_graphics_memory {
#define LVDS_PORT_EN (1 << 31)
#define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
#define LVDS_B0B3PAIRS_POWER_UP (3 << 2)
#define LVDS_PLL_MODE_LVDS (2 << 26)
#define LVDS_18BIT_DITHER (1 << 25)
// PLL flags
@@ -454,6 +453,7 @@ struct intel_free_graphics_memory {
#define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29)
#define DISPLAY_PLL_NO_VGA_CONTROL (1UL << 28)
#define DISPLAY_PLL_MODE_ANALOG (1UL << 26)
#define DISPLAY_PLL_MODE_LVDS (2UL << 26)
#define DISPLAY_PLL_DIVIDE_HIGH (1UL << 24)
#define DISPLAY_PLL_DIVIDE_4X (1UL << 23)
#define DISPLAY_PLL_POST1_DIVIDE_2 (1UL << 21)
@@ -474,18 +474,21 @@ struct intel_free_graphics_memory {
#define DISPLAY_PLL_PULSE_PHASE_SHIFT 9
// display
#define INTEL_DISPLAY_A_HTOTAL (0x0000 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_HBLANK (0x0004 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_HSYNC (0x0008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VTOTAL (0x000c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VBLANK (0x0010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VSYNC (0x0014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HTOTAL (0x1000 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HBLANK (0x1004 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HSYNC (0x1008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VTOTAL (0x100c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VBLANK (0x1010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VSYNC (0x1014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_OFFSET 0x1000
#define INTEL_DISPLAY_A_HTOTAL (0x0000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_HBLANK (0x0004 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_HSYNC (0x0008 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VTOTAL (0x000c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VBLANK (0x0010 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VSYNC (0x0014 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HTOTAL (0x1000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HBLANK (0x1004 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HSYNC (0x1008 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VTOTAL (0x100c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VBLANK (0x1010 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VSYNC (0x1014 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT)
@@ -513,11 +516,12 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_PORT_D (0x4300 | REGS_NORTH_PIPE_AND_PORT)
// planes
#define INTEL_PIPE_BASE_REGISTER (0x0000 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_PIPE_ENABLED (1UL << 31)
#define INTEL_PIPE_CONTROL 0x0008
#define INTEL_PIPE_STATUS 0x0024
#define INTEL_PIPE_OFFSET 0x1000
#define INTEL_PLANE_OFFSET 0x1000
#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_CONTROL (0x1008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_A_PIPE_STATUS (0x0024 | REGS_NORTH_PLANE_CONTROL)
@@ -576,9 +580,10 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_B_PLL (0x6018 | REGS_SOUTH_SHARED)
#define CHV_DISPLAY_C_PLL (0x6030 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_MULTIPLIER_DIVISOR (INTEL_DISPLAY_A_PLL + 0x8)
#define INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR (INTEL_DISPLAY_B_PLL + 0x8)
#define CHV_DISPLAY_C_PLL_MULTIPLIER_DIVISOR (CHV_DISPLAY_C_PLL + 0xc)
// Multiplier Divisor
#define INTEL_DISPLAY_A_PLL_MD (0x601C | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_B_PLL_MD (0x6020 | REGS_SOUTH_SHARED)
#define CHV_DISPLAY_B_PLL_MD (0x603C | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_DIVISOR_0 (0x6040 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_DIVISOR_1 (0x6044 | REGS_SOUTH_SHARED)
@@ -21,11 +21,16 @@
#define TRACE_PIPE
#ifdef TRACE_PIPE
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x) _sPrintf x
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x) ;
# define TRACE(x...) ;
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
// PIPE: 6
// PLANE: 7
void
program_pipe_color_modes(uint32 colorMode)
@@ -47,9 +52,13 @@ DisplayPipe::DisplayPipe(pipe_index pipeIndex)
:
// fFDILink(NULL),
// fPanelFitter(NULL),
fBaseRegister(INTEL_PIPE_BASE_REGISTER + pipeIndex * INTEL_PIPE_OFFSET),
fPipeIndex(pipeIndex)
fPipeIndex(pipeIndex),
fPipeBase(REGS_NORTH_PIPE_AND_PORT + pipeIndex * INTEL_DISPLAY_OFFSET),
fPlaneBase(REGS_NORTH_PLANE_CONTROL + pipeIndex * INTEL_PLANE_OFFSET)
{
TRACE("DisplayPipe %s. Pipe Base: 0x%" B_PRIxADDR
" Plane Base: 0x% " B_PRIxADDR "\n", (pipeIndex == INTEL_PIPE_A)
? "A" : "B", fPipeBase, fPlaneBase);
}
@@ -61,17 +70,60 @@ DisplayPipe::~DisplayPipe()
bool
DisplayPipe::IsEnabled()
{
return (read32(fBaseRegister + INTEL_PIPE_CONTROL)
& INTEL_PIPE_ENABLED) != 0;
CALLED();
return (read32(fPlaneBase + INTEL_PIPE_CONTROL) & INTEL_PIPE_ENABLED) != 0;
}
void
DisplayPipe::Enable(const display_mode& mode)
DisplayPipe::Enable(display_mode* target, addr_t portAddress)
{
CALLED();
if (target == NULL) {
ERROR("%s: Invalid display mode!\n", __func__);
return;
}
if (portAddress == 0) {
ERROR("%s: Invalid port address!\n", __func__);
return;
}
// Enable display pipe
_Enable(true);
write32(INTEL_DISPLAY_B_IMAGE_SIZE, ((uint32)(mode.virtual_width - 1) << 16)
| (uint32)(mode.virtual_height - 1));
// update timing (fPipeBase bumps the DISPLAY_A to B when needed)
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HTOTAL),
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HBLANK),
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HSYNC),
((uint32)(target->timing.h_sync_end - 1) << 16)
| ((uint32)target->timing.h_sync_start - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VTOTAL),
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VBLANK),
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VSYNC),
((uint32)(target->timing.v_sync_end - 1) << 16)
| ((uint32)target->timing.v_sync_start - 1));
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_IMAGE_SIZE),
((uint32)(target->virtual_width - 1) << 16)
| ((uint32)target->virtual_height - 1));
write32(portAddress, (read32(portAddress)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target->timing.flags & B_POSITIVE_HSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
| ((target->timing.flags & B_POSITIVE_VSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
}
@@ -83,105 +135,84 @@ DisplayPipe::Disable()
void
DisplayPipe::ConfigureTimings(const pll_divisors& divisors)
DisplayPipe::ConfigureTimings(const pll_divisors& divisors, uint32 extraFlags)
{
CALLED();
addr_t pllDivisorA = INTEL_DISPLAY_A_PLL_DIVISOR_0;
addr_t pllDivisorB = INTEL_DISPLAY_A_PLL_DIVISOR_1;
addr_t pllControl = INTEL_DISPLAY_A_PLL;
if (fPipeIndex == INTEL_PIPE_B) {
pllDivisorA = INTEL_DISPLAY_B_PLL_DIVISOR_0;
pllDivisorB = INTEL_DISPLAY_B_PLL_DIVISOR_1;
pllControl = INTEL_DISPLAY_B_PLL;
}
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
write32(pllDivisorA, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(pllDivisorA, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags;
if (gInfo->shared_info->device_type.Generation() >= 4) {
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_MODE_ANALOG;
pll |= DISPLAY_PLL_2X_CLOCK;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
pll |= DISPLAY_PLL_2X_CLOCK;
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
#if 0
// update timing parameters
write32(INTEL_DISPLAY_A_HTOTAL,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HBLANK,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC,
((uint32)(target.timing.h_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1));
write32(INTEL_DISPLAY_A_VTOTAL,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VSYNC,
((uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.v_sync_start - 1));
write32(INTEL_DISPLAY_A_IMAGE_SIZE,
((uint32)(target.virtual_width - 1) << 16)
| ((uint32)target.virtual_height - 1));
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target.timing.flags & B_POSITIVE_HSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
| ((target.timing.flags & B_POSITIVE_VSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
#endif
write32(pllControl, pll);
read32(pllControl);
spin(150);
write32(pllControl, pll);
read32(pllControl);
spin(150);
}
void
DisplayPipe::_Enable(bool enable)
{
uint32 targetRegister = fBaseRegister + INTEL_PIPE_CONTROL;
CALLED();
addr_t targetRegister = fPlaneBase + INTEL_PIPE_CONTROL;
TRACE("%s: @ %" B_PRIxADDR "\n", __func__, targetRegister);
write32(targetRegister, (read32(targetRegister) & ~INTEL_PIPE_ENABLED)
| (enable ? INTEL_PIPE_ENABLED : 0));
read32(targetRegister);
@@ -36,11 +36,12 @@ public:
{ return fPipeIndex; }
bool IsEnabled();
void Enable(const display_mode& mode);
void Enable(display_mode* mode,
addr_t portRegister);
void Disable();
void ConfigureTimings(
const pll_divisors& divisors);
void ConfigureTimings(const pll_divisors& divisors,
uint32 extraFlags);
// access to the various parts of the pipe
// ::FDILink* FDILink()
@@ -54,8 +55,10 @@ private:
// FDILink* fFDILink;
// PanelFitter* fPanelFitter;
addr_t fBaseRegister;
pipe_index fPipeIndex;
addr_t fPipeBase;
addr_t fPlaneBase;
};
+66 -127
View File
@@ -38,9 +38,9 @@
Port::Port(port_index index, const char* baseName)
:
fDisplayPipe(NULL),
fPortIndex(index),
fPortName(NULL),
fDisplayPipe(NULL),
fEDIDState(B_NO_INIT)
{
char portID[2];
@@ -121,7 +121,7 @@ Port::GetEDID(edid1_info* edid, bool forceRead)
return fEDIDState;
}
TRACE("%s: using register %" B_PRIxADDR "\n", PortName(), ddcRegister);
TRACE("%s: using ddc @ 0x%" B_PRIxADDR "\n", PortName(), ddcRegister);
i2c_bus bus;
bus.cookie = (void*)ddcRegister;
@@ -241,127 +241,30 @@ AnalogPort::_PortRegister()
status_t
AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
{
TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
target->virtual_width, target->virtual_height);
TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
target->virtual_height);
if (fDisplayPipe == NULL) {
ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
return B_ERROR;
}
pll_divisors divisors;
compute_pll_divisors(target, &divisors, false);
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
uint32 extraPLLFlags = 0;
if (gInfo->shared_info->device_type.Generation() >= 4)
extraPLLFlags |= DISPLAY_PLL_MODE_ANALOG;
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)
|| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)
|| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SOC0)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
// Program pipe PLL's
fDisplayPipe->ConfigureTimings(divisors, extraPLLFlags);
pll |= DISPLAY_PLL_MODE_ANALOG;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_2X_CLOCK;
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
// Programmer's Ref says we must allow the DPLL to "warm up" before starting the plane
// so mask its bit, wait, enable its bit
write32(INTEL_DISPLAY_A_PLL, pll & ~DISPLAY_PLL_NO_VGA_CONTROL);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
// update timing parameters
write32(INTEL_DISPLAY_A_HTOTAL,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_DISPLAY_A_HBLANK,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC,
((uint32)(target->timing.h_sync_end - 1) << 16)
| ((uint32)target->timing.h_sync_start - 1));
write32(INTEL_DISPLAY_A_VTOTAL,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_DISPLAY_A_VSYNC,
((uint32)(target->timing.v_sync_end - 1) << 16)
| ((uint32)target->timing.v_sync_start - 1));
write32(INTEL_DISPLAY_A_IMAGE_SIZE,
((uint32)(target->virtual_width - 1) << 16)
| ((uint32)target->virtual_height - 1));
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target->timing.flags & B_POSITIVE_HSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
| ((target->timing.flags & B_POSITIVE_VSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
// TODO: verify the two comments below: the X driver doesn't seem to
// care about both of them!
// These two have to be set for display B, too - this obviously means
// that the second head always must adopt the color space of the first
// head.
write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) {
write32(INTEL_DISPLAY_B_IMAGE_SIZE,
((uint32)(target->virtual_width - 1) << 16)
| ((uint32)target->virtual_height - 1));
write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
}
// Program target display mode
fDisplayPipe->Enable(target, _PortRegister());
// XXX: Crashes?
// Set fCurrentMode to our set display mode
memcpy(fCurrentMode, target, sizeof(display_mode));
//memcpy(fCurrentMode, target, sizeof(display_mode));
return B_OK;
}
@@ -428,6 +331,22 @@ LVDSPort::_PortRegister()
status_t
LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
{
CALLED();
if (target == NULL) {
ERROR("%s: Invalid target mode passed!\n", __func__);
return B_ERROR;
}
TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
target->virtual_width, target->virtual_height);
if (fDisplayPipe == NULL) {
ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
return B_ERROR;
}
// TODO: Fix software scaling?
#if 0
// For LVDS panels, we actually always set the native mode in hardware
// Then we use the panel fitter to scale the picture to that.
display_mode hardwareTarget;
@@ -515,17 +434,19 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
read32(INTEL_DISPLAY_B_PLL);
spin(150);
}
#endif
uint32 lvds = read32(INTEL_DIGITAL_LVDS_PORT) | LVDS_PORT_EN
| LVDS_A0A2_CLKA_POWER_UP;
pll_divisors divisors;
compute_pll_divisors(target, &divisors, true);
uint32 lvds = read32(_PortRegister())
| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
lvds |= LVDS_18BIT_DITHER;
// TODO: do not do this if the connected panel is 24-bit
// (I don't know how to detect that)
float referenceClock = gInfo->shared_info->pll_info.reference_frequency
/ 1000.0f;
// Set the B0-B3 data pairs corresponding to whether we're going to
// set the DPLLs for dual-channel mode or not.
if (divisors.post2 == LVDS_POST2_RATE_FAST)
@@ -533,9 +454,22 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
else
lvds &= ~(LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP);
write32(INTEL_DIGITAL_LVDS_PORT, lvds);
read32(INTEL_DIGITAL_LVDS_PORT);
write32(_PortRegister(), lvds);
read32(_PortRegister());
uint32 extraPLLFlags = 0;
// DPLL mode LVDS for i915+
if (gInfo->shared_info->device_type.Generation() >= 4)
extraPLLFlags |= DISPLAY_PLL_MODE_LVDS;
// Program pipe PLL's
fDisplayPipe->ConfigureTimings(divisors, extraPLLFlags);
// Program target display mode
fDisplayPipe->Enable(target, _PortRegister());
#if 0
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IGD)) {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
(((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
@@ -558,6 +492,9 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
// Wait for the clocks to stabilize
spin(150);
float referenceClock = gInfo->shared_info->pll_info.reference_frequency
/ 1000.0f;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
float adjusted = ((referenceClock * divisors.m) / divisors.n)
/ divisors.post;
@@ -570,7 +507,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
/ (target->timing.pixel_clock / 1000.0f));
}
write32(INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR, (0 << 24)
write32(INTEL_DISPLAY_B_PLL_MD, (0 << 24)
| ((pixelMultiply - 1) << 8));
} else
write32(INTEL_DISPLAY_B_PLL, dpll);
@@ -655,10 +592,6 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
| ((uint32)target->timing.v_sync_start - 1));
}
write32(INTEL_DISPLAY_B_IMAGE_SIZE,
((uint32)(target->virtual_width - 1) << 16)
| ((uint32)target->virtual_height - 1));
write32(INTEL_DISPLAY_B_POS, 0);
write32(INTEL_DISPLAY_B_PIPE_SIZE,
((uint32)(target->timing.v_display - 1) << 16)
@@ -671,6 +604,11 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
read32(INTEL_DISPLAY_B_PIPE_CONTROL) | INTEL_PIPE_ENABLED);
read32(INTEL_DISPLAY_B_PIPE_CONTROL);
#endif
// XXX: Crashes?
// Set fCurrentMode to our set display mode
//memcpy(fCurrentMode, target, sizeof(display_mode));
return B_OK;
}
@@ -717,6 +655,7 @@ DigitalPort::_DDCRegister()
addr_t
DigitalPort::_PortRegister()
{
ERROR("%s: %s PortRegister fallthrough\n", __func__, PortName());
return 0;
}
@@ -75,6 +75,8 @@ static status_t _SetI2CSignals(void* cookie, int clock,
int data);
display_mode* fCurrentMode;
DisplayPipe* fDisplayPipe;
private:
virtual addr_t _DDCRegister() = 0;
@@ -83,8 +85,6 @@ virtual addr_t _PortRegister() = 0;
port_index fPortIndex;
char* fPortName;
DisplayPipe* fDisplayPipe;
status_t fEDIDState;
edid1_info fEDIDInfo;
};
@@ -620,8 +620,11 @@ if (first) {
ERROR("%s: Unable to set display mode!\n", __func__);
}
TRACE("%s: Port configuration completed successfully!\n", __func__);
// RIP DIGITAL / LVDS (strange..)
#if 0
if ((gInfo->head_mode & HEAD_MODE_STIPPI) != 0) {
pll_divisors divisors;
compute_pll_divisors(&target, &divisors, false);
@@ -711,6 +714,7 @@ if (first) {
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
}
#endif
// RIP ANALOG