diff options
author | Eric Anholt <eric@anholt.net> | 2006-12-28 11:53:33 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2006-12-28 12:16:48 -0800 |
commit | c7083a6f30fdf1859f60beba4c352bd790af4773 (patch) | |
tree | 79bcf4086fbe5fdd4884747303453b2277204884 /src/ch7017 | |
parent | 778db49616b233f5a2f4f007ceb62a1a878a6e25 (diff) |
Add WIP CH7017 LVDS driver. This is disconnected because it's untested.
Diffstat (limited to 'src/ch7017')
-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 |
4 files changed, 503 insertions, 0 deletions
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 */ |