Home | History | Annotate | Line # | Download | only in dev
fb.c revision 1.26
      1 /*	$NetBSD: fb.c,v 1.26 2014/01/31 15:43:06 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.26 2014/01/31 15:43:06 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 
     48 struct fb_devconfig {
     49 	u_char *dc_fbbase;		/* VRAM base address */
     50 	struct rasops_info dc_ri;
     51 };
     52 
     53 struct fb_softc {
     54 	device_t sc_dev;
     55 	struct fb_devconfig *sc_dc;
     56 	int sc_nscreens;
     57 };
     58 
     59 int fb_match(device_t, cfdata_t, void *);
     60 void fb_attach(device_t, device_t, void *);
     61 
     62 int fb_common_init(struct fb_devconfig *);
     63 int fb_is_console(void);
     64 
     65 int fb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
     66 paddr_t fb_mmap(void *, void *, off_t, int);
     67 int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
     68     int *, long *);
     69 void fb_free_screen(void *, void *);
     70 int fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
     71 
     72 void fb_cnattach(void);
     73 
     74 static void fb253_init(void);
     75 
     76 CFATTACH_DECL_NEW(fb, sizeof(struct fb_softc),
     77     fb_match, fb_attach, NULL, NULL);
     78 
     79 struct fb_devconfig fb_console_dc;
     80 
     81 struct 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 
     90 struct wsscreen_descr fb_stdscreen = {
     91 	"std",
     92 	0, 0,
     93 	0,
     94 	0, 0,
     95 	WSSCREEN_REVERSE
     96 };
     97 
     98 const struct wsscreen_descr *fb_scrlist[] = {
     99 	&fb_stdscreen
    100 };
    101 
    102 struct 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 
    110 static const char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" }; /* XXX ? */
    111 
    112 int
    113 fb_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 
    128 void
    129 fb_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 
    175 int
    176 fb_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 
    227 int
    228 fb_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 
    238 int
    239 fb_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_LINEBYTES:
    259 		*(u_int *)data = dc->dc_ri.ri_stride;
    260 		return 0;
    261 
    262 	case WSDISPLAYIO_SVIDEO:
    263 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
    264 			volatile u_short *ctlreg = NWB253_CTLREG;
    265 			*ctlreg = 0;			/* stop crtc */
    266 		} else
    267 			fb253_init();
    268 		return 0;
    269 
    270 	case WSDISPLAYIO_GETCMAP:
    271 	case WSDISPLAYIO_PUTCMAP:
    272 		break;
    273 	}
    274 	return EPASSTHROUGH;
    275 }
    276 
    277 paddr_t
    278 fb_mmap(void *v, void *vs, off_t offset, int prot)
    279 {
    280 	struct fb_softc *sc = v;
    281 	struct fb_devconfig *dc = sc->sc_dc;
    282 
    283 	if (offset >= 2048 * 2048 / 8 || offset < 0)
    284 		return -1;
    285 
    286 	return mips_btop((int)dc->dc_fbbase + offset);
    287 }
    288 
    289 int
    290 fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep,
    291     int *ccolp, int *crowp, long *attrp)
    292 {
    293 	struct fb_softc *sc = v;
    294 	struct rasops_info *ri = &sc->sc_dc->dc_ri;
    295 	long defattr;
    296 
    297 	if (sc->sc_nscreens > 0)
    298 		return ENOMEM;
    299 
    300 	*cookiep = ri;
    301 	*ccolp = *crowp = 0;
    302 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    303 	*attrp = defattr;
    304 	sc->sc_nscreens++;
    305 
    306 	return 0;
    307 }
    308 
    309 void
    310 fb_free_screen(void *v, void *cookie)
    311 {
    312 	struct fb_softc *sc = v;
    313 
    314 	if (sc->sc_dc == &fb_console_dc)
    315 		panic("%s: console", __func__);
    316 
    317 	sc->sc_nscreens--;
    318 }
    319 
    320 int
    321 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
    322     void *cbarg)
    323 {
    324 
    325 	return 0;
    326 }
    327 
    328 void
    329 fb_cnattach(void)
    330 {
    331 	struct fb_devconfig *dc = &fb_console_dc;
    332 	struct rasops_info *ri = &dc->dc_ri;
    333 	long defattr;
    334 
    335 	if (!fb_is_console())
    336 		return;
    337 
    338 	dc->dc_fbbase = NWB253_VRAM;
    339 	fb_common_init(dc);
    340 
    341 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    342 	wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
    343 }
    344 
    345 static const uint8_t
    346 nwp512_data1[] = {
    347 	0x00, 0x44,
    348 	0x01, 0x33,
    349 	0x02, 0x3c,
    350 	0x03, 0x38,
    351 	0x04, 0x84,
    352 	0x05, 0x03,
    353 	0x06, 0x80,
    354 	0x07, 0x80,
    355 	0x08, 0x10,
    356 	0x09, 0x07,
    357 	0x0a, 0x20,
    358 	0x0c, 0x00,
    359 	0x0d, 0x00,
    360 	0x1b, 0x03
    361 };
    362 
    363 static const uint8_t
    364 nwp512_data2[] = {
    365 	0x1e, 0x08,
    366 	0x20, 0x08,
    367 	0x21, 0x0d
    368 };
    369 
    370 static const uint8_t
    371 nwp518_data1[] = {
    372 	0x00, 0x52,
    373 	0x01, 0x40,
    374 	0x02, 0x4a,
    375 	0x03, 0x49,
    376 	0x04, 0x63,
    377 	0x05, 0x02,
    378 	0x06, 0x60,
    379 	0x07, 0x60,
    380 	0x08, 0x10,
    381 	0x09, 0x07,
    382 	0x0a, 0x20,
    383 	0x0c, 0x00,
    384 	0x0d, 0x00,
    385 	0x1b, 0x04
    386 };
    387 
    388 static const uint8_t
    389 nwp518_data2[] = {
    390 	0x1e, 0x08,
    391 	0x20, 0x00,
    392 	0x21, 0x00
    393 };
    394 
    395 static const uint8_t
    396 nwe501_data1[] = {
    397 	0x00, 0x4b,
    398 	0x01, 0x40,
    399 	0x02, 0x4a,
    400 	0x03, 0x43,
    401 	0x04, 0x64,
    402 	0x05, 0x02,
    403 	0x06, 0x60,
    404 	0x07, 0x60,
    405 	0x08, 0x10,
    406 	0x09, 0x07,
    407 	0x0a, 0x20,
    408 	0x0c, 0x00,
    409 	0x0d, 0x00,
    410 	0x1b, 0x04
    411 };
    412 
    413 static const uint8_t
    414 nwe501_data2[] = {
    415 	0x1e, 0x08,
    416 	0x20, 0x00,
    417 	0x21, 0x00
    418 };
    419 
    420 static const uint8_t
    421 *crtc_data[3][2] = {
    422 	{ nwp512_data1, nwp512_data2 },
    423 	{ nwp518_data1, nwp518_data2 },
    424 	{ nwe501_data1, nwe501_data2 }
    425 };
    426 
    427 static void
    428 fb253_init(void)
    429 {
    430 	volatile uint16_t *ctlreg = NWB253_CTLREG;
    431 	volatile uint16_t *crtreg = NWB253_CRTREG;
    432 	int id = (*ctlreg >> 8) & 0xf;
    433 	const uint8_t *p;
    434 	int i;
    435 
    436 	*ctlreg = 0;			/* stop crtc */
    437 	delay(10);
    438 
    439 	/* initialize crtc without R3{0,1,2} */
    440 	p = crtc_data[id][0];
    441 	for (i = 0; i < 28; i++) {
    442 		*crtreg++ = *p++;
    443 		delay(10);
    444 	}
    445 
    446 	*ctlreg = 0x02;			/* start crtc */
    447 	delay(10);
    448 
    449 	/* set crtc control reg */
    450 	p = crtc_data[id][1];
    451 	for (i = 0; i < 6; i++) {
    452 		*crtreg++ = *p++;
    453 		delay(10);
    454 	}
    455 }
    456 
    457 #if 0
    458 static struct wsdisplay_font newsrom8x16;
    459 static struct wsdisplay_font newsrom12x24;
    460 static char fontarea16[96][32];
    461 static char fontarea24[96][96];
    462 
    463 void
    464 initfont(struct rasops_info *ri)
    465 {
    466 	int c, x;
    467 
    468 	for (c = 0; c < 96; c++) {
    469 		x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
    470 		memcpy(fontarea16 + c, (char *)0xb8e00000 + x + 96, 32);
    471 		memcpy(fontarea24 + c, (char *)0xb8e00000 + x, 96);
    472 	}
    473 
    474 	newsrom8x16.name = "rom8x16";
    475 	newsrom8x16.firstchar = 32;
    476 	newsrom8x16.numchars = 96;
    477 	newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
    478 	newsrom8x16.fontwidth = 8;
    479 	newsrom8x16.fontheight = 16;
    480 	newsrom8x16.stride = 2;
    481 	newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
    482 	newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
    483 	newsrom8x16.data = fontarea16;
    484 
    485 	newsrom12x24.name = "rom12x24";
    486 	newsrom12x24.firstchar = 32;
    487 	newsrom12x24.numchars = 96;
    488 	newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
    489 	newsrom12x24.fontwidth = 12;
    490 	newsrom12x24.fontheight = 24;
    491 	newsrom12x24.stride = 4;
    492 	newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
    493 	newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
    494 	newsrom12x24.data = fontarea24;
    495 
    496 	ri->ri_font = &newsrom8x16;
    497 	ri->ri_font = &newsrom12x24;
    498 	ri->ri_wsfcookie = -1;		/* not using wsfont */
    499 }
    500 #endif
    501