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