xref: /plan9-contrib/sys/src/9/loongson/screen.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1 /*
2  *	radeon frame buffer
3  *	currently use all PMON defaults
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 
12 #define	Image	IMAGE
13 #include <draw.h>
14 #include <memdraw.h>
15 #include <cursor.h>
16 #include "screen.h"
17 
18 enum {
19 	Tabstop		= 4,
20 	Scroll		= 8,
21 	Wid			= 640,
22 	Ht			= 480,
23 	Depth		= 16,
24 };
25 
26 Cursor	arrow = {
27 	{ -1, -1 },
28 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
29 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
30 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
31 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
32 	},
33 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
34 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
35 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
36 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
37 	},
38 };
39 
40 Memimage *gscreen;
41 
42 static Memdata xgdata;
43 
44 static Memimage xgscreen =
45 {
46 	{ 0, 0, Wid, Ht },	/* r */
47 	{ 0, 0, Wid, Ht },	/* clipr */
48 	Depth,			/* depth */
49 	3,			/* nchan */
50 	RGB16,			/* chan */
51 	nil,			/* cmap */
52 	&xgdata,		/* data */
53 	0,			/* zero */
54 	0, 			/* width in words of a single scan line */
55 	0,			/* layer */
56 	0,			/* flags */
57 };
58 
59 static Memimage		*conscol;
60 static Memimage		*back;
61 static Memsubfont	*memdefont;
62 
63 static Lock screenlock;
64 
65 static Point		curpos;
66 static int			h, w;
67 static Rectangle	window;
68 
69 int screenwid;
70 int screenht;
71 int screendepth;
72 
73 /*
74  * Software cursor.
75  */
76 static int	swvisible;	/* is the cursor visible? */
77 static int	swenabled;	/* is the cursor supposed to be on the screen? */
78 static Memimage *swback;	/* screen under cursor */
79 static Memimage *swimg;		/* cursor image */
80 static Memimage *swmask;	/* cursor mask */
81 static Memimage *swimg1;
82 static Memimage *swmask1;
83 
84 static Point	swoffset;
85 static Rectangle swrect;	/* screen rectangle in swback */
86 static Point	swpt;		/* desired cursor location */
87 static Point	swvispt;	/* actual cursor location */
88 static int	swvers;		/* incremented each time cursor image changes */
89 static int	swvisvers;	/* the version on the screen */
90 
91 /*
92  * called with drawlock locked for us, most of the time.
93  * kernel prints at inopportune times might mean we don't
94  * hold the lock, but memimagedraw is now reentrant so
95  * that should be okay: worst case we get cursor droppings.
96  */
97 static void
swcursorhide(void)98 swcursorhide(void)
99 {
100 	if(swvisible == 0)
101 		return;
102 	if(swback == nil)
103 		return;
104 	swvisible = 0;
105 	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
106 	flushmemscreen(swrect);
107 }
108 
109 static void
swcursoravoid(Rectangle r)110 swcursoravoid(Rectangle r)
111 {
112 	if(swvisible && rectXrect(r, swrect))
113 		swcursorhide();
114 }
115 
116 static void
swcursordraw(void)117 swcursordraw(void)
118 {
119 	int dounlock;
120 
121 	if(swvisible)
122 		return;
123 	if(swenabled == 0)
124 		return;
125 	if(swback == nil || swimg1 == nil || swmask1 == nil)
126 		return;
127 	dounlock = canqlock(&drawlock);
128 	swvispt = swpt;
129 	swvisvers = swvers;
130 	swrect = rectaddpt(Rect(0,0,16,16), swvispt);
131 	memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
132 	memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
133 	flushmemscreen(swrect);
134 	swvisible = 1;
135 	if(dounlock)
136 		qunlock(&drawlock);
137 }
138 
139 int
cursoron(int dolock)140 cursoron(int dolock)
141 {
142 	int retry;
143 
144 	if (dolock)
145 		lock(&cursor);
146 	if (canqlock(&drawlock)) {
147 		retry = 0;
148 		swcursorhide();
149 		swcursordraw();
150 		qunlock(&drawlock);
151 	} else
152 		retry = 1;
153 	if (dolock)
154 		unlock(&cursor);
155 	return retry;
156 }
157 
158 void
cursoroff(int dolock)159 cursoroff(int dolock)
160 {
161 	if (dolock)
162 		lock(&cursor);
163 	swcursorhide();
164 	if (dolock)
165 		unlock(&cursor);
166 }
167 
168 static void
swload(Cursor * curs)169 swload(Cursor *curs)
170 {
171 	uchar *ip, *mp;
172 	int i, j, set, clr;
173 
174 	if(!swimg || !swmask || !swimg1 || !swmask1)
175 		return;
176 	/*
177 	 * Build cursor image and mask.
178 	 * Image is just the usual cursor image
179 	 * but mask is a transparent alpha mask.
180 	 *
181 	 * The 16x16x8 memimages do not have
182 	 * padding at the end of their scan lines.
183 	 */
184 	ip = byteaddr(swimg, ZP);
185 	mp = byteaddr(swmask, ZP);
186 	for(i=0; i<32; i++){
187 		set = curs->set[i];
188 		clr = curs->clr[i];
189 		for(j=0x80; j; j>>=1){
190 			*ip++ = set&j ? 0x00 : 0xFF;
191 			*mp++ = (clr|set)&j ? 0xFF : 0x00;
192 		}
193 	}
194 	swoffset = curs->offset;
195 	swvers++;
196 	memimagedraw(swimg1,  swimg1->r,  swimg,  ZP, memopaque, ZP, S);
197 	memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
198 }
199 
200 /* called from devmouse */
201 void
setcursor(Cursor * curs)202 setcursor(Cursor* curs)
203 {
204 	cursoroff(0);
205 	swload(curs);
206 	cursoron(0);
207 }
208 
209 static int
swmove(Point p)210 swmove(Point p)
211 {
212 	swpt = addpt(p, swoffset);
213 	return 0;
214 }
215 
216 static void
swcursorclock(void)217 swcursorclock(void)
218 {
219 	int x;
220 
221 	if(!swenabled)
222 		return;
223 	swmove(mousexy());
224 	if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
225 		return;
226 
227 	x = splhi();
228 	if(swenabled)
229 	if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
230 	if(canqlock(&drawlock)){
231 		swcursorhide();
232 		swcursordraw();
233 		qunlock(&drawlock);
234 	}
235 	splx(x);
236 }
237 
238 void
swcursorinit(void)239 swcursorinit(void)
240 {
241 	static int init;
242 
243 	if(!init){
244 		init = 1;
245 		addclock0link(swcursorclock, 10);
246 		swenabled = 1;
247 	}
248 	if(swback){
249 		freememimage(swback);
250 		freememimage(swmask);
251 		freememimage(swmask1);
252 		freememimage(swimg);
253 		freememimage(swimg1);
254 	}
255 
256 	swback  = allocmemimage(Rect(0,0,32,32), gscreen->chan);
257 	swmask  = allocmemimage(Rect(0,0,16,16), GREY8);
258 	swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
259 	swimg   = allocmemimage(Rect(0,0,16,16), GREY8);
260 	swimg1  = allocmemimage(Rect(0,0,16,16), GREY1);
261 	if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
262 		print("software cursor: allocmemimage fails\n");
263 		return;
264 	}
265 
266 	memfillcolor(swmask, DOpaque);
267 	memfillcolor(swmask1, DOpaque);
268 	memfillcolor(swimg, DBlack);
269 	memfillcolor(swimg1, DBlack);
270 }
271 
272 static int
screensize(void)273 screensize(void)
274 {
275 	char *p;
276 	char *f[3];
277 	int width, height, depth;
278 
279 	p = getconf("vgasize");
280 	if(p == nil || getfields(p, f, nelem(f), 0, "x") != nelem(f) ||
281 			(width = atoi(f[0])) < 16 || (height = atoi(f[1])) <= 0 ||
282 		(depth = atoi(f[2])) <= 0) {
283 		width = screenwid? screenwid: Wid;
284 		height = screenht? screenht: Ht;
285 		depth = screendepth? screendepth: Depth;
286 	}
287 
288 	xgscreen.r.max = Pt(width, height);
289 	xgscreen.depth = depth;
290 	return 0;
291 }
292 
293 void
flushmemscreen(Rectangle)294 flushmemscreen(Rectangle)
295 {
296 }
297 
298 static void
screenwin(void)299 screenwin(void)
300 {
301 	char *greet;
302 	Memimage *orange;
303 	Point p, q;
304 	Rectangle r;
305 
306 	back = memwhite;
307 	conscol = memblack;
308 
309 	orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
310 	orange->flags |= Frepl;
311 	orange->clipr = gscreen->r;
312 	orange->data->bdata[0] = 0x40;		/* magic: colour? */
313 	orange->data->bdata[1] = 0xfd;		/* magic: colour? */
314 
315 	w = memdefont->info[' '].width;
316 	h = memdefont->height;
317 
318 	r = insetrect(gscreen->r, 0);
319 
320 	memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
321 	window = insetrect(r, 0);
322 	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
323 
324 	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
325 		window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
326 	freememimage(orange);
327 	window = insetrect(window, 5);
328 
329 	greet = " Plan 9 Console ";
330 	p = addpt(window.min, Pt(10, 0));
331 	q = memsubfontwidth(memdefont, greet);
332 	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
333 	flushmemscreen(r);
334 	window.min.y += h + 6;
335 	curpos = window.min;
336 	window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
337 }
338 
339 static void
scroll(void)340 scroll(void)
341 {
342 	int o;
343 	Point p;
344 	Rectangle r;
345 
346 	o = Scroll*h;
347 	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
348 	p = Pt(window.min.x, window.min.y+o);
349 	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
350 	flushmemscreen(r);
351 	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
352 	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
353 	flushmemscreen(r);
354 
355 	curpos.y -= o;
356 }
357 
358 static void
screenputc(char * buf)359 screenputc(char *buf)
360 {
361 	int w;
362 	uint pos;
363 	Point p;
364 	Rectangle r;
365 	static int *xp;
366 	static int xbuf[256];
367 
368 	if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
369 		xp = xbuf;
370 
371 	switch (buf[0]) {
372 	case '\n':
373 		if (curpos.y + h >= window.max.y)
374 			scroll();
375 		curpos.y += h;
376 		screenputc("\r");
377 		break;
378 	case '\r':
379 		xp = xbuf;
380 		curpos.x = window.min.x;
381 		break;
382 	case '\t':
383 		p = memsubfontwidth(memdefont, " ");
384 		w = p.x;
385 		if (curpos.x >= window.max.x - Tabstop * w)
386 			screenputc("\n");
387 
388 		pos = (curpos.x - window.min.x) / w;
389 		pos = Tabstop - pos % Tabstop;
390 		*xp++ = curpos.x;
391 		r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
392 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
393 		flushmemscreen(r);
394 		curpos.x += pos * w;
395 		break;
396 	case '\b':
397 		if (xp <= xbuf)
398 			break;
399 		xp--;
400 		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
401 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
402 		flushmemscreen(r);
403 		curpos.x = *xp;
404 		break;
405 	case '\0':
406 		break;
407 	default:
408 		p = memsubfontwidth(memdefont, buf);
409 		w = p.x;
410 
411 		if (curpos.x >= window.max.x - w)
412 			screenputc("\n");
413 
414 		*xp++ = curpos.x;
415 		r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
416 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
417 		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
418 		flushmemscreen(r);
419 		curpos.x += w;
420 		break;
421 	}
422 }
423 
424 static void
myscreenputs(char * s,int n)425 myscreenputs(char *s, int n)
426 {
427 	int i;
428 	Rune r;
429 	char buf[4];
430 
431 	if(!islo()) {
432 		/* don't deadlock trying to print in interrupt */
433 		if(!canlock(&screenlock))
434 			return;
435 	}
436 	else
437 		lock(&screenlock);
438 
439 	while(n > 0){
440 		i = chartorune(&r, s);
441 		if(i == 0){
442 			s++;
443 			--n;
444 			continue;
445 		}
446 		memmove(buf, s, i);
447 		buf[i] = 0;
448 		n -= i;
449 		s += i;
450 		screenputc(buf);
451 	}
452 	unlock(&screenlock);
453 }
454 
455 void
screeninit(void)456 screeninit(void)
457 {
458 	ulong chan;
459 	uchar *fb;
460 
461 	screensize();
462 	fb = (uchar*)fbinit();
463 	if(fb == nil){
464 		print("can't initialise %dx%dx%d framebuffer \n",
465 			xgscreen.r.max.x, xgscreen.r.max.y, xgscreen.depth);
466 		return;
467 	}
468 
469 	xgscreen.clipr = xgscreen.r;
470 	switch(xgscreen.depth){
471 	default:
472 		print("unsupported screen depth %d\n", xgscreen.depth);
473 		xgscreen.depth = 16;
474 		/* fall through */
475 	case 16:
476 		chan = RGB16;
477 		break;
478 	case 24:
479 		chan = BGR24;
480 		break;
481 	case 32:
482 		chan = ARGB32;
483 		break;
484 	}
485 	memsetchan(&xgscreen, chan);
486 	conf.monitor = 1;
487 	xgdata.bdata = fb;
488 	xgdata.ref = 1;
489 	gscreen = &xgscreen;
490 	gscreen->width = wordsperline(gscreen->r, gscreen->depth);
491 
492 	memimageinit();
493 	memdefont = getmemdefont();
494 	screenwin();
495 	screenputs = myscreenputs;
496 }
497 
498 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)499 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
500 {
501 	*r = gscreen->r;
502 	*d = gscreen->depth;
503 	*chan = gscreen->chan;
504 	*width = gscreen->width;
505 	*softscreen = 0;
506 
507 	return gscreen->data->bdata;
508 }
509 
510 void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)511 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
512 {
513 	USED(p, pr, pg, pb);
514 }
515 
516 int
setcolor(ulong p,ulong r,ulong g,ulong b)517 setcolor(ulong p, ulong r, ulong g, ulong b)
518 {
519 	USED(p, r, g, b);
520 	return 0;
521 }
522 
523 void
blankscreen(int blank)524 blankscreen(int blank)
525 {
526 	USED(blank);
527 }
528 
529 int
hwdraw(Memdrawparam * par)530 hwdraw(Memdrawparam *par)
531 {
532 	Memimage *dst, *src, *mask;
533 
534 	if((dst=par->dst) == nil || dst->data == nil)
535 		return 0;
536 	if((src=par->src) == nil || src->data == nil)
537 		return 0;
538 	if((mask=par->mask) == nil || mask->data == nil)
539 		return 0;
540 
541 	if(dst->data->bdata == xgdata.bdata)
542 		swcursoravoid(par->r);
543 	if(src->data->bdata == xgdata.bdata)
544 		swcursoravoid(par->sr);
545 	if(mask->data->bdata == xgdata.bdata)
546 		swcursoravoid(par->mr);
547 
548 	return 0;
549 }
550 
551 /* radeon frame buffer control */
552 typedef struct Ctlr {
553 	Pcidev*	pcidev;
554 	int		port;
555 	void*	mmio;
556 	ulong	paddr;
557 	void*	vaddr;
558 } Ctlr;
559 
560 static Ctlr *ctlr;
561 
562 static Pcidev*
videopci(void)563 videopci(void)
564 {
565 	static Pcidev *p = nil;
566 
567 	while((p = pcimatch(p, 0, 0)) != nil){
568 		if(p->ccrb != Pcibcdisp || p->ccru != 0)
569 			continue;
570 		return p;
571 	}
572 	return nil;
573 }
574 
575 static void
fbenable(void)576 fbenable(void)
577 {
578 	Pcidev *p;
579 
580 	if(ctlr)
581 		return;
582 	p = videopci();
583 	if(p == nil)
584 		return;
585 	ctlr = malloc(sizeof(Ctlr));
586 	ctlr->pcidev = p;
587 	ctlr->paddr = PCIMEMADDR(p->mem[0].bar & ~0x0f);
588 	ctlr->vaddr = KSEG1ADDR(ctlr->paddr);
589 	ctlr->port = p->mem[1].bar & ~0x01;
590 	ctlr->mmio = KSEG1ADDR(PCIMEMADDR(p->mem[2].bar & ~0x0f));
591 }
592 
593 void*
fbinit(void)594 fbinit(void)
595 {
596 	if(!ctlr)
597 		fbenable();
598 
599 	if(!ctlr)
600 		return nil;
601 	else
602 		return ctlr->vaddr;
603 }
604