fb.c revision 1.20
1/*	$NetBSD: fb.c,v 1.20 2005/06/03 13:44:50 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.20 2005/06/03 13:44:50 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
48struct fb_devconfig {
49	u_char *dc_fbbase;		/* VRAM base address */
50	struct rasops_info dc_ri;
51};
52
53struct fb_softc {
54	struct device sc_dev;
55	struct fb_devconfig *sc_dc;
56	int sc_nscreens;
57};
58
59int fb_match(struct device *, struct cfdata *, void *);
60void fb_attach(struct device *, struct device *, void *);
61
62int fb_common_init(struct fb_devconfig *);
63int fb_is_console(void);
64
65int fb_ioctl(void *, u_long, caddr_t, int, struct proc *);
66paddr_t fb_mmap(void *, off_t, int);
67int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
68    int *, long *);
69void fb_free_screen(void *, void *);
70int fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
71
72void fb_cnattach(void);
73
74static void fb253_init(void);
75
76CFATTACH_DECL(fb, sizeof(struct fb_softc),
77    fb_match, fb_attach, NULL, NULL);
78
79struct fb_devconfig fb_console_dc;
80
81struct 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
90struct wsscreen_descr fb_stdscreen = {
91	"std",
92	0, 0,
93	0,
94	0, 0,
95	WSSCREEN_REVERSE
96};
97
98const struct wsscreen_descr *fb_scrlist[] = {
99	&fb_stdscreen
100};
101
102struct 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
110static const char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" }; /* XXX ? */
111
112int
113fb_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
128void
129fb_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
172int
173fb_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
222int
223fb_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
233int
234fb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
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
268paddr_t
269fb_mmap(void *v, 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
280int
281fb_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
300void
301fb_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
311int
312fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
313    void *cbarg)
314{
315
316	return 0;
317}
318
319void
320fb_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
336static const uint8_t
337nwp512_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
354static const uint8_t
355nwp512_data2[] = {
356	0x1e, 0x08,
357	0x20, 0x08,
358	0x21, 0x0d
359};
360
361static const uint8_t
362nwp518_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
379static const uint8_t
380nwp518_data2[] = {
381	0x1e, 0x08,
382	0x20, 0x00,
383	0x21, 0x00
384};
385
386static const uint8_t
387nwe501_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
404static const uint8_t
405nwe501_data2[] = {
406	0x1e, 0x08,
407	0x20, 0x00,
408	0x21, 0x00
409};
410
411static 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
418static void
419fb253_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
449static struct wsdisplay_font newsrom8x16;
450static struct wsdisplay_font newsrom12x24;
451static char fontarea16[96][32];
452static char fontarea24[96][96];
453
454void
455initfont(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