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