From f69b48fe24ef94dac44b8123884ca71df675be4b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 18 Dec 2007 18:10:33 -0800 Subject: [PATCH] Unconditionally restore pipe configuration This is a partial fix for #13196, which covers both leaving pipes disabled at server exit time and problems with restoring the pipe configuration on certain chipsets. It restores the pipe configuration unconditionally (previously we made sure the PLL was running and we weren't in VGA mode) but also adds some additional PLL settle time to the PLL register write paths. --- src/i830_driver.c | 97 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/src/i830_driver.c b/src/i830_driver.c index 7818ee4e..ca4544d8 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -1991,6 +1991,13 @@ SaveHWState(ScrnInfoPtr pScrn) return TRUE; } +/* Wait for the PLL to settle down after programming */ +static void +i830_dpll_settle(void) +{ + usleep(10000); /* 10 ms *should* be plenty */ +} + static Bool RestoreHWState(ScrnInfoPtr pScrn) { @@ -2025,6 +2032,23 @@ RestoreHWState(ScrnInfoPtr pScrn) if (!IS_I830(pI830) && !IS_845G(pI830)) OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL); + /* + * Pipe regs + * To restore the saved state, we first need to program the PLL regs, + * followed by the pipe configuration and finally the display plane + * configuration. The VGA registers can program one, both or neither + * of the PLL regs, depending on their VGA_MOD_DIS bit value. + */ + + /* + * Since either or both pipes may use the VGA clocks, make sure the + * regs are valid. + */ + OUTREG(VCLK_DIVISOR_VGA0, pI830->saveVCLK_DIVISOR_VGA0); + OUTREG(VCLK_DIVISOR_VGA1, pI830->saveVCLK_DIVISOR_VGA1); + OUTREG(VCLK_POST_DIV, pI830->saveVCLK_POST_DIV); + + /* If the pipe A PLL is active, we can restore the pipe & plane config */ if (pI830->saveDPLL_A & DPLL_VCO_ENABLE) { OUTREG(DPLL_A, pI830->saveDPLL_A & ~DPLL_VCO_ENABLE); @@ -2033,13 +2057,14 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(FPA0, pI830->saveFPA0); OUTREG(FPA1, pI830->saveFPA1); OUTREG(DPLL_A, pI830->saveDPLL_A); - usleep(150); + i830_dpll_settle(); if (IS_I965G(pI830)) OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD); else OUTREG(DPLL_A, pI830->saveDPLL_A); - usleep(150); + i830_dpll_settle(); + /* Restore mode config */ OUTREG(HTOTAL_A, pI830->saveHTOTAL_A); OUTREG(HBLANK_A, pI830->saveHBLANK_A); OUTREG(HSYNC_A, pI830->saveHSYNC_A); @@ -2058,20 +2083,31 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(DSPASURF, pI830->saveDSPASURF); OUTREG(DSPATILEOFF, pI830->saveDSPATILEOFF); } + + OUTREG(PIPEACONF, pI830->savePIPEACONF); + i830WaitForVblank(pScrn); + /* - * Make sure the DPLL is active and not in VGA mode or the - * write of PIPEnCONF may cause a crash + * Program Pipe A's plane + * The corresponding display plane may be disabled, and should only be + * enabled if pipe A is actually on (otherwise we have a bug in the initial + * state). */ - if ((pI830->saveDPLL_A & DPLL_VCO_ENABLE) && - (pI830->saveDPLL_A & DPLL_VGA_MODE_DIS)) - OUTREG(PIPEACONF, pI830->savePIPEACONF); - i830WaitForVblank(pScrn); - OUTREG(DSPACNTR, pI830->saveDSPACNTR); - OUTREG(DSPABASE, INREG(DSPABASE)); - i830WaitForVblank(pScrn); - + if (pI830->saveDSPACNTR & DISPPLANE_SEL_PIPE_A) { + OUTREG(DSPACNTR, pI830->saveDSPACNTR); + OUTREG(DSPABASE, INREG(DSPABASE)); + i830WaitForVblank(pScrn); + } + if (pI830->saveDSPBCNTR & DISPPLANE_SEL_PIPE_A) { + OUTREG(DSPBCNTR, pI830->saveDSPBCNTR); + OUTREG(DSPBBASE, INREG(DSPBBASE)); + i830WaitForVblank(pScrn); + } + + /* See note about pipe programming above */ if(xf86_config->num_crtc == 2) { + /* If the pipe B PLL is active, we can restore the pipe & plane config */ if (pI830->saveDPLL_B & DPLL_VCO_ENABLE) { OUTREG(DPLL_B, pI830->saveDPLL_B & ~DPLL_VCO_ENABLE); @@ -2080,13 +2116,14 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(FPB0, pI830->saveFPB0); OUTREG(FPB1, pI830->saveFPB1); OUTREG(DPLL_B, pI830->saveDPLL_B); - usleep(150); + i830_dpll_settle(); if (IS_I965G(pI830)) OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD); else OUTREG(DPLL_B, pI830->saveDPLL_B); - usleep(150); + i830_dpll_settle(); + /* Restore mode config */ OUTREG(HTOTAL_B, pI830->saveHTOTAL_B); OUTREG(HBLANK_B, pI830->saveHBLANK_B); OUTREG(HSYNC_B, pI830->saveHSYNC_B); @@ -2105,18 +2142,28 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(DSPBTILEOFF, pI830->saveDSPBTILEOFF); } + OUTREG(PIPEBCONF, pI830->savePIPEBCONF); + i830WaitForVblank(pScrn); + /* - * See PIPEnCONF note above + * Program Pipe B's plane + * Note that pipe B may be disabled, and in that case, the plane + * should also be disabled or we must have had a bad initial state. */ - if ((pI830->saveDPLL_B & DPLL_VCO_ENABLE) && - (pI830->saveDPLL_B & DPLL_VGA_MODE_DIS)) - OUTREG(PIPEBCONF, pI830->savePIPEBCONF); - i830WaitForVblank(pScrn); - OUTREG(DSPBCNTR, pI830->saveDSPBCNTR); - OUTREG(DSPBBASE, INREG(DSPBBASE)); - i830WaitForVblank(pScrn); + if (pI830->saveDSPACNTR & DISPPLANE_SEL_PIPE_B) { + OUTREG(DSPACNTR, pI830->saveDSPACNTR); + OUTREG(DSPABASE, INREG(DSPABASE)); + i830WaitForVblank(pScrn); + } + if (pI830->saveDSPBCNTR & DISPPLANE_SEL_PIPE_B) { + OUTREG(DSPBCNTR, pI830->saveDSPBCNTR); + OUTREG(DSPBBASE, INREG(DSPBBASE)); + i830WaitForVblank(pScrn); + } } + OUTREG(VGACNTRL, pI830->saveVGACNTRL); + /* Restore outputs */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; @@ -2124,12 +2171,6 @@ RestoreHWState(ScrnInfoPtr pScrn) output->funcs->restore(output); } - OUTREG(VGACNTRL, pI830->saveVGACNTRL); - - OUTREG(VCLK_DIVISOR_VGA0, pI830->saveVCLK_DIVISOR_VGA0); - OUTREG(VCLK_DIVISOR_VGA1, pI830->saveVCLK_DIVISOR_VGA1); - OUTREG(VCLK_POST_DIV, pI830->saveVCLK_POST_DIV); - i830_restore_palette(pI830, PIPE_A); i830_restore_palette(pI830, PIPE_B);