1 /* $NetBSD: grf_obio.c,v 1.59 2019/07/26 10:48:44 rin Exp $ */ 2 3 /* 4 * Copyright (C) 1998 Scott Reynolds 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 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /* 30 * Copyright (c) 1995 Allen Briggs. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by Allen Briggs. 43 * 4. The name of the author may not be used to endorse or promote products 44 * derived from this software without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 /* 58 * Graphics display driver for the Macintosh internal video for machines 59 * that don't map it into a fake nubus card. 60 */ 61 62 #include <sys/cdefs.h> 63 __KERNEL_RCSID(0, "$NetBSD: grf_obio.c,v 1.59 2019/07/26 10:48:44 rin Exp $"); 64 65 #include <sys/param.h> 66 #include <sys/device.h> 67 #include <sys/ioctl.h> 68 #include <sys/kmem.h> 69 #include <sys/file.h> 70 #include <sys/mman.h> 71 #include <sys/proc.h> 72 #include <sys/systm.h> 73 74 #include <machine/autoconf.h> 75 #include <machine/bus.h> 76 #include <machine/cpu.h> 77 #include <machine/grfioctl.h> 78 #include <machine/viareg.h> 79 #include <machine/video.h> 80 81 #include <mac68k/nubus/nubus.h> 82 #include <mac68k/obio/grf_obioreg.h> 83 #include <mac68k/obio/obiovar.h> 84 #include <mac68k/dev/grfvar.h> 85 86 static int grfiv_mode(struct grf_softc *, int, void *); 87 static int grfiv_match(device_t, cfdata_t, void *); 88 static void grfiv_attach(device_t, device_t, void *); 89 90 static void dafb_set_mapreg(void *, int, int, int, int); 91 static void civic_set_mapreg(void *, int, int, int, int); 92 static void valkyrie_set_mapreg(void *, int, int, int, int); 93 static void rbv_set_mapreg(void *, int, int, int, int); 94 95 CFATTACH_DECL_NEW(intvid, sizeof(struct grfbus_softc), 96 grfiv_match, grfiv_attach, NULL, NULL); 97 98 static int 99 grfiv_match(device_t parent, cfdata_t cf, void *aux) 100 { 101 struct obio_attach_args *oa = (struct obio_attach_args *)aux; 102 bus_space_handle_t bsh; 103 int found; 104 u_int base; 105 106 found = 1; 107 108 switch (current_mac_model->class) { 109 case MACH_CLASSQ2: 110 if (current_mac_model->machineid != MACH_MACLC575) { 111 base = VALKYRIE_CONTROL_BASE; 112 113 if (bus_space_map(oa->oa_tag, base, 0x40, 0, &bsh)) 114 return 0; 115 116 /* Disable interrupts */ 117 bus_space_write_1(oa->oa_tag, bsh, 0x18, 0x1); 118 119 bus_space_unmap(oa->oa_tag, bsh, 0x40); 120 break; 121 } 122 /* 123 * Note: the only system in this class that does not have 124 * the Valkyrie chip -- at least, that we know of -- is 125 * the Performa/LC 57x series. This system has a version 126 * of the DAFB controller, instead. 127 * 128 * If this assumption proves false, we'll have to be more 129 * intelligent here. 130 */ 131 /*FALLTHROUGH*/ 132 case MACH_CLASSQ: 133 /* 134 * Assume DAFB for all of these, unless we can't 135 * access the memory. 136 */ 137 base = DAFB_CONTROL_BASE; 138 139 if (bus_space_map(oa->oa_tag, base, 0x20, 0, &bsh)) 140 return 0; 141 142 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0x1c, 4) == 0) { 143 bus_space_unmap(oa->oa_tag, bsh, 0x20); 144 return 0; 145 } 146 147 bus_space_unmap(oa->oa_tag, bsh, 0x20); 148 149 if (bus_space_map(oa->oa_tag, base + 0x100, 0x20, 0, &bsh)) 150 return 0; 151 152 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0x04, 4) == 0) { 153 bus_space_unmap(oa->oa_tag, bsh, 0x20); 154 return 0; 155 } 156 157 /* Disable interrupts */ 158 bus_space_write_4(oa->oa_tag, bsh, 0x04, 0); 159 160 /* Clear any interrupts */ 161 bus_space_write_4(oa->oa_tag, bsh, 0x0C, 0); 162 bus_space_write_4(oa->oa_tag, bsh, 0x10, 0); 163 bus_space_write_4(oa->oa_tag, bsh, 0x14, 0); 164 165 bus_space_unmap(oa->oa_tag, bsh, 0x20); 166 break; 167 case MACH_CLASSAV: 168 base = CIVIC_CONTROL_BASE; 169 170 if (bus_space_map(oa->oa_tag, base, 0x1000, 0, &bsh)) 171 return 0; 172 173 /* Disable interrupts */ 174 bus_space_write_1(oa->oa_tag, bsh, 0x120, 0); 175 176 bus_space_unmap(oa->oa_tag, bsh, 0x1000); 177 break; 178 case MACH_CLASSIIci: 179 case MACH_CLASSIIsi: 180 if (mac68k_video.mv_len == 0 || 181 (via2_reg(rMonitor) & RBVMonitorMask) == RBVMonIDNone) 182 found = 0; 183 break; 184 default: 185 if (mac68k_video.mv_len == 0) 186 found = 0; 187 break; 188 } 189 190 return found; 191 } 192 193 static void 194 grfiv_attach(device_t parent, device_t self, void *aux) 195 { 196 struct obio_attach_args *oa = (struct obio_attach_args *)aux; 197 struct grfbus_softc *sc; 198 struct grfmode *gm; 199 u_long base, length; 200 u_int32_t vbase1, vbase2; 201 202 sc = device_private(self); 203 sc->sc_dev = self; 204 205 sc->card_id = 0; 206 207 switch (current_mac_model->class) { 208 case MACH_CLASSQ2: 209 if (current_mac_model->machineid != MACH_MACLC575) { 210 sc->sc_basepa = VALKYRIE_FB_BASE; 211 length = 0x00100000; /* 1MB */ 212 213 if (sc->sc_basepa <= mac68k_video.mv_phys && 214 mac68k_video.mv_phys < (sc->sc_basepa + length)) { 215 sc->sc_fbofs = 216 mac68k_video.mv_phys - sc->sc_basepa; 217 } else { 218 sc->sc_basepa = 219 m68k_trunc_page(mac68k_video.mv_phys); 220 sc->sc_fbofs = 221 m68k_page_offset(mac68k_video.mv_phys); 222 length = mac68k_video.mv_len + sc->sc_fbofs; 223 } 224 225 if (bus_space_map(sc->sc_tag, VALKYRIE_CMAP_BASE, 226 VALKYRIE_CMAP_LEN, 0, &sc->sc_cmh) == 0) 227 sc->sc_set_mapreg = valkyrie_set_mapreg; 228 229 printf(" @ %lx: Valkyrie video subsystem\n", 230 sc->sc_basepa + sc->sc_fbofs); 231 break; 232 } 233 /* See note in grfiv_match() */ 234 /*FALLTHROUGH*/ 235 case MACH_CLASSQ: 236 base = DAFB_CONTROL_BASE; 237 sc->sc_tag = oa->oa_tag; 238 if (bus_space_map(sc->sc_tag, base, 0x20, 0, &sc->sc_regh)) { 239 printf(": failed to map DAFB register space\n"); 240 return; 241 } 242 243 sc->sc_basepa = DAFB_FB_BASE; 244 length = 0x00100000; /* 1MB */ 245 246 /* Compute the current frame buffer offset */ 247 vbase1 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x0) & 0xfff; 248 #if 1 249 /* 250 * XXX The following exists because the DAFB v7 in these 251 * systems doesn't return reasonable values to use for fbofs. 252 * Ken'ichi Ishizaka gets credit for this hack. (sar 19990426) 253 * (Does this get us the correct result for _all_ DAFB- 254 * equipped systems and monitor combinations? It seems 255 * possible, if not likely...) 256 */ 257 switch (current_mac_model->machineid) { 258 case MACH_MACLC475: 259 case MACH_MACLC475_33: 260 case MACH_MACLC575: 261 case MACH_MACQ605: 262 case MACH_MACQ605_33: 263 vbase1 &= 0x3f; 264 break; 265 } 266 #endif 267 vbase2 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x4) & 0xf; 268 sc->sc_fbofs = (vbase1 << 9) | (vbase2 << 5); 269 270 if (bus_space_map(sc->sc_tag, DAFB_CMAP_BASE, DAFB_CMAP_LEN, 271 0, &sc->sc_cmh) == 0) { 272 uint8_t *buf = kmem_zalloc(256 * 3, KM_SLEEP); 273 sc->sc_cmap.red = buf; 274 sc->sc_cmap.green = buf + 256; 275 sc->sc_cmap.blue = buf + 256 * 2; 276 sc->sc_set_mapreg = dafb_set_mapreg; 277 } 278 279 printf(" @ %lx: DAFB video subsystem, monitor sense %x\n", 280 sc->sc_basepa + sc->sc_fbofs, 281 (bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x1c) & 0x7)); 282 283 bus_space_unmap(sc->sc_tag, sc->sc_regh, 0x20); 284 break; 285 case MACH_CLASSAV: 286 sc->sc_basepa = CIVIC_FB_BASE; 287 length = 0x00200000; /* 2MB */ 288 if (mac68k_video.mv_phys >= sc->sc_basepa && 289 mac68k_video.mv_phys < (sc->sc_basepa + length)) { 290 sc->sc_fbofs = mac68k_video.mv_phys - sc->sc_basepa; 291 } else { 292 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); 293 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); 294 length = mac68k_video.mv_len + sc->sc_fbofs; 295 } 296 297 if (bus_space_map(sc->sc_tag, CIVIC_CMAP_BASE, CIVIC_CMAP_LEN, 298 0, &sc->sc_cmh) == 0) 299 sc->sc_set_mapreg = civic_set_mapreg; 300 301 printf(" @ %lx: CIVIC video subsystem\n", 302 sc->sc_basepa + sc->sc_fbofs); 303 break; 304 case MACH_CLASSIIci: 305 case MACH_CLASSIIsi: 306 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); 307 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); 308 length = mac68k_video.mv_len + sc->sc_fbofs; 309 310 if (bus_space_map(sc->sc_tag, RBV_CMAP_BASE, RBV_CMAP_LEN, 311 0, &sc->sc_cmh) == 0) 312 sc->sc_set_mapreg = rbv_set_mapreg; 313 314 printf(" @ %lx: RBV video subsystem, ", 315 sc->sc_basepa + sc->sc_fbofs); 316 switch (via2_reg(rMonitor) & RBVMonitorMask) { 317 case RBVMonIDBWP: 318 printf("15\" monochrome portrait"); 319 break; 320 case RBVMonIDRGB12: 321 printf("12\" color"); 322 break; 323 case RBVMonIDRGB15: 324 printf("15\" color"); 325 break; 326 case RBVMonIDStd: 327 printf("Macintosh II"); 328 break; 329 default: 330 printf("unrecognized"); 331 break; 332 } 333 printf(" display\n"); 334 335 break; 336 default: 337 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); 338 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); 339 length = mac68k_video.mv_len + sc->sc_fbofs; 340 341 /* XXX setpalette? */ 342 343 printf(" @ %lx: On-board video\n", 344 sc->sc_basepa + sc->sc_fbofs); 345 break; 346 } 347 348 if (bus_space_map(sc->sc_tag, sc->sc_basepa, length, 0, 349 &sc->sc_handle)) { 350 printf("%s: failed to map video RAM\n", device_xname(sc->sc_dev)); 351 return; 352 } 353 354 if (sc->sc_basepa <= mac68k_video.mv_phys && 355 mac68k_video.mv_phys < (sc->sc_basepa + length)) { 356 /* XXX Hack */ 357 mac68k_video.mv_kvaddr = sc->sc_handle.base + sc->sc_fbofs; 358 } 359 360 gm = &(sc->curr_mode); 361 gm->mode_id = 0; 362 gm->psize = mac68k_video.mv_depth; 363 gm->ptype = 0; 364 gm->width = mac68k_video.mv_width; 365 gm->height = mac68k_video.mv_height; 366 gm->rowbytes = mac68k_video.mv_stride; 367 gm->hres = 80; /* XXX hack */ 368 gm->vres = 80; /* XXX hack */ 369 gm->fbsize = gm->height * gm->rowbytes; 370 gm->fbbase = (void *)sc->sc_handle.base; /* XXX yet another hack */ 371 gm->fboff = sc->sc_fbofs; 372 373 /* Perform common video attachment. */ 374 grf_establish(sc, NULL, grfiv_mode); 375 } 376 377 static int 378 grfiv_mode(struct grf_softc *sc, int cmd, void *arg) 379 { 380 switch (cmd) { 381 case GM_GRFON: 382 case GM_GRFOFF: 383 return 0; 384 case GM_CURRMODE: 385 break; 386 case GM_NEWMODE: 387 break; 388 case GM_LISTMODES: 389 break; 390 } 391 return EINVAL; 392 } 393 394 #define CHECK_INDEX(index) \ 395 do { \ 396 size_t depth = mac68k_video.mv_depth; \ 397 if (depth == 1 || depth > 8 || (index) >= (1 << depth)) \ 398 return; \ 399 } while (0 /* CONSTCOND */) 400 401 static void 402 dafb_set_mapreg(void *cookie, int index, int r, int g, int b) 403 { 404 struct grfbus_softc *sc = (struct grfbus_softc *)cookie; 405 static int last = -2; 406 407 CHECK_INDEX(index); 408 409 #define dafb_write_lut(val) \ 410 bus_space_write_1(sc->sc_tag, sc->sc_cmh, DAFB_CMAP_LUT, val) 411 412 if (index != last + 1) { 413 bus_space_write_4(sc->sc_tag, sc->sc_cmh, DAFB_CMAP_RESET, 0); 414 for (int i = 0; i < index; i++) { 415 dafb_write_lut(sc->sc_cmap.red[i]); 416 dafb_write_lut(sc->sc_cmap.green[i]); 417 dafb_write_lut(sc->sc_cmap.blue[i]); 418 } 419 } 420 421 dafb_write_lut(r); 422 dafb_write_lut(g); 423 dafb_write_lut(b); 424 425 last = index; 426 sc->sc_cmap.red[index] = r; 427 sc->sc_cmap.green[index] = g; 428 sc->sc_cmap.blue[index] = b; 429 430 #undef dafb_write_lut 431 432 } 433 434 static void 435 civic_set_mapreg(void *cookie, int index, int r, int g, int b) 436 { 437 struct grfbus_softc *sc = (struct grfbus_softc *)cookie; 438 uint8_t status, junk = 0; 439 440 CHECK_INDEX(index); 441 442 #define civic_read_lut \ 443 bus_space_read_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_LUT) 444 #define civic_write_lut(val) \ 445 bus_space_write_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_LUT, val) 446 447 bus_space_write_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_ADDR, index); 448 status = bus_space_read_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_STATUS2); 449 if (status & 0x08) { 450 junk = civic_read_lut; 451 junk = civic_read_lut; 452 junk = civic_read_lut; 453 junk = civic_read_lut; 454 if (status & 0x0d) { 455 civic_write_lut(0); 456 civic_write_lut(0); 457 } 458 } 459 civic_write_lut(r); 460 civic_write_lut(g); 461 civic_write_lut(b); 462 civic_write_lut(junk); 463 464 #undef civic_read_lut 465 #undef civic_write_lut 466 467 } 468 469 static void 470 valkyrie_set_mapreg(void *cookie, int index, int r, int g, int b) 471 { 472 struct grfbus_softc *sc = (struct grfbus_softc *)cookie; 473 474 CHECK_INDEX(index); 475 476 #define valkyrie_write_lut(val) \ 477 bus_space_write_1(sc->sc_tag, sc->sc_cmh, VALKYRIE_CMAP_LUT, val) 478 479 bus_space_write_1(sc->sc_tag, sc->sc_cmh, VALKYRIE_CMAP_ADDR, index); 480 delay(1); 481 valkyrie_write_lut(r); 482 valkyrie_write_lut(g); 483 valkyrie_write_lut(b); 484 485 #undef valkyrie_write_lut 486 487 } 488 489 static void 490 rbv_set_mapreg(void *cookie, int index, int r, int g, int b) 491 { 492 struct grfbus_softc *sc = (struct grfbus_softc *)cookie; 493 494 CHECK_INDEX(index); 495 496 #define rbv_write_lut(val) \ 497 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_LUT, val) 498 499 index += 256 - (1 << mac68k_video.mv_depth); 500 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_CNTL, 0xff); 501 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_ADDR, index); 502 rbv_write_lut(r); 503 rbv_write_lut(g); 504 rbv_write_lut(b); 505 506 #undef rbv_write_lut 507 508 } 509 510 #undef CHECK_INDEX 511