tvga_dac.c revision 2378475a
1/*
2 * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
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
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane 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 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE 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 * Author:  Alan Hourihane, alanh@fairlite.demon.co.uk
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "xf86PciInfo.h"
32#include "xf86Pci.h"
33
34#include "vgaHW.h"
35
36#include "trident.h"
37#include "trident_regs.h"
38
39Bool
40TVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
41{
42    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
43    TRIDENTRegPtr pReg = &pTrident->ModeReg;
44    int vgaIOBase;
45    int offset = 0;
46    int clock = mode->Clock;
47    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
48
49    OUTB(0x3C4, 0x0B); INB(0x3C5); /* Ensure we are in New Mode */
50
51    pReg->tridentRegsDAC[0x00] = 0x00;
52    OUTB(0x3C4, ConfPort2);
53    pReg->tridentRegs3C4[ConfPort2] = INB(0x3C5);
54    OUTB(0x3CE, MiscExtFunc);
55    pReg->tridentRegs3CE[MiscExtFunc] = INB(0x3CF) & 0xF0;
56    OUTB(vgaIOBase + 4, FIFOControl);
57    pReg->tridentRegs3x4[FIFOControl] = INB(vgaIOBase + 5) | 0x24;
58
59       	/* YUK ! here we have to mess with old mode operation */
60       	OUTB(0x3C4, 0x0B); OUTB(0x3C5, 0x00); /* Goto Old Mode */
61       	OUTB(0x3C4, OldMode2 + NewMode2);
62       	pReg->tridentRegs3C4[OldMode2] = 0x10;
63       	OUTB(0x3C4, 0x0B); INB(0x3C5); /* Back to New Mode */
64   	pReg->tridentRegs3x4[Underline] = 0x40;
65	if (pTrident->Chipset < TGUI9440AGi)
66	    pReg->tridentRegs3x4[CRTCMode] = 0xA3;
67
68    if (pScrn->videoRam > 512)
69    	pReg->tridentRegs3C4[ConfPort2] |= 0x20;
70    else
71    	pReg->tridentRegs3C4[ConfPort2] &= 0xDF;
72
73    switch (pScrn->bitsPerPixel) {
74	case 8:
75	    if (pScrn->videoRam < 1024)
76    	    	offset = pScrn->displayWidth >> 3;
77	    else
78    	    	offset = pScrn->displayWidth >> 4;
79	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
80	    break;
81	case 16:
82	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
83    	    offset = pScrn->displayWidth >> 3;
84	    /* Reload with any chipset specific stuff here */
85	    if (pTrident->Chipset == TVGA8900D) {
86		if (pScrn->depth == 15)
87	    	    pReg->tridentRegsDAC[0x00] = 0xA0;
88		else
89	    	    pReg->tridentRegsDAC[0x00] = 0xE0;
90    	    	pReg->tridentRegs3CE[MiscExtFunc] |= 0x08; /* Clock Div by 2*/
91	    	clock *= 2;	/* Double the clock */
92	    }
93	    break;
94	case 24:
95	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
96    	    offset = (pScrn->displayWidth * 3) >> 3;
97	    pReg->tridentRegsDAC[0x00] = 0xD0;
98	    break;
99	case 32:
100	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x02;
101    	    pReg->tridentRegs3CE[MiscExtFunc] |= 0x08; /* Clock Division by 2*/
102	    clock *= 2;	/* Double the clock */
103    	    offset = pScrn->displayWidth >> 1;
104	    pReg->tridentRegsDAC[0x00] = 0x42;
105	    break;
106    }
107    pReg->tridentRegs3x4[Offset] = offset & 0xFF;
108
109    pReg->tridentRegsClock[0x00] = mode->ClockIndex;
110
111    pReg->tridentRegs3C4[NewMode1] = 0x80;
112
113    if (LINEAR())
114    	pReg->tridentRegs3x4[LinearAddReg] = ((pTrident->FbAddress >> 24) << 6)|
115					 ((pTrident->FbAddress >> 20) & 0x0F)|
116					 0x20;
117    else {
118	pReg->tridentRegs3CE[MiscExtFunc] |= 0x04;
119    	pReg->tridentRegs3x4[LinearAddReg] = 0;
120    }
121
122    pReg->tridentRegs3x4[CRTCModuleTest] =
123				(mode->Flags & V_INTERLACE ? 0x84 : 0x80);
124    OUTB(vgaIOBase+ 4, AddColReg);
125    pReg->tridentRegs3x4[AddColReg] = (INB(vgaIOBase + 5) & 0xCF) |
126				      ((offset & 0x100) >> 4);
127
128    return(TRUE);
129}
130
131void
132TVGARestore(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
133{
134    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
135    int vgaIOBase;
136    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
137
138    /* Goto Old Mode */
139    OUTB(0x3C4, 0x0B);
140    OUTB(0x3C5, 0x00);
141    OUTB(0x3C4, OldMode2 + NewMode2);
142    OUTB(0x3C5, tridentReg->tridentRegs3C4[OldMode2]);
143
144    /* Goto New Mode */
145    OUTB(0x3C4, 0x0B);
146    (void) INB(0x3C5);
147
148    /* Unprotect registers */
149    OUTW(0x3C4, (0x80 << 8) | NewMode1);
150
151    (void) INB(0x3C8);
152    (void) INB(0x3C6);
153    (void) INB(0x3C6);
154    (void) INB(0x3C6);
155    (void) INB(0x3C6);
156    OUTB(0x3C6, tridentReg->tridentRegsDAC[0x00]);
157    (void) INB(0x3C8);
158
159    OUTW_3x4(CRTCModuleTest);
160    OUTW_3x4(LinearAddReg);
161    OUTW_3x4(FIFOControl);
162    OUTW_3C4(ConfPort2);
163    OUTW_3x4(Underline);
164    if (pTrident->Chipset < TGUI9440AGi)
165           OUTW_3x4(CRTCMode);
166    OUTW_3x4(AddColReg);
167    OUTW_3CE(MiscExtFunc);
168    OUTW_3x4(Offset);
169
170    TRIDENTClockSelect(pScrn, tridentReg->tridentRegsClock[0x00]);
171
172    OUTW(0x3C4, ((tridentReg->tridentRegs3C4[NewMode1]) << 8)| NewMode1);
173}
174
175void
176TVGASave(ScrnInfoPtr pScrn, TRIDENTRegPtr tridentReg)
177{
178    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
179    int vgaIOBase;
180    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
181
182    (void) INB(0x3C8);
183    (void) INB(0x3C6);
184    (void) INB(0x3C6);
185    (void) INB(0x3C6);
186    (void) INB(0x3C6);
187    tridentReg->tridentRegsDAC[0x00] = INB(0x3C6);
188    (void) INB(0x3C8);
189
190    /* Goto Old Mode */
191    OUTB(0x3C4, 0x0B);
192    OUTB(0x3C5, 0x00);
193    OUTB(0x3C4, OldMode2 + NewMode2);
194    tridentReg->tridentRegs3C4[OldMode2] = INB(0x3C5);
195
196    /* Goto New Mode */
197    OUTB(0x3C4, 0x0B);
198    (void) INB(0x3C5);
199
200    INB_3C4(NewMode1);
201
202    /* Unprotect registers */
203    OUTW(0x3C4, ((0x80 ^ 0x02) << 8) | NewMode1);
204    OUTW(vgaIOBase + 4, (0x92 << 8) | NewMode1);
205
206    INB_3x4(Underline);
207    if (pTrident->Chipset < TGUI9440AGi)
208            INB_3x4(CRTCMode);
209    INB_3x4(LinearAddReg);
210    INB_3x4(FIFOControl);
211    INB_3x4(CRTCModuleTest);
212    INB_3x4(AddColReg);
213    INB_3CE(MiscExtFunc);
214    INB_3C4(ConfPort2);
215
216    TRIDENTClockSelect(pScrn, CLK_REG_SAVE);
217
218    /* Protect registers */
219    OUTW_3C4(NewMode1);
220}
221