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 /*
9219b2ee8SDavid du Colombier * Tseng Labs Inc. ET4000 Video Controller.
10219b2ee8SDavid du Colombier */
11219b2ee8SDavid du Colombier enum {
12219b2ee8SDavid du Colombier Crtcbx = 0x217A, /* Secondary CRT controller */
13219b2ee8SDavid du Colombier
14219b2ee8SDavid du Colombier Sprite = 0xE0,
15219b2ee8SDavid du Colombier NSprite = 0x10,
16219b2ee8SDavid du Colombier
17219b2ee8SDavid du Colombier Ima = 0xF0,
18219b2ee8SDavid du Colombier NIma = 0x08,
19219b2ee8SDavid du Colombier };
20219b2ee8SDavid du Colombier
21219b2ee8SDavid du Colombier static void
setkey(void)22219b2ee8SDavid du Colombier setkey(void)
23219b2ee8SDavid du Colombier {
24219b2ee8SDavid du Colombier outportb(0x3BF, 0x03);
25219b2ee8SDavid du Colombier outportb(0x3D8, 0xA0);
26219b2ee8SDavid du Colombier outportb(0x3CD, 0x00);
27219b2ee8SDavid du Colombier }
28219b2ee8SDavid du Colombier
29219b2ee8SDavid du Colombier static void
snarf(Vga * vga,Ctlr * ctlr)30219b2ee8SDavid du Colombier snarf(Vga* vga, Ctlr* ctlr)
31219b2ee8SDavid du Colombier {
32219b2ee8SDavid du Colombier int i;
33219b2ee8SDavid du Colombier
34219b2ee8SDavid du Colombier setkey();
35219b2ee8SDavid du Colombier
36219b2ee8SDavid du Colombier vga->sequencer[0x06] = vgaxi(Seqx, 0x06);
37219b2ee8SDavid du Colombier vga->sequencer[0x07] = vgaxi(Seqx, 0x07);
38219b2ee8SDavid du Colombier
39219b2ee8SDavid du Colombier for(i = 0x30; i < 0x38; i++)
40219b2ee8SDavid du Colombier vga->crt[i] = vgaxi(Crtx, i);
41219b2ee8SDavid du Colombier vga->crt[0x3F] = vgaxi(Crtx, 0x3F);
42219b2ee8SDavid du Colombier
43219b2ee8SDavid du Colombier vga->attribute[0x16] = vgaxi(Attrx, 0x16);
44219b2ee8SDavid du Colombier vga->attribute[0x17] = vgaxi(Attrx, 0x17);
45219b2ee8SDavid du Colombier
46219b2ee8SDavid du Colombier /*
47219b2ee8SDavid du Colombier * Memory size.
48219b2ee8SDavid du Colombier */
49219b2ee8SDavid du Colombier switch(vga->crt[0x37] & 0x03){
50219b2ee8SDavid du Colombier
51219b2ee8SDavid du Colombier case 1:
527dd7cddfSDavid du Colombier vga->vmz = 256*1024;
53219b2ee8SDavid du Colombier break;
54219b2ee8SDavid du Colombier
55219b2ee8SDavid du Colombier case 2:
567dd7cddfSDavid du Colombier vga->vmz = 512*1024;
57219b2ee8SDavid du Colombier break;
58219b2ee8SDavid du Colombier
59219b2ee8SDavid du Colombier case 3:
607dd7cddfSDavid du Colombier vga->vmz = 1024*1024;
61219b2ee8SDavid du Colombier break;
62219b2ee8SDavid du Colombier }
63219b2ee8SDavid du Colombier if(strncmp(ctlr->name, "et4000-w32", 10) == 0){
64219b2ee8SDavid du Colombier if(vga->crt[0x32] & 0x80)
657dd7cddfSDavid du Colombier vga->vmz *= 2;
66219b2ee8SDavid du Colombier }
67219b2ee8SDavid du Colombier else if(vga->crt[0x37] & 0x80)
687dd7cddfSDavid du Colombier vga->vmz *= 2;
69219b2ee8SDavid du Colombier
70219b2ee8SDavid du Colombier ctlr->flag |= Fsnarf;
71219b2ee8SDavid du Colombier }
72219b2ee8SDavid du Colombier
73219b2ee8SDavid du Colombier static void
options(Vga * vga,Ctlr * ctlr)74219b2ee8SDavid du Colombier options(Vga* vga, Ctlr* ctlr)
75219b2ee8SDavid du Colombier {
76219b2ee8SDavid du Colombier /*
77219b2ee8SDavid du Colombier * The ET4000 does not need to have the vertical
78219b2ee8SDavid du Colombier * timing values divided by 2 for interlace mode.
79219b2ee8SDavid du Colombier */
80219b2ee8SDavid du Colombier if(vga->mode->interlace == 'v')
81219b2ee8SDavid du Colombier vga->mode->interlace = 'V';
82219b2ee8SDavid du Colombier
83219b2ee8SDavid du Colombier if(strncmp(ctlr->name, "et4000-w32", 10) == 0)
84219b2ee8SDavid du Colombier ctlr->flag |= Hpclk2x8;
85219b2ee8SDavid du Colombier
867dd7cddfSDavid du Colombier ctlr->flag |= Hclkdiv|Foptions;
87219b2ee8SDavid du Colombier }
88219b2ee8SDavid du Colombier
89219b2ee8SDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)90219b2ee8SDavid du Colombier init(Vga* vga, Ctlr* ctlr)
91219b2ee8SDavid du Colombier {
92219b2ee8SDavid du Colombier Mode *mode;
93219b2ee8SDavid du Colombier ulong x;
94219b2ee8SDavid du Colombier
957dd7cddfSDavid du Colombier if(vga->mode->z > 8)
967dd7cddfSDavid du Colombier error("depth %d not supported\n", vga->mode->z);
97219b2ee8SDavid du Colombier
98219b2ee8SDavid du Colombier if(ctlr->flag & Upclk2x8){
99219b2ee8SDavid du Colombier mode = vga->mode;
100219b2ee8SDavid du Colombier vga->crt[0x00] = ((mode->ht/2)>>3)-5;
101219b2ee8SDavid du Colombier vga->crt[0x01] = ((mode->x/2)>>3)-1;
102219b2ee8SDavid du Colombier vga->crt[0x02] = ((mode->shb/2)>>3)-1;
103219b2ee8SDavid du Colombier
104219b2ee8SDavid du Colombier x = (mode->ehb/2)>>3;
105219b2ee8SDavid du Colombier vga->crt[0x03] = 0x80|(x & 0x1F);
1067dd7cddfSDavid du Colombier vga->crt[0x04] = (mode->shs/2)>>3;
1077dd7cddfSDavid du Colombier vga->crt[0x05] = ((mode->ehs/2)>>3) & 0x1F;
108219b2ee8SDavid du Colombier if(x & 0x20)
109219b2ee8SDavid du Colombier vga->crt[0x05] |= 0x80;
110219b2ee8SDavid du Colombier }
111219b2ee8SDavid du Colombier /*
112219b2ee8SDavid du Colombier * Itth a mythtawee.
113219b2ee8SDavid du Colombier */
114219b2ee8SDavid du Colombier if(vga->crt[0x14] & 0x20)
115219b2ee8SDavid du Colombier vga->crt[0x17] |= 0x08;
116219b2ee8SDavid du Colombier vga->crt[0x17] &= ~0x20;
117219b2ee8SDavid du Colombier
118219b2ee8SDavid du Colombier vga->crt[0x30] = 0x00;
119219b2ee8SDavid du Colombier vga->crt[0x33] = 0x00;
120219b2ee8SDavid du Colombier
121219b2ee8SDavid du Colombier /*
122219b2ee8SDavid du Colombier * Overflow High.
123219b2ee8SDavid du Colombier */
124219b2ee8SDavid du Colombier vga->crt[0x35] = 0x00;
125219b2ee8SDavid du Colombier if(vga->crt[0x15] & 0x400)
126219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x01;
127219b2ee8SDavid du Colombier if(vga->crt[0x06] & 0x400)
128219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x02;
129219b2ee8SDavid du Colombier if(vga->crt[0x12] & 0x400)
130219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x04;
131219b2ee8SDavid du Colombier if(vga->crt[0x10] & 0x400)
132219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x08;
133219b2ee8SDavid du Colombier if(vga->crt[0x18] & 0x400)
134219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x10;
135219b2ee8SDavid du Colombier if(vga->mode->interlace == 'V')
136219b2ee8SDavid du Colombier vga->crt[0x35] |= 0x80;
137219b2ee8SDavid du Colombier
138219b2ee8SDavid du Colombier /*
139219b2ee8SDavid du Colombier * Horizontal Overflow.
140219b2ee8SDavid du Colombier */
141219b2ee8SDavid du Colombier vga->crt[0x3F] = 0x00;
142219b2ee8SDavid du Colombier if(vga->crt[0x00] & 0x100)
143219b2ee8SDavid du Colombier vga->crt[0x3F] |= 0x01;
144219b2ee8SDavid du Colombier if(vga->crt[0x02] & 0x100)
145219b2ee8SDavid du Colombier vga->crt[0x3F] |= 0x04;
146219b2ee8SDavid du Colombier if(vga->crt[0x04] & 0x100)
147219b2ee8SDavid du Colombier vga->crt[0x3F] |= 0x10;
148219b2ee8SDavid du Colombier if(vga->crt[0x13] & 0x100)
149219b2ee8SDavid du Colombier vga->crt[0x3F] |= 0x80;
150219b2ee8SDavid du Colombier
151219b2ee8SDavid du Colombier /*
152219b2ee8SDavid du Colombier * Turn off MMU buffers, linear map
153219b2ee8SDavid du Colombier * and memory-mapped registers.
154219b2ee8SDavid du Colombier */
155219b2ee8SDavid du Colombier vga->crt[0x36] &= ~0x38;
156219b2ee8SDavid du Colombier
157219b2ee8SDavid du Colombier if(strncmp(ctlr->name, "et4000-w32", 10) == 0)
158219b2ee8SDavid du Colombier vga->crt[0x37] |= 0x80;
159219b2ee8SDavid du Colombier
160219b2ee8SDavid du Colombier vga->sequencer[0x06] = 0x00;
161219b2ee8SDavid du Colombier
162219b2ee8SDavid du Colombier /*
163219b2ee8SDavid du Colombier * Clock select.
164219b2ee8SDavid du Colombier */
1657dd7cddfSDavid du Colombier if(vga->f[0] > 86000000)
1667dd7cddfSDavid du Colombier error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
167219b2ee8SDavid du Colombier vga->misc &= ~0x0C;
1687dd7cddfSDavid du Colombier vga->misc |= (vga->i[0] & 0x03)<<2;
1697dd7cddfSDavid du Colombier if(vga->i[0] & 0x04)
170219b2ee8SDavid du Colombier vga->crt[0x34] |= 0x02;
171219b2ee8SDavid du Colombier else
172219b2ee8SDavid du Colombier vga->crt[0x34] &= ~0x02;
173219b2ee8SDavid du Colombier vga->crt[0x31] &= ~0xC0;
1747dd7cddfSDavid du Colombier vga->crt[0x31] |= (vga->i[0] & 0x18)<<3;
175219b2ee8SDavid du Colombier
176219b2ee8SDavid du Colombier vga->sequencer[0x07] &= ~0x41;
1777dd7cddfSDavid du Colombier if(vga->d[0] == 4)
178219b2ee8SDavid du Colombier vga->sequencer[0x07] |= 0x01;
1797dd7cddfSDavid du Colombier else if(vga->d[0] == 2)
180219b2ee8SDavid du Colombier vga->sequencer[0x07] |= 0x40;
181219b2ee8SDavid du Colombier
182219b2ee8SDavid du Colombier vga->attribute[0x10] &= ~0x40;
18359cc4ca5SDavid du Colombier vga->attribute[0x11] = Pblack;
184219b2ee8SDavid du Colombier vga->attribute[0x16] = 0x80;
185219b2ee8SDavid du Colombier
186219b2ee8SDavid du Colombier if(ctlr->flag & Upclk2x8)
187219b2ee8SDavid du Colombier vga->attribute[0x16] |= 0x20;
188219b2ee8SDavid du Colombier
189219b2ee8SDavid du Colombier ctlr->flag |= Finit;
190219b2ee8SDavid du Colombier }
191219b2ee8SDavid du Colombier
192219b2ee8SDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)193219b2ee8SDavid du Colombier load(Vga* vga, Ctlr* ctlr)
194219b2ee8SDavid du Colombier {
195219b2ee8SDavid du Colombier vgaxo(Crtx, 0x30, vga->crt[0x30]);
196219b2ee8SDavid du Colombier vgaxo(Crtx, 0x31, vga->crt[0x31]);
197219b2ee8SDavid du Colombier vgaxo(Crtx, 0x33, vga->crt[0x33]);
198219b2ee8SDavid du Colombier vgaxo(Crtx, 0x34, vga->crt[0x34]);
199219b2ee8SDavid du Colombier vgaxo(Crtx, 0x35, vga->crt[0x35]);
200219b2ee8SDavid du Colombier vgaxo(Crtx, 0x36, vga->crt[0x36]);
201219b2ee8SDavid du Colombier vgaxo(Crtx, 0x37, vga->crt[0x37]);
202219b2ee8SDavid du Colombier vgaxo(Crtx, 0x3F, vga->crt[0x3F]);
203219b2ee8SDavid du Colombier
204219b2ee8SDavid du Colombier vgaxo(Seqx, 0x06, vga->sequencer[0x06]);
205219b2ee8SDavid du Colombier vgaxo(Seqx, 0x07, vga->sequencer[0x07]);
206219b2ee8SDavid du Colombier
207219b2ee8SDavid du Colombier vgaxo(Attrx, 0x16, vga->attribute[0x16]);
208219b2ee8SDavid du Colombier
209219b2ee8SDavid du Colombier ctlr->flag |= Fload;
210219b2ee8SDavid du Colombier }
211219b2ee8SDavid du Colombier
212219b2ee8SDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)213219b2ee8SDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
214219b2ee8SDavid du Colombier {
215219b2ee8SDavid du Colombier int i;
216219b2ee8SDavid du Colombier char *name;
217219b2ee8SDavid du Colombier ushort shb, vrs, x;
218219b2ee8SDavid du Colombier
219219b2ee8SDavid du Colombier name = ctlr->name;
220219b2ee8SDavid du Colombier
221219b2ee8SDavid du Colombier printitem(name, "Seq06");
222219b2ee8SDavid du Colombier printreg(vga->sequencer[0x06]);
223219b2ee8SDavid du Colombier printreg(vga->sequencer[0x07]);
224219b2ee8SDavid du Colombier
225219b2ee8SDavid du Colombier printitem(name, "Crt30");
226219b2ee8SDavid du Colombier for(i = 0x30; i < 0x38; i++)
227219b2ee8SDavid du Colombier printreg(vga->crt[i]);
228219b2ee8SDavid du Colombier printitem(name, "Crt3F");
229219b2ee8SDavid du Colombier printreg(vga->crt[0x3F]);
230219b2ee8SDavid du Colombier
231219b2ee8SDavid du Colombier printitem(name, "Attr16");
232219b2ee8SDavid du Colombier printreg(vga->attribute[0x16]);
233219b2ee8SDavid du Colombier printreg(vga->attribute[0x17]);
234219b2ee8SDavid du Colombier
235219b2ee8SDavid du Colombier if(strncmp(name, "et4000-w32", 10) == 0){
236219b2ee8SDavid du Colombier printitem(name, "SpriteE0");
237219b2ee8SDavid du Colombier for(i = Sprite; i < Sprite+NSprite; i++){
238219b2ee8SDavid du Colombier outportb(Crtcbx, i);
239219b2ee8SDavid du Colombier printreg(inportb(Crtcbx+1));
240219b2ee8SDavid du Colombier }
241219b2ee8SDavid du Colombier printitem(name, "ImaF0");
242219b2ee8SDavid du Colombier for(i = Ima; i < Ima+NIma; i++){
243219b2ee8SDavid du Colombier outportb(Crtcbx, i);
244219b2ee8SDavid du Colombier printreg(inportb(Crtcbx+1));
245219b2ee8SDavid du Colombier }
246219b2ee8SDavid du Colombier }
247219b2ee8SDavid du Colombier
248219b2ee8SDavid du Colombier /*
249219b2ee8SDavid du Colombier * Try to disassemble the snarfed values into
250219b2ee8SDavid du Colombier * understandable numbers.
251219b2ee8SDavid du Colombier * Only do this if we weren't called after Finit.
252219b2ee8SDavid du Colombier */
253219b2ee8SDavid du Colombier if(ctlr->flag & Finit)
254219b2ee8SDavid du Colombier return;
255219b2ee8SDavid du Colombier
256219b2ee8SDavid du Colombier x = (vga->crt[0x01]+1)<<3;
257219b2ee8SDavid du Colombier printitem(name, "hde");
258219b2ee8SDavid du Colombier printreg(x);
2597dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
260219b2ee8SDavid du Colombier
261219b2ee8SDavid du Colombier shb = ((((vga->crt[0x3F] & 0x04)<<6)|vga->crt[0x02])+1)<<3;
262219b2ee8SDavid du Colombier printitem(name, "shb");
263219b2ee8SDavid du Colombier printreg(shb);
2647dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", shb);
265219b2ee8SDavid du Colombier
266219b2ee8SDavid du Colombier x = (((vga->crt[0x05] & 0x80)>>2)|(vga->crt[0x03] & 0x1F))<<3;
267219b2ee8SDavid du Colombier printitem(name, "ehb");
268219b2ee8SDavid du Colombier printreg(x);
269219b2ee8SDavid du Colombier for(i = 0; x < shb; i++)
270219b2ee8SDavid du Colombier x |= 0x200<<i;
2717dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
272219b2ee8SDavid du Colombier
273219b2ee8SDavid du Colombier x = ((((vga->crt[0x3F] & 0x01)<<8)|vga->crt[0x00])+5)<<3;
274219b2ee8SDavid du Colombier printitem(name, "ht");
275219b2ee8SDavid du Colombier printreg(x);
2767dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
277219b2ee8SDavid du Colombier
278219b2ee8SDavid du Colombier x = vga->crt[0x12];
279219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x02)
280219b2ee8SDavid du Colombier x |= 0x100;
281219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x40)
282219b2ee8SDavid du Colombier x |= 0x200;
283219b2ee8SDavid du Colombier if(vga->crt[0x35] & 0x04)
284219b2ee8SDavid du Colombier x |= 0x400;
285219b2ee8SDavid du Colombier x += 1;
286219b2ee8SDavid du Colombier printitem(name, "vde");
287219b2ee8SDavid du Colombier printreg(x);
2887dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
289219b2ee8SDavid du Colombier
290219b2ee8SDavid du Colombier vrs = vga->crt[0x10];
291219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x04)
292219b2ee8SDavid du Colombier vrs |= 0x100;
293219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x80)
294219b2ee8SDavid du Colombier vrs |= 0x200;
295219b2ee8SDavid du Colombier if(vga->crt[0x35] & 0x08)
296219b2ee8SDavid du Colombier vrs |= 0x400;
297219b2ee8SDavid du Colombier printitem(name, "vrs");
298219b2ee8SDavid du Colombier printreg(vrs);
2997dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", vrs);
300219b2ee8SDavid du Colombier
301219b2ee8SDavid du Colombier x = (vrs & ~0x0F)|(vga->crt[0x11] & 0x0F);
302219b2ee8SDavid du Colombier printitem(name, "vre");
303219b2ee8SDavid du Colombier printreg(x);
3047dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
305219b2ee8SDavid du Colombier
306219b2ee8SDavid du Colombier x = vga->crt[0x06];
307219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x01)
308219b2ee8SDavid du Colombier x |= 0x100;
309219b2ee8SDavid du Colombier if(vga->crt[0x07] & 0x20)
310219b2ee8SDavid du Colombier x |= 0x200;
311219b2ee8SDavid du Colombier if(vga->crt[0x35] & 0x02)
312219b2ee8SDavid du Colombier x |= 0x400;
313219b2ee8SDavid du Colombier x += 2;
314219b2ee8SDavid du Colombier printitem(name, "vt");
315219b2ee8SDavid du Colombier printreg(x);
3167dd7cddfSDavid du Colombier Bprint(&stdout, "%6ud", x);
317219b2ee8SDavid du Colombier
318219b2ee8SDavid du Colombier printitem(name, "d i");
319219b2ee8SDavid du Colombier if(vga->sequencer[0x07] & 0x01)
320219b2ee8SDavid du Colombier x = 4;
321219b2ee8SDavid du Colombier else if(vga->sequencer[0x07] & 0x40)
322219b2ee8SDavid du Colombier x = 2;
323219b2ee8SDavid du Colombier else
324219b2ee8SDavid du Colombier x = 0;
3257dd7cddfSDavid du Colombier Bprint(&stdout, "%9ud", x);
326219b2ee8SDavid du Colombier x = (vga->misc & 0x0C)>>2;
327219b2ee8SDavid du Colombier if(vga->crt[0x34] & 0x02)
328219b2ee8SDavid du Colombier x |= 0x04;
329219b2ee8SDavid du Colombier x |= (vga->crt[0x31] & 0xC0)>>3;
3307dd7cddfSDavid du Colombier Bprint(&stdout, "%8ud\n", x);
331219b2ee8SDavid du Colombier }
332219b2ee8SDavid du Colombier
333219b2ee8SDavid du Colombier Ctlr et4000 = {
334219b2ee8SDavid du Colombier "et4000", /* name */
335219b2ee8SDavid du Colombier snarf, /* snarf */
336219b2ee8SDavid du Colombier options, /* options */
337219b2ee8SDavid du Colombier init, /* init */
338219b2ee8SDavid du Colombier load, /* load */
339219b2ee8SDavid du Colombier dump, /* dump */
340219b2ee8SDavid du Colombier };
341