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