1 /* $NetBSD: et4000.c,v 1.5 2000/06/26 04:55:35 simonb 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/param.h> 55 #include <sys/ioctl.h> 56 #include <sys/queue.h> 57 #include <sys/malloc.h> 58 #include <sys/device.h> 59 #include <sys/systm.h> 60 #include <sys/conf.h> 61 #include <atari/vme/vmevar.h> 62 63 #include <machine/iomap.h> 64 #include <machine/video.h> 65 #include <machine/mfp.h> 66 #include <machine/cpu.h> 67 #include <atari/atari/device.h> 68 #include <atari/dev/grfioctl.h> 69 #include <atari/dev/grf_etreg.h> 70 71 /* 72 * Allow a 8Kb io-region and a 1MB frame buffer to be mapped. This 73 * is more or less required by the XFree server. The X server also 74 * requires that the frame buffer be mapped above 0x3fffff. 75 */ 76 #define REG_MAPPABLE (8 * 1024) /* 0x2000 */ 77 #define FRAME_MAPPABLE (1 * 1024 * 1024) /* 0x100000 */ 78 #define FRAME_BASE (4 * 1024 * 1024) /* 0x400000 */ 79 #define VGA_MAPPABLE (128 * 1024) /* 0x20000 */ 80 #define VGA_BASE 0xa0000 81 82 static int et_vme_match __P((struct device *, struct cfdata *, void *)); 83 static void et_vme_attach __P((struct device *, struct device *, void *)); 84 static int et_probe_addresses __P((struct vme_attach_args *)); 85 static void et_start __P((bus_space_tag_t *, bus_space_handle_t *, int *, 86 u_char *)); 87 static void et_stop __P((bus_space_tag_t *, bus_space_handle_t *, int *, 88 u_char *)); 89 static int et_detect __P((bus_space_tag_t *, bus_space_tag_t *, 90 bus_space_handle_t *, bus_space_handle_t *, u_int)); 91 92 dev_decl(et,open); 93 dev_decl(et,close); 94 dev_decl(et,read); 95 dev_decl(et,write); 96 dev_decl(et,ioctl); 97 dev_decl(et,mmap); 98 99 int eton __P((dev_t)); 100 int etoff __P((dev_t)); 101 102 /* Register and screen memory addresses for ET4000 based VME cards */ 103 static struct et_addresses { 104 u_long io_addr; 105 u_long io_size; 106 u_long mem_addr; 107 u_long mem_size; 108 } etstd[] = { 109 { 0xfebf0000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE }, /* Crazy Dots VME & II */ 110 { 0xfed00000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE }, /* Spektrum I & HC */ 111 { 0xfed80000, REG_MAPPABLE, 0xfec00000, FRAME_MAPPABLE } /* Spektrum TC */ 112 }; 113 114 #define NETSTD (sizeof(etstd) / sizeof(etstd[0])) 115 116 struct grfabs_et_priv { 117 volatile caddr_t regkva; 118 volatile caddr_t memkva; 119 int regsz; 120 int memsz; 121 } et_priv; 122 123 struct et_softc { 124 struct device sc_dev; 125 bus_space_tag_t sc_iot; 126 bus_space_tag_t sc_memt; 127 bus_space_handle_t sc_ioh; 128 bus_space_handle_t sc_memh; 129 int sc_flags; 130 int sc_iobase; 131 int sc_maddr; 132 int sc_iosize; 133 int sc_msize; 134 }; 135 136 #define ET_SC_FLAGS_INUSE 1 137 138 struct cfattach et_ca = { 139 sizeof(struct et_softc), et_vme_match, et_vme_attach 140 }; 141 142 extern struct cfdriver et_cd; 143 144 /* 145 * Look for a ET4000 (Crazy Dots) card on the VME bus. We might 146 * match Spektrum cards too (untested). 147 */ 148 int 149 et_vme_match(pdp, cfp, auxp) 150 struct device *pdp; 151 struct cfdata *cfp; 152 void *auxp; 153 { 154 struct vme_attach_args *va = auxp; 155 156 return(et_probe_addresses(va)); 157 } 158 159 static int 160 et_probe_addresses(va) 161 struct vme_attach_args *va; 162 { 163 int i, found = 0; 164 bus_space_tag_t iot; 165 bus_space_tag_t memt; 166 bus_space_handle_t ioh; 167 bus_space_handle_t memh; 168 169 iot = va->va_iot; 170 memt = va->va_memt; 171 172 /* Loop around our possible addresses looking for a match */ 173 for (i = 0; i < NETSTD; i++) { 174 struct et_addresses *et_ap = &etstd[i]; 175 struct vme_attach_args vat = *va; 176 177 if (vat.va_irq != VMECF_IRQ_DEFAULT) { 178 printf("et probe: config error: no irq support\n"); 179 return(0); 180 } 181 if (vat.va_iobase == VMECF_IOPORT_DEFAULT) 182 vat.va_iobase = et_ap->io_addr; 183 if (vat.va_maddr == VMECF_MEM_DEFAULT) 184 vat.va_maddr = et_ap->mem_addr; 185 if (vat.va_iosize == VMECF_IOSIZE_DEFAULT) 186 vat.va_iosize = et_ap->io_size; 187 if (vat.va_msize == VMECF_MEMSIZ_DEFAULT) 188 vat.va_msize = et_ap->mem_size; 189 if (bus_space_map(iot, vat.va_iobase, vat.va_iosize, 0, 190 &ioh)) { 191 printf("et probe: cannot map io area\n"); 192 return(0); 193 } 194 if (bus_space_map(memt, vat.va_maddr, vat.va_msize, 195 BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_CACHEABLE, 196 &memh)) { 197 bus_space_unmap(iot, ioh, vat.va_iosize); 198 printf("et probe: cannot map memory area\n"); 199 return(0); 200 } 201 found = et_detect(&iot, &memt, &ioh, &memh, vat.va_msize); 202 bus_space_unmap(iot, ioh, vat.va_iosize); 203 bus_space_unmap(memt, memh, vat.va_msize); 204 if (found) { 205 *va = vat; 206 return(1); 207 } 208 } 209 return(0); 210 } 211 212 static void 213 et_start(iot, ioh, vgabase, saved) 214 bus_space_tag_t *iot; 215 bus_space_handle_t *ioh; 216 int *vgabase; 217 u_char *saved; 218 { 219 /* Enable VGA */ 220 bus_space_write_1(*iot, *ioh, GREG_VIDEOSYSENABLE, 0x01); 221 /* Check whether colour (base = 3d0) or mono (base = 3b0) mode */ 222 *vgabase = (bus_space_read_1(*iot, *ioh, GREG_MISC_OUTPUT_R) & 0x01) 223 ? 0x3d0 : 0x3b0; 224 /* Enable 'Tseng Extensions' - writes to CRTC and ATC[16] */ 225 bus_space_write_1(*iot, *ioh, GREG_HERCULESCOMPAT, 0x03); 226 bus_space_write_1(*iot, *ioh, *vgabase + 0x08, 0xa0); 227 /* Set up 16 bit I/O, memory, Tseng addressing and linear mapping */ 228 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x36); 229 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, 0xf0); 230 /* Enable writes to CRTC[0..7] */ 231 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x11); 232 *saved = bus_space_read_1(*iot, *ioh, *vgabase + 0x05); 233 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, *saved & 0x7f); 234 /* Map all memory for video modes */ 235 bus_space_write_1(*iot, *ioh, 0x3ce, 0x06); 236 bus_space_write_1(*iot, *ioh, 0x3cf, 0x01); 237 } 238 239 static void 240 et_stop(iot, ioh, vgabase, saved) 241 bus_space_tag_t *iot; 242 bus_space_handle_t *ioh; 243 int *vgabase; 244 u_char *saved; 245 { 246 /* Restore writes to CRTC[0..7] */ 247 bus_space_write_1(*iot, *ioh, *vgabase + 0x04, 0x11); 248 *saved = bus_space_read_1(*iot, *ioh, *vgabase + 0x05); 249 bus_space_write_1(*iot, *ioh, *vgabase + 0x05, *saved | 0x80); 250 /* Disable 'Tseng Extensions' */ 251 bus_space_write_1(*iot, *ioh, *vgabase + 0x08, 0x00); 252 bus_space_write_1(*iot, *ioh, GREG_DISPMODECONTROL, 0x29); 253 bus_space_write_1(*iot, *ioh, GREG_HERCULESCOMPAT, 0x01); 254 } 255 256 static int 257 et_detect(iot, memt, ioh, memh, memsize) 258 bus_space_tag_t *iot, *memt; 259 bus_space_handle_t *ioh, *memh; 260 u_int memsize; 261 { 262 u_char orig, new, saved; 263 int vgabase; 264 265 /* Test accessibility of registers and memory */ 266 if(!bus_space_peek_1(*iot, *ioh, GREG_STATUS1_R)) 267 return(0); 268 if(!bus_space_peek_1(*memt, *memh, 0)) 269 return(0); 270 271 et_start(iot, ioh, &vgabase, &saved); 272 273 /* Is the card a Tseng card? Check read/write of ATC[16] */ 274 (void)bus_space_read_1(*iot, *ioh, vgabase + 0x0a); 275 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, 0x16 | 0x20); 276 orig = bus_space_read_1(*iot, *ioh, ACT_ADDRESS_R); 277 bus_space_write_1(*iot, *ioh, ACT_ADDRESS_W, (orig ^ 0x10)); 278 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, 0x16 | 0x20); 279 new = bus_space_read_1(*iot, *ioh, ACT_ADDRESS_R); 280 bus_space_write_1(*iot, *ioh, ACT_ADDRESS, orig); 281 if (new != (orig ^ 0x10)) { 282 #ifdef DEBUG_ET4000 283 printf("et4000: ATC[16] failed (%x != %x)\n", 284 new, (orig ^ 0x10)); 285 #else 286 et_stop(iot, ioh, &vgabase, &saved); 287 return(0); 288 #endif 289 } 290 /* Is the card and ET4000? Check read/write of CRTC[33] */ 291 bus_space_write_1(*iot, *ioh, vgabase + 0x04, 0x33); 292 orig = bus_space_read_1(*iot, *ioh, vgabase + 0x05); 293 bus_space_write_1(*iot, *ioh, vgabase + 0x05, (orig ^ 0x0f)); 294 new = bus_space_read_1(*iot, *ioh, vgabase + 0x05); 295 bus_space_write_1(*iot, *ioh, vgabase + 0x05, orig); 296 if (new != (orig ^ 0x0f)) { 297 #ifdef DEBUG_ET4000 298 printf("et4000: CRTC[33] failed (%x != %x)\n", 299 new, (orig ^ 0x0f)); 300 #else 301 et_stop(iot, ioh, &vgabase, &saved); 302 return(0); 303 #endif 304 } 305 306 /* Set up video memory so we can read & write it */ 307 bus_space_write_1(*iot, *ioh, 0x3c4, 0x04); 308 bus_space_write_1(*iot, *ioh, 0x3c5, 0x06); 309 bus_space_write_1(*iot, *ioh, 0x3c4, 0x07); 310 bus_space_write_1(*iot, *ioh, 0x3c5, 0xa8); 311 bus_space_write_1(*iot, *ioh, 0x3ce, 0x01); 312 bus_space_write_1(*iot, *ioh, 0x3cf, 0x00); 313 bus_space_write_1(*iot, *ioh, 0x3ce, 0x03); 314 bus_space_write_1(*iot, *ioh, 0x3cf, 0x00); 315 bus_space_write_1(*iot, *ioh, 0x3ce, 0x05); 316 bus_space_write_1(*iot, *ioh, 0x3cf, 0x40); 317 318 #define TEST_PATTERN 0xa5a5a5a5 319 320 bus_space_write_4(*memt, *memh, 0x0, TEST_PATTERN); 321 if (bus_space_read_4(*memt, *memh, 0x0) != TEST_PATTERN) 322 { 323 #ifdef DEBUG_ET4000 324 printf("et4000: Video base write/read failed\n"); 325 #else 326 et_stop(iot, ioh, &vgabase, &saved); 327 return(0); 328 #endif 329 } 330 bus_space_write_4(*memt, *memh, memsize - 4, TEST_PATTERN); 331 if (bus_space_read_4(*memt, *memh, memsize - 4) != TEST_PATTERN) 332 { 333 #ifdef DEBUG_ET4000 334 printf("et4000: Video top write/read failed\n"); 335 #else 336 et_stop(iot, ioh, &vgabase, &saved); 337 return(0); 338 #endif 339 } 340 341 et_stop(iot, ioh, &vgabase, &saved); 342 return(1); 343 } 344 345 static void 346 et_vme_attach(parent, self, aux) 347 struct device *parent, *self; 348 void *aux; 349 { 350 struct et_softc *sc = (struct et_softc *)self; 351 struct vme_attach_args *va = aux; 352 bus_space_handle_t ioh; 353 bus_space_handle_t memh; 354 355 printf("\n"); 356 357 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 358 panic("et attach: cannot map io area\n"); 359 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 360 panic("et attach: cannot map mem area\n"); 361 362 sc->sc_iot = va->va_iot; 363 sc->sc_ioh = ioh; 364 sc->sc_memt = va->va_memt; 365 sc->sc_memh = memh; 366 sc->sc_flags = 0; 367 sc->sc_iobase = va->va_iobase; 368 sc->sc_maddr = va->va_maddr; 369 sc->sc_iosize = va->va_iosize; 370 sc->sc_msize = va->va_msize; 371 372 et_priv.regkva = (volatile caddr_t)ioh; 373 et_priv.memkva = (volatile caddr_t)memh; 374 et_priv.regsz = va->va_iosize; 375 et_priv.memsz = va->va_msize; 376 } 377 378 int 379 etopen(dev, flags, devtype, p) 380 dev_t dev; 381 int flags, devtype; 382 struct proc *p; 383 { 384 struct et_softc *sc; 385 386 if (minor(dev) >= et_cd.cd_ndevs) 387 return(ENXIO); 388 sc = et_cd.cd_devs[minor(dev)]; 389 if (sc->sc_flags & ET_SC_FLAGS_INUSE) 390 return(EBUSY); 391 sc->sc_flags |= ET_SC_FLAGS_INUSE; 392 return(0); 393 } 394 395 int 396 etclose(dev, flags, devtype, p) 397 dev_t dev; 398 int flags, devtype; 399 struct proc *p; 400 { 401 struct et_softc *sc; 402 403 /* 404 * XXX: Should we reset to a default mode? 405 */ 406 sc = et_cd.cd_devs[minor(dev)]; 407 sc->sc_flags &= ~ET_SC_FLAGS_INUSE; 408 return(0); 409 } 410 411 int 412 etread(dev, uio, flags) 413 dev_t dev; 414 struct uio *uio; 415 int flags; 416 { 417 return(EINVAL); 418 } 419 420 int 421 etwrite(dev, uio, flags) 422 dev_t dev; 423 struct uio *uio; 424 int flags; 425 { 426 return(EINVAL); 427 } 428 429 int 430 etioctl(dev, cmd, data, flags, p) 431 dev_t dev; 432 u_long cmd; 433 caddr_t data; 434 int flags; 435 struct proc *p; 436 { 437 struct grfinfo g_display; 438 struct et_softc *sc; 439 440 sc = et_cd.cd_devs[minor(dev)]; 441 switch (cmd) { 442 case GRFIOCON: 443 return(0); 444 break; 445 case GRFIOCOFF: 446 return(0); 447 break; 448 case GRFIOCGINFO: 449 g_display.gd_fbaddr = (caddr_t) (sc->sc_maddr); 450 g_display.gd_fbsize = sc->sc_msize; 451 g_display.gd_linbase = FRAME_BASE; 452 g_display.gd_regaddr = (caddr_t) (sc->sc_iobase); 453 g_display.gd_regsize = sc->sc_iosize; 454 g_display.gd_vgaaddr = (caddr_t) (sc->sc_maddr); 455 g_display.gd_vgasize = VGA_MAPPABLE; 456 g_display.gd_vgabase = VGA_BASE; 457 g_display.gd_colors = 16; 458 g_display.gd_planes = 4; 459 g_display.gd_fbwidth = 640; /* XXX: should be 'unknown' */ 460 g_display.gd_fbheight = 400; /* XXX: should be 'unknown' */ 461 g_display.gd_fbx = 0; 462 g_display.gd_fby = 0; 463 g_display.gd_dwidth = 0; 464 g_display.gd_dheight = 0; 465 g_display.gd_dx = 0; 466 g_display.gd_dy = 0; 467 g_display.gd_bank_size = 0; 468 bcopy((caddr_t)&g_display, data, sizeof(struct grfinfo)); 469 break; 470 case GRFIOCMAP: 471 return(EINVAL); 472 break; 473 case GRFIOCUNMAP: 474 return(EINVAL); 475 break; 476 default: 477 return(EINVAL); 478 break; 479 } 480 return(0); 481 } 482 483 paddr_t 484 etmmap(dev, offset, prot) 485 dev_t dev; 486 off_t offset; 487 int prot; 488 { 489 struct et_softc *sc; 490 491 sc = et_cd.cd_devs[minor(dev)]; 492 493 /* 494 * control registers 495 * mapped from offset 0x0 to REG_MAPPABLE 496 */ 497 if (offset >= 0 && offset <= sc->sc_iosize) 498 return(m68k_btop(sc->sc_iobase + offset)); 499 500 /* 501 * VGA memory 502 * mapped from offset 0xa0000 to 0xc0000 503 */ 504 if (offset >= VGA_BASE && offset < (VGA_MAPPABLE + VGA_BASE)) 505 return(m68k_btop(sc->sc_maddr + offset - VGA_BASE)); 506 507 /* 508 * frame buffer 509 * mapped from offset 0x400000 to 0x4fffff 510 */ 511 if (offset >= FRAME_BASE && offset < sc->sc_msize + FRAME_BASE) 512 return(m68k_btop(sc->sc_maddr + offset - FRAME_BASE)); 513 514 return(-1); 515 } 516 517 int 518 eton(dev) 519 dev_t dev; 520 { 521 struct et_softc *sc; 522 523 if (minor(dev) >= et_cd.cd_ndevs) 524 return(ENXIO); 525 sc = et_cd.cd_devs[minor(dev)]; 526 if (!sc) 527 return(ENXIO); 528 return(0); 529 } 530 531 int 532 etoff(dev) 533 dev_t dev; 534 { 535 return(0); 536 } 537 538