1/* -*- c-basic-offset: 4 -*- */ 2/************************************************************************** 3 4Copyright © 2006 Dave Airlie 5 6All Rights Reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a 9copy of this software and associated documentation files (the 10"Software"), to deal in the Software without restriction, including 11without limitation the rights to use, copy, modify, merge, publish, 12distribute, sub license, and/or sell copies of the Software, and to 13permit persons to whom the Software is furnished to do so, subject to 14the following conditions: 15 16The above copyright notice and this permission notice (including the 17next paragraph) shall be included in all copies or substantial portions 18of the Software. 19 20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 23IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 28**************************************************************************/ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif 33 34#include <stdint.h> 35 36#include "xf86.h" 37#include "xf86_OSproc.h" 38#include "compiler.h" 39#include "miscstruct.h" 40#include "xf86i2c.h" 41#include "xf86Crtc.h" 42#ifdef HAVE_XEXTPROTO_71 43#include <X11/extensions/dpmsconst.h> 44#else 45#define DPMS_SERVER 46#include <X11/extensions/dpms.h> 47#endif 48 49 50#include "../i2c_vid.h" 51#include "sil164.h" 52#include "sil164_reg.h" 53 54typedef struct _Sil164SaveRec { 55 uint8_t reg8; 56 uint8_t reg9; 57 uint8_t regc; 58} SIL164SaveRec; 59 60typedef struct { 61 I2CDevRec d; 62 Bool quiet; 63 SIL164SaveRec SavedReg; 64 SIL164SaveRec ModeReg; 65} SIL164Rec, *SIL164Ptr; 66 67#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) 68 69static Bool 70sil164ReadByte(SIL164Ptr sil, int addr, uint8_t *ch) 71{ 72 if (!xf86I2CReadByte(&(sil->d), addr, ch)) { 73 if (!sil->quiet) { 74 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, 75 "Unable to read from %s Slave %d.\n", 76 sil->d.pI2CBus->BusName, sil->d.SlaveAddr); 77 } 78 return FALSE; 79 } 80 return TRUE; 81} 82 83static Bool 84sil164WriteByte(SIL164Ptr sil, int addr, uint8_t ch) 85{ 86 if (!xf86I2CWriteByte(&(sil->d), addr, ch)) { 87 if (!sil->quiet) { 88 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, 89 "Unable to write to %s Slave %d.\n", 90 sil->d.pI2CBus->BusName, sil->d.SlaveAddr); 91 } 92 return FALSE; 93 } 94 return TRUE; 95} 96 97/* Silicon Image 164 driver for chip on i2c bus */ 98static void * 99sil164_init(I2CBusPtr b, I2CSlaveAddr addr) 100{ 101 /* this will detect the SIL164 chip on the specified i2c bus */ 102 SIL164Ptr sil; 103 unsigned char ch; 104 105 sil = xcalloc(1, sizeof(SIL164Rec)); 106 if (sil == NULL) 107 return NULL; 108 109 sil->d.DevName = "SIL164 TMDS Controller"; 110 sil->d.SlaveAddr = addr; 111 sil->d.pI2CBus = b; 112 sil->d.StartTimeout = b->StartTimeout; 113 sil->d.BitTimeout = b->BitTimeout; 114 sil->d.AcknTimeout = b->AcknTimeout; 115 sil->d.ByteTimeout = b->ByteTimeout; 116 sil->d.DriverPrivate.ptr = sil; 117 sil->quiet = TRUE; 118 119 if (!sil164ReadByte(sil, SIL164_VID_LO, &ch)) 120 goto out; 121 122 if (ch!=(SIL164_VID & 0xFF)) { 123 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, 124 "sil164 not detected got %d: from %s Slave %d.\n", 125 ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr); 126 goto out; 127 } 128 129 if (!sil164ReadByte(sil, SIL164_DID_LO, &ch)) 130 goto out; 131 132 if (ch!=(SIL164_DID & 0xFF)) { 133 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, 134 "sil164 not detected got %d: from %s Slave %d.\n", 135 ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr); 136 goto out; 137 } 138 sil->quiet = FALSE; 139 140 if (!xf86I2CDevInit(&(sil->d))) { 141 goto out; 142 } 143 144 return sil; 145 146out: 147 xfree(sil); 148 return NULL; 149} 150 151static xf86OutputStatus 152sil164_detect(I2CDevPtr d) 153{ 154 SIL164Ptr sil = SILPTR(d); 155 uint8_t reg9; 156 157 sil164ReadByte(sil, SIL164_REG9, ®9); 158 159 if (reg9 & SIL164_9_HTPLG) 160 return XF86OutputStatusConnected; 161 else 162 return XF86OutputStatusDisconnected; 163} 164 165static ModeStatus 166sil164_mode_valid(I2CDevPtr d, DisplayModePtr mode) 167{ 168 return MODE_OK; 169} 170 171static void 172sil164_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) 173{ 174 /* As long as the basics are set up, since we don't have clock dependencies 175 * in the mode setup, we can just leave the registers alone and everything 176 * will work fine. 177 */ 178 /* recommended programming sequence from doc */ 179 /*sil164WriteByte(sil, 0x08, 0x30); 180 sil164WriteByte(sil, 0x09, 0x00); 181 sil164WriteByte(sil, 0x0a, 0x90); 182 sil164WriteByte(sil, 0x0c, 0x89); 183 sil164WriteByte(sil, 0x08, 0x31);*/ 184 /* don't do much */ 185 return; 186} 187 188/* set the SIL164 power state */ 189static void 190sil164_dpms(I2CDevPtr d, int mode) 191{ 192 SIL164Ptr sil = SILPTR(d); 193 int ret; 194 unsigned char ch; 195 196 ret = sil164ReadByte(sil, SIL164_REG8, &ch); 197 if (ret == FALSE) 198 return; 199 200 if (mode == DPMSModeOn) 201 ch |= SIL164_8_PD; 202 else 203 ch &= ~SIL164_8_PD; 204 205 sil164WriteByte(sil, SIL164_REG8, ch); 206 207 return; 208} 209 210static void 211sil164_dump_regs(I2CDevPtr d) 212{ 213 SIL164Ptr sil = SILPTR(d); 214 uint8_t val; 215 216 sil164ReadByte(sil, SIL164_FREQ_LO, &val); 217 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_LO: 0x%02x\n", 218 val); 219 sil164ReadByte(sil, SIL164_FREQ_HI, &val); 220 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_HI: 0x%02x\n", 221 val); 222 sil164ReadByte(sil, SIL164_REG8, &val); 223 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG8: 0x%02x\n", val); 224 sil164ReadByte(sil, SIL164_REG9, &val); 225 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG9: 0x%02x\n", val); 226 sil164ReadByte(sil, SIL164_REGC, &val); 227 xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REGC: 0x%02x\n", val); 228} 229 230static void 231sil164_save(I2CDevPtr d) 232{ 233 SIL164Ptr sil = SILPTR(d); 234 235 if (!sil164ReadByte(sil, SIL164_REG8, &sil->SavedReg.reg8)) 236 return; 237 238 if (!sil164ReadByte(sil, SIL164_REG9, &sil->SavedReg.reg9)) 239 return; 240 241 if (!sil164ReadByte(sil, SIL164_REGC, &sil->SavedReg.regc)) 242 return; 243 244 return; 245} 246 247static void 248sil164_restore(I2CDevPtr d) 249{ 250 SIL164Ptr sil = SILPTR(d); 251 252 /* Restore it powered down initially */ 253 sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8 & ~0x1); 254 255 sil164WriteByte(sil, SIL164_REG9, sil->SavedReg.reg9); 256 sil164WriteByte(sil, SIL164_REGC, sil->SavedReg.regc); 257 sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8); 258} 259 260 261_X_EXPORT I830I2CVidOutputRec SIL164VidOutput = { 262 .init = sil164_init, 263 .detect = sil164_detect, 264 .mode_valid = sil164_mode_valid, 265 .mode_set = sil164_mode_set, 266 .dpms = sil164_dpms, 267 .dump_regs = sil164_dump_regs, 268 .save = sil164_save, 269 .restore = sil164_restore, 270}; 271