xref: /netbsd-src/sys/arch/newsmips/dev/fb.c (revision 7fa608457b817eca6e0977b37f758ae064f3c99c)
1 /*	$NetBSD: fb.c,v 1.23 2007/03/04 06:00:26 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.23 2007/03/04 06:00:26 christos Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/device.h>
34 #include <sys/ioctl.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
37 
38 #include <uvm/uvm_extern.h>
39 
40 #include <machine/adrsmap.h>
41 
42 #include <newsmips/dev/hbvar.h>
43 
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wsdisplayvar.h>
46 #include <dev/rasops/rasops.h>
47 
48 struct fb_devconfig {
49 	u_char *dc_fbbase;		/* VRAM base address */
50 	struct rasops_info dc_ri;
51 };
52 
53 struct fb_softc {
54 	struct device sc_dev;
55 	struct fb_devconfig *sc_dc;
56 	int sc_nscreens;
57 };
58 
59 int fb_match(struct device *, struct cfdata *, void *);
60 void fb_attach(struct device *, struct device *, void *);
61 
62 int fb_common_init(struct fb_devconfig *);
63 int fb_is_console(void);
64 
65 int fb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
66 paddr_t fb_mmap(void *, void *, off_t, int);
67 int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
68     int *, long *);
69 void fb_free_screen(void *, void *);
70 int fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
71 
72 void fb_cnattach(void);
73 
74 static void fb253_init(void);
75 
76 CFATTACH_DECL(fb, sizeof(struct fb_softc),
77     fb_match, fb_attach, NULL, NULL);
78 
79 struct fb_devconfig fb_console_dc;
80 
81 struct wsdisplay_accessops fb_accessops = {
82 	fb_ioctl,
83 	fb_mmap,
84 	fb_alloc_screen,
85 	fb_free_screen,
86 	fb_show_screen,
87 	NULL	/* load_font */
88 };
89 
90 struct wsscreen_descr fb_stdscreen = {
91 	"std",
92 	0, 0,
93 	0,
94 	0, 0,
95 	WSSCREEN_REVERSE
96 };
97 
98 const struct wsscreen_descr *fb_scrlist[] = {
99 	&fb_stdscreen
100 };
101 
102 struct wsscreen_list fb_screenlist = {
103 	sizeof(fb_scrlist) / sizeof(fb_scrlist[0]), fb_scrlist
104 };
105 
106 #define NWB253_VRAM   ((u_char *) 0x88000000)
107 #define NWB253_CTLREG ((u_short *)0xb8ff0000)
108 #define NWB253_CRTREG ((u_short *)0xb8fe0000)
109 
110 static const char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" }; /* XXX ? */
111 
112 int
113 fb_match(struct device *parent, struct cfdata *match, void *aux)
114 {
115 	struct hb_attach_args *ha = aux;
116 
117 	if (strcmp(ha->ha_name, "fb") != 0)
118 		return 0;
119 
120 	if (hb_badaddr(NWB253_CTLREG, 2) || hb_badaddr(NWB253_CRTREG, 2))
121 		return 0;
122 	if ((*(volatile u_short *)NWB253_CTLREG & 7) != 4)
123 		return 0;
124 
125 	return 1;
126 }
127 
128 void
129 fb_attach(struct device *parent, struct device *self, void *aux)
130 {
131 	struct fb_softc *sc = (void *)self;
132 	struct wsemuldisplaydev_attach_args waa;
133 	struct fb_devconfig *dc;
134 	struct rasops_info *ri;
135 	int console;
136 	volatile u_short *ctlreg = NWB253_CTLREG;
137 	int id;
138 
139 	console = fb_is_console();
140 
141 	if (console) {
142 		dc = &fb_console_dc;
143 		ri = &dc->dc_ri;
144 		sc->sc_nscreens = 1;
145 	} else {
146 		dc = malloc(sizeof(struct fb_devconfig), M_DEVBUF,
147 		    M_WAITOK|M_ZERO);
148 
149 		dc->dc_fbbase = NWB253_VRAM;
150 		fb_common_init(dc);
151 		ri = &dc->dc_ri;
152 
153 		/* clear screen */
154 		(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
155 
156 		fb253_init();
157 	}
158 	sc->sc_dc = dc;
159 
160 	id = (*ctlreg >> 8) & 0xf;
161 	printf(": %s, %d x %d, %dbpp\n", devname[id],
162 	    ri->ri_width, ri->ri_height, ri->ri_depth);
163 
164 	waa.console = console;
165 	waa.scrdata = &fb_screenlist;
166 	waa.accessops = &fb_accessops;
167 	waa.accesscookie = sc;
168 
169 	config_found(self, &waa, wsemuldisplaydevprint);
170 }
171 
172 int
173 fb_common_init(struct fb_devconfig *dc)
174 {
175 	struct rasops_info *ri = &dc->dc_ri;
176 	volatile u_short *ctlreg = NWB253_CTLREG;
177 	int id;
178 	int width, height, xoff, yoff, cols, rows;
179 
180 	id = (*ctlreg >> 8) & 0xf;
181 
182 	/* initialize rasops */
183 	switch (id) {
184 	case 0:
185 		width = 816;
186 		height = 1024;
187 		break;
188 	case 1:
189 	case 2:
190 	default:
191 		width = 1024;
192 		height = 768;
193 		break;
194 	}
195 
196 	ri->ri_width = width;
197 	ri->ri_height = height;
198 	ri->ri_depth = 1;
199 	ri->ri_stride = 2048 / 8;
200 	ri->ri_bits = dc->dc_fbbase;
201 	ri->ri_flg = RI_FULLCLEAR;
202 
203 	rasops_init(ri, 24, 80);
204 	rows = (height - 2) / ri->ri_font->fontheight;
205 	cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
206 	xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
207 	yoff = (height - rows * ri->ri_font->fontheight) / 2;
208 	rasops_reconfig(ri, rows, cols);
209 
210 	ri->ri_xorigin = xoff;
211 	ri->ri_yorigin = yoff;
212 	ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
213 
214 	fb_stdscreen.nrows = ri->ri_rows;
215 	fb_stdscreen.ncols = ri->ri_cols;
216 	fb_stdscreen.textops = &ri->ri_ops;
217 	fb_stdscreen.capabilities = ri->ri_caps;
218 
219 	return 0;
220 }
221 
222 int
223 fb_is_console(void)
224 {
225 	volatile u_int *dipsw = (void *)DIP_SWITCH;
226 
227 	if (*dipsw & 7)					/* XXX right? */
228 		return 1;
229 
230 	return 0;
231 }
232 
233 int
234 fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
235 {
236 	struct fb_softc *sc = v;
237 	struct fb_devconfig *dc = sc->sc_dc;
238 	struct wsdisplay_fbinfo *wdf;
239 
240 	switch (cmd) {
241 	case WSDISPLAYIO_GTYPE:
242 		*(int *)data = WSDISPLAY_TYPE_UNKNOWN;	/* XXX */
243 		return 0;
244 
245 	case WSDISPLAYIO_GINFO:
246 		wdf = (void *)data;
247 		wdf->height = dc->dc_ri.ri_height;
248 		wdf->width = dc->dc_ri.ri_width;
249 		wdf->depth = dc->dc_ri.ri_depth;
250 		wdf->cmsize = 2;
251 		return 0;
252 
253 	case WSDISPLAYIO_SVIDEO:
254 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
255 			volatile u_short *ctlreg = NWB253_CTLREG;
256 			*ctlreg = 0;			/* stop crtc */
257 		} else
258 			fb253_init();
259 		return 0;
260 
261 	case WSDISPLAYIO_GETCMAP:
262 	case WSDISPLAYIO_PUTCMAP:
263 		break;
264 	}
265 	return EPASSTHROUGH;
266 }
267 
268 paddr_t
269 fb_mmap(void *v, void *vs, off_t offset, int prot)
270 {
271 	struct fb_softc *sc = v;
272 	struct fb_devconfig *dc = sc->sc_dc;
273 
274 	if (offset >= 2048 * 2048 / 8 || offset < 0)
275 		return -1;
276 
277 	return mips_btop((int)dc->dc_fbbase + offset);
278 }
279 
280 int
281 fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep,
282     int *ccolp, int *crowp, long *attrp)
283 {
284 	struct fb_softc *sc = v;
285 	struct rasops_info *ri = &sc->sc_dc->dc_ri;
286 	long defattr;
287 
288 	if (sc->sc_nscreens > 0)
289 		return ENOMEM;
290 
291 	*cookiep = ri;
292 	*ccolp = *crowp = 0;
293 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
294 	*attrp = defattr;
295 	sc->sc_nscreens++;
296 
297 	return 0;
298 }
299 
300 void
301 fb_free_screen(void *v, void *cookie)
302 {
303 	struct fb_softc *sc = v;
304 
305 	if (sc->sc_dc == &fb_console_dc)
306 		panic("fb_free_screen: console");
307 
308 	sc->sc_nscreens--;
309 }
310 
311 int
312 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
313     void *cbarg)
314 {
315 
316 	return 0;
317 }
318 
319 void
320 fb_cnattach(void)
321 {
322 	struct fb_devconfig *dc = &fb_console_dc;
323 	struct rasops_info *ri = &dc->dc_ri;
324 	long defattr;
325 
326 	if (!fb_is_console())
327 		return;
328 
329 	dc->dc_fbbase = NWB253_VRAM;
330 	fb_common_init(dc);
331 
332 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
333 	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
334 }
335 
336 static const uint8_t
337 nwp512_data1[] = {
338 	0x00, 0x44,
339 	0x01, 0x33,
340 	0x02, 0x3c,
341 	0x03, 0x38,
342 	0x04, 0x84,
343 	0x05, 0x03,
344 	0x06, 0x80,
345 	0x07, 0x80,
346 	0x08, 0x10,
347 	0x09, 0x07,
348 	0x0a, 0x20,
349 	0x0c, 0x00,
350 	0x0d, 0x00,
351 	0x1b, 0x03
352 };
353 
354 static const uint8_t
355 nwp512_data2[] = {
356 	0x1e, 0x08,
357 	0x20, 0x08,
358 	0x21, 0x0d
359 };
360 
361 static const uint8_t
362 nwp518_data1[] = {
363 	0x00, 0x52,
364 	0x01, 0x40,
365 	0x02, 0x4a,
366 	0x03, 0x49,
367 	0x04, 0x63,
368 	0x05, 0x02,
369 	0x06, 0x60,
370 	0x07, 0x60,
371 	0x08, 0x10,
372 	0x09, 0x07,
373 	0x0a, 0x20,
374 	0x0c, 0x00,
375 	0x0d, 0x00,
376 	0x1b, 0x04
377 };
378 
379 static const uint8_t
380 nwp518_data2[] = {
381 	0x1e, 0x08,
382 	0x20, 0x00,
383 	0x21, 0x00
384 };
385 
386 static const uint8_t
387 nwe501_data1[] = {
388 	0x00, 0x4b,
389 	0x01, 0x40,
390 	0x02, 0x4a,
391 	0x03, 0x43,
392 	0x04, 0x64,
393 	0x05, 0x02,
394 	0x06, 0x60,
395 	0x07, 0x60,
396 	0x08, 0x10,
397 	0x09, 0x07,
398 	0x0a, 0x20,
399 	0x0c, 0x00,
400 	0x0d, 0x00,
401 	0x1b, 0x04
402 };
403 
404 static const uint8_t
405 nwe501_data2[] = {
406 	0x1e, 0x08,
407 	0x20, 0x00,
408 	0x21, 0x00
409 };
410 
411 static const uint8_t
412 *crtc_data[3][2] = {
413 	{ nwp512_data1, nwp512_data2 },
414 	{ nwp518_data1, nwp518_data2 },
415 	{ nwe501_data1, nwe501_data2 }
416 };
417 
418 static void
419 fb253_init(void)
420 {
421 	volatile u_short *ctlreg = NWB253_CTLREG;
422 	volatile u_short *crtreg = NWB253_CRTREG;
423 	int id = (*ctlreg >> 8) & 0xf;
424 	const uint8_t *p;
425 	int i;
426 
427 	*ctlreg = 0;			/* stop crtc */
428 	delay(10);
429 
430 	/* initialize crtc without R3{0,1,2} */
431 	p = crtc_data[id][0];
432 	for (i = 0; i < 28; i++) {
433 		*crtreg++ = *p++;
434 		delay(10);
435 	}
436 
437 	*ctlreg = 0x02;			/* start crtc */
438 	delay(10);
439 
440 	/* set crtc control reg */
441 	p = crtc_data[id][1];
442 	for (i = 0; i < 6; i++) {
443 		*crtreg++ = *p++;
444 		delay(10);
445 	}
446 }
447 
448 #if 0
449 static struct wsdisplay_font newsrom8x16;
450 static struct wsdisplay_font newsrom12x24;
451 static char fontarea16[96][32];
452 static char fontarea24[96][96];
453 
454 void
455 initfont(struct rasops_info *ri)
456 {
457 	int c, x;
458 
459 	for (c = 0; c < 96; c++) {
460 		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
461 		memcpy(fontarea16 + c, (char *)0xb8e00000 + x + 96, 32);
462 		memcpy(fontarea24 + c, (char *)0xb8e00000 + x, 96);
463 	}
464 
465 	newsrom8x16.name = "rom8x16";
466 	newsrom8x16.firstchar = 32;
467 	newsrom8x16.numchars = 96;
468 	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
469 	newsrom8x16.fontwidth = 8;
470 	newsrom8x16.fontheight = 16;
471 	newsrom8x16.stride = 2;
472 	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
473 	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
474 	newsrom8x16.data = fontarea16;
475 
476 	newsrom12x24.name = "rom12x24";
477 	newsrom12x24.firstchar = 32;
478 	newsrom12x24.numchars = 96;
479 	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
480 	newsrom12x24.fontwidth = 12;
481 	newsrom12x24.fontheight = 24;
482 	newsrom12x24.stride = 4;
483 	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
484 	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
485 	newsrom12x24.data = fontarea24;
486 
487 	ri->ri_font = &newsrom8x16;
488 	ri->ri_font = &newsrom12x24;
489 	ri->ri_wsfcookie = -1;		/* not using wsfont */
490 }
491 #endif
492