intel_extreme: Fix i965 LVDS panel programming
* polarity regs move on LVDS vs analog * add knowledge or transcoder registers, they exist seperately on PCH-split * Native resolutions now work on LVDS under i965
This commit is contained in:
parent
e28962a280
commit
d35a52e8e2
|
@ -448,18 +448,18 @@ struct intel_free_graphics_memory {
|
|||
|
||||
#define LVDS_POST2_RATE_SLOW 14 // PLL Divisors
|
||||
#define LVDS_POST2_RATE_FAST 7
|
||||
#define LVDS_B0B3_POWER_MASK (3 << 2)
|
||||
#define LVDS_B0B3_POWER_UP (3 << 2)
|
||||
#define LVDS_CLKB_POWER_MASK (3 << 4)
|
||||
#define LVDS_CLKB_POWER_UP (3 << 4)
|
||||
#define LVDS_A3_POWER_MASK (3 << 6)
|
||||
#define LVDS_A3_POWER_UP (3 << 6)
|
||||
#define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
|
||||
#define LVDS_BORDER_ENABLE (1 << 15)
|
||||
#define LVDS_HSYNC_POLARITY (1 << 20)
|
||||
#define LVDS_VSYNC_POLARITY (1 << 21)
|
||||
#define LVDS_18BIT_DITHER (1 << 25)
|
||||
#define LVDS_PORT_EN (1 << 31)
|
||||
#define LVDS_B0B3_POWER_MASK (3UL << 2)
|
||||
#define LVDS_B0B3_POWER_UP (3UL << 2)
|
||||
#define LVDS_CLKB_POWER_MASK (3UL << 4)
|
||||
#define LVDS_CLKB_POWER_UP (3UL << 4)
|
||||
#define LVDS_A3_POWER_MASK (3UL << 6)
|
||||
#define LVDS_A3_POWER_UP (3UL << 6)
|
||||
#define LVDS_A0A2_CLKA_POWER_UP (3UL << 8)
|
||||
#define LVDS_BORDER_ENABLE (1UL << 15)
|
||||
#define LVDS_HSYNC_POLARITY (1UL << 20)
|
||||
#define LVDS_VSYNC_POLARITY (1UL << 21)
|
||||
#define LVDS_18BIT_DITHER (1UL << 25)
|
||||
#define LVDS_PORT_EN (1UL << 31)
|
||||
|
||||
|
||||
// PLL flags
|
||||
|
@ -508,6 +508,23 @@ struct intel_free_graphics_memory {
|
|||
#define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT)
|
||||
|
||||
// on PCH we also have to set the transcoder
|
||||
#define INTEL_TRANSCODER_A_HTOTAL (0x0000 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_HBLANK (0x0004 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_HSYNC (0x0008 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_VTOTAL (0x000c | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_VBLANK (0x0010 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_VSYNC (0x0014 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_HTOTAL (0x1000 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_HBLANK (0x1004 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_HSYNC (0x1008 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_VTOTAL (0x100c | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_VBLANK (0x1010 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_VSYNC (0x1014 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
|
||||
#define INTEL_TRANSCODER_A_IMAGE_SIZE (0x001c | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_B_IMAGE_SIZE (0x101c | REGS_SOUTH_TRANSCODER_PORT)
|
||||
|
||||
#define INTEL_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_DIGITAL_PORT_A (0x1120 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_DIGITAL_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
|
|
|
@ -52,26 +52,29 @@ program_pipe_color_modes(uint32 colorMode)
|
|||
|
||||
Pipe::Pipe(pipe_index pipeIndex)
|
||||
:
|
||||
fHasTranscoder(false),
|
||||
fFDILink(NULL),
|
||||
// fPanelFitter(NULL),
|
||||
fPipeIndex(pipeIndex),
|
||||
fPipeBase(REGS_NORTH_PIPE_AND_PORT),
|
||||
fPlaneBase(REGS_NORTH_PLANE_CONTROL)
|
||||
fPipeOffset(0),
|
||||
fPlaneOffset(0)
|
||||
{
|
||||
if (pipeIndex == INTEL_PIPE_B) {
|
||||
fPipeBase += INTEL_DISPLAY_OFFSET;
|
||||
fPlaneBase += INTEL_PLANE_OFFSET;
|
||||
fPipeOffset = INTEL_DISPLAY_OFFSET;
|
||||
fPlaneOffset = INTEL_PLANE_OFFSET;
|
||||
}
|
||||
|
||||
// Program FDILink if PCH
|
||||
if (gInfo->shared_info->device_type.HasPlatformControlHub()) {
|
||||
fHasTranscoder = true;
|
||||
|
||||
// Program FDILink if PCH
|
||||
if (fFDILink == NULL)
|
||||
fFDILink = new(std::nothrow) FDILink(pipeIndex);
|
||||
}
|
||||
|
||||
TRACE("Pipe %s. Pipe Base: 0x%" B_PRIxADDR
|
||||
" Plane Base: 0x% " B_PRIxADDR "\n", (pipeIndex == INTEL_PIPE_A)
|
||||
? "A" : "B", fPipeBase, fPlaneBase);
|
||||
? "A" : "B", fPipeOffset, fPlaneOffset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,12 +87,47 @@ bool
|
|||
Pipe::IsEnabled()
|
||||
{
|
||||
CALLED();
|
||||
return (read32(fPlaneBase + INTEL_PIPE_CONTROL) & INTEL_PIPE_ENABLED) != 0;
|
||||
return (read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPlaneOffset)
|
||||
& INTEL_PIPE_ENABLED) != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pipe::Enable(display_mode* target, addr_t portAddress)
|
||||
Pipe::_EnableTranscoder(display_mode* target)
|
||||
{
|
||||
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
|
||||
write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.h_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.h_sync_start - 1));
|
||||
|
||||
write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.v_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.v_sync_start - 1));
|
||||
|
||||
#if 0
|
||||
// XXX: Is it ok to do these on non-digital?
|
||||
write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0);
|
||||
write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset,
|
||||
((uint32)(target->virtual_width - 1) << 16)
|
||||
| ((uint32)target->virtual_height - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pipe::Enable(display_mode* target)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
|
@ -97,58 +135,48 @@ Pipe::Enable(display_mode* target, addr_t portAddress)
|
|||
ERROR("%s: Invalid display mode!\n", __func__);
|
||||
return;
|
||||
}
|
||||
if (portAddress == 0) {
|
||||
ERROR("%s: Invalid port address!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// update timing (fPipeBase bumps the DISPLAY_A to B when needed)
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HTOTAL),
|
||||
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
|
||||
write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HBLANK),
|
||||
write32(INTEL_DISPLAY_A_HBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_HSYNC),
|
||||
write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.h_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.h_sync_start - 1));
|
||||
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VTOTAL),
|
||||
write32(INTEL_DISPLAY_A_VTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VBLANK),
|
||||
write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_VSYNC),
|
||||
write32(INTEL_DISPLAY_A_VSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.v_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.v_sync_start - 1));
|
||||
|
||||
// XXX: Is it ok to do these on non-digital?
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_POS), 0);
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_IMAGE_SIZE),
|
||||
write32(INTEL_DISPLAY_A_POS + fPipeOffset, 0);
|
||||
write32(INTEL_DISPLAY_A_IMAGE_SIZE + fPipeOffset,
|
||||
((uint32)(target->virtual_width - 1) << 16)
|
||||
| ((uint32)target->virtual_height - 1));
|
||||
|
||||
write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_PIPE_SIZE),
|
||||
write32(INTEL_DISPLAY_A_PIPE_SIZE + fPipeOffset,
|
||||
((uint32)(target->timing.v_display - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
|
||||
// This is useful for debugging: it sets the border to red, so you
|
||||
// can see what is border and what is porch (black area around the
|
||||
// sync)
|
||||
//write32(fPipeBase + REGISTER_REGISTER(INTEL_DISPLAY_A_RED), 0x00FF0000);
|
||||
//write32(INTEL_DISPLAY_A_RED + fPipeOffset, 0x00FF0000);
|
||||
|
||||
// XXX: Is it ok to do this on non-analog?
|
||||
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));
|
||||
if (fHasTranscoder)
|
||||
_EnableTranscoder(target);
|
||||
|
||||
// Enable display pipe
|
||||
_Enable(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -263,7 +291,7 @@ Pipe::_Enable(bool enable)
|
|||
{
|
||||
CALLED();
|
||||
|
||||
addr_t targetRegister = fPlaneBase + INTEL_PIPE_CONTROL;
|
||||
addr_t targetRegister = INTEL_DISPLAY_A_PIPE_CONTROL + fPlaneOffset;
|
||||
|
||||
write32(targetRegister, (read32(targetRegister) & ~INTEL_PIPE_ENABLED)
|
||||
| (enable ? INTEL_PIPE_ENABLED : 0));
|
||||
|
|
|
@ -35,8 +35,7 @@ public:
|
|||
{ return fPipeIndex; }
|
||||
|
||||
bool IsEnabled();
|
||||
void Enable(display_mode* mode,
|
||||
addr_t portRegister);
|
||||
void Enable(display_mode* mode);
|
||||
void Disable();
|
||||
|
||||
void ConfigureTimings(
|
||||
|
@ -52,14 +51,17 @@ public:
|
|||
|
||||
private:
|
||||
void _Enable(bool enable);
|
||||
void _EnableTranscoder(display_mode* mode);
|
||||
|
||||
bool fHasTranscoder;
|
||||
|
||||
FDILink* fFDILink;
|
||||
// PanelFitter* fPanelFitter;
|
||||
|
||||
pipe_index fPipeIndex;
|
||||
|
||||
addr_t fPipeBase;
|
||||
addr_t fPlaneBase;
|
||||
addr_t fPipeOffset;
|
||||
addr_t fPlaneOffset;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -305,12 +305,19 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||
if (gInfo->shared_info->device_type.Generation() >= 4)
|
||||
extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
|
||||
|
||||
write32(_PortRegister(), (read32(_PortRegister())
|
||||
& ~(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));
|
||||
|
||||
// Program pipe PLL's
|
||||
fPipe->ConfigureTimings(divisors, target->timing.pixel_clock,
|
||||
extraPLLFlags);
|
||||
|
||||
// Program target display mode
|
||||
fPipe->Enable(target, _PortRegister());
|
||||
fPipe->Enable(target);
|
||||
|
||||
// Set fCurrentMode to our set display mode
|
||||
memcpy(&fCurrentMode, target, sizeof(display_mode));
|
||||
|
@ -345,7 +352,7 @@ LVDSPort::IsConnected()
|
|||
}
|
||||
}
|
||||
|
||||
uint32 registerValue = read32(INTEL_DIGITAL_LVDS_PORT);
|
||||
uint32 registerValue = read32(_PortRegister());
|
||||
if (gInfo->shared_info->device_type.HasPlatformControlHub()) {
|
||||
// there's a detection bit we can use
|
||||
if ((registerValue & PCH_LVDS_DETECTED) == 0) {
|
||||
|
@ -524,11 +531,15 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||
|
||||
// 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_high)
|
||||
if (divisors.post2_high) {
|
||||
TRACE("LVDS: dual channel\n");
|
||||
lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
|
||||
else
|
||||
} else {
|
||||
TRACE("LVDS: single channel\n");
|
||||
lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
|
||||
}
|
||||
|
||||
// LVDS port control moves polarity bits because Intel hates you.
|
||||
// Set LVDS sync polarity
|
||||
lvds &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
|
||||
|
||||
|
@ -538,7 +549,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||
if ((target->timing.flags & B_POSITIVE_VSYNC) == 0)
|
||||
lvds |= LVDS_VSYNC_POLARITY;
|
||||
|
||||
TRACE("%s: LVDS Control: 0x%" B_PRIx32 "\n", __func__, lvds);
|
||||
TRACE("%s: LVDS Write: 0x%" B_PRIx32 "\n", __func__, lvds);
|
||||
write32(_PortRegister(), lvds);
|
||||
read32(_PortRegister());
|
||||
|
||||
|
@ -560,7 +571,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||
ERROR("%s: %s didn't power on within 1000ms!\n", __func__, PortName());
|
||||
|
||||
// Program target display mode
|
||||
fPipe->Enable(target, _PortRegister());
|
||||
fPipe->Enable(target);
|
||||
|
||||
#if 0
|
||||
|
||||
|
@ -732,7 +743,7 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||
extraPLLFlags);
|
||||
|
||||
// Program target display mode
|
||||
fPipe->Enable(target, _PortRegister());
|
||||
fPipe->Enable(target);
|
||||
|
||||
// Set fCurrentMode to our set display mode
|
||||
memcpy(&fCurrentMode, target, sizeof(display_mode));
|
||||
|
|
Loading…
Reference in New Issue