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