xref: /inferno-os/os/ipaq1110/lcd.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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