fb.c revision 1.27
1/*	$NetBSD: fb.c,v 1.27 2020/11/21 17:54:47 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/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.27 2020/11/21 17:54:47 thorpej Exp $");
31
32#include <sys/param.h>
33#include <sys/device.h>
34#include <sys/ioctl.h>
35#include <sys/kmem.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 = kmem_zalloc(sizeof(struct fb_devconfig), KM_SLEEP);
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	aprint_normal(": %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(struct fb_devconfig *dc)
176{
177	struct rasops_info *ri = &dc->dc_ri;
178	volatile uint16_t *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	default:
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	if (dc == &fb_console_dc)
205		ri->ri_flg |= RI_NO_AUTO;
206
207	rasops_init(ri, 24, 80);
208	rows = (height - 2) / ri->ri_font->fontheight;
209	cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
210	xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
211	yoff = (height - rows * ri->ri_font->fontheight) / 2;
212	rasops_reconfig(ri, rows, cols);
213
214	ri->ri_xorigin = xoff;
215	ri->ri_yorigin = yoff;
216	ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
217
218	fb_stdscreen.nrows = ri->ri_rows;
219	fb_stdscreen.ncols = ri->ri_cols;
220	fb_stdscreen.textops = &ri->ri_ops;
221	fb_stdscreen.capabilities = ri->ri_caps;
222
223	return 0;
224}
225
226int
227fb_is_console(void)
228{
229	volatile u_int *dipsw = (void *)DIP_SWITCH;
230
231	if (*dipsw & 7)					/* XXX right? */
232		return 1;
233
234	return 0;
235}
236
237int
238fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
239{
240	struct fb_softc *sc = v;
241	struct fb_devconfig *dc = sc->sc_dc;
242	struct wsdisplay_fbinfo *wdf;
243
244	switch (cmd) {
245	case WSDISPLAYIO_GTYPE:
246		*(int *)data = WSDISPLAY_TYPE_UNKNOWN;	/* XXX */
247		return 0;
248
249	case WSDISPLAYIO_GINFO:
250		wdf = (void *)data;
251		wdf->height = dc->dc_ri.ri_height;
252		wdf->width = dc->dc_ri.ri_width;
253		wdf->depth = dc->dc_ri.ri_depth;
254		wdf->cmsize = 2;
255		return 0;
256
257	case WSDISPLAYIO_LINEBYTES:
258		*(u_int *)data = dc->dc_ri.ri_stride;
259		return 0;
260
261	case WSDISPLAYIO_SVIDEO:
262		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
263			volatile u_short *ctlreg = NWB253_CTLREG;
264			*ctlreg = 0;			/* stop crtc */
265		} else
266			fb253_init();
267		return 0;
268
269	case WSDISPLAYIO_GETCMAP:
270	case WSDISPLAYIO_PUTCMAP:
271		break;
272	}
273	return EPASSTHROUGH;
274}
275
276paddr_t
277fb_mmap(void *v, void *vs, off_t offset, int prot)
278{
279	struct fb_softc *sc = v;
280	struct fb_devconfig *dc = sc->sc_dc;
281
282	if (offset >= 2048 * 2048 / 8 || offset < 0)
283		return -1;
284
285	return mips_btop((int)dc->dc_fbbase + offset);
286}
287
288int
289fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep,
290    int *ccolp, int *crowp, long *attrp)
291{
292	struct fb_softc *sc = v;
293	struct rasops_info *ri = &sc->sc_dc->dc_ri;
294	long defattr;
295
296	if (sc->sc_nscreens > 0)
297		return ENOMEM;
298
299	*cookiep = ri;
300	*ccolp = *crowp = 0;
301	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
302	*attrp = defattr;
303	sc->sc_nscreens++;
304
305	return 0;
306}
307
308void
309fb_free_screen(void *v, void *cookie)
310{
311	struct fb_softc *sc = v;
312
313	if (sc->sc_dc == &fb_console_dc)
314		panic("%s: console", __func__);
315
316	sc->sc_nscreens--;
317}
318
319int
320fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
321    void *cbarg)
322{
323
324	return 0;
325}
326
327void
328fb_cnattach(void)
329{
330	struct fb_devconfig *dc = &fb_console_dc;
331	struct rasops_info *ri = &dc->dc_ri;
332	long defattr;
333
334	if (!fb_is_console())
335		return;
336
337	dc->dc_fbbase = NWB253_VRAM;
338	fb_common_init(dc);
339
340	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
341	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
342}
343
344static const uint8_t
345nwp512_data1[] = {
346	0x00, 0x44,
347	0x01, 0x33,
348	0x02, 0x3c,
349	0x03, 0x38,
350	0x04, 0x84,
351	0x05, 0x03,
352	0x06, 0x80,
353	0x07, 0x80,
354	0x08, 0x10,
355	0x09, 0x07,
356	0x0a, 0x20,
357	0x0c, 0x00,
358	0x0d, 0x00,
359	0x1b, 0x03
360};
361
362static const uint8_t
363nwp512_data2[] = {
364	0x1e, 0x08,
365	0x20, 0x08,
366	0x21, 0x0d
367};
368
369static const uint8_t
370nwp518_data1[] = {
371	0x00, 0x52,
372	0x01, 0x40,
373	0x02, 0x4a,
374	0x03, 0x49,
375	0x04, 0x63,
376	0x05, 0x02,
377	0x06, 0x60,
378	0x07, 0x60,
379	0x08, 0x10,
380	0x09, 0x07,
381	0x0a, 0x20,
382	0x0c, 0x00,
383	0x0d, 0x00,
384	0x1b, 0x04
385};
386
387static const uint8_t
388nwp518_data2[] = {
389	0x1e, 0x08,
390	0x20, 0x00,
391	0x21, 0x00
392};
393
394static const uint8_t
395nwe501_data1[] = {
396	0x00, 0x4b,
397	0x01, 0x40,
398	0x02, 0x4a,
399	0x03, 0x43,
400	0x04, 0x64,
401	0x05, 0x02,
402	0x06, 0x60,
403	0x07, 0x60,
404	0x08, 0x10,
405	0x09, 0x07,
406	0x0a, 0x20,
407	0x0c, 0x00,
408	0x0d, 0x00,
409	0x1b, 0x04
410};
411
412static const uint8_t
413nwe501_data2[] = {
414	0x1e, 0x08,
415	0x20, 0x00,
416	0x21, 0x00
417};
418
419static const uint8_t
420*crtc_data[3][2] = {
421	{ nwp512_data1, nwp512_data2 },
422	{ nwp518_data1, nwp518_data2 },
423	{ nwe501_data1, nwe501_data2 }
424};
425
426static void
427fb253_init(void)
428{
429	volatile uint16_t *ctlreg = NWB253_CTLREG;
430	volatile uint16_t *crtreg = NWB253_CRTREG;
431	int id = (*ctlreg >> 8) & 0xf;
432	const uint8_t *p;
433	int i;
434
435	*ctlreg = 0;			/* stop crtc */
436	delay(10);
437
438	/* initialize crtc without R3{0,1,2} */
439	p = crtc_data[id][0];
440	for (i = 0; i < 28; i++) {
441		*crtreg++ = *p++;
442		delay(10);
443	}
444
445	*ctlreg = 0x02;			/* start crtc */
446	delay(10);
447
448	/* set crtc control reg */
449	p = crtc_data[id][1];
450	for (i = 0; i < 6; i++) {
451		*crtreg++ = *p++;
452		delay(10);
453	}
454}
455
456#if 0
457static struct wsdisplay_font newsrom8x16;
458static struct wsdisplay_font newsrom12x24;
459static char fontarea16[96][32];
460static char fontarea24[96][96];
461
462void
463initfont(struct rasops_info *ri)
464{
465	int c, x;
466
467	for (c = 0; c < 96; c++) {
468		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
469		memcpy(fontarea16 + c, (char *)0xb8e00000 + x + 96, 32);
470		memcpy(fontarea24 + c, (char *)0xb8e00000 + x, 96);
471	}
472
473	newsrom8x16.name = "rom8x16";
474	newsrom8x16.firstchar = 32;
475	newsrom8x16.numchars = 96;
476	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
477	newsrom8x16.fontwidth = 8;
478	newsrom8x16.fontheight = 16;
479	newsrom8x16.stride = 2;
480	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
481	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
482	newsrom8x16.data = fontarea16;
483
484	newsrom12x24.name = "rom12x24";
485	newsrom12x24.firstchar = 32;
486	newsrom12x24.numchars = 96;
487	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
488	newsrom12x24.fontwidth = 12;
489	newsrom12x24.fontheight = 24;
490	newsrom12x24.stride = 4;
491	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
492	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
493	newsrom12x24.data = fontarea24;
494
495	ri->ri_font = &newsrom8x16;
496	ri->ri_font = &newsrom12x24;
497	ri->ri_wsfcookie = -1;		/* not using wsfont */
498}
499#endif
500