atimach64i2c.c revision 1b12faf6
1/*
2 * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as-is" without express or implied warranty.
13 *
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "ati.h"
28#include "atichip.h"
29#include "atii2c.h"
30#include "atimach64i2c.h"
31#include "atimach64io.h"
32#include "atituner.h"
33
34/* MPP_CONFIG register values */
35#define MPP_INIT     pATI->NewHW.mpp_config
36
37#define MPP_WRITE    (MPP_INIT                                               )
38#define MPP_WRITEINC (MPP_INIT | (MPP_AUTO_INC_EN                           ))
39#define MPP_READ     (MPP_INIT | (                  MPP_BUFFER_MODE_PREFETCH))
40#define MPP_READINC  (MPP_INIT | (MPP_AUTO_INC_EN | MPP_BUFFER_MODE_PREFETCH))
41
42/*
43 * ATIMach64MPPWaitForIdle --
44 *
45 * Support function to wait for the Multimedia Peripheral Port to become idle.
46 * Currently, this function's return value indicates whether or not the port
47 * became idle within 512 polling iterations.  For now, this value is ignored
48 * by the rest of the code, but might be used in the future.
49 */
50static Bool
51ATIMach64MPPWaitForIdle
52(
53    ATIPtr pATI
54)
55{
56    CARD32 Count = 0x0200;
57
58    while (in8(MPP_CONFIG + 3) & GetByte(MPP_BUSY, 3))
59    {
60        if (!--Count)
61            return FALSE;
62        usleep(1);              /* XXX Excessive? */
63    }
64
65    return TRUE;
66}
67
68/*
69 * ATIMach64MPPSetAddress --
70 *
71 * Sets a 16-bit ImpacTV address on the Multimedia Peripheral Port.
72 */
73static void
74ATIMach64MPPSetAddress
75(
76    ATIPtr pATI,
77    CARD16 Address
78)
79{
80    ATIMach64MPPWaitForIdle(pATI);
81    outr(MPP_CONFIG, MPP_WRITEINC);
82    outr(MPP_ADDR, 0x00000008U);
83    out8(MPP_DATA, (CARD8)Address);
84    ATIMach64MPPWaitForIdle(pATI);
85    out8(MPP_DATA, (CARD8)(Address >> 8));
86    ATIMach64MPPWaitForIdle(pATI);
87    outr(MPP_CONFIG, MPP_WRITE);
88    outr(MPP_ADDR, 0x00000018U);
89    ATIMach64MPPWaitForIdle(pATI);
90}
91
92/*
93 * ATIMach64ImpacTVProbe --
94 *
95 * This probes for an ImpacTV chip and returns its chip ID, or 0.
96 */
97static int
98ATIMach64ImpacTVProbe
99(
100    int    iScreen,
101    ATIPtr pATI
102)
103{
104    CARD8 ChipID = 0;
105
106    /* Assume ATIModePreInit() has already been called */
107    outr(MPP_STROBE_SEQ, pATI->NewHW.mpp_strobe_seq);
108    outr(TVO_CNTL, pATI->NewHW.tvo_cntl);
109
110    outr(MPP_CONFIG, MPP_READ);
111    ATIMach64MPPWaitForIdle(pATI);
112    outr(MPP_ADDR, 0x0000000AU);
113    if (!(ChipID = in8(MPP_DATA)))
114    {
115         ATIMach64MPPWaitForIdle(pATI);
116         outr(MPP_ADDR, 0x00000023U);
117         if ((ChipID = in8(MPP_DATA)) != 0x54U)
118         {
119             ATIMach64MPPWaitForIdle(pATI);
120             outr(MPP_ADDR, 0x0000000BU);
121             ChipID = in8(MPP_DATA);
122         }
123    }
124    ATIMach64MPPWaitForIdle(pATI);
125    outr(MPP_CONFIG, MPP_WRITE);
126
127    if (ChipID)
128        xf86DrvMsg(iScreen, X_PROBED, "ImpacTV chip ID 0x%02X detected.\n",
129            ChipID);
130
131    return (int)(CARD16)ChipID;
132}
133
134/*
135 * ATIMach64ImpacTVSetBits --
136 *
137 * Controls I2C SDA and SCL lines through ImpacTV.
138 */
139static void
140ATIMach64ImpacTVSetBits
141(
142    ATII2CPtr pATII2C,
143    ATIPtr    pATI,
144    CARD32    Bits
145)
146{
147    pATII2C->I2CCur = Bits;
148
149    ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL);
150
151    outr(MPP_CONFIG, MPP_WRITE);
152
153    out8(MPP_DATA, (CARD8)Bits);
154
155    ATIMach64MPPWaitForIdle(pATI);
156}
157
158/*
159 * ATIMach64ImpacTVGetBits --
160 *
161 * Returns the status of an ImpacTV's I2C control lines.
162 */
163static CARD32
164ATIMach64ImpacTVGetBits
165(
166    ATIPtr    pATI
167)
168{
169    ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL);
170
171    outr(MPP_CONFIG, MPP_READ);
172
173    ATIMach64MPPWaitForIdle(pATI);
174
175    return in8(MPP_DATA);
176}
177
178/*
179 * ATIMach64I2C_CNTLSetBits --
180 *
181 * Controls SDA and SCL lines through a 3D Rage Pro's hardware assisted I2C.
182 */
183static void
184ATIMach64I2C_CNTLSetBits
185(
186    ATII2CPtr pATII2C,
187    ATIPtr    pATI,
188    CARD32    Bits
189)
190{
191    pATII2C->I2CCur = Bits;
192
193    out8(I2C_CNTL_0 + 1, (CARD8)Bits);
194}
195
196/*
197 * ATIMach64I2C_CNTLGetBits --
198 *
199 * Returns the status of a 3D Rage Pro's hardware assisted I2C control lines.
200 */
201static CARD32
202ATIMach64I2C_CNTLGetBits
203(
204    ATIPtr    pATI
205)
206{
207    return in8(I2C_CNTL_0 + 1);
208}
209
210/*
211 * ATIMach64GP_IOSetBits --
212 *
213 * Controls SDA and SCL control lines through a Mach64's GP_IO register.
214 */
215static void
216ATIMach64GP_IOSetBits
217(
218    ATII2CPtr pATII2C,
219    ATIPtr    pATI,
220    CARD32    Bits
221)
222{
223    pATII2C->I2CCur = Bits;
224
225    outr(GP_IO, Bits);
226}
227
228/*
229 * ATIMach64GP_IOGetBits --
230 *
231 * Returns the status of I2C control lines through a Mach64's GP_IO register.
232 */
233static CARD32
234ATIMach64GP_IOGetBits
235(
236    ATIPtr    pATI
237)
238{
239    return inr(GP_IO);
240}
241
242#define GPIO1_MASK \
243    (DAC_GIO_STATE_1 | DAC_GIO_DIR_1)
244#define GPIO2_MASK \
245    (GEN_GIO2_DATA_OUT | GEN_GIO2_DATA_IN | GEN_GIO2_WRITE)
246
247/*
248 * ATIMach64DAC_GENSetBits --
249 *
250 * Controls SDA and SCL control lines through a Mach64's GEN_TEST_CNTL and
251 * DAC_CNTL registers.
252 */
253static void
254ATIMach64DAC_GENSetBits
255(
256    ATII2CPtr pATII2C,
257    ATIPtr    pATI,
258    CARD32    Bits
259)
260{
261    CARD32 tmp;
262
263    pATII2C->I2CCur = Bits;
264
265    tmp = inr(DAC_CNTL) & ~GPIO1_MASK;
266    outr(DAC_CNTL, tmp | (Bits & GPIO1_MASK));
267    tmp = inr(GEN_TEST_CNTL) & ~GPIO2_MASK;
268    outr(GEN_TEST_CNTL, tmp | (Bits & GPIO2_MASK));
269}
270
271/*
272 * ATIMach64DAC_GENGetBits --
273 *
274 * Returns the status of I2C control lines through a Mach64's GEN_TEST_CNTL and
275 * DAC_CNTL registers.
276 */
277static CARD32
278ATIMach64DAC_GENGetBits
279(
280    ATIPtr    pATI
281)
282{
283    return (inr(DAC_CNTL) & GPIO1_MASK) | (inr(GEN_TEST_CNTL) & GPIO2_MASK);
284}
285
286/*
287 * ATITVAddOnProbe --
288 *
289 * Probe for an ATI-TV add-on card at specific addresses on an I2C bus.
290 */
291static Bool
292ATITVAddOnProbe
293(
294    ScrnInfoPtr pScreenInfo,
295    ATIPtr      pATI,
296    I2CBusPtr   pI2CBus
297)
298{
299    I2CDevPtr pI2CDev = xnfcalloc(1, SizeOf(I2CDevRec));
300    int       Index;
301    I2CByte   tmp;
302
303    static const CARD8 ATITVAddOnAddresses[] = {0x70, 0x40, 0x78, 0x72, 0x42};
304
305    pI2CDev->DevName      = "ATI-TV Add-on";
306    pI2CDev->pI2CBus      = pI2CBus;
307    pI2CDev->StartTimeout = pI2CBus->StartTimeout;
308    pI2CDev->BitTimeout   = pI2CBus->BitTimeout;
309    pI2CDev->AcknTimeout  = pI2CBus->AcknTimeout;
310    pI2CDev->ByteTimeout  = pI2CBus->ByteTimeout;
311
312    for (Index = 0;  Index < NumberOf(ATITVAddOnAddresses);  Index++)
313    {
314        pI2CDev->SlaveAddr = ATITVAddOnAddresses[Index];
315
316        if (xf86I2CFindDev(pI2CBus, pI2CDev->SlaveAddr))
317            continue;
318
319        tmp = 0xFFU;
320
321        if (!(*pI2CBus->I2CWriteRead)(pI2CDev, &tmp, 1, NULL, 0) ||
322            !(*pI2CBus->I2CWriteRead)(pI2CDev, NULL, 0, &tmp, 1) ||
323            (tmp == 0xFFU) || ((tmp = tmp & 0x1FU) == /*ATI_TUNER_NONE*/0))
324            continue;
325
326        if (!xf86I2CDevInit(pI2CDev))
327        {
328            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
329                "Failed to register I2C device for ATI-TV add-on.\n");
330            break;
331        }
332
333        if (pATI->Tuner != tmp)
334        {
335            if (pATI->Tuner != ATI_TUNER_NONE)
336                xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
337                    "Tuner type mismatch:  BIOS 0x%x, ATI-TV 0x%x.\n",
338                    pATI->Tuner, tmp);
339
340            pATI->Tuner = tmp;
341        }
342
343        xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
344            "%s tuner detected on ATI-TV add-on adapter at I2C bus address"
345            " 0x%2x.\n", ATITuners[pATI->Tuner].name, pI2CDev->SlaveAddr);
346
347        return TRUE;
348    }
349
350    free(pI2CDev);
351    return FALSE;
352}
353
354/*
355 * ATIMach64I2CPreInit --
356 *
357 * This function potentially allocates an I2CBusRec and initialises it with
358 * ATI-specific and Mach64-specific information.
359 */
360void
361ATIMach64I2CPreInit
362(
363    ScrnInfoPtr pScreenInfo,
364    ATIPtr      pATI
365)
366{
367    I2CBusPtr pI2CBus;
368    ATII2CPtr pATII2C;
369
370    if ((pATI->Chip < ATI_CHIP_264CT) || (pATI->Chip >= ATI_CHIP_Mach64))
371        return;
372
373    /* Create an I2CBusRec and generically prime it */
374    if (!(pI2CBus = ATICreateI2CBusRec(pScreenInfo->scrnIndex, pATI, "Mach64")))
375        return;
376
377    pATII2C = pI2CBus->DriverPrivate.ptr;
378
379    switch (pATI->Chip)
380    {
381        case ATI_CHIP_264GTPRO:
382        case ATI_CHIP_264LTPRO:
383        case ATI_CHIP_264XL:
384        case ATI_CHIP_MOBILITY:
385            /*
386             * These have I2C-specific registers.  Assume older I2C access
387             * mechanisms are inoperative.
388             */
389            pATII2C->I2CSetBits = ATIMach64I2C_CNTLSetBits;
390            pATII2C->I2CGetBits = ATIMach64I2C_CNTLGetBits;
391            pATII2C->SCLDir = pATII2C->SDADir = 0;
392            pATII2C->SCLGet = pATII2C->SCLSet = GetByte(I2C_CNTL_SCL, 1);
393            pATII2C->SDAGet = pATII2C->SDASet = GetByte(I2C_CNTL_SDA, 1);
394
395            out8(I2C_CNTL_1 + 2, GetByte(I2C_SEL, 2));
396            out8(I2C_CNTL_0 + 0,
397                GetByte(I2C_CNTL_STAT | I2C_CNTL_HPTR_RST, 0));
398            break;
399
400        case ATI_CHIP_264VTB:
401        case ATI_CHIP_264GTB:
402        case ATI_CHIP_264VT3:
403        case ATI_CHIP_264GTDVD:
404        case ATI_CHIP_264LT:
405        case ATI_CHIP_264VT4:
406        case ATI_CHIP_264GT2C:
407            /* If an ImpacTV chip is found, use it to provide I2C access */
408            if (ATIMach64ImpacTVProbe(pScreenInfo->scrnIndex, pATI))
409            {
410                pATII2C->I2CSetBits = ATIMach64ImpacTVSetBits;
411                pATII2C->I2CGetBits = ATIMach64ImpacTVGetBits;
412                pATII2C->SCLDir = IT_SCL_DIR;
413                pATII2C->SCLGet = IT_SCL_GET;
414                pATII2C->SCLSet = IT_SCL_SET;
415                pATII2C->SDADir = IT_SDA_DIR;
416                pATII2C->SDAGet = IT_SDA_GET;
417                pATII2C->SDASet = IT_SDA_SET;
418
419                ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL);
420                outr(MPP_CONFIG, MPP_WRITEINC);
421                out8(MPP_DATA, 0x00U);
422                out8(MPP_DATA, 0x55U);
423                out8(MPP_DATA, 0x00U);
424                out8(MPP_DATA, 0x00U);
425                ATIMach64MPPWaitForIdle(pATI);
426                break;
427            }
428            /* Otherwise, fall through to the older case */
429
430        case ATI_CHIP_264VT:
431        case ATI_CHIP_264GT:
432            /* First try GIO pins 11 (clock) and 4 (data) */
433            pATII2C->I2CSetBits = ATIMach64GP_IOSetBits;
434            pATII2C->I2CGetBits = ATIMach64GP_IOGetBits;
435            pATII2C->SCLDir = GP_IO_DIR_B;
436            pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_B;
437            pATII2C->SDADir = GP_IO_DIR_4;
438            pATII2C->SDAGet = pATII2C->SDASet = GP_IO_4;
439
440            if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus))
441                break;
442
443            /* Next, try pins 10 (clock) and 12 (data) */
444            pATII2C->SCLDir = GP_IO_DIR_A;
445            pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_A;
446            pATII2C->SDADir = GP_IO_DIR_C;
447            pATII2C->SDAGet = pATII2C->SDASet = GP_IO_C;
448
449            if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus))
450                break;
451            /* Otherwise, fall back to ATI's first I2C implementation */
452
453        default:
454            /*
455             * First generation integrated controllers access GIO pin 1 (clock)
456             * though DAC_CNTL, and pin 2 (data) through GEN_TEST_CNTL.
457             */
458            pATII2C->I2CSetBits = ATIMach64DAC_GENSetBits;
459            pATII2C->I2CGetBits = ATIMach64DAC_GENGetBits;
460            pATII2C->SCLDir = DAC_GIO_DIR_1;
461            pATII2C->SCLGet = pATII2C->SCLSet = DAC_GIO_STATE_1;
462            pATII2C->SDADir = GEN_GIO2_WRITE;
463            pATII2C->SDAGet = GEN_GIO2_DATA_IN;
464            pATII2C->SDASet = GEN_GIO2_DATA_OUT;
465
466            (void)ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus);
467            break;
468    }
469}
470