fb.c revision 1.14
1/*	$NetBSD: fb.c,v 1.14 2002/10/02 04:27:52 thorpej 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
72CFATTACH_DECL(fb, sizeof(struct fb_softc),
73    fb_match, fb_attach, NULL, NULL);
74
75struct fb_devconfig fb_console_dc;
76
77struct wsdisplay_accessops fb_accessops = {
78	fb_ioctl,
79	fb_mmap,
80	fb_alloc_screen,
81	fb_free_screen,
82	fb_show_screen,
83	NULL	/* load_font */
84};
85
86struct wsscreen_descr fb_stdscreen = {
87	"std",
88	0, 0,
89	0,
90	0, 0,
91	WSSCREEN_REVERSE
92};
93
94const struct wsscreen_descr *fb_scrlist[] = {
95	&fb_stdscreen
96};
97
98struct wsscreen_list fb_screenlist = {
99	sizeof(fb_scrlist) / sizeof(fb_scrlist[0]), fb_scrlist
100};
101
102#define NWB253_VRAM   ((u_char *) 0x88000000)
103#define NWB253_CTLREG ((u_short *)0xb8ff0000)
104#define NWB253_CRTREG ((u_short *)0xb8fe0000)
105
106static char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" };	/* XXX ? */
107
108int
109fb_match(parent, match, aux)
110	struct device *parent;
111	struct cfdata *match;
112	void *aux;
113{
114	struct confargs *ca = aux;
115
116	if (strcmp(ca->ca_name, "fb") != 0)
117		return 0;
118
119	if (badaddr(NWB253_CTLREG, 2) || badaddr(NWB253_CRTREG, 2))
120		return 0;
121	if ((*(volatile u_short *)NWB253_CTLREG & 7) != 4)
122		return 0;
123
124	return 1;
125}
126
127void
128fb_attach(parent, self, aux)
129	struct device *parent, *self;
130	void *aux;
131{
132	struct fb_softc *sc = (void *)self;
133	struct wsemuldisplaydev_attach_args waa;
134	struct fb_devconfig *dc;
135	struct rasops_info *ri;
136	int console;
137	volatile u_short *ctlreg = NWB253_CTLREG;
138	int id;
139
140	console = fb_is_console();
141
142	if (console) {
143		dc = &fb_console_dc;
144		ri = &dc->dc_ri;
145		sc->sc_nscreens = 1;
146	} else {
147		dc = malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
148		bzero(dc, sizeof(struct fb_devconfig));
149
150		dc->dc_fbbase = NWB253_VRAM;
151		fb_common_init(dc);
152		ri = &dc->dc_ri;
153
154		/* clear screen */
155		(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
156
157		fb253_init();
158	}
159	sc->sc_dc = dc;
160
161	id = (*ctlreg >> 8) & 0xf;
162	printf(": %s, %d x %d, %dbpp\n", devname[id],
163	    ri->ri_width, ri->ri_height, ri->ri_depth);
164
165	waa.console = console;
166	waa.scrdata = &fb_screenlist;
167	waa.accessops = &fb_accessops;
168	waa.accesscookie = sc;
169
170	config_found(self, &waa, wsemuldisplaydevprint);
171}
172
173int
174fb_common_init(dc)
175	struct fb_devconfig *dc;
176{
177	struct rasops_info *ri = &dc->dc_ri;
178	volatile u_short *ctlreg = NWB253_CTLREG;
179	int id;
180	int width, height, xoff, yoff, cols, rows;
181
182	id = (*ctlreg >> 8) & 0xf;
183
184	/* initialize rasops */
185	switch (id) {
186	case 0:
187		width = 816;
188		height = 1024;
189		break;
190	case 1:
191	case 2:
192		width = 1024;
193		height = 768;
194		break;
195	}
196
197	ri->ri_width = width;
198	ri->ri_height = height;
199	ri->ri_depth = 1;
200	ri->ri_stride = 2048 / 8;
201	ri->ri_bits = dc->dc_fbbase;
202	ri->ri_flg = RI_FULLCLEAR;
203
204	rasops_init(ri, 24, 80);
205	rows = (height - 2) / ri->ri_font->fontheight;
206	cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
207	xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
208	yoff = (height - rows * ri->ri_font->fontheight) / 2;
209	rasops_reconfig(ri, rows, cols);
210
211	ri->ri_xorigin = xoff;
212	ri->ri_yorigin = yoff;
213	ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
214
215	fb_stdscreen.nrows = ri->ri_rows;
216	fb_stdscreen.ncols = ri->ri_cols;
217	fb_stdscreen.textops = &ri->ri_ops;
218	fb_stdscreen.capabilities = ri->ri_caps;
219
220	return 0;
221}
222
223int
224fb_is_console()
225{
226	volatile u_int *dipsw = (void *)DIP_SWITCH;
227
228	if (*dipsw & 7)					/* XXX right? */
229		return 1;
230
231	return 0;
232}
233
234int
235fb_ioctl(v, cmd, data, flag, p)
236	void *v;
237	u_long cmd;
238	caddr_t data;
239	int flag;
240	struct proc *p;
241{
242	struct fb_softc *sc = v;
243	struct fb_devconfig *dc = sc->sc_dc;
244	struct wsdisplay_fbinfo *wdf;
245
246	switch (cmd) {
247	case WSDISPLAYIO_GTYPE:
248		*(int *)data = WSDISPLAY_TYPE_UNKNOWN;	/* XXX */
249		return 0;
250
251	case WSDISPLAYIO_GINFO:
252		wdf = (void *)data;
253		wdf->height = dc->dc_ri.ri_height;
254		wdf->width = dc->dc_ri.ri_width;
255		wdf->depth = dc->dc_ri.ri_depth;
256		wdf->cmsize = 2;
257		return 0;
258
259	case WSDISPLAYIO_SVIDEO:
260		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
261			volatile u_short *ctlreg = NWB253_CTLREG;
262			*ctlreg = 0;			/* stop crtc */
263		} else
264			fb253_init();
265		return 0;
266
267	case WSDISPLAYIO_GETCMAP:
268	case WSDISPLAYIO_PUTCMAP:
269		break;
270	}
271	return EPASSTHROUGH;
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.allocattr)(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.allocattr)(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