1 /* $OpenBSD: rfx.c,v 1.12 2014/01/22 03:03:09 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2004, Miodrag Vallat. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 /* 31 * Driver for the Vitec RasterFlex family of frame buffers. 32 * It should support RasterFlex-24, RasterFlex-32 and RasterFlex-HR. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/buf.h> 38 #include <sys/device.h> 39 #include <sys/ioctl.h> 40 #include <sys/malloc.h> 41 #include <sys/mman.h> 42 #include <sys/tty.h> 43 #include <sys/conf.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #include <machine/autoconf.h> 48 #include <machine/pmap.h> 49 #include <machine/cpu.h> 50 #include <machine/conf.h> 51 #include <machine/openfirm.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 #include <dev/rasops/rasops.h> 56 #include <machine/fbvar.h> 57 58 #include <dev/sbus/sbusvar.h> 59 60 #include <dev/ic/bt463reg.h> 61 62 /* 63 * Configuration structure 64 */ 65 struct rfx_config { 66 u_int16_t unknown; 67 u_int16_t version; 68 u_int32_t scanline; 69 u_int32_t maxwidth; /* unsure */ 70 u_int32_t maxheight; /* unsure */ 71 u_int32_t width; 72 u_int32_t height; 73 }; 74 75 /* 76 * In-memory offsets 77 */ 78 79 #define RFX_RAMDAC_ADDR 0x00020000 80 #define RFX_RAMDAC_SIZE 0x00000004 81 82 #define RFX_CONTROL_ADDR 0x00040000 83 #define RFX_CONTROL_SIZE 0x000000e0 84 85 #define RFX_INIT_ADDR 0x00018000 86 #define RFX_INIT_OFFSET 0x0000001c 87 #define RFX_INIT_SIZE 0x00008000 88 89 #define RFX_VRAM_ADDR 0x00100000 90 91 /* 92 * Control registers 93 */ 94 95 #define RFX_VIDCTRL_REG 0x10 96 #define RFX_VSYNC_ENABLE 0x00000001 97 #define RFX_VIDEO_DISABLE 0x00000002 98 99 /* 100 * Shadow colormap 101 */ 102 struct rfx_cmap { 103 u_int8_t red[256]; 104 u_int8_t green[256]; 105 u_int8_t blue[256]; 106 }; 107 108 struct rfx_softc { 109 struct sunfb sc_sunfb; 110 111 bus_space_tag_t sc_bustag; 112 bus_addr_t sc_paddr; 113 114 struct intrhand sc_ih; 115 116 struct rfx_cmap sc_cmap; 117 volatile u_int8_t *sc_ramdac; 118 volatile u_int32_t *sc_ctrl; 119 120 int sc_nscreens; 121 }; 122 123 void rfx_burner(void *, u_int, u_int); 124 int rfx_ioctl(void *, u_long, caddr_t, int, struct proc *); 125 paddr_t rfx_mmap(void *, off_t, int); 126 127 int rfx_getcmap(struct rfx_cmap *, struct wsdisplay_cmap *); 128 int rfx_initialize(struct rfx_softc *, struct sbus_attach_args *, 129 struct rfx_config *); 130 int rfx_intr(void *); 131 void rfx_loadcmap(struct rfx_softc *, int, int); 132 int rfx_putcmap(struct rfx_cmap *, struct wsdisplay_cmap *); 133 void rfx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 134 135 struct wsdisplay_accessops rfx_accessops = { 136 .ioctl = rfx_ioctl, 137 .mmap = rfx_mmap, 138 .burn_screen = rfx_burner 139 }; 140 141 int rfxmatch(struct device *, void *, void *); 142 void rfxattach(struct device *, struct device *, void *); 143 144 #if defined(OpenBSD) 145 struct cfattach rfx_ca = { 146 sizeof (struct rfx_softc), rfxmatch, rfxattach 147 }; 148 149 struct cfdriver rfx_cd = { 150 NULL, "rfx", DV_DULL 151 }; 152 #else 153 CFATTACH_DECL(rfx, sizeof (struct rfx_softc), rfxmatch, rfxattach, NULL, NULL); 154 #endif 155 156 /* 157 * Match a supported RasterFlex card. 158 */ 159 int 160 rfxmatch(struct device *parent, void *vcf, void *aux) 161 { 162 struct sbus_attach_args *sa = aux; 163 const char *device = sa->sa_name; 164 165 /* skip vendor name (could be CWARE, VITec, ...) */ 166 while (*device != ',' && *device != '\0') 167 device++; 168 if (*device == '\0') 169 device = sa->sa_name; 170 else 171 device++; 172 173 if (strncmp(device, "RasterFLEX", strlen("RasterFLEX")) != 0) 174 return (0); 175 176 /* RasterVideo and RasterFlex-TV are frame grabbers */ 177 if (strcmp(device, "RasterFLEX-TV") == 0) 178 return (0); 179 180 return (1); 181 } 182 183 /* 184 * Attach and initialize a rfx display, as well as a child wsdisplay. 185 */ 186 void 187 rfxattach(struct device *parent, struct device *self, void *args) 188 { 189 struct rfx_softc *sc = (struct rfx_softc *)self; 190 struct sbus_attach_args *sa = args; 191 const char *device = sa->sa_name; 192 struct rfx_config cf; 193 bus_space_tag_t bt; 194 bus_space_handle_t bh; 195 int node, cflen, isconsole = 0; 196 197 /* skip vendor name (could be CWARE, VITec, ...) */ 198 while (*device != ',' && *device != '\0') 199 device++; 200 if (*device == '\0') 201 device = sa->sa_name; 202 else 203 device++; 204 205 printf(": %s", device); 206 207 if (sa->sa_nreg == 0) { 208 printf("\n%s: no SBus registers!\n", self->dv_xname); 209 return; 210 } 211 212 bt = sa->sa_bustag; 213 node = sa->sa_node; 214 isconsole = node == fbnode; 215 216 /* 217 * Parse configuration structure 218 */ 219 cflen = getproplen(node, "configuration"); 220 if (cflen != sizeof cf) { 221 printf(", unknown %d bytes conf. structure", cflen); 222 /* fill in default values */ 223 cf.version = 0; 224 cf.scanline = 2048; 225 cf.width = 1152; 226 cf.height = 900; 227 } else { 228 OF_getprop(node, "configuration", &cf, cflen); 229 printf(", revision %d", cf.version); 230 } 231 232 /* 233 * Map registers 234 */ 235 236 sc->sc_bustag = bt; 237 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset); 238 239 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_RAMDAC_ADDR, 240 RFX_RAMDAC_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 241 printf("\n%s: couldn't map ramdac registers\n", self->dv_xname); 242 return; 243 } 244 sc->sc_ramdac = (u_int8_t *)bus_space_vaddr(bt, bh); 245 246 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_CONTROL_ADDR, 247 RFX_CONTROL_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 248 printf("\n%s: couldn't map control registers\n", self->dv_xname); 249 return; 250 } 251 sc->sc_ctrl = (u_int32_t *)bus_space_vaddr(bt, bh); 252 253 #if 0 /* not yet */ 254 sc->sc_ih.ih_fun = rfx_intr; 255 sc->sc_ih.ih_arg = sc; 256 intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB); 257 #endif 258 259 /* 260 * The following is an equivalent for 261 * fb_setsize(&sc->sc_sunfb, 8, cf.width, cf.height, 262 * node, ca->ca_bustype); 263 * forcing the correct scan line value. Since the usual frame buffer 264 * properties are missing on this card, no need to go through 265 * fb_setsize()... 266 */ 267 sc->sc_sunfb.sf_depth = 8; 268 sc->sc_sunfb.sf_width = cf.width; 269 sc->sc_sunfb.sf_height = cf.height; 270 sc->sc_sunfb.sf_linebytes = cf.scanline; 271 sc->sc_sunfb.sf_fbsize = cf.height * cf.scanline; 272 273 printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 274 275 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_VRAM_ADDR, 276 round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 277 0, &bh) != 0) { 278 printf("\n%s: couldn't map video memory\n", self->dv_xname); 279 return; 280 } 281 sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); 282 sc->sc_sunfb.sf_ro.ri_hw = sc; 283 284 /* 285 * If we are not the console, the frame buffer has not been 286 * initialized by the PROM - do this ourselves. 287 */ 288 if (!isconsole) { 289 if (rfx_initialize(sc, sa, &cf) != 0) 290 return; 291 } 292 293 fbwscons_init(&sc->sc_sunfb, 0, isconsole); 294 295 bzero(&sc->sc_cmap, sizeof(sc->sc_cmap)); 296 fbwscons_setcolormap(&sc->sc_sunfb, rfx_setcolor); 297 298 if (isconsole) 299 fbwscons_console_init(&sc->sc_sunfb, -1); 300 301 /* enable video */ 302 rfx_burner(sc, 1, 0); 303 304 fbwscons_attach(&sc->sc_sunfb, &rfx_accessops, isconsole); 305 } 306 307 /* 308 * Common wsdisplay operations 309 */ 310 311 int 312 rfx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 313 { 314 struct rfx_softc *sc = v; 315 struct wsdisplay_cmap *cm; 316 struct wsdisplay_fbinfo *wdf; 317 int error; 318 319 switch (cmd) { 320 case WSDISPLAYIO_GTYPE: 321 *(u_int *)data = WSDISPLAY_TYPE_RFLEX; 322 break; 323 case WSDISPLAYIO_GINFO: 324 wdf = (struct wsdisplay_fbinfo *)data; 325 wdf->height = sc->sc_sunfb.sf_height; 326 wdf->width = sc->sc_sunfb.sf_width; 327 wdf->depth = sc->sc_sunfb.sf_depth; 328 wdf->cmsize = 256; 329 break; 330 case WSDISPLAYIO_LINEBYTES: 331 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 332 break; 333 334 case WSDISPLAYIO_GETCMAP: 335 cm = (struct wsdisplay_cmap *)data; 336 error = rfx_getcmap(&sc->sc_cmap, cm); 337 if (error != 0) 338 return (error); 339 break; 340 case WSDISPLAYIO_PUTCMAP: 341 cm = (struct wsdisplay_cmap *)data; 342 error = rfx_putcmap(&sc->sc_cmap, cm); 343 if (error != 0) 344 return (error); 345 rfx_loadcmap(sc, cm->index, cm->count); 346 break; 347 348 case WSDISPLAYIO_SVIDEO: 349 case WSDISPLAYIO_GVIDEO: 350 break; 351 352 default: 353 return (-1); 354 } 355 356 return (0); 357 } 358 359 paddr_t 360 rfx_mmap(void *v, off_t offset, int prot) 361 { 362 struct rfx_softc *sc = v; 363 364 if (offset & PGOFSET) 365 return (-1); 366 367 if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { 368 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 369 RFX_VRAM_ADDR + offset, prot, BUS_SPACE_MAP_LINEAR)); 370 } 371 372 return (-1); 373 } 374 375 void 376 rfx_burner(void *v, u_int on, u_int flags) 377 { 378 struct rfx_softc *sc = v; 379 380 if (on) { 381 sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VIDEO_DISABLE; 382 sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VSYNC_ENABLE; 383 } else { 384 sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VIDEO_DISABLE; 385 if (flags & WSDISPLAY_BURN_VBLANK) 386 sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VSYNC_ENABLE; 387 } 388 } 389 390 /* 391 * Colormap helper functions 392 */ 393 394 void 395 rfx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 396 { 397 struct rfx_softc *sc = v; 398 399 sc->sc_cmap.red[index] = r; 400 sc->sc_cmap.green[index] = g; 401 sc->sc_cmap.blue[index] = b; 402 403 rfx_loadcmap(sc, index, 1); 404 } 405 406 int 407 rfx_getcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm) 408 { 409 u_int index = rcm->index, count = rcm->count; 410 int error; 411 412 if (index >= 256 || count > 256 - index) 413 return (EINVAL); 414 415 if ((error = copyout(cm->red + index, rcm->red, count)) != 0) 416 return (error); 417 if ((error = copyout(cm->green + index, rcm->green, count)) != 0) 418 return (error); 419 if ((error = copyout(cm->blue + index, rcm->blue, count)) != 0) 420 return (error); 421 422 return (0); 423 } 424 425 int 426 rfx_putcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm) 427 { 428 u_int index = rcm->index, count = rcm->count; 429 u_int8_t red[256], green[256], blue[256]; 430 int error; 431 432 if (index >= 256 || count > 256 - index) 433 return (EINVAL); 434 435 if ((error = copyin(rcm->red, red, count)) != 0) 436 return (error); 437 if ((error = copyin(rcm->green, green, count)) != 0) 438 return (error); 439 if ((error = copyin(rcm->blue, blue, count)) != 0) 440 return (error); 441 442 bcopy(red, cm->red + index, count); 443 bcopy(green, cm->green + index, count); 444 bcopy(blue, cm->blue + index, count); 445 446 return (0); 447 } 448 449 void 450 rfx_loadcmap(struct rfx_softc *sc, int start, int ncolors) 451 { 452 u_int8_t *r, *g, *b; 453 454 r = sc->sc_cmap.red + start; 455 g = sc->sc_cmap.green + start; 456 b = sc->sc_cmap.blue + start; 457 458 start += BT463_IREG_CPALETTE_RAM; 459 sc->sc_ramdac[BT463_REG_ADDR_LOW] = start & 0xff; 460 sc->sc_ramdac[BT463_REG_ADDR_HIGH] = (start >> 8) & 0xff; 461 462 while (ncolors-- != 0) { 463 sc->sc_ramdac[BT463_REG_CMAP_DATA] = *r++; 464 sc->sc_ramdac[BT463_REG_CMAP_DATA] = *g++; 465 sc->sc_ramdac[BT463_REG_CMAP_DATA] = *b++; 466 } 467 } 468 469 /* 470 * Initialization code parser 471 */ 472 473 int 474 rfx_initialize(struct rfx_softc *sc, struct sbus_attach_args *sa, 475 struct rfx_config *cf) 476 { 477 u_int32_t *data, offset, value; 478 size_t cnt; 479 bus_space_handle_t bh; 480 int error; 481 482 /* 483 * Map the initialization data 484 */ 485 if ((error = sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset + 486 RFX_INIT_ADDR, RFX_INIT_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh)) != 0) { 487 printf("\n%s: couldn't map initialization data\n", 488 sc->sc_sunfb.sf_dev.dv_xname); 489 return error; 490 } 491 data = (u_int32_t *)bus_space_vaddr(sa->sa_bustag, bh); 492 493 /* 494 * Skip copyright notice 495 */ 496 data += RFX_INIT_OFFSET / sizeof(u_int32_t); 497 cnt = (RFX_INIT_SIZE - RFX_INIT_OFFSET) / sizeof(u_int32_t); 498 cnt >>= 1; 499 500 /* 501 * Parse and apply settings 502 */ 503 while (cnt != 0) { 504 offset = *data++; 505 value = *data++; 506 507 if (offset == (u_int32_t)-1 && value == (u_int32_t)-1) 508 break; 509 510 /* Old PROM are little-endian */ 511 if (cf->version <= 1) { 512 offset = letoh32(offset); 513 value = letoh32(offset); 514 } 515 516 if (offset & (1U << 31)) { 517 offset = (offset & ~(1U << 31)) - RFX_RAMDAC_ADDR; 518 if (offset < RFX_RAMDAC_SIZE) 519 sc->sc_ramdac[offset] = value >> 24; 520 } else { 521 offset -= RFX_CONTROL_ADDR; 522 if (offset < RFX_CONTROL_SIZE) 523 sc->sc_ctrl[offset >> 2] = value; 524 } 525 526 cnt--; 527 } 528 529 #ifdef DEBUG 530 if (cnt != 0) 531 printf("%s: incoherent initialization data!\n", 532 sc->sc_sunfb.sf_dev.dv_xname); 533 #endif 534 535 bus_space_unmap(sa->sa_bustag, bh, RFX_INIT_SIZE); 536 537 return 0; 538 } 539