fb.c revision 1.11
1/*	$NetBSD: fb.c,v 1.11 2002/05/31 21:40:49 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
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		break;
271	}
272	return EPASSTHROUGH;
273}
274
275paddr_t
276fb_mmap(v, offset, prot)
277	void *v;
278	off_t offset;
279	int prot;
280{
281	struct fb_softc *sc = v;
282	struct fb_devconfig *dc = sc->sc_dc;
283
284	if (offset >= 2048 * 2048 / 8 || offset < 0)
285		return -1;
286
287	return mips_btop((int)dc->dc_fbbase + offset);
288}
289
290int
291fb_alloc_screen(v, scrdesc, cookiep, ccolp, crowp, attrp)
292	void *v;
293	const struct wsscreen_descr *scrdesc;
294	void **cookiep;
295	int *ccolp, *crowp;
296	long *attrp;
297{
298	struct fb_softc *sc = v;
299	struct rasops_info *ri = &sc->sc_dc->dc_ri;
300	long defattr;
301
302	if (sc->sc_nscreens > 0)
303		return ENOMEM;
304
305	*cookiep = ri;
306	*ccolp = *crowp = 0;
307	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
308	*attrp = defattr;
309	sc->sc_nscreens++;
310
311	return 0;
312}
313
314void
315fb_free_screen(v, cookie)
316	void *v;
317	void *cookie;
318{
319	struct fb_softc *sc = v;
320
321	if (sc->sc_dc == &fb_console_dc)
322		panic("fb_free_screen: console");
323
324	sc->sc_nscreens--;
325}
326
327int
328fb_show_screen(v, cookie, waitok, cb, cbarg)
329	void *v;
330	void *cookie;
331	int waitok;
332	void (*cb)(void *, int, int);
333	void *cbarg;
334{
335	return 0;
336}
337
338void
339fb_cnattach()
340{
341	struct fb_devconfig *dc = &fb_console_dc;
342	struct rasops_info *ri = &dc->dc_ri;
343	long defattr;
344
345	if (!fb_is_console())
346		return;
347
348	dc->dc_fbbase = NWB253_VRAM;
349	fb_common_init(dc);
350
351	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
352	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
353}
354
355static u_char
356nwp512_data1[] = {
357	0x00, 0x44,
358	0x01, 0x33,
359	0x02, 0x3c,
360	0x03, 0x38,
361	0x04, 0x84,
362	0x05, 0x03,
363	0x06, 0x80,
364	0x07, 0x80,
365	0x08, 0x10,
366	0x09, 0x07,
367	0x0a, 0x20,
368	0x0c, 0x00,
369	0x0d, 0x00,
370	0x1b, 0x03
371};
372
373static u_char
374nwp512_data2[] = {
375	0x1e, 0x08,
376	0x20, 0x08,
377	0x21, 0x0d
378};
379
380static u_char
381nwp518_data1[] = {
382	0x00, 0x52,
383	0x01, 0x40,
384	0x02, 0x4a,
385	0x03, 0x49,
386	0x04, 0x63,
387	0x05, 0x02,
388	0x06, 0x60,
389	0x07, 0x60,
390	0x08, 0x10,
391	0x09, 0x07,
392	0x0a, 0x20,
393	0x0c, 0x00,
394	0x0d, 0x00,
395	0x1b, 0x04
396};
397
398static u_char
399nwp518_data2[] = {
400	0x1e, 0x08,
401	0x20, 0x00,
402	0x21, 0x00
403};
404
405static u_char
406nwe501_data1[] = {
407	0x00, 0x4b,
408	0x01, 0x40,
409	0x02, 0x4a,
410	0x03, 0x43,
411	0x04, 0x64,
412	0x05, 0x02,
413	0x06, 0x60,
414	0x07, 0x60,
415	0x08, 0x10,
416	0x09, 0x07,
417	0x0a, 0x20,
418	0x0c, 0x00,
419	0x0d, 0x00,
420	0x1b, 0x04
421};
422
423static u_char
424nwe501_data2[] = {
425	0x1e, 0x08,
426	0x20, 0x00,
427	0x21, 0x00
428};
429
430static u_char
431*crtc_data[3][2] = {
432	{ nwp512_data1, nwp512_data2 },
433	{ nwp518_data1, nwp518_data2 },
434	{ nwe501_data1, nwe501_data2 }
435};
436
437static void
438fb253_init(void)
439{
440	volatile u_short *ctlreg = NWB253_CTLREG;
441	volatile u_short *crtreg = NWB253_CRTREG;
442	int id = (*ctlreg >> 8) & 0xf;
443	u_char *p;
444	int i;
445
446	*ctlreg = 0;			/* stop crtc */
447	delay(10);
448
449	/* initialize crtc without R3{0,1,2} */
450	p = crtc_data[id][0];
451	for (i = 0; i < 28; i++) {
452		*crtreg++ = *p++;
453		delay(10);
454	}
455
456	*ctlreg = 0x02;			/* start crtc */
457	delay(10);
458
459	/* set crtc control reg */
460	p = crtc_data[id][1];
461	for (i = 0; i < 6; i++) {
462		*crtreg++ = *p++;
463		delay(10);
464	}
465}
466
467#if 0
468static struct wsdisplay_font newsrom8x16;
469static struct wsdisplay_font newsrom12x24;
470static char fontarea16[96][32];
471static char fontarea24[96][96];
472
473void
474initfont(ri)
475	struct rasops_info *ri;
476{
477	int c, x;
478
479	for (c = 0; c < 96; c++) {
480		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
481		bcopy((char *)0xb8e00000 + x + 96, fontarea16 + c, 32);
482		bcopy((char *)0xb8e00000 + x, fontarea24 + c, 96);
483	}
484
485	newsrom8x16.name = "rom8x16";
486	newsrom8x16.firstchar = 32;
487	newsrom8x16.numchars = 96;
488	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
489	newsrom8x16.fontwidth = 8;
490	newsrom8x16.fontheight = 16;
491	newsrom8x16.stride = 2;
492	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
493	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
494	newsrom8x16.data = fontarea16;
495
496	newsrom12x24.name = "rom12x24";
497	newsrom12x24.firstchar = 32;
498	newsrom12x24.numchars = 96;
499	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
500	newsrom12x24.fontwidth = 12;
501	newsrom12x24.fontheight = 24;
502	newsrom12x24.stride = 4;
503	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
504	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
505	newsrom12x24.data = fontarea24;
506
507	ri->ri_font = &newsrom8x16;
508	ri->ri_font = &newsrom12x24;
509	ri->ri_wsfcookie = -1;		/* not using wsfont */
510}
511#endif
512