xref: /netbsd-src/sys/arch/luna68k/dev/lunafb.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: lunafb.c,v 1.15 2007/03/04 06:00:03 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tohru Nishimura.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
40 
41 __KERNEL_RCSID(0, "$NetBSD: lunafb.c,v 1.15 2007/03/04 06:00:03 christos Exp $");
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/conf.h>
46 #include <sys/device.h>
47 #include <sys/ioctl.h>
48 #include <sys/malloc.h>
49 #include <sys/mman.h>
50 #include <sys/proc.h>
51 #include <sys/tty.h>
52 #include <sys/errno.h>
53 #include <sys/buf.h>
54 
55 #include <uvm/uvm_extern.h>
56 
57 #include <dev/rcons/raster.h>
58 #include <dev/wscons/wsconsio.h>
59 #include <dev/wscons/wscons_raster.h>
60 #include <dev/wscons/wsdisplayvar.h>
61 
62 #include <machine/cpu.h>
63 #include <machine/autoconf.h>
64 
65 struct bt454 {
66 	u_int8_t bt_addr;		/* map address register */
67 	u_int8_t bt_cmap;		/* colormap data register */
68 };
69 
70 struct bt458 {
71 	u_int8_t bt_addr;		/* map address register */
72 		unsigned :24;
73 	u_int8_t bt_cmap;		/* colormap data register */
74 		unsigned :24;
75 	u_int8_t bt_ctrl;		/* control register */
76 		unsigned :24;
77 	u_int8_t bt_omap;		/* overlay (cursor) map register */
78 		unsigned :24;
79 };
80 
81 #define	OMFB_RFCNT	0xB1000000	/* video h-origin/v-origin */
82 #define	OMFB_PLANEMASK	0xB1040000	/* planemask register */
83 #define	OMFB_FB_WADDR	0xB1080008	/* common plane */
84 #define	OMFB_FB_RADDR	0xB10C0008	/* plane #0 */
85 #define	OMFB_ROPFUNC	0xB12C0000	/* ROP function code */
86 #define	OMFB_RAMDAC	0xC1100000	/* Bt454/Bt458 RAMDAC */
87 #define	OMFB_SIZE	(0xB1300000 - 0xB1080000 + PAGE_SIZE)
88 
89 struct om_hwdevconfig {
90 	int	dc_wid;			/* width of frame buffer */
91 	int	dc_ht;			/* height of frame buffer */
92 	int	dc_depth;		/* depth, bits per pixel */
93 	int	dc_rowbytes;		/* bytes in a FB scan line */
94 	int	dc_cmsize;		/* colormap size */
95 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
96 	struct raster	dc_raster;	/* raster description */
97 	struct rcons	dc_rcons;	/* raster blitter control info */
98 };
99 
100 struct hwcmap {
101 #define CMAP_SIZE 256
102 	u_int8_t r[CMAP_SIZE];
103 	u_int8_t g[CMAP_SIZE];
104 	u_int8_t b[CMAP_SIZE];
105 };
106 
107 struct omfb_softc {
108 	struct device sc_dev;		/* base device */
109 	struct om_hwdevconfig *sc_dc;	/* device configuration */
110 	struct hwcmap sc_cmap;		/* software copy of colormap */
111 	int nscreens;
112 };
113 
114 static int  omgetcmap __P((struct omfb_softc *, struct wsdisplay_cmap *));
115 static int  omsetcmap __P((struct omfb_softc *, struct wsdisplay_cmap *));
116 
117 static struct om_hwdevconfig omfb_console_dc;
118 static void omfb_getdevconfig __P((paddr_t, struct om_hwdevconfig *));
119 
120 extern struct wsdisplay_emulops omfb_emulops;
121 
122 static struct wsscreen_descr omfb_stdscreen = {
123 	"std", 0, 0,
124 	&omfb_emulops,
125 	0, 0,
126 	0
127 };
128 
129 static const struct wsscreen_descr *_omfb_scrlist[] = {
130 	&omfb_stdscreen,
131 };
132 
133 static const struct wsscreen_list omfb_screenlist = {
134 	sizeof(_omfb_scrlist) / sizeof(struct wsscreen_descr *), _omfb_scrlist
135 };
136 
137 static int   omfbioctl __P((void *, void *, u_long, void *, int,
138 		            struct lwp *));
139 static paddr_t omfbmmap __P((void *, void *, off_t, int));
140 static int   omfb_alloc_screen __P((void *, const struct wsscreen_descr *,
141 				      void **, int *, int *, long *));
142 static void  omfb_free_screen __P((void *, void *));
143 static int   omfb_show_screen __P((void *, void *, int,
144 				void (*) (void *, int, int), void *));
145 
146 static const struct wsdisplay_accessops omfb_accessops = {
147 	omfbioctl,
148 	omfbmmap,
149 	omfb_alloc_screen,
150 	omfb_free_screen,
151 	omfb_show_screen,
152 	0 /* load_font */
153 };
154 
155 static int  omfbmatch __P((struct device *, struct cfdata *, void *));
156 static void omfbattach __P((struct device *, struct device *, void *));
157 
158 CFATTACH_DECL(fb, sizeof(struct omfb_softc),
159     omfbmatch, omfbattach, NULL, NULL);
160 extern struct cfdriver fb_cd;
161 
162 extern int hwplanemask;	/* hardware planemask; retrieved at boot */
163 
164 static int omfb_console;
165 int  omfb_cnattach __P((void));
166 
167 static int
168 omfbmatch(parent, cf, aux)
169 	struct device *parent;
170 	struct cfdata *cf;
171 	void *aux;
172 {
173 	struct mainbus_attach_args *ma = aux;
174 
175 	if (strcmp(ma->ma_name, fb_cd.cd_name))
176 		return (0);
177 #if 0	/* XXX badaddr() bombs if no framebuffer is installed */
178 	if (badaddr((void *)ma->ma_addr, 4))
179 		return (0);
180 #else
181 	if (hwplanemask == 0)
182 		return (0);
183 #endif
184 	return (1);
185 }
186 
187 static void
188 omfbattach(parent, self, args)
189 	struct device *parent, *self;
190 	void *args;
191 {
192 	struct omfb_softc *sc = (struct omfb_softc *)self;
193 	struct wsemuldisplaydev_attach_args waa;
194 
195 	if (omfb_console) {
196 		sc->sc_dc = &omfb_console_dc;
197 		sc->nscreens = 1;
198 	}
199 	else {
200 		sc->sc_dc = (struct om_hwdevconfig *)
201 		    malloc(sizeof(struct om_hwdevconfig), M_DEVBUF, M_WAITOK);
202 		omfb_getdevconfig(OMFB_FB_WADDR, sc->sc_dc);
203 	}
204 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
205 	    sc->sc_dc->dc_depth);
206 
207 #if 0	/* WHITE on BLACK */
208 	cm = &sc->sc_cmap;
209 	memset(cm, 255, sizeof(struct hwcmap));
210 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
211 #endif
212 	waa.console = omfb_console;
213 	waa.scrdata = &omfb_screenlist;
214 	waa.accessops = &omfb_accessops;
215 	waa.accesscookie = sc;
216 
217 	config_found(self, &waa, wsemuldisplaydevprint);
218 }
219 
220 /* EXPORT */ int
221 omfb_cnattach()
222 {
223 	struct om_hwdevconfig *dc = &omfb_console_dc;
224 	long defattr;
225 
226 	omfb_getdevconfig(OMFB_FB_WADDR, dc);
227 	(*omfb_emulops.allocattr)(&dc->dc_rcons, 0, 0, 0, &defattr);
228 	wsdisplay_cnattach(&omfb_stdscreen, &dc->dc_rcons, 0, 0, defattr);
229 	omfb_console = 1;
230 	return (0);
231 }
232 
233 static int
234 omfbioctl(v, vs, cmd, data, flag, l)
235 	void *v;
236 	void *vs;
237 	u_long cmd;
238 	void *data;
239 	int flag;
240 	struct lwp *l;
241 {
242 	struct omfb_softc *sc = v;
243 	struct om_hwdevconfig *dc = sc->sc_dc;
244 
245 	switch (cmd) {
246 	case WSDISPLAYIO_GTYPE:
247 		*(u_int *)data = 0x19990927;
248 		return (0);
249 
250 	case WSDISPLAYIO_GINFO:
251 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
252 		wsd_fbip->height = dc->dc_ht;
253 		wsd_fbip->width = dc->dc_wid;
254 		wsd_fbip->depth = dc->dc_depth;
255 		wsd_fbip->cmsize = dc->dc_cmsize;
256 #undef fbt
257 		return (0);
258 
259 	case WSDISPLAYIO_GETCMAP:
260 		return omgetcmap(sc, (struct wsdisplay_cmap *)data);
261 
262 	case WSDISPLAYIO_PUTCMAP:
263 		return omsetcmap(sc, (struct wsdisplay_cmap *)data);
264 
265 	case WSDISPLAYIO_SVIDEO:
266 	case WSDISPLAYIO_GVIDEO:
267 	case WSDISPLAYIO_GCURPOS:
268 	case WSDISPLAYIO_SCURPOS:
269 	case WSDISPLAYIO_GCURMAX:
270 	case WSDISPLAYIO_GCURSOR:
271 	case WSDISPLAYIO_SCURSOR:
272 		break;
273 	}
274 	return (EPASSTHROUGH);
275 }
276 
277 /*
278  * Return the address that would map the given device at the given
279  * offset, allowing for the given protection, or return -1 for error.
280  */
281 static paddr_t
282 omfbmmap(v, vs, offset, prot)
283 	void *v;
284 	void *vs;
285 	off_t offset;
286 	int prot;
287 {
288 	struct omfb_softc *sc = v;
289 
290 	if (offset >= OMFB_SIZE || offset < 0)
291 		return (-1);
292 	return m68k_btop(m68k_trunc_page(sc->sc_dc->dc_videobase) + offset);
293 }
294 
295 static int
296 omgetcmap(sc, p)
297 	struct omfb_softc *sc;
298 	struct wsdisplay_cmap *p;
299 {
300 	u_int index = p->index, count = p->count;
301 	int cmsize, error;
302 
303 	cmsize = sc->sc_dc->dc_cmsize;
304 	if (index >= cmsize || count > cmsize - index)
305 		return (EINVAL);
306 
307 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
308 	if (error)
309 		return error;
310 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
311 	if (error)
312 		return error;
313 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
314 	return error;
315 }
316 
317 static int
318 omsetcmap(sc, p)
319 	struct omfb_softc *sc;
320 	struct wsdisplay_cmap *p;
321 {
322 	struct hwcmap cmap;
323 	u_int index = p->index, count = p->count;
324 	int cmsize, i, error;
325 
326 	cmsize = sc->sc_dc->dc_cmsize;
327 	if (index >= cmsize || (index + count) > cmsize)
328 		return (EINVAL);
329 
330 	error = copyin(p->red, &cmap.r[index], count);
331 	if (error)
332 		return error;
333 	error = copyin(p->green, &cmap.g[index], count);
334 	if (error)
335 		return error;
336 	error = copyin(p->blue, &cmap.b[index], count);
337 	if (error)
338 		return error;
339 
340 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
341 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
342 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
343 	if (hwplanemask == 0x0f) {
344 		struct bt454 *odac = (struct bt454 *)OMFB_RAMDAC;
345 		odac->bt_addr = index;
346 		for (i = index; i < count; i++) {
347 			odac->bt_cmap = sc->sc_cmap.r[i];
348 			odac->bt_cmap = sc->sc_cmap.g[i];
349 			odac->bt_cmap = sc->sc_cmap.b[i];
350 		}
351 	}
352 	else if (hwplanemask == 0xff) {
353 		struct bt458 *ndac = (struct bt458 *)OMFB_RAMDAC;
354 		ndac->bt_addr = index;
355 		for (i = index; i < count; i++) {
356 			ndac->bt_cmap = sc->sc_cmap.r[i];
357 			ndac->bt_cmap = sc->sc_cmap.g[i];
358 			ndac->bt_cmap = sc->sc_cmap.b[i];
359 		}
360 	}
361 	return (0);
362 }
363 
364 static void
365 omfb_getdevconfig(paddr, dc)
366 	paddr_t paddr;
367 	struct om_hwdevconfig *dc;
368 {
369 	int bpp, i;
370 	struct raster *rap;
371 	struct rcons *rcp;
372 	union {
373 		struct { short h, v; } p;
374 		u_int32_t u;
375 	} rfcnt;
376 
377 	switch (hwplanemask) {
378 	case 0xff:
379 		bpp = 8;	/* XXX check monochrome bit in DIPSW */
380 		break;
381 	default:
382 	case 0x0f:
383 		bpp = 4;	/* XXX check monochrome bit in DIPSW */
384 		break;
385 	case 1:
386 		bpp = 1;
387 		break;
388 	}
389 	dc->dc_wid = 1280;
390 	dc->dc_ht = 1024;
391 	dc->dc_depth = bpp;
392 	dc->dc_rowbytes = 2048 / 8;
393 	dc->dc_cmsize = (bpp == 1) ? 0 : 1 << bpp;
394 	dc->dc_videobase = paddr;
395 
396 #if 0 /* WHITE on BLACK XXX experiment resulted in WHITE on SKYBLUE... */
397 	if (hwplanemask == 0x0f) {
398 		/* XXX Need Bt454 initialization */
399 		struct bt454 *odac = (struct bt454 *)OMFB_RAMDAC;
400 		odac->bt_addr = 0;
401 		odac->bt_cmap = 0;
402 		odac->bt_cmap = 0;
403 		odac->bt_cmap = 0;
404 		for (i = 1; i < 16; i++) {
405 			odac->bt_cmap = 255;
406 			odac->bt_cmap = 255;
407 			odac->bt_cmap = 255;
408 		}
409 	}
410 	else if (hwplanemask == 0xff) {
411 		struct bt458 *ndac = (struct bt458 *)OMFB_RAMDAC;
412 
413 		ndac->bt_addr = 0x04;
414 		ndac->bt_ctrl = 0xff; /* all planes will be read */
415 		ndac->bt_ctrl = 0x00; /* all planes have non-blink */
416 		ndac->bt_ctrl = 0x43; /* pallete enabled, ovly plane */
417 		ndac->bt_ctrl = 0x00; /* no test mode */
418 		ndac->bt_addr = 0;
419 		ndac->bt_cmap = 0;
420 		ndac->bt_cmap = 0;
421 		ndac->bt_cmap = 0;
422 		for (i = 1; i < 256; i++) {
423 			ndac->bt_cmap = 255;
424 			ndac->bt_cmap = 255;
425 			ndac->bt_cmap = 255;
426 		}
427 	}
428 #endif
429 
430 	/* adjust h/v orgin on screen */
431 	rfcnt.p.h = 7;
432 	rfcnt.p.v = -27;
433 	*(u_int32_t *)OMFB_RFCNT = rfcnt.u; /* single write of 0x007ffe6 */
434 
435 	/* clear the screen */
436 	*(u_int32_t *)OMFB_PLANEMASK = 0xff;
437 	((u_int32_t *)OMFB_ROPFUNC)[5] = ~0;	/* ROP copy */
438 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes/sizeof(u_int32_t); i++)
439 		*((u_int32_t *)dc->dc_videobase + i) = 0;
440 	*(u_int32_t *)OMFB_PLANEMASK = 0x01;
441 
442 	/* initialize the raster */
443 	rap = &dc->dc_raster;
444 	rap->width = dc->dc_wid;
445 	rap->height = dc->dc_ht;
446 	rap->depth = dc->dc_depth;
447 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
448 	rap->pixels = (u_int32_t *)dc->dc_videobase;
449 
450 	/* initialize the raster console blitter */
451 	rcp = &dc->dc_rcons;
452 	rcp->rc_sp = rap;
453 	rcp->rc_crow = rcp->rc_ccol = -1;
454 	rcp->rc_crowp = &rcp->rc_crow;
455 	rcp->rc_ccolp = &rcp->rc_ccol;
456 	rcons_init(rcp, 34, 80);
457 
458 	omfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
459 	omfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
460 }
461 
462 static int
463 omfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
464 	void *v;
465 	const struct wsscreen_descr *type;
466 	void **cookiep;
467 	int *curxp, *curyp;
468 	long *attrp;
469 {
470 	struct omfb_softc *sc = v;
471 	long defattr;
472 
473 	if (sc->nscreens > 0)
474 		return (ENOMEM);
475 
476 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
477 	*curxp = 0;
478 	*curyp = 0;
479 	(*omfb_emulops.allocattr)(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
480 	*attrp = defattr;
481 	sc->nscreens++;
482 	return (0);
483 }
484 
485 static void
486 omfb_free_screen(v, cookie)
487 	void *v;
488 	void *cookie;
489 {
490 	struct omfb_softc *sc = v;
491 
492 	if (sc->sc_dc == &omfb_console_dc)
493 		panic("omfb_free_screen: console");
494 
495 	sc->nscreens--;
496 }
497 
498 static int
499 omfb_show_screen(v, cookie, waitok, cb, cbarg)
500 	void *v;
501 	void *cookie;
502 	int waitok;
503 	void (*cb) __P((void *, int, int));
504 	void *cbarg;
505 {
506 	return 0;
507 }
508