Create known output configuration at EnterVT time

Since we added the pipe A force quirk (leaving pipe A on all the time),
DPMS calls to disable it have silently returned, leaving the pipe on.
If another driver (like vesafb) has enabled it, we may end up with a bad
configuration, leading to hangs or blank screens at VT switch time.

Fixes bug #19603.
This commit is contained in:
Jesse Barnes 2009-03-18 09:36:58 -07:00
parent 7c94227dd4
commit 6deb26ae7b
3 changed files with 155 additions and 105 deletions

View File

@ -1121,6 +1121,134 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
}
void
i830_crtc_enable(xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
uint32_t temp;
/* Enable the DPLL */
temp = INREG(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) == 0)
{
OUTREG(dpll_reg, temp);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
}
/* Enable the pipe */
temp = INREG(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) == 0)
OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
/* Enable the plane */
temp = INREG(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) == 0)
{
OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
OUTREG(dspbase_reg, INREG(dspbase_reg));
}
i830_crtc_load_lut(crtc);
/* Give the overlay scaler a chance to enable if it's on this pipe */
i830_crtc_dpms_video(crtc, TRUE);
/* Reenable compression if needed */
if (i830_use_fb_compression(crtc))
i830_enable_fb_compression(crtc);
i830_modeset_ctl(crtc, 0);
}
void
i830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
uint32_t temp;
i830_modeset_ctl(crtc, 1);
/* Shut off compression if in use */
if (i830_use_fb_compression(crtc))
i830_disable_fb_compression(crtc);
/* Give the overlay scaler a chance to disable if it's on this pipe */
i830_crtc_dpms_video(crtc, FALSE);
/*
* The documentation says :
* - Disable planes (VGA or hires)
* - Disable pipe
* - Disable VGA display
*/
/* Disable display plane */
temp = INREG(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) != 0)
{
OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
OUTREG(dspbase_reg, INREG(dspbase_reg));
POSTING_READ(dspbase_reg);
}
if (!IS_I9XX(pI830)) {
/* Wait for vblank for the disable to take effect */
i830WaitForVblank(pScrn);
}
/* May need to leave pipe A on */
if (disable_pipe)
{
/* Next, disable display pipes */
temp = INREG(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) {
OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
POSTING_READ(pipeconf_reg);
}
/* Wait for vblank for the disable to take effect. */
i830WaitForVblank(pScrn);
temp = INREG(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) {
OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
}
/* Wait for the clocks to turn off. */
usleep(150);
}
/* Disable the VGA plane that we never use. */
i830_disable_vga_plane (crtc);
}
/**
* Sets the power management mode of the pipe and plane.
*
@ -1134,12 +1262,7 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
I830Ptr pI830 = I830PTR(pScrn);
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
uint32_t temp;
Bool disable_pipe = TRUE;
/* XXX: When our outputs are all unaware of DPMS modes other than off and
* on, we should map those modes to DPMSModeOff in the CRTC.
@ -1148,105 +1271,12 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
case DPMSModeOn:
case DPMSModeStandby:
case DPMSModeSuspend:
/* Enable the DPLL */
temp = INREG(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) == 0)
{
OUTREG(dpll_reg, temp);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
}
/* Enable the pipe */
temp = INREG(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) == 0)
OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
/* Enable the plane */
temp = INREG(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) == 0)
{
OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
OUTREG(dspbase_reg, INREG(dspbase_reg));
}
i830_crtc_load_lut(crtc);
/* Give the overlay scaler a chance to enable if it's on this pipe */
i830_crtc_dpms_video(crtc, TRUE);
/* Reenable compression if needed */
if (i830_use_fb_compression(crtc))
i830_enable_fb_compression(crtc);
i830_modeset_ctl(crtc, 0);
i830_crtc_enable(crtc);
break;
case DPMSModeOff:
i830_modeset_ctl(crtc, 1);
/* Shut off compression if in use */
if (i830_use_fb_compression(crtc))
i830_disable_fb_compression(crtc);
/* Give the overlay scaler a chance to disable if it's on this pipe */
i830_crtc_dpms_video(crtc, FALSE);
/*
* The documentation says :
* - Disable planes (VGA or hires)
* - Disable pipe
* - Disable VGA display
*/
/* Disable display plane */
temp = INREG(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) != 0)
{
OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
OUTREG(dspbase_reg, INREG(dspbase_reg));
POSTING_READ(dspbase_reg);
}
if (!IS_I9XX(pI830)) {
/* Wait for vblank for the disable to take effect */
i830WaitForVblank(pScrn);
}
/* May need to leave pipe A on */
if ((pipe != 0) || !(pI830->quirk_flag & QUIRK_PIPEA_FORCE))
{
/* Next, disable display pipes */
temp = INREG(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) {
OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
POSTING_READ(pipeconf_reg);
}
/* Wait for vblank for the disable to take effect. */
i830WaitForVblank(pScrn);
temp = INREG(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) {
OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
POSTING_READ(dpll_reg);
}
/* Wait for the clocks to turn off. */
usleep(150);
}
/* Disable the VGA plane that we never use. */
i830_disable_vga_plane (crtc);
if ((pipe == 0) && (pI830->quirk_flag & QUIRK_PIPEA_FORCE))
disable_pipe = FALSE;
i830_crtc_disable(crtc, disable_pipe);
break;
}

View File

@ -32,6 +32,8 @@ void i830PipeSetBase(xf86CrtcPtr crtc, int x, int y);
void i830WaitForVblank(ScrnInfoPtr pScrn);
void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn);
void i830_set_new_crtc_bo(ScrnInfoPtr pScrn);
void i830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe);
void i830_crtc_enable(xf86CrtcPtr crtc);
xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output, DisplayModePtr mode, int *dpms_mode);
void i830ReleaseLoadDetectPipe(xf86OutputPtr output, int dpms_mode);

View File

@ -2275,7 +2275,7 @@ RestoreHWState(ScrnInfoPtr pScrn)
/* Disable pipes */
for (i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
crtc->funcs->dpms(crtc, DPMSModeOff);
i830_crtc_disable(crtc, TRUE);
}
i830WaitForVblank(pScrn);
@ -3460,8 +3460,9 @@ static Bool
I830EnterVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
I830Ptr pI830 = I830PTR(pScrn);
int ret;
int i, ret;
DPRINTF(PFX, "Enter VT\n");
@ -3482,6 +3483,23 @@ I830EnterVT(int scrnIndex, int flags)
SaveHWState(pScrn);
}
/* Get the hardware into a known state if needed */
if (!pI830->use_drm_mode) {
/* Disable outputs */
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
output->funcs->dpms(output, DPMSModeOff);
}
i830WaitForVblank(pScrn);
/* Disable pipes */
for (i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
i830_crtc_disable(crtc, TRUE);
}
i830WaitForVblank(pScrn);
}
pI830->leaving = FALSE;
if (!pI830->use_drm_mode)