1 /* $OpenBSD: tvtwo.c,v 1.15 2013/10/20 20:07:31 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2006, 2008, 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 Parallax XVideo and PowerVideo graphics boards. 32 * 33 * Some details about these board used to be available at: 34 * http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html 35 */ 36 37 /* 38 * The Parallax XVideo series frame buffers are 8/24-bit accelerated 39 * frame buffers, with hardware MPEG capabilities using a CCube chipset. 40 */ 41 42 /* 43 * Currently, this driver can only handle the 8-bit and 24-bit planes of the 44 * frame buffer, in an unaccelerated mode. 45 * 46 * TODO: 47 * - nvram handling 48 * - use the accelerator 49 * - interface to the c^3 50 */ 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/buf.h> 55 #include <sys/device.h> 56 #include <sys/ioctl.h> 57 #include <sys/mman.h> 58 #include <sys/conf.h> 59 60 #include <uvm/uvm_extern.h> 61 62 #include <machine/autoconf.h> 63 #include <machine/bus.h> 64 #include <machine/pmap.h> 65 #include <machine/cpu.h> 66 #include <machine/conf.h> 67 68 #include <dev/wscons/wsconsio.h> 69 #include <dev/wscons/wsdisplayvar.h> 70 #include <dev/rasops/rasops.h> 71 #include <machine/fbvar.h> 72 73 #include <dev/sbus/sbusvar.h> 74 75 /* 76 * The memory layout of the board is as follows: 77 * 78 * PROM0 000000 - 00ffff 79 * overlay plane 010000 - 037fff 80 * registers 040000 - 0404d0 81 * CCube 050000 - 05ffff 82 * 8-bit plane 080000 - 17ffff 83 * 24-bit plane 200000 - 6fffff 84 * PROM1 7f0000 - 7fffff 85 */ 86 87 #define PX_PROM0_OFFSET 0x000000 88 #define PX_OVERLAY_OFFSET 0x010000 89 #define PX_REG_OFFSET 0x040000 90 #define PX_CCUBE_OFFSET 0x050000 91 #define PX_PLANE8_OFFSET 0x080000 92 #define PX_PLANE24_OFFSET 0x200000 93 #define PX_PROM1_OFFSET 0x7f0000 94 95 #define PX_MAP_SIZE 0x800000 96 97 /* 98 * Partial registers layout 99 */ 100 101 #define PX_REG_DISPKLUGE 0x00b8 /* write only */ 102 #define DISPKLUGE_DEFAULT 0xc41f 103 #define DISPKLUGE_BLANK (1 << 12) 104 #define DISPKLUGE_SYNC (1 << 13) 105 106 #define PX_REG_BT463_RED 0x0480 107 #define PX_REG_BT463_GREEN 0x0490 108 #define PX_REG_BT463_BLUE 0x04a0 109 #define PX_REG_BT463_ALL 0x04b0 110 111 #define PX_REG_SIZE 0x04d0 112 113 114 /* per-display variables */ 115 struct tvtwo_softc { 116 struct sunfb sc_sunfb; /* common base device */ 117 118 bus_space_tag_t sc_bustag; 119 bus_addr_t sc_paddr; 120 121 volatile u_int8_t *sc_m8; 122 volatile u_int8_t *sc_m24; 123 volatile u_int8_t *sc_regs; 124 125 int sc_nscreens; 126 }; 127 128 int tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *); 129 paddr_t tvtwo_mmap(void *, off_t, int); 130 void tvtwo_burner(void *, u_int, u_int); 131 132 struct wsdisplay_accessops tvtwo_accessops = { 133 .ioctl = tvtwo_ioctl, 134 .mmap = tvtwo_mmap, 135 .burn_screen = tvtwo_burner 136 }; 137 138 void tvtwo_directcmap(struct tvtwo_softc *); 139 static __inline__ 140 void tvtwo_ramdac_wraddr(struct tvtwo_softc *, u_int32_t); 141 void tvtwo_reset(struct tvtwo_softc *, u_int); 142 void tvtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 143 144 int tvtwomatch(struct device *, void *, void *); 145 void tvtwoattach(struct device *, struct device *, void *); 146 147 struct cfattach tvtwo_ca = { 148 sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach 149 }; 150 151 struct cfdriver tvtwo_cd = { 152 NULL, "tvtwo", DV_DULL 153 }; 154 155 /* 156 * Default frame buffer resolution, depending upon the "freqcode" 157 */ 158 #define NFREQCODE 5 159 const int defwidth[NFREQCODE] = { 1152, 1152, 1152, 1024, 640 }; 160 const int defheight[NFREQCODE] = { 900, 900, 900, 768, 480 }; 161 162 /* 163 * Match an XVideo or PowerVideo card. 164 */ 165 int 166 tvtwomatch(struct device *parent, void *vcf, void *aux) 167 { 168 struct sbus_attach_args *sa = aux; 169 170 if (strcmp(sa->sa_name, "PGI,tvtwo") == 0 || 171 strcmp(sa->sa_name, "PGI,tvthree") == 0) 172 return (1); 173 174 return (0); 175 } 176 177 /* 178 * Attach a display. 179 */ 180 void 181 tvtwoattach(struct device *parent, struct device *self, void *args) 182 { 183 struct tvtwo_softc *sc = (struct tvtwo_softc *)self; 184 struct sbus_attach_args *sa = args; 185 bus_space_tag_t bt; 186 bus_space_handle_t bh; 187 int node, width, height, freqcode; 188 int isconsole; 189 char *freqstring, *revision; 190 191 bt = sa->sa_bustag; 192 node = sa->sa_node; 193 194 printf(": %s", getpropstring(node, "model")); 195 revision = getpropstring(node, "revision"); 196 if (*revision != '\0') 197 printf(", revision %s", revision); 198 199 /* Older XVideo provide two sets of SBus registers: 200 * R0 040000 - 040800 201 * R1 080000 - 17d200 202 * While the more recent revisions provide only one register: 203 * R0 000000 - 7fffff 204 * 205 * We'll simply ``rewrite'' R0 on older boards and handle them as 206 * recent boards. 207 */ 208 if (sa->sa_nreg > 1) { 209 sa->sa_offset -= PX_REG_OFFSET; 210 sa->sa_size = PX_MAP_SIZE; 211 } 212 213 isconsole = node == fbnode; 214 215 /* Map registers. */ 216 sc->sc_bustag = bt; 217 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_REG_OFFSET, 218 PX_REG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 219 printf("%s: couldn't map registers\n", self->dv_xname); 220 return; 221 } 222 sc->sc_regs = bus_space_vaddr(bt, bh); 223 224 /* 225 * Compute framebuffer size. 226 * Older boards do not have the ``freqcode'' property and are 227 * restricted to 1152x900. 228 */ 229 freqstring = getpropstring(node, "freqcode"); 230 if (*freqstring != '\0') { 231 freqcode = (int)*freqstring; 232 if (freqcode == 'g') { 233 width = height = 1024; 234 } else { 235 if (freqcode < '1' || freqcode > '6') 236 freqcode = 0; 237 else 238 freqcode -= '1'; 239 width = defwidth[freqcode]; 240 height = defheight[freqcode]; 241 242 /* in case our table is wrong or incomplete... */ 243 width = getpropint(node, "hres", width); 244 height = getpropint(node, "vres", height); 245 } 246 } else { 247 width = 1152; 248 height = 900; 249 } 250 251 /* 252 * Since the depth property is missing, we could do 253 * fb_setsize(&sc->sc_sunfb, 8, width, height, node, 0); 254 * but for safety in case it would exist and be set to 32, do it 255 * manually... 256 */ 257 sc->sc_sunfb.sf_depth = 8; 258 sc->sc_sunfb.sf_width = width; 259 sc->sc_sunfb.sf_height = height; 260 sc->sc_sunfb.sf_linebytes = width >= 1024 ? width : 1024; 261 sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_linebytes * height; 262 263 printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 264 265 /* Map the frame buffer memory area we're interested in. */ 266 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset); 267 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE8_OFFSET, 268 round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0, 269 &bh) != 0) { 270 printf("%s: couldn't map 8-bit video plane\n", self->dv_xname); 271 return; 272 } 273 sc->sc_m8 = bus_space_vaddr(bt, bh); 274 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE24_OFFSET, 275 round_page(4 * sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0, 276 &bh) != 0) { 277 printf("%s: couldn't map 32-bit video plane\n", self->dv_xname); 278 return; 279 } 280 sc->sc_m24 = bus_space_vaddr(bt, bh); 281 282 /* Enable video. */ 283 tvtwo_burner(sc, 1, 0); 284 285 sc->sc_sunfb.sf_ro.ri_hw = sc; 286 sc->sc_sunfb.sf_ro.ri_bits = (u_char *)sc->sc_m8; 287 288 fbwscons_init(&sc->sc_sunfb, 0, isconsole); 289 fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor); 290 291 if (isconsole) 292 fbwscons_console_init(&sc->sc_sunfb, -1); 293 294 fbwscons_attach(&sc->sc_sunfb, &tvtwo_accessops, isconsole); 295 } 296 297 int 298 tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p) 299 { 300 struct tvtwo_softc *sc = dev; 301 struct wsdisplay_fbinfo *wdf; 302 303 /* 304 * Note that, although the emulation (text) mode is running in a 305 * 8-bit plane, we advertize the frame buffer as 32-bit. 306 */ 307 switch (cmd) { 308 case WSDISPLAYIO_GTYPE: 309 *(u_int *)data = WSDISPLAY_TYPE_XVIDEO; 310 break; 311 case WSDISPLAYIO_GINFO: 312 wdf = (struct wsdisplay_fbinfo *)data; 313 wdf->height = sc->sc_sunfb.sf_height; 314 wdf->width = sc->sc_sunfb.sf_width; 315 wdf->depth = 32; 316 wdf->cmsize = 0; 317 break; 318 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 319 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 320 break; 321 case WSDISPLAYIO_LINEBYTES: 322 *(u_int *)data = sc->sc_sunfb.sf_linebytes * 4; 323 break; 324 325 case WSDISPLAYIO_GETCMAP: 326 case WSDISPLAYIO_PUTCMAP: 327 break; 328 329 case WSDISPLAYIO_SMODE: 330 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 331 /* Back from X11 to text mode */ 332 tvtwo_reset(sc, 8); 333 } else { 334 /* Starting X11, initialize 32-bit mode */ 335 tvtwo_reset(sc, 32); 336 } 337 break; 338 339 case WSDISPLAYIO_SVIDEO: 340 case WSDISPLAYIO_GVIDEO: 341 break; 342 343 case WSDISPLAYIO_GCURPOS: 344 case WSDISPLAYIO_SCURPOS: 345 case WSDISPLAYIO_GCURMAX: 346 case WSDISPLAYIO_GCURSOR: 347 case WSDISPLAYIO_SCURSOR: 348 default: 349 return (-1); 350 } 351 352 return (0); 353 } 354 355 /* 356 * Return the address that would map the given device at the given 357 * offset, allowing for the given protection, or return -1 for error. 358 */ 359 paddr_t 360 tvtwo_mmap(void *v, off_t offset, int prot) 361 { 362 struct tvtwo_softc *sc = v; 363 364 if (offset & PGOFSET) 365 return (-1); 366 367 /* Allow mapping as a dumb framebuffer from offset 0 */ 368 if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize * 4) { 369 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 370 PX_PLANE24_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR)); 371 } 372 373 return (-1); 374 } 375 376 void 377 tvtwo_burner(void *v, u_int on, u_int flags) 378 { 379 struct tvtwo_softc *sc = v; 380 u_int32_t dispkluge; 381 382 if (on) 383 dispkluge = DISPKLUGE_DEFAULT & ~DISPKLUGE_BLANK; 384 else { 385 dispkluge = DISPKLUGE_DEFAULT | DISPKLUGE_BLANK; 386 if (flags & WSDISPLAY_BURN_VBLANK) 387 dispkluge |= DISPKLUGE_SYNC; 388 } 389 390 *(volatile u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUGE) = dispkluge; 391 } 392 393 void 394 tvtwo_reset(struct tvtwo_softc *sc, u_int depth) 395 { 396 if (depth == 32) { 397 /* Initialize a direct color map. */ 398 tvtwo_directcmap(sc); 399 } else { 400 fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor); 401 } 402 } 403 404 /* 405 * Simple Bt463 programming routines. 406 */ 407 408 static __inline__ void 409 tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr) 410 { 411 volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED); 412 413 dac[0] = (addr & 0xff); /* lo addr */ 414 dac[1] = ((addr >> 8) & 0xff); /* hi addr */ 415 } 416 417 void 418 tvtwo_directcmap(struct tvtwo_softc *sc) 419 { 420 volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED); 421 u_int32_t c; 422 423 tvtwo_ramdac_wraddr(sc, 0); 424 for (c = 0; c < 256; c++) { 425 dac[3] = c; /* R */ 426 dac[3] = c; /* G */ 427 dac[3] = c; /* B */ 428 } 429 } 430 431 void 432 tvtwo_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 433 { 434 struct tvtwo_softc *sc = v; 435 volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED); 436 437 tvtwo_ramdac_wraddr(sc, index); 438 dac[3] = r; 439 dac[3] = g; 440 dac[3] = b; 441 } 442