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