1 /* $NetBSD: grf_nubus.c,v 1.27 1997/07/01 19:04:19 scottr Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Allen Briggs. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Allen Briggs. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Device-specific routines for handling Nubus-based video cards. 33 */ 34 35 #include <sys/param.h> 36 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/file.h> 40 #include <sys/malloc.h> 41 #include <sys/mman.h> 42 #include <sys/proc.h> 43 #include <sys/systm.h> 44 45 #include <machine/bus.h> 46 #include <machine/cpu.h> 47 #include <machine/grfioctl.h> 48 #include <machine/viareg.h> 49 50 #include "nubus.h" 51 #include "grfvar.h" 52 53 static void load_image_data __P((caddr_t data, struct image_data *image)); 54 55 static void grfmv_intr_generic __P((void *vsc, int slot)); 56 static void grfmv_intr_radius __P((void *vsc, int slot)); 57 static void grfmv_intr_cti __P((void *vsc, int slot)); 58 static void grfmv_intr_cb264 __P((void *vsc, int slot)); 59 static void grfmv_intr_cb364 __P((void *vsc, int slot)); 60 61 static int grfmv_mode __P((struct grf_softc *gp, int cmd, void *arg)); 62 static caddr_t grfmv_phys __P((struct grf_softc *gp, vm_offset_t addr)); 63 static int grfmv_match __P((struct device *, struct cfdata *, void *)); 64 static void grfmv_attach __P((struct device *, struct device *, void *)); 65 66 struct cfdriver macvid_cd = { 67 NULL, "macvid", DV_DULL 68 }; 69 70 struct cfattach macvid_ca = { 71 sizeof(struct grfbus_softc), grfmv_match, grfmv_attach 72 }; 73 74 static void 75 load_image_data(data, image) 76 caddr_t data; 77 struct image_data *image; 78 { 79 bcopy(data , &image->size, 4); 80 bcopy(data + 4, &image->offset, 4); 81 bcopy(data + 8, &image->rowbytes, 2); 82 bcopy(data + 10, &image->top, 2); 83 bcopy(data + 12, &image->left, 2); 84 bcopy(data + 14, &image->bottom, 2); 85 bcopy(data + 16, &image->right, 2); 86 bcopy(data + 18, &image->version, 2); 87 bcopy(data + 20, &image->packType, 2); 88 bcopy(data + 22, &image->packSize, 4); 89 bcopy(data + 26, &image->hRes, 4); 90 bcopy(data + 30, &image->vRes, 4); 91 bcopy(data + 34, &image->pixelType, 2); 92 bcopy(data + 36, &image->pixelSize, 2); 93 bcopy(data + 38, &image->cmpCount, 2); 94 bcopy(data + 40, &image->cmpSize, 2); 95 bcopy(data + 42, &image->planeBytes, 4); 96 } 97 98 99 static int 100 grfmv_match(parent, cf, aux) 101 struct device *parent; 102 struct cfdata *cf; 103 void *aux; 104 { 105 struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 106 107 if (na->category != NUBUS_CATEGORY_DISPLAY) 108 return 0; 109 110 if (na->type != NUBUS_TYPE_VIDEO) 111 return 0; 112 113 if (na->drsw != NUBUS_DRSW_APPLE) 114 return 0; 115 116 /* 117 * If we've gotten this far, then we're dealing with a real-live 118 * Apple QuickDraw-compatible display card resource. Now, how to 119 * determine that this is an active resource??? Dunno. But we'll 120 * proceed like it is. 121 */ 122 123 return 1; 124 } 125 126 static void 127 grfmv_attach(parent, self, aux) 128 struct device *parent, *self; 129 void *aux; 130 { 131 struct grfbus_softc *sc = (struct grfbus_softc *)self; 132 struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 133 struct image_data image_store, image; 134 struct grfmode *gm; 135 char cardname[CARD_NAME_LEN]; 136 nubus_dirent dirent; 137 nubus_dir dir, mode_dir; 138 int mode; 139 140 sc->sc_tag = na->na_tag; 141 sc->card_id = na->drhw; 142 143 bcopy(na->fmt, &sc->sc_slot, sizeof(nubus_slot)); 144 145 if (bus_space_map(sc->sc_tag, 146 NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &sc->sc_handle)) { 147 printf(": grfmv_attach: failed to map slot %d\n", na->slot); 148 return; 149 } 150 151 nubus_get_main_dir(&sc->sc_slot, &dir); 152 153 if (nubus_find_rsrc(sc->sc_tag, sc->sc_handle, 154 &sc->sc_slot, &dir, na->rsrcid, &dirent) <= 0) { 155 bad: 156 bus_space_unmap(sc->sc_tag, sc->sc_handle, NBMEMSIZE); 157 return; 158 } 159 160 nubus_get_dir_from_rsrc(&sc->sc_slot, &dirent, &sc->board_dir); 161 162 if (nubus_find_rsrc(sc->sc_tag, sc->sc_handle, 163 &sc->sc_slot, &sc->board_dir, NUBUS_RSRC_TYPE, &dirent) <= 0) 164 if ((na->rsrcid != 128) || 165 (nubus_find_rsrc(sc->sc_tag, sc->sc_handle, 166 &sc->sc_slot, &dir, 129, &dirent) <= 0)) 167 goto bad; 168 169 mode = NUBUS_RSRC_FIRSTMODE; 170 if (nubus_find_rsrc(sc->sc_tag, sc->sc_handle, 171 &sc->sc_slot, &sc->board_dir, mode, &dirent) <= 0) { 172 printf(": probe failed to get board rsrc.\n"); 173 goto bad; 174 } 175 176 nubus_get_dir_from_rsrc(&sc->sc_slot, &dirent, &mode_dir); 177 178 if (nubus_find_rsrc(sc->sc_tag, sc->sc_handle, 179 &sc->sc_slot, &mode_dir, VID_PARAMS, &dirent) <= 0) { 180 printf(": probe failed to get mode dir.\n"); 181 goto bad; 182 } 183 184 if (nubus_get_ind_data(sc->sc_tag, sc->sc_handle, &sc->sc_slot, 185 &dirent, (caddr_t)&image_store, sizeof(struct image_data)) <= 0) { 186 printf(": probe failed to get indirect mode data.\n"); 187 goto bad; 188 } 189 190 /* Need to load display info (and driver?), etc... (?) */ 191 192 load_image_data((caddr_t)&image_store, &image); 193 194 gm = &sc->curr_mode; 195 gm->mode_id = mode; 196 gm->fbbase = (caddr_t)(sc->sc_handle + image.offset); /* XXX evil! */ 197 gm->fboff = image.offset; 198 gm->rowbytes = image.rowbytes; 199 gm->width = image.right - image.left; 200 gm->height = image.bottom - image.top; 201 gm->fbsize = sc->curr_mode.height * sc->curr_mode.rowbytes; 202 gm->hres = image.hRes; 203 gm->vres = image.vRes; 204 gm->ptype = image.pixelType; 205 gm->psize = image.pixelSize; 206 207 strncpy(cardname, nubus_get_card_name(sc->sc_tag, sc->sc_handle, 208 &sc->sc_slot), CARD_NAME_LEN); 209 cardname[CARD_NAME_LEN-1] = '\0'; 210 printf(": %s\n", cardname); 211 212 if (sc->card_id == NUBUS_DRHW_TFB) { 213 /* 214 * This is the Toby card, but apparently some manufacturers 215 * (like Cornerstone) didn't bother to get/use their own 216 * value here, even though the cards are different, so we 217 * so we try to differentiate here. 218 */ 219 if (strncmp(cardname, "Samsung 768", 11) == 0) 220 sc->card_id = NUBUS_DRHW_SAM768; 221 else if (strncmp(cardname, "Toby frame", 10) != 0) 222 printf("%s: This display card pretends to be a TFB!\n", 223 sc->sc_dev.dv_xname); 224 } 225 226 switch (sc->card_id) { 227 case NUBUS_DRHW_M2HRVC: 228 case NUBUS_DRHW_TFB: 229 case NUBUS_DRHW_PVC: 230 sc->cli_offset = 0xa0000; 231 sc->cli_value = 0; 232 add_nubus_intr(na->slot, grfmv_intr_generic, sc); 233 break; 234 case NUBUS_DRHW_WVC: 235 sc->cli_offset = 0xa00000; 236 sc->cli_value = 0; 237 add_nubus_intr(na->slot, grfmv_intr_generic, sc); 238 break; 239 case NUBUS_DRHW_RPC8XJ: 240 add_nubus_intr(na->slot, grfmv_intr_radius, sc); 241 break; 242 case NUBUS_DRHW_FIILX: 243 case NUBUS_DRHW_FIISXDSP: 244 sc->cli_offset = 0xf05000; 245 sc->cli_value = 0x80; 246 add_nubus_intr(na->slot, grfmv_intr_generic, sc); 247 break; 248 case NUBUS_DRHW_SAM768: 249 add_nubus_intr(na->slot, grfmv_intr_cti, sc); 250 break; 251 case NUBUS_DRHW_CB264: 252 add_nubus_intr(na->slot, grfmv_intr_cb264, sc); 253 break; 254 case NUBUS_DRHW_CB364: 255 add_nubus_intr(na->slot, grfmv_intr_cb364, sc); 256 break; 257 case NUBUS_DRHW_SE30: 258 /* Do nothing--SE/30 interrupts are disabled */ 259 break; 260 case NUBUS_DRHW_MICRON: 261 /* What do we know about this one? */ 262 default: 263 printf("%s: Unknown video card ID 0x%x --", 264 sc->sc_dev.dv_xname, sc->card_id); 265 printf(" Not installing interrupt routine.\n"); 266 break; 267 } 268 269 /* Perform common video attachment. */ 270 grf_establish(sc, &sc->sc_slot, grfmv_mode, grfmv_phys); 271 } 272 273 static int 274 grfmv_mode(gp, cmd, arg) 275 struct grf_softc *gp; 276 int cmd; 277 void *arg; 278 { 279 switch (cmd) { 280 case GM_GRFON: 281 case GM_GRFOFF: 282 return 0; 283 case GM_CURRMODE: 284 break; 285 case GM_NEWMODE: 286 break; 287 case GM_LISTMODES: 288 break; 289 } 290 return EINVAL; 291 } 292 293 static caddr_t 294 grfmv_phys(gp, addr) 295 struct grf_softc *gp; 296 vm_offset_t addr; 297 { 298 return (caddr_t)(NUBUS_SLOT2PA(gp->sc_slot->slot) + 299 (addr - gp->sc_handle)); /* XXX evil hack */ 300 } 301 302 /* Interrupt handlers... */ 303 /* 304 * Generic routine to clear interrupts for cards where it simply takes 305 * a CLR.B to clear the interrupt. The offset of this byte varies between 306 * cards. 307 */ 308 /*ARGSUSED*/ 309 static void 310 grfmv_intr_generic(vsc, slot) 311 void *vsc; 312 int slot; 313 { 314 struct grfbus_softc *sc = (struct grfbus_softc *)vsc; 315 316 bus_space_write_1(sc->sc_tag, sc->sc_handle, 317 sc->cli_offset, sc->cli_value); 318 } 319 320 /* 321 * Routine to clear interrupts for the Radius PrecisionColor 8xj card. 322 */ 323 /*ARGSUSED*/ 324 static void 325 grfmv_intr_radius(vsc, slot) 326 void *vsc; 327 int slot; 328 { 329 struct grfbus_softc *sc = (struct grfbus_softc *)vsc; 330 u_int8_t c; 331 332 /* 333 * The value 0x66 was the observed value on one card. It is read 334 * from the driver's information block, so this may not be sufficient. 335 * Then again, we're not setting up any other interrupts... 336 */ 337 c = 0x66; 338 339 c |= 0x80; 340 bus_space_write_1(sc->sc_tag, sc->sc_handle, 0xd00403, c); 341 c &= 0x7f; 342 bus_space_write_1(sc->sc_tag, sc->sc_handle, 0xd00403, c); 343 } 344 345 /* 346 * Routine to clear interrupts on Samsung 768x1006 video controller. 347 * This controller was manufactured by Cornerstone Technology, Inc., 348 * now known as Cornerstone Imaging. 349 * 350 * To clear this interrupt, we apparently have to set, then clear, 351 * bit 2 at byte offset 0x80000 from the card's base. 352 * Information for this provided by Brad Salai <bsalai@servtech.com> 353 */ 354 /*ARGSUSED*/ 355 static void 356 grfmv_intr_cti(vsc, slot) 357 void *vsc; 358 int slot; 359 { 360 struct grfbus_softc *sc = (struct grfbus_softc *)vsc; 361 u_int8_t c; 362 363 c = bus_space_read_1(sc->sc_tag, sc->sc_handle, 0x80000); 364 c |= 0x02; 365 bus_space_write_1(sc->sc_tag, sc->sc_handle, 0x80000, c); 366 c &= 0xfd; 367 bus_space_write_1(sc->sc_tag, sc->sc_handle, 0x80000, c); 368 } 369 370 /*ARGSUSED*/ 371 static void 372 grfmv_intr_cb264(vsc, slot) 373 void *vsc; 374 int slot; 375 { 376 struct grfbus_softc *sc; 377 volatile char *slotbase; 378 379 sc = (struct grfbus_softc *)vsc; 380 slotbase = (volatile char *)sc->sc_handle; /* XXX evil hack */ 381 asm volatile(" movl %0,a0 382 movl a0@(0xff6028),d0 383 andl #0x2,d0 384 beq _mv_intr0 385 movql #0x3,d0 386 _mv_intr0: 387 movl a0@(0xff600c),d1 388 andl #0x3,d1 389 cmpl d1,d0 390 beq _mv_intr_fin 391 movl d0,a0@(0xff600c) 392 nop 393 tstb d0 394 beq _mv_intr1 395 movl #0x0002,a0@(0xff6040) 396 movl #0x0102,a0@(0xff6044) 397 movl #0x0105,a0@(0xff6048) 398 movl #0x000e,a0@(0xff604c) 399 movl #0x001c,a0@(0xff6050) 400 movl #0x00bc,a0@(0xff6054) 401 movl #0x00c3,a0@(0xff6058) 402 movl #0x0061,a0@(0xff605c) 403 movl #0x0012,a0@(0xff6060) 404 bra _mv_intr_fin 405 _mv_intr1: 406 movl #0x0002,a0@(0xff6040) 407 movl #0x0209,a0@(0xff6044) 408 movl #0x020c,a0@(0xff6048) 409 movl #0x000f,a0@(0xff604c) 410 movl #0x0027,a0@(0xff6050) 411 movl #0x00c7,a0@(0xff6054) 412 movl #0x00d7,a0@(0xff6058) 413 movl #0x006b,a0@(0xff605c) 414 movl #0x0029,a0@(0xff6060) 415 _mv_intr_fin: 416 movl #0x1,a0@(0xff6014)" 417 : : "g" (slotbase) : "a0","d0","d1"); 418 } 419 420 /* 421 * Support for the Colorboard 364 might be more complex than it needs to 422 * be. If we can find more information about this card, this might be 423 * significantly simplified. Contributions welcome... :-) 424 */ 425 /*ARGSUSED*/ 426 static void 427 grfmv_intr_cb364(vsc, slot) 428 void *vsc; 429 int slot; 430 { 431 struct grfbus_softc *sc; 432 volatile char *slotbase; 433 434 sc = (struct grfbus_softc *)vsc; 435 slotbase = (volatile char *)sc->sc_handle; /* XXX evil hack */ 436 asm volatile(" movl %0,a0 437 movl a0@(0xfe6028),d0 438 andl #0x2,d0 439 beq _cb364_intr4 440 movql #0x3,d0 441 movl a0@(0xfe6018),d1 442 movl #0x3,a0@(0xfe6018) 443 movw a0@(0xfe7010),d2 444 movl d1,a0@(0xfe6018) 445 movl a0@(0xfe6020),d1 446 btst #0x06,d2 447 beq _cb364_intr0 448 btst #0x00,d1 449 beq _cb364_intr5 450 bsr _cb364_intr1 451 bra _cb364_intr_out 452 _cb364_intr0: 453 btst #0x00,d1 454 bne _cb364_intr5 455 bsr _cb364_intr1 456 bra _cb364_intr_out 457 _cb364_intr1: 458 movl d0,a0@(0xfe600c) 459 nop 460 tstb d0 461 beq _cb364_intr3 462 movl #0x0002,a0@(0xfe6040) 463 movl #0x0105,a0@(0xfe6048) 464 movl #0x000e,a0@(0xfe604c) 465 movl #0x00c3,a0@(0xfe6058) 466 movl #0x0061,a0@(0xfe605c) 467 btst #0x06,d2 468 beq _cb364_intr2 469 movl #0x001c,a0@(0xfe6050) 470 movl #0x00bc,a0@(0xfe6054) 471 movl #0x0012,a0@(0xfe6060) 472 movl #0x000e,a0@(0xfe6044) 473 movl #0x00c3,a0@(0xfe6064) 474 movl #0x0061,a0@(0xfe6020) 475 rts 476 _cb364_intr2: 477 movl #0x0016,a0@(0xfe6050) 478 movl #0x00b6,a0@(0xfe6054) 479 movl #0x0011,a0@(0xfe6060) 480 movl #0x0101,a0@(0xfe6044) 481 movl #0x00bf,a0@(0xfe6064) 482 movl #0x0001,a0@(0xfe6020) 483 rts 484 _cb364_intr3: 485 movl #0x0002,a0@(0xfe6040) 486 movl #0x0209,a0@(0xfe6044) 487 movl #0x020c,a0@(0xfe6048) 488 movl #0x000f,a0@(0xfe604c) 489 movl #0x0027,a0@(0xfe6050) 490 movl #0x00c7,a0@(0xfe6054) 491 movl #0x00d7,a0@(0xfe6058) 492 movl #0x006b,a0@(0xfe605c) 493 movl #0x0029,a0@(0xfe6060) 494 oril #0x0040,a0@(0xfe6064) 495 movl #0x0000,a0@(0xfe6020) 496 rts 497 _cb364_intr4: 498 movq #0x00,d0 499 _cb364_intr5: 500 movl a0@(0xfe600c),d1 501 andl #0x3,d1 502 cmpl d1,d0 503 beq _cb364_intr_out 504 bsr _cb364_intr1 505 _cb364_intr_out: 506 movl #0x1,a0@(0xfe6014) 507 _cb364_intr_quit: 508 " : : "g" (slotbase) : "a0","d0","d1","d2"); 509 } 510