screen.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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. #define Image IMAGE
  19. #include <draw.h>
  20. #include <memdraw.h>
  21. #include <cursor.h>
  22. #include "screen.h"
  23. // #include "gamma.h"
  24. enum {
  25. Tabstop = 4, /* should be 8 */
  26. /*
  27. * screen settings for Wid and Ht, should a bit more dynamic?
  28. * http://www.epanorama.net/faq/vga2rgb/calc.html
  29. * used to calculate settings.
  30. */
  31. // Hbp = (248-1) << 20,
  32. // Hfp = (48-1) << 8,
  33. // Hsw = 112-1,
  34. // Vbp = 38 << 20,
  35. // Vfp = 1 << 8,
  36. // Vsw = 3,
  37. Tft = 0x60,
  38. // Pcd = HOWMANY(432000, pixelclock), /* a bit too magic */
  39. Loadmode = 2 << 1,
  40. Fifosize = 0x400,
  41. /* dispc sysconfig */
  42. Midlemode = 2 << 12,
  43. Sidlemode = 2 << 3,
  44. EnableWakeup = 1 << 2,
  45. Autoidle = 1 << 0,
  46. /* dispc pool_freq */
  47. Ipc = 1 << 14,
  48. Ihs = 1 << 13,
  49. Ivs = 1 << 12,
  50. Acb = 0x28,
  51. /* gfx attribs */
  52. Burstsize = 2 << 6,
  53. Format = 6 << 1,
  54. Gfxenable = 1 << 0,
  55. /* dispc control */
  56. Gpout1 = 1 << 16,
  57. Gpout0 = 1 << 15,
  58. Tftdata = 3 << 8,
  59. Digital = 1 << 6,
  60. Lcd = 1 << 5,
  61. Stntft = 1 << 3,
  62. Digitalen = 1 << 1,
  63. // Lcden = 1 << 0, /* unused */
  64. };
  65. enum { /* settings indices */
  66. Res800x600,
  67. Res1024x768,
  68. Res1280x1024,
  69. };
  70. typedef struct Dispcregs Dispc;
  71. typedef struct Dssregs Dss;
  72. typedef struct Ioregs Ioregs;
  73. struct Ioregs { /* common registers, 68 (0x44) bytes */
  74. ulong rev;
  75. uchar _pad0[0x10-0x4];
  76. ulong sysconf;
  77. ulong sysstat;
  78. ulong irqstat1;
  79. /* Dispc only regs */
  80. ulong irqen1;
  81. ulong wkupen;
  82. ulong _pad1;
  83. ulong irqsts2;
  84. ulong irqen2;
  85. ulong _pad2[4];
  86. ulong ctrl;
  87. };
  88. struct Dssregs { /* display subsys at 0x48050000 */
  89. Ioregs;
  90. ulong sdicrtl;
  91. ulong pllcrtl;
  92. uchar _pad3[0x5c-0x4c];
  93. ulong sdistat;
  94. };
  95. struct Dispcregs { /* display ctlr at 0x48050400 */
  96. Ioregs;
  97. ulong config;
  98. ulong _pad3;
  99. ulong defaultcolor[2];
  100. ulong transcolor[2];
  101. ulong linestat;
  102. ulong linenum;
  103. ulong timing_h;
  104. ulong timing_v;
  105. ulong pol_req;
  106. ulong divisor;
  107. ulong alpha;
  108. ulong digsize;
  109. ulong lcdsize;
  110. ulong base[2]; /* should allocate both to avoid dithering */
  111. ulong pos;
  112. ulong size;
  113. ulong _pad4[4];
  114. ulong attrib;
  115. ulong fifothr;
  116. ulong fifosize;
  117. ulong rowinc;
  118. ulong pixelinc;
  119. ulong winskip;
  120. ulong palette; /* gfx_table_ba */
  121. uchar _pad5[0x5d4 - 0x4bc];
  122. ulong datacycle[3];
  123. uchar _pad5[0x620 - 0x5e0];
  124. ulong cprcoefr;
  125. ulong cprcoefg;
  126. ulong cprcoefb;
  127. ulong preload;
  128. };
  129. int drawdebug;
  130. Point ZP = {0, 0};
  131. Cursor arrow = {
  132. { -1, -1 },
  133. { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
  134. 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
  135. 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
  136. 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
  137. },
  138. { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
  139. 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
  140. 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
  141. 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
  142. },
  143. };
  144. #ifdef notdef
  145. #define MINX 8
  146. static struct {
  147. Point pos;
  148. int bwid;
  149. } out;
  150. #endif
  151. OScreen oscreen;
  152. OScreen settings[] = {
  153. 0, 800, 600, 60, RGB16, 40000, 87<<20, 39<<8, 127, 23<<20, 1<<8, 4,
  154. 0, 1024, 768, 60, RGB16, 65000, 159<<20, 23<<8, 135, 29<<20, 3<<8, 6,
  155. 0, 1280, 1024, 60, RGB16, 108000, 247<<20, 47<<8, 111, 38<<20, 1<<8, 3,
  156. };
  157. Omap3fb *framebuf;
  158. Memimage *gscreen;
  159. static Memdata xgdata;
  160. static Memimage xgscreen =
  161. {
  162. { 0, 0, Wid, Ht }, /* r */
  163. { 0, 0, Wid, Ht }, /* clipr */
  164. Depth, /* depth */
  165. 3, /* nchan */
  166. RGB16, /* chan */
  167. nil, /* cmap */
  168. &xgdata, /* data */
  169. 0, /* zero */
  170. Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
  171. 0, /* layer */
  172. 0, /* flags */
  173. };
  174. static Memimage *conscol;
  175. static Memimage *back;
  176. static Memsubfont *memdefont;
  177. static Lock screenlock;
  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. static Dispc *dispc = (Dispc *)PHYSDISPC;
  184. static Dss *dss = (Dss *)PHYSDSS;
  185. static void omapscreenputs(char *s, int n);
  186. static ulong rep(ulong, int);
  187. static void screenputc(char *buf);
  188. static void screenwin(void);
  189. static void
  190. lcdoff(void)
  191. {
  192. dispc->ctrl &= ~1; /* disable the lcd */
  193. coherence();
  194. dispc->irqstat1 |= 1; /* set framedone */
  195. coherence();
  196. /* the lcd never comes ready, so don't bother with this */
  197. #ifdef notdef
  198. /* spin until the frame is complete, but not forever */
  199. for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
  200. delay(10);
  201. #endif
  202. delay(20); /* worst case for 1 frame, 50Hz */
  203. }
  204. static void
  205. dssstart(void)
  206. {
  207. /* should reset the dss system */
  208. dss->sysconf |= 1;
  209. }
  210. static void
  211. configdispc(void)
  212. {
  213. dss->ctrl &= 0x78; /* choose dss clock */
  214. dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
  215. dispc->config = Loadmode;
  216. coherence();
  217. /* pll */
  218. dispc->defaultcolor[0] = 0; /* set background color to black? */
  219. dispc->defaultcolor[1] = 0;
  220. dispc->transcolor[0] = 0; /* set transparency to full */
  221. dispc->transcolor[1] = 0;
  222. dispc->timing_h = oscreen.hbp | oscreen.hfp | oscreen.hsw;
  223. dispc->timing_v = oscreen.vbp | oscreen.vfp | oscreen.vsw;
  224. dispc->pol_req = Ipc | Ihs | Ivs | Acb;
  225. dispc->divisor = 1 << 16 | HOWMANY(432000, oscreen.pixelclock);
  226. dispc->lcdsize = (oscreen.ht - 1) << 16 | (oscreen.wid - 1);
  227. coherence();
  228. dispc->base[0] = PADDR(framebuf->pixel);
  229. dispc->base[1] = PADDR(framebuf->pixel);
  230. dispc->pos = 0; /* place screen in the left corner */
  231. /* use the whole screen */
  232. dispc->size = (oscreen.ht - 1) << 16 | (oscreen.wid - 1);
  233. /* what mode does plan 9 use for fb? */
  234. dispc->attrib = Burstsize | Format | Gfxenable;
  235. dispc->preload = Tft;
  236. dispc->fifosize = Fifosize;
  237. /* 1008 is max for our Burstsize */
  238. dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
  239. /* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
  240. dispc->rowinc = 1;
  241. dispc->pixelinc = 1;
  242. dispc->winskip = 0; /* don't skip anything */
  243. coherence();
  244. // dispc->palette = PADDR(framebuf->palette);
  245. }
  246. static void
  247. lcdon(int enable)
  248. {
  249. dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
  250. Digitalen | enable;
  251. coherence();
  252. delay(10);
  253. }
  254. static void
  255. lcdinit(void)
  256. {
  257. configscreengpio();
  258. screenclockson();
  259. lcdoff();
  260. dssstart();
  261. configdispc();
  262. }
  263. /* Paint the image data with blue pixels */
  264. void
  265. screentest(void)
  266. {
  267. int i;
  268. for (i = nelem(framebuf->pixel) - 1; i >= 0; i--)
  269. framebuf->pixel[i] = 0x1f; /* blue */
  270. // memset(framebuf->pixel, ~0, sizeof framebuf->pixel); /* white */
  271. }
  272. void
  273. screenpower(int on)
  274. {
  275. blankscreen(on == 0);
  276. }
  277. int
  278. cursoron(int) // TODO
  279. {
  280. return 0;
  281. }
  282. void
  283. cursoroff(int)
  284. {
  285. }
  286. void
  287. setcursor(Cursor* curs) // TODO
  288. {
  289. // VGAscr *scr;
  290. USED(curs);
  291. // scr = &vgascreen[0];
  292. // cursorload(scr, curs);
  293. }
  294. void
  295. screeninit(void)
  296. {
  297. iprint("screeninit...");
  298. oscreen = settings[Res1280x1024];
  299. /* mode is 16*32 = 512 */
  300. framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
  301. lcdinit();
  302. lcdon(1);
  303. screentest();
  304. xgdata.ref = 1;
  305. xgdata.bdata = (uchar *)framebuf->pixel;
  306. gscreen = &xgscreen;
  307. gscreen->r = Rect(0, 0, Wid, Ht);
  308. gscreen->clipr = gscreen->r;
  309. /* width, in words, of a single scan line */
  310. gscreen->width = Wid * (Depth / BI2BY) / BY2WD;
  311. flushmemscreen(gscreen->r);
  312. iprint("on: blue for 2 seconds...");
  313. delay(2*1000);
  314. iprint("\n");
  315. memimageinit();
  316. memdefont = getmemdefont();
  317. #ifdef notdef
  318. out.pos.x = MINX;
  319. out.pos.y = 0;
  320. out.bwid = memdefont->info[' '].width;
  321. #endif
  322. blanktime = 3; /* minutes */
  323. screenwin(); /* draw border & top orange bar */
  324. screenputs = omapscreenputs;
  325. iprint("screen: frame buffer at %#p\n", framebuf);
  326. }
  327. /* flushmemscreen should change buffer? */
  328. void
  329. flushmemscreen(Rectangle r)
  330. {
  331. ulong start, end;
  332. if (r.min.x < 0)
  333. r.min.x = 0;
  334. if (r.max.x > Wid)
  335. r.max.x = Wid;
  336. if (r.min.y < 0)
  337. r.min.y = 0;
  338. if (r.max.y > Ht)
  339. r.max.y = Ht;
  340. if (rectclip(&r, gscreen->r) == 0)
  341. return;
  342. start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
  343. end = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
  344. cachedwbse((ulong *)start, end - start);
  345. }
  346. /*
  347. * export screen to devdraw
  348. */
  349. uchar*
  350. attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
  351. {
  352. *r = gscreen->r;
  353. *d = gscreen->depth;
  354. *chan = gscreen->chan;
  355. *width = gscreen->width;
  356. *softscreen = (landscape == 0);
  357. return (uchar *)gscreen->data->bdata;
  358. }
  359. void
  360. getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
  361. {
  362. USED(p, pr, pg, pb);
  363. }
  364. int
  365. setcolor(ulong p, ulong r, ulong g, ulong b)
  366. {
  367. USED(p, r, g, b);
  368. return 0;
  369. }
  370. void
  371. blankscreen(int blank)
  372. {
  373. if (blank)
  374. lcdon(0);
  375. else {
  376. lcdinit();
  377. lcdon(1);
  378. }
  379. }
  380. static void
  381. omapscreenputs(char *s, int n)
  382. {
  383. int i;
  384. Rune r;
  385. char buf[4];
  386. if (!islo()) {
  387. /* don't deadlock trying to print in interrupt */
  388. if (!canlock(&screenlock))
  389. return; /* discard s */
  390. } else
  391. lock(&screenlock);
  392. while (n > 0) {
  393. i = chartorune(&r, s);
  394. if (i == 0) {
  395. s++;
  396. --n;
  397. continue;
  398. }
  399. memmove(buf, s, i);
  400. buf[i] = 0;
  401. n -= i;
  402. s += i;
  403. screenputc(buf);
  404. }
  405. unlock(&screenlock);
  406. }
  407. static void
  408. screenwin(void)
  409. {
  410. char *greet;
  411. Memimage *orange;
  412. Point p, q;
  413. Rectangle r;
  414. memsetchan(gscreen, RGB16);
  415. back = memwhite;
  416. conscol = memblack;
  417. orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
  418. orange->flags |= Frepl;
  419. orange->clipr = gscreen->r;
  420. orange->data->bdata[0] = 0x40; /* magic: colour? */
  421. orange->data->bdata[1] = 0xfd; /* magic: colour? */
  422. w = memdefont->info[' '].width;
  423. h = memdefont->height;
  424. r = insetrect(gscreen->r, 4);
  425. memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
  426. window = insetrect(r, 4);
  427. memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
  428. memimagedraw(gscreen, Rect(window.min.x, window.min.y,
  429. window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
  430. freememimage(orange);
  431. window = insetrect(window, 5);
  432. greet = " Plan 9 Console ";
  433. p = addpt(window.min, Pt(10, 0));
  434. q = memsubfontwidth(memdefont, greet);
  435. memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
  436. flushmemscreen(r);
  437. window.min.y += h + 6;
  438. curpos = window.min;
  439. window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
  440. }
  441. static void
  442. scroll(void)
  443. {
  444. int o;
  445. Point p;
  446. Rectangle r;
  447. /* move window contents up 8 text lines */
  448. o = 8 * h;
  449. r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
  450. p = Pt(window.min.x, window.min.y + o);
  451. memimagedraw(gscreen, r, gscreen, p, nil, p, S);
  452. flushmemscreen(r);
  453. /* clear the bottom 8 text lines */
  454. r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
  455. memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
  456. flushmemscreen(r);
  457. curpos.y -= o;
  458. }
  459. static void
  460. screenputc(char *buf)
  461. {
  462. int w;
  463. uint pos;
  464. Point p;
  465. Rectangle r;
  466. static int *xp;
  467. static int xbuf[256];
  468. if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
  469. xp = xbuf;
  470. switch (buf[0]) {
  471. case '\n':
  472. if (curpos.y + h >= window.max.y)
  473. scroll();
  474. curpos.y += h;
  475. screenputc("\r");
  476. break;
  477. case '\r':
  478. xp = xbuf;
  479. curpos.x = window.min.x;
  480. break;
  481. case '\t':
  482. p = memsubfontwidth(memdefont, " ");
  483. w = p.x;
  484. if (curpos.x >= window.max.x - Tabstop * w)
  485. screenputc("\n");
  486. pos = (curpos.x - window.min.x) / w;
  487. pos = Tabstop - pos % Tabstop;
  488. *xp++ = curpos.x;
  489. r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
  490. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  491. flushmemscreen(r);
  492. curpos.x += pos * w;
  493. break;
  494. case '\b':
  495. if (xp <= xbuf)
  496. break;
  497. xp--;
  498. r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
  499. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  500. flushmemscreen(r);
  501. curpos.x = *xp;
  502. break;
  503. case '\0':
  504. break;
  505. default:
  506. p = memsubfontwidth(memdefont, buf);
  507. w = p.x;
  508. if (curpos.x >= window.max.x - w)
  509. screenputc("\n");
  510. *xp++ = curpos.x;
  511. r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
  512. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  513. memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
  514. flushmemscreen(r);
  515. curpos.x += w;
  516. }
  517. }