1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 enum {
9 NSeqx = 0x05,
10 NCrtx = 0x19,
11 NGrx = 0x09,
12 NAttrx = 0x15,
13 };
14
15 uchar
vgai(long port)16 vgai(long port)
17 {
18 uchar data;
19
20 switch(port){
21
22 case MiscR:
23 case Status0:
24 case Status1:
25 case FeatureR:
26 case PaddrW:
27 case Pdata:
28 case Pixmask:
29 case Pstatus:
30 data = inportb(port);
31 break;
32
33 default:
34 error("vgai(0x%4.4lX): unknown port\n", port);
35 /*NOTREACHED*/
36 data = 0xFF;
37 break;
38 }
39 return data;
40 }
41
42 uchar
vgaxi(long port,uchar index)43 vgaxi(long port, uchar index)
44 {
45 uchar data;
46
47 switch(port){
48
49 case Seqx:
50 case Crtx:
51 case Grx:
52 outportb(port, index);
53 data = inportb(port+1);
54 break;
55
56 case Attrx:
57 /*
58 * Allow processor access to the colour
59 * palette registers. Writes to Attrx must
60 * be preceded by a read from Status1 to
61 * initialise the register to point to the
62 * index register and not the data register.
63 * Processor access is allowed by turning
64 * off bit 0x20.
65 */
66 inportb(Status1);
67 if(index < 0x10){
68 outportb(Attrx, index);
69 data = inportb(Attrx+1);
70 inportb(Status1);
71 outportb(Attrx, 0x20|index);
72 }
73 else{
74 outportb(Attrx, 0x20|index);
75 data = inportb(Attrx+1);
76 }
77 break;
78
79 default:
80 error("vgaxi(0x%4.4lx, 0x%2.2uX): unknown port\n", port, index);
81 /*NOTREACHED*/
82 data = 0xFF;
83 break;
84 }
85 return data;
86 }
87
88 void
vgao(long port,uchar data)89 vgao(long port, uchar data)
90 {
91 switch(port){
92
93 case MiscW:
94 case FeatureW:
95 case PaddrW:
96 case Pdata:
97 case Pixmask:
98 case PaddrR:
99 outportb(port, data);
100 break;
101
102 default:
103 error("vgao(0x%4.4lX, 0x%2.2uX): unknown port\n", port, data);
104 /*NOTREACHED*/
105 break;
106 }
107 }
108
109 void
vgaxo(long port,uchar index,uchar data)110 vgaxo(long port, uchar index, uchar data)
111 {
112 switch(port){
113
114 case Seqx:
115 case Crtx:
116 case Grx:
117 /*
118 * We could use an outport here, but some chips
119 * (e.g. 86C928) have trouble with that for some
120 * registers.
121 */
122 outportb(port, index);
123 outportb(port+1, data);
124 break;
125
126 case Attrx:
127 inportb(Status1);
128 if(index < 0x10){
129 outportb(Attrx, index);
130 outportb(Attrx, data);
131 inportb(Status1);
132 outportb(Attrx, 0x20|index);
133 }
134 else{
135 outportb(Attrx, 0x20|index);
136 outportb(Attrx, data);
137 }
138 break;
139
140 default:
141 error("vgaxo(0x%4.4lX, 0x%2.2uX, 0x%2.2uX): unknown port\n",
142 port, index, data);
143 break;
144 }
145 }
146
147 static void
snarf(Vga * vga,Ctlr * ctlr)148 snarf(Vga* vga, Ctlr* ctlr)
149 {
150 int i;
151
152 /*
153 * Generic VGA registers:
154 * misc, feature;
155 * sequencer;
156 * crt;
157 * graphics;
158 * attribute;
159 * palette.
160 */
161 vga->misc = vgai(MiscR);
162 vga->feature = vgai(FeatureR);
163
164 for(i = 0; i < NSeqx; i++)
165 vga->sequencer[i] = vgaxi(Seqx, i);
166
167 for(i = 0; i < NCrtx; i++)
168 vga->crt[i] = vgaxi(Crtx, i);
169
170 for(i = 0; i < NGrx; i++)
171 vga->graphics[i] = vgaxi(Grx, i);
172
173 for(i = 0; i < NAttrx; i++)
174 vga->attribute[i] = vgaxi(Attrx, i);
175
176 if(dflag)
177 palette.snarf(vga, ctlr);
178
179 ctlr->flag |= Fsnarf;
180 }
181
182 static void
init(Vga * vga,Ctlr * ctlr)183 init(Vga* vga, Ctlr* ctlr)
184 {
185 Mode *mode;
186 int vt, vde, vrs, vre;
187 ulong tmp;
188
189 mode = vga->mode;
190
191 memset(vga->sequencer, 0, NSeqx*sizeof(vga->sequencer[0]));
192 memset(vga->crt, 0, NCrtx*sizeof(vga->crt[0]));
193 memset(vga->graphics, 0, NGrx*sizeof(vga->graphics[0]));
194 memset(vga->attribute, 0, NAttrx*sizeof(vga->attribute[0]));
195 if(dflag)
196 memset(vga->palette, 0, sizeof(vga->palette));
197
198 /*
199 * Misc. If both the horizontal and vertical sync polarity
200 * options are set, use them. Otherwise use the defaults for
201 * the given vertical size.
202 */
203 vga->misc = 0x23;
204 if(mode->frequency == VgaFreq1)
205 vga->misc |= 0x04;
206 if(mode->hsync && mode->vsync){
207 if(mode->hsync == '-')
208 vga->misc |= 0x40;
209 if(mode->vsync == '-')
210 vga->misc |= 0x80;
211 }
212 else{
213 if(mode->y < 480)
214 vga->misc |= 0x40;
215 else if(mode->y < 400)
216 vga->misc |= 0x80;
217 else if(mode->y < 768)
218 vga->misc |= 0xC0;
219 }
220
221 /*
222 * Sequencer
223 */
224 vga->sequencer[0x00] = 0x03;
225 vga->sequencer[0x01] = 0x01;
226 vga->sequencer[0x02] = 0x0F;
227 vga->sequencer[0x03] = 0x00;
228 if(mode->z >= 8)
229 vga->sequencer[0x04] = 0x0A;
230 else
231 vga->sequencer[0x04] = 0x06;
232
233 /*
234 * Crt. Most of the work here is in dealing
235 * with field overflow.
236 */
237 memset(vga->crt, 0, NCrtx);
238
239 vga->crt[0x00] = (mode->ht>>3)-5;
240 vga->crt[0x01] = (mode->x>>3)-1;
241 vga->crt[0x02] = (mode->shb>>3)-1;
242
243 /*
244 * End Horizontal Blank is a 6-bit field, 5-bits
245 * in Crt3, high bit in Crt5.
246 */
247 tmp = mode->ehb>>3;
248 vga->crt[0x03] = 0x80|(tmp & 0x1F);
249 if(tmp & 0x20)
250 vga->crt[0x05] |= 0x80;
251
252 if(mode->shs == 0)
253 mode->shs = mode->shb;
254 vga->crt[0x04] = mode->shs>>3;
255 if(mode->ehs == 0)
256 mode->ehs = mode->ehb;
257 vga->crt[0x05] |= ((mode->ehs>>3) & 0x1F);
258
259 /*
260 * Vertical Total is 10-bits, 8 in Crt6, the high
261 * two bits in Crt7. What if vt is >= 1024? We hope
262 * the specific controller has some more overflow
263 * bits.
264 *
265 * Interlace: if 'v', divide the vertical timing
266 * values by 2.
267 */
268 vt = mode->vt;
269 vde = mode->y;
270 vrs = mode->vrs;
271 vre = mode->vre;
272
273 if(mode->interlace == 'v'){
274 vt /= 2;
275 vde /= 2;
276 vrs /= 2;
277 vre /= 2;
278 }
279
280 tmp = vt-2;
281 vga->crt[0x06] = tmp;
282 if(tmp & 0x100)
283 vga->crt[0x07] |= 0x01;
284 if(tmp & 0x200)
285 vga->crt[0x07] |= 0x20;
286
287 tmp = vrs;
288 vga->crt[0x10] = tmp;
289 if(tmp & 0x100)
290 vga->crt[0x07] |= 0x04;
291 if(tmp & 0x200)
292 vga->crt[0x07] |= 0x80;
293
294 vga->crt[0x11] = 0x20|(vre & 0x0F);
295
296 tmp = vde-1;
297 vga->crt[0x12] = tmp;
298 if(tmp & 0x100)
299 vga->crt[0x07] |= 0x02;
300 if(tmp & 0x200)
301 vga->crt[0x07] |= 0x40;
302
303 vga->crt[0x15] = vrs;
304 if(vrs & 0x100)
305 vga->crt[0x07] |= 0x08;
306 if(vrs & 0x200)
307 vga->crt[0x09] |= 0x20;
308
309 vga->crt[0x16] = (vrs+1);
310
311 vga->crt[0x17] = 0x83;
312 tmp = ((vga->virtx*mode->z)/8);
313 if(tmp >= 512){
314 vga->crt[0x14] |= 0x60;
315 tmp /= 8;
316 }
317 else if(tmp >= 256){
318 vga->crt[0x17] |= 0x08;
319 tmp /= 4;
320 }
321 else{
322 vga->crt[0x17] |= 0x40;
323 tmp /= 2;
324 }
325 vga->crt[0x13] = tmp;
326
327 if(mode->x*mode->y*mode->z/8 > 64*1024)
328 vga->crt[0x17] |= 0x20;
329
330 vga->crt[0x18] = 0x7FF;
331 if(vga->crt[0x18] & 0x100)
332 vga->crt[0x07] |= 0x10;
333 if(vga->crt[0x18] & 0x200)
334 vga->crt[0x09] |= 0x40;
335
336 /*
337 * Graphics
338 */
339 memset(vga->graphics, 0, NGrx);
340 if((vga->sequencer[0x04] & 0x04) == 0)
341 vga->graphics[0x05] |= 0x10;
342 if(mode->z >= 8)
343 vga->graphics[0x05] |= 0x40;
344 vga->graphics[0x06] = 0x05;
345 vga->graphics[0x07] = 0x0F;
346 vga->graphics[0x08] = 0xFF;
347
348 /*
349 * Attribute
350 */
351 memset(vga->attribute, 0, NAttrx);
352 for(tmp = 0; tmp < 0x10; tmp++)
353 vga->attribute[tmp] = tmp;
354 vga->attribute[0x10] = 0x01;
355 if(mode->z >= 8)
356 vga->attribute[0x10] |= 0x40;
357 vga->attribute[0x11] = 0xFF;
358 vga->attribute[0x12] = 0x0F;
359
360 /*
361 * Palette
362 */
363 if(dflag)
364 palette.init(vga, ctlr);
365
366 ctlr->flag |= Finit;
367 }
368
369 static void
load(Vga * vga,Ctlr * ctlr)370 load(Vga* vga, Ctlr* ctlr)
371 {
372 int i;
373
374 /*
375 * Reset the sequencer and leave it off.
376 * Load the generic VGA registers:
377 * misc;
378 * sequencer (but not seq01, display enable);
379 * take the sequencer out of reset;
380 * take off write-protect on crt[0x00-0x07];
381 * crt;
382 * graphics;
383 * attribute;
384 * palette.
385 vgaxo(Seqx, 0x00, 0x00);
386 */
387
388 vgao(MiscW, vga->misc);
389
390 for(i = 2; i < NSeqx; i++)
391 vgaxo(Seqx, i, vga->sequencer[i]);
392 /*vgaxo(Seqx, 0x00, 0x03);*/
393
394 vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
395 for(i = 0; i < NCrtx; i++)
396 vgaxo(Crtx, i, vga->crt[i]);
397
398 for(i = 0; i < NGrx; i++)
399 vgaxo(Grx, i, vga->graphics[i]);
400
401 for(i = 0; i < NAttrx; i++)
402 vgaxo(Attrx, i, vga->attribute[i]);
403
404 if(dflag)
405 palette.load(vga, ctlr);
406
407 ctlr->flag |= Fload;
408 }
409
410 static void
dump(Vga * vga,Ctlr * ctlr)411 dump(Vga* vga, Ctlr* ctlr)
412 {
413 int i;
414
415 printitem(ctlr->name, "misc");
416 printreg(vga->misc);
417 printitem(ctlr->name, "feature");
418 printreg(vga->feature);
419
420 printitem(ctlr->name, "sequencer");
421 for(i = 0; i < NSeqx; i++)
422 printreg(vga->sequencer[i]);
423
424 printitem(ctlr->name, "crt");
425 for(i = 0; i < NCrtx; i++)
426 printreg(vga->crt[i]);
427
428 printitem(ctlr->name, "graphics");
429 for(i = 0; i < NGrx; i++)
430 printreg(vga->graphics[i]);
431
432 printitem(ctlr->name, "attribute");
433 for(i = 0; i < NAttrx; i++)
434 printreg(vga->attribute[i]);
435
436 if(dflag)
437 palette.dump(vga, ctlr);
438
439 printitem(ctlr->name, "virtual");
440 Bprint(&stdout, "%ld %ld\n", vga->virtx, vga->virty);
441 printitem(ctlr->name, "panning");
442 Bprint(&stdout, "%s\n", vga->panning ? "on" : "off");
443 if(vga->f[0]){
444 printitem(ctlr->name, "clock[0] f");
445 Bprint(&stdout, "%9ld\n", vga->f[0]);
446 printitem(ctlr->name, "clock[0] d i m");
447 Bprint(&stdout, "%9ld %8ld - %8ld\n",
448 vga->d[0], vga->i[0], vga->m[0]);
449 printitem(ctlr->name, "clock[0] n p q r");
450 Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
451 vga->n[0], vga->p[0], vga->q[0], vga->r[0]);
452 }
453 if(vga->f[1]){
454 printitem(ctlr->name, "clock[1] f");
455 Bprint(&stdout, "%9ld\n", vga->f[1]);
456 printitem(ctlr->name, "clock[1] d i m");
457 Bprint(&stdout, "%9ld %8ld - %8ld\n",
458 vga->d[1], vga->i[1], vga->m[1]);
459 printitem(ctlr->name, "clock[1] n p q r");
460 Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
461 vga->n[1], vga->p[1], vga->q[1], vga->r[1]);
462 }
463
464 if(vga->vma || vga->vmb){
465 printitem(ctlr->name, "vm a b");
466 Bprint(&stdout, "%9lud %8lud\n", vga->vma, vga->vmb);
467 }
468 if(vga->vmz){
469 printitem(ctlr->name, "vmz");
470 Bprint(&stdout, "%9lud\n", vga->vmz);
471 }
472 printitem(ctlr->name, "apz");
473 Bprint(&stdout, "%9lud\n", vga->apz);
474
475 printitem(ctlr->name, "linear");
476 Bprint(&stdout, "%9d\n", vga->linear);
477 }
478
479 Ctlr generic = {
480 "vga", /* name */
481 snarf, /* snarf */
482 0, /* options */
483 init, /* init */
484 load, /* load */
485 dump, /* dump */
486 };
487