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