xref: /plan9/sys/src/9/pc/vganeomagic.c (revision 5b7f163ef926031138d13ab99fb6fc8ce599f427)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 
9 #define	Image	IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14 
15 typedef struct CursorNM CursorNM;
16 struct CursorNM {
17 	int	enable;
18 	int	x;
19 	int	y;
20 	int	colour1;
21 	int	colour2;
22 	int	addr;
23 };
24 
25 static void
neomagicenable(VGAscr * scr)26 neomagicenable(VGAscr* scr)
27 {
28 	Pcidev *p;
29 	int curoff, vmsize;
30 	ulong ioaddr;
31 	ulong iosize;
32 
33 	/*
34 	 * scr->mmio holds the virtual address of the cursor registers
35 	 * in the MMIO space. This may need to change for older chips
36 	 * which have the MMIO space offset in the framebuffer region.
37 	 *
38 	 * scr->io holds the offset into mmio of the CursorNM struct.
39 	 */
40 	if(scr->mmio)
41 		return;
42 	if(p = pcimatch(nil, 0x10C8, 0)){
43 		switch(p->did){
44 		case 0x0003:		/* MagicGraph 128ZV */
45 			curoff = 0x100;
46 			vmsize = 1152*1024;
47 			ioaddr = (p->mem[0].bar & ~0x0F) + 0x200000;
48 			iosize = 0x200000;
49 			break;
50 		case 0x0083:		/* MagicGraph 128ZV+ */
51 			curoff = 0x100;
52 			vmsize = 1152*1024;
53 			ioaddr = p->mem[1].bar & ~0x0F;
54 			iosize = p->mem[1].size;
55 			break;
56 		case 0x0004:		/* MagicGraph 128XD */
57 			curoff = 0x100;
58 			vmsize = 2048*1024;
59 			ioaddr = p->mem[1].bar & ~0x0F;
60 			iosize = p->mem[1].size;
61 			break;
62 		case 0x0005:		/* MagicMedia 256AV */
63 			curoff = 0x1000;
64 			vmsize = 2560*1024;
65 			ioaddr = p->mem[1].bar & ~0x0F;
66 			iosize = p->mem[1].size;
67 			break;
68 		case 0x0006:		/* MagicMedia 256ZX */
69 			curoff = 0x1000;
70 			vmsize = 4096*1024;
71 			ioaddr = p->mem[1].bar & ~0x0F;
72 			iosize = p->mem[1].size;
73 			break;
74 		case 0x0016:		/* MagicMedia 256XL+ */
75 			curoff = 0x1000;
76 			/* Vaio VESA BIOS says 6080, but then hwgc doesn't work */
77 			vmsize = 4096*1024;
78 			ioaddr = p->mem[1].bar & ~0x0F;
79 			iosize = p->mem[1].size;
80 			break;
81 		default:
82 			return;
83 		}
84 	}
85 	else
86 		return;
87 	scr->pci = p;
88 
89 	scr->mmio = vmap(ioaddr, iosize);
90 	if(scr->mmio == nil)
91 		return;
92 	addvgaseg("neomagicmmio", ioaddr, iosize);
93 
94 	/*
95 	 * Find a place for the cursor data in display memory.
96 	 * 2 cursor images might be needed, 1KB each so use the
97 	 * last 2KB of the framebuffer.
98 	 */
99 	scr->storage = vmsize-2*1024;
100 	scr->io = curoff;
101 	vgalinearpci(scr);
102 	if(scr->paddr)
103 		addvgaseg("neomagicscreen", scr->paddr, scr->apsize);
104 }
105 
106 static void
neomagiccurdisable(VGAscr * scr)107 neomagiccurdisable(VGAscr* scr)
108 {
109 	CursorNM *cursornm;
110 
111 	if(scr->mmio == 0)
112 		return;
113 	cursornm = (void*)((char*)scr->mmio + scr->io);
114 	cursornm->enable = 0;
115 }
116 
117 static void
neomagicinitcursor(VGAscr * scr,int xo,int yo,int index)118 neomagicinitcursor(VGAscr* scr, int xo, int yo, int index)
119 {
120 	uchar *p;
121 	uint p0, p1;
122 	int x, y;
123 
124 	p = (uchar*)scr->vaddr;
125 	p += scr->storage + index*1024;
126 
127 	for(y = yo; y < 16; y++){
128 		p0 = scr->set[2*y];
129 		p1 = scr->set[2*y+1];
130 		if(xo){
131 			p0 = (p0<<xo)|(p1>>(8-xo));
132 			p1 <<= xo;
133 		}
134 		*p++ = p0;
135 		*p++ = p1;
136 
137 		for(x = 16; x < 64; x += 8)
138 			*p++ = 0x00;
139 
140 		p0 = scr->clr[2*y]|scr->set[2*y];
141 		p1 = scr->clr[2*y+1]|scr->set[2*y+1];
142 		if(xo){
143 			p0 = (p0<<xo)|(p1>>(8-xo));
144 			p1 <<= xo;
145 		}
146 		*p++ = p0;
147 		*p++ = p1;
148 
149 		for(x = 16; x < 64; x += 8)
150 			*p++ = 0x00;
151 	}
152 	while(y < 64+yo){
153 		for(x = 0; x < 64; x += 8){
154 			*p++ = 0x00;
155 			*p++ = 0x00;
156 		}
157 		y++;
158 	}
159 }
160 
161 static void
neomagiccurload(VGAscr * scr,Cursor * curs)162 neomagiccurload(VGAscr* scr, Cursor* curs)
163 {
164 	CursorNM *cursornm;
165 
166 	if(scr->mmio == 0)
167 		return;
168 	cursornm = (void*)((char*)scr->mmio + scr->io);
169 
170 	cursornm->enable = 0;
171 	memmove(&scr->Cursor, curs, sizeof(Cursor));
172 	neomagicinitcursor(scr, 0, 0, 0);
173 	cursornm->enable = 1;
174 }
175 
176 static int
neomagiccurmove(VGAscr * scr,Point p)177 neomagiccurmove(VGAscr* scr, Point p)
178 {
179 	CursorNM *cursornm;
180 	int addr, index, x, xo, y, yo;
181 
182 	if(scr->mmio == 0)
183 		return 1;
184 	cursornm = (void*)((char*)scr->mmio + scr->io);
185 
186 	index = 0;
187 	if((x = p.x+scr->offset.x) < 0){
188 		xo = -x;
189 		x = 0;
190 	}
191 	else
192 		xo = 0;
193 	if((y = p.y+scr->offset.y) < 0){
194 		yo = -y;
195 		y = 0;
196 	}
197 	else
198 		yo = 0;
199 
200 	if(xo || yo){
201 		index = 1;
202 		neomagicinitcursor(scr, xo, yo, index);
203 	}
204 	addr = ((scr->storage+(1024*index))>>10) & 0xFFF;
205 	addr = ((addr & 0x00F)<<8)|((addr>>4) & 0xFF);
206 	if(cursornm->addr != addr)
207 		cursornm->addr = addr;
208 
209 	cursornm->x = x;
210 	cursornm->y = y;
211 
212 	return 0;
213 }
214 
215 static void
neomagiccurenable(VGAscr * scr)216 neomagiccurenable(VGAscr* scr)
217 {
218 	CursorNM *cursornm;
219 
220 	neomagicenable(scr);
221 	if(scr->mmio == 0)
222 		return;
223 	cursornm = (void*)((char*)scr->mmio + scr->io);
224 	cursornm->enable = 0;
225 
226 	/*
227 	 * Cursor colours.
228 	 */
229 	cursornm->colour1 = (Pblack<<16)|(Pblack<<8)|Pblack;
230 	cursornm->colour2 = (Pwhite<<16)|(Pwhite<<8)|Pwhite;
231 
232 	/*
233 	 * Load, locate and enable the 64x64 cursor.
234 	 */
235 	neomagiccurload(scr, &arrow);
236 	neomagiccurmove(scr, ZP);
237 	cursornm->enable = 1;
238 }
239 
240 static int neomagicbltflags;
241 
242 /* registers */
243 enum {
244 	BltStat = 0,
245 	BltCntl = 1,
246 	XPColor = 2,
247 	FGColor = 3,
248 	BGColor = 4,
249 	Pitch = 5,
250 	ClipLT = 6,
251 	ClipRB = 7,
252 	SrcBitOff = 8,
253 	SrcStartOff = 9,
254 
255 	DstStartOff = 11,
256 	XYExt = 12,
257 
258 	PageCntl = 20,
259 	PageBase,
260 	PostBase,
261 	PostPtr,
262 	DataPtr,
263 };
264 
265 /* flags */
266 enum {
267 	NEO_BS0_BLT_BUSY =	0x00000001,
268 	NEO_BS0_FIFO_AVAIL =	0x00000002,
269 	NEO_BS0_FIFO_PEND =	0x00000004,
270 
271 	NEO_BC0_DST_Y_DEC =	0x00000001,
272 	NEO_BC0_X_DEC =		0x00000002,
273 	NEO_BC0_SRC_TRANS =	0x00000004,
274 	NEO_BC0_SRC_IS_FG =	0x00000008,
275 	NEO_BC0_SRC_Y_DEC =	0x00000010,
276 	NEO_BC0_FILL_PAT =	0x00000020,
277 	NEO_BC0_SRC_MONO =	0x00000040,
278 	NEO_BC0_SYS_TO_VID =	0x00000080,
279 
280 	NEO_BC1_DEPTH8 =	0x00000100,
281 	NEO_BC1_DEPTH16 =	0x00000200,
282 	NEO_BC1_DEPTH24 =	0x00000300,
283 	NEO_BC1_X_320 =		0x00000400,
284 	NEO_BC1_X_640 =		0x00000800,
285 	NEO_BC1_X_800 =		0x00000c00,
286 	NEO_BC1_X_1024 =	0x00001000,
287 	NEO_BC1_X_1152 =	0x00001400,
288 	NEO_BC1_X_1280 =	0x00001800,
289 	NEO_BC1_X_1600 =	0x00001c00,
290 	NEO_BC1_DST_TRANS =	0x00002000,
291 	NEO_BC1_MSTR_BLT =	0x00004000,
292 	NEO_BC1_FILTER_Z =	0x00008000,
293 
294 	NEO_BC2_WR_TR_DST =	0x00800000,
295 
296 	NEO_BC3_SRC_XY_ADDR =	0x01000000,
297 	NEO_BC3_DST_XY_ADDR =	0x02000000,
298 	NEO_BC3_CLIP_ON =	0x04000000,
299 	NEO_BC3_FIFO_EN =	0x08000000,
300 	NEO_BC3_BLT_ON_ADDR =	0x10000000,
301 	NEO_BC3_SKIP_MAPPING =	0x80000000,
302 
303 	NEO_MODE1_DEPTH8 =	0x0100,
304 	NEO_MODE1_DEPTH16 =	0x0200,
305 	NEO_MODE1_DEPTH24 =	0x0300,
306 	NEO_MODE1_X_320 =	0x0400,
307 	NEO_MODE1_X_640 =	0x0800,
308 	NEO_MODE1_X_800 =	0x0c00,
309 	NEO_MODE1_X_1024 =	0x1000,
310 	NEO_MODE1_X_1152 =	0x1400,
311 	NEO_MODE1_X_1280 =	0x1800,
312 	NEO_MODE1_X_1600 =	0x1c00,
313 	NEO_MODE1_BLT_ON_ADDR =	0x2000,
314 };
315 
316 /* Raster Operations */
317 enum {
318 	GXclear =		0x000000,	/* 0x0000 */
319 	GXand =			0x080000,	/* 0x1000 */
320 	GXandReverse =		0x040000,	/* 0x0100 */
321 	GXcopy =		0x0c0000,	/* 0x1100 */
322 	GXandInvert =		0x020000,	/* 0x0010 */
323 	GXnoop =		0x0a0000,	/* 0x1010 */
324 	GXxor =			0x060000,	/* 0x0110 */
325 	GXor =			0x0e0000,	/* 0x1110 */
326 	GXnor =			0x010000,	/* 0x0001 */
327 	GXequiv =		0x090000,	/* 0x1001 */
328 	GXinvert =		0x050000,	/* 0x0101 */
329 	GXorReverse =		0x0d0000,	/* 0x1101 */
330 	GXcopyInvert =		0x030000,	/* 0x0011 */
331 	GXorInverted =		0x0b0000,	/* 0x1011 */
332 	GXnand =		0x070000,	/* 0x0111 */
333 	GXset =			0x0f0000,	/* 0x1111 */
334 };
335 
336 static void
waitforidle(VGAscr * scr)337 waitforidle(VGAscr *scr)
338 {
339 	ulong *mmio;
340 	long x;
341 
342 	mmio = scr->mmio;
343 	x = 0;
344 	while((mmio[BltStat] & NEO_BS0_BLT_BUSY) && x++ < 1000000)
345 		;
346 	//if(x >= 1000000)
347 	//	iprint("idle stat %lud scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat], scr->mmio, scr, getcallerpc(&scr));
348 }
349 
350 static void
waitforfifo(VGAscr * scr,int entries)351 waitforfifo(VGAscr *scr, int entries)
352 {
353 	ulong *mmio;
354 	long x;
355 
356 	mmio = scr->mmio;
357 	x = 0;
358 	while(((mmio[BltStat]>>8) < entries) && x++ < 1000000)
359 		;
360 	//if(x >= 1000000)
361 	//	iprint("fifo stat %d scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat]>>8, scr->mmio, scr, getcallerpc(&scr));
362 	/* DirectFB says the above doesn't work.  if so... */
363 	/* waitforidle(scr); */
364 }
365 
366 static int
neomagichwfill(VGAscr * scr,Rectangle r,ulong sval)367 neomagichwfill(VGAscr *scr, Rectangle r, ulong sval)
368 {
369 	ulong *mmio;
370 
371 	mmio = scr->mmio;
372 
373 	waitforfifo(scr, 1);
374 	mmio[FGColor] = sval;
375 	waitforfifo(scr, 3);
376 	mmio[BltCntl] = neomagicbltflags
377 		| NEO_BC3_FIFO_EN
378 		| NEO_BC0_SRC_IS_FG
379 		| NEO_BC3_SKIP_MAPPING
380 		| GXcopy;
381 	mmio[DstStartOff] = scr->paddr
382 		+ r.min.y*scr->gscreen->width*BY2WD
383 		+ r.min.x*scr->gscreen->depth/BI2BY;
384 	mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
385 	waitforidle(scr);
386 	return 1;
387 }
388 
389 static int
neomagichwscroll(VGAscr * scr,Rectangle r,Rectangle sr)390 neomagichwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
391 {
392 	ulong *mmio;
393 	int pitch, pixel;
394 
395 	mmio = scr->mmio;
396 
397 	pitch = scr->gscreen->width*BY2WD;
398 	pixel = scr->gscreen->depth/BI2BY;
399 
400 	waitforfifo(scr, 4);
401 	if (r.min.y < sr.min.y || (r.min.y == sr.min.y && r.min.x < sr.min.x)) {
402 		/* start from upper-left */
403 		mmio[BltCntl] = neomagicbltflags
404 			| NEO_BC3_FIFO_EN
405 			| NEO_BC3_SKIP_MAPPING
406 			| GXcopy;
407 		mmio[SrcStartOff] = scr->paddr
408 			+ sr.min.y*pitch + sr.min.x*pixel;
409 		mmio[DstStartOff] = scr->paddr
410 			+ r.min.y*pitch + r.min.x*pixel;
411 	} else {
412 		/* start from lower-right */
413 		mmio[BltCntl] = neomagicbltflags
414 			| NEO_BC0_X_DEC
415 			| NEO_BC0_DST_Y_DEC
416 			| NEO_BC0_SRC_Y_DEC
417 			| NEO_BC3_FIFO_EN
418 			| NEO_BC3_SKIP_MAPPING
419 			| GXcopy;
420 		mmio[SrcStartOff] = scr->paddr
421 			+ (sr.max.y-1)*pitch + (sr.max.x-1)*pixel;
422 		mmio[DstStartOff] = scr->paddr
423 			+ (r.max.y-1)*pitch + (r.max.x-1)*pixel;
424 	}
425 	mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
426 	waitforidle(scr);
427 	return 1;
428 }
429 
430 static void
neomagicdrawinit(VGAscr * scr)431 neomagicdrawinit(VGAscr *scr)
432 {
433 	ulong *mmio;
434 	uint bltmode, pitch;
435 
436 	mmio = scr->mmio;
437 
438 	pitch = scr->gscreen->width*BY2WD;
439 
440 	neomagicbltflags = bltmode = 0;
441 
442 	switch(scr->gscreen->depth) {
443 	case 8:
444 		bltmode |= NEO_MODE1_DEPTH8;
445 		neomagicbltflags |= NEO_BC1_DEPTH8;
446 		break;
447 	case 16:
448 		bltmode |= NEO_MODE1_DEPTH16;
449 		neomagicbltflags |= NEO_BC1_DEPTH16;
450 		break;
451 	case 24:	/* I can't get it to work, and XFree86 doesn't either. */
452 	default:	/* give up */
453 		return;
454 	}
455 
456 	switch(Dx(scr->gscreen->r)) {
457 	case 320:
458 		bltmode |= NEO_MODE1_X_320;
459 		neomagicbltflags |= NEO_BC1_X_320;
460 		break;
461 	case 640:
462 		bltmode |= NEO_MODE1_X_640;
463 		neomagicbltflags |= NEO_BC1_X_640;
464 		break;
465 	case 800:
466 		bltmode |= NEO_MODE1_X_800;
467 		neomagicbltflags |= NEO_BC1_X_800;
468 		break;
469 	case 1024:
470 		bltmode |= NEO_MODE1_X_1024;
471 		neomagicbltflags |= NEO_BC1_X_1024;
472 		break;
473 	case 1152:
474 		bltmode |= NEO_MODE1_X_1152;
475 		neomagicbltflags |= NEO_BC1_X_1152;
476 		break;
477 	case 1280:
478 		bltmode |= NEO_MODE1_X_1280;
479 		neomagicbltflags |= NEO_BC1_X_1280;
480 		break;
481 	case 1600:
482 		bltmode |= NEO_MODE1_X_1600;
483 		neomagicbltflags |= NEO_BC1_X_1600;
484 		break;
485 	default:
486 		/* don't worry about it */
487 		break;
488 	}
489 
490 	waitforidle(scr);
491 	mmio[BltStat] = bltmode << 16;
492 	mmio[Pitch] = (pitch << 16) | (pitch & 0xffff);
493 
494 	scr->fill = neomagichwfill;
495 	scr->scroll = neomagichwscroll;
496 }
497 
498 VGAdev vganeomagicdev = {
499 	"neomagic",
500 
501 	neomagicenable,
502 	nil,
503 	nil,
504 	nil,
505 	neomagicdrawinit,
506 };
507 
508 VGAcur vganeomagiccur = {
509 	"neomagichwgc",
510 
511 	neomagiccurenable,
512 	neomagiccurdisable,
513 	neomagiccurload,
514 	neomagiccurmove,
515 };
516 
517