atidac.c revision 32b578d3
1/*
2 * Copyright 1997 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 <string.h>
28
29#include "ati.h"
30#include "atidac.h"
31#include "atimach64io.h"
32
33/*
34 * RAMDAC-related definitions.
35 */
36const SymTabRec ATIDACDescriptors[] =
37{   /* Keep this table in ascending DACType order */
38    {ATI_DAC_ATI68830,      "ATI 68830 or similar"},
39    {ATI_DAC_SC11483,       "Sierra 11483 or similar"},
40    {ATI_DAC_ATI68875,      "ATI 68875 or similar"},
41    {ATI_DAC_TVP3026_A,     "TI ViewPoint3026 or similar"},
42    {ATI_DAC_GENERIC,       "Brooktree 476 or similar"},
43    {ATI_DAC_BT481,         "Brooktree 481 or similar"},
44    {ATI_DAC_ATT20C491,     "AT&T 20C491 or similar"},
45    {ATI_DAC_SC15026,       "Sierra 15026 or similar"},
46    {ATI_DAC_MU9C1880,      "Music 9C1880 or similar"},
47    {ATI_DAC_IMSG174,       "Inmos G174 or similar"},
48    {ATI_DAC_ATI68860_B,    "ATI 68860 (Revision B) or similar"},
49    {ATI_DAC_ATI68860_C,    "ATI 68860 (Revision C) or similar"},
50    {ATI_DAC_TVP3026_B,     "TI ViewPoint3026 or similar"},
51    {ATI_DAC_STG1700,       "SGS-Thompson 1700 or similar"},
52    {ATI_DAC_ATT20C498,     "AT&T 20C498 or similar"},
53    {ATI_DAC_STG1702,       "SGS-Thompson 1702 or similar"},
54    {ATI_DAC_SC15021,       "Sierra 15021 or similar"},
55    {ATI_DAC_ATT21C498,     "AT&T 21C498 or similar"},
56    {ATI_DAC_STG1703,       "SGS-Thompson 1703 or similar"},
57    {ATI_DAC_CH8398,        "Chrontel 8398 or similar"},
58    {ATI_DAC_ATT20C408,     "AT&T 20C408 or similar"},
59    {ATI_DAC_INTERNAL,      "Internal"},
60    {ATI_DAC_IBMRGB514,     "IBM RGB 514 or similar"},
61    {ATI_DAC_UNKNOWN,       "Unknown"}          /* Must be last */
62};
63
64#ifndef AVOID_CPIO
65
66/*
67 * ATISetDACIOPorts --
68 *
69 * This function sets up DAC access I/O port numbers.
70 */
71void
72ATISetDACIOPorts
73(
74    ATIPtr      pATI,
75    ATICRTCType crtc
76)
77{
78    switch (crtc)
79    {
80        case ATI_CRTC_VGA:
81            pATI->CPIO_DAC_DATA = VGA_DAC_DATA;
82            pATI->CPIO_DAC_MASK = VGA_DAC_MASK;
83            pATI->CPIO_DAC_READ = VGA_DAC_READ;
84            pATI->CPIO_DAC_WRITE = VGA_DAC_WRITE;
85            pATI->CPIO_DAC_WAIT = GENS1(pATI->CPIO_VGABase);
86            break;
87
88        case ATI_CRTC_8514:
89            pATI->CPIO_DAC_DATA = IBM_DAC_DATA;
90            pATI->CPIO_DAC_MASK = IBM_DAC_MASK;
91            pATI->CPIO_DAC_READ = IBM_DAC_READ;
92            pATI->CPIO_DAC_WRITE = IBM_DAC_WRITE;
93            pATI->CPIO_DAC_WAIT = pATI->CPIO_DAC_MASK;
94            break;
95
96        case ATI_CRTC_MACH64:
97            pATI->CPIO_DAC_DATA = ATIIOPort(DAC_REGS) + 1;
98            pATI->CPIO_DAC_MASK = ATIIOPort(DAC_REGS) + 2;
99            pATI->CPIO_DAC_READ = ATIIOPort(DAC_REGS) + 3;
100            pATI->CPIO_DAC_WRITE = ATIIOPort(DAC_REGS) + 0;
101            pATI->CPIO_DAC_WAIT = pATI->CPIOBase;
102            break;
103
104        default:
105            break;
106    }
107}
108
109#endif /* AVOID_CPIO */
110
111/*
112 * ATIGetDACCmdReg --
113 *
114 * Setup to access a RAMDAC's command register.
115 */
116CARD8
117ATIGetDACCmdReg
118(
119    ATIPtr pATI
120)
121{
122
123#ifdef AVOID_CPIO
124
125    (void)in8(M64_DAC_WRITE);           /* Reset to PEL mode */
126    (void)in8(M64_DAC_MASK);
127    (void)in8(M64_DAC_MASK);
128    (void)in8(M64_DAC_MASK);
129    return in8(M64_DAC_MASK);
130
131#else /* AVOID_CPIO */
132
133    (void)inb(pATI->CPIO_DAC_WRITE);    /* Reset to PEL mode */
134    (void)inb(pATI->CPIO_DAC_MASK);
135    (void)inb(pATI->CPIO_DAC_MASK);
136    (void)inb(pATI->CPIO_DAC_MASK);
137    return inb(pATI->CPIO_DAC_MASK);
138
139#endif /* AVOID_CPIO */
140
141}
142
143/*
144 * ATIDACPreInit --
145 *
146 * This function initialises the fields in an ATIHWRec that relate to DACs.
147 */
148void
149ATIDACPreInit
150(
151    ScrnInfoPtr pScreenInfo,
152    ATIPtr      pATI,
153    ATIHWPtr    pATIHW
154)
155{
156    int Index, Index2;
157    CARD8 maxColour = (1 << pATI->rgbBits) - 1;
158
159    pATIHW->dac_read = pATIHW->dac_write = 0x00U;
160    pATIHW->dac_mask = 0xFFU;
161
162    /*
163     * Set colour lookup table.  The first entry has already been zeroed out.
164     */
165    if (pATI->depth > 8)
166        for (Index = 1;  Index < (NumberOf(pATIHW->lut) / 3);  Index++)
167        {
168            Index2 = Index * 3;
169            pATIHW->lut[Index2 + 0] =
170                pATIHW->lut[Index2 + 1] =
171                pATIHW->lut[Index2 + 2] = Index;
172        }
173    else
174    {
175        /*
176         * Initialise hardware colour map so that use of uninitialised
177         * software colour map entries can easily be seen.  For 256-colour
178         * modes, this doesn't remain effective for very long...
179         */
180        pATIHW->lut[3] = pATIHW->lut[4] = pATIHW->lut[5] = 0xFFU;
181        for (Index = 2;  Index < (NumberOf(pATIHW->lut) / 3);  Index++)
182        {
183            Index2 = Index * 3;
184            pATIHW->lut[Index2 + 0] = maxColour;
185            pATIHW->lut[Index2 + 1] = 0x00U;
186            pATIHW->lut[Index2 + 2] = maxColour;
187        }
188    }
189}
190
191/*
192 * ATIDACSave --
193 *
194 * This function is called to save the current RAMDAC state into an ATIHWRec
195 * structure occurrence.
196 */
197void
198ATIDACSave
199(
200    ATIPtr   pATI,
201    ATIHWPtr pATIHW
202)
203{
204    int Index;
205
206#ifdef AVOID_CPIO
207
208    pATIHW->dac_read = in8(M64_DAC_READ);
209    DACDelay;
210    pATIHW->dac_write = in8(M64_DAC_WRITE);
211    DACDelay;
212    pATIHW->dac_mask = in8(M64_DAC_MASK);
213    DACDelay;
214
215    /* Save DAC's colour lookup table */
216    out8(M64_DAC_MASK, 0xFFU);
217    DACDelay;
218    out8(M64_DAC_READ, 0x00U);
219    DACDelay;
220    for (Index = 0;  Index < NumberOf(pATIHW->lut);  Index++)
221    {
222        pATIHW->lut[Index] = in8(M64_DAC_DATA);
223        DACDelay;
224    }
225
226    out8(M64_DAC_MASK, pATIHW->dac_mask);
227    DACDelay;
228    out8(M64_DAC_READ, pATIHW->dac_read);
229    DACDelay;
230
231#else /* AVOID_CPIO */
232
233    ATISetDACIOPorts(pATI, pATIHW->crtc);
234
235    pATIHW->dac_read = inb(pATI->CPIO_DAC_READ);
236    DACDelay;
237    pATIHW->dac_write = inb(pATI->CPIO_DAC_WRITE);
238    DACDelay;
239    pATIHW->dac_mask = inb(pATI->CPIO_DAC_MASK);
240    DACDelay;
241
242    /* Save DAC's colour lookup table */
243    outb(pATI->CPIO_DAC_MASK, 0xFFU);
244    DACDelay;
245    outb(pATI->CPIO_DAC_READ, 0x00U);
246    DACDelay;
247    for (Index = 0;  Index < NumberOf(pATIHW->lut);  Index++)
248    {
249        pATIHW->lut[Index] = inb(pATI->CPIO_DAC_DATA);
250        DACDelay;
251    }
252
253    outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
254    DACDelay;
255    outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
256    DACDelay;
257
258#endif /* AVOID_CPIO */
259
260}
261
262/*
263 * ATIDACSet --
264 *
265 * This function loads RAMDAC data from an ATIHWRec structure occurrence.
266 */
267void
268ATIDACSet
269(
270    ATIPtr   pATI,
271    ATIHWPtr pATIHW
272)
273{
274    int Index;
275
276#ifdef AVOID_CPIO
277
278    /* Load DAC's colour lookup table */
279    out8(M64_DAC_MASK, 0xFFU);
280    DACDelay;
281    out8(M64_DAC_WRITE, 0x00U);
282    DACDelay;
283    for (Index = 0;  Index < NumberOf(pATIHW->lut);  Index++)
284    {
285        out8(M64_DAC_DATA, pATIHW->lut[Index]);
286        DACDelay;
287    }
288
289    out8(M64_DAC_MASK, pATIHW->dac_mask);
290    DACDelay;
291    out8(M64_DAC_READ, pATIHW->dac_read);
292    DACDelay;
293    out8(M64_DAC_WRITE, pATIHW->dac_write);
294    DACDelay;
295
296#else /* AVOID_CPIO */
297
298    ATISetDACIOPorts(pATI, pATIHW->crtc);
299
300    /* Load DAC's colour lookup table */
301    outb(pATI->CPIO_DAC_MASK, 0xFFU);
302    DACDelay;
303    outb(pATI->CPIO_DAC_WRITE, 0x00U);
304    DACDelay;
305    for (Index = 0;  Index < NumberOf(pATIHW->lut);  Index++)
306    {
307        outb(pATI->CPIO_DAC_DATA, pATIHW->lut[Index]);
308        DACDelay;
309    }
310
311    outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
312    DACDelay;
313    outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
314    DACDelay;
315    outb(pATI->CPIO_DAC_WRITE, pATIHW->dac_write);
316    DACDelay;
317
318#endif /* AVOID_CPIO */
319
320}
321
322/*
323 * ATISetLUTEntry --
324 *
325 * This function is called to set one of a DAC's LUT entries.
326 */
327static void
328ATISetLUTEntry
329(
330    ATIPtr pATI,
331    int    Index,
332    CARD8  *LUTEntry
333)
334{
335#ifdef AVOID_CPIO
336
337    out8(M64_DAC_WRITE, Index);
338    DACDelay;
339    out8(M64_DAC_DATA, LUTEntry[0]);
340    DACDelay;
341    out8(M64_DAC_DATA, LUTEntry[1]);
342    DACDelay;
343    out8(M64_DAC_DATA, LUTEntry[2]);
344    DACDelay;
345
346#else /* AVOID_CPIO */
347
348    outb(pATI->CPIO_DAC_WRITE, Index);
349    DACDelay;
350    outb(pATI->CPIO_DAC_DATA, LUTEntry[0]);
351    DACDelay;
352    outb(pATI->CPIO_DAC_DATA, LUTEntry[1]);
353    DACDelay;
354    outb(pATI->CPIO_DAC_DATA, LUTEntry[2]);
355    DACDelay;
356
357#endif /* AVOID_CPIO */
358}
359
360/*
361 * ATILoadPalette --
362 *
363 * This function updates the RAMDAC's LUT and the in-memory copy of it in
364 * NewHW.
365 */
366void
367ATILoadPalette
368(
369    ScrnInfoPtr pScreenInfo,
370    int         nColours,
371    int         *Indices,
372    LOCO        *Colours,
373    VisualPtr   pVisual
374)
375{
376    ATIPtr pATI = ATIPTR(pScreenInfo);
377    CARD8  *LUTEntry;
378    int    i, j, Index;
379
380    if (((pVisual->class | DynamicClass) == DirectColor) &&
381        ((1 << pVisual->nplanes) > (SizeOf(pATI->NewHW.lut) / 3)))
382    {
383        int reds = pVisual->redMask >> pVisual->offsetRed;
384        int greens = pVisual->greenMask >> pVisual->offsetGreen;
385        int blues = pVisual->blueMask >> pVisual->offsetBlue;
386
387        int redShift = 8 - pATI->weight.red;
388        int greenShift = 8 - pATI->weight.green;
389        int blueShift = 8 - pATI->weight.blue;
390
391        int redMult = 3 << redShift;
392        int greenMult = 3 << greenShift;
393        int blueMult = 3 << blueShift;
394
395        int minShift;
396
397        CARD8 fChanged[SizeOf(pATI->NewHW.lut) / 3];
398
399        (void)memset(fChanged, 0, SizeOf(fChanged));
400
401        minShift = redShift;
402        if (minShift > greenShift)
403            minShift = greenShift;
404        if (minShift > blueShift)
405            minShift = blueShift;
406
407        for (i = 0;  i < nColours;  i++)
408        {
409            if((Index = Indices[i]) < 0)
410                continue;
411
412            if (Index <= reds)
413            {
414                j = Index * redMult;
415                pATI->NewHW.lut[j + 0] = Colours[Index].red;
416                fChanged[j / 3] = TRUE;
417            }
418            if (Index <= greens)
419            {
420                j = Index * greenMult;
421                pATI->NewHW.lut[j + 1] = Colours[Index].green;
422                fChanged[j / 3] = TRUE;
423            }
424            if (Index <= blues)
425            {
426                j = Index * blueMult;
427                pATI->NewHW.lut[j + 2] = Colours[Index].blue;
428                fChanged[j / 3] = TRUE;
429            }
430        }
431
432        if (pScreenInfo->vtSema || pATI->currentMode)
433        {
434            /* Rewrite LUT entries that could have been changed */
435            i = 1 << minShift;
436            LUTEntry = pATI->NewHW.lut;
437
438            for (Index = 0;
439                 Index < (SizeOf(pATI->NewHW.lut) / 3);
440                 Index += i, LUTEntry += i * 3)
441                if (fChanged[Index])
442                    ATISetLUTEntry(pATI, Index, LUTEntry);
443        }
444    }
445    else
446    {
447        for (i = 0;  i < nColours;  i++)
448        {
449            Index = Indices[i];
450            if ((Index < 0) || (Index >= (SizeOf(pATI->NewHW.lut) / 3)))
451                continue;
452
453            LUTEntry = &pATI->NewHW.lut[Index * 3];
454            LUTEntry[0] = Colours[Index].red;
455            LUTEntry[1] = Colours[Index].green;
456            LUTEntry[2] = Colours[Index].blue;
457
458            if (pScreenInfo->vtSema || pATI->currentMode)
459                ATISetLUTEntry(pATI, Index, LUTEntry);
460        }
461    }
462}
463