i830_i2c.c revision ce2d3770
1/**************************************************************************
2
3 Copyright 2006 Dave Airlie <airlied@linux.ie>
4
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the "Software"),
9to deal in the Software without restriction, including without limitation
10on the rights to use, copy, modify, merge, publish, distribute, sub
11license, and/or sell copies of the Software, and to permit persons to whom
12the Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice (including the next
15paragraph) shall be included in all copies or substantial portions of the
16Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26**************************************************************************/
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33#include "xf86_OSproc.h"
34#include "xf86cmap.h"
35#include "compiler.h"
36#include "vgaHW.h"
37#include "mipointer.h"
38#include "micmap.h"
39#include "shadowfb.h"
40#include <X11/extensions/randr.h>
41#include "fb.h"
42#include "miscstruct.h"
43#include "xf86xv.h"
44#include <X11/extensions/Xv.h>
45#include "shadow.h"
46#include "i830.h"
47
48#define AIRLIED_I2C	0
49
50#if AIRLIED_I2C
51
52#define I2C_TIMEOUT(x)	/*(x)*/  /* Report timeouts */
53#define I2C_TRACE(x)    /*(x)*/  /* Report progress */
54
55static void i830_setscl(I2CBusPtr b, int state)
56{
57    ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
58    I830Ptr pI830 = I830PTR(pScrn);
59    uint32_t val;
60
61    OUTREG(b->DriverPrivate.uval,
62	   (state ? GPIO_CLOCK_VAL_OUT : 0) | GPIO_CLOCK_DIR_OUT |
63	   GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK);
64    val = INREG(b->DriverPrivate.uval);
65}
66
67static void i830_setsda(I2CBusPtr b, int state)
68{
69    ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
70    I830Ptr pI830 = I830PTR(pScrn);
71    uint32_t val;
72
73    OUTREG(b->DriverPrivate.uval,
74	   (state ? GPIO_DATA_VAL_OUT : 0) | GPIO_DATA_DIR_OUT |
75	   GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK);
76    val = INREG(b->DriverPrivate.uval);
77}
78
79static void i830_getscl(I2CBusPtr b, int *state)
80{
81    ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
82    I830Ptr pI830 = I830PTR(pScrn);
83    uint32_t val;
84
85    OUTREG(b->DriverPrivate.uval, GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK);
86    OUTREG(b->DriverPrivate.uval, 0);
87    val = INREG(b->DriverPrivate.uval);
88    *state = ((val & GPIO_CLOCK_VAL_IN) != 0);
89}
90
91static int i830_getsda(I2CBusPtr b)
92 {
93     ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
94     I830Ptr pI830 = I830PTR(pScrn);
95     uint32_t val;
96
97     OUTREG(b->DriverPrivate.uval, GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK);
98     OUTREG(b->DriverPrivate.uval, 0);
99     val = INREG(b->DriverPrivate.uval);
100     return ((val & GPIO_DATA_VAL_IN) != 0);
101}
102
103static inline void sdalo(I2CBusPtr b)
104{
105    i830_setsda(b, 0);
106    b->I2CUDelay(b, b->RiseFallTime);
107}
108
109static inline void sdahi(I2CBusPtr b)
110{
111    i830_setsda(b, 1);
112    b->I2CUDelay(b, b->RiseFallTime);
113}
114
115static inline void scllo(I2CBusPtr b)
116{
117    i830_setscl(b, 0);
118    b->I2CUDelay(b, b->RiseFallTime);
119}
120
121static inline int sclhi(I2CBusPtr b, int timeout)
122{
123    int scl = 0;
124    int i;
125
126    i830_setscl(b, 1);
127    b->I2CUDelay(b, b->RiseFallTime);
128
129    for (i = timeout; i > 0; i -= b->RiseFallTime) {
130	i830_getscl(b, &scl);
131	if (scl) break;
132	b->I2CUDelay(b, b->RiseFallTime);
133    }
134
135    if (i <= 0) {
136	I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d) timeout]",
137			   b->BusName, timeout));
138	return FALSE;
139    }
140    return TRUE;
141}
142
143static Bool
144I830I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last)
145{
146    I2CBusPtr b = d->pI2CBus;
147    int i, sda;
148    unsigned char indata = 0;
149
150    sdahi(b);
151
152    for (i = 0; i < 8; i++) {
153	if (sclhi(b, d->BitTimeout) == FALSE) {
154	    I2C_TRACE(ErrorF("timeout at bit #%d\n", 7-i));
155	    return FALSE;
156	};
157	indata *= 2;
158	if (i830_getsda(b))
159	    indata |= 0x01;
160	scllo(b);
161    }
162
163    if (last) {
164	sdahi(b);
165    } else {
166	sdalo(b);
167    }
168
169    if (sclhi(b, d->BitTimeout) == FALSE) {
170	sdahi(b);
171	return FALSE;
172    };
173
174    scllo(b);
175    sdahi(b);
176
177    *data = indata & 0xff;
178    I2C_TRACE(ErrorF("R%02x ", (int) *data));
179
180    return TRUE;
181}
182
183static Bool
184I830I2CPutByte(I2CDevPtr d, I2CByte c)
185{
186    Bool r;
187    int i, scl, sda;
188    int sb, ack;
189    I2CBusPtr b = d->pI2CBus;
190
191    for (i = 7; i >= 0; i--) {
192	sb = c & (1 << i);
193	i830_setsda(b, sb);
194	b->I2CUDelay(b, b->RiseFallTime);
195
196	if (sclhi(b, d->ByteTimeout) == FALSE) {
197	    sdahi(b);
198	    return FALSE;
199	}
200
201	i830_setscl(b, 0);
202	b->I2CUDelay(b, b->RiseFallTime);
203    }
204    sdahi(b);
205    if (sclhi(b, d->ByteTimeout) == FALSE) {
206	I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]",
207			   b->BusName, c, d->BitTimeout,
208			   d->ByteTimeout, d->AcknTimeout));
209	return FALSE;
210    }
211    ack = i830_getsda(b);
212    I2C_TRACE(ErrorF("Put byte 0x%02x , getsda() = %d\n", c & 0xff, ack));
213
214    scllo(b);
215    return (0 == ack);
216}
217
218static Bool
219I830I2CStart(I2CBusPtr b, int timeout)
220{
221    if (sclhi(b, timeout) == FALSE)
222	return FALSE;
223
224    sdalo(b);
225    scllo(b);
226
227    return TRUE;
228}
229
230static void
231I830I2CStop(I2CDevPtr d)
232{
233    I2CBusPtr b = d->pI2CBus;
234
235    sdalo(b);
236    sclhi(b, d->ByteTimeout);
237    sdahi(b);
238}
239
240static Bool
241I830I2CAddress(I2CDevPtr d, I2CSlaveAddr addr)
242{
243    if (I830I2CStart(d->pI2CBus, d->StartTimeout)) {
244	if (I830I2CPutByte(d, addr & 0xFF)) {
245	    if ((addr & 0xF8) != 0xF0 &&
246		(addr & 0xFE) != 0x00)
247		return TRUE;
248
249	    if (I830I2CPutByte(d, (addr >> 8) & 0xFF))
250		return TRUE;
251	}
252
253	I830I2CStop(d);
254    }
255
256    return FALSE;
257}
258
259#else
260
261#define I2C_DEBUG 0
262
263#if I2C_DEBUG
264static Bool first = TRUE;
265#endif
266
267static void
268i830I2CGetBits(I2CBusPtr b, int *clock, int *data)
269{
270    ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
271    I830Ptr pI830 = I830PTR(pScrn);
272    uint32_t val;
273
274    val = INREG(b->DriverPrivate.uval);
275
276    /*
277     * to read valid data, we must have written a 1 to
278     * the associated bit. Writing a 1 is done by
279     * tri-stating the bus in PutBits, so we needn't make
280     * sure that is true here
281     */
282    *data = (val & GPIO_DATA_VAL_IN) != 0;
283    *clock = (val & GPIO_CLOCK_VAL_IN) != 0;
284
285#if I2C_DEBUG
286    ErrorF("Getting %s:                   %c %c\n", b->BusName,
287	   *clock ? '^' : 'v',
288	   *data ? '^' : 'v');
289#endif
290}
291
292static void
293i830I2CPutBits(I2CBusPtr b, int clock, int data)
294{
295    uint32_t reserved = 0;
296    uint32_t data_bits, clock_bits;
297
298#if I2C_DEBUG
299    int cur_clock, cur_data;
300#endif
301
302    ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
303    I830Ptr pI830 = I830PTR(pScrn);
304
305#if I2C_DEBUG
306    i830I2CGetBits(b, &cur_clock, &cur_data);
307
308    if (first) {
309	ErrorF("%s Debug:        C D      C D\n", b->BusName);
310	first = FALSE;
311    }
312
313    ErrorF("Setting %s 0x%08x to: %c %c\n", b->BusName,
314	   (int)b->DriverPrivate.uval,
315	   clock ? '^' : 'v',
316	   data ? '^' : 'v');
317#endif
318
319    if (!IS_I830(pI830) && !IS_845G(pI830)) {
320	/* On most chips, these bits must be preserved in software. */
321	reserved = INREG(b->DriverPrivate.uval) &
322	    (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
323    }
324
325    /* data or clock == 1 means to tristate the bus. otherwise, drive it low */
326    if (data)
327	data_bits = GPIO_DATA_DIR_IN|GPIO_DATA_DIR_MASK;
328    else
329	data_bits = GPIO_DATA_DIR_OUT|GPIO_DATA_DIR_MASK|GPIO_DATA_VAL_MASK;
330    if (clock)
331	clock_bits = GPIO_CLOCK_DIR_IN|GPIO_CLOCK_DIR_MASK;
332    else
333	clock_bits = GPIO_CLOCK_DIR_OUT|GPIO_CLOCK_DIR_MASK|GPIO_CLOCK_VAL_MASK;
334
335    OUTREG(b->DriverPrivate.uval, reserved | data_bits | clock_bits);
336    POSTING_READ(b->DriverPrivate.uval);
337}
338
339#endif
340
341/* the i830 has a number of I2C Buses */
342Bool
343I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
344{
345    I2CBusPtr pI2CBus;
346    I830Ptr pI830 = I830PTR(pScrn);
347
348    pI2CBus = xf86CreateI2CBusRec();
349
350    if (!pI2CBus)
351	return FALSE;
352
353    pI2CBus->BusName = name;
354    pI2CBus->scrnIndex = pScrn->scrnIndex;
355#if AIRLIED_I2C
356    pI2CBus->I2CGetByte = I830I2CGetByte;
357    pI2CBus->I2CPutByte = I830I2CPutByte;
358    pI2CBus->I2CStart = I830I2CStart;
359    pI2CBus->I2CStop = I830I2CStop;
360    pI2CBus->I2CAddress = I830I2CAddress;
361#else
362    pI2CBus->I2CGetBits = i830I2CGetBits;
363    pI2CBus->I2CPutBits = i830I2CPutBits;
364#endif
365    pI2CBus->DriverPrivate.uval = i2c_reg;
366
367    /* Assume all busses are used for DDCish stuff */
368
369    /*
370     * These were set incorrectly in the server pre-1.3, Having
371     * duplicate settings is sub-optimal, but this lets the driver
372     * work with older servers
373     */
374    pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
375    pI2CBus->StartTimeout = 550;
376    pI2CBus->BitTimeout = 40;
377    pI2CBus->AcknTimeout = 40;
378    pI2CBus->RiseFallTime = 20;
379
380    /* Disable the GMBUS, which we won't use.  If it is left enabled (for
381     * example, by Mac Mini EFI initialization), GPIO access to the pins it
382     * uses gets disabled.
383     */
384    OUTREG(GMBUS0, 0);
385
386    if (!xf86I2CBusInit(pI2CBus))
387	return FALSE;
388
389    *bus_ptr = pI2CBus;
390    return TRUE;
391}
392