xref: /inferno-os/os/boot/rpcg/screen.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include	"all.h"
2 #include	<libg.h>
3 #include	<gnot.h>
4 
5 enum {
6 	Colldepth		= 3,
7 	Colmaxx		= 640,
8 	Colmaxxvis	= 640,
9 	Colmaxy		= 480,
10 };
11 
12 #define	MINX	8
13 
14 extern	GSubfont	defont0;
15 
16 struct{
17 	Point	pos;
18 	int	bwid;
19 }out;
20 
21 typedef struct Mode Mode;
22 struct Mode {
23 	int	x;
24 	int	y;
25 	int	d;
26 	char*	aperture;
27 	int	apsize;
28 };
29 
30 GBitmap	gscreen;
31 Point	gchar(GBitmap*, Point, GFont*, int, Fcode);
32 int	setcolor(ulong, ulong, ulong, ulong);
33 static	void	lcdinit(Mode*);
34 
35 void
36 screeninit(void)
37 {
38 	Mode m;
39 
40 	m.x = Colmaxx;
41 	m.y = Colmaxy;
42 	m.d = Colldepth;
43 	m.aperture = 0;
44 	lcdinit(&m);
45 	if(m.aperture == 0)
46 		return;
47 	gscreen.ldepth = 3;
48 	gscreen.base = (ulong*)m.aperture;
49 	gscreen.width = Colmaxx/BY2WD;
50 	gscreen.r = Rect(0, 0, Colmaxxvis, Colmaxy);
51 	gscreen.clipr = gscreen.r;
52 	/*
53 	 * For now, just use a fixed colormap:
54 	 * 0 == white and 255 == black
55 	 */
56 	setcolor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
57 	setcolor(255, 0x00000000, 0x00000000, 0x00000000);
58 
59 	gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, Zero);
60 	out.pos.x = MINX;
61 	out.pos.y = 0;
62 	out.bwid = defont0.info[' '].width;
63 }
64 
65 void
66 screenputc(int c)
67 {
68 	Fontchar *i;
69 	Point p;
70 
71 	if(gscreen.base == nil)
72 		return;
73 	switch(c){
74 	case '\n':
75 		out.pos.x = MINX;
76 		out.pos.y += defont0.height;
77 		if(out.pos.y > gscreen.r.max.y-defont0.height)
78 			out.pos.y = gscreen.r.min.y;
79 		gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen,
80 		  Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height),
81 		  Zero);
82 		break;
83 	case '\t':
84 		out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
85 		if(out.pos.x >= gscreen.r.max.x)
86 			screenputc('\n');
87 		break;
88 	case '\b':
89 		if(out.pos.x >= out.bwid+MINX){
90 			out.pos.x -= out.bwid;
91 			screenputc(' ');
92 			out.pos.x -= out.bwid;
93 		}
94 		break;
95 	default:
96 		if(out.pos.x >= gscreen.r.max.x-out.bwid)
97 			screenputc('\n');
98 		c &= 0x7f;
99 		if(c <= 0 || c >= defont0.n)
100 			break;
101 		i = defont0.info + c;
102 		p = out.pos;
103 		gbitblt(&gscreen, Pt(p.x+i->left, p.y), defont0.bits,
104 			Rect(i[0].x, 0, i[1].x, defont0.height),
105 			S);
106 		out.pos.x = p.x + i->width;
107 		break;
108 	}
109 }
110 
111 void
112 screenputs(char *s, int n)
113 {
114 	while(n-- > 0)
115 		screenputc(*s++);
116 }
117 
118 /*
119  * See section 5.2.1 (page 5-6) of the MPC823 manual
120  */
121 static uchar lcdclock[17] = {	/* (a<<2)|b => divisor of (1<<a)*((b<<1)+1) */
122 	0, 0, (1<<2), 1,
123 	(2<<2), 2, (1<<2)|1, 3,
124 	(3<<2), (1<<2)|2, (1<<2)|2, (2<<2)|1,
125 	(2<<2)|1, (1<<2)|3, (1<<2)|3, (4<<2),
126 	(4<<2)
127 };
128 
129 /*
130  * support for the Sharp LQ64D341 TFT colour display
131  */
132 
133 enum {
134 	COLS = 640,
135 	ROWS = 480,
136 	LDEPTH = 3,	/* screen depth */
137 	LCDFREQ = 25000000,
138 
139 	/* lccr */
140 	ClockLow = 1<<11,
141 	OELow = 1<<10,
142 	HsyncLow = 1<<9,
143 	VsyncLow = 1<<8,
144 	DataLow = 1<<7,
145 	Passive8 = 1<<4,
146 	DualScan = 1<<3,
147 	IsColour = 1<<2,
148 	IsTFT = 1<<1,
149 	Enable = 1<<0,
150 
151 	/* lchcr */
152 	BigEndian = 1<<24,
153 	AT7 = 7<<21,	/* access type */
154 
155 	/* sdcr */
156 	LAM = 1<<6,	/* ``LCD aggressive mode'' */
157 };
158 
159 /*
160  * TO DO: most of the data could come from a table
161  */
162 static void
163 lcdinit(Mode *mode)
164 {
165 	IMM *io;
166 	int i, d;
167 	long hz;
168 
169 	io = m->iomem;
170 	mode->y = ROWS;
171 	mode->x = COLS;
172 	mode->d = LDEPTH;
173 	mode->aperture = ialloc(mode->x*mode->y, 16);
174 	mode->apsize = mode->x*mode->y;
175 
176 	io->sdcr &= ~LAM;	/* MPC823 errata: turn off LAM before disabling controller */
177 	io->lcfaa = PADDR(mode->aperture);
178 	io->lccr = (((mode->x*mode->y*(1<<LDEPTH)+127)/128) << 17) | (LDEPTH << 5) | IsColour | IsTFT | OELow | VsyncLow | ClockLow;
179 
180 	switch(LDEPTH){
181 	default:
182 	case 0:
183 		/* monochrome/greyscale identity map */
184 		for(i=0; i<16; i++)
185 			io->lcdmap[i] = i;
186 		break;
187 	case 2:
188 		/* 4-bit grey scale map */
189 		for(i=0; i<16; i++)
190 			io->lcdmap[0] = (i<<8)|(i<<4)|i;
191 		break;
192 	case 3:
193 		/* 8-bit linear map */
194 		for(i=0; i<256; i++)
195 			io->lcdmap[i] = (i<<8)|(i<<4)|i;
196 		break;
197 	}
198 
199 	io->lcvcr = (mode->y << 11) | (1<<28) | 33;	/* 2 line vsync pulse, 34 line wait between frames */
200 	io->lchcr = (mode->x<<10) | BigEndian | 228;	/* clock cycles between lines */
201 
202 	hz = m->cpuhz;
203 	d = hz/LCDFREQ;
204 	if(hz/d > LCDFREQ)
205 		d++;
206 	if(d >= 16)
207 		d = 16;
208 
209 	/*
210 	 * enable LCD outputs
211 	 */
212 	io->pddat = 0;
213 	io->pdpar = 0x1fff;
214 io->pdpar &= ~SIBIT(6);	/* 823 bug fix? */
215 	io->pddir = 0x1fff;
216 	io->pbpar |= IBIT(31) | IBIT(19) | IBIT(17);
217 	io->pbdir |= IBIT(31) | IBIT(19) | IBIT(17);
218 	io->pbodr &= ~(IBIT(31) | IBIT(19) | IBIT(17));
219 
220 	eieio();
221 	io->sccrk = KEEP_ALIVE_KEY;
222 	eieio();
223 	io->sccr  = (io->sccr & ~0x1F) | lcdclock[d];
224 	eieio();
225 	io->sccrk = ~KEEP_ALIVE_KEY;
226 	eieio();
227 	gscreen.width = gscreen.width;	/* access external memory before enabling (mpc823 errata) */
228 	io->lcsr = 7;	/* clear status */
229 	eieio();
230 	io->lccr |= Enable;
231 	archbacklight(1);
232 }
233 
234 int
235 setcolor(ulong p, ulong r, ulong g, ulong b)
236 {
237 	r >>= 28;
238 	g >>= 28;
239 	b >>= 28;
240 	m->iomem->lcdmap[~p&0xFF] = (r<<8) | (g<<4) | b;	/* TO DO: it's a function of the ldepth */
241 	return 1;
242 }
243