1/* -*- c-basic-offset: 4 -*- */ 2/* 3 * Copyright © 2007 Dave Mueller 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * Authors: 25 * Dave Mueller <dave.mueller@gmx.ch> 26 * 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <stdint.h> 34 35#include "xf86.h" 36#include "xf86_OSproc.h" 37#include "compiler.h" 38#include "miscstruct.h" 39#include "xf86i2c.h" 40#include "xf86Crtc.h" 41#ifdef HAVE_XEXTPROTO_71 42#include <X11/extensions/dpmsconst.h> 43#else 44#define DPMS_SERVER 45#include <X11/extensions/dpms.h> 46#endif 47 48 49#include "../i2c_vid.h" 50#include "tfp410.h" 51#include "tfp410_reg.h" 52 53typedef struct _TFP410SaveRec { 54 uint8_t ctl1; 55 uint8_t ctl2; 56} TFP410SaveRec; 57 58typedef struct { 59 I2CDevRec d; 60 Bool quiet; 61 62 TFP410SaveRec SavedReg; 63 TFP410SaveRec ModeReg; 64} TFP410Rec, *TFP410Ptr; 65 66#define TFPPTR(d) ((TFP410Ptr)(d->DriverPrivate.ptr)) 67 68static Bool 69tfp410ReadByte(TFP410Ptr tfp, int addr, uint8_t *ch) 70{ 71 if (!xf86I2CReadByte(&(tfp->d), addr, ch)) { 72 if (!tfp->quiet) { 73 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, 74 "Unable to read from %s Slave %d.\n", 75 tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); 76 } 77 return FALSE; 78 } 79 return TRUE; 80} 81 82static Bool 83tfp410WriteByte(TFP410Ptr tfp, int addr, uint8_t ch) 84{ 85 if (!xf86I2CWriteByte(&(tfp->d), addr, ch)) { 86 if (!tfp->quiet) { 87 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, 88 "Unable to write to %s Slave %d.\n", 89 tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); 90 } 91 return FALSE; 92 } 93 return TRUE; 94} 95 96static int 97tfp410GetID(TFP410Ptr tfp, int addr) 98{ 99 unsigned char ch1, ch2; 100 101 if (tfp410ReadByte(tfp, addr+0, &ch1) && 102 tfp410ReadByte(tfp, addr+1, &ch2)) { 103 104 return ((ch2<<8) & 0xFF00) | (ch1 & 0x00FF); 105 } 106 return -1; 107} 108 109/* Ti TFP410 driver for chip on i2c bus */ 110static void * 111tfp410_init(I2CBusPtr b, I2CSlaveAddr addr) 112{ 113 /* this will detect the tfp410 chip on the specified i2c bus */ 114 TFP410Ptr tfp; 115 int id; 116 117 tfp = xcalloc(1, sizeof(TFP410Rec)); 118 if (tfp == NULL) 119 return NULL; 120 121 tfp->d.DevName = "TFP410 TMDS Controller"; 122 tfp->d.SlaveAddr = addr; 123 tfp->d.pI2CBus = b; 124 tfp->d.StartTimeout = b->StartTimeout; 125 tfp->d.BitTimeout = b->BitTimeout; 126 tfp->d.AcknTimeout = b->AcknTimeout; 127 tfp->d.ByteTimeout = b->ByteTimeout; 128 tfp->d.DriverPrivate.ptr = tfp; 129 tfp->quiet = TRUE; 130 131 if ((id = tfp410GetID(tfp, TFP410_VID_LO)) != TFP410_VID) { 132 if (id != 0xffffffff) { 133 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, 134 "tfp410 not detected got VID %X: from %s Slave %d.\n", 135 id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); 136 } 137 goto out; 138 } 139 140 if ((id = tfp410GetID(tfp, TFP410_DID_LO)) != TFP410_DID) { 141 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, 142 "tfp410 not detected got DID %X: from %s Slave %d.\n", 143 id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); 144 goto out; 145 } 146 tfp->quiet = FALSE; 147 148 if (!xf86I2CDevInit(&(tfp->d))) { 149 goto out; 150 } 151 152 return tfp; 153 154out: 155 xfree(tfp); 156 return NULL; 157} 158 159static xf86OutputStatus 160tfp410_detect(I2CDevPtr d) 161{ 162 TFP410Ptr tfp = TFPPTR(d); 163 xf86OutputStatus ret = XF86OutputStatusDisconnected; 164 unsigned char ctl2; 165 166 if (tfp410ReadByte(tfp, TFP410_CTL_2, &ctl2)) { 167 if (ctl2 & TFP410_CTL_2_HTPLG) 168 ret = XF86OutputStatusConnected; 169 else 170 ret = XF86OutputStatusDisconnected; 171 } 172 173 return ret; 174} 175 176static ModeStatus 177tfp410_mode_valid(I2CDevPtr d, DisplayModePtr mode) 178{ 179 return MODE_OK; 180} 181 182static void 183tfp410_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) 184{ 185 /* As long as the basics are set up, since we don't have clock dependencies 186 * in the mode setup, we can just leave the registers alone and everything 187 * will work fine. 188 */ 189 /* don't do much */ 190 return; 191} 192 193/* set the tfp410 power state */ 194static void 195tfp410_dpms(I2CDevPtr d, int mode) 196{ 197 TFP410Ptr tfp = TFPPTR(d); 198 unsigned char ctl1; 199 200 if (!tfp410ReadByte(tfp, TFP410_CTL_1, &ctl1)) 201 return; 202 203 if (mode == DPMSModeOn) 204 ctl1 |= TFP410_CTL_1_PD; 205 else 206 ctl1 &= ~TFP410_CTL_1_PD; 207 208 tfp410WriteByte(tfp, TFP410_CTL_1, ctl1); 209} 210 211static void 212tfp410_dump_regs(I2CDevPtr d) 213{ 214 TFP410Ptr tfp = TFPPTR(d); 215 uint8_t val, val2; 216 217 tfp410ReadByte(tfp, TFP410_REV, &val); 218 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 219 "TFP410_REV: 0x%02X\n", val); 220 tfp410ReadByte(tfp, TFP410_CTL_1, &val); 221 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 222 "TFP410_CTL1: 0x%02X\n", val); 223 tfp410ReadByte(tfp, TFP410_CTL_2, &val); 224 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 225 "TFP410_CTL2: 0x%02X\n", val); 226 tfp410ReadByte(tfp, TFP410_CTL_3, &val); 227 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 228 "TFP410_CTL3: 0x%02X\n", val); 229 tfp410ReadByte(tfp, TFP410_USERCFG, &val); 230 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 231 "TFP410_USERCFG: 0x%02X\n", val); 232 tfp410ReadByte(tfp, TFP410_DE_DLY, &val); 233 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 234 "TFP410_DE_DLY: 0x%02X\n", val); 235 tfp410ReadByte(tfp, TFP410_DE_CTL, &val); 236 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 237 "TFP410_DE_CTL: 0x%02X\n", val); 238 tfp410ReadByte(tfp, TFP410_DE_TOP, &val); 239 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 240 "TFP410_DE_TOP: 0x%02X\n", val); 241 tfp410ReadByte(tfp, TFP410_DE_CNT_LO, &val); 242 tfp410ReadByte(tfp, TFP410_DE_CNT_HI, &val2); 243 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 244 "TFP410_DE_CNT: 0x%02X%02X\n", val2, val); 245 tfp410ReadByte(tfp, TFP410_DE_LIN_LO, &val); 246 tfp410ReadByte(tfp, TFP410_DE_LIN_HI, &val2); 247 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 248 "TFP410_DE_LIN: 0x%02X%02X\n", val2, val); 249 tfp410ReadByte(tfp, TFP410_H_RES_LO, &val); 250 tfp410ReadByte(tfp, TFP410_H_RES_HI, &val2); 251 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 252 "TFP410_H_RES: 0x%02X%02X\n", val2, val); 253 tfp410ReadByte(tfp, TFP410_V_RES_LO, &val); 254 tfp410ReadByte(tfp, TFP410_V_RES_HI, &val2); 255 xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, 256 "TFP410_V_RES: 0x%02X%02X\n", val2, val); 257} 258 259static void 260tfp410_save(I2CDevPtr d) 261{ 262 TFP410Ptr tfp = TFPPTR(d); 263 264 if (!tfp410ReadByte(tfp, TFP410_CTL_1, &tfp->SavedReg.ctl1)) 265 return; 266 267 if (!tfp410ReadByte(tfp, TFP410_CTL_2, &tfp->SavedReg.ctl2)) 268 return; 269} 270 271static void 272tfp410_restore(I2CDevPtr d) 273{ 274 TFP410Ptr tfp = TFPPTR(d); 275 276 /* Restore it powered down initially */ 277 tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1 & ~0x1); 278 279 tfp410WriteByte(tfp, TFP410_CTL_2, tfp->SavedReg.ctl2); 280 tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1); 281} 282 283_X_EXPORT I830I2CVidOutputRec TFP410VidOutput = { 284 .init = tfp410_init, 285 .detect = tfp410_detect, 286 .mode_valid = tfp410_mode_valid, 287 .mode_set = tfp410_mode_set, 288 .dpms = tfp410_dpms, 289 .dump_regs = tfp410_dump_regs, 290 .save = tfp410_save, 291 .restore = tfp410_restore, 292}; 293