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