xf86-video-intel: 2 commits - src/bios_reader/bios_reader.c src/ch7017/ch7017.c src/ch7xxx/ch7xxx.c src/i2c_vid.h src/i830_bios.c src/i830_bios.h src/i830_dvo.c src/i830.h src/i830_lvds.c src/ivch/ivch.c src/ivch/ivch_reg.h src/sil164/sil164.c

Keith Packard keithp at kemper.freedesktop.org
Wed May 16 14:02:04 PDT 2007


 src/bios_reader/bios_reader.c |    9 -
 src/ch7017/ch7017.c           |    2 
 src/ch7xxx/ch7xxx.c           |    2 
 src/i2c_vid.h                 |  136 ++++++++++++++++++++++++++++-
 src/i830.h                    |   11 --
 src/i830_bios.c               |   59 +++++++++++-
 src/i830_bios.h               |   52 ++++++++++-
 src/i830_dvo.c                |  121 ++++++++++++++------------
 src/i830_lvds.c               |  174 ++++++++++++++++++++++---------------
 src/ivch/ivch.c               |  171 ++++++++++++++++++++++++++++++++-----
 src/ivch/ivch_reg.h           |  194 ++++++++++++++++++++++++++++++++++++++++--
 src/sil164/sil164.c           |    2 
 12 files changed, 750 insertions(+), 183 deletions(-)

New commits:
diff-tree c0daa0a982e7074af4b50653b4a45b0a6352b43d (from b28817a87a1608e849e4a9a736dda43533a84b0c)
Author: Keith Packard <keithp at dulcimer.keithp.com>
Date:   Wed May 16 14:02:00 2007 -0700

    Change DVO module interface to pass more state across. Fix IVCH display.
    
    The DVO module interface reflected most of the xf86Output API to the
    underlying functions; finish that work given the changes that have since
    occurred in the xf86Output API.
    
    Move the LVDS-specific code into the IVCH module and make that work on the
    Thinkpad X30 (an i830-based laptop). Panel scaling does not work yet.

diff --git a/src/ch7017/ch7017.c b/src/ch7017/ch7017.c
index 7070c7d..8e3a6ef 100644
--- a/src/ch7017/ch7017.c
+++ b/src/ch7017/ch7017.c
@@ -144,7 +144,7 @@ ch7017_mode_valid(I2CDevPtr d, DisplayMo
 }
 
 static void
-ch7017_mode_set(I2CDevPtr d, DisplayModePtr mode)
+ch7017_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
     struct ch7017_priv *priv = d->DriverPrivate.ptr;
     CARD8 lvds_pll_feedback_div, lvds_pll_vco_control;
diff --git a/src/ch7xxx/ch7xxx.c b/src/ch7xxx/ch7xxx.c
index 0a96555..09a9627 100644
--- a/src/ch7xxx/ch7xxx.c
+++ b/src/ch7xxx/ch7xxx.c
@@ -206,7 +206,7 @@ ch7xxx_mode_valid(I2CDevPtr d, DisplayMo
 }
 
 static void
-ch7xxx_mode_set(I2CDevPtr d, DisplayModePtr mode)
+ch7xxx_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
     struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr;
     CARD8 tvco, tpcp, tpd, tlpf, idf;
diff --git a/src/i2c_vid.h b/src/i2c_vid.h
index 3be394d..1a21fca 100644
--- a/src/i2c_vid.h
+++ b/src/i2c_vid.h
@@ -1,16 +1,142 @@
-/* this needs to go in the server */
+/*
+ * Copyright © 2006 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
 #ifndef I2C_VID_H
 #define I2C_VID_H
+#include <randrstr.h>
 
 typedef struct _I830I2CVidOutputRec {
+    /**
+     * Initialize the device at startup time.
+     * Returns NULL if the device does not exist.
+     */
     void *(*init)(I2CBusPtr b, I2CSlaveAddr addr);
-    xf86OutputStatus (*detect)(I2CDevPtr d);
-    ModeStatus (*mode_valid)(I2CDevPtr d, DisplayModePtr mode);
-    void (*mode_set)(I2CDevPtr d, DisplayModePtr mode);
+    
+    /**
+     * Setup the device for use, after the relevant output has been created
+     */
+    Bool
+    (*setup) (I2CDevPtr d, xf86OutputPtr output);
+
+    /**
+     * Called to allow the output a chance to create properties after the
+     * RandR objects have been created.
+     */
+    void
+    (*create_resources)(I2CDevPtr d);
+
+    /**
+     * Turns the output on/off, or sets intermediate power levels if available.
+     *
+     * Unsupported intermediate modes drop to the lower power setting.  If the
+     * mode is DPMSModeOff, the output must be disabled, as the DPLL may be
+     * disabled afterwards.
+     */
     void (*dpms)(I2CDevPtr d, int mode);
-    void (*dump_regs)(I2CDevPtr d);
+    
+    /**
+     * Saves the output's state for restoration on VT switch.
+     */
     void (*save)(I2CDevPtr d);
+
+    /**
+     * Restore's the output's state at VT switch.
+     */
     void (*restore)(I2CDevPtr d);
+
+    /**
+     * Callback for testing a video mode for a given output.
+     *
+     * This function should only check for cases where a mode can't be supported
+     * on the output specifically, and not represent generic CRTC limitations.
+     *
+     * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
+     */
+    int (*mode_valid)(I2CDevPtr d, DisplayModePtr mode);
+
+    /**
+     * Callback to adjust the mode to be set in the CRTC.
+     *
+     * This allows an output to adjust the clock or even the entire set of
+     * timings, which is used for panels with fixed timings or for
+     * buses with clock limitations.
+     */
+    Bool (*mode_fixup)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode);
+
+    /**
+     * Callback for preparing mode changes on an output
+     */
+    void (*prepare)(I2CDevPtr d);
+
+    /**
+     * Callback for committing mode changes on an output
+     */
+    void (*commit)(I2CDevPtr d);
+    
+    /**
+     * Callback for setting up a video mode after fixups have been made.
+     *
+     * This is only called while the output is disabled.  The dpms callback
+     * must be all that's necessary for the output, to turn the output on
+     * after this function is called.
+     */
+    void (*mode_set)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode);
+    
+    /**
+     * Probe for a connected output, and return detect_status.
+     */
+    xf86OutputStatus (*detect)(I2CDevPtr d);
+
+    /**
+     * Query the device for the modes it provides.
+     *
+     * This function may also update MonInfo, mm_width, and mm_height.
+     *
+     * \return singly-linked list of modes or NULL if no modes found.
+     */
+    DisplayModePtr
+    (*get_modes)(I2CDevPtr d);
+    
+#ifdef RANDR_12_INTERFACE
+    /**
+     * Callback when an output's property has changed.
+     */
+    Bool
+    (*set_property)(I2CDevPtr d, Atom property, RRPropertyValuePtr value);
+#endif
+
+    /**
+     * Clean up driver-specific bits of the output
+     */
+    void (*destroy) (I2CDevPtr d);
+
+    /**
+     * Debugging hook to dump device registers to log file
+     */
+    void (*dump_regs)(I2CDevPtr d);
 } I830I2CVidOutputRec, *I830I2CVidOutputPtr;
 
+/* XXX change this name to avoid driver-specific prefix */
+DisplayModePtr
+i830_dvo_get_current_mode (xf86OutputPtr output);
+
 #endif
diff --git a/src/i830.h b/src/i830.h
index c91be79..0fe5d41 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -205,6 +205,7 @@ struct _I830DVODriver {
    int type;
    char *modulename;
    char *fntablename;
+   unsigned int dvo_reg;
    int address;
    const char **symbols;
    I830I2CVidOutputRec *vid_rec;
@@ -466,13 +467,6 @@ typedef struct _I830Rec {
 
    int ddc2;
 
-   /* The BIOS's fixed timings for the LVDS */
-   DisplayModePtr panel_fixed_mode;
-
-   int backlight_duty_cycle;  /* restore backlight to this value */
-   
-   Bool panel_wants_dither;
-
    CARD32 saveDSPACNTR;
    CARD32 saveDSPBCNTR;
    CARD32 savePIPEACONF;
@@ -637,9 +631,6 @@ 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_dvo.c b/src/i830_dvo.c
index 129651c..b69105e 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -60,11 +60,11 @@ static const char *ch7017_symbols[] = {
 /* driver list */
 struct _I830DVODriver i830_dvo_drivers[] =
 {
-    {I830_DVO_CHIP_TMDS, "sil164", "SIL164VidOutput",
+    {I830_DVO_CHIP_TMDS, "sil164", "SIL164VidOutput", DVOC,
      (SIL164_ADDR_1<<1), SIL164Symbols, NULL , NULL, NULL},
-    {I830_DVO_CHIP_TMDS | I830_DVO_CHIP_TVOUT, "ch7xxx", "CH7xxxVidOutput",
+    {I830_DVO_CHIP_TMDS | I830_DVO_CHIP_TVOUT, "ch7xxx", "CH7xxxVidOutput", DVOC,
      (CH7xxx_ADDR_1<<1), CH7xxxSymbols, NULL , NULL, NULL},
-    {I830_DVO_CHIP_LVDS, "ivch", "ivch_methods",
+    {I830_DVO_CHIP_LVDS, "ivch", "ivch_methods", DVOA,
      0x04, ivch_symbols, NULL, NULL, NULL},
     /*
     {I830_DVO_CHIP_LVDS, "ivch", "ivch_methods",
@@ -88,20 +88,18 @@ i830_dvo_dpms(xf86OutputPtr output, int 
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    void *		    dev_priv = intel_output->i2c_drv->dev_priv;
-    unsigned int	    dvo_reg;
-
-    if (intel_output->i2c_drv->type & I830_DVO_CHIP_LVDS)
-	dvo_reg = DVOA;
-    else
-	dvo_reg = DVOC;
+    struct _I830DVODriver   *drv = intel_output->i2c_drv;
+    void *		    dev_priv = drv->dev_priv;
+    unsigned int	    dvo_reg = drv->dvo_reg;
 
     if (mode == DPMSModeOn) {
 	OUTREG(dvo_reg, INREG(dvo_reg) | DVO_ENABLE);
+	POSTING_READ(dvo_reg);
 	(*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode);
     } else {
 	(*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode);
 	OUTREG(dvo_reg, INREG(dvo_reg) & ~DVO_ENABLE);
+	POSTING_READ(dvo_reg);
     }
 }
 
@@ -131,18 +129,18 @@ i830_dvo_restore(xf86OutputPtr output)
     I830OutputPrivatePtr    intel_output = output->driver_private;
     void *		    dev_priv = intel_output->i2c_drv->dev_priv;
 
+    (*intel_output->i2c_drv->vid_rec->restore)(dev_priv);
+
     OUTREG(DVOA, pI830->saveDVOA);
     OUTREG(DVOB, pI830->saveDVOB);
     OUTREG(DVOC, pI830->saveDVOC);
-
-    (*intel_output->i2c_drv->vid_rec->restore)(dev_priv);
 }
 
 static int
 i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 {
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    void *dev_priv = intel_output->i2c_drv->dev_priv;
+    void		    *dev_priv = intel_output->i2c_drv->dev_priv;
 
     if (pMode->Flags & V_DBLSCAN)
 	return MODE_NO_DBLESCAN;
@@ -156,8 +154,11 @@ static Bool
 i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		    DisplayModePtr adjusted_mode)
 {
-    /* XXX: Hook this up to a DVO driver function */
+    I830OutputPrivatePtr    intel_output = output->driver_private;
 
+    if (intel_output->i2c_drv->vid_rec->mode_fixup)
+	return intel_output->i2c_drv->vid_rec->mode_fixup (intel_output->i2c_drv->dev_priv,
+							   mode, adjusted_mode);
     return TRUE;
 }
 
@@ -170,21 +171,26 @@ i830_dvo_mode_set(xf86OutputPtr output, 
     xf86CrtcPtr	    crtc = output->crtc;
     I830CrtcPrivatePtr	    intel_crtc = crtc->driver_private;
     I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct _I830DVODriver   *drv = intel_output->i2c_drv;
     int			    pipe = intel_crtc->pipe;
     CARD32		    dvo;
-    unsigned int	    dvo_reg, dvo_srcdim_reg;
+    unsigned int	    dvo_reg = drv->dvo_reg, dvo_srcdim_reg;
     int			    dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
 
-    if (intel_output->i2c_drv->type & I830_DVO_CHIP_LVDS) {
-	dvo_reg = DVOA;
+    switch (dvo_reg) {
+    case DVOA:
 	dvo_srcdim_reg = DVOA_SRCDIM;
-    } else {
-	dvo_reg = DVOC;
+	break;
+    case DVOB:
+	dvo_srcdim_reg = DVOB_SRCDIM;
+	break;
+    case DVOC:
 	dvo_srcdim_reg = DVOC_SRCDIM;
+	break;
     }
 
     intel_output->i2c_drv->vid_rec->mode_set(intel_output->i2c_drv->dev_priv,
-					     mode);
+					     mode, adjusted_mode);
 
     /* Save the data order, since I don't know what it should be set to. */
     dvo = INREG(dvo_reg) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
@@ -227,8 +233,6 @@ i830_dvo_detect(xf86OutputPtr output)
 static DisplayModePtr
 i830_dvo_get_modes(xf86OutputPtr output)
 {
-    ScrnInfoPtr		    pScrn = output->scrn;
-    I830Ptr		    pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
     DisplayModePtr	    modes;
 
@@ -241,11 +245,11 @@ i830_dvo_get_modes(xf86OutputPtr output)
     if (modes != NULL)
 	return modes;
 
-    if (intel_output->i2c_drv->type & I830_DVO_CHIP_LVDS &&
-	pI830->panel_fixed_mode != NULL)
+    if (intel_output->i2c_drv->vid_rec->get_modes)
     {
-	xf86PrintModeline(pScrn->scrnIndex, pI830->panel_fixed_mode);
-	return xf86DuplicateMode(pI830->panel_fixed_mode);
+	modes = intel_output->i2c_drv->vid_rec->get_modes (intel_output->i2c_drv->dev_priv);
+	if (modes != NULL)
+	    return modes;
     }
 
     return NULL;
@@ -258,11 +262,12 @@ i830_dvo_destroy (xf86OutputPtr output)
 
     if (intel_output)
     {
+	if (intel_output->i2c_drv->vid_rec->destroy)
+	    intel_output->i2c_drv->vid_rec->destroy (intel_output->i2c_drv->dev_priv);
 	if (intel_output->pI2CBus)
 	    xf86DestroyI2CBusRec (intel_output->pI2CBus, TRUE, TRUE);
 	if (intel_output->pDDCBus)
 	    xf86DestroyI2CBusRec (intel_output->pDDCBus, TRUE, TRUE);
-	/* XXX sub module cleanup? */
 	xfree (intel_output);
     }
 }
@@ -287,35 +292,49 @@ static const xf86OutputFuncsRec i830_dvo
  * Other chips with DVO LVDS will need to extend this to deal with the LVDS
  * chip being on DVOB/C and having multiple pipes.
  */
-static void
-i830_dvo_get_panel_timings(xf86OutputPtr output)
+DisplayModePtr
+i830_dvo_get_current_mode (xf86OutputPtr output)
 {
     ScrnInfoPtr		    pScrn = output->scrn;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
     I830Ptr		    pI830 = I830PTR(pScrn);
-    CARD32 dvoa = INREG(DVOA);
-
-    if (!IS_I830(pI830))
-	return;
+    struct _I830DVODriver   *drv = intel_output->i2c_drv;
+    unsigned int	    dvo_reg = drv->dvo_reg;
+    CARD32		    dvo = INREG(dvo_reg);
+    DisplayModePtr    	    mode = NULL;
 
-    assert(pI830->fixed_panel_mode == NULL);
-
-    /* If the DVOA port is active, that'll be the LVDS, so we can pull out
+    /* If the DVO port is active, that'll be the LVDS, so we can pull out
      * its timings to get how the BIOS set up the panel.
      */
-    if (dvoa & DVO_ENABLE) {
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
-	int pipe = (dvoa & DVO_PIPE_B_SELECT) ? 1 : 0;
-	xf86CrtcPtr crtc = xf86_config->crtc[pipe];
-
-	pI830->panel_fixed_mode = i830_crtc_mode_get(pScrn, crtc);
-	if (pI830->panel_fixed_mode != NULL)
-	    pI830->panel_fixed_mode->type |= M_T_PREFERRED;
-
-	if (dvoa & DVO_HSYNC_ACTIVE_HIGH)
-	    pI830->panel_fixed_mode->Flags |= V_PHSYNC;
-	if (dvoa & DVO_VSYNC_ACTIVE_HIGH)
-	    pI830->panel_fixed_mode->Flags |= V_PVSYNC;
+    if (dvo & DVO_ENABLE) 
+    {
+	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	int		    pipe = (dvo & DVO_PIPE_B_SELECT) ? 1 : 0;
+	int		    c;
+
+	for (c = 0; c < xf86_config->num_crtc; c++)
+	{
+	    xf86CrtcPtr		crtc = xf86_config->crtc[c];
+	    I830CrtcPrivatePtr	intel_crtc = crtc->driver_private;
+
+	    if (intel_crtc->pipe == pipe)
+	    {
+		mode = i830_crtc_mode_get(pScrn, crtc);
+
+		if (mode)
+		{
+		    mode->type |= M_T_PREFERRED;
+
+		    if (dvo & DVO_HSYNC_ACTIVE_HIGH)
+			mode->Flags |= V_PHSYNC;
+		    if (dvo & DVO_VSYNC_ACTIVE_HIGH)
+			mode->Flags |= V_PVSYNC;
+		}
+		break;
+	    }
+	}
     }
+    return mode;
 }
 
 void
@@ -394,9 +413,6 @@ i830_dvo_init(ScrnInfoPtr pScrn)
 		return;
 	    }
 
-	    if (drv->type & I830_DVO_CHIP_LVDS)
-		i830_dvo_get_panel_timings(output);
-
 	    output->driver_private = intel_output;
 	    output->subpixel_order = SubPixelHorizontalRGB;
 	    output->interlaceAllowed = FALSE;
@@ -405,6 +421,7 @@ i830_dvo_init(ScrnInfoPtr pScrn)
 	    drv->dev_priv = ret_ptr;
 	    intel_output->i2c_drv = drv;
 	    intel_output->pI2CBus = pI2CBus;
+	    drv->vid_rec->setup (drv->dev_priv, output);
 	    return;
 	}
 	xf86UnloadSubModule(drv->modhandle);
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index d16eccb..e909812 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -35,14 +35,27 @@
 #include "i830_display.h"
 #include "X11/Xatom.h"
 
+struct i830_lvds_priv {
+    /* The BIOS's fixed timings for the LVDS */
+    DisplayModePtr panel_fixed_mode;
+    
+    /* The panel needs dithering enabled */
+    Bool	    panel_wants_dither;
+
+    /* restore backlight to this value */
+    int		    backlight_duty_cycle;
+};
+
+
 /**
  * Sets the backlight level.
  *
  * \param level backlight level, from 0 to i830_lvds_get_max_backlight().
  */
 static void
-i830_lvds_set_backlight(ScrnInfoPtr pScrn, int level)
+i830_lvds_set_backlight(xf86OutputPtr output, int level)
 {
+    ScrnInfoPtr pScrn = output->scrn;
     I830Ptr pI830 = I830PTR(pScrn);
     CARD32 blc_pwm_ctl;
 
@@ -54,9 +67,10 @@ i830_lvds_set_backlight(ScrnInfoPtr pScr
  * Returns the maximum level of the backlight duty cycle field.
  */
 static CARD32
-i830_lvds_get_max_backlight(ScrnInfoPtr pScrn)
+i830_lvds_get_max_backlight(xf86OutputPtr output)
 {
-    I830Ptr pI830 = I830PTR(pScrn);
+    ScrnInfoPtr pScrn = output->scrn;
+    I830Ptr	pI830 = I830PTR(pScrn);
     
     return ((INREG(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
 	BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
@@ -66,10 +80,13 @@ i830_lvds_get_max_backlight(ScrnInfoPtr 
  * Sets the power state for the panel.
  */
 static void
-i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
+i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
 {
-    I830Ptr pI830 = I830PTR(pScrn);
-    CARD32 pp_status;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
+    CARD32		    pp_status;
 
     if (on) {
 	OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
@@ -77,9 +94,9 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn,
 	    pp_status = INREG(PP_STATUS);
 	} while ((pp_status & PP_ON) == 0);
 
-	i830_lvds_set_backlight(pScrn, pI830->backlight_duty_cycle);
+	i830_lvds_set_backlight(output, dev_priv->backlight_duty_cycle);
     } else {
-	i830_lvds_set_backlight(pScrn, 0);
+	i830_lvds_set_backlight(output, 0);
 
 	OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
 	do {
@@ -91,12 +108,10 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn,
 static void
 i830_lvds_dpms (xf86OutputPtr output, int mode)
 {
-    ScrnInfoPtr	pScrn = output->scrn;
-
     if (mode == DPMSModeOn)
-	i830SetLVDSPanelPower(pScrn, TRUE);
+	i830SetLVDSPanelPower(output, TRUE);
     else
-	i830SetLVDSPanelPower(pScrn, FALSE);
+	i830SetLVDSPanelPower(output, FALSE);
 
     /* XXX: We never power down the LVDS pairs. */
 }
@@ -104,22 +119,24 @@ i830_lvds_dpms (xf86OutputPtr output, in
 static void
 i830_lvds_save (xf86OutputPtr output)
 {
-    ScrnInfoPtr	pScrn = output->scrn;
-    I830Ptr	pI830 = I830PTR(pScrn);
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
 
     pI830->savePP_ON = INREG(LVDSPP_ON);
     pI830->savePP_OFF = INREG(LVDSPP_OFF);
     pI830->savePP_CONTROL = INREG(PP_CONTROL);
     pI830->savePP_CYCLE = INREG(PP_CYCLE);
     pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
-    pI830->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
-				   BACKLIGHT_DUTY_CYCLE_MASK);
+    dev_priv->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
+				      BACKLIGHT_DUTY_CYCLE_MASK);
 
     /*
      * If the light is off at server startup, just make it full brightness
      */
-    if (pI830->backlight_duty_cycle == 0)
-	pI830->backlight_duty_cycle = i830_lvds_get_max_backlight(pScrn);
+    if (dev_priv->backlight_duty_cycle == 0)
+	dev_priv->backlight_duty_cycle = i830_lvds_get_max_backlight(output);
 }
 
 static void
@@ -134,17 +151,17 @@ i830_lvds_restore(xf86OutputPtr output)
     OUTREG(PP_CYCLE, pI830->savePP_CYCLE);
     OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
     if (pI830->savePP_CONTROL & POWER_TARGET_ON)
-	i830SetLVDSPanelPower(pScrn, TRUE);
+	i830SetLVDSPanelPower(output, TRUE);
     else
-	i830SetLVDSPanelPower(pScrn, FALSE);
+	i830SetLVDSPanelPower(output, FALSE);
 }
 
 static int
 i830_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 {
-    ScrnInfoPtr pScrn = output->scrn;
-    I830Ptr pI830 = I830PTR(pScrn);
-    DisplayModePtr  pFixedMode = pI830->panel_fixed_mode;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    DisplayModePtr	    pFixedMode = dev_priv->panel_fixed_mode;
 
     if (pFixedMode)
     {
@@ -161,10 +178,11 @@ static Bool
 i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		     DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr pScrn = output->scrn;
-    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
-    I830Ptr pI830 = I830PTR(pScrn);
-    I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    xf86CrtcConfigPtr	    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    I830CrtcPrivatePtr	    intel_crtc = output->crtc->driver_private;
     int i;
 
     for (i = 0; i < xf86_config->num_output; i++) {
@@ -189,16 +207,16 @@ i830_lvds_mode_fixup(xf86OutputPtr outpu
      * with the panel scaling set up to source from the H/VDisplay
      * of the original mode.
      */
-    if (pI830->panel_fixed_mode != NULL) {
-	adjusted_mode->HDisplay = pI830->panel_fixed_mode->HDisplay;
-	adjusted_mode->HSyncStart = pI830->panel_fixed_mode->HSyncStart;
-	adjusted_mode->HSyncEnd = pI830->panel_fixed_mode->HSyncEnd;
-	adjusted_mode->HTotal = pI830->panel_fixed_mode->HTotal;
-	adjusted_mode->VDisplay = pI830->panel_fixed_mode->VDisplay;
-	adjusted_mode->VSyncStart = pI830->panel_fixed_mode->VSyncStart;
-	adjusted_mode->VSyncEnd = pI830->panel_fixed_mode->VSyncEnd;
-	adjusted_mode->VTotal = pI830->panel_fixed_mode->VTotal;
-	adjusted_mode->Clock = pI830->panel_fixed_mode->Clock;
+    if (dev_priv->panel_fixed_mode != NULL) {
+	adjusted_mode->HDisplay = dev_priv->panel_fixed_mode->HDisplay;
+	adjusted_mode->HSyncStart = dev_priv->panel_fixed_mode->HSyncStart;
+	adjusted_mode->HSyncEnd = dev_priv->panel_fixed_mode->HSyncEnd;
+	adjusted_mode->HTotal = dev_priv->panel_fixed_mode->HTotal;
+	adjusted_mode->VDisplay = dev_priv->panel_fixed_mode->VDisplay;
+	adjusted_mode->VSyncStart = dev_priv->panel_fixed_mode->VSyncStart;
+	adjusted_mode->VSyncEnd = dev_priv->panel_fixed_mode->VSyncEnd;
+	adjusted_mode->VTotal = dev_priv->panel_fixed_mode->VTotal;
+	adjusted_mode->Clock = dev_priv->panel_fixed_mode->Clock;
 	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
     }
 
@@ -214,10 +232,12 @@ static void
 i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 		   DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr pScrn = output->scrn;
-    I830Ptr pI830 = I830PTR(pScrn);
-    I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private;
-    CARD32 pfit_control;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
+    I830CrtcPrivatePtr	    intel_crtc = output->crtc->driver_private;
+    CARD32		    pfit_control;
 
     /* The LVDS pin pair will already have been turned on in the
      * i830_crtc_mode_set since it has a large impact on the DPLL settings.
@@ -232,7 +252,7 @@ i830_lvds_mode_set(xf86OutputPtr output,
 		    VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
 
     if (!IS_I965G(pI830)) {
-	if (pI830->panel_wants_dither)
+	if (dev_priv->panel_wants_dither)
 	    pfit_control |= PANEL_8TO6_DITHER_ENABLE;
     } else {
 	pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
@@ -260,8 +280,7 @@ static DisplayModePtr
 i830_lvds_get_modes(xf86OutputPtr output)
 {
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    ScrnInfoPtr		    pScrn = output->scrn;
-    I830Ptr		    pI830 = I830PTR(pScrn);
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
     xf86MonPtr		    edid_mon;
     DisplayModePtr	    modes;
 
@@ -290,8 +309,8 @@ i830_lvds_get_modes(xf86OutputPtr output
 	}
     }
 
-    if (pI830->panel_fixed_mode != NULL)
-	return xf86DuplicateMode(pI830->panel_fixed_mode);
+    if (dev_priv->panel_fixed_mode != NULL)
+	return xf86DuplicateMode(dev_priv->panel_fixed_mode);
 
     return NULL;
 }
@@ -302,7 +321,12 @@ i830_lvds_destroy (xf86OutputPtr output)
     I830OutputPrivatePtr    intel_output = output->driver_private;
 
     if (intel_output)
+    {
+	struct i830_lvds_priv	*dev_priv = intel_output->dev_priv;
+	
+        xf86DeleteMode (&dev_priv->panel_fixed_mode, dev_priv->panel_fixed_mode);
 	xfree (intel_output);
+    }
 }
 
 #ifdef RANDR_12_INTERFACE
@@ -314,10 +338,11 @@ static void
 i830_lvds_create_resources(xf86OutputPtr output)
 {
 #ifdef RANDR_12_INTERFACE
-    ScrnInfoPtr pScrn = output->scrn;
-    I830Ptr pI830 = I830PTR(pScrn);
-    INT32 range[2];
-    int data, err;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    INT32		    range[2];
+    int			    data, err;
 
     /* Set up the backlight property, which takes effect immediately
      * and accepts values only within the range.
@@ -329,7 +354,7 @@ i830_lvds_create_resources(xf86OutputPtr
 	TRUE);
 
     range[0] = 0;
-    range[1] = i830_lvds_get_max_backlight(pScrn);
+    range[1] = i830_lvds_get_max_backlight(output);
     err = RRConfigureOutputProperty(output->randr_output, backlight_atom,
 				    FALSE, TRUE, FALSE, 2, range);
     if (err != 0) {
@@ -337,7 +362,7 @@ i830_lvds_create_resources(xf86OutputPtr
 		   "RRConfigureOutputProperty error, %d\n", err);
     }
     /* Set the current value of the backlight property */
-    data = pI830->backlight_duty_cycle;
+    data = dev_priv->backlight_duty_cycle;
     err = RRChangeOutputProperty(output->randr_output, backlight_atom,
 				 XA_INTEGER, 32, PropModeReplace, 1, &data,
 				 FALSE, TRUE);
@@ -354,8 +379,8 @@ static Bool
 i830_lvds_set_property(xf86OutputPtr output, Atom property,
 		       RRPropertyValuePtr value)
 {
-    ScrnInfoPtr pScrn = output->scrn;
-    I830Ptr pI830 = I830PTR(pScrn);
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
     
     if (property == backlight_atom) {
 	INT32 val;
@@ -367,13 +392,13 @@ i830_lvds_set_property(xf86OutputPtr out
 	}
 
 	val = *(INT32 *)value->data;
-	if (val < 0 || val > i830_lvds_get_max_backlight(pScrn))
+	if (val < 0 || val > i830_lvds_get_max_backlight(output))
 	    return FALSE;
 
-	if (val != pI830->backlight_duty_cycle)
+	if (val != dev_priv->backlight_duty_cycle)
 	{
-	    i830_lvds_set_backlight(pScrn, val);
-	    pI830->backlight_duty_cycle = val;
+	    i830_lvds_set_backlight(output, val);
+	    dev_priv->backlight_duty_cycle = val;
 	}
 	return TRUE;
     }
@@ -407,11 +432,13 @@ i830_lvds_init(ScrnInfoPtr pScrn)
     xf86OutputPtr	    output;
     I830OutputPrivatePtr    intel_output;
     DisplayModePtr	    modes, scan, bios_mode;
+    struct i830_lvds_priv   *dev_priv;
 
     output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS");
     if (!output)
 	return;
-    intel_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1);
+    intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) + 
+			      sizeof (struct i830_lvds_priv), 1);
     if (!intel_output)
     {
 	xf86OutputDestroy (output);
@@ -423,6 +450,9 @@ i830_lvds_init(ScrnInfoPtr pScrn)
     output->interlaceAllowed = FALSE;
     output->doubleScanAllowed = FALSE;
 
+    dev_priv = (struct i830_lvds_priv *) (intel_output + 1);
+    intel_output->dev_priv = dev_priv;
+
     /* Set up the LVDS DDC channel.  Most panels won't support it, but it can
      * be useful if available.
      */
@@ -444,7 +474,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 	    scan->prev = scan->next;
 	if (scan->next != NULL)
 	    scan->next = scan->prev;
-	pI830->panel_fixed_mode = scan;
+	dev_priv->panel_fixed_mode = scan;
     }
     /* Delete the mode list */
     while (modes != NULL)
@@ -453,16 +483,16 @@ i830_lvds_init(ScrnInfoPtr pScrn)
     /* 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) {
+    if (dev_priv->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;
+	    dev_priv->panel_fixed_mode = i830_crtc_mode_get(pScrn, crtc);
+	    if (dev_priv->panel_fixed_mode != NULL)
+		dev_priv->panel_fixed_mode->type |= M_T_PREFERRED;
 	}
     }
 
@@ -470,11 +500,11 @@ i830_lvds_init(ScrnInfoPtr pScrn)
      * the BIOS being unavailable or broken, but lack the configuration options
      * for now.
      */
-    bios_mode = i830_bios_get_panel_mode(pScrn);
+    bios_mode = i830_bios_get_panel_mode(pScrn, &dev_priv->panel_wants_dither);
     if (bios_mode != NULL) {
-	if (pI830->panel_fixed_mode != NULL) {
+	if (dev_priv->panel_fixed_mode != NULL) {
 	    if (pI830->debug_modes &&
-		!xf86ModesEqual(pI830->panel_fixed_mode, bios_mode))
+		!xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode))
 	    {
 		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
 			   "BIOS panel mode data doesn't match probed data, "
@@ -482,12 +512,12 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 		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);
+		xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode);
 		xfree(bios_mode->name);
 		xfree(bios_mode);
 	    }
 	}  else {
-	    pI830->panel_fixed_mode = bios_mode;
+	    dev_priv->panel_fixed_mode = bios_mode;
 	}
     } else {
 	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
@@ -513,9 +543,9 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 	     * display.
 	     */
 
-	    if (pI830->panel_fixed_mode != NULL &&
-		pI830->panel_fixed_mode->HDisplay == 800 &&
-		pI830->panel_fixed_mode->VDisplay == 600)
+	    if (dev_priv->panel_fixed_mode != NULL &&
+		dev_priv->panel_fixed_mode->HDisplay == 800 &&
+		dev_priv->panel_fixed_mode->VDisplay == 600)
 	    {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 			   "Suspected Mac Mini, ignoring the LVDS\n");
diff --git a/src/ivch/ivch.c b/src/ivch/ivch.c
index efc74f8..a76e339 100644
--- a/src/ivch/ivch.c
+++ b/src/ivch/ivch.c
@@ -38,17 +38,42 @@
 #include "xf86Crtc.h"
 #define DPMS_SERVER
 #include <X11/extensions/dpms.h>
+#include <unistd.h>
 
 #include "../i2c_vid.h"
+#include "../i830_bios.h"
 #include "ivch_reg.h"
 
 struct ivch_priv {
-    I2CDevRec d;
+    I2CDevRec	    d;
 
-    CARD16 save_VR01;
-    CARD16 save_VR40;
+    xf86OutputPtr   output;
+
+    DisplayModePtr  panel_fixed_mode;
+    Bool	    panel_wants_dither;
+
+    CARD16    	    width;
+    CARD16    	    height;
+
+    CARD16	    save_VR01;
+    CARD16	    save_VR40;
 };
 
+struct vch_capabilities {
+    struct aimdb_block	aimdb_block;
+    CARD8		panel_type;
+    CARD8		set_panel_type;
+    CARD8		slave_address;
+    CARD8		capabilities;
+#define VCH_PANEL_FITTING_SUPPORT	(0x3 << 0)
+#define VCH_PANEL_FITTING_TEXT		(1 << 2)
+#define VCH_PANEL_FITTING_GRAPHICS	(1 << 3)
+#define VCH_PANEL_FITTING_RATIO		(1 << 4)
+#define VCH_DITHERING			(1 << 5)
+    CARD8		backlight_gpio;
+    CARD8		set_panel_type_us_gpios;
+} __attribute__ ((packed));
+
 static void
 ivch_dump_regs(I2CDevPtr d);
 
@@ -129,8 +154,8 @@ ivch_write(struct ivch_priv *priv, int a
 static void *
 ivch_init(I2CBusPtr b, I2CSlaveAddr addr)
 {
-    struct ivch_priv *priv;
-    CARD16 temp;
+    struct	ivch_priv *priv;
+    CARD16	temp;
 
     xf86DrvMsg(b->scrnIndex, X_INFO, "detecting ivch\n");
 
@@ -138,6 +163,7 @@ ivch_init(I2CBusPtr b, I2CSlaveAddr addr
     if (priv == NULL)
 	return NULL;
 
+    priv->output = NULL;
     priv->d.DevName = "i82807aa \"ivch\" LVDS/CMOS panel controller";
     priv->d.SlaveAddr = addr;
     priv->d.pI2CBus = b;
@@ -165,6 +191,10 @@ ivch_init(I2CBusPtr b, I2CSlaveAddr addr
 	goto out;
     }
 
+    ivch_read (priv, VR01, &temp); xf86DrvMsg (priv->d.pI2CBus->scrnIndex, X_INFO,
+					       "ivch VR01 0x%x\n", temp);
+    ivch_read (priv, VR40, &temp); xf86DrvMsg (priv->d.pI2CBus->scrnIndex, X_INFO,
+					       "ivch VR40 0x%x\n", temp);
     return priv;
 
 out:
@@ -172,18 +202,58 @@ out:
     return NULL;
 }
 
+/** Gets the panel mode */
+static Bool
+ivch_setup (I2CDevPtr d, xf86OutputPtr output)
+{
+    struct ivch_priv	*priv = d->DriverPrivate.ptr;
+
+    priv->output = output;
+    ivch_read (priv, VR20, &priv->width);
+    ivch_read (priv, VR21, &priv->height);
+    
+    priv->panel_fixed_mode = i830_bios_get_panel_mode (output->scrn, &priv->panel_wants_dither);
+    if (!priv->panel_fixed_mode)
+    {
+	priv->panel_fixed_mode = i830_dvo_get_current_mode (output);
+	priv->panel_wants_dither = TRUE;
+    }
+
+    return TRUE;
+}
+
 static xf86OutputStatus
 ivch_detect(I2CDevPtr d)
 {
     return XF86OutputStatusUnknown;
 }
 
+static DisplayModePtr
+ivch_get_modes (I2CDevPtr d)
+{
+    struct ivch_priv	*priv = d->DriverPrivate.ptr;
+
+    if (priv->panel_fixed_mode)
+	return xf86DuplicateMode (priv->panel_fixed_mode);
+
+    return NULL;
+}
+
 static ModeStatus
 ivch_mode_valid(I2CDevPtr d, DisplayModePtr mode)
 {
+    struct ivch_priv	*priv = d->DriverPrivate.ptr;
+    DisplayModePtr	panel_fixed_mode = priv->panel_fixed_mode;
+    
     if (mode->Clock > 112000)
 	return MODE_CLOCK_HIGH;
 
+    if (panel_fixed_mode)
+    {
+	if (!xf86ModesEqual (mode, panel_fixed_mode))
+	    return MODE_PANEL;
+    }
+    
     return MODE_OK;
 }
 
@@ -193,37 +263,68 @@ ivch_dpms(I2CDevPtr d, int mode)
 {
     struct ivch_priv *priv = d->DriverPrivate.ptr;
     int i;
-    CARD16 temp;
+    CARD16 vr01, vr30, backlight;
 
     /* Set the new power state of the panel. */
-    if (!ivch_read(priv, VR01, &temp))
+    if (!ivch_read(priv, VR01, &vr01))
 	return;
 
     if (mode == DPMSModeOn)
-	temp |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
+	backlight = 1;
     else
-	temp &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
+	backlight = 0;
+    ivch_write(priv, VR80, backlight);
+    
+    if (mode == DPMSModeOn)
+	vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
+    else
+	vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
+
+    vr01 &= ~VR01_PANEL_FIT_ENABLE;
 
-    ivch_write(priv, VR01, temp);
+    ivch_write(priv, VR01, vr01);
 
     /* Wait for the panel to make its state transition */
-    for (i = 0; i < 1000; i++) {
-	if (!ivch_read(priv, VR30, &temp))
+    for (i = 0; i < 100; i++) {
+	if (!ivch_read(priv, VR30, &vr30))
 	    break;
 
-	if (((temp & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn))
+	if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn))
 	    break;
+	usleep (1000);
     }
+    /* And wait some more; without this, the vch fails to resync sometimes */
+    usleep (16 * 1000);
 }
 
+static Bool
+ivch_mode_fixup(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+    
 static void
-ivch_mode_set(I2CDevPtr d, DisplayModePtr mode)
+ivch_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
-    struct ivch_priv *priv = d->DriverPrivate.ptr;
+    struct ivch_priv	*priv = d->DriverPrivate.ptr;
+    CARD16		vr40 = 0;
+    CARD16		vr01;
 
+    ivch_read (priv, VR01, &vr01);
     /* Disable panel fitting for now, until we can test. */
-    ivch_write(priv, VR40, 0);
+    if (adjusted_mode->HDisplay != priv->width || adjusted_mode->VDisplay != priv->height)
+    {
+	vr01 |= VR01_PANEL_FIT_ENABLE;
+	vr40 |= VR40_AUTO_RATIO_ENABLE;
+    }
+    else
+    {
+	vr01 &= ~VR01_PANEL_FIT_ENABLE;
+	vr40 &= ~VR40_AUTO_RATIO_ENABLE;
+    }
 
+    ivch_write(priv, VR01, vr01);
+    ivch_write(priv, VR40, vr40);
     ivch_dpms(d, DPMSModeOn);
 
     ivch_dump_regs(d);
@@ -244,6 +345,33 @@ ivch_dump_regs(I2CDevPtr d)
     ivch_read(priv, VR40, &val);
     xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR40: 0x%04x\n", val);
 
+    /* GPIO registers */
+    ivch_read(priv, VR80, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR80: 0x%04x\n", val);
+    ivch_read(priv, VR81, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR81: 0x%04x\n", val);
+    ivch_read(priv, VR82, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR82: 0x%04x\n", val);
+    ivch_read(priv, VR83, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR83: 0x%04x\n", val);
+    ivch_read(priv, VR84, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR84: 0x%04x\n", val);
+    ivch_read(priv, VR85, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR85: 0x%04x\n", val);
+    ivch_read(priv, VR86, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR86: 0x%04x\n", val);
+    ivch_read(priv, VR87, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR87: 0x%04x\n", val);
+    ivch_read(priv, VR88, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR88: 0x%04x\n", val);
+
+    /* Scratch register 0 - AIM Panel type */
+    ivch_read(priv, VR8E, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR8E: 0x%04x\n", val);
+
+    /* Scratch register 1 - Status register */
+    ivch_read(priv, VR8F, &val);
+    xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR8F: 0x%04x\n", val);
 }
 
 static void
@@ -267,11 +395,14 @@ ivch_restore(I2CDevPtr d)
 
 I830I2CVidOutputRec ivch_methods = {
     .init = ivch_init,
-    .detect = ivch_detect,
-    .mode_valid = ivch_mode_valid,
-    .mode_set = ivch_mode_set,
+    .setup = ivch_setup,
     .dpms = ivch_dpms,
-    .dump_regs = ivch_dump_regs,
     .save = ivch_save,
     .restore = ivch_restore,
+    .mode_valid = ivch_mode_valid,
+    .mode_fixup = ivch_mode_fixup,
+    .mode_set = ivch_mode_set,
+    .detect = ivch_detect,
+    .get_modes = ivch_get_modes,
+    .dump_regs = ivch_dump_regs,
 };
diff --git a/src/ivch/ivch_reg.h b/src/ivch/ivch_reg.h
index 112c97d..fe5507a 100644
--- a/src/ivch/ivch_reg.h
+++ b/src/ivch/ivch_reg.h
@@ -35,14 +35,14 @@
 #ifndef I82807AA_REG_H
 #define I82807AA_REG_H
 
-/** @defgroup VR00
+/** @defgroup VR00 VCH Revision & GMBus Base Addr
  * @{
  */
 #define VR00		0x00
 # define VR00_BASE_ADDRESS_MASK		0x007f
 /** @} */
 
-/** @defgroup VR01
+/** @defgroup VR01 VCH Functionality Enable
  * @{
  */
 #define VR01		0x01
@@ -59,7 +59,7 @@
 # define VR01_DVO_ENABLE		(1 << 0)
 /** @} */
 
-/** @defgroup VR10
+/** @defgroup VR10 LCD Interface Format
  * @{
  */
 #define VR10		0x10
@@ -75,7 +75,79 @@
 # define VR10_INTERFACE_2X24		(3 << 2)
 /** @} */
 
-/** @defgroup VR30
+/** @defgroup VR11 CMOS Output Control
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR12 LVDS Output Control
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR18 PLL clock select
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR19 PLL clock divisor M
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR1A PLL clock divisor N
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR1F FIFO Pre-load
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR20 LCD Horizontal Display Size
+ * @{
+ */
+#define VR20	0x20
+/** @} */
+
+/** @defgroup VR21 LCD Vertical Display Size
+ * @{
+ */
+#define VR21	0x20
+/** @} */
+
+/** @defgroup VR22 Horizontal TRP to DE Start Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR23 Horizontal TRP to DE End Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR24 Horizontal TRP To LP Start Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR25 Horizontal TRP To LP End Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR26 Vertical TRP To FLM Start Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR27 Vertical TRP To FLM End Delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR30 Panel power down status
  * @{
  */
 #define VR30		0x30
@@ -83,6 +155,31 @@
 # define VR30_PANEL_ON			(1 << 15)
 /** @} */
 
+/** @defgroup VR31 Tpon Panel power on sequencing delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR32 Tpon Panel power off sequencing delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR33 Tstay Panel power off stay down delay
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR34 Maximal FLM Pulse Interval
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR35 Maximal LP Pulse Interval
+ * @{
+ */
+/** @} */
+
 /** @defgroup VR40
  * @{
  */
@@ -90,8 +187,95 @@
 # define VR40_STALL_ENABLE		(1 << 13)
 # define VR40_VERTICAL_INTERP_ENABLE	(1 << 11)
 # define VR40_HORIZONTAL_INTERP_ENABLE	(1 << 10)
-# define VR40_RATIO_ENABLE		(1 << 9)
+# define VR40_AUTO_RATIO_ENABLE		(1 << 9)
 # define VR40_PANEL_FIT_ENABLE		(1 << 8)
 /** @} */
 
+/** @defgroup VR41 Panel Fitting Vertical Ratio
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR42 Panel Fitting Horizontal Ratio
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR43 Horizontal Image Size
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR44 Panel Fitting Coefficient 0
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR45 Panel Fitting Coefficient 1
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR46 Panel Fitting Coefficient 2
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR47 Panel Fitting Coefficient 3
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR48 Panel Fitting Coefficient 4
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR49 Panel Fitting Coefficient 5
+ * @{
+ */
+/** @} */
+
+/** @defgroup VR80 GPIO 0
+ * @{
+ */
+/** @} */
+
+#define VR80	    0x80
+#define VR81	    0x81
+#define VR82	    0x82
+#define VR83	    0x83
+#define VR84	    0x84
+#define VR85	    0x85
+#define VR86	    0x86
+#define VR87	    0x87
+    
+/** @defgroup VR88 GPIO 8
+ * @{
+ */
+/** @} */
+
+#define VR88	    0x88
+
+/** @defgroup VR8E Graphics BIOS scratch 0
+ * @{
+ */
+#define VR8E	    0x8E
+# define VR8E_PANEL_TYPE_MASK		(0xf << 0)
+# define VR8E_PANEL_INTERFACE_CMOS	(0 << 4)
+# define VR8E_PANEL_INTERFACE_LVDS	(1 << 4)
+# define VR8E_FORCE_DEFAULT_PANEL	(1 << 5)
+/** @} */
+
+/** @defgroup VR8F Graphics BIOS scratch 1
+ * @{
+ */
+#define VR8F	    0x8F
+# define VR8F_VCH_PRESENT		(1 << 0)
+# define VR8F_DISPLAY_CONN		(1 << 1)
+# define VR8F_POWER_MASK		(0x3c)
+# define VR8F_POWER_POS			(2)
+/** @} */
+
+
 #endif /* I82807AA_REG_H */
diff --git a/src/sil164/sil164.c b/src/sil164/sil164.c
index 80b1b6a..60a03e2 100644
--- a/src/sil164/sil164.c
+++ b/src/sil164/sil164.c
@@ -144,7 +144,7 @@ sil164_mode_valid(I2CDevPtr d, DisplayMo
 }
 
 static void
-sil164_mode_set(I2CDevPtr d, DisplayModePtr mode)
+sil164_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
     /* As long as the basics are set up, since we don't have clock dependencies
      * in the mode setup, we can just leave the registers alone and everything
diff-tree b28817a87a1608e849e4a9a736dda43533a84b0c (from b31bef1a8effa9acb6de7edd206b9d8c48d88144)
Author: Keith Packard <keithp at dulcimer.keithp.com>
Date:   Wed May 16 13:59:36 2007 -0700

    Add i830_bios_get_aim_data_block to read AIM data from BIOS
    
    Add-in modules have per-module data in the BIOS which contains configuration
    information which cannot be entirely discovered.

diff --git a/src/bios_reader/bios_reader.c b/src/bios_reader/bios_reader.c
index a52bcc7..9ec73c1 100644
--- a/src/bios_reader/bios_reader.c
+++ b/src/bios_reader/bios_reader.c
@@ -30,16 +30,11 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include "../i830_bios.h"
+
 #define _PARSE_EDID_
 #include "edid.h"
 
-/* Define some types so we can reuse i830_bios.h */
-typedef void *ScrnInfoPtr;
-typedef int Bool;
-#define TRUE 1
-#define FALSE 0
-#include "../i830_bios.h"
-
 
 /* Make a fake pI830 so we can easily pull i830_bios.c code in here. */
 struct _fake_i830 {
diff --git a/src/i830_bios.c b/src/i830_bios.c
index 0d00917..7703c80 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -77,8 +77,8 @@ i830DumpBIOSToFile(ScrnInfoPtr pScrn, un
  * feed an updated VBT back through that, compared to what we'll fetch using
  * this method of groping around in the BIOS data.
  */
-static unsigned char *
-i830GetBIOS(ScrnInfoPtr pScrn)
+unsigned char *
+i830_bios_get (ScrnInfoPtr pScrn)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     struct vbt_header *vbt;
@@ -131,7 +131,7 @@ i830GetBIOS(ScrnInfoPtr pScrn)
  * detecting the panel mode is preferable.
  */
 DisplayModePtr
-i830_bios_get_panel_mode(ScrnInfoPtr pScrn)
+i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     struct vbt_header *vbt;
@@ -140,7 +140,7 @@ i830_bios_get_panel_mode(ScrnInfoPtr pSc
     int panel_type = -1;
     unsigned char *bios;
 
-    bios = i830GetBIOS(pScrn);
+    bios = i830_bios_get (pScrn);
 
     if (bios == NULL)
 	return NULL;
@@ -156,6 +156,7 @@ i830_bios_get_panel_mode(ScrnInfoPtr pSc
 	return NULL;
     }
 
+    *wants_dither = FALSE;
     for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
 	 bdb_block_off += block_size)
     {
@@ -175,7 +176,7 @@ i830_bios_get_panel_mode(ScrnInfoPtr pSc
 	    lvds1 = (struct lvds_bdb_1 *)(bios + start);
 	    panel_type = lvds1->panel_type;
 	    if (lvds1->caps & LVDS_CAP_DITHER)
-		pI830->panel_wants_dither = TRUE;
+		*wants_dither = TRUE;
 	    break;
 	case 41:
 	    if (panel_type == -1)
@@ -243,3 +244,51 @@ i830_bios_get_panel_mode(ScrnInfoPtr pSc
     xfree(bios);
     return NULL;
 }
+
+unsigned char *
+i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block)
+{
+    unsigned char   *bios;
+    int		    bdb_off;
+    int		    vbt_off;
+    int		    aim_off;
+    struct vbt_header *vbt;
+    struct aimdb_header *aimdb;
+    struct aimdb_block *aimdb_block;
+
+    bios = i830_bios_get (pScrn);
+    if (!bios)
+	return NULL;
+
+    vbt_off = INTEL_BIOS_16(0x1a);
+    vbt = (struct vbt_header *)(bios + vbt_off);
+
+    aim_off = vbt->aim_offset[aim];
+    if (!aim_off)
+    {
+	free (bios);
+	return NULL;
+    }
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "aim_off %d\n", aim_off);
+    aimdb = (struct aimdb_header *) (bios + vbt_off + aim_off);
+    bdb_off = aimdb->aimdb_header_size;
+    while (bdb_off < aimdb->aimdb_size)
+    {
+	aimdb_block = (struct aimdb_block *) (bios + vbt_off + aim_off + bdb_off);
+	if (aimdb_block->aimdb_id == data_block)
+	{
+	    unsigned char   *aim = malloc (aimdb_block->aimdb_size + sizeof (struct aimdb_block));
+	    if (!aim)
+	    {
+		free (bios);
+		return NULL;
+	    }
+	    memcpy (aim, aimdb_block, aimdb_block->aimdb_size + sizeof (struct aimdb_block));
+	    free (bios);
+	    return aim;
+	}
+	bdb_off += aimdb_block->aimdb_size + sizeof (struct aimdb_block);
+    }
+    free (bios);
+    return NULL;
+}
diff --git a/src/i830_bios.h b/src/i830_bios.h
index 881d5c8..cb7666e 100644
--- a/src/i830_bios.h
+++ b/src/i830_bios.h
@@ -25,6 +25,11 @@
  *
  */
 
+#ifndef _I830_BIOS_H_
+#define _I830_BIOS_H_
+
+#include <xf86str.h>
+
 struct vbt_header {
     char signature[20];			/**< Always starts with 'VBT$' */
     CARD16 version;			/**< decimal */
@@ -33,10 +38,7 @@ struct vbt_header {
     CARD8 vbt_checksum;
     CARD8 reserved0;
     CARD32 bdb_offset;			/**< from beginning of VBT */
-    CARD32 aim1_offset;			/**< from beginning of VBT */
-    CARD32 aim2_offset;			/**< from beginning of VBT */
-    CARD32 aim3_offset;			/**< from beginning of VBT */
-    CARD32 aim4_offset;			/**< from beginning of VBT */
+    CARD32 aim_offset[4];		/**< from beginning of VBT */
 } __attribute__((packed));
 
 struct bdb_header {
@@ -114,3 +116,45 @@ struct lvds_bdb_2 {
     CARD8 table_size;	/* not sure on this one */
     struct lvds_bdb_2_entry panels[16];
 } __attribute__((packed));
+
+struct aimdb_header {
+    char    signature[16];
+    char    oem_device[20];
+    CARD16  aimdb_version;
+    CARD16  aimdb_header_size;
+    CARD16  aimdb_size;
+} __attribute__((packed));
+
+struct aimdb_block {
+    CARD8   aimdb_id;
+    CARD16  aimdb_size;
+} __attribute__((packed));
+
+struct vch_bdb_20 {
+} __attribute__((packed));
+
+struct vch_panel_data {
+    CARD16	fp_timing_offset;
+    CARD8	fp_timing_size;
+    CARD16	dvo_timing_offset;
+    CARD8	dvo_timing_size;
+    CARD16	text_fitting_offset;
+    CARD8	text_fitting_size;
+    CARD16	graphics_fitting_offset;
+    CARD8	graphics_fitting_size;
+} __attribute__((packed));
+
+struct vch_bdb_22 {
+    struct aimdb_block	    aimdb_block;
+    struct vch_panel_data   panels[16];
+} __attribute__((packed));
+
+unsigned char *
+i830_bios_get (ScrnInfoPtr pScrn);
+
+DisplayModePtr i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither);
+
+unsigned char *
+i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block);
+
+#endif /* _I830_BIOS_H_ */


More information about the xorg-commit mailing list