xref: /plan9/sys/src/cmd/aux/vga/vga.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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