xf86-video-intel: Branch 'modesetting' - 2 commits - src/i830_bios.c src/i830_bios.h src/i830_display.c src/i830_display.h src/i830_driver.c src/i830.h src/i830_lvds.c

Eric Anholt anholt at kemper.freedesktop.org
Tue Feb 13 20:25:48 EET 2007


 src/i830.h         |   18 +-------
 src/i830_bios.c    |   26 ++++++-----
 src/i830_bios.h    |    3 -
 src/i830_display.c |   85 +++++++++++++++++++++++++++++++++++++++
 src/i830_display.h |    1 
 src/i830_driver.c  |    2 
 src/i830_lvds.c    |  115 +++++++++++++++++++++++++++++++++++++++++------------
 7 files changed, 196 insertions(+), 54 deletions(-)

New commits:
diff-tree 6641aec0a1cbc869fba1956c556cdd204631545a (from 991439d4c78cf5b2a8f6bb8f5b36fffbfcc4e4fc)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Feb 13 10:21:12 2007 -0800

    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).

diff --git a/src/i830.h b/src/i830.h
index 57d8da1..96972eb 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -590,6 +590,9 @@ extern Bool I830I2CInit(ScrnInfoPtr pScr
 /* return a mask of output indices matching outputs against type_mask */
 int i830_output_clones (ScrnInfoPtr pScrn, int type_mask);
 
+/* i830_bios.c */
+DisplayModePtr i830_bios_get_panel_mode(ScrnInfoPtr pScrn);
+
 /* i830_display.c */
 Bool
 i830PipeHasType (xf86CrtcPtr crtc, int type);
diff --git a/src/i830_bios.c b/src/i830_bios.c
index a9ef474..cb886b5 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -122,8 +122,16 @@ i830GetBIOS(ScrnInfoPtr pScrn)
     return bios;
 }
 
-Bool
-i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn)
+/**
+ * Returns the BIOS's fixed panel mode.
+ *
+ * Note that many BIOSes will have the appropriate tables for a panel even when
+ * a panel is not attached.  Additionally, many BIOSes adjust table sizes or
+ * offsets, such that this parsing fails.  Thus, almost any other method for
+ * detecting the panel mode is preferable.
+ */
+DisplayModePtr
+i830_bios_get_panel_mode(ScrnInfoPtr pScrn)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     struct vbt_header *vbt;
@@ -131,12 +139,11 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
     int vbt_off, bdb_off, bdb_block_off, block_size;
     int panel_type = -1;
     unsigned char *bios;
-    Bool found_panel_info = FALSE;
 
     bios = i830GetBIOS(pScrn);
 
     if (bios == NULL)
-	return FALSE;
+	return NULL;
 
     vbt_off = INTEL_BIOS_16(0x1a);
     vbt = (struct vbt_header *)(bios + vbt_off);
@@ -146,7 +153,7 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
     if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n");
 	xfree(bios);
-	return FALSE;
+	return NULL;
     }
 
     for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
@@ -163,7 +170,6 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
 
 	id = INTEL_BIOS_8(start);
 	block_size = INTEL_BIOS_16(start + 1) + 3;
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found BDB block type %d\n", id);
 	switch (id) {
 	case 40:
 	    lvds1 = (struct lvds_bdb_1 *)(bios + start);
@@ -227,13 +233,11 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
 		       "Found panel mode in BIOS VBT tables:\n");
 	    xf86PrintModeline(pScrn->scrnIndex, fixed_mode);
 
-	    pI830->panel_fixed_mode = fixed_mode;
-
-	    found_panel_info = TRUE;
-	    break;
+	    xfree(bios);
+	    return fixed_mode;
 	}
     }
 
     xfree(bios);
-    return found_panel_info;
+    return NULL;
 }
diff --git a/src/i830_bios.h b/src/i830_bios.h
index 9bd0db8..881d5c8 100644
--- a/src/i830_bios.h
+++ b/src/i830_bios.h
@@ -114,6 +114,3 @@ struct lvds_bdb_2 {
     CARD8 table_size;	/* not sure on this one */
     struct lvds_bdb_2_entry panels[16];
 } __attribute__((packed));
-
-Bool
-i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn);
diff --git a/src/i830_display.c b/src/i830_display.c
index 8202985..345eea9 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1132,6 +1132,91 @@ i830ReleaseLoadDetectPipe(xf86OutputPtr 
     }
 }
 
+/* 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 */
diff --git a/src/i830_display.h b/src/i830_display.h
index dc80055..dbd1ea8 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -39,3 +39,4 @@ xf86CrtcPtr i830GetLoadDetectPipe(xf86Ou
 void i830ReleaseLoadDetectPipe(xf86OutputPtr output);
 void i830_crtc_init(ScrnInfoPtr pScrn, int pipe);
 void i830_crtc_load_lut(xf86CrtcPtr crtc);
+DisplayModePtr i830_crtc_mode_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc);
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 0f66311..cb3dd87 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1332,10 +1332,10 @@ I830PreInit(ScrnInfoPtr pScrn, int flags
    }
 
    I830PreInitDDC(pScrn);
-   I830SetupOutputs(pScrn);
    for (i = 0; i < num_pipe; i++) {
        i830_crtc_init(pScrn, i);
    }
+   I830SetupOutputs(pScrn);
 
    SaveHWState(pScrn);
    /* Do an initial detection of the outputs while none are configured on yet.
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 59af13b..4c1afb0 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);
 }
diff-tree 991439d4c78cf5b2a8f6bb8f5b36fffbfcc4e4fc (from c3aed56d46baba057d83dc6ea12c6b4e705e54ba)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Feb 13 10:07:47 2007 -0800

    Remove dead #if 0-ed structure.

diff --git a/src/i830.h b/src/i830.h
index 42933f9..57d8da1 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -232,21 +232,6 @@ enum last_3d {
     LAST_3D_ROTATION
 };
 
-#if 0
-typedef struct _I830PipeRec {
-   Bool		  enabled;
-   int		  x;
-   int		  y;
-   Bool		  cursorInRange;
-   Bool		  cursorShown;
-   DisplayModeRec curMode;
-   DisplayModeRec desiredMode;
-#ifdef RANDR_12_INTERFACE
-   RRCrtcPtr	  randr_crtc;
-#endif
-} I830PipeRec, *I830PipePtr;
-#endif
-
 typedef struct _I830Rec {
    unsigned char *MMIOBase;
    unsigned char *FbBase;



More information about the xorg-commit mailing list