summaryrefslogtreecommitdiff
path: root/src/ivch/ivch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ivch/ivch.c')
-rw-r--r--src/ivch/ivch.c171
1 files changed, 151 insertions, 20 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,
};