xref: /plan9/sys/src/9/pc/vgat2r4.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
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 /*
16  * #9 Ticket to Ride IV.
17  */
18 enum {
19 	IndexLo		= 0x10/4,
20 	IndexHi		= 0x14/4,
21 	Data		= 0x18/4,
22 	IndexCtl	= 0x1C/4,
23 
24 	Zoom		= 0x54/4,
25 };
26 
27 enum {						/* index registers */
28 	CursorSyncCtl	= 0x03,
29 	  HsyncHi = 0x01,
30 	  HsyncLo = 0x02,
31 	  VsyncHi = 0x04,
32 	  VsyncLo = 0x08,
33 
34 	CursorCtl	= 0x30,
35 	CursorXLo	= 0x31,
36 	CursorXHi	= 0x32,
37 	CursorYLo	= 0x33,
38 	CursorYHi	= 0x34,
39 	CursorHotX	= 0x35,
40 	CursorHotY	= 0x36,
41 
42 	CursorR1	= 0x40,
43 	CursorG1	= 0x41,
44 	CursorB1	= 0x42,
45 	CursorR2	= 0x43,
46 	CursorG2	= 0x44,
47 	CursorB2	= 0x45,
48 	CursorR3	= 0x46,
49 	CursorG3	= 0x47,
50 	CursorB3	= 0x48,
51 
52 	CursorArray	= 0x100,
53 
54 	CursorMode32x32	= 0x23,
55 	CursorMode64x64	= 0x27,
56 	CursorMode	= CursorMode32x32,
57 };
58 
59 static void
t2r4enable(VGAscr * scr)60 t2r4enable(VGAscr* scr)
61 {
62 	Pcidev *p;
63 	void *mmio;
64 
65 	if(scr->mmio)
66 		return;
67 	if(p = pcimatch(nil, 0x105D, 0)){
68 		switch(p->did){
69 		case 0x5348:
70 			break;
71 		default:
72 			return;
73 		}
74 	}
75 	else
76 		return;
77 	scr->pci = p;
78 
79 	mmio = vmap(p->mem[4].bar & ~0x0F, p->mem[4].size);
80 	if(mmio == nil)
81 		return;
82 	addvgaseg("t2r4mmio", p->mem[4].bar & ~0x0F, p->mem[4].size);
83 
84 	scr->mmio = mmio;
85 	vgalinearpci(scr);
86 	if(scr->paddr)
87 		addvgaseg("t2r4screen", scr->paddr, scr->apsize);
88 }
89 
90 static uchar
t2r4xi(VGAscr * scr,int index)91 t2r4xi(VGAscr* scr, int index)
92 {
93 	ulong *mmio;
94 
95 	mmio = scr->mmio;
96 	mmio[IndexLo] = index & 0xFF;
97 	mmio[IndexHi] = (index>>8) & 0xFF;
98 
99 	return mmio[Data];
100 }
101 
102 static void
t2r4xo(VGAscr * scr,int index,uchar data)103 t2r4xo(VGAscr* scr, int index, uchar data)
104 {
105 	ulong *mmio;
106 
107 	mmio = scr->mmio;
108 	mmio[IndexLo] = index & 0xFF;
109 	mmio[IndexHi] = (index>>8) & 0xFF;
110 
111 	mmio[Data] = data;
112 }
113 
114 static void
t2r4curdisable(VGAscr * scr)115 t2r4curdisable(VGAscr* scr)
116 {
117 	if(scr->mmio == 0)
118 		return;
119 	t2r4xo(scr, CursorCtl, 0x00);
120 }
121 
122 static void
t2r4curload(VGAscr * scr,Cursor * curs)123 t2r4curload(VGAscr* scr, Cursor* curs)
124 {
125 	uchar *data;
126 	int size, x, y, zoom;
127 	ulong clr, *mmio, pixels, set;
128 
129 	mmio = scr->mmio;
130 	if(mmio == 0)
131 		return;
132 
133 	/*
134 	 * Make sure cursor is off by initialising the cursor
135 	 * control to defaults.
136 	 */
137 	t2r4xo(scr, CursorCtl, 0x00);
138 
139 	/*
140 	 * Set auto-increment mode for index-register addressing
141 	 * and initialise the cursor array index.
142 	 */
143 	mmio[IndexCtl] = 0x01;
144 	mmio[IndexLo] = CursorArray & 0xFF;
145 	mmio[IndexHi] = (CursorArray>>8) & 0xFF;
146 
147 	/*
148 	 * Initialise the cursor RAM array. There are 2 planes,
149 	 * p0 and p1. Data is written 4 pixels per byte, with p1 the
150 	 * MS bit of each pixel.
151 	 * The cursor is set in X-Windows mode which gives the following
152 	 * truth table:
153 	 *	p1 p0	colour
154 	 *	 0  0	underlying pixel colour
155 	 *	 0  1	underlying pixel colour
156 	 *	 1  0	cursor colour 1
157 	 *	 1  1	cursor colour 2
158 	 * Put the cursor into the top-left of the array.
159 	 *
160 	 * Although this looks a lot like the IBM RGB524 cursor, the
161 	 * scanlines appear to be twice as long as they should be and
162 	 * some of the other features are missing.
163 	 */
164 	if(mmio[Zoom] & 0x0F)
165 		zoom = 32;
166 	else
167 		zoom = 16;
168 	data = (uchar*)&mmio[Data];
169 	for(y = 0; y < zoom; y++){
170 		clr = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
171 		set = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
172 		pixels = 0;
173 		for(x = 0; x < 16; x++){
174 			if(set & (1<<x))
175 				pixels |= 0x03<<(x*2);
176 			else if(clr & (1<<x))
177 				pixels |= 0x02<<(x*2);
178 		}
179 
180 		*data = pixels>>24;
181 		*data = pixels>>16;
182 		*data = pixels>>8;
183 		*data = pixels;
184 
185 		*data = 0x00;
186 		*data = 0x00;
187 		*data = 0x00;
188 		*data = 0x00;
189 
190 		if(CursorMode == CursorMode32x32 && zoom == 16)
191 			continue;
192 		*data = pixels>>24;
193 		*data = pixels>>16;
194 		*data = pixels>>8;
195 		*data = pixels;
196 
197 		*data = 0x00;
198 		*data = 0x00;
199 		*data = 0x00;
200 		*data = 0x00;
201 	}
202 	if(CursorMode == CursorMode32x32)
203 		size = 32;
204 	else
205 		size = 64;
206 	while(y < size){
207 		for(x = 0; x < size/8; x++){
208 			*data = 0x00;
209 			*data = 0x00;
210 		}
211 		y++;
212 	}
213 	mmio[IndexCtl] = 0x00;
214 
215 	/*
216 	 * Initialise the hotpoint and enable the cursor.
217 	 */
218 	t2r4xo(scr, CursorHotX, -curs->offset.x);
219 	zoom = (scr->mmio[Zoom] & 0x0F)+1;
220 	t2r4xo(scr, CursorHotY, -curs->offset.y*zoom);
221 
222 	t2r4xo(scr, CursorCtl, CursorMode);
223 }
224 
225 static int
t2r4curmove(VGAscr * scr,Point p)226 t2r4curmove(VGAscr* scr, Point p)
227 {
228 	int y, zoom;
229 
230 	if(scr->mmio == 0)
231 		return 1;
232 
233 	t2r4xo(scr, CursorXLo, p.x & 0xFF);
234 	t2r4xo(scr, CursorXHi, (p.x>>8) & 0x0F);
235 
236 	zoom = (scr->mmio[Zoom] & 0x0F)+1;
237 	y = p.y*zoom;
238 	t2r4xo(scr, CursorYLo, y & 0xFF);
239 	t2r4xo(scr, CursorYHi, (y>>8) & 0x0F);
240 
241 	return 0;
242 }
243 
244 static void
t2r4curenable(VGAscr * scr)245 t2r4curenable(VGAscr* scr)
246 {
247 	t2r4enable(scr);
248 	if(scr->mmio == 0)
249 		return;
250 
251 	/*
252 	 * Make sure cursor is off by initialising the cursor
253 	 * control to defaults.
254 	 */
255 	t2r4xo(scr, CursorCtl, 0x00);
256 
257 	/*
258 	 * Cursor colour 1 (white),
259 	 * cursor colour 2 (black).
260 	 */
261 	t2r4xo(scr, CursorR1, Pwhite);
262 	t2r4xo(scr, CursorG1, Pwhite);
263 	t2r4xo(scr, CursorB1, Pwhite);
264 
265 	t2r4xo(scr, CursorR2, Pblack);
266 	t2r4xo(scr, CursorG2, Pblack);
267 	t2r4xo(scr, CursorB2, Pblack);
268 
269 	/*
270 	 * Load, locate and enable the cursor, 64x64, mode 2.
271 	 */
272 	t2r4curload(scr, &arrow);
273 	t2r4curmove(scr, ZP);
274 	t2r4xo(scr, CursorCtl, CursorMode);
275 }
276 
277 enum {
278 	Flow		= 0x08/4,
279 	Busy		= 0x0C/4,
280 	BufCtl		= 0x20/4,
281 	DeSorg		= 0x28/4,
282 	DeDorg		= 0x2C/4,
283 	DeSptch		= 0x40/4,
284 	DeDptch		= 0x44/4,
285 	CmdOpc		= 0x50/4,
286 	CmdRop		= 0x54/4,
287 	CmdStyle 	= 0x58/4,
288 	CmdPatrn 	= 0x5C/4,
289 	CmdClp		= 0x60/4,
290 	CmdPf		= 0x64/4,
291 	Fore		= 0x68/4,
292 	Back		= 0x6C/4,
293 	Mask		= 0x70/4,
294 	DeKey		= 0x74/4,
295 	Lpat		= 0x78/4,
296 	Pctrl 		= 0x7C/4,
297 	Clptl		= 0x80/4,
298 	Clpbr		= 0x84/4,
299 	XY0		= 0x88/4,
300 	XY1		= 0x8C/4,
301 	XY2		= 0x90/4,
302 	XY3		= 0x94/4,
303 	XY4		= 0x98/4,
304 	Alpha 		= 0x128/4,
305 	ACtl 		= 0x16C/4,
306 
307 	RBaseD 		= 0x4000/4,
308 };
309 
310 /* wait until pipeline ready for new command */
311 static void
waitforfifo(VGAscr * scr)312 waitforfifo(VGAscr *scr)
313 {
314 	int x;
315 	ulong *d;
316 	x = 0;
317 
318 	d = scr->mmio + RBaseD;
319 	while((d[Busy]&1) && x++ < 1000000)
320 		;
321 	if(x >= 1000000)	/* shouldn't happen */
322 		iprint("busy %8lux\n", d[Busy]);
323 }
324 
325 /* wait until command has finished executing */
326 static void
waitforcmd(VGAscr * scr)327 waitforcmd(VGAscr *scr)
328 {
329 	int x;
330 	ulong *d;
331 	x = 0;
332 
333 	d = scr->mmio + RBaseD;
334 	while((d[Flow]&0x1B) && x++ < 1000000)
335 		;
336 	if(x >= 1000000)	/* shouldn't happen */
337 		iprint("flow %8lux\n", d[Flow]);
338 }
339 
340 /* wait until memory controller not busy (i.e. wait for writes to flush) */
341 static void
waitformem(VGAscr * scr)342 waitformem(VGAscr *scr)
343 {
344 	int x;
345 	ulong *d;
346 	x = 0;
347 
348 	d = scr->mmio + RBaseD;
349 	while((d[Flow]&2)&& x++ < 1000000)
350 		;
351 	if(x >= 1000000)	/* shouldn't happen */
352 		iprint("mem %8lux\n", d[Busy]);
353 }
354 
355 static int
t2r4hwscroll(VGAscr * scr,Rectangle r,Rectangle sr)356 t2r4hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
357 {
358 	int ctl;
359 	Point dp, sp;
360 	ulong *d;
361 	int depth;
362 
363 	if(r.min.y == sr.min.y){	/* a purely horizontal scroll */
364 		depth = scr->gscreen->depth;
365 		switch(depth){
366 		case 32:
367 			/*
368 			 * Using the SGI flat panels with the Ticket-to-Ride IV, horizontal
369 			 * 32-bit scrolls don't work perfectly on rectangles of width <= 24.
370 			 * we bail on a bigger bound for padding.
371 			 */
372 			if(Dx(r) < 32)
373 				return 0;
374 			break;
375 		case 16:
376 			/*
377 			 * Using the SGI flat panels with the Ticket-to-Ride IV, horizontal
378 			 * 16-bit scrolls don't work perfectly on rectangles of width <= 96.
379 			 * we bail on a bigger bound for padding.
380 			 */
381 			if(Dx(r) < 104)
382 				return 0;
383 			break;
384 		}
385 	}
386 	waitformem(scr);
387 	waitforfifo(scr);
388 	d = scr->mmio + RBaseD;
389 	ctl = 0;
390 	if(r.min.x <= sr.min.x){
391 		dp.x = r.min.x;
392 		sp.x = sr.min.x;
393 	}else{
394 		ctl |= 2;
395 		dp.x = r.max.x-1;
396 		sp.x = sr.max.x-1;
397 	}
398 
399 	if(r.min.y < sr.min.y){
400 		dp.y = r.min.y;
401 		sp.y = sr.min.y;
402 	}else{
403 		ctl |= 1;
404 		dp.y = r.max.y-1;
405 		sp.y = sr.max.y-1;
406 	}
407 
408 	d[CmdOpc] = 0x1;	/* bitblt */
409 	d[CmdRop] = 0xC;	/* copy source */
410 	d[CmdStyle] = 0;
411 	d[CmdPatrn] = 0;
412 	d[Fore] = 0;
413 	d[Back] = 0;
414 
415 	/* writing XY1 executes cmd */
416 	d[XY3] = ctl;
417 	d[XY0] = (sp.x<<16)|sp.y;
418 	d[XY2] = (Dx(r)<<16)|Dy(r);
419 	d[XY4] = 0;
420 	d[XY1] = (dp.x<<16)|dp.y;
421 	waitforcmd(scr);
422 
423 	return 1;
424 }
425 
426 static int
t2r4hwfill(VGAscr * scr,Rectangle r,ulong sval)427 t2r4hwfill(VGAscr *scr, Rectangle r, ulong sval)
428 {
429 	ulong *d;
430 
431 	d = scr->mmio + RBaseD;
432 
433 	waitformem(scr);
434 	waitforfifo(scr);
435 	d[CmdOpc] = 0x1;	/* bitblt */
436 	d[CmdRop] = 0xC;	/* copy source */
437 	d[CmdStyle] = 1;	/* use source from Fore register */
438 	d[CmdPatrn] = 0;	/* no stipple */
439 	d[Fore] = sval;
440 	d[Back] = sval;
441 
442 	/* writing XY1 executes cmd */
443 	d[XY3] = 0;
444 	d[XY0] = (r.min.x<<16)|r.min.y;
445 	d[XY2] = (Dx(r)<<16)|Dy(r);
446 	d[XY4] = 0;
447 	d[XY1] = (r.min.x<<16)|r.min.y;
448 	waitforcmd(scr);
449 
450 	return 1;
451 }
452 
453 static void
t2r4blank(VGAscr * scr,int blank)454 t2r4blank(VGAscr *scr, int blank)
455 {
456 	uchar x;
457 
458 	x = t2r4xi(scr, CursorSyncCtl);
459 	x &= ~0x0F;
460 	if(blank)
461 		x |= HsyncLo | VsyncLo;
462 	t2r4xo(scr, CursorSyncCtl, x);
463 }
464 
465 static void
t2r4drawinit(VGAscr * scr)466 t2r4drawinit(VGAscr *scr)
467 {
468 	ulong pitch;
469 	int depth;
470 	int fmt;
471 	ulong *d;
472 
473 	pitch = Dx(scr->gscreen->r);
474 	depth = scr->gscreen->depth;
475 
476 	switch(scr->gscreen->chan){
477 	case RGB16:
478 		fmt = 3;
479 		break;
480 	case XRGB32:
481 		fmt = 2;
482 		break;
483 	case RGB15:
484 		fmt = 1;
485 		break;
486 	default:
487 		scr->fill = nil;
488 		scr->scroll = nil;
489 		return;
490 	}
491 
492 	d = scr->mmio + RBaseD;
493 
494 	d[BufCtl] = fmt<<24;
495 	d[DeSorg] = 0;
496 	d[DeDorg] = 0;
497 	d[DeSptch] = (pitch*depth)/8;
498 	d[DeDptch] = (pitch*depth)/8;
499 	d[CmdClp] = 0;	/* 2 = inside rectangle */
500 	d[Mask] = ~0;
501 	d[DeKey] = 0;
502 	d[Clptl] = 0;
503 	d[Clpbr] = 0xFFF0FFF0;
504 	d[Alpha] = 0;
505 	d[ACtl] = 0;
506 
507 	scr->fill = t2r4hwfill;
508 	scr->scroll = t2r4hwscroll;
509 	scr->blank = t2r4blank;
510 	hwblank = 1;
511 }
512 
513 VGAdev vgat2r4dev = {
514 	"t2r4",
515 
516 	t2r4enable,
517 	nil,
518 	nil,
519 	nil,
520 	t2r4drawinit,
521 };
522 
523 VGAcur vgat2r4cur = {
524 	"t2r4hwgc",
525 
526 	t2r4curenable,
527 	t2r4curdisable,
528 	t2r4curload,
529 	t2r4curmove,
530 };
531 
532