fb.c revision 1.9
1/*	$NetBSD: fb.c,v 1.9 2000/12/03 01:42:30 matt 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/param.h>
30#include <sys/device.h>
31#include <sys/ioctl.h>
32#include <sys/malloc.h>
33#include <sys/systm.h>
34
35#include <uvm/uvm_extern.h>
36
37#include <machine/adrsmap.h>
38#include <machine/autoconf.h>
39
40#include <dev/wscons/wsconsio.h>
41#include <dev/wscons/wsdisplayvar.h>
42#include <dev/rasops/rasops.h>
43
44struct fb_devconfig {
45	u_char *dc_fbbase;		/* VRAM base address */
46	struct rasops_info dc_ri;
47};
48
49struct fb_softc {
50	struct device sc_dev;
51	struct fb_devconfig *sc_dc;
52	int sc_nscreens;
53};
54
55int fb_match(struct device *, struct cfdata *, void *);
56void fb_attach(struct device *, struct device *, void *);
57
58int fb_common_init(struct fb_devconfig *);
59int fb_is_console(void);
60
61int fb_ioctl(void *, u_long, caddr_t, int, struct proc *);
62paddr_t fb_mmap(void *, off_t, int);
63int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
64		    int *, long *);
65void fb_free_screen(void *, void *);
66int fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
67
68void fb_cnattach(void);
69
70static void fb253_init(void);
71
72struct cfattach fb_ca = {
73	sizeof(struct fb_softc), fb_match, fb_attach,
74};
75
76struct fb_devconfig fb_console_dc;
77
78struct wsdisplay_accessops fb_accessops = {
79	fb_ioctl,
80	fb_mmap,
81	fb_alloc_screen,
82	fb_free_screen,
83	fb_show_screen,
84	NULL	/* load_font */
85};
86
87struct wsscreen_descr fb_stdscreen = {
88	"std",
89	0, 0,
90	0,
91	0, 0,
92	WSSCREEN_REVERSE
93};
94
95const struct wsscreen_descr *fb_scrlist[] = {
96	&fb_stdscreen
97};
98
99struct wsscreen_list fb_screenlist = {
100	sizeof(fb_scrlist) / sizeof(fb_scrlist[0]), fb_scrlist
101};
102
103#define NWB253_VRAM   ((u_char *) 0x88000000)
104#define NWB253_CTLREG ((u_short *)0xb8ff0000)
105#define NWB253_CRTREG ((u_short *)0xb8fe0000)
106
107static char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" };	/* XXX ? */
108
109int
110fb_match(parent, match, aux)
111	struct device *parent;
112	struct cfdata *match;
113	void *aux;
114{
115	struct confargs *ca = aux;
116
117	if (strcmp(ca->ca_name, "fb") != 0)
118		return 0;
119
120	if (badaddr(NWB253_CTLREG, 2) || 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(parent, self, aux)
130	struct device *parent, *self;
131	void *aux;
132{
133	struct fb_softc *sc = (void *)self;
134	struct wsemuldisplaydev_attach_args waa;
135	struct fb_devconfig *dc;
136	struct rasops_info *ri;
137	int console;
138	volatile u_short *ctlreg = NWB253_CTLREG;
139	int id;
140
141	console = fb_is_console();
142
143	if (console) {
144		dc = &fb_console_dc;
145		ri = &dc->dc_ri;
146		sc->sc_nscreens = 1;
147	} else {
148		dc = malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
149		bzero(dc, sizeof(struct fb_devconfig));
150
151		dc->dc_fbbase = NWB253_VRAM;
152		fb_common_init(dc);
153		ri = &dc->dc_ri;
154
155		/* clear screen */
156		(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
157
158		fb253_init();
159	}
160	sc->sc_dc = dc;
161
162	id = (*ctlreg >> 8) & 0xf;
163	printf(": %s, %d x %d, %dbpp\n", devname[id],
164	    ri->ri_width, ri->ri_height, ri->ri_depth);
165
166	waa.console = console;
167	waa.scrdata = &fb_screenlist;
168	waa.accessops = &fb_accessops;
169	waa.accesscookie = sc;
170
171	config_found(self, &waa, wsemuldisplaydevprint);
172}
173
174int
175fb_common_init(dc)
176	struct fb_devconfig *dc;
177{
178	struct rasops_info *ri = &dc->dc_ri;
179	volatile u_short *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		width = 1024;
194		height = 768;
195		break;
196	}
197
198	ri->ri_width = width;
199	ri->ri_height = height;
200	ri->ri_depth = 1;
201	ri->ri_stride = 2048 / 8;
202	ri->ri_bits = dc->dc_fbbase;
203	ri->ri_flg = RI_FULLCLEAR;
204
205	rasops_init(ri, 24, 80);
206	rows = (height - 2) / ri->ri_font->fontheight;
207	cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
208	xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
209	yoff = (height - rows * ri->ri_font->fontheight) / 2;
210	rasops_reconfig(ri, rows, cols);
211
212	ri->ri_xorigin = xoff;
213	ri->ri_yorigin = yoff;
214	ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
215
216	fb_stdscreen.nrows = ri->ri_rows;
217	fb_stdscreen.ncols = ri->ri_cols;
218	fb_stdscreen.textops = &ri->ri_ops;
219	fb_stdscreen.capabilities = ri->ri_caps;
220
221	return 0;
222}
223
224int
225fb_is_console()
226{
227	volatile u_int *dipsw = (void *)DIP_SWITCH;
228
229	if (*dipsw & 7)					/* XXX right? */
230		return 1;
231
232	return 0;
233}
234
235int
236fb_ioctl(v, cmd, data, flag, p)
237	void *v;
238	u_long cmd;
239	caddr_t data;
240	int flag;
241	struct proc *p;
242{
243	struct fb_softc *sc = v;
244	struct fb_devconfig *dc = sc->sc_dc;
245	struct wsdisplay_fbinfo *wdf;
246
247	switch (cmd) {
248	case WSDISPLAYIO_GTYPE:
249		*(int *)data = WSDISPLAY_TYPE_UNKNOWN;	/* XXX */
250		return 0;
251
252	case WSDISPLAYIO_GINFO:
253		wdf = (void *)data;
254		wdf->height = dc->dc_ri.ri_height;
255		wdf->width = dc->dc_ri.ri_width;
256		wdf->depth = dc->dc_ri.ri_depth;
257		wdf->cmsize = 2;
258		return 0;
259
260	case WSDISPLAYIO_SVIDEO:
261		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
262			volatile u_short *ctlreg = NWB253_CTLREG;
263			*ctlreg = 0;			/* stop crtc */
264		} else
265			fb253_init();
266		return 0;
267
268	case WSDISPLAYIO_GETCMAP:
269	case WSDISPLAYIO_PUTCMAP:
270	}
271	return -1;
272}
273
274paddr_t
275fb_mmap(v, offset, prot)
276	void *v;
277	off_t offset;
278	int prot;
279{
280	struct fb_softc *sc = v;
281	struct fb_devconfig *dc = sc->sc_dc;
282
283	if (offset >= 2048 * 2048 / 8 || offset < 0)
284		return -1;
285
286	return mips_btop((int)dc->dc_fbbase + offset);
287}
288
289int
290fb_alloc_screen(v, scrdesc, cookiep, ccolp, crowp, attrp)
291	void *v;
292	const struct wsscreen_descr *scrdesc;
293	void **cookiep;
294	int *ccolp, *crowp;
295	long *attrp;
296{
297	struct fb_softc *sc = v;
298	struct rasops_info *ri = &sc->sc_dc->dc_ri;
299	long defattr;
300
301	if (sc->sc_nscreens > 0)
302		return ENOMEM;
303
304	*cookiep = ri;
305	*ccolp = *crowp = 0;
306	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
307	*attrp = defattr;
308	sc->sc_nscreens++;
309
310	return 0;
311}
312
313void
314fb_free_screen(v, cookie)
315	void *v;
316	void *cookie;
317{
318	struct fb_softc *sc = v;
319
320	if (sc->sc_dc == &fb_console_dc)
321		panic("fb_free_screen: console");
322
323	sc->sc_nscreens--;
324}
325
326int
327fb_show_screen(v, cookie, waitok, cb, cbarg)
328	void *v;
329	void *cookie;
330	int waitok;
331	void (*cb)(void *, int, int);
332	void *cbarg;
333{
334	return 0;
335}
336
337void
338fb_cnattach()
339{
340	struct fb_devconfig *dc = &fb_console_dc;
341	struct rasops_info *ri = &dc->dc_ri;
342	long defattr;
343
344	if (!fb_is_console())
345		return;
346
347	dc->dc_fbbase = NWB253_VRAM;
348	fb_common_init(dc);
349
350	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
351	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
352}
353
354static u_char
355nwp512_data1[] = {
356	0x00, 0x44,
357	0x01, 0x33,
358	0x02, 0x3c,
359	0x03, 0x38,
360	0x04, 0x84,
361	0x05, 0x03,
362	0x06, 0x80,
363	0x07, 0x80,
364	0x08, 0x10,
365	0x09, 0x07,
366	0x0a, 0x20,
367	0x0c, 0x00,
368	0x0d, 0x00,
369	0x1b, 0x03
370};
371
372static u_char
373nwp512_data2[] = {
374	0x1e, 0x08,
375	0x20, 0x08,
376	0x21, 0x0d
377};
378
379static u_char
380nwp518_data1[] = {
381	0x00, 0x52,
382	0x01, 0x40,
383	0x02, 0x4a,
384	0x03, 0x49,
385	0x04, 0x63,
386	0x05, 0x02,
387	0x06, 0x60,
388	0x07, 0x60,
389	0x08, 0x10,
390	0x09, 0x07,
391	0x0a, 0x20,
392	0x0c, 0x00,
393	0x0d, 0x00,
394	0x1b, 0x04
395};
396
397static u_char
398nwp518_data2[] = {
399	0x1e, 0x08,
400	0x20, 0x00,
401	0x21, 0x00
402};
403
404static u_char
405nwe501_data1[] = {
406	0x00, 0x4b,
407	0x01, 0x40,
408	0x02, 0x4a,
409	0x03, 0x43,
410	0x04, 0x64,
411	0x05, 0x02,
412	0x06, 0x60,
413	0x07, 0x60,
414	0x08, 0x10,
415	0x09, 0x07,
416	0x0a, 0x20,
417	0x0c, 0x00,
418	0x0d, 0x00,
419	0x1b, 0x04
420};
421
422static u_char
423nwe501_data2[] = {
424	0x1e, 0x08,
425	0x20, 0x00,
426	0x21, 0x00
427};
428
429static u_char
430*crtc_data[3][2] = {
431	{ nwp512_data1, nwp512_data2 },
432	{ nwp518_data1, nwp518_data2 },
433	{ nwe501_data1, nwe501_data2 }
434};
435
436static void
437fb253_init(void)
438{
439	volatile u_short *ctlreg = NWB253_CTLREG;
440	volatile u_short *crtreg = NWB253_CRTREG;
441	int id = (*ctlreg >> 8) & 0xf;
442	u_char *p;
443	int i;
444
445	*ctlreg = 0;			/* stop crtc */
446	delay(10);
447
448	/* initialize crtc without R3{0,1,2} */
449	p = crtc_data[id][0];
450	for (i = 0; i < 28; i++) {
451		*crtreg++ = *p++;
452		delay(10);
453	}
454
455	*ctlreg = 0x02;			/* start crtc */
456	delay(10);
457
458	/* set crtc control reg */
459	p = crtc_data[id][1];
460	for (i = 0; i < 6; i++) {
461		*crtreg++ = *p++;
462		delay(10);
463	}
464}
465
466#if 0
467static struct wsdisplay_font newsrom8x16;
468static struct wsdisplay_font newsrom12x24;
469static char fontarea16[96][32];
470static char fontarea24[96][96];
471
472void
473initfont(ri)
474	struct rasops_info *ri;
475{
476	int c, x;
477
478	for (c = 0; c < 96; c++) {
479		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
480		bcopy((char *)0xb8e00000 + x + 96, fontarea16 + c, 32);
481		bcopy((char *)0xb8e00000 + x, fontarea24 + c, 96);
482	}
483
484	newsrom8x16.name = "rom8x16";
485	newsrom8x16.firstchar = 32;
486	newsrom8x16.numchars = 96;
487	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
488	newsrom8x16.fontwidth = 8;
489	newsrom8x16.fontheight = 16;
490	newsrom8x16.stride = 2;
491	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
492	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
493	newsrom8x16.data = fontarea16;
494
495	newsrom12x24.name = "rom12x24";
496	newsrom12x24.firstchar = 32;
497	newsrom12x24.numchars = 96;
498	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
499	newsrom12x24.fontwidth = 12;
500	newsrom12x24.fontheight = 24;
501	newsrom12x24.stride = 4;
502	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
503	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
504	newsrom12x24.data = fontarea24;
505
506	ri->ri_font = &newsrom8x16;
507	ri->ri_font = &newsrom12x24;
508	ri->ri_wsfcookie = -1;		/* not using wsfont */
509}
510#endif
511