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