xref: /plan9/sys/src/cmd/aux/vga/s3generic.c (revision fb7f0c934c48abaed6040d054ef636408c3c522d)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * Generic S3 GUI Accelerator.
10  */
11 static void
snarf(Vga * vga,Ctlr * ctlr)12 snarf(Vga* vga, Ctlr* ctlr)
13 {
14 	int i;
15 
16 	trace("%s->snarf->s3generic\n", ctlr->name);
17 
18 	/*
19 	 * Unlock extended registers.
20 	 * 0xA5 ensures Crt36 and Crt37 are also unlocked
21 	 * (0xA0 unlocks everything else).
22 	 */
23 	vgaxo(Crtx, 0x38, 0x48);
24 	vgaxo(Crtx, 0x39, 0xA5);
25 
26 	/*
27 	 * Not all registers exist on all chips.
28 	 * Crt3[EF] don't exist on any.
29 	 */
30 	for(i = 0x30; i < 0x70; i++)
31 		vga->crt[i] = vgaxi(Crtx, i);
32 
33 	/*
34 	 * Memory size.
35 	 */
36 	switch((vga->crt[0x36]>>5) & 0x07){
37 
38 	case 0x00:
39 		vga->vmz = 4*1024*1024;
40 		break;
41 
42 	case 0x02:
43 		vga->vmz = 3*1024*1024;
44 		break;
45 
46 	case 0x04:
47 		vga->vmz = 2*1024*1024;
48 		break;
49 
50 	case 0x06:
51 		vga->vmz = 1*1024*1024;
52 		break;
53 
54 	case 0x07:
55 		vga->vmz = 512*1024;
56 		break;
57 	}
58 
59 	ctlr->flag |= Fsnarf;
60 }
61 
62 static void
init(Vga * vga,Ctlr * ctlr)63 init(Vga* vga, Ctlr* ctlr)
64 {
65 	Mode *mode;
66 	ulong x;
67 
68 	trace("%s->init->s3generic\n", ctlr->name);
69 	mode = vga->mode;
70 
71 	/*
72 	 * Is enhanced mode is necessary?
73 	 */
74 	if((ctlr->flag & (Uenhanced|Henhanced)) == Henhanced){
75 		if(mode->z >= 8)
76 			resyncinit(vga, ctlr, Uenhanced, 0);
77 		else
78 			resyncinit(vga, ctlr, 0, Uenhanced|Henhanced);
79 	}
80 	if((ctlr->flag & Uenhanced) == 0 && mode->x > 1024)
81 		error("%s: no support for 1-bit mode > 1024x768x1\n", ctlr->name);
82 
83 	vga->crt[0x31] = 0x85;
84 	vga->crt[0x6A] &= 0xC0;
85 	vga->crt[0x32] &= ~0x40;
86 
87 	vga->crt[0x31] |= 0x08;
88 	vga->crt[0x32] |= 0x40;
89 
90 	vga->crt[0x33] |= 0x20;
91 	if(mode->z >= 8)
92 		vga->crt[0x3A] |= 0x10;
93 	else
94 		vga->crt[0x3A] &= ~0x10;
95 
96 	vga->crt[0x34] = 0x10;
97 	vga->crt[0x35] = 0x00;
98 	if(mode->interlace){
99 		vga->crt[0x3C] = vga->crt[0]/2;
100 		vga->crt[0x42] |= 0x20;
101 	}
102 	else{
103 		vga->crt[0x3C] = 0x00;
104 		vga->crt[0x42] &= ~0x20;
105 	}
106 
107 	vga->crt[0x40] = (vga->crt[0x40] & 0xF2);
108 	vga->crt[0x43] = 0x00;
109 	vga->crt[0x45] = 0x00;
110 
111 	vga->crt[0x50] &= 0x3E;
112 	if(mode->x <= 640)
113 		x = 0x40;
114 	else if(mode->x <= 800)
115 		x = 0x80;
116 	else if(mode->x <= 1024)
117 		x = 0x00;
118 	else if(mode->x <= 1152)
119 		x = 0x01;
120 	else if(mode->x <= 1280)
121 		x = 0xC0;
122 	else
123 		x = 0x81;
124 	vga->crt[0x50] |= x;
125 
126 	vga->crt[0x51] = (vga->crt[0x51] & 0xC3)|((vga->crt[0x13]>>4) & 0x30);
127 	vga->crt[0x53] &= ~0x10;
128 
129 	/*
130 	 * Set up linear aperture. For the moment it's 64K at 0xA0000.
131 	 * The real base address will be assigned before load is called.
132 	 */
133 	vga->crt[0x58] = 0x88;
134 	if(ctlr->flag & Uenhanced){
135 		vga->crt[0x58] |= 0x10;
136 		if(vga->linear && (ctlr->flag & Hlinear))
137 			ctlr->flag |= Ulinear;
138 		if(vga->vmz <= 1024*1024)
139 			vga->vma = 1024*1024;
140 		else if(vga->vmz <= 2*1024*1024)
141 			vga->vma = 2*1024*1024;
142 		else
143 			vga->vma = 8*1024*1024;
144 	}
145 	vga->crt[0x59] = 0x00;
146 	vga->crt[0x5A] = 0x0A;
147 
148 	vga->crt[0x5D] &= 0x80;
149 	if(vga->crt[0x00] & 0x100)
150 		vga->crt[0x5D] |= 0x01;
151 	if(vga->crt[0x01] & 0x100)
152 		vga->crt[0x5D] |= 0x02;
153 	if(vga->crt[0x02] & 0x100)
154 		vga->crt[0x5D] |= 0x04;
155 	if(vga->crt[0x04] & 0x100)
156 		vga->crt[0x5D] |= 0x10;
157 	if(vga->crt[0x3B] & 0x100)
158 		vga->crt[0x5D] |= 0x40;
159 
160 	vga->crt[0x5E] = 0x40;
161 	if(vga->crt[0x06] & 0x400)
162 		vga->crt[0x5E] |= 0x01;
163 	if(vga->crt[0x12] & 0x400)
164 		vga->crt[0x5E] |= 0x02;
165 	if(vga->crt[0x15] & 0x400)
166 		vga->crt[0x5E] |= 0x04;
167 	if(vga->crt[0x10] & 0x400)
168 		vga->crt[0x5E] |= 0x10;
169 
170 	ctlr->type = s3generic.name;
171 
172 	ctlr->flag |= Finit;
173 }
174 
175 static void
load(Vga * vga,Ctlr * ctlr)176 load(Vga* vga, Ctlr* ctlr)
177 {
178 	ulong l;
179 
180 	trace("%s->load->s3generic\n", ctlr->name);
181 
182 	vgaxo(Crtx, 0x31, vga->crt[0x31]);
183 	vgaxo(Crtx, 0x32, vga->crt[0x32]);
184 	vgaxo(Crtx, 0x33, vga->crt[0x33]);
185 	vgaxo(Crtx, 0x34, vga->crt[0x34]);
186 	vgaxo(Crtx, 0x35, vga->crt[0x35]);
187 	vgaxo(Crtx, 0x3A, vga->crt[0x3A]);
188 	vgaxo(Crtx, 0x3B, vga->crt[0x3B]);
189 	vgaxo(Crtx, 0x3C, vga->crt[0x3C]);
190 
191 	vgaxo(Crtx, 0x40, vga->crt[0x40]|0x01);
192 	vgaxo(Crtx, 0x42, vga->crt[0x42]);
193 	vgaxo(Crtx, 0x43, vga->crt[0x43]);
194 	vgaxo(Crtx, 0x45, vga->crt[0x45]);
195 
196 	vgaxo(Crtx, 0x50, vga->crt[0x50]);
197 	vgaxo(Crtx, 0x51, vga->crt[0x51]);
198 	vgaxo(Crtx, 0x53, vga->crt[0x53]);
199 	vgaxo(Crtx, 0x54, vga->crt[0x54]);
200 	vgaxo(Crtx, 0x55, vga->crt[0x55]);
201 
202 	if(ctlr->flag & Ulinear){
203 		l = vga->vmb>>16;
204 		vga->crt[0x59] = (l>>8) & 0xFF;
205 		vga->crt[0x5A] = l & 0xFF;
206 		if(vga->vmz <= 1024*1024)
207 			vga->crt[0x58] |= 0x01;
208 		else if(vga->vmz <= 2*1024*1024)
209 			vga->crt[0x58] |= 0x02;
210 		else
211 			vga->crt[0x58] |= 0x03;
212 	}
213 	vgaxo(Crtx, 0x59, vga->crt[0x59]);
214 	vgaxo(Crtx, 0x5A, vga->crt[0x5A]);
215 	vgaxo(Crtx, 0x58, vga->crt[0x58]);
216 
217 	vgaxo(Crtx, 0x5D, vga->crt[0x5D]);
218 	vgaxo(Crtx, 0x5E, vga->crt[0x5E]);
219 
220 	vgaxo(Crtx, 0x6A, vga->crt[0x6A]);
221 
222 	ctlr->flag |= Fload;
223 }
224 
225 static void
dump(Vga * vga,Ctlr * ctlr)226 dump(Vga* vga, Ctlr* ctlr)
227 {
228 	int i, id, interlace, mul, div;
229 	char *name;
230 	ushort shb, vrs, x;
231 
232 	name = ctlr->name;
233 
234 	printitem(name, "Crt30");
235 	for(i = 0x30; i < 0x3E; i++)
236 		printreg(vga->crt[i]);
237 
238 	printitem(name, "Crt40");
239 	for(i = 0x40; i < 0x50; i++)
240 		printreg(vga->crt[i]);
241 
242 	printitem(name, "Crt50");
243 	for(i = 0x50; i < 0x60; i++)
244 		printreg(vga->crt[i]);
245 
246 	printitem(name, "Crt60");
247 	for(i = 0x60; i < 0x70; i++)
248 		printreg(vga->crt[i]);
249 
250 	/*
251 	 * Try to disassemble the snarfed values into
252 	 * understandable numbers.
253 	 * Only do this if we weren't called after Finit.
254 	 */
255 	if(ctlr->flag & Finit)
256 		return;
257 
258 
259 	/*
260 	 * If hde <= 400, assume this is a 928 or Vision964
261 	 * and the horizontal values have been divided by 4.
262 	 *
263 	 * if ViRGE/[DG]X and 15 or 16bpp, horizontal values have
264 	 * been multiplied by 2.
265 	 */
266 	mul = 1;
267 	div = 1;
268 
269 	if(strcmp(name, "virge") == 0){
270 		id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
271 		/* S3 ViRGE/[DG]X */
272 		if(id==0x8A01 && ((vga->crt[0x67] & 0x30) || (vga->crt[0x67] & 0x50))){
273 			mul = 1;
274 			div = 2;
275 		}
276 	}
277 
278 	x = vga->crt[0x01];
279 	if(vga->crt[0x5D] & 0x02)
280 		x |= 0x100;
281 	x = (x+1)<<3;
282 
283 	if(x <= 400){
284 		mul = 4;
285 		div = 1;
286 	}
287 
288 	x = (x * mul) / div;
289 	printitem(name, "hde");
290 	printreg(x);
291 	Bprint(&stdout, "%6ud", x);
292 
293 	shb = vga->crt[0x02];
294 	if(vga->crt[0x5D] & 0x04)
295 		shb |= 0x100;
296 	shb = (shb+1)<<3;
297 	shb = (shb * mul) / div;
298 	printitem(name, "shb");
299 	printreg(shb);
300 	Bprint(&stdout, "%6ud", shb);
301 
302 	x = vga->crt[0x03] & 0x1F;
303 	if(vga->crt[0x05] & 0x80)
304 		x |= 0x20;
305 	x = (x * mul) / div;
306 	x = shb|x;					/* ???? */
307 	if(vga->crt[0x5D] & 0x08)
308 		x += 64;
309 	printitem(name, "ehb");
310 	printreg(x);
311 	Bprint(&stdout, "%6ud", x);
312 
313 	x = vga->crt[0x00];
314 	if(vga->crt[0x5D] & 0x01)
315 		x |= 0x100;
316 	x = (x+5)<<3;
317 	x = (x * mul) / div;
318 	printitem(name, "ht");
319 	printreg(x);
320 	Bprint(&stdout, "%6ud", x);
321 
322 	interlace = vga->crt[0x42] & 0x20;
323 	x = vga->crt[0x12];
324 	if(vga->crt[0x07] & 0x02)
325 		x |= 0x100;
326 	if(vga->crt[0x07] & 0x40)
327 		x |= 0x200;
328 	if(vga->crt[0x5E] & 0x02)
329 		x |= 0x400;
330 	x += 1;
331 	if(interlace)
332 		x *= 2;
333 	printitem(name, "vde");
334 	printreg(x);
335 	Bprint(&stdout, "%6ud", x);
336 
337 	vrs = vga->crt[0x10];
338 	if(vga->crt[0x07] & 0x04)
339 		vrs |= 0x100;
340 	if(vga->crt[0x07] & 0x80)
341 		vrs |= 0x200;
342 	if(vga->crt[0x5E] & 0x10)
343 		vrs |= 0x400;
344 	if(interlace)
345 		vrs *= 2;
346 	printitem(name, "vrs");
347 	printreg(vrs);
348 	Bprint(&stdout, "%6ud", vrs);
349 
350 	if(interlace)
351 		vrs /= 2;
352 	x = (vrs & ~0x0F)|(vga->crt[0x11] & 0x0F);
353 	if(interlace)
354 		x *= 2;
355 	printitem(name, "vre");
356 	printreg(x);
357 	Bprint(&stdout, "%6ud", x);
358 
359 	x = vga->crt[0x06];
360 	if(vga->crt[0x07] & 0x01)
361 		x |= 0x100;
362 	if(vga->crt[0x07] & 0x20)
363 		x |= 0x200;
364 	if(vga->crt[0x5E] & 0x01)
365 		x |= 0x400;
366 	x += 2;
367 	if(interlace)
368 		x *= 2;
369 	printitem(name, "vt");
370 	printreg(x);
371 	Bprint(&stdout, "%6ud", x);
372 }
373 
374 Ctlr s3generic = {
375 	"s3",				/* name */
376 	snarf,				/* snarf */
377 	0,				/* options */
378 	init,				/* init */
379 	load,				/* load */
380 	dump,				/* dump */
381 };
382