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