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