summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Packard <keithp@neko.keithp.com>2006-12-28 16:34:38 -0800
committerKeith Packard <keithp@neko.keithp.com>2006-12-28 16:34:38 -0800
commit2b0a997e5b4b51267fa4f6725f8a965093392434 (patch)
tree05db003da637a1eb2fad1b64d9ef68eb0432cd03 /src
parentbb238a8fc234a8e5e86cd2f42c58c9816a15732c (diff)
parent9cfbf1ceda8f153438df1ba4b1712c55cc872017 (diff)
Merge branch 'modesetting-origin' into modesetting
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/ch7017/Makefile.am15
-rw-r--r--src/ch7017/ch7017.c302
-rw-r--r--src/ch7017/ch7017_module.c36
-rw-r--r--src/ch7017/ch7017_reg.h150
-rw-r--r--src/i830_dvo.c138
-rw-r--r--src/i830_video.c39
-rw-r--r--src/i830_video.h4
-rw-r--r--src/i915_video.c34
-rw-r--r--src/i965_video.c32
-rw-r--r--src/ivch/Makefile.am15
-rw-r--r--src/ivch/ivch.c234
-rw-r--r--src/ivch/ivch_module.c64
-rw-r--r--src/ivch/ivch_reg.h97
14 files changed, 1078 insertions, 85 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d843ecff..5309eea9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,8 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-SUBDIRS = xvmc bios_reader ch7xxx sil164
+SUBDIRS = xvmc bios_reader ch7017 ch7xxx ivch sil164
+
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
diff --git a/src/ch7017/Makefile.am b/src/ch7017/Makefile.am
new file mode 100644
index 00000000..9cf2fa49
--- /dev/null
+++ b/src/ch7017/Makefile.am
@@ -0,0 +1,15 @@
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@
+
+ch7017_la_LTLIBRARIES = ch7017.la
+ch7017_la_LDFLAGS = -module -avoid-version
+ch7017_ladir = @moduledir@/drivers
+
+ch7017_la_SOURCES = \
+ ch7017.c \
+ ch7017_module.c \
+ ch7017_reg.h
diff --git a/src/ch7017/ch7017.c b/src/ch7017/ch7017.c
new file mode 100644
index 00000000..28bce0d2
--- /dev/null
+++ b/src/ch7017/ch7017.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Resources.h"
+#include "compiler.h"
+#include "miscstruct.h"
+#include "xf86i2c.h"
+#include "../i830_xf86Crtc.h"
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "../i2c_vid.h"
+#include "ch7017_reg.h"
+
+struct ch7017_priv {
+ I2CDevRec d;
+
+ CARD8 save_hapi;
+ CARD8 save_vali;
+ CARD8 save_valo;
+ CARD8 save_lvds_pll_vco;
+ CARD8 save_feedback_div;
+ CARD8 save_lvds_control_2;
+ CARD8 save_outputs_enable;
+ CARD8 save_lvds_power_down;
+};
+
+static void
+ch7017_dump_regs(I2CDevPtr d);
+
+static Bool
+ch7017_read(struct ch7017_priv *priv, int addr, CARD8 *val)
+{
+ if (!xf86I2CReadByte(&priv->d, addr, val)) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to read from %s Slave %d.\n",
+ priv->d.pI2CBus->BusName, priv->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static Bool
+ch7017_write(struct ch7017_priv *priv, int addr, CARD8 val)
+{
+ if (!xf86I2CWriteByte(&priv->d, addr, val)) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to write to %s Slave %d.\n",
+ priv->d.pI2CBus->BusName, priv->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/** Probes for a CH7017 on the given bus and slave address. */
+static void *
+ch7017_init(I2CBusPtr b, I2CSlaveAddr addr)
+{
+ struct ch7017_priv *priv;
+ CARD8 val;
+
+ xf86DrvMsg(b->scrnIndex, X_INFO, "detecting ch7017\n");
+
+ priv = xcalloc(1, sizeof(struct ch7017_priv));
+ if (priv == NULL)
+ return NULL;
+
+ priv->d.DevName = "CH7017/7018 TMDS Controller";
+ priv->d.SlaveAddr = addr;
+ priv->d.pI2CBus = b;
+ priv->d.StartTimeout = b->StartTimeout;
+ priv->d.BitTimeout = b->BitTimeout;
+ priv->d.AcknTimeout = b->AcknTimeout;
+ priv->d.ByteTimeout = b->ByteTimeout;
+ priv->d.DriverPrivate.ptr = priv;
+
+ if (!xf86I2CReadByte(&priv->d, CH7017_DEVICE_ID, &val))
+ goto fail;
+
+ if (val != CH7017_DEVICE_ID_VALUE && val != CH7018_DEVICE_ID_VALUE) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "ch7017 not detected, got %d: from %s Slave %d.\n",
+ val, priv->d.pI2CBus->BusName, priv->d.SlaveAddr);
+ goto fail;
+ }
+
+ if (!xf86I2CDevInit(&(priv->d)))
+ goto fail;
+
+ return priv;
+
+fail:
+ xfree(priv);
+ return NULL;
+}
+
+static xf86OutputStatus
+ch7017_detect(I2CDevPtr d)
+{
+ return XF86OutputStatusUnknown;
+}
+
+static ModeStatus
+ch7017_mode_valid(I2CDevPtr d, DisplayModePtr mode)
+{
+ if (mode->Clock > 160000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static void
+ch7017_mode_set(I2CDevPtr d, DisplayModePtr mode)
+{
+ struct ch7017_priv *priv = d->DriverPrivate.ptr;
+ CARD8 lvds_pll_feedback_div, lvds_pll_vco_control;
+ CARD8 outputs_enable, lvds_control_2, lvds_power_down;
+ CARD8 horizontal_active_pixel_input;
+ CARD8 horizontal_active_pixel_output, vertical_active_line_output;
+ CARD8 active_input_line_output;
+
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO,
+ "Registers before mode setting\n");
+ ch7017_dump_regs(d);
+
+ /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
+ if (mode->Clock < 50000) {
+ lvds_pll_feedback_div = 45;
+ lvds_pll_vco_control = (2 << 4) | (3 << 0);
+ outputs_enable = (0 << 0); /* XXX: enables */
+ lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
+ (0 << CH7017_PHASE_DETECTOR_SHIFT);
+ } else if (mode->Clock < 100000) {
+ lvds_pll_feedback_div = 45;
+ lvds_pll_vco_control = (2 << 4) | (3 << 0);
+ outputs_enable = (0 << 0); /* XXX: enables */
+ lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
+ (0 << CH7017_PHASE_DETECTOR_SHIFT);
+ } else if (mode->Clock < 160000) {
+ lvds_pll_feedback_div = 35;
+ outputs_enable = (3 << 0); /* XXX: enables */
+ lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
+ (0 << CH7017_PHASE_DETECTOR_SHIFT);
+ if (1) { /* XXX: dual panel */
+ lvds_pll_vco_control = (2 << 4) | (13 << 0);
+ } else {
+ lvds_pll_vco_control = (1 << 4) | (13 << 0);
+ }
+ } else {
+ FatalError("Invalid mode clock (%.1fMHz)\n",
+ (float)mode->Clock / 1000.0);
+ }
+
+ horizontal_active_pixel_input = mode->HDisplay & 0x00ff;
+
+ vertical_active_line_output = mode->VDisplay & 0x00ff;
+ horizontal_active_pixel_output = mode->HDisplay & 0x00ff;
+
+ active_input_line_output = ((mode->HDisplay & 0x0700) >> 9) |
+ ((mode->VDisplay & 0x0700) >> 8);
+
+ lvds_power_down = (mode->HDisplay & 0x0f00) >> 8;
+
+ ch7017Power(d, FALSE);
+ ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
+ horizontal_active_pixel_input);
+ ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
+ horizontal_active_pixel_output);
+ ch7017_write(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
+ vertical_active_line_output);
+ ch7017_write(priv, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
+ ch7017_write(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
+ ch7017_write(priv, CH7017_LVDS_CONTROL_2, lvds_control_2);
+ ch7017_write(priv, CH7017_OUTPUTS_ENABLE, outputs_enable);
+
+ /* Turn the LVDS back on with new settings. */
+ ch7017_write(priv, CH7017_LVDS_POWER_DOWN, lvds_power_down);
+
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO,
+ "Registers after mode setting\n");
+ ch7017PrintRegs(d);
+}
+
+/* set the CH7017 power state */
+static void
+ch7017_dpms(I2CDevPtr d, int mode)
+{
+ struct ch7017_priv *priv = d->DriverPrivate.ptr;
+ CARD8 val;
+
+ ch7017_read(priv, CH7017_LVDS_POWER_DOWN, &val);
+
+ if (mode == DPMSModeOn) {
+ /* Turn on the LVDS */
+ ch7017_write(priv, CH7017_LVDS_POWER_DOWN,
+ val & ~CH7017_LVDS_POWER_DOWN_EN);
+ } else {
+ /* Turn on the LVDS */
+ ch7017_write(priv, CH7017_LVDS_POWER_DOWN,
+ val | CH7017_LVDS_POWER_DOWN_EN);
+ }
+
+ /* XXX: Should actually wait for update power status somehow */
+ usleep(50000);
+}
+
+static void
+ch7017_dump_regs(I2CDevPtr d)
+{
+ struct ch7017_priv *priv = d->DriverPrivate.ptr;
+ CARD8 val;
+
+#define DUMP(reg) \
+do { \
+ ch7017_read(priv, reg, &val); \
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, \
+ #reg ": %02x\n", val); \
+} while (0)
+
+ DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
+ DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
+ DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
+ DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
+ DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
+ DUMP(CH7017_LVDS_CONTROL_2);
+ DUMP(CH7017_OUTPUTS_ENABLE);
+ DUMP(CH7017_LVDS_POWER_DOWN);
+}
+
+static void
+ch7017_save(I2CDevPtr d)
+{
+ struct ch7017_priv *priv = d->DriverPrivate.ptr;
+
+ ch7017_read(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi);
+ ch7017_read(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo);
+ ch7017_read(priv, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco);
+ ch7017_read(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div);
+ ch7017_read(priv, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2);
+ ch7017_read(priv, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable);
+ ch7017_read(priv, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down);
+}
+
+static void
+ch7017_restore(I2CDevPtr d)
+{
+ struct ch7017_priv *priv = d->DriverPrivate.ptr;
+
+ /* Power down before changing mode */
+ ch7017Power(d, FALSE);
+
+ ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi);
+ ch7017_write(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo);
+ ch7017_write(priv, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco);
+ ch7017_write(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div);
+ ch7017_write(priv, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2);
+ ch7017_write(priv, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable);
+ ch7017_write(priv, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down);
+}
+
+I830I2CVidOutputRec ch7017_methods = {
+ .init = ch7017_init,
+ .detect = ch7017_detect,
+ .mode_valid = ch7017_mode_valid,
+ .mode_set = ch7017_mode_set,
+ .dpms = ch7017_dpms,
+ .dump_regs = ch7017_dump_regs,
+ .save = ch7017_save,
+ .restore = ch7017_restore,
+};
diff --git a/src/ch7017/ch7017_module.c b/src/ch7017/ch7017_module.c
new file mode 100644
index 00000000..135f3c65
--- /dev/null
+++ b/src/ch7017/ch7017_module.c
@@ -0,0 +1,36 @@
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86Module.h"
+
+static MODULESETUPPROTO(ch7017Setup);
+
+static XF86ModuleVersionInfo ch7017VersRec =
+ {
+ "ch7017",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ { 0,0,0,0 }
+ };
+
+_X_EXPORT XF86ModuleData ch7017ModuleData = {
+ &ch7017VersRec,
+ ch7017Setup,
+ NULL
+};
+
+static pointer
+ch7017Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
+ return (pointer)1;
+}
diff --git a/src/ch7017/ch7017_reg.h b/src/ch7017/ch7017_reg.h
new file mode 100644
index 00000000..89f81cc3
--- /dev/null
+++ b/src/ch7017/ch7017_reg.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifndef CH7017_REG_H
+#define CH7017_REG_H
+
+#define CH7017_TV_DISPLAY_MODE 0x00
+#define CH7017_FLICKER_FILTER 0x01
+#define CH7017_VIDEO_BANDWIDTH 0x02
+#define CH7017_TEXT_ENHANCEMENT 0x03
+#define CH7017_START_ACTIVE_VIDEO 0x04
+#define CH7017_HORIZONTAL_POSITION 0x05
+#define CH7017_VERTICAL_POSITION 0x06
+#define CH7017_BLACK_LEVEL 0x07
+#define CH7017_CONTRAST_ENHANCEMENT 0x08
+#define CH7017_TV_PLL 0x09
+#define CH7017_TV_PLL_M 0x0a
+#define CH7017_TV_PLL_N 0x0b
+#define CH7017_SUB_CARRIER_0 0x0c
+#define CH7017_CIV_CONTROL 0x10
+#define CH7017_CIV_0 0x11
+#define CH7017_CHROMA_BOOST 0x14
+#define CH7017_CLOCK_MODE 0x1c
+#define CH7017_INPUT_CLOCK 0x1d
+#define CH7017_GPIO_CONTROL 0x1e
+#define CH7017_INPUT_DATA_FORMAT 0x1f
+#define CH7017_CONNECTION_DETECT 0x20
+#define CH7017_DAC_CONTROL 0x21
+#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22
+#define CH7017_DEFEAT_VSYNC 0x47
+#define CH7017_TEST_PATTERN 0x48
+
+#define CH7017_POWER_MANAGEMENT 0x49
+/** Enables the TV output path. */
+#define CH7017_TV_EN (1 << 0)
+#define CH7017_DAC0_POWER_DOWN (1 << 1)
+#define CH7017_DAC1_POWER_DOWN (1 << 2)
+#define CH7017_DAC2_POWER_DOWN (1 << 3)
+#define CH7017_DAC3_POWER_DOWN (1 << 4)
+/** Powers down the TV out block, and DAC0-3 */
+#define CH7017_TV_POWER_DOWN_EN (1 << 5)
+
+#define CH7017_VERSION_ID 0x4a
+
+#define CH7017_DEVICE_ID 0x4b
+#define CH7017_DEVICE_ID_VALUE 0x1b
+#define CH7018_DEVICE_ID_VALUE 0x1a
+
+#define CH7017_XCLK_D2_ADJUST 0x53
+#define CH7017_UP_SCALER_COEFF_0 0x55
+#define CH7017_UP_SCALER_COEFF_1 0x56
+#define CH7017_UP_SCALER_COEFF_2 0x57
+#define CH7017_UP_SCALER_COEFF_3 0x58
+#define CH7017_UP_SCALER_COEFF_4 0x59
+#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a
+#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b
+#define CH7017_GPIO_INVERT 0x5c
+#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d
+#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f
+/**< Low bits of horizontal active pixel input */
+
+#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60
+/** High bits of horizontal active pixel input */
+#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0)
+/** High bits of vertical active line output */
+#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3)
+
+#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61
+/**< Low bits of vertical active line output */
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62
+/**< Low bits of horizontal active pixel output */
+
+#define CH7017_LVDS_POWER_DOWN 0x63
+/** High bits of horizontal active pixel output */
+#define CH7017_LVDS_HAP_HIGH_MASK (0xf << 0)
+/** Enables the LVDS power down state transition */
+#define CH7017_LVDS_POWER_DOWN_EN (1 << 6)
+/** Enables the LVDS upscaler */
+#define CH7017_LVDS_UPSCALER_EN (1 << 7)
+
+#define CH7017_LVDS_ENCODING 0x64
+#define CH7017_LVDS_DITHER_2D (1 << 2)
+#define CH7017_LVDS_DITHER_DIS (1 << 3)
+#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4)
+#define CH7017_LVDS_24_BIT (1 << 5)
+
+#define CH7017_LVDS_ENCODING_2 0x65
+
+#define CH7017_LVDS_PLL_CONTROL 0x66
+/** Enables the LVDS panel output path */
+#define CH7017_LVDS_PANEN (1 << 0)
+/** Enables the LVDS panel backlight */
+#define CH7017_LVDS_BKLEN (1 << 3)
+
+#define CH7017_POWER_SEQUENCING_T1 0x67
+#define CH7017_POWER_SEQUENCING_T2 0x68
+#define CH7017_POWER_SEQUENCING_T3 0x69
+#define CH7017_POWER_SEQUENCING_T4 0x6a
+#define CH7017_POWER_SEQUENCING_T5 0x6b
+#define CH7017_GPIO_DRIVER_TYPE 0x6c
+#define CH7017_GPIO_DATA 0x6d
+#define CH7017_GPIO_DIRECTION_CONTROL 0x6e
+#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71
+#define CH7017_LVDS_PLL_VCO_CONTROL 0x72
+
+#define CH7017_OUTPUTS_ENABLE 0x73
+# define CH7017_LVDS_CHANNEL_A (1 << 3)
+# define CH7017_LVDS_CHANNEL_B (1 << 4)
+# define CH7017_TV_DAC_A (1 << 5)
+# define CH7017_TV_DAC_B (1 << 6)
+# define CH7017_DDC_SELECT_DC2 (1 << 7)
+
+#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74
+#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75
+#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
+
+#define CH7017_LVDS_CONTROL_2 0x78
+# define CH7017_LOOP_FILTER_SHIFT 5
+# define CH7017_PHASE_DETECTOR_SHIFT 0
+
+#define CH7017_BANG_LIMIT_CONTROL 0x7f
+
+#endif /* CH7017_REG_H */
diff --git a/src/i830_dvo.c b/src/i830_dvo.c
index 97453ded..d1010545 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -45,13 +45,34 @@ static const char *CH7xxxSymbols[] = {
NULL
};
+#if 0
+static const char *ivch_symbols[] = {
+ "ivch_methods",
+ NULL
+};
+#endif
+#if 0
+static const char *ch7017_symbols[] = {
+ "ch7017_methods",
+ NULL
+};
+#endif
+
/* driver list */
struct _I830DVODriver i830_dvo_drivers[] =
{
- { I830_DVO_CHIP_TMDS, "sil164", "SIL164VidOutput",
- (SIL164_ADDR_1<<1), SIL164Symbols, NULL , NULL, NULL},
- { I830_DVO_CHIP_TMDS | I830_DVO_CHIP_TVOUT, "ch7xxx", "CH7xxxVidOutput",
- (CH7xxx_ADDR_1<<1), CH7xxxSymbols, NULL , NULL, NULL}
+ {I830_DVO_CHIP_TMDS, "sil164", "SIL164VidOutput",
+ (SIL164_ADDR_1<<1), SIL164Symbols, NULL , NULL, NULL},
+ {I830_DVO_CHIP_TMDS | I830_DVO_CHIP_TVOUT, "ch7xxx", "CH7xxxVidOutput",
+ (CH7xxx_ADDR_1<<1), CH7xxxSymbols, NULL , NULL, NULL},
+ /*
+ {I830_DVO_CHIP_LVDS, "ivch", "ivch_methods",
+ (0x2 << 1), ivch_symbols, NULL, NULL, NULL},
+ */
+ /*
+ { I830_DVO_CHIP_LVDS, "ch7017", "ch7017_methods",
+ (CH7017_ADDR_1 << 1), ch7017_symbols, NULL, NULL, NULL }
+ */
};
#define I830_NUM_DVO_DRIVERS (sizeof(i830_dvo_drivers)/sizeof(struct _I830DVODriver))
@@ -183,37 +204,6 @@ i830_dvo_detect(xf86OutputPtr output)
return intel_output->i2c_drv->vid_rec->detect(dev_priv);
}
-static Bool
-I830I2CDetectDVOControllers(ScrnInfoPtr pScrn, I2CBusPtr pI2CBus,
- struct _I830DVODriver **retdrv)
-{
- int i;
- void *ret_ptr;
- struct _I830DVODriver *drv;
-
- for (i = 0; i < I830_NUM_DVO_DRIVERS; i++) {
- drv = &i830_dvo_drivers[i];
- drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename);
- if (drv->modhandle == NULL)
- continue;
-
- xf86LoaderReqSymLists(drv->symbols, NULL);
-
- ret_ptr = NULL;
- drv->vid_rec = LoaderSymbol(drv->fntablename);
- if (drv->vid_rec != NULL)
- ret_ptr = drv->vid_rec->init(pI2CBus, drv->address);
-
- if (ret_ptr != NULL) {
- drv->dev_priv = ret_ptr;
- *retdrv = drv;
- return TRUE;
- }
- xf86UnloadSubModule(drv->modhandle);
- }
- return FALSE;
-}
-
static void
i830_dvo_destroy (xf86OutputPtr output)
{
@@ -245,9 +235,14 @@ static const xf86OutputFuncsRec i830_dvo_output_funcs = {
void
i830_dvo_init(ScrnInfoPtr pScrn)
{
- xf86OutputPtr output;
- I830OutputPrivatePtr intel_output;
- int ret;
+ xf86OutputPtr output;
+ I830OutputPrivatePtr intel_output;
+ int ret;
+ int i;
+ void *ret_ptr;
+ struct _I830DVODriver *drv;
+ int gpio_inited = 0;
+ I2CBusPtr pI2CBus = NULL;
output = xf86OutputCreate (pScrn, &i830_dvo_output_funcs,
"TMDS");
@@ -263,14 +258,7 @@ i830_dvo_init(ScrnInfoPtr pScrn)
output->driver_private = intel_output;
output->subpixel_order = SubPixelHorizontalRGB;
- /* Set up the I2C and DDC buses */
- ret = I830I2CInit(pScrn, &intel_output->pI2CBus, GPIOE, "DVOI2C_E");
- if (!ret)
- {
- xf86OutputDestroy (output);
- return;
- }
-
+ /* Set up the DDC bus */
ret = I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOD, "DVODDC_D");
if (!ret)
{
@@ -279,17 +267,51 @@ i830_dvo_init(ScrnInfoPtr pScrn)
}
/* Now, try to find a controller */
- ret = I830I2CDetectDVOControllers(pScrn, intel_output->pI2CBus,
- &intel_output->i2c_drv);
- if (ret)
- {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found i2c %s on %08lX\n",
- intel_output->i2c_drv->modulename,
- intel_output->pI2CBus->DriverPrivate.uval);
- }
- else
- {
- xf86OutputDestroy (output);
- return;
+ for (i = 0; i < I830_NUM_DVO_DRIVERS; i++) {
+ int gpio;
+
+ drv = &i830_dvo_drivers[i];
+ drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename);
+ if (drv->modhandle == NULL)
+ continue;
+
+ xf86LoaderReqSymLists(drv->symbols, NULL);
+
+ ret_ptr = NULL;
+ drv->vid_rec = LoaderSymbol(drv->fntablename);
+
+ if (drv->type & I830_DVO_CHIP_LVDS)
+ gpio = GPIOB;
+ else
+ gpio = GPIOE;
+
+ /* Set up the I2C bus necessary for the chip we're probing. It appears
+ * that everything is on GPIOE except for panels on i830 laptops, which
+ * are on GPIOB (DVOA).
+ */
+ if (gpio_inited != gpio) {
+ if (pI2CBus != NULL)
+ xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
+ if (!I830I2CInit(pScrn, &intel_output->pI2CBus, gpio,
+ gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E")) {
+ continue;
+ }
+ }
+
+ if (drv->vid_rec != NULL)
+ ret_ptr = drv->vid_rec->init(pI2CBus, drv->address);
+
+ if (ret_ptr != NULL) {
+ drv->dev_priv = ret_ptr;
+ intel_output->i2c_drv = drv;
+ intel_output->pI2CBus = pI2CBus;
+ return;
+ }
+ xf86UnloadSubModule(drv->modhandle);
}
+
+ /* Didn't find a chip, so tear down. */
+ if (pI2CBus != NULL)
+ xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
+ xf86OutputDestroy (output);
}
diff --git a/src/i830_video.c b/src/i830_video.c
index 76d4f9c8..f031a873 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -76,6 +76,8 @@ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "xf86fbman.h"
#include "regionstr.h"
#include "randrstr.h"
+#include "windowstr.h"
+#include "damage.h"
#include "i830.h"
#include "i830_video.h"
#include "xf86xv.h"
@@ -138,6 +140,11 @@ static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
#define OVERLAY_DEBUG if (0) ErrorF
#endif
+/* Oops, I never exported this function in EXA. I meant to. */
+#ifndef exaMoveInPixmap
+void exaMoveInPixmap (PixmapPtr pPixmap);
+#endif
+
/*
* This is more or less the correct way to initalise, update, and shut down
* the overlay. Note OVERLAY_OFF should be used only after disabling the
@@ -2016,7 +2023,6 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
OVERLAY_UPDATE;
}
-
#ifdef I830_USE_EXA
static void
I830VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
@@ -2167,6 +2173,7 @@ I830PutImage(ScrnInfoPtr pScrn,
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem->Start);
+ PixmapPtr pPixmap;
INT32 x1, x2, y1, y2;
int srcPitch, srcPitch2 = 0, dstPitch, destId;
int top, left, npixels, nlines, size, loops;
@@ -2380,6 +2387,28 @@ I830PutImage(ScrnInfoPtr pScrn,
break;
}
+ if (pDraw->type == DRAWABLE_WINDOW) {
+ pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
+ } else {
+ pPixmap = (PixmapPtr)pDraw;
+ }
+
+#ifdef I830_USE_EXA
+ if (pI830->useEXA) {
+ /* Force the pixmap into framebuffer so we can draw to it. */
+ exaMoveInPixmap(pPixmap);
+ }
+#endif
+
+ if (((char *)pPixmap->devPrivate.ptr < (char *)pI830->FbBase) ||
+ ((char *)pPixmap->devPrivate.ptr >= (char *)pI830->FbBase +
+ pI830->FbMapSize)) {
+ /* If the pixmap wasn't in framebuffer, then we have no way in XAA to
+ * force it there. So, we simply refuse to draw and fail.
+ */
+ return BadAlloc;
+ }
+
if (!pPriv->textured) {
/* update cliplist */
if (!RegionsEqual(&pPriv->clip, clipBoxes)) {
@@ -2392,12 +2421,16 @@ I830PutImage(ScrnInfoPtr pScrn,
} else if (IS_I965G(pI830)) {
I965DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height,
dstPitch, x1, y1, x2, y2,
- src_w, src_h, drw_w, drw_h, pDraw);
+ src_w, src_h, drw_w, drw_h, pPixmap);
} else {
I915DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height,
dstPitch, x1, y1, x2, y2,
- src_w, src_h, drw_w, drw_h, pDraw);
+ src_w, src_h, drw_w, drw_h, pPixmap);
+ }
+ if (pPriv->textured) {
+ DamageDamageRegion(pDraw, clipBoxes);
}
+
pPriv->videoStatus = CLIENT_VIDEO_ON;
return Success;
diff --git a/src/i830_video.h b/src/i830_video.h
index 90c58b76..854d0b80 100644
--- a/src/i830_video.h
+++ b/src/i830_video.h
@@ -92,7 +92,7 @@ void I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv,
int x1, int y1, int x2, int y2,
short src_w, short src_h,
short drw_w, short drw_h,
- DrawablePtr pDraw);
+ PixmapPtr pPixmap);
void I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv,
int id, RegionPtr dstRegion, short width,
@@ -100,4 +100,4 @@ void I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv,
int x1, int y1, int x2, int y2,
short src_w, short src_h,
short drw_w, short drw_h,
- DrawablePtr pDraw);
+ PixmapPtr pPixmap);
diff --git a/src/i915_video.c b/src/i915_video.c
index 636b2cbd..52fe1a51 100644
--- a/src/i915_video.c
+++ b/src/i915_video.c
@@ -57,12 +57,12 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
short width, short height, int video_pitch,
int x1, int y1, int x2, int y2,
short src_w, short src_h, short drw_w, short drw_h,
- DrawablePtr pDraw)
+ PixmapPtr pPixmap)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 format, ms3, s2, s5;
BoxPtr pbox;
- int nbox, dxo, dyo;
+ int nbox, dxo, dyo, pix_xoff, pix_yoff;
Bool planar;
#if 0
@@ -103,7 +103,8 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
/* draw rect -- just clipping */
OUT_RING(_3DSTATE_DRAW_RECT_CMD);
- OUT_RING(DRAW_DITHER_OFS_X(pDraw->x & 3)| DRAW_DITHER_OFS_Y(pDraw->y & 3)); /* flags */
+ OUT_RING(DRAW_DITHER_OFS_X(pPixmap->drawable.x & 3) |
+ DRAW_DITHER_OFS_Y(pPixmap->drawable.y & 3));
OUT_RING(0x00000000); /* ymin, xmin */
OUT_RING((pScrn->virtualX - 1) |
(pScrn->virtualY - 1) << 16); /* ymax, xmax */
@@ -155,8 +156,8 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
/* front buffer, pitch, offset */
OUT_RING(_3DSTATE_BUF_INFO_CMD);
OUT_RING(BUF_3D_ID_COLOR_BACK | BUF_3D_USE_FENCE |
- (((pI830->displayWidth * pI830->cpp) / 4) << 2));
- OUT_RING(pI830->bufferOffset);
+ BUF_3D_PITCH(pPixmap->devKind));
+ OUT_RING(BUF_3D_ADDR((long)pPixmap->devPrivate.ptr - (long)pI830->FbBase));
ADVANCE_LP_RING();
if (!planar) {
@@ -340,6 +341,17 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
ADVANCE_LP_RING();
}
+ /* Set up the offset for translating from the given region (in screen
+ * coordinates) to the backing pixmap.
+ */
+#ifdef COMPOSITE
+ pix_xoff = -pPixmap->screen_x + pPixmap->drawable.x;
+ pix_yoff = -pPixmap->screen_y + pPixmap->drawable.y;
+#else
+ pix_xoff = 0;
+ pix_yoff = 0;
+#endif
+
dxo = dstRegion->extents.x1;
dyo = dstRegion->extents.y1;
@@ -380,8 +392,8 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
(vert_data_count - 1));
/* bottom right */
- OUT_RING_F(box_x2);
- OUT_RING_F(box_y2);
+ OUT_RING_F(box_x2 + pix_xoff);
+ OUT_RING_F(box_y2 + pix_yoff);
if (!planar) {
OUT_RING_F((box_x2 - dxo) * src_scale_x);
OUT_RING_F((box_y2 - dyo) * src_scale_y);
@@ -393,8 +405,8 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
}
/* bottom left */
- OUT_RING_F(box_x1);
- OUT_RING_F(box_y2);
+ OUT_RING_F(box_x1 + pix_xoff);
+ OUT_RING_F(box_y2 + pix_yoff);
if (!planar) {
OUT_RING_F((box_x1 - dxo) * src_scale_x);
OUT_RING_F((box_y2 - dyo) * src_scale_y);
@@ -406,8 +418,8 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
}
/* top left */
- OUT_RING_F(box_x1);
- OUT_RING_F(box_y1);
+ OUT_RING_F(box_x1 + pix_xoff);
+ OUT_RING_F(box_y1 + pix_yoff);
if (!planar) {
OUT_RING_F((box_x1 - dxo) * src_scale_x);
OUT_RING_F((box_y1 - dyo) * src_scale_y);
diff --git a/src/i965_video.c b/src/i965_video.c
index af22cb24..0d1bec69 100644
--- a/src/i965_video.c
+++ b/src/i965_video.c
@@ -149,11 +149,11 @@ I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
int x1, int y1, int x2, int y2,
short src_w, short src_h,
short drw_w, short drw_h,
- DrawablePtr pDraw)
+ PixmapPtr pPixmap)
{
I830Ptr pI830 = I830PTR(pScrn);
BoxPtr pbox;
- int nbox, dxo, dyo;
+ int nbox, dxo, dyo, pix_xoff, pix_yoff;
int urb_vs_start, urb_vs_size;
int urb_gs_start, urb_gs_size;
int urb_clip_start, urb_clip_size;
@@ -381,12 +381,13 @@ I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
dest_surf_state->ss0.mipmap_layout_mode = 0;
dest_surf_state->ss0.render_cache_read_mode = 0;
- dest_surf_state->ss1.base_addr = pI830->FrontBuffer.Start;
+ dest_surf_state->ss1.base_addr = (long)pPixmap->devPrivate.ptr -
+ (long)pI830->FbBase;
dest_surf_state->ss2.height = pScrn->virtualY - 1;
dest_surf_state->ss2.width = pScrn->virtualX - 1;
dest_surf_state->ss2.mip_count = 0;
dest_surf_state->ss2.render_target_rotation = 0;
- dest_surf_state->ss3.pitch = (pI830->displayWidth * pI830->cpp) - 1;
+ dest_surf_state->ss3.pitch = pPixmap->devKind - 1;
/* Set up the source surface state buffer */
memset(src_surf_state, 0, sizeof(*src_surf_state));
@@ -656,6 +657,17 @@ I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
ADVANCE_LP_RING();
}
+ /* Set up the offset for translating from the given region (in screen
+ * coordinates) to the backing pixmap.
+ */
+#ifdef COMPOSITE
+ pix_xoff = -pPixmap->screen_x + pPixmap->drawable.x;
+ pix_yoff = -pPixmap->screen_y + pPixmap->drawable.y;
+#else
+ pix_xoff = 0;
+ pix_yoff = 0;
+#endif
+
dxo = dstRegion->extents.x1;
dyo = dstRegion->extents.y1;
@@ -685,18 +697,18 @@ I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
i = 0;
vb[i++] = (box_x2 - dxo) * src_scale_x;
vb[i++] = (box_y2 - dyo) * src_scale_y;
- vb[i++] = (float) box_x2;
- vb[i++] = (float) box_y2;
+ vb[i++] = (float) box_x2 + pix_xoff;
+ vb[i++] = (float) box_y2 + pix_yoff;
vb[i++] = (box_x1 - dxo) * src_scale_x;
vb[i++] = (box_y2 - dyo) * src_scale_y;
- vb[i++] = (float) box_x1;
- vb[i++] = (float) box_y2;
+ vb[i++] = (float) box_x1 + pix_xoff;
+ vb[i++] = (float) box_y2 + pix_yoff;
vb[i++] = (box_x1 - dxo) * src_scale_x;
vb[i++] = (box_y1 - dyo) * src_scale_y;
- vb[i++] = (float) box_x1;
- vb[i++] = (float) box_y1;
+ vb[i++] = (float) box_x1 + pix_xoff;
+ vb[i++] = (float) box_y1 + pix_yoff;
#if 0
ErrorF ("before EU_ATT 0x%08x%08x EU_ATT_DATA 0x%08x%08x\n",
diff --git a/src/ivch/Makefile.am b/src/ivch/Makefile.am
new file mode 100644
index 00000000..fac074db
--- /dev/null
+++ b/src/ivch/Makefile.am
@@ -0,0 +1,15 @@
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@
+
+ivch_la_LTLIBRARIES = ivch.la
+ivch_la_LDFLAGS = -module -avoid-version
+ivch_ladir = @moduledir@/drivers
+
+ivch_la_SOURCES = \
+ ivch.c \
+ ivch_module.c \
+ ivch_reg.h
diff --git a/src/ivch/ivch.c b/src/ivch/ivch.c
new file mode 100644
index 00000000..6c5db6c9
--- /dev/null
+++ b/src/ivch/ivch.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Resources.h"
+#include "compiler.h"
+#include "miscstruct.h"
+#include "xf86i2c.h"
+#include "../i830_xf86Crtc.h"
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "../i2c_vid.h"
+#include "ivch_reg.h"
+
+struct ivch_priv {
+ I2CDevRec d;
+
+ CARD16 save_VR01;
+ CARD16 save_VR40;
+};
+
+static void
+ivch_dump_regs(I2CDevPtr d);
+
+/**
+ * Reads a register on the ivch.
+ *
+ * Each of the 256 registers are 16 bits long.
+ */
+static Bool
+ivch_read(struct ivch_priv *priv, int addr, CARD16 *data)
+{
+ if (!xf86I2CReadWord(&priv->d, addr, data)) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to read register 0x%02x from %s:%d.\n",
+ addr, priv->d.pI2CBus->BusName, priv->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/** Writes a 16-bit register on the ivch */
+static Bool
+ivch_write(struct ivch_priv *priv, int addr, CARD16 data)
+{
+ if (!xf86I2CWriteWord(&priv->d, addr, data)) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to write register 0x%02x to %s:%d.\n",
+ addr, priv->d.pI2CBus->BusName, priv->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/** Probes the given bus and slave address for an ivch */
+static void *
+ivch_init(I2CBusPtr b, I2CSlaveAddr addr)
+{
+ struct ivch_priv *priv;
+ CARD16 temp;
+
+ xf86DrvMsg(b->scrnIndex, X_INFO, "detecting ivch\n");
+
+ priv = xcalloc(1, sizeof(struct ivch_priv));
+ if (priv = NULL)
+ return NULL;
+
+ priv->d.DevName = "i82807aa \"ivch\" LVDS/CMOS panel controller";
+ priv->d.SlaveAddr = addr;
+ priv->d.pI2CBus = b;
+ priv->d.StartTimeout = b->StartTimeout;
+ priv->d.BitTimeout = b->BitTimeout;
+ priv->d.AcknTimeout = b->AcknTimeout;
+ priv->d.ByteTimeout = b->ByteTimeout;
+ priv->d.DriverPrivate.ptr = priv;
+
+ if (!xf86I2CReadWord(&priv->d, VR00, &temp))
+ goto out;
+
+ /* Since the identification bits are probably zeroes, which doesn't seem
+ * very unique, check that the value in the base address field matches
+ * the address it's responding on.
+ */
+ if ((temp & VR00_BASE_ADDRESS_MASK) != priv->d.SlaveAddr) {
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR,
+ "ivch detect failed due to address mismatch "
+ "(%d vs %d)\n",
+ (temp & VR00_BASE_ADDRESS_MASK), priv->d.SlaveAddr);
+ }
+
+ if (!xf86I2CDevInit(&priv->d)) {
+ goto out;
+ }
+
+ return priv;
+
+out:
+ xfree(priv);
+ return NULL;
+}
+
+static xf86OutputStatus
+ivch_detect(I2CDevPtr d)
+{
+ return XF86OutputStatusUnknown;
+}
+
+static ModeStatus
+ivch_mode_valid(I2CDevPtr d, DisplayModePtr mode)
+{
+ if (mode->Clock > 112000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+/** Sets the power state of the panel connected to the ivch */
+static void
+ivch_dpms(I2CDevPtr d, int mode)
+{
+ struct ivch_priv *priv = d->DriverPrivate.ptr;
+ int i;
+ CARD16 temp;
+
+ /* Set the new power state of the panel. */
+ if (!ivch_read(priv, VR01, &temp))
+ return;
+
+ if (mode == DPMSModeOn)
+ temp |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
+ else
+ temp &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
+
+ ivch_write(priv, VR01, temp);
+
+ /* Wait for the panel to make its state transition */
+ for (i = 0; i < 1000; i++) {
+ if (!ivch_read(priv, VR30, &temp))
+ break;
+
+ if (((temp & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn))
+ break;
+ }
+}
+
+static void
+ivch_mode_set(I2CDevPtr d, DisplayModePtr mode)
+{
+ struct ivch_priv *priv = d->DriverPrivate.ptr;
+
+ /* Disable panel fitting for now, until we can test. */
+ ivch_write(priv, VR40, 0);
+
+ ivch_dpms(d, DPMSModeOn);
+
+ ivch_dump_regs(d);
+}
+
+static void
+ivch_dump_regs(I2CDevPtr d)
+{
+ struct ivch_priv *priv = d->DriverPrivate.ptr;
+ CARD16 val;
+
+ ivch_read(priv, VR00, &val);
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR00: 0x%04x\n", val);
+ ivch_read(priv, VR01, &val);
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR01: 0x%04x\n", val);
+ ivch_read(priv, VR30, &val);
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR30: 0x%04x\n", val);
+ ivch_read(priv, VR40, &val);
+ xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR40: 0x%04x\n", val);
+
+}
+
+static void
+ivch_save(I2CDevPtr d)
+{
+ struct ivch_priv *priv = d->DriverPrivate.ptr;
+
+ ivch_read(priv, VR01, &priv->save_VR01);
+ ivch_read(priv, VR40, &priv->save_VR40);
+}
+
+static void
+ivch_restore(I2CDevPtr d)
+{
+ struct ivch_priv *priv = d->DriverPrivate.ptr;
+
+ ivch_write(priv, VR01, priv->save_VR01);
+ ivch_write(priv, VR40, priv->save_VR40);
+}
+
+
+I830I2CVidOutputRec ivch_methods = {
+ .init = ivch_init,
+ .detect = ivch_detect,
+ .mode_valid = ivch_mode_valid,
+ .mode_set = ivch_mode_set,
+ .dpms = ivch_dpms,
+ .dump_regs = ivch_dump_regs,
+ .save = ivch_save,
+ .restore = ivch_restore,
+};
diff --git a/src/ivch/ivch_module.c b/src/ivch/ivch_module.c
new file mode 100644
index 00000000..1ed483b1
--- /dev/null
+++ b/src/ivch/ivch_module.c
@@ -0,0 +1,64 @@
+/* -*- c-basic-offset: 4 -*- */
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86Module.h"
+
+static MODULESETUPPROTO(ivch_setup);
+
+static XF86ModuleVersionInfo ivch_version = {
+ "ivch",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ { 0,0,0,0 }
+};
+
+_X_EXPORT XF86ModuleData ivchModuleData = {
+ &ivch_version,
+ ivch_setup,
+ NULL
+};
+
+static pointer
+ivch_setup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+ return (pointer)1;
+}
diff --git a/src/ivch/ivch_reg.h b/src/ivch/ivch_reg.h
new file mode 100644
index 00000000..112c97d6
--- /dev/null
+++ b/src/ivch/ivch_reg.h
@@ -0,0 +1,97 @@
+/* -*- c-basic-offset: 4 -*- */
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file
+ * This file contains the register definitions for the i82807aa.
+ *
+ * Documentation on this chipset can be found in datasheet #29069001 at
+ * intel.com.
+ */
+#ifndef I82807AA_REG_H
+#define I82807AA_REG_H
+
+/** @defgroup VR00
+ * @{
+ */
+#define VR00 0x00
+# define VR00_BASE_ADDRESS_MASK 0x007f
+/** @} */
+
+/** @defgroup VR01
+ * @{
+ */
+#define VR01 0x01
+# define VR01_PANEL_FIT_ENABLE (1 << 3)
+/**
+ * Enables the LCD display.
+ *
+ * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
+ */
+# define VR01_LCD_ENABLE (1 << 2)
+/** Enables the DVO repeater. */
+# define VR01_DVO_BYPASS_ENABLE (1 << 1)
+/** Enables the DVO clock */
+# define VR01_DVO_ENABLE (1 << 0)
+/** @} */
+
+/** @defgroup VR10
+ * @{
+ */
+#define VR10 0x10
+/** Enables LVDS output instead of CMOS */
+# define VR10_LVDS_ENABLE (1 << 4)
+/** Enables 18-bit LVDS output. */
+# define VR10_INTERFACE_1X18 (0 << 2)
+/** Enables 24-bit LVDS or CMOS output */
+# define VR10_INTERFACE_1X24 (1 << 2)
+/** Enables 2x18-bit LVDS or CMOS output. */
+# define VR10_INTERFACE_2X18 (2 << 2)
+/** Enables 2x24-bit LVDS output */
+# define VR10_INTERFACE_2X24 (3 << 2)
+/** @} */
+
+/** @defgroup VR30
+ * @{
+ */
+#define VR30 0x30
+/** Read only bit indicating that the panel is not in a safe poweroff state. */
+# define VR30_PANEL_ON (1 << 15)
+/** @} */
+
+/** @defgroup VR40
+ * @{
+ */
+#define VR40 0x40
+# 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_PANEL_FIT_ENABLE (1 << 8)
+/** @} */
+
+#endif /* I82807AA_REG_H */