diff options
author | Keith Packard <keithp@neko.keithp.com> | 2006-12-28 16:34:38 -0800 |
---|---|---|
committer | Keith Packard <keithp@neko.keithp.com> | 2006-12-28 16:34:38 -0800 |
commit | 2b0a997e5b4b51267fa4f6725f8a965093392434 (patch) | |
tree | 05db003da637a1eb2fad1b64d9ef68eb0432cd03 /src | |
parent | bb238a8fc234a8e5e86cd2f42c58c9816a15732c (diff) | |
parent | 9cfbf1ceda8f153438df1ba4b1712c55cc872017 (diff) |
Merge branch 'modesetting-origin' into modesetting
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/ch7017/Makefile.am | 15 | ||||
-rw-r--r-- | src/ch7017/ch7017.c | 302 | ||||
-rw-r--r-- | src/ch7017/ch7017_module.c | 36 | ||||
-rw-r--r-- | src/ch7017/ch7017_reg.h | 150 | ||||
-rw-r--r-- | src/i830_dvo.c | 138 | ||||
-rw-r--r-- | src/i830_video.c | 39 | ||||
-rw-r--r-- | src/i830_video.h | 4 | ||||
-rw-r--r-- | src/i915_video.c | 34 | ||||
-rw-r--r-- | src/i965_video.c | 32 | ||||
-rw-r--r-- | src/ivch/Makefile.am | 15 | ||||
-rw-r--r-- | src/ivch/ivch.c | 234 | ||||
-rw-r--r-- | src/ivch/ivch_module.c | 64 | ||||
-rw-r--r-- | src/ivch/ivch_reg.h | 97 |
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 */ |