From 28e2affd437d59beb3843ff58d860f56d4146736 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Jul 2009 01:21:36 +0200 Subject: [PATCH 1/2] Initial support for NS2501 LVDS driving chip. This chip can be found on Fujitsu-Siemens Stylistic series of tablets which are powered by an i830. --- configure.ac | 1 + src/Makefile.am | 2 +- src/i830_dvo.c | 9 ++ src/ns2501/Makefile.am | 17 +++ src/ns2501/ns2501.c | 307 ++++++++++++++++++++++++++++++++++++++++++++ src/ns2501/ns2501.h | 31 +++++ src/ns2501/ns2501_module.c | 38 ++++++ src/ns2501/ns2501_reg.h | 60 +++++++++ 8 files changed, 464 insertions(+), 1 deletions(-) create mode 100644 src/ns2501/Makefile.am create mode 100644 src/ns2501/ns2501.c create mode 100644 src/ns2501/ns2501.h create mode 100644 src/ns2501/ns2501_module.c create mode 100644 src/ns2501/ns2501_reg.h diff --git a/configure.ac b/configure.ac index d5c12a8..67dc05a 100644 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,7 @@ AC_OUTPUT([ src/ch7017/Makefile src/ch7xxx/Makefile src/ivch/Makefile + src/ns2501/Makefile src/reg_dumper/Makefile src/sil164/Makefile src/tfp410/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index ea52fcb..2f90495 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ # 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 ch7017 ch7xxx ivch sil164 tfp410 reg_dumper render_program +SUBDIRS = xvmc bios_reader ch7017 ch7xxx ivch sil164 tfp410 ns2501 reg_dumper render_program # this is obnoxious: # -module lets us name the module exactly how we want diff --git a/src/i830_dvo.c b/src/i830_dvo.c index 2f74144..cf1ad41 100644 --- a/src/i830_dvo.c +++ b/src/i830_dvo.c @@ -37,6 +37,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "sil164/sil164.h" #include "ch7xxx/ch7xxx.h" #include "tfp410/tfp410.h" +#include "ns2501/ns2501.h" /* driver list */ static struct _I830DVODriver i830_dvo_drivers[] = @@ -63,6 +64,14 @@ static struct _I830DVODriver i830_dvo_drivers[] = .address = 0x04, /* Might also be 0x44, 0x84, 0xc4 */ }, { + .type = I830_OUTPUT_DVO_LVDS, + .modulename = "ns2501", + .fntablename = "NS2501VidOutput", + .dvo_reg = DVOC, + .address = (NS2501_ADDR_1<<1), + .gpio = GPIOE, + }, + { .type = I830_OUTPUT_DVO_TMDS, .modulename = "tfp410", .fntablename = "TFP410VidOutput", diff --git a/src/ns2501/Makefile.am b/src/ns2501/Makefile.am new file mode 100644 index 0000000..c98c730 --- /dev/null +++ b/src/ns2501/Makefile.am @@ -0,0 +1,17 @@ +# 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 = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ \ + @PCIACCESS_CFLAGS@ + +ns2501_la_LTLIBRARIES = ns2501.la +ns2501_la_LDFLAGS = -module -avoid-version +ns2501_ladir = @moduledir@/drivers + +ns2501_la_SOURCES = \ + ns2501.c \ + ns2501_module.c \ + ns2501.h \ + ns2501_reg.h diff --git a/src/ns2501/ns2501.c b/src/ns2501/ns2501.c new file mode 100644 index 0000000..2e06df4 --- /dev/null +++ b/src/ns2501/ns2501.c @@ -0,0 +1,307 @@ +/* -*- c-basic-offset: 4 -*- */ +/************************************************************************** + +Copyright © 2006 Dave Airlie + +All Rights Reserved. + +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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR 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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include + +#include "../i2c_vid.h" +#include "ns2501.h" +#include "ns2501_reg.h" + +typedef struct _NS2501SaveRec { + uint8_t reg8; + uint8_t reg9; + uint8_t regc; +} NS2501SaveRec; + +typedef struct { + I2CDevRec d; + Bool quiet; + NS2501SaveRec SavedReg; + NS2501SaveRec ModeReg; +} NS2501Rec, *NS2501Ptr; + +#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) + +static Bool +ns2501ReadByte(NS2501Ptr ns, int addr, uint8_t *ch) +{ + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501 READ BYTE, addr %d\n", addr); + + if (!xf86I2CReadByte(&(ns->d), addr, ch)) { + if (!ns->quiet) { + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_ERROR, + "ns2501 Unable to read from %s Slave %d.\n", + ns->d.pI2CBus->BusName, ns->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +static Bool +ns2501WriteByte(NS2501Ptr ns, int addr, uint8_t ch) +{ + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501 WRITE BYTE, addr %d: %d\n", addr, ch); + + if (!xf86I2CWriteByte(&(ns->d), addr, ch)) { + if (!ns->quiet) { + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_ERROR, + "ns2501 Unable to write to %s Slave %d.\n", + ns->d.pI2CBus->BusName, ns->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +static int +ns2501GetID(NS2501Ptr ns, int addr) +{ + unsigned char ch1, ch2; + + if (ns2501ReadByte(ns, addr+0, &ch1) && + ns2501ReadByte(ns, addr+1, &ch2)) { + + return ((ch2<<8) & 0xFF00) | (ch1 & 0x00FF); + } + return -1; +} + +/* National Semiconductor 2501 driver for chip on i2c bus */ +static void * +ns2501_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + /* this will detect the NS2501 chip on the specified i2c bus */ + NS2501Ptr ns; + unsigned char ch; + int id; + + ns = xcalloc(1, sizeof(NS2501Rec)); + if (ns == NULL) + return NULL; + + ns->d.DevName = "NS2501 LVDS Controller"; + ns->d.SlaveAddr = addr; + ns->d.pI2CBus = b; + ns->d.StartTimeout = b->StartTimeout; + ns->d.BitTimeout = b->BitTimeout; + ns->d.AcknTimeout = b->AcknTimeout; + ns->d.ByteTimeout = b->ByteTimeout; + ns->d.DriverPrivate.ptr = ns; + ns->quiet = FALSE; + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_init\n"); + + if ((id = ns2501GetID(ns, NS2501_VID_LO)) != NS2501_VID) { + if (id != 0xffffffff) { + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_ERROR, + "ns2501 not detected got VID %X!=%X: from %s Slave %d.\n", + NS2501_VID, id, ns->d.pI2CBus->BusName, ns->d.SlaveAddr); + } + goto out; + } + + + if (!ns2501ReadByte(ns, NS2501_VID_LO, &ch)) + goto out; + + if (ch!=(NS2501_VID & 0xFF)) { + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_ERROR, + "ns2501 not detected got %d: from %s Slave %d.\n", + ch, ns->d.pI2CBus->BusName, ns->d.SlaveAddr); + goto out; + } + + if (!ns2501ReadByte(ns, NS2501_DID_LO, &ch)) + goto out; + + if (ch!=(NS2501_DID & 0xFF)) { + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_ERROR, + "ns2501 not detected got %d: from %s Slave %d.\n", + ch, ns->d.pI2CBus->BusName, ns->d.SlaveAddr); + goto out; + } + ns->quiet = FALSE; + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_init FINAL\n"); + + if (!xf86I2CDevInit(&(ns->d))) { + goto out; + } + + return ns; + +out: + xfree(ns); + return NULL; +} + +static xf86OutputStatus +ns2501_detect(I2CDevPtr d) +{ + NS2501Ptr ns = NSPTR(d); + uint8_t reg9; + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_detect\n"); + ns2501ReadByte(ns, NS2501_REG9, ®9); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_detect, get %X\n", reg9); + + if (! (reg9 & NS2501_9_RSEN)) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; +} + +static ModeStatus +ns2501_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + return MODE_OK; +} + +static void +ns2501_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + /* As long as the basics are set up, since we don't have clock dependencies + * in the mode setup, we can just leave the registers alone and everything + * will work fine. + */ + /* recommended programming sequence from doc */ + /*ns2501WriteByte(ns, 0x08, 0x30); + ns2501WriteByte(ns, 0x09, 0x00); + ns2501WriteByte(ns, 0x0a, 0x90); + ns2501WriteByte(ns, 0x0c, 0x89); + ns2501WriteByte(ns, 0x08, 0x31);*/ + /* don't do much */ + return; +} + +/* set the NS2501 power state */ +static void +ns2501_dpms(I2CDevPtr d, int mode) +{ + NS2501Ptr ns = NSPTR(d); + int ret; + unsigned char ch; + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_dpms\n"); + + ret = ns2501ReadByte(ns, NS2501_REG8, &ch); + if (ret == FALSE) + return; + + if (mode == DPMSModeOn) + ch |= NS2501_8_PD; + else + ch &= ~NS2501_8_PD; + + ns2501WriteByte(ns, NS2501_REG8, ch); + + return; +} + +static void +ns2501_dump_regs(I2CDevPtr d) +{ + NS2501Ptr ns = NSPTR(d); + uint8_t val; + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_dump_regs\n"); + + ns2501ReadByte(ns, NS2501_FREQ_LO, &val); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "NS2501_FREQ_LO: 0x%02x\n", + val); + ns2501ReadByte(ns, NS2501_FREQ_HI, &val); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "NS2501_FREQ_HI: 0x%02x\n", + val); + ns2501ReadByte(ns, NS2501_REG8, &val); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "NS2501_REG8: 0x%02x\n", val); + ns2501ReadByte(ns, NS2501_REG9, &val); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "NS2501_REG9: 0x%02x\n", val); + ns2501ReadByte(ns, NS2501_REGC, &val); + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "NS2501_REGC: 0x%02x\n", val); +} + +static void +ns2501_save(I2CDevPtr d) +{ + NS2501Ptr ns = NSPTR(d); + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_save\n"); + + if (!ns2501ReadByte(ns, NS2501_REG8, &ns->SavedReg.reg8)) + return; + + if (!ns2501ReadByte(ns, NS2501_REG9, &ns->SavedReg.reg9)) + return; + + if (!ns2501ReadByte(ns, NS2501_REGC, &ns->SavedReg.regc)) + return; + + return; +} + +static void +ns2501_restore(I2CDevPtr d) +{ + NS2501Ptr ns = NSPTR(d); + + xf86DrvMsg(ns->d.pI2CBus->scrnIndex, X_INFO, "ns2501_restore\n"); + + /* Restore it powered down initially */ + ns2501WriteByte(ns, NS2501_REG8, ns->SavedReg.reg8 & ~0x1); + + ns2501WriteByte(ns, NS2501_REG9, ns->SavedReg.reg9); + ns2501WriteByte(ns, NS2501_REGC, ns->SavedReg.regc); + ns2501WriteByte(ns, NS2501_REG8, ns->SavedReg.reg8); +} + + +_X_EXPORT I830I2CVidOutputRec NS2501VidOutput = { + .init = ns2501_init, + .detect = ns2501_detect, + .mode_valid = ns2501_mode_valid, + .mode_set = ns2501_mode_set, + .dpms = ns2501_dpms, + .dump_regs = ns2501_dump_regs, + .save = ns2501_save, + .restore = ns2501_restore, +}; diff --git a/src/ns2501/ns2501.h b/src/ns2501/ns2501.h new file mode 100644 index 0000000..19a1b2a --- /dev/null +++ b/src/ns2501/ns2501.h @@ -0,0 +1,31 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 +on the rights to use, copy, modify, merge, publish, distribute, sub +license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS 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. + +**************************************************************************/ + +#ifndef NS2501_H +#define NS2501_H + +#define NS2501_ADDR_1 0x38 + +#endif diff --git a/src/ns2501/ns2501_module.c b/src/ns2501/ns2501_module.c new file mode 100644 index 0000000..639684e --- /dev/null +++ b/src/ns2501/ns2501_module.c @@ -0,0 +1,38 @@ +/* -*- c-basic-offset: 4 -*- */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(ns2501Setup); + +static XF86ModuleVersionInfo ns2501VersRec = { + "ns2501", + 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 ns2501ModuleData = { + &ns2501VersRec, + ns2501Setup, + NULL +}; + +static pointer +ns2501Setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + return (pointer)1; +} diff --git a/src/ns2501/ns2501_reg.h b/src/ns2501/ns2501_reg.h new file mode 100644 index 0000000..799b4c4 --- /dev/null +++ b/src/ns2501/ns2501_reg.h @@ -0,0 +1,60 @@ +/* -*- c-basic-offset: 4 -*- */ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 +on the rights to use, copy, modify, merge, publish, distribute, sub +license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS 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. + +**************************************************************************/ + +#ifndef NS2501_REG_H +#define NS2501_REG_H + +#define NS2501_VID 0x1305 +#define NS2501_DID 0x6726 + +#define NS2501_VID_LO 0x00 +#define NS2501_VID_HI 0x01 +#define NS2501_DID_LO 0x02 +#define NS2501_DID_HI 0x03 +#define NS2501_REV 0x04 +#define NS2501_RSVD 0x05 +#define NS2501_FREQ_LO 0x06 +#define NS2501_FREQ_HI 0x07 + +#define NS2501_REG8 0x08 +#define NS2501_8_VEN (1<<5) +#define NS2501_8_HEN (1<<4) +#define NS2501_8_DSEL (1<<3) +#define NS2501_8_BSEL (1<<2) +#define NS2501_8_EDGE (1<<1) +#define NS2501_8_PD (1<<0) + +#define NS2501_REG9 0x09 +#define NS2501_9_VLOW (1<<7) +#define NS2501_9_MSEL_MASK (0x7<<4) +#define NS2501_9_TSEL (1<<3) +#define NS2501_9_RSEN (1<<2) +#define NS2501_9_HTPLG (1<<1) +#define NS2501_9_MDI (1<<0) + +#define NS2501_REGC 0x0c + +#endif -- 1.6.3.3