xref: /plan9/sys/src/9/pc/vgamga4xx.c (revision 1066d6debf4f3ce80fbab98c906650d920c13a7a)
1 
2 /*
3  * Matrox G200, G400 and G450.
4  * Written by Philippe Anel <xigh@free.fr>
5  *
6  *  2006-08-07 : Minor fix to allow the G200 cards to work fine. YDSTORG is now initialized.
7  *             : Also support for 16 and 24 bit modes is added.
8  *             : by Leonardo Valencia <leoval@anixcorp.com>
9  */
10 
11 #include "u.h"
12 #include "../port/lib.h"
13 #include "mem.h"
14 #include "dat.h"
15 #include "fns.h"
16 #include "io.h"
17 #include "../port/error.h"
18 
19 #define	Image IMAGE
20 #include <draw.h>
21 #include <memdraw.h>
22 #include <cursor.h>
23 #include "screen.h"
24 
25 enum {
26 	MATROX			= 0x102B,
27 	MGA550			= 0x2527,
28 	MGA4xx			= 0x0525,
29 	MGA200			= 0x0521,
30 
31 	FCOL			= 0x1c24,
32 	FXRIGHT			= 0x1cac,
33 	FXLEFT			= 0x1ca8,
34 	YDST			= 0x1c90,
35 	YLEN			= 0x1c5c,
36  	DWGCTL			= 0x1c00,
37  		DWG_TRAP		= 0x04,
38  		DWG_BITBLT		= 0x08,
39  		DWG_ILOAD		= 0x09,
40  		DWG_LINEAR		= 0x0080,
41  		DWG_SOLID		= 0x0800,
42  		DWG_ARZERO		= 0x1000,
43  		DWG_SGNZERO		= 0x2000,
44  		DWG_SHIFTZERO	= 0x4000,
45 		DWG_REPLACE		= 0x000C0000,
46  		DWG_BFCOL		= 0x04000000,
47  	SRCORG			= 0x2cb4,
48 	PITCH			= 0x1c8c,
49 	DSTORG			= 0x2cb8,
50 	YDSTORG			= 0x1c94,
51 	PLNWRT			= 0x1c1c,
52 	ZORG			= 0x1c0c,
53 	MACCESS			= 0x1c04,
54 	STATUS			= 0x1e14,
55 	FXBNDRY			= 0x1C84,
56  	CXBNDRY			= 0x1C80,
57 	YTOP			= 0x1C98,
58 	YBOT			= 0x1C9C,
59 	YDSTLEN			= 0x1C88,
60 	AR0				= 0x1C60,
61 	AR1				= 0x1C64,
62 	AR2				= 0x1C68,
63 	AR3				= 0x1C6C,
64 	AR4				= 0x1C70,
65 	AR5				= 0x1C74,
66 	SGN				= 0x1C58,
67 		SGN_LEFT		= 1,
68 		SGN_UP			= 4,
69 
70 	GO				= 0x0100,
71  	FIFOSTATUS		= 0x1E10,
72 	CACHEFLUSH		= 0x1FFF,
73 
74 	CRTCEXTIDX		= 0x1FDE,		/* CRTC Extension Index */
75 	CRTCEXTDATA		= 0x1FDF,		/* CRTC Extension Data */
76 
77 	FILL_OPERAND	= 0x800c7804,
78 };
79 
80 static Pcidev *
mgapcimatch(void)81 mgapcimatch(void)
82 {
83 	Pcidev *p;
84 
85 	p = pcimatch(nil, MATROX, MGA4xx);
86 	if(p == nil)
87 		p = pcimatch(nil, MATROX, MGA550);
88 	if(p == nil)
89 		p = pcimatch(nil, MATROX, MGA200);
90 	return p;
91 }
92 
93 
94 static void
mgawrite8(VGAscr * scr,int index,uchar val)95 mgawrite8(VGAscr *scr, int index, uchar val)
96 {
97 	((uchar*)scr->mmio)[index] = val;
98 }
99 
100 static uchar
mgaread8(VGAscr * scr,int index)101 mgaread8(VGAscr *scr, int index)
102 {
103 	return ((uchar*)scr->mmio)[index];
104 }
105 
106 static uchar
crtcextset(VGAscr * scr,int index,uchar set,uchar clr)107 crtcextset(VGAscr *scr, int index, uchar set, uchar clr)
108 {
109 	uchar tmp;
110 
111 	mgawrite8(scr, CRTCEXTIDX, index);
112 	tmp = mgaread8(scr, CRTCEXTDATA);
113 	mgawrite8(scr, CRTCEXTIDX, index);
114 	mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set);
115 
116 	return tmp;
117 }
118 
119 static void
mga4xxenable(VGAscr * scr)120 mga4xxenable(VGAscr* scr)
121 {
122 	Pcidev *pci;
123 	int size;
124 	int i, n, k;
125 	uchar *p;
126 	uchar x[16];
127 	uchar crtcext3;
128 
129 	if(scr->mmio)
130 		return;
131 
132 	pci = mgapcimatch();
133 	if(pci == nil)
134 		return;
135 
136 	scr->mmio = vmap(pci->mem[1].bar&~0x0F, 16*1024);
137 	if(scr->mmio == nil)
138 		return;
139 
140 	addvgaseg("mga4xxmmio", pci->mem[1].bar&~0x0F, pci->mem[1].size);
141 
142 	/* need to map frame buffer here too, so vga can find memory size */
143 	if(pci->did == MGA4xx || pci->did == MGA550)
144 		size = 32*MB;
145 	else
146 		size = 8*MB;
147 	vgalinearaddr(scr, pci->mem[0].bar&~0x0F, size);
148 
149 	if(scr->paddr){
150 
151 		/* Find out how much memory is here, some multiple of 2 MB */
152 
153 		/* First Set MGA Mode ... */
154 		crtcext3 = crtcextset(scr, 3, 0x80, 0x00);
155 
156 		p = scr->vaddr;
157 		n = (size / MB) / 2;
158 		for(i = 0; i < n; i++){
159 			k = (2*i+1)*MB;
160 			p[k] = 0;
161 			p[k] = i+1;
162 			*((uchar*)scr->mmio + CACHEFLUSH) = 0;
163 			x[i] = p[k];
164  		}
165 		for(i = 1; i < n; i++)
166 			if(x[i] != i+1)
167 				break;
168 		scr->apsize = 2*i*MB;	/* sketchy */
169 		addvgaseg("mga4xxscreen", scr->paddr, scr->apsize);
170 		crtcextset(scr, 3, crtcext3, 0xff);
171 	}
172 }
173 
174 enum{
175 	Index		= 0x00,		/* Index */
176 	Data			= 0x0A,		/* Data */
177 
178 	Cxlsb		= 0x0C,		/* Cursor X LSB */
179 	Cxmsb		= 0x0D,		/* Cursor X MSB */
180 	Cylsb		= 0x0E,		/* Cursor Y LSB */
181 	Cymsb		= 0x0F,		/* Cursor Y MSB */
182 
183 	Icuradrl		= 0x04,		/* Cursor Base Address Low */
184 	Icuradrh		= 0x05,		/* Cursor Base Address High */
185 	Icctl			= 0x06,		/* Indirect Cursor Control */
186 };
187 
188 static void
dac4xxdisable(VGAscr * scr)189 dac4xxdisable(VGAscr *scr)
190 {
191 	uchar *dac4xx;
192 
193 	if(scr->mmio == 0)
194 		return;
195 
196 	dac4xx = (uchar*)scr->mmio+0x3C00;
197 
198 	*(dac4xx+Index) = Icctl;
199 	*(dac4xx+Data) = 0x00;
200 }
201 
202 static void
dac4xxload(VGAscr * scr,Cursor * curs)203 dac4xxload(VGAscr *scr, Cursor *curs)
204 {
205 	int y;
206 	uchar *p;
207 	uchar *dac4xx;
208 
209 	if(scr->mmio == 0)
210 		return;
211 
212 	dac4xx = (uchar*)scr->mmio+0x3C00;
213 
214 	dac4xxdisable(scr);
215 
216 	p = (uchar*)scr->storage;
217 	for(y = 0; y < 64; y++){
218 		*p++ = 0; *p++ = 0; *p++ = 0;
219 		*p++ = 0; *p++ = 0; *p++ = 0;
220 		if(y < 16){
221 			*p++ = curs->set[1+y*2];
222 			*p++ = curs->set[y*2];
223 		} else{
224 			*p++ = 0; *p++ = 0;
225 		}
226 
227 		*p++ = 0; *p++ = 0; *p++ = 0;
228 		*p++ = 0; *p++ = 0; *p++ = 0;
229 		if(y < 16){
230 			*p++ = curs->set[1+y*2]|curs->clr[1+2*y];
231 			*p++ = curs->set[y*2]|curs->clr[2*y];
232 		} else{
233 			*p++ = 0; *p++ = 0;
234 		}
235 	}
236 	scr->offset.x = 64 + curs->offset.x;
237 	scr->offset.y = 64 + curs->offset.y;
238 
239 	*(dac4xx+Index) = Icctl;
240 	*(dac4xx+Data) = 0x03;
241 }
242 
243 static int
dac4xxmove(VGAscr * scr,Point p)244 dac4xxmove(VGAscr *scr, Point p)
245 {
246 	int x, y;
247 	uchar *dac4xx;
248 
249 	if(scr->mmio == 0)
250 		return 1;
251 
252 	dac4xx = (uchar*)scr->mmio + 0x3C00;
253 
254 	x = p.x + scr->offset.x;
255 	y = p.y + scr->offset.y;
256 
257 	*(dac4xx+Cxlsb) = x & 0xFF;
258 	*(dac4xx+Cxmsb) = (x>>8) & 0x0F;
259 
260 	*(dac4xx+Cylsb) = y & 0xFF;
261 	*(dac4xx+Cymsb) = (y>>8) & 0x0F;
262 
263 	return 0;
264 }
265 
266 static void
dac4xxenable(VGAscr * scr)267 dac4xxenable(VGAscr *scr)
268 {
269 	uchar *dac4xx;
270 	ulong storage;
271 
272 	if(scr->mmio == 0)
273 		return;
274 	dac4xx = (uchar*)scr->mmio+0x3C00;
275 
276 	dac4xxdisable(scr);
277 
278 	storage = (scr->apsize-4096)&~0x3ff;
279 
280 	*(dac4xx+Index) = Icuradrl;
281 	*(dac4xx+Data) = 0xff & (storage >> 10);
282 	*(dac4xx+Index) = Icuradrh;
283 	*(dac4xx+Data) = 0xff & (storage >> 18);
284 
285 	scr->storage = (ulong)scr->vaddr + storage;
286 
287 	/* Show X11-Like Cursor */
288 	*(dac4xx+Index) = Icctl;
289 	*(dac4xx+Data) = 0x03;
290 
291 	/* Cursor Color 0 : White */
292 	*(dac4xx+Index) = 0x08;
293 	*(dac4xx+Data)  = 0xff;
294 	*(dac4xx+Index) = 0x09;
295 	*(dac4xx+Data)  = 0xff;
296 	*(dac4xx+Index) = 0x0a;
297 	*(dac4xx+Data)  = 0xff;
298 
299 	/* Cursor Color 1 : Black */
300 	*(dac4xx+Index) = 0x0c;
301 	*(dac4xx+Data)  = 0x00;
302 	*(dac4xx+Index) = 0x0d;
303 	*(dac4xx+Data)  = 0x00;
304 	*(dac4xx+Index) = 0x0e;
305 	*(dac4xx+Data)  = 0x00;
306 
307 	/* Cursor Color 2 : Red */
308 	*(dac4xx+Index) = 0x10;
309 	*(dac4xx+Data)  = 0xff;
310 	*(dac4xx+Index) = 0x11;
311 	*(dac4xx+Data)  = 0x00;
312 	*(dac4xx+Index) = 0x12;
313 	*(dac4xx+Data)  = 0x00;
314 
315 	/*
316 	 * Load, locate and enable the
317 	 * 64x64 cursor in X11 mode.
318 	 */
319 	dac4xxload(scr, &arrow);
320 	dac4xxmove(scr, ZP);
321 }
322 
323 static void
mga4xxblank(VGAscr * scr,int blank)324 mga4xxblank(VGAscr *scr, int blank)
325 {
326 	char *cp;
327 	uchar *mga;
328 	uchar seq1, crtcext1;
329 
330 	/* blank = 0 -> turn screen on */
331 	/* blank = 1 -> turn screen off */
332 
333 	if(scr->mmio == 0)
334 		return;
335 	mga = (uchar*)scr->mmio;
336 
337 	if(blank == 0){
338 		seq1 = 0x00;
339 		crtcext1 = 0x00;
340 	} else {
341 		seq1 = 0x20;
342 		crtcext1 = 0x10;			/* Default value ... : standby */
343 		cp = getconf("*dpms");
344 		if(cp){
345 			if(cistrcmp(cp, "standby") == 0)
346 				crtcext1 = 0x10;
347 			else if(cistrcmp(cp, "suspend") == 0)
348 				crtcext1 = 0x20;
349 			else if(cistrcmp(cp, "off") == 0)
350 				crtcext1 = 0x30;
351 		}
352 	}
353 
354 	*(mga + 0x1fc4) = 1;
355 	seq1 |= *(mga + 0x1fc5) & ~0x20;
356 	*(mga + 0x1fc5) = seq1;
357 
358 	*(mga + 0x1fde) = 1;
359 	crtcext1 |= *(mga + 0x1fdf) & ~0x30;
360 	*(mga + 0x1fdf) = crtcext1;
361 }
362 
363 static void
mgawrite32(uchar * mga,ulong reg,ulong val)364 mgawrite32(uchar *mga, ulong reg, ulong val)
365 {
366 	*((ulong*)(&mga[reg])) = val;
367 }
368 
369 static ulong
mgaread32(uchar * mga,ulong reg)370 mgaread32(uchar *mga, ulong reg)
371 {
372 	return *((ulong*)(&mga[reg]));
373 }
374 
375 static void
mga_fifo(uchar * mga,uchar n)376 mga_fifo(uchar *mga, uchar n)
377 {
378 	ulong t;
379 
380 #define Timeout 100
381 	for (t = 0; t < Timeout; t++)
382 		if ((mgaread32(mga, FIFOSTATUS) & 0xff) >= n)
383 			break;
384 	if (t >= Timeout)
385 		print("mga4xx: fifo timeout");
386 }
387 
388 static int
mga4xxfill(VGAscr * scr,Rectangle r,ulong color)389 mga4xxfill(VGAscr *scr, Rectangle r, ulong color)
390 {
391 	uchar *mga;
392 
393 	if(scr->mmio == 0)
394 		return 0;
395 	mga = (uchar*)scr->mmio;
396 
397 	mga_fifo(mga, 7);
398 	mgawrite32(mga, DWGCTL, 0);
399 	mgawrite32(mga, FCOL, color);
400 	mgawrite32(mga, FXLEFT, r.min.x);
401 	mgawrite32(mga, FXRIGHT, r.max.x);
402 	mgawrite32(mga, YDST, r.min.y);
403 	mgawrite32(mga, YLEN, Dy(r));
404 	mgawrite32(mga, DWGCTL + GO, FILL_OPERAND);
405 
406 	while(mgaread32(mga, STATUS) & 0x00010000)
407 		;
408 
409 	return 1;
410 }
411 
412 static int
mga4xxscroll(VGAscr * scr,Rectangle dr,Rectangle sr)413 mga4xxscroll(VGAscr *scr, Rectangle dr, Rectangle sr)
414 {
415 	uchar * mga;
416 	int pitch;
417  	int width, height;
418 	ulong start, end, sgn;
419 	Point sp, dp;
420 
421 	if(scr->mmio == 0)
422 		return 0;
423 	mga = (uchar*)scr->mmio;
424 
425 	assert(Dx(sr) == Dx(dr) && Dy(sr) == Dy(dr));
426 
427 	sp = sr.min;
428 	dp = dr.min;
429 	if(eqpt(sp, dp))
430 		return 1;
431 
432 	pitch = Dx(scr->gscreen->r);
433 	width = Dx(sr);
434 	height = Dy(sr);
435 	sgn = 0;
436 
437 	if(dp.y > sp.y && dp.y < sp.y + height){
438 		sp.y += height - 1;
439 		dp.y += height - 1;
440 		sgn |= SGN_UP;
441 	}
442 
443 	width--;
444 	start = end = sp.x + (sp.y * pitch);
445 
446 	if(dp.x > sp.x && dp.x < sp.x + width){
447 		start += width;
448 		sgn |= SGN_LEFT;
449 	}
450 	else
451 		end += width;
452 
453 	mga_fifo(mga, 8);
454 	mgawrite32(mga, DWGCTL, 0);
455 	mgawrite32(mga, SGN, sgn);
456 	mgawrite32(mga, AR5, sgn & SGN_UP ? -pitch : pitch);
457 	mgawrite32(mga, AR0, end);
458 	mgawrite32(mga, AR3, start);
459 	mgawrite32(mga, FXBNDRY, ((dp.x + width) << 16) | dp.x);
460 	mgawrite32(mga, YDSTLEN, (dp.y << 16) | height);
461 	mgawrite32(mga, DWGCTL + GO, DWG_BITBLT | DWG_SHIFTZERO | DWG_BFCOL | DWG_REPLACE);
462 
463 	while(mgaread32(mga, STATUS) & 0x00010000)
464 		;
465 
466 	return 1;
467 }
468 
469 static void
mga4xxdrawinit(VGAscr * scr)470 mga4xxdrawinit(VGAscr *scr)
471 {
472 	uchar *mga;
473 
474 	if(scr->mmio == 0)
475 		return;
476 
477 	mga = (uchar*)scr->mmio;
478 
479 	mgawrite32(mga, SRCORG, 0);
480 	mgawrite32(mga, DSTORG, 0);
481 	mgawrite32(mga, YDSTORG, 0);
482 	mgawrite32(mga, ZORG, 0);
483 	mgawrite32(mga, PLNWRT, ~0);
484 	mgawrite32(mga, FCOL, 0xffff0000);
485 	mgawrite32(mga, CXBNDRY, 0xFFFF0000);
486 	mgawrite32(mga, YTOP, 0);
487 	mgawrite32(mga, YBOT, 0x01FFFFFF);
488 	mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1));
489 	switch(scr->gscreen->depth){
490 	case 8:
491 		mgawrite32(mga, MACCESS, 0);
492 		break;
493 	case 16:
494 		mgawrite32(mga, MACCESS, 1);
495 		break;
496 	case 24:
497 		mgawrite32(mga, MACCESS, 3);
498 		break;
499 	case 32:
500 		mgawrite32(mga, MACCESS, 2);
501 		break;
502 	default:
503 		return;		/* depth not supported ! */
504 	}
505 	scr->fill = mga4xxfill;
506 	scr->scroll = mga4xxscroll;
507 	scr->blank = mga4xxblank;
508 }
509 
510 VGAdev vgamga4xxdev = {
511 	"mga4xx",
512 	mga4xxenable,		/* enable */
513 	0,					/* disable */
514 	0,					/* page */
515 	0,					/* linear */
516 	mga4xxdrawinit,
517 };
518 
519 VGAcur vgamga4xxcur = {
520 	"mga4xxhwgc",
521 	dac4xxenable,
522 	dac4xxdisable,
523 	dac4xxload,
524 	dac4xxmove,
525 };
526