diff options
author | Keith Packard <keithp@dulcimer.keithp.com> | 2007-05-16 14:02:00 -0700 |
---|---|---|
committer | Keith Packard <keithp@dulcimer.keithp.com> | 2007-05-16 14:02:00 -0700 |
commit | c0daa0a982e7074af4b50653b4a45b0a6352b43d (patch) | |
tree | 784a6d552d5ff6e957d5a5fefac99f206f654c46 /src/ivch | |
parent | b28817a87a1608e849e4a9a736dda43533a84b0c (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.c | 171 | ||||
-rw-r--r-- | src/ivch/ivch_reg.h | 194 |
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 */ |