1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier
5*9a747e4fSDavid du Colombier #include "pci.h"
6219b2ee8SDavid du Colombier #include "vga.h"
7219b2ee8SDavid du Colombier
8219b2ee8SDavid du Colombier /*
97dd7cddfSDavid du Colombier * Tvp302[056] Viewpoint Video Interface Palette.
10219b2ee8SDavid du Colombier * Assumes hooked up to an S3 86C928 or S3 Vision964.
11219b2ee8SDavid du Colombier */
12219b2ee8SDavid du Colombier enum {
13219b2ee8SDavid du Colombier Index = 0x06, /* Index register */
14219b2ee8SDavid du Colombier Data = 0x07, /* Data register */
15219b2ee8SDavid du Colombier
16219b2ee8SDavid du Colombier Id = 0x3F, /* ID Register */
17219b2ee8SDavid du Colombier Tvp3020 = 0x20,
18219b2ee8SDavid du Colombier Tvp3025 = 0x25,
197dd7cddfSDavid du Colombier Tvp3026 = 0x26,
20219b2ee8SDavid du Colombier };
21219b2ee8SDavid du Colombier
22219b2ee8SDavid du Colombier /*
23219b2ee8SDavid du Colombier * The following two arrays give read (bit 0) and write (bit 1)
24219b2ee8SDavid du Colombier * permissions on the direct and index registers. Bits 4 and 5
25219b2ee8SDavid du Colombier * are for the Tvp3025. The Tvp3020 has only 8 direct registers.
26219b2ee8SDavid du Colombier */
27219b2ee8SDavid du Colombier static uchar directreg[32] = {
28219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33,
29219b2ee8SDavid du Colombier 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
31219b2ee8SDavid du Colombier 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x33, 0x33,
32219b2ee8SDavid du Colombier };
33219b2ee8SDavid du Colombier
34219b2ee8SDavid du Colombier static uchar indexreg[64] = {
35219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00,
36219b2ee8SDavid du Colombier 0x02, 0x02, 0x33, 0x00, 0x00, 0x00, 0x30, 0x30,
37219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
38219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x00,
39219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
40219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30,
41219b2ee8SDavid du Colombier 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
42219b2ee8SDavid du Colombier 0x33, 0x30, 0x33, 0x11, 0x11, 0x11, 0x22, 0x11,
43219b2ee8SDavid du Colombier };
44219b2ee8SDavid du Colombier
45219b2ee8SDavid du Colombier /*
46219b2ee8SDavid du Colombier * Check the index register access is valid.
47219b2ee8SDavid du Colombier * Return the number of direct registers.
48219b2ee8SDavid du Colombier */
49219b2ee8SDavid du Colombier static uchar
checkindex(uchar index,uchar access)50219b2ee8SDavid du Colombier checkindex(uchar index, uchar access)
51219b2ee8SDavid du Colombier {
52219b2ee8SDavid du Colombier uchar crt55;
53219b2ee8SDavid du Colombier static uchar id;
54219b2ee8SDavid du Colombier
55219b2ee8SDavid du Colombier if(id == 0){
56219b2ee8SDavid du Colombier crt55 = vgaxi(Crtx, 0x55) & 0xFC;
57219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55|((Index>>2) & 0x03));
58219b2ee8SDavid du Colombier vgao(dacxreg[Index & 0x03], Id);
59219b2ee8SDavid du Colombier
60219b2ee8SDavid du Colombier id = vgai(dacxreg[Data & 0x03]);
61219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55);
62219b2ee8SDavid du Colombier }
63219b2ee8SDavid du Colombier
64219b2ee8SDavid du Colombier if(index == 0xFF)
65219b2ee8SDavid du Colombier return id;
66219b2ee8SDavid du Colombier
67219b2ee8SDavid du Colombier access &= 0x03;
68219b2ee8SDavid du Colombier switch(id){
69219b2ee8SDavid du Colombier
70219b2ee8SDavid du Colombier case Tvp3020:
71219b2ee8SDavid du Colombier break;
72219b2ee8SDavid du Colombier
73219b2ee8SDavid du Colombier case Tvp3025:
747dd7cddfSDavid du Colombier case Tvp3026:
75219b2ee8SDavid du Colombier access = access<<4;
76219b2ee8SDavid du Colombier break;
77219b2ee8SDavid du Colombier
78219b2ee8SDavid du Colombier default:
797dd7cddfSDavid du Colombier Bprint(&stdout, "%s: unknown chip id - 0x%2.2X\n", tvp3020.name, id);
80219b2ee8SDavid du Colombier break;
81219b2ee8SDavid du Colombier }
82219b2ee8SDavid du Colombier
83219b2ee8SDavid du Colombier if(index > sizeof(indexreg) || (indexreg[index] & access) == 0)
847dd7cddfSDavid du Colombier error("%s: bad register index - 0x%2.2X\n", tvp3020.name, index);
85219b2ee8SDavid du Colombier
86219b2ee8SDavid du Colombier return id;
87219b2ee8SDavid du Colombier }
88219b2ee8SDavid du Colombier
89219b2ee8SDavid du Colombier static uchar
tvp3020io(uchar reg,uchar data)90219b2ee8SDavid du Colombier tvp3020io(uchar reg, uchar data)
91219b2ee8SDavid du Colombier {
92219b2ee8SDavid du Colombier uchar crt55;
93219b2ee8SDavid du Colombier
94219b2ee8SDavid du Colombier crt55 = vgaxi(Crtx, 0x55) & 0xFC;
95219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
96219b2ee8SDavid du Colombier vgao(dacxreg[reg & 0x03], data);
97219b2ee8SDavid du Colombier
98219b2ee8SDavid du Colombier return crt55;
99219b2ee8SDavid du Colombier }
100219b2ee8SDavid du Colombier
101219b2ee8SDavid du Colombier uchar
tvp3020i(uchar reg)102219b2ee8SDavid du Colombier tvp3020i(uchar reg)
103219b2ee8SDavid du Colombier {
104219b2ee8SDavid du Colombier uchar crt55, r;
105219b2ee8SDavid du Colombier
106219b2ee8SDavid du Colombier crt55 = vgaxi(Crtx, 0x55) & 0xFC;
107219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
108219b2ee8SDavid du Colombier r = vgai(dacxreg[reg & 0x03]);
109219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55);
110219b2ee8SDavid du Colombier
111219b2ee8SDavid du Colombier return r;
112219b2ee8SDavid du Colombier }
113219b2ee8SDavid du Colombier
114219b2ee8SDavid du Colombier uchar
tvp3020xi(uchar index)115219b2ee8SDavid du Colombier tvp3020xi(uchar index)
116219b2ee8SDavid du Colombier {
117219b2ee8SDavid du Colombier uchar crt55, r;
118219b2ee8SDavid du Colombier
119219b2ee8SDavid du Colombier checkindex(index, 0x01);
120219b2ee8SDavid du Colombier
121219b2ee8SDavid du Colombier crt55 = tvp3020io(Index, index);
122219b2ee8SDavid du Colombier r = vgai(dacxreg[Data & 0x03]);
123219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55);
124219b2ee8SDavid du Colombier
125219b2ee8SDavid du Colombier return r;
126219b2ee8SDavid du Colombier }
127219b2ee8SDavid du Colombier
128219b2ee8SDavid du Colombier void
tvp3020o(uchar reg,uchar data)129219b2ee8SDavid du Colombier tvp3020o(uchar reg, uchar data)
130219b2ee8SDavid du Colombier {
131219b2ee8SDavid du Colombier uchar crt55;
132219b2ee8SDavid du Colombier
133219b2ee8SDavid du Colombier crt55 = tvp3020io(reg, data);
134219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55);
135219b2ee8SDavid du Colombier }
136219b2ee8SDavid du Colombier
137219b2ee8SDavid du Colombier void
tvp3020xo(uchar index,uchar data)138219b2ee8SDavid du Colombier tvp3020xo(uchar index, uchar data)
139219b2ee8SDavid du Colombier {
140219b2ee8SDavid du Colombier uchar crt55;
141219b2ee8SDavid du Colombier
142219b2ee8SDavid du Colombier checkindex(index, 0x02);
143219b2ee8SDavid du Colombier
144219b2ee8SDavid du Colombier crt55 = tvp3020io(Index, index);
145219b2ee8SDavid du Colombier vgao(dacxreg[Data & 0x03], data);
146219b2ee8SDavid du Colombier vgaxo(Crtx, 0x55, crt55);
147219b2ee8SDavid du Colombier }
148219b2ee8SDavid du Colombier
149219b2ee8SDavid du Colombier static void
options(Vga *,Ctlr * ctlr)1507dd7cddfSDavid du Colombier options(Vga*, Ctlr* ctlr)
151219b2ee8SDavid du Colombier {
152219b2ee8SDavid du Colombier ctlr->flag |= Hclk2|Hextsid|Hpvram|Henhanced|Foptions;
153219b2ee8SDavid du Colombier }
154219b2ee8SDavid du Colombier
155219b2ee8SDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)156219b2ee8SDavid du Colombier init(Vga* vga, Ctlr* ctlr)
157219b2ee8SDavid du Colombier {
158219b2ee8SDavid du Colombier ulong grade;
159219b2ee8SDavid du Colombier char *p;
160219b2ee8SDavid du Colombier
161219b2ee8SDavid du Colombier /*
162219b2ee8SDavid du Colombier * Work out the part speed-grade from name. Name can have,
163219b2ee8SDavid du Colombier * e.g. '-135' on the end for 135MHz part.
164219b2ee8SDavid du Colombier */
165219b2ee8SDavid du Colombier grade = 110000000;
166219b2ee8SDavid du Colombier if(p = strrchr(ctlr->name, '-'))
167219b2ee8SDavid du Colombier grade = strtoul(p+1, 0, 0) * 1000000;
168219b2ee8SDavid du Colombier
169219b2ee8SDavid du Colombier /*
170219b2ee8SDavid du Colombier * If we don't already have a desired pclk,
171219b2ee8SDavid du Colombier * take it from the mode.
172219b2ee8SDavid du Colombier * Check it's within range.
173219b2ee8SDavid du Colombier */
1747dd7cddfSDavid du Colombier if(vga->f[0] == 0)
1757dd7cddfSDavid du Colombier vga->f[0] = vga->mode->frequency;
1767dd7cddfSDavid du Colombier if(vga->f[0] > grade)
1777dd7cddfSDavid du Colombier error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
178219b2ee8SDavid du Colombier
179219b2ee8SDavid du Colombier /*
180219b2ee8SDavid du Colombier * Determine whether to use clock-doubler or not.
181219b2ee8SDavid du Colombier */
1827dd7cddfSDavid du Colombier if(vga->f[0] > 85000000){
1837dd7cddfSDavid du Colombier vga->f[0] /= 2;
184219b2ee8SDavid du Colombier resyncinit(vga, ctlr, Uclk2, 0);
185219b2ee8SDavid du Colombier }
186219b2ee8SDavid du Colombier
187219b2ee8SDavid du Colombier ctlr->flag |= Finit;
188219b2ee8SDavid du Colombier }
189219b2ee8SDavid du Colombier
190219b2ee8SDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)191219b2ee8SDavid du Colombier load(Vga* vga, Ctlr* ctlr)
192219b2ee8SDavid du Colombier {
193219b2ee8SDavid du Colombier uchar x;
194219b2ee8SDavid du Colombier
195219b2ee8SDavid du Colombier /*
196219b2ee8SDavid du Colombier * Input Clock Selection:
197219b2ee8SDavid du Colombier * VGA CLK0
198219b2ee8SDavid du Colombier * enhanced CLK1
199219b2ee8SDavid du Colombier * doubled if necessary.
200219b2ee8SDavid du Colombier */
201219b2ee8SDavid du Colombier x = 0x00;
202219b2ee8SDavid du Colombier if(ctlr->flag & Uenhanced)
203219b2ee8SDavid du Colombier x |= 0x01;
204219b2ee8SDavid du Colombier if(ctlr->flag & Uclk2)
205219b2ee8SDavid du Colombier x |= 0x10;
206219b2ee8SDavid du Colombier tvp3020xo(0x1A, x);
207219b2ee8SDavid du Colombier
208219b2ee8SDavid du Colombier /*
209219b2ee8SDavid du Colombier * Output Clock Selection:
210219b2ee8SDavid du Colombier * VGA default VGA
211219b2ee8SDavid du Colombier * enhanced RCLK=SCLK=/8, VCLK/4
212219b2ee8SDavid du Colombier */
213219b2ee8SDavid du Colombier x = 0x3E;
214219b2ee8SDavid du Colombier if(ctlr->flag & Uenhanced)
215219b2ee8SDavid du Colombier x = 0x53;
216219b2ee8SDavid du Colombier tvp3020xo(0x1B, x);
217219b2ee8SDavid du Colombier
218219b2ee8SDavid du Colombier /*
219219b2ee8SDavid du Colombier * Auxiliary Control:
220219b2ee8SDavid du Colombier * default settings - self-clocked, palette graphics, no zoom
221219b2ee8SDavid du Colombier * Colour Key Control:
222219b2ee8SDavid du Colombier * default settings - pointing to palette graphics
223219b2ee8SDavid du Colombier * Mux Control Register 1:
224219b2ee8SDavid du Colombier * pseudo colour
225219b2ee8SDavid du Colombier */
226219b2ee8SDavid du Colombier tvp3020xo(0x29, 0x09);
227219b2ee8SDavid du Colombier tvp3020xo(0x38, 0x10);
228219b2ee8SDavid du Colombier tvp3020xo(0x18, 0x80);
229219b2ee8SDavid du Colombier
230219b2ee8SDavid du Colombier /*
231219b2ee8SDavid du Colombier * Mux Control Register 2:
232219b2ee8SDavid du Colombier * VGA default VGA
233219b2ee8SDavid du Colombier * enhanced 8-bpp, 8:1 mux, 64-bit pixel-bus width
234219b2ee8SDavid du Colombier */
235219b2ee8SDavid du Colombier x = 0x98;
236219b2ee8SDavid du Colombier if(ctlr->flag & Uenhanced){
237219b2ee8SDavid du Colombier if(vga->mode->z == 8)
238219b2ee8SDavid du Colombier x = 0x1C;
239219b2ee8SDavid du Colombier else if(vga->mode->z == 1)
240219b2ee8SDavid du Colombier x = 0x04;
241219b2ee8SDavid du Colombier }
242219b2ee8SDavid du Colombier tvp3020xo(0x19, x);
243219b2ee8SDavid du Colombier
244219b2ee8SDavid du Colombier /*
245219b2ee8SDavid du Colombier * General Control:
246219b2ee8SDavid du Colombier * output sync polarity
247219b2ee8SDavid du Colombier * It's important to set this properly and to turn off the
248219b2ee8SDavid du Colombier * VGA controller H and V syncs. Can't be set in VGA mode.
249219b2ee8SDavid du Colombier */
250219b2ee8SDavid du Colombier x = 0x00;
251219b2ee8SDavid du Colombier if((vga->misc & 0x40) == 0)
252219b2ee8SDavid du Colombier x |= 0x01;
253219b2ee8SDavid du Colombier if((vga->misc & 0x80) == 0)
254219b2ee8SDavid du Colombier x |= 0x02;
255219b2ee8SDavid du Colombier tvp3020xo(0x1D, x);
256219b2ee8SDavid du Colombier vga->misc |= 0xC0;
257219b2ee8SDavid du Colombier vgao(MiscW, vga->misc);
258219b2ee8SDavid du Colombier
259219b2ee8SDavid du Colombier /*
260219b2ee8SDavid du Colombier * Select the DAC via the General Purpose I/O
261219b2ee8SDavid du Colombier * Register and Pins.
262219b2ee8SDavid du Colombier * Guesswork by looking at register dumps.
263219b2ee8SDavid du Colombier */
264219b2ee8SDavid du Colombier tvp3020xo(0x2A, 0x1F);
265219b2ee8SDavid du Colombier if(ctlr->flag & Uenhanced)
266219b2ee8SDavid du Colombier x = 0x1D;
267219b2ee8SDavid du Colombier else
268219b2ee8SDavid du Colombier x = 0x1C;
269219b2ee8SDavid du Colombier tvp3020xo(0x2B, x);
270219b2ee8SDavid du Colombier
271219b2ee8SDavid du Colombier ctlr->flag |= Fload;
272219b2ee8SDavid du Colombier }
273219b2ee8SDavid du Colombier
274219b2ee8SDavid du Colombier static void
dump(Vga *,Ctlr * ctlr)2757dd7cddfSDavid du Colombier dump(Vga*, Ctlr* ctlr)
276219b2ee8SDavid du Colombier {
277219b2ee8SDavid du Colombier uchar access;
278219b2ee8SDavid du Colombier int i;
279219b2ee8SDavid du Colombier
280219b2ee8SDavid du Colombier access = 0x01;
2817dd7cddfSDavid du Colombier if(checkindex(0x00, 0x01) != Tvp3020)
282219b2ee8SDavid du Colombier access <<= 4;
283219b2ee8SDavid du Colombier
284219b2ee8SDavid du Colombier printitem(ctlr->name, "direct");
285219b2ee8SDavid du Colombier for(i = 0; i < 8; i++){
286219b2ee8SDavid du Colombier if(directreg[i] & access)
287219b2ee8SDavid du Colombier printreg(tvp3020i(i));
288219b2ee8SDavid du Colombier else
289219b2ee8SDavid du Colombier printreg(0xFF);
290219b2ee8SDavid du Colombier }
291219b2ee8SDavid du Colombier
292219b2ee8SDavid du Colombier printitem(ctlr->name, "index");
293219b2ee8SDavid du Colombier for(i = 0; i < sizeof(indexreg); i++){
294219b2ee8SDavid du Colombier if(indexreg[i] & access)
295219b2ee8SDavid du Colombier printreg(tvp3020xi(i));
296219b2ee8SDavid du Colombier else
297219b2ee8SDavid du Colombier printreg(0xFF);
298219b2ee8SDavid du Colombier }
299219b2ee8SDavid du Colombier }
300219b2ee8SDavid du Colombier
301219b2ee8SDavid du Colombier Ctlr tvp3020 = {
302219b2ee8SDavid du Colombier "tvp3020", /* name */
303219b2ee8SDavid du Colombier 0, /* snarf */
304219b2ee8SDavid du Colombier options, /* options */
305219b2ee8SDavid du Colombier init, /* init */
306219b2ee8SDavid du Colombier load, /* load */
307219b2ee8SDavid du Colombier dump, /* dump */
308219b2ee8SDavid du Colombier };
309