1 /* $NetBSD: et4000.c,v 1.12 2005/12/11 12:17:02 christos Exp $ */ 2 /*- 3 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Julian Coleman. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Thanks to: 40 * Leo Weppelman 41 * 'Maximum Entropy' 42 * Thomas Gerner 43 * Juergen Orscheidt 44 * for their help and for code that I could refer to when writing this driver. 45 * 46 * Defining DEBUG_ET4000 will cause the driver to *always* attach. Use for 47 * debugging register settings. 48 */ 49 50 /* 51 #define DEBUG_ET4000 52 */ 53 54 #include <sys/cdefs.h> 55 __KERNEL_RCSID(0, "$NetBSD: et4000.c,v 1.12 2005/12/11 12:17:02 christos Exp $"); 56 57 #include <sys/param.h> 58 #include <sys/ioctl.h> 59 #include <sys/queue.h> 60 #include <sys/malloc.h> 61 #include <sys/device.h> 62 #include <sys/systm.h> 63 #include <sys/conf.h> 64 #include <sys/event.h> 65 #include <atari/vme/vmevar.h> 66 67 #include <machine/iomap.h> 68 #include <machine/video.h> 69 #include <machine/mfp.h> 70 #include <machine/cpu.h> 71 #include <atari/atari/device.h> 72 #include <atari/dev/grfioctl.h> 73 #include <atari/dev/grf_etreg.h> 74 75 /* 76 * Allow a 8Kb io-region and a 1MB frame buffer to be mapped. This 77 * is more or less required by the XFree server. The X server also 78 * requires that the frame buffer be mapped above 0x3fffff. 79 */ 80 #define REG_MAPPABLE (8 * 1024) /* 0x2000 */ 81 #define FRAME_MAPPABLE (1 * 1024 * 1024) /* 0x100000 */ 82 #define FRAME_BASE (4 * 1024 * 1024) /* 0x400000 */ 83 #define VGA_MAPPABLE (128 * 1024) /* 0x20000 */ 84 #define VGA_BASE 0xa0000 85 86 static int et_vme_match __P((struct device *, struct cfdata *, void *)); 87 static void et_vme_attach __P((struct device *, struct device *, void *)); 88 static int et_probe_addresses __P((struct vme_attach_args *)); 89 static void et_start __P((bus_space_tag_t *, bus_space_handle_t *, int *, 90 u_char *)); 91 static void et_stop __P((bus_space_tag_t *, bus_space_handle_t *, int *, 92 u_char *)); 93 static int et_detect __P((bus_space_tag_t *, bus_space_tag_t *, 94 bus_space_handle_t *, bus_space_handle_t *, u_int)); 95 96 int eton __P((dev_t)); 97 int etoff __P((dev_t)); 98 99 /* Register and screen memory addresses for ET4000 based VME cards */ 100 static struct et_addresses { 101 u_long io_addr; 102 u_long io_size; 103 u_long mem_addr; 104 u_long mem_size; 105 } etstd[] = { 106 { 0xfebf0000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE }, /* Crazy Dots VME & II */ 107 { 0xfed00000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE }, /* Spektrum I & HC */ 108 { 0xfed80000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE } /* Spektrum TC */ 109 }; 110 111 #define NETSTD (sizeof(etstd) / sizeof(etstd[0])) 112 113 struct grfabs_et_priv { 114 volatile caddr_t regkva; 115 volatile caddr_t memkva; 116 int regsz; 117 int memsz; 118 } et_priv; 119 120 struct et_softc { 121 struct device sc_dev; 122 bus_space_tag_t sc_iot; 123 bus_space_tag_t sc_memt; 124 bus_space_handle_t sc_ioh; 125 bus_space_handle_t sc_memh; 126 int sc_flags; 127 int sc_iobase; 128 int sc_maddr; 129 int sc_iosize; 130 int sc_msize; 131 }; 132 133 #define ET_SC_FLAGS_INUSE 1 134 135 CFATTACH_DECL(et, sizeof(struct et_softc), 136 et_vme_match, et_vme_attach, NULL, NULL); 137 138 extern struct cfdriver et_cd; 139 140 dev_type_open(etopen); 141 dev_type_close(etclose); 142 dev_type_read(etread); 143 dev_type_write(etwrite); 144 dev_type_ioctl(etioctl); 145 dev_type_mmap(etmmap); 146 147 const struct cdevsw et_cdevsw = { 148 etopen, etclose, etread, etwrite, etioctl, 149 nostop, notty, nopoll, etmmap, nokqfilter, 150 }; 151 152 /* 153 * Look for a ET4000 (Crazy Dots) card on the VME bus. We might 154 * match Spektrum cards too (untested). 155 */ 156 int 157 et_vme_match(pdp, cfp, auxp) 158 struct device *pdp; 159 struct cfdata *cfp; 160 void *auxp; 161 { 162 struct vme_attach_args *va = auxp; 163 164 return(et_probe_addresses(va)); 165 } 166 167 static int 168 et_probe_addresses(va) 169 struct vme_attach_args *va; 170 { 171 int i, found = 0; 172 bus_space_tag_t iot; 173 bus_space_tag_t memt; 174 bus_space_handle_t ioh; 175 bus_space_handle_t memh; 176 177 iot = va->va_iot; 178 memt = va->va_memt; 179 180 /* Loop around our possible addresses looking for a match */ 181 for (i = 0; i < NETSTD; i++) { 182 struct et_addresses *et_ap = &etstd[i]; 183 struct vme_attach_args vat = *va; 184 185 if (vat.va_irq != VMECF_IRQ_DEFAULT) { 186 printf("et probe: config error: no irq support\n"); 187 return(0); 188 } 189 if (vat.va_iobase == VMECF_IOPORT_DEFAULT) 190 vat.va_iobase = et_ap->io_addr; 191 if (vat.va_maddr == VMECF_MEM_DEFAULT) 192 vat.va_maddr = et_ap->mem_addr; 193 if (vat.va_iosize == VMECF_IOSIZE_DEFAULT) 194 vat.va_iosize = et_ap->io_size; 195 if (vat.va_msize == VMECF_MEMSIZ_DEFAULT) 196 vat.va_msize = et_ap->mem_size; 197 if (bus_space_map(iot, vat.va_iobase, vat.va_iosize, 0, 198 &ioh)) { 199 printf("et probe: cannot map io area\n"); 200 return(0); 201 } 202 if (bus_space_map(memt, vat.va_maddr, vat.va_msize, 203 BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_CACHEABLE, 204 &memh)) { 205 bus_space_unmap(iot, ioh, vat.va_iosize); 206 printf("et probe: cannot map memory area\n"); 207 return(0); 208 } 209 found = et_detect(&iot, &memt, &ioh, &memh, vat.va_msize); 210 bus_space_unmap(iot, ioh, vat.va_iosize); 211 bus_space_unmap(memt, memh, vat.va_msize); 212 if (found) { 213 *va = vat; 214 return(1); 215 } 216 } 217 return(0); 218 } 219 220 static void 221 et_start(iot, ioh, vgabase, saved) 222 bus_space_tag_t *iot; 223 bus_space_handle_t *ioh; 224 int *vgabase; 225 u_char *saved; 226 { 227 /* Enable VGA */ 228 bus_space_write_1(*iot, *ioh, GREG_VIDEOSYSENABLE, 0x01); 229 /* Check whether colour (base = 3d0) or mono (base = 3b0) mode */ 230 *vgabase = (bus_space_read_1(*iot, *ioh, GREG_MISC_OUTPUT_R) & 0x01) 231 ? 0x3d0 : 0x3b0; 232 /* Enable 'Tseng Extensions' - writes to CRTC and ATC[16] */ 233 bus_space_write_1(*iot, *ioh, GREG_HERCULESCOMPAT, 0x03); 234 bus_space_write_1(*iot, *ioh, *vgabase + 0x08, 0xa0); 235 /* Set up 16 bit I/O, memory, Tseng addressing and linear mapping */ 236 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x36); 237 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, 0xf0); 238 /* Enable writes to CRTC[0..7] */ 239 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x11); 240 *saved = bus_space_read_1(*iot, *ioh, *vgabase + 0x05); 241 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, *saved & 0x7f); 242 /* Map all memory for video modes */ 243 bus_space_write_1(*iot, *ioh, 0x3ce, 0x06); 244 bus_space_write_1(*iot, *ioh, 0x3cf, 0x01); 245 } 246 247 static void 248 et_stop(iot, ioh, vgabase, saved) 249 bus_space_tag_t *iot; 250 bus_space_handle_t *ioh; 251 int *vgabase; 252 u_char *saved; 253 { 254 /* Restore writes to CRTC[0..7] */ 255 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x11); 256 *saved = bus_space_read_1(*iot, *ioh, *vgabase + 0x05); 257 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, *saved | 0x80); 258 /* Disable 'Tseng Extensions' */ 259 bus_space_write_1(*iot, *ioh, *vgabase + 0x08, 0x00); 260 bus_space_write_1(*iot, *ioh, GREG_DISPMODECONTROL, 0x29); 261 bus_space_write_1(*iot, *ioh, GREG_HERCULESCOMPAT, 0x01); 262 } 263 264 static int 265 et_detect(iot, memt, ioh, memh, memsize) 266 bus_space_tag_t *iot, *memt; 267 bus_space_handle_t *ioh, *memh; 268 u_int memsize; 269 { 270 u_char orig, new, saved; 271 int vgabase; 272 273 /* Test accessibility of registers and memory */ 274 if(!bus_space_peek_1(*iot, *ioh, GREG_STATUS1_R)) 275 return(0); 276 if(!bus_space_peek_1(*memt, *memh, 0)) 277 return(0); 278 279 et_start(iot, ioh, &vgabase, &saved); 280 281 /* Is the card a Tseng card? Check read/write of ATC[16] */ 282 (void)bus_space_read_1(*iot, *ioh, vgabase + 0x0a); 283 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, 0x16 | 0x20); 284 orig = bus_space_read_1(*iot, *ioh, ACT_ADDRESS_R); 285 bus_space_write_1(*iot, *ioh, ACT_ADDRESS_W, (orig ^ 0x10)); 286 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, 0x16 | 0x20); 287 new = bus_space_read_1(*iot, *ioh, ACT_ADDRESS_R); 288 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, orig); 289 if (new != (orig ^ 0x10)) { 290 #ifdef DEBUG_ET4000 291 printf("et4000: ATC[16] failed (%x != %x)\n", 292 new, (orig ^ 0x10)); 293 #else 294 et_stop(iot, ioh, &vgabase, &saved); 295 return(0); 296 #endif 297 } 298 /* Is the card and ET4000? Check read/write of CRTC[33] */ 299 bus_space_write_1(*iot, *ioh, vgabase + 0x04, 0x33); 300 orig = bus_space_read_1(*iot, *ioh, vgabase + 0x05); 301 bus_space_write_1(*iot, *ioh, vgabase + 0x05, (orig ^ 0x0f)); 302 new = bus_space_read_1(*iot, *ioh, vgabase + 0x05); 303 bus_space_write_1(*iot, *ioh, vgabase + 0x05, orig); 304 if (new != (orig ^ 0x0f)) { 305 #ifdef DEBUG_ET4000 306 printf("et4000: CRTC[33] failed (%x != %x)\n", 307 new, (orig ^ 0x0f)); 308 #else 309 et_stop(iot, ioh, &vgabase, &saved); 310 return(0); 311 #endif 312 } 313 314 /* Set up video memory so we can read & write it */ 315 bus_space_write_1(*iot, *ioh, 0x3c4, 0x04); 316 bus_space_write_1(*iot, *ioh, 0x3c5, 0x06); 317 bus_space_write_1(*iot, *ioh, 0x3c4, 0x07); 318 bus_space_write_1(*iot, *ioh, 0x3c5, 0xa8); 319 bus_space_write_1(*iot, *ioh, 0x3ce, 0x01); 320 bus_space_write_1(*iot, *ioh, 0x3cf, 0x00); 321 bus_space_write_1(*iot, *ioh, 0x3ce, 0x03); 322 bus_space_write_1(*iot, *ioh, 0x3cf, 0x00); 323 bus_space_write_1(*iot, *ioh, 0x3ce, 0x05); 324 bus_space_write_1(*iot, *ioh, 0x3cf, 0x40); 325 326 #define TEST_PATTERN 0xa5a5a5a5 327 328 bus_space_write_4(*memt, *memh, 0x0, TEST_PATTERN); 329 if (bus_space_read_4(*memt, *memh, 0x0) != TEST_PATTERN) 330 { 331 #ifdef DEBUG_ET4000 332 printf("et4000: Video base write/read failed\n"); 333 #else 334 et_stop(iot, ioh, &vgabase, &saved); 335 return(0); 336 #endif 337 } 338 bus_space_write_4(*memt, *memh, memsize - 4, TEST_PATTERN); 339 if (bus_space_read_4(*memt, *memh, memsize - 4) != TEST_PATTERN) 340 { 341 #ifdef DEBUG_ET4000 342 printf("et4000: Video top write/read failed\n"); 343 #else 344 et_stop(iot, ioh, &vgabase, &saved); 345 return(0); 346 #endif 347 } 348 349 et_stop(iot, ioh, &vgabase, &saved); 350 return(1); 351 } 352 353 static void 354 et_vme_attach(parent, self, aux) 355 struct device *parent, *self; 356 void *aux; 357 { 358 struct et_softc *sc = (struct et_softc *)self; 359 struct vme_attach_args *va = aux; 360 bus_space_handle_t ioh; 361 bus_space_handle_t memh; 362 363 printf("\n"); 364 365 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 366 panic("et attach: cannot map io area"); 367 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 368 panic("et attach: cannot map mem area"); 369 370 sc->sc_iot = va->va_iot; 371 sc->sc_ioh = ioh; 372 sc->sc_memt = va->va_memt; 373 sc->sc_memh = memh; 374 sc->sc_flags = 0; 375 sc->sc_iobase = va->va_iobase; 376 sc->sc_maddr = va->va_maddr; 377 sc->sc_iosize = va->va_iosize; 378 sc->sc_msize = va->va_msize; 379 380 et_priv.regkva = (volatile caddr_t)ioh; 381 et_priv.memkva = (volatile caddr_t)memh; 382 et_priv.regsz = va->va_iosize; 383 et_priv.memsz = va->va_msize; 384 } 385 386 int 387 etopen(dev, flags, devtype, l) 388 dev_t dev; 389 int flags, devtype; 390 struct lwp *l; 391 { 392 struct et_softc *sc; 393 394 if (minor(dev) >= et_cd.cd_ndevs) 395 return(ENXIO); 396 sc = et_cd.cd_devs[minor(dev)]; 397 if (sc->sc_flags & ET_SC_FLAGS_INUSE) 398 return(EBUSY); 399 sc->sc_flags |= ET_SC_FLAGS_INUSE; 400 return(0); 401 } 402 403 int 404 etclose(dev, flags, devtype, l) 405 dev_t dev; 406 int flags, devtype; 407 struct lwp *l; 408 { 409 struct et_softc *sc; 410 411 /* 412 * XXX: Should we reset to a default mode? 413 */ 414 sc = et_cd.cd_devs[minor(dev)]; 415 sc->sc_flags &= ~ET_SC_FLAGS_INUSE; 416 return(0); 417 } 418 419 int 420 etread(dev, uio, flags) 421 dev_t dev; 422 struct uio *uio; 423 int flags; 424 { 425 return(EINVAL); 426 } 427 428 int 429 etwrite(dev, uio, flags) 430 dev_t dev; 431 struct uio *uio; 432 int flags; 433 { 434 return(EINVAL); 435 } 436 437 int 438 etioctl(dev, cmd, data, flags, l) 439 dev_t dev; 440 u_long cmd; 441 caddr_t data; 442 int flags; 443 struct lwp *l; 444 { 445 struct grfinfo g_display; 446 struct et_softc *sc; 447 448 sc = et_cd.cd_devs[minor(dev)]; 449 switch (cmd) { 450 case GRFIOCON: 451 return(0); 452 break; 453 case GRFIOCOFF: 454 return(0); 455 break; 456 case GRFIOCGINFO: 457 g_display.gd_fbaddr = (caddr_t) (sc->sc_maddr); 458 g_display.gd_fbsize = sc->sc_msize; 459 g_display.gd_linbase = FRAME_BASE; 460 g_display.gd_regaddr = (caddr_t) (sc->sc_iobase); 461 g_display.gd_regsize = sc->sc_iosize; 462 g_display.gd_vgaaddr = (caddr_t) (sc->sc_maddr); 463 g_display.gd_vgasize = VGA_MAPPABLE; 464 g_display.gd_vgabase = VGA_BASE; 465 g_display.gd_colors = 16; 466 g_display.gd_planes = 4; 467 g_display.gd_fbwidth = 640; /* XXX: should be 'unknown' */ 468 g_display.gd_fbheight = 400; /* XXX: should be 'unknown' */ 469 g_display.gd_fbx = 0; 470 g_display.gd_fby = 0; 471 g_display.gd_dwidth = 0; 472 g_display.gd_dheight = 0; 473 g_display.gd_dx = 0; 474 g_display.gd_dy = 0; 475 g_display.gd_bank_size = 0; 476 bcopy((caddr_t)&g_display, data, sizeof(struct grfinfo)); 477 break; 478 case GRFIOCMAP: 479 return(EINVAL); 480 break; 481 case GRFIOCUNMAP: 482 return(EINVAL); 483 break; 484 default: 485 return(EINVAL); 486 break; 487 } 488 return(0); 489 } 490 491 paddr_t 492 etmmap(dev, offset, prot) 493 dev_t dev; 494 off_t offset; 495 int prot; 496 { 497 struct et_softc *sc; 498 499 sc = et_cd.cd_devs[minor(dev)]; 500 501 /* 502 * control registers 503 * mapped from offset 0x0 to REG_MAPPABLE 504 */ 505 if (offset >= 0 && offset <= sc->sc_iosize) 506 return(m68k_btop(sc->sc_iobase + offset)); 507 508 /* 509 * VGA memory 510 * mapped from offset 0xa0000 to 0xc0000 511 */ 512 if (offset >= VGA_BASE && offset < (VGA_MAPPABLE + VGA_BASE)) 513 return(m68k_btop(sc->sc_maddr + offset - VGA_BASE)); 514 515 /* 516 * frame buffer 517 * mapped from offset 0x400000 to 0x4fffff 518 */ 519 if (offset >= FRAME_BASE && offset < sc->sc_msize + FRAME_BASE) 520 return(m68k_btop(sc->sc_maddr + offset - FRAME_BASE)); 521 522 return(-1); 523 } 524 525 int 526 eton(dev) 527 dev_t dev; 528 { 529 struct et_softc *sc; 530 531 if (minor(dev) >= et_cd.cd_ndevs) 532 return(ENXIO); 533 sc = et_cd.cd_devs[minor(dev)]; 534 if (!sc) 535 return(ENXIO); 536 return(0); 537 } 538 539 int 540 etoff(dev) 541 dev_t dev; 542 { 543 return(0); 544 } 545 546