lcd.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include "u.h"
  2. #include "mem.h"
  3. #include "../port/lib.h"
  4. #include "dat.h"
  5. #include "draw.h"
  6. #include "fns.h"
  7. #include "io.h"
  8. #include <memdraw.h>
  9. #include "screen.h"
  10. #define DPRINT if(1)iprint
  11. enum {
  12. /* lccr0 */
  13. EnableCtlr = 1<<0, /* controller enable */
  14. IsColour = 0<<1,
  15. IsMono = 1<<1,
  16. SinglePanel = 0<<2,
  17. DualPanel = 1<<2,
  18. DisableDone = 1<<3,
  19. DisableBAU = 1<<4,
  20. DisableErr = 1<<5,
  21. PassivePanel = 0<<7,
  22. ActivePanel = 1<<7,
  23. BigEndian = 1<<8,
  24. DoublePixel = 1<<9,
  25. /* 19:12 is palette dma delay */
  26. /* lcsr */
  27. CtlrReady = 1<<0,
  28. /* lccr3 */
  29. VsyncLow = 1<<20,
  30. HsyncLow = 1<<21,
  31. PixelClockLow = 1<<22,
  32. OELow = 1<<23,
  33. };
  34. typedef struct {
  35. Vdisplay;
  36. LCDparam;
  37. ushort* palette;
  38. uchar* upper;
  39. uchar* lower;
  40. } LCDdisplay;
  41. static LCDdisplay *vd; // current active display
  42. void
  43. lcd_setcolor(ulong p, ulong r, ulong g, ulong b)
  44. {
  45. if(vd->pbs == 0 && p > 15 ||
  46. vd->pbs == 1 && p > 255 ||
  47. vd->pbs == 2)
  48. return;
  49. vd->palette[p] = (vd->pbs<<12) |
  50. ((r>>(32-4))<<8) |
  51. ((g>>(32-4))<<4) |
  52. (b>>(32-4));
  53. }
  54. static void
  55. disablelcd(void)
  56. {
  57. LcdReg *lcd = LCDREG;
  58. int i;
  59. /* if LCD enabled, turn off and wait for current frame to end */
  60. if(lcd->lccr0 & EnableCtlr) {
  61. lcd->lccr0 &= ~EnableCtlr;
  62. for(i=0; i < 50 && !(lcd->lcsr & CtlrReady); i++)
  63. delay(5);
  64. }
  65. }
  66. static void
  67. setlcdmode(LCDdisplay *vd)
  68. {
  69. LCDmode *p;
  70. int ppf, pclk, clockdiv;
  71. ulong v, c;
  72. LcdReg *lcd = LCDREG;
  73. GpioReg *gpio = GPIOREG;
  74. p = (LCDmode*)&vd->Vmode;
  75. ppf = ((((p->x+p->sol_wait+p->eol_wait) *
  76. (p->mono ? 1 : 3)) >> (3-p->mono)) +
  77. p->hsync_wid) *
  78. (p->y/(p->dual+1)+p->vsync_hgt+
  79. p->sof_wait+p->eof_wait);
  80. pclk = ppf*p->hz;
  81. clockdiv = ((m->cpuhz/pclk) >> 1)-2;
  82. DPRINT(" oclockdiv=%d\n", clockdiv);
  83. clockdiv=0x10;
  84. disablelcd();
  85. lcd->lccr0 = 0; /* reset it */
  86. DPRINT(" pclk=%d clockdiv=%d\n", pclk, clockdiv);
  87. lcd->lccr3 = (clockdiv << 0) |
  88. (p->acbias_lines << 8) |
  89. (p->lines_per_int << 16) |
  90. VsyncLow | HsyncLow; /* vsync active low, hsync active low */
  91. lcd->lccr2 = (((p->y/(p->dual+1))-1) << 0) |
  92. (p->vsync_hgt << 10) |
  93. (p->eof_wait << 16) |
  94. (p->sof_wait << 24);
  95. lcd->lccr1 = ((p->x-16) << 0) |
  96. (p->hsync_wid << 10) |
  97. (p->eol_wait << 16) |
  98. (p->sol_wait << 24);
  99. // enable LCD controller, CODEC, and lower 4/8 data bits (for tft/dual)
  100. v = p->obits < 12? 0: p->obits < 16? 0x3c: 0x3fc;
  101. c = p->obits == 12? 0x3c0: 0;
  102. gpio->gafr |= v;
  103. gpio->gpdr |= v | c;
  104. gpio->gpcr = c;
  105. lcd->dbar1 = PADDR(vd->palette);
  106. if(vd->dual)
  107. lcd->dbar2 = PADDR(vd->lower);
  108. // Enable LCD
  109. lcd->lccr0 = EnableCtlr | (p->mono?IsMono:IsColour)
  110. | (p->palette_delay << 12)
  111. | (p->dual ? DualPanel : SinglePanel)
  112. | (p->active? ActivePanel: PassivePanel)
  113. | DisableDone | DisableBAU | DisableErr;
  114. // recalculate actual HZ
  115. pclk = (m->cpuhz/(clockdiv+2)) >> 1;
  116. p->hz = pclk/ppf;
  117. archlcdenable(1);
  118. iprint("lccr0=%8.8lux lccr1=%8.8lux lccr2=%8.8lux lccr3=%8.8lux\n", lcd->lccr0, lcd->lccr1, lcd->lccr2, lcd->lccr3);
  119. }
  120. static LCDdisplay main_display; /* TO DO: limits us to a single display */
  121. Vdisplay*
  122. lcd_init(LCDmode *p)
  123. {
  124. int palsize;
  125. int fbsize;
  126. vd = &main_display;
  127. vd->Vmode = *p;
  128. vd->LCDparam = *p;
  129. DPRINT("%dx%dx%d: hz=%d\n", vd->x, vd->y, vd->depth, vd->hz); /* */
  130. palsize = vd->pbs==1? 256 : 16;
  131. fbsize = palsize*2+(((vd->x*vd->y) * vd->depth) >> 3);
  132. if((vd->palette = xspanalloc(fbsize+CACHELINESZ+512, CACHELINESZ, 0)) == nil) /* at least 16-byte alignment */
  133. panic("no vidmem, no party...");
  134. vd->palette[0] = (vd->pbs<<12);
  135. vd->palette = minicached(vd->palette);
  136. vd->upper = (uchar*)(vd->palette + palsize);
  137. vd->bwid = (vd->x << vd->pbs) >> 1;
  138. vd->lower = vd->upper+((vd->bwid*vd->y) >> 1);
  139. vd->fb = vd->upper;
  140. DPRINT(" fbsize=%d p=%p u=%p l=%p\n", fbsize, vd->palette, vd->upper, vd->lower); /* */
  141. setlcdmode(vd);
  142. return vd;
  143. }
  144. void
  145. lcd_flush(void)
  146. {
  147. if(conf.useminicache)
  148. minidcflush();
  149. else
  150. dcflushall(); /* need more precise addresses */
  151. }
  152. void
  153. blankscreen(int blank)
  154. {
  155. if (blank) {
  156. disablelcd();
  157. archlcdenable(0);
  158. } else {
  159. archlcdenable(1);
  160. setlcdmode(&main_display);
  161. }
  162. }