xref: /netbsd/sys/arch/newsmips/dev/fb.c (revision 6550d01e)
1 /*	$NetBSD: fb.c,v 1.25 2010/05/15 10:01:44 tsutsui 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.25 2010/05/15 10:01:44 tsutsui 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 	device_t sc_dev;
55 	struct fb_devconfig *sc_dc;
56 	int sc_nscreens;
57 };
58 
59 int fb_match(device_t, cfdata_t, void *);
60 void fb_attach(device_t, device_t, 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_NEW(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 	__arraycount(fb_scrlist), fb_scrlist
104 };
105 
106 #define NWB253_VRAM   ((uint8_t *) 0x88000000)
107 #define NWB253_CTLREG ((uint16_t *)0xb8ff0000)
108 #define NWB253_CRTREG ((uint16_t *)0xb8fe0000)
109 
110 static const char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" }; /* XXX ? */
111 
112 int
113 fb_match(device_t parent, cfdata_t cf, 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 uint16_t *)NWB253_CTLREG & 7) != 4)
123 		return 0;
124 
125 	return 1;
126 }
127 
128 void
129 fb_attach(device_t parent, device_t self, void *aux)
130 {
131 	struct fb_softc *sc = device_private(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 	sc->sc_dev = self;
140 
141 	console = fb_is_console();
142 
143 	if (console) {
144 		dc = &fb_console_dc;
145 		ri = &dc->dc_ri;
146 		ri->ri_flg &= ~RI_NO_AUTO;
147 		sc->sc_nscreens = 1;
148 	} else {
149 		dc = malloc(sizeof(struct fb_devconfig), M_DEVBUF,
150 		    M_WAITOK|M_ZERO);
151 
152 		dc->dc_fbbase = NWB253_VRAM;
153 		fb_common_init(dc);
154 		ri = &dc->dc_ri;
155 
156 		/* clear screen */
157 		(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
158 
159 		fb253_init();
160 	}
161 	sc->sc_dc = dc;
162 
163 	id = (*ctlreg >> 8) & 0xf;
164 	aprint_normal(": %s, %d x %d, %dbpp\n", devname[id],
165 	    ri->ri_width, ri->ri_height, ri->ri_depth);
166 
167 	waa.console = console;
168 	waa.scrdata = &fb_screenlist;
169 	waa.accessops = &fb_accessops;
170 	waa.accesscookie = sc;
171 
172 	config_found(self, &waa, wsemuldisplaydevprint);
173 }
174 
175 int
176 fb_common_init(struct fb_devconfig *dc)
177 {
178 	struct rasops_info *ri = &dc->dc_ri;
179 	volatile uint16_t *ctlreg = NWB253_CTLREG;
180 	int id;
181 	int width, height, xoff, yoff, cols, rows;
182 
183 	id = (*ctlreg >> 8) & 0xf;
184 
185 	/* initialize rasops */
186 	switch (id) {
187 	case 0:
188 		width = 816;
189 		height = 1024;
190 		break;
191 	case 1:
192 	case 2:
193 	default:
194 		width = 1024;
195 		height = 768;
196 		break;
197 	}
198 
199 	ri->ri_width = width;
200 	ri->ri_height = height;
201 	ri->ri_depth = 1;
202 	ri->ri_stride = 2048 / 8;
203 	ri->ri_bits = dc->dc_fbbase;
204 	ri->ri_flg = RI_FULLCLEAR;
205 	if (dc == &fb_console_dc)
206 		ri->ri_flg |= RI_NO_AUTO;
207 
208 	rasops_init(ri, 24, 80);
209 	rows = (height - 2) / ri->ri_font->fontheight;
210 	cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
211 	xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
212 	yoff = (height - rows * ri->ri_font->fontheight) / 2;
213 	rasops_reconfig(ri, rows, cols);
214 
215 	ri->ri_xorigin = xoff;
216 	ri->ri_yorigin = yoff;
217 	ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
218 
219 	fb_stdscreen.nrows = ri->ri_rows;
220 	fb_stdscreen.ncols = ri->ri_cols;
221 	fb_stdscreen.textops = &ri->ri_ops;
222 	fb_stdscreen.capabilities = ri->ri_caps;
223 
224 	return 0;
225 }
226 
227 int
228 fb_is_console(void)
229 {
230 	volatile u_int *dipsw = (void *)DIP_SWITCH;
231 
232 	if (*dipsw & 7)					/* XXX right? */
233 		return 1;
234 
235 	return 0;
236 }
237 
238 int
239 fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
240 {
241 	struct fb_softc *sc = v;
242 	struct fb_devconfig *dc = sc->sc_dc;
243 	struct wsdisplay_fbinfo *wdf;
244 
245 	switch (cmd) {
246 	case WSDISPLAYIO_GTYPE:
247 		*(int *)data = WSDISPLAY_TYPE_UNKNOWN;	/* XXX */
248 		return 0;
249 
250 	case WSDISPLAYIO_GINFO:
251 		wdf = (void *)data;
252 		wdf->height = dc->dc_ri.ri_height;
253 		wdf->width = dc->dc_ri.ri_width;
254 		wdf->depth = dc->dc_ri.ri_depth;
255 		wdf->cmsize = 2;
256 		return 0;
257 
258 	case WSDISPLAYIO_SVIDEO:
259 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
260 			volatile u_short *ctlreg = NWB253_CTLREG;
261 			*ctlreg = 0;			/* stop crtc */
262 		} else
263 			fb253_init();
264 		return 0;
265 
266 	case WSDISPLAYIO_GETCMAP:
267 	case WSDISPLAYIO_PUTCMAP:
268 		break;
269 	}
270 	return EPASSTHROUGH;
271 }
272 
273 paddr_t
274 fb_mmap(void *v, void *vs, off_t offset, int prot)
275 {
276 	struct fb_softc *sc = v;
277 	struct fb_devconfig *dc = sc->sc_dc;
278 
279 	if (offset >= 2048 * 2048 / 8 || offset < 0)
280 		return -1;
281 
282 	return mips_btop((int)dc->dc_fbbase + offset);
283 }
284 
285 int
286 fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep,
287     int *ccolp, int *crowp, long *attrp)
288 {
289 	struct fb_softc *sc = v;
290 	struct rasops_info *ri = &sc->sc_dc->dc_ri;
291 	long defattr;
292 
293 	if (sc->sc_nscreens > 0)
294 		return ENOMEM;
295 
296 	*cookiep = ri;
297 	*ccolp = *crowp = 0;
298 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
299 	*attrp = defattr;
300 	sc->sc_nscreens++;
301 
302 	return 0;
303 }
304 
305 void
306 fb_free_screen(void *v, void *cookie)
307 {
308 	struct fb_softc *sc = v;
309 
310 	if (sc->sc_dc == &fb_console_dc)
311 		panic("%s: console", __func__);
312 
313 	sc->sc_nscreens--;
314 }
315 
316 int
317 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
318     void *cbarg)
319 {
320 
321 	return 0;
322 }
323 
324 void
325 fb_cnattach(void)
326 {
327 	struct fb_devconfig *dc = &fb_console_dc;
328 	struct rasops_info *ri = &dc->dc_ri;
329 	long defattr;
330 
331 	if (!fb_is_console())
332 		return;
333 
334 	dc->dc_fbbase = NWB253_VRAM;
335 	fb_common_init(dc);
336 
337 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
338 	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
339 }
340 
341 static const uint8_t
342 nwp512_data1[] = {
343 	0x00, 0x44,
344 	0x01, 0x33,
345 	0x02, 0x3c,
346 	0x03, 0x38,
347 	0x04, 0x84,
348 	0x05, 0x03,
349 	0x06, 0x80,
350 	0x07, 0x80,
351 	0x08, 0x10,
352 	0x09, 0x07,
353 	0x0a, 0x20,
354 	0x0c, 0x00,
355 	0x0d, 0x00,
356 	0x1b, 0x03
357 };
358 
359 static const uint8_t
360 nwp512_data2[] = {
361 	0x1e, 0x08,
362 	0x20, 0x08,
363 	0x21, 0x0d
364 };
365 
366 static const uint8_t
367 nwp518_data1[] = {
368 	0x00, 0x52,
369 	0x01, 0x40,
370 	0x02, 0x4a,
371 	0x03, 0x49,
372 	0x04, 0x63,
373 	0x05, 0x02,
374 	0x06, 0x60,
375 	0x07, 0x60,
376 	0x08, 0x10,
377 	0x09, 0x07,
378 	0x0a, 0x20,
379 	0x0c, 0x00,
380 	0x0d, 0x00,
381 	0x1b, 0x04
382 };
383 
384 static const uint8_t
385 nwp518_data2[] = {
386 	0x1e, 0x08,
387 	0x20, 0x00,
388 	0x21, 0x00
389 };
390 
391 static const uint8_t
392 nwe501_data1[] = {
393 	0x00, 0x4b,
394 	0x01, 0x40,
395 	0x02, 0x4a,
396 	0x03, 0x43,
397 	0x04, 0x64,
398 	0x05, 0x02,
399 	0x06, 0x60,
400 	0x07, 0x60,
401 	0x08, 0x10,
402 	0x09, 0x07,
403 	0x0a, 0x20,
404 	0x0c, 0x00,
405 	0x0d, 0x00,
406 	0x1b, 0x04
407 };
408 
409 static const uint8_t
410 nwe501_data2[] = {
411 	0x1e, 0x08,
412 	0x20, 0x00,
413 	0x21, 0x00
414 };
415 
416 static const uint8_t
417 *crtc_data[3][2] = {
418 	{ nwp512_data1, nwp512_data2 },
419 	{ nwp518_data1, nwp518_data2 },
420 	{ nwe501_data1, nwe501_data2 }
421 };
422 
423 static void
424 fb253_init(void)
425 {
426 	volatile uint16_t *ctlreg = NWB253_CTLREG;
427 	volatile uint16_t *crtreg = NWB253_CRTREG;
428 	int id = (*ctlreg >> 8) & 0xf;
429 	const uint8_t *p;
430 	int i;
431 
432 	*ctlreg = 0;			/* stop crtc */
433 	delay(10);
434 
435 	/* initialize crtc without R3{0,1,2} */
436 	p = crtc_data[id][0];
437 	for (i = 0; i < 28; i++) {
438 		*crtreg++ = *p++;
439 		delay(10);
440 	}
441 
442 	*ctlreg = 0x02;			/* start crtc */
443 	delay(10);
444 
445 	/* set crtc control reg */
446 	p = crtc_data[id][1];
447 	for (i = 0; i < 6; i++) {
448 		*crtreg++ = *p++;
449 		delay(10);
450 	}
451 }
452 
453 #if 0
454 static struct wsdisplay_font newsrom8x16;
455 static struct wsdisplay_font newsrom12x24;
456 static char fontarea16[96][32];
457 static char fontarea24[96][96];
458 
459 void
460 initfont(struct rasops_info *ri)
461 {
462 	int c, x;
463 
464 	for (c = 0; c < 96; c++) {
465 		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
466 		memcpy(fontarea16 + c, (char *)0xb8e00000 + x + 96, 32);
467 		memcpy(fontarea24 + c, (char *)0xb8e00000 + x, 96);
468 	}
469 
470 	newsrom8x16.name = "rom8x16";
471 	newsrom8x16.firstchar = 32;
472 	newsrom8x16.numchars = 96;
473 	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
474 	newsrom8x16.fontwidth = 8;
475 	newsrom8x16.fontheight = 16;
476 	newsrom8x16.stride = 2;
477 	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
478 	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
479 	newsrom8x16.data = fontarea16;
480 
481 	newsrom12x24.name = "rom12x24";
482 	newsrom12x24.firstchar = 32;
483 	newsrom12x24.numchars = 96;
484 	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
485 	newsrom12x24.fontwidth = 12;
486 	newsrom12x24.fontheight = 24;
487 	newsrom12x24.stride = 4;
488 	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
489 	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
490 	newsrom12x24.data = fontarea24;
491 
492 	ri->ri_font = &newsrom8x16;
493 	ri->ri_font = &newsrom12x24;
494 	ri->ri_wsfcookie = -1;		/* not using wsfont */
495 }
496 #endif
497