]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/screen.c
kernel: expose no execute bit to portable mmu code as SG_NOEXEC / PTENOEXEC, add...
[plan9front.git] / sys / src / 9 / omap / screen.c
1 /*
2  * ti omap35 display subsystem (dss)
3  *
4  * can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits.
5  * can handle   1024×768 at 60 Hz with pixel clock of 63.5 MHz
6  *              1280×800 at 59.91 Hz with pixel clock of 71 MHz
7  *              1400×1050 lcd at 50 MHz with pixel clock of 75 MHz
8  * has 256 24-bit entries in RGB palette
9  */
10 #include "u.h"
11 #include "../port/lib.h"
12 #include "mem.h"
13 #include "dat.h"
14 #include "fns.h"
15 #include "io.h"
16 #include "ureg.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 // #include "gamma.h"
25
26 enum {
27         Tabstop = 4,            /* should be 8 */
28         Scroll  = 8,            /* lines to scroll at one time */
29         /*
30          * screen settings for Wid and Ht, should a bit more dynamic?
31          * http://www.epanorama.net/faq/vga2rgb/calc.html
32          * used to calculate settings.
33          */
34
35 //      Hbp     = (248-1) << 20,
36 //      Hfp     = (48-1) << 8,
37 //      Hsw     = 112-1,
38
39 //      Vbp     = 38 << 20,
40 //      Vfp     = 1 << 8,
41 //      Vsw     = 3,
42
43         Tft     = 0x60,
44
45         Loadmode = 2 << 1,
46         Fifosize = 0x400,
47
48         /* dispc sysconfig */
49         Midlemode       = 2 << 12,
50         Sidlemode       = 2 << 3,
51         EnableWakeup    = 1 << 2,
52         Autoidle        = 1 << 0,
53
54         /* dispc pool_freq */
55         Ipc             = 1 << 14,
56         Ihs             = 1 << 13,
57         Ivs             = 1 << 12,
58         Acb             = 0x28,
59
60         /* gfx attribs */
61         Burstsize       = 2 << 6,
62         Format          = 6 << 1,
63         Gfxenable       = 1 << 0,
64
65         /* dispc control */
66         Gpout1          = 1 << 16,
67         Gpout0          = 1 << 15,
68         Tftdata         = 3 << 8,
69         Digital         = 1 << 6,
70         Lcd             = 1 << 5,
71         Stntft          = 1 << 3,
72         Digitalen       = 1 << 1,
73 //      Lcden           = 1 << 0,       /* unused */
74 };
75
76 typedef struct Dispcregs Dispc;
77 typedef struct Dssregs Dss;
78 typedef struct Ioregs Ioregs;
79
80 struct Ioregs {                         /* common registers, 68 (0x44) bytes */
81         ulong   rev;
82         uchar   _pad0[0x10-0x4];
83         ulong   sysconf;
84         ulong   sysstat;
85         ulong   irqstat1;
86
87         /* Dispc only regs */
88         ulong   irqen1;
89         ulong   wkupen;
90         ulong   _pad1;
91         ulong   irqsts2;
92         ulong   irqen2;
93         ulong   _pad2[4];
94
95         ulong   ctrl;
96 };
97
98 struct Dssregs {                        /* display subsys at 0x48050000 */
99         Ioregs;
100         ulong   sdicrtl;
101         ulong   pllcrtl;
102         uchar   _pad3[0x5c-0x4c];
103         ulong   sdistat;
104 };
105
106 struct Dispcregs {                      /* display ctlr at 0x48050400 */
107         Ioregs;
108         ulong   config;
109         ulong   _pad3;
110         ulong   defaultcolor[2];
111         ulong   transcolor[2];
112         ulong   linestat;
113         ulong   linenum;
114         ulong   timing_h;
115         ulong   timing_v;
116         ulong   pol_req;
117         ulong   divisor;
118         ulong   alpha;
119         ulong   digsize;
120         ulong   lcdsize;
121
122         ulong   base[2];        /* should allocate both to avoid dithering */
123         ulong   pos;
124         ulong   size;
125         ulong   _pad4[4];
126         ulong   attrib;
127         ulong   fifothr;
128         ulong   fifosize;
129         ulong   rowinc;
130         ulong   pixelinc;
131         ulong   winskip;
132         ulong   palette;                /* gfx_table_ba */
133         uchar   _pad5[0x5d4 - 0x4bc];
134
135         ulong   datacycle[3];
136         uchar   _pad5[0x620 - 0x5e0];
137
138         ulong   cprcoefr;
139         ulong   cprcoefg;
140         ulong   cprcoefb;
141         ulong   preload;
142 };
143
144 OScreen oscreen;
145 Settings settings[] = {
146 [Res800x600]   {  800,  600, 60, RGB16,  40000,  88, 40, 128,   23, 1, 5, },
147 [Res1024x768]  { 1024,  768, 60, RGB16,  65000, 160, 24, 136,   29, 3, 7, },
148 [Res1280x1024] { 1280, 1024, 60, RGB16, 108000, 248, 48, 112,   38, 1, 4, },
149 [Res1400x1050] { 1400, 1050, 50, RGB16, 108000, 248, 48, 112,   38, 1, 4, }, // TODO
150 };
151 Omap3fb *framebuf;
152 Memimage *gscreen;
153
154 static Memdata xgdata;
155
156 static Memimage xgscreen =
157 {
158         { 0, 0, Wid, Ht },      /* r */
159         { 0, 0, Wid, Ht },      /* clipr */
160         Depth,                  /* depth */
161         3,                      /* nchan */
162         RGB16,                  /* chan */
163         nil,                    /* cmap */
164         &xgdata,                /* data */
165         0,                      /* zero */
166         Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
167         0,                      /* layer */
168         0,                      /* flags */
169 };
170
171 static Memimage *conscol;
172 static Memimage *back;
173
174 static Memsubfont *memdefont;
175
176 static Lock screenlock;
177
178 static Point    curpos;
179 static int      h, w;
180 static int      landscape = 0;  /* screen orientation, default is 0: portrait */
181 static ushort   *vscreen;       /* virtual screen */
182 static Rectangle window;
183
184 static Dispc *dispc = (Dispc *)PHYSDISPC;
185 static Dss *dss = (Dss *)PHYSDSS;
186
187 static  void    omapscreenputs(char *s, int n);
188 static  ulong   rep(ulong, int);
189 static  void    screenputc(char *buf);
190 static  void    screenwin(void);
191
192 /*
193  * Software cursor. 
194  */
195 int     swvisible;      /* is the cursor visible? */
196 int     swenabled;      /* is the cursor supposed to be on the screen? */
197 Memimage*       swback; /* screen under cursor */
198 Memimage*       swimg;  /* cursor image */
199 Memimage*       swmask; /* cursor mask */
200 Memimage*       swimg1;
201 Memimage*       swmask1;
202
203 Point   swoffset;
204 Rectangle       swrect; /* screen rectangle in swback */
205 Point   swpt;   /* desired cursor location */
206 Point   swvispt;        /* actual cursor location */
207 int     swvers; /* incremented each time cursor image changes */
208 int     swvisvers;      /* the version on the screen */
209
210 static void
211 lcdoff(void)
212 {
213         dispc->ctrl &= ~1;              /* disable the lcd */
214         coherence();
215
216         dispc->irqstat1 |= 1;           /* set framedone */
217         coherence();
218
219         /* the lcd never comes ready, so don't bother with this */
220 #ifdef notdef
221         /* spin until the frame is complete, but not forever */
222         for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
223                 delay(10);
224 #endif
225         delay(20);                      /* worst case for 1 frame, 50Hz */
226 }
227
228 static void
229 dssstart(void)
230 {
231         /* should reset the dss system */
232         dss->sysconf |= 1;
233         coherence();
234 }
235
236 /* see spruf98i §15.6.7.4.2 */
237 static void
238 configdispc(void)
239 {
240         Settings *sp;
241
242         sp = oscreen.settings;
243         dss->ctrl &= 0x78;              /* choose dss clock */
244         dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
245         dispc->config = Loadmode;
246         coherence();
247
248         /* pll */
249         dispc->defaultcolor[0] = 0;     /* set background color to black? */
250         dispc->defaultcolor[1] = 0;
251         dispc->transcolor[0] = 0;       /* set transparency to full */
252         dispc->transcolor[1] = 0;
253
254         dispc->timing_h = (sp->hbp-1) << 20 | (sp->hfp-1) << 8 |
255                         (sp->hsw-1);
256         dispc->timing_v = sp->vbp << 20 | sp->vfp << 8 |
257                         (sp->vsw-1);
258
259         dispc->pol_req = Ipc | Ihs | Ivs | Acb;
260         dispc->divisor = 1 << 16 | ((432000+sp->pixelclock-1)/sp->pixelclock);
261
262         dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1);
263         coherence();
264
265         dispc->base[0] = PADDR(framebuf->pixel);
266         dispc->base[1] = PADDR(framebuf->pixel);
267
268         dispc->pos = 0;                 /* place screen in the left corner */
269         /* use the whole screen */
270         dispc->size = (sp->ht - 1) << 16 | (sp->wid - 1);
271
272         /* what mode does plan 9 use for fb? */
273         dispc->attrib = Burstsize | Format | Gfxenable;
274
275         dispc->preload = Tft;
276         dispc->fifosize = Fifosize;
277         /* 1008 is max for our Burstsize */
278         dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
279
280         /* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
281         dispc->rowinc = 1;
282         dispc->pixelinc = 1;
283         dispc->winskip = 0;             /* don't skip anything */
284         coherence();
285
286         // dispc->palette = PADDR(framebuf->palette);
287 }
288
289 static void
290 lcdon(int enable)
291 {
292         dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
293                 Digitalen | enable;
294         coherence();
295         delay(10);
296 }
297
298 static void
299 lcdstop(void)
300 {
301         configscreengpio();
302         screenclockson();
303
304         lcdoff();
305 }
306
307 static void
308 lcdinit(void)
309 {
310         lcdstop();
311
312         dssstart();
313         configdispc();
314 }
315
316 /* Paint the image data with blue pixels */
317 void
318 screentest(void)
319 {
320         int i;
321
322         for (i = nelem(framebuf->pixel) - 1; i >= 0; i--)
323                 framebuf->pixel[i] = 0x1f;                      /* blue */
324 //      memset(framebuf->pixel, ~0, sizeof framebuf->pixel);    /* white */
325 }
326
327 void
328 screenpower(int on)
329 {
330         blankscreen(on == 0);
331 }
332
333 void
334 cursoron(void)
335 {
336         qlock(&drawlock);
337         lock(&cursor);
338         swcursorhide();
339         swcursordraw(mousexy());
340         unlock(&cursor);
341         qunlock(&drawlock);
342 }
343
344 void
345 cursoroff(void)
346 {
347         qlock(&drawlock);
348         lock(&cursor);
349         swcursorhide();
350         unlock(&cursor);
351         qunlock(&drawlock);
352 }
353
354 /* called from devmouse */
355 void
356 setcursor(Cursor* curs)
357 {
358         oscreen.Cursor = *curs;
359         swcursorload(curs);
360 }
361
362 /* called from main and possibly later from devdss to change resolution */
363 void
364 screeninit(void)
365 {
366         static int first = 1;
367
368         if (first) {
369                 iprint("screeninit...");
370                 oscreen.settings = &settings[Res1280x1024];
371
372                 lcdstop();
373                 if (framebuf)
374                         free(framebuf);
375                 /* mode is 16*32 = 512 */
376                 framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
377         }
378
379         lcdinit();
380         lcdon(1);
381         if (first) {
382                 memimageinit();
383                 memdefont = getmemdefont();
384                 screentest();
385         }
386
387         xgdata.ref = 1;
388         xgdata.bdata = (uchar *)framebuf->pixel;
389
390         gscreen = &xgscreen;
391         gscreen->r = Rect(0, 0, Wid, Ht);
392         gscreen->clipr = gscreen->r;
393         /* width, in words, of a single scan line */
394         gscreen->width = Wid * (Depth / BI2BY) / BY2WD;
395         flushmemscreen(gscreen->r);
396
397         if (first) {
398                 iprint("on: blue for 3 seconds...");
399                 delay(3*1000);
400                 iprint("\n");
401
402                 screenwin();            /* draw border & top orange bar */
403                 screenputs = omapscreenputs;
404                 iprint("screen: frame buffer at %#p for %dx%d\n",
405                         framebuf, oscreen.settings->wid, oscreen.settings->ht);
406
407                 swenabled = 1;
408                 swcursorinit();         /* needs gscreen set */
409                 setcursor(&arrow);
410
411                 first = 0;
412         }
413 }
414
415 /* flushmemscreen should change buffer? */
416 void
417 flushmemscreen(Rectangle r)
418 {
419         ulong start, end;
420
421         if (r.min.x < 0)
422                 r.min.x = 0;
423         if (r.max.x > Wid)
424                 r.max.x = Wid;
425         if (r.min.y < 0)
426                 r.min.y = 0;
427         if (r.max.y > Ht)
428                 r.max.y = Ht;
429         if (rectclip(&r, gscreen->r) == 0)
430                 return;
431         start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
432         end   = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
433         cachedwbse((ulong *)start, end - start);
434 }
435
436 /*
437  * export screen to devdraw
438  */
439 Memdata*
440 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
441 {
442         if(gscreen == nil)
443                 return nil;
444
445         *r = gscreen->r;
446         *d = gscreen->depth;
447         *chan = gscreen->chan;
448         *width = gscreen->width;
449         *softscreen = (landscape == 0);
450
451         gscreen->data->ref++;
452         return gscreen->data;
453 }
454
455 void
456 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
457 {
458         USED(p, pr, pg, pb);
459 }
460
461 int
462 setcolor(ulong p, ulong r, ulong g, ulong b)
463 {
464         USED(p, r, g, b);
465         return 0;
466 }
467
468 void
469 blankscreen(int blank)
470 {
471         if (blank)
472                 lcdon(0);
473         else {
474                 lcdinit();
475                 lcdon(1);
476         }
477 }
478
479 static void
480 omapscreenputs(char *s, int n)
481 {
482         int i;
483         Rune r;
484         char buf[4];
485
486         if (!islo()) {
487                 /* don't deadlock trying to print in interrupt */
488                 if (!canlock(&screenlock))
489                         return;                 /* discard s */
490         } else
491                 lock(&screenlock);
492
493         while (n > 0) {
494                 i = chartorune(&r, s);
495                 if (i == 0) {
496                         s++;
497                         --n;
498                         continue;
499                 }
500                 memmove(buf, s, i);
501                 buf[i] = 0;
502                 n -= i;
503                 s += i;
504                 screenputc(buf);
505         }
506         unlock(&screenlock);
507 }
508
509 static void
510 screenwin(void)
511 {
512         char *greet;
513         Memimage *orange;
514         Point p, q;
515         Rectangle r;
516
517         memsetchan(gscreen, RGB16);
518
519         back = memwhite;
520         conscol = memblack;
521
522         orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
523         orange->flags |= Frepl;
524         orange->clipr = gscreen->r;
525         orange->data->bdata[0] = 0x40;          /* magic: colour? */
526         orange->data->bdata[1] = 0xfd;          /* magic: colour? */
527
528         w = memdefont->info[' '].width;
529         h = memdefont->height;
530
531         r = insetrect(gscreen->r, 4);
532
533         memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
534         window = insetrect(r, 4);
535         memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
536
537         memimagedraw(gscreen, Rect(window.min.x, window.min.y,
538                 window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
539         freememimage(orange);
540         window = insetrect(window, 5);
541
542         greet = " Plan 9 Console ";
543         p = addpt(window.min, Pt(10, 0));
544         q = memsubfontwidth(memdefont, greet);
545         memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
546         flushmemscreen(r);
547         window.min.y += h + 6;
548         curpos = window.min;
549         window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
550 }
551
552 static void
553 scroll(void)
554 {
555         int o;
556         Point p;
557         Rectangle r;
558
559         /* move window contents up Scroll text lines */
560         o = Scroll * h;
561         r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
562         p = Pt(window.min.x, window.min.y + o);
563         memimagedraw(gscreen, r, gscreen, p, nil, p, S);
564         flushmemscreen(r);
565
566         /* clear the bottom Scroll text lines */
567         r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
568         memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
569         flushmemscreen(r);
570
571         curpos.y -= o;
572 }
573
574 static void
575 screenputc(char *buf)
576 {
577         int w;
578         uint pos;
579         Point p;
580         Rectangle r;
581         static int *xp;
582         static int xbuf[256];
583
584         if (xp < xbuf || xp >= &xbuf[nelem(xbuf)])
585                 xp = xbuf;
586
587         switch (buf[0]) {
588         case '\n':
589                 if (curpos.y + h >= window.max.y)
590                         scroll();
591                 curpos.y += h;
592                 screenputc("\r");
593                 break;
594         case '\r':
595                 xp = xbuf;
596                 curpos.x = window.min.x;
597                 break;
598         case '\t':
599                 p = memsubfontwidth(memdefont, " ");
600                 w = p.x;
601                 if (curpos.x >= window.max.x - Tabstop * w)
602                         screenputc("\n");
603
604                 pos = (curpos.x - window.min.x) / w;
605                 pos = Tabstop - pos % Tabstop;
606                 *xp++ = curpos.x;
607                 r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
608                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
609                 flushmemscreen(r);
610                 curpos.x += pos * w;
611                 break;
612         case '\b':
613                 if (xp <= xbuf)
614                         break;
615                 xp--;
616                 r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
617                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
618                 flushmemscreen(r);
619                 curpos.x = *xp;
620                 break;
621         case '\0':
622                 break;
623         default:
624                 p = memsubfontwidth(memdefont, buf);
625                 w = p.x;
626
627                 if (curpos.x >= window.max.x - w)
628                         screenputc("\n");
629
630                 *xp++ = curpos.x;
631                 r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
632                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
633                 memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
634                 flushmemscreen(r);
635                 curpos.x += w;
636         }
637 }