1 /* $NetBSD: fb.c,v 1.25 2010/05/15 10:01:44 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.25 2010/05/15 10:01:44 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_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 273 paddr_t 274 fb_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 285 int 286 fb_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 305 void 306 fb_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 316 int 317 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 318 void *cbarg) 319 { 320 321 return 0; 322 } 323 324 void 325 fb_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 341 static const uint8_t 342 nwp512_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 359 static const uint8_t 360 nwp512_data2[] = { 361 0x1e, 0x08, 362 0x20, 0x08, 363 0x21, 0x0d 364 }; 365 366 static const uint8_t 367 nwp518_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 384 static const uint8_t 385 nwp518_data2[] = { 386 0x1e, 0x08, 387 0x20, 0x00, 388 0x21, 0x00 389 }; 390 391 static const uint8_t 392 nwe501_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 409 static const uint8_t 410 nwe501_data2[] = { 411 0x1e, 0x08, 412 0x20, 0x00, 413 0x21, 0x00 414 }; 415 416 static 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 423 static void 424 fb253_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 454 static struct wsdisplay_font newsrom8x16; 455 static struct wsdisplay_font newsrom12x24; 456 static char fontarea16[96][32]; 457 static char fontarea24[96][96]; 458 459 void 460 initfont(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