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_lvds.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_lvds.c')
-rw-r--r-- | src/i830_lvds.c | 115 |
1 files changed, 91 insertions, 24 deletions
diff --git a/src/i830_lvds.c b/src/i830_lvds.c index 59af13b9..4c1afb05 100644 --- a/src/i830_lvds.c +++ b/src/i830_lvds.c @@ -32,6 +32,7 @@ #include "xf86.h" #include "i830.h" #include "i830_bios.h" +#include "i830_display.h" #include "X11/Xatom.h" /** @@ -406,21 +407,99 @@ i830_lvds_init(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); xf86OutputPtr output; I830OutputPrivatePtr intel_output; + DisplayModePtr modes, scan, bios_mode; + output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS"); + if (!output) + return; + intel_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1); + if (!intel_output) + { + xf86OutputDestroy (output); + return; + } + intel_output->type = I830_OUTPUT_LVDS; + output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + /* Set up the LVDS DDC channel. Most panels won't support it, but it can + * be useful if available. + */ + I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C"); + + /* Attempt to get the fixed panel mode from DDC. Assume that the preferred + * mode is the right one. + */ + modes = i830_ddc_get_modes(output); + for (scan = modes; scan != NULL; scan = scan->next) { + if (scan->type & M_T_PREFERRED) + break; + } + if (scan != NULL) { + /* Pull our chosen mode out and make it the fixed mode */ + if (modes == scan) + modes = modes->next; + if (scan->prev != NULL) + scan->prev = scan->next; + if (scan->next != NULL) + scan->next = scan->prev; + pI830->panel_fixed_mode = scan; + } + /* Delete the mode list */ + while (modes != NULL) + xf86DeleteMode(&modes, modes); + + /* If we didn't get EDID, try checking if the panel is already turned on. + * If so, assume that whatever is currently programmed is the correct mode. + */ + if (pI830->panel_fixed_mode == NULL) { + CARD32 lvds = INREG(LVDS); + int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = xf86_config->crtc[pipe]; + + if (lvds & LVDS_PORT_EN) { + pI830->panel_fixed_mode = i830_crtc_mode_get(pScrn, crtc); + if (pI830->panel_fixed_mode != NULL) + pI830->panel_fixed_mode->type |= M_T_PREFERRED; + } + } /* Get the LVDS fixed mode out of the BIOS. We should support LVDS with * the BIOS being unavailable or broken, but lack the configuration options * for now. */ - if (!i830GetLVDSInfoFromBIOS(pScrn)) - return; + bios_mode = i830_bios_get_panel_mode(pScrn); + if (bios_mode != NULL) { + if (pI830->panel_fixed_mode != NULL) { + if (!xf86ModesEqual(pI830->panel_fixed_mode, bios_mode)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "BIOS panel mode data doesn't match probed data, " + "continuing with probed.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, bios_mode); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, pI830->panel_fixed_mode); + xfree(bios_mode->name); + xfree(bios_mode); + } + } else { + pI830->panel_fixed_mode = bios_mode; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Couldn't detect panel mode. Disabling panel\n"); + goto disable_exit; + } /* Blacklist machines with BIOSes that list an LVDS panel without actually * having one. */ if (pI830->PciInfo->chipType == PCI_CHIP_I945_GM) { if (pI830->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */ - return; + goto disable_exit; if ((pI830->PciInfo->subsysVendor == 0x8086) && (pI830->PciInfo->subsysCard == 0x7270)) { @@ -435,31 +514,19 @@ i830_lvds_init(ScrnInfoPtr pScrn) if (pI830->panel_fixed_mode != NULL && pI830->panel_fixed_mode->HDisplay == 800 && - pI830->panel_fixed_mode->VDisplay == 600) { + pI830->panel_fixed_mode->VDisplay == 600) + { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Suspected Mac Mini, ignoring the LVDS\n"); - return; + goto disable_exit; } } - } - - output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS"); - if (!output) - return; - intel_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1); - if (!intel_output) - { - xf86OutputDestroy (output); - return; } - intel_output->type = I830_OUTPUT_LVDS; - output->driver_private = intel_output; - output->subpixel_order = SubPixelHorizontalRGB; - output->interlaceAllowed = FALSE; - output->doubleScanAllowed = FALSE; - /* Set up the LVDS DDC channel. Most panels won't support it, but it can - * be useful if available. - */ - I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C"); + return; + +disable_exit: + xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE); + xfree(intel_output); + xf86OutputDestroy(output); } |