More SandyBridge fixes and cleanups

Modesetting
===========

My previous hack was setting the transcoder registers, instead of the
display ones. Do that the way it is designed in the driver instead:

- If there is a transcoder, set its registers, but do not set the
display timings. The display will remain set at its native (and only)
resolution, and panel fitting will adjust the output of the transcoder
to match.
- If there is no transcoder, set the display registers directly to the
native resolution, as it was done on previous generation devices.
- fPipeOffset hacks no longer needed

DPMS
====

It seems the panel control register is not readable on PCH? Anyway, the
code would loop forever waiting for the bit to become unset when turning
the display off. Waiting seems to not be needed, so just remove it as
well as the "unlock" bit, which does not work for me and results in a
black screen.

Remaining hacks
===============

I still need to force HEAD_MODE_A_ANALOG to get output on pipe B (LVDS
display) working. I suspect something is common to the two pipes or not
allocated to the right one.

This version will have less side effects on other generations and help
with getting things to work on SandyBridge and possibly later devices.
Please test and report.
This commit is contained in:
Adrien Destugues 2016-08-25 19:34:45 +02:00
parent 81a9bf1a88
commit adc0f76e64
4 changed files with 56 additions and 48 deletions

View File

@ -120,6 +120,7 @@
#define MCH_SHARED_REGISTER_BASE 0x00000
#define MCH_PIPE_AND_PORT_REGISTER_BASE 0x60000
#define MCH_PLANE_CONTROL_REGISTER_BASE 0x70000
#define ICH_SHARED_REGISTER_BASE 0x00000
#define ICH_PORT_REGISTER_BASE 0x60000
@ -520,18 +521,18 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_OFFSET 0x1000
#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_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)

View File

@ -182,26 +182,32 @@ Pipe::ConfigureTimings(display_mode* target)
return;
}
// 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));
/* If there is a transcoder, leave the display at its native resolution,
* and configure only the transcoder (panel fitting will match them
* together). */
if (!fHasTranscoder)
{
// 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(INTEL_DISPLAY_A_HBLANK + fPipeOffset,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset,
((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_VTOTAL + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
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?

View File

@ -354,14 +354,14 @@ LVDSPort::LVDSPort()
:
Port(INTEL_PORT_C, "LVDS")
{
#if 0
// FIXME results in black screen on SandyBridge
// Always unlock LVDS port as soon as we start messing with it.
uint32 panelControl = INTEL_PANEL_CONTROL;
if (gInfo->shared_info->pch_info != INTEL_PCH_NONE)
panelControl = PCH_PANEL_CONTROL;
if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
// FIXME writing there results in black screen on SandyBridge
return;
// panelControl = PCH_PANEL_CONTROL;
}
write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK);
#endif
}

View File

@ -47,10 +47,6 @@ static void
enable_lvds_panel(bool enable)
{
bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
if (hasPCH) {
// TODO: fix for PCH (does not enable the panel - crashes?)
return;
}
int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL;
int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS;
@ -61,21 +57,26 @@ enable_lvds_panel(bool enable)
if (enable) {
if ((control & PANEL_CONTROL_POWER_TARGET_ON) == 0) {
write32(controlRegister, control | PANEL_CONTROL_POWER_TARGET_ON
| (hasPCH ? PANEL_REGISTER_UNLOCK : 0));
/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
}
do {
panelStatus = read32(statusRegister);
} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
if (!hasPCH) {
do {
panelStatus = read32(statusRegister);
} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
}
} else {
if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
write32(controlRegister, (control & ~PANEL_CONTROL_POWER_TARGET_ON)
| (hasPCH ? PANEL_REGISTER_UNLOCK : 0));
/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
}
do {
panelStatus = read32(statusRegister);
} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
if (!hasPCH)
{
do {
panelStatus = read32(statusRegister);
} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
}
}
}