diff options
author | Eric Anholt <eric@anholt.net> | 2007-02-13 10:21:12 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2007-02-13 10:21:12 -0800 |
commit | 6641aec0a1cbc869fba1956c556cdd204631545a (patch) | |
tree | 80706e6785fc773324aa6867bf234a7aa1b7f634 /src/i830_display.c | |
parent | 991439d4c78cf5b2a8f6bb8f5b36fffbfcc4e4fc (diff) |
Attempt to detect panel fixed mode from EDID or current programmed mode.
These two sources are placed in higher priority to the BIOS data when
available, since the BIOS data has proven unreliable. The BIOS data is still
read, and warnings printed if it doesn't match what we probe. The BIOS data
remains useful for the situation where we want to turn on LVDS but there is no
EDID available and no current mode programmed (i.e. booting with VGA or TV
connected).
Diffstat (limited to 'src/i830_display.c')
-rw-r--r-- | src/i830_display.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/i830_display.c b/src/i830_display.c index 82029850..345eea9f 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -1132,6 +1132,91 @@ i830ReleaseLoadDetectPipe(xf86OutputPtr output) } } +/* Returns the clock of the currently programmed mode of the given pipe. */ +static int +i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + CARD32 dpll = INREG((pipe == 0) ? DPLL_A : DPLL_B); + CARD32 fp; + intel_clock_t clock; + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = INREG((pipe == 0) ? FPA0 : FPB0); + else + fp = INREG((pipe == 0) ? FPA1 : FPB1); + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unknown DPLL mode %08x in programmed mode\n", + (int)(dpll & DPLL_MODE_MASK)); + return 0; + } + + /* XXX: Handle the 100Mhz refclk */ + if (IS_I9XX(pI830)) + i9xx_clock(96000, &clock); + else + i9xx_clock(48000, &clock); + + if (!i830PllIsValid(crtc, &clock)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Bad clock found programmed in pipe %c\n", + pipe == 0 ? 'A' : 'B'); + i830PrintPll("", &clock); + } + + return clock.dot; +} + +/** Returns the currently programmed mode of the given pipe. */ +DisplayModePtr +i830_crtc_mode_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + DisplayModePtr mode; + int htot = INREG((pipe == 0) ? HTOTAL_A : HTOTAL_B); + int hsync = INREG((pipe == 0) ? HSYNC_A : HSYNC_B); + int vtot = INREG((pipe == 0) ? VTOTAL_A : VTOTAL_B); + int vsync = INREG((pipe == 0) ? VSYNC_A : VSYNC_B); + + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (mode == NULL) + return NULL; + + memset(mode, 0, sizeof(*mode)); + + mode->Clock = i830_crtc_clock_get(pScrn, crtc); + mode->HDisplay = (htot & 0xffff) + 1; + mode->HTotal = ((htot & 0xffff0000) >> 16) + 1; + mode->HSyncStart = (hsync & 0xffff) + 1; + mode->HSyncEnd = ((hsync & 0xffff0000) >> 16) + 1; + mode->VDisplay = (vtot & 0xffff) + 1; + mode->VTotal = ((vtot & 0xffff0000) >> 16) + 1; + mode->VSyncStart = (vsync & 0xffff) + 1; + mode->VSyncEnd = ((vsync & 0xffff0000) >> 16) + 1; + xf86SetModeDefaultName(mode); + xf86SetModeCrtc(mode, 0); + + return mode; +} + static const xf86CrtcFuncsRec i830_crtc_funcs = { .dpms = i830_crtc_dpms, .save = NULL, /* XXX */ |