summaryrefslogtreecommitdiff
path: root/src/ivch
diff options
context:
space:
mode:
authorKeith Packard <keithp@dulcimer.keithp.com>2007-05-16 14:02:00 -0700
committerKeith Packard <keithp@dulcimer.keithp.com>2007-05-16 14:02:00 -0700
commitc0daa0a982e7074af4b50653b4a45b0a6352b43d (patch)
tree784a6d552d5ff6e957d5a5fefac99f206f654c46 /src/ivch
parentb28817a87a1608e849e4a9a736dda43533a84b0c (diff)
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.
Diffstat (limited to 'src/ivch')
-rw-r--r--src/ivch/ivch.c171
-rw-r--r--src/ivch/ivch_reg.h194
2 files changed, 340 insertions, 25 deletions
diff --git a/src/ivch/ivch.c b/src/ivch/ivch.c
index efc74f83..a76e339f 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 addr, CARD16 data)
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 112c97d6..fe5507a8 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 */