1 /* $NetBSD: gayle_pcmcia.c,v 1.34 2021/08/07 16:18:41 thorpej Exp $ */ 2 3 /* public domain */ 4 5 #include <sys/cdefs.h> 6 __KERNEL_RCSID(0, "$NetBSD: gayle_pcmcia.c,v 1.34 2021/08/07 16:18:41 thorpej Exp $"); 7 8 /* PCMCIA front-end driver for A1200's and A600's. */ 9 10 #include <sys/param.h> 11 #include <sys/device.h> 12 #include <sys/kernel.h> 13 #include <sys/kthread.h> 14 #include <sys/systm.h> 15 16 #include <uvm/uvm.h> 17 18 #include <dev/pcmcia/pcmciareg.h> 19 #include <dev/pcmcia/pcmciavar.h> 20 21 #include <machine/cpu.h> 22 #include <amiga/amiga/custom.h> 23 #include <amiga/amiga/device.h> 24 #include <amiga/amiga/gayle.h> 25 #include <amiga/amiga/isr.h> 26 27 28 /* There is one of these for each slot. And yes, there is only one slot. */ 29 struct pccard_slot { 30 struct pccard_softc *sc; /* refer to `parent' */ 31 int (*intr_func)(void *); 32 void * intr_arg; 33 device_t card; 34 int flags; 35 #define SLOT_OCCUPIED 0x01 36 #define SLOT_NEW_CARD_EVENT 0x02 37 }; 38 39 struct pccard_softc { 40 struct bus_space_tag io_space; 41 struct bus_space_tag attr_space; 42 struct bus_space_tag mem_space; 43 struct pccard_slot devs[1]; 44 struct isr intr6; 45 struct isr intr2; 46 }; 47 48 static int pccard_probe(device_t, cfdata_t, void *); 49 static void pccard_attach(device_t, device_t, void *); 50 static void pccard_attach_slot(struct pccard_slot *); 51 static int pccard_intr6(void *); 52 static int pccard_intr2(void *); 53 static void pccard_kthread(void *); 54 55 static int pcf_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 56 struct pcmcia_mem_handle *); 57 static void pcf_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *); 58 static int pcf_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, 59 struct pcmcia_mem_handle *, bus_addr_t *, int *); 60 static void pcf_mem_unmap(pcmcia_chipset_handle_t, int); 61 static int pcf_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, 62 bus_size_t, struct pcmcia_io_handle *); 63 static void pcf_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *); 64 static int pcf_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, 65 struct pcmcia_io_handle *, int *); 66 static void pcf_io_unmap(pcmcia_chipset_handle_t, int); 67 static void *pcf_intr_establish(pcmcia_chipset_handle_t, 68 struct pcmcia_function *, int, int (*)(void *), void *); 69 static void pcf_intr_disestablish(pcmcia_chipset_handle_t, void *); 70 static void pcf_socket_enable(pcmcia_chipset_handle_t); 71 static void pcf_socket_disable(pcmcia_chipset_handle_t); 72 static void pcf_socket_settype(pcmcia_chipset_handle_t, int); 73 74 static bsr(pcmio_bsr1, u_int8_t); 75 static bsw(pcmio_bsw1, u_int8_t); 76 static bsrm(pcmio_bsrm1, u_int8_t); 77 static bswm(pcmio_bswm1, u_int8_t); 78 static bsrm(pcmio_bsrr1, u_int8_t); 79 static bswm(pcmio_bswr1, u_int8_t); 80 static bssr(pcmio_bssr1, u_int8_t); 81 static bscr(pcmio_bscr1, u_int8_t); 82 83 CFATTACH_DECL_NEW(pccard, sizeof(struct pccard_softc), 84 pccard_probe, pccard_attach, NULL, NULL); 85 86 static struct pcmcia_chip_functions chip_functions = { 87 pcf_mem_alloc, pcf_mem_free, 88 pcf_mem_map, pcf_mem_unmap, 89 pcf_io_alloc, pcf_io_free, 90 pcf_io_map, pcf_io_unmap, 91 pcf_intr_establish, pcf_intr_disestablish, 92 pcf_socket_enable, pcf_socket_disable, 93 pcf_socket_settype 94 }; 95 96 static struct amiga_bus_space_methods pcmio_bs_methods; 97 98 static u_int8_t *reset_card_reg; 99 100 static int 101 pccard_probe(device_t parent, cfdata_t cf, void *aux) 102 { 103 104 return (is_a600() || is_a1200()) && matchname(aux, "pccard"); 105 } 106 107 static void 108 pccard_attach(device_t parent, device_t self, void *aux) 109 { 110 struct pccard_softc *sc = device_private(self); 111 struct pcmciabus_attach_args paa; 112 vaddr_t pcmcia_base; 113 vaddr_t i; 114 115 printf("\n"); 116 117 gayle_init(); 118 119 pcmcia_base = uvm_km_alloc(kernel_map, 120 GAYLE_PCMCIA_END - GAYLE_PCMCIA_START, 121 0, UVM_KMF_VAONLY | UVM_KMF_NOWAIT); 122 if (pcmcia_base == 0) { 123 printf("attach failed (no virtual memory)\n"); 124 return; 125 } 126 127 for (i = GAYLE_PCMCIA_START; i < GAYLE_PCMCIA_END; i += PAGE_SIZE) 128 pmap_enter(vm_map_pmap(kernel_map), 129 i - GAYLE_PCMCIA_START + pcmcia_base, i, 130 VM_PROT_READ | VM_PROT_WRITE, true); 131 pmap_update(vm_map_pmap(kernel_map)); 132 133 /* override the one-byte access methods for I/O space */ 134 pcmio_bs_methods = amiga_bus_stride_1swap; 135 pcmio_bs_methods.bsr1 = pcmio_bsr1; 136 pcmio_bs_methods.bsw1 = pcmio_bsw1; 137 pcmio_bs_methods.bsrm1 = pcmio_bsrm1; 138 pcmio_bs_methods.bswm1 = pcmio_bswm1; 139 pcmio_bs_methods.bsrr1 = pcmio_bsrr1; 140 pcmio_bs_methods.bswr1 = pcmio_bswr1; 141 pcmio_bs_methods.bssr1 = pcmio_bssr1; 142 pcmio_bs_methods.bscr1 = pcmio_bscr1; 143 144 reset_card_reg = (u_int8_t *) pcmcia_base + 145 (GAYLE_PCMCIA_RESET - GAYLE_PCMCIA_START); 146 147 sc->io_space.base = (bus_addr_t) pcmcia_base + 148 (GAYLE_PCMCIA_IO_START - GAYLE_PCMCIA_START); 149 sc->io_space.absm = &pcmio_bs_methods; 150 151 sc->attr_space.base = (bus_addr_t) pcmcia_base + 152 (GAYLE_PCMCIA_ATTR_START - GAYLE_PCMCIA_START); 153 sc->attr_space.absm = &amiga_bus_stride_1; 154 155 /* XXX we should check if the 4M of common memory are actually 156 * RAM or PCMCIA usable. 157 * For now, we just do as if the 4M were RAM and make common memory 158 * point to attribute memory, which is OK for some I/O cards. 159 */ 160 sc->mem_space.base = (bus_addr_t) pcmcia_base; 161 sc->mem_space.absm = &amiga_bus_stride_1; 162 163 sc->devs[0].sc = sc; 164 sc->devs[0].intr_func = NULL; 165 sc->devs[0].intr_arg = NULL; 166 sc->devs[0].flags = 0; 167 168 gayle_pcmcia_status_write(0); 169 gayle_intr_ack(0); 170 gayle_pcmcia_config_write(0); 171 gayle_intr_enable_set(GAYLE_INT_IDE); 172 173 paa.paa_busname = "pcmcia"; 174 paa.pct = &chip_functions; 175 paa.pch = &sc->devs[0]; 176 sc->devs[0].card = config_found(self, &paa, simple_devprint, 177 CFARGS_NONE); 178 if (sc->devs[0].card == NULL) { 179 printf("attach failed, config_found() returned NULL\n"); 180 pmap_remove(kernel_map->pmap, pcmcia_base, 181 pcmcia_base + (GAYLE_PCMCIA_END - GAYLE_PCMCIA_START)); 182 pmap_update(kernel_map->pmap); 183 uvm_deallocate(kernel_map, pcmcia_base, 184 GAYLE_PCMCIA_END - GAYLE_PCMCIA_START); 185 return; 186 } 187 188 sc->intr6.isr_intr = pccard_intr6; 189 sc->intr6.isr_arg = sc; 190 sc->intr6.isr_ipl = 6; 191 add_isr(&sc->intr6); 192 193 sc->intr2.isr_intr = pccard_intr2; 194 sc->intr2.isr_arg = sc; 195 sc->intr2.isr_ipl = 2; 196 add_isr(&sc->intr2); 197 198 if (kthread_create(PRI_NONE, 0, NULL, pccard_kthread, sc, 199 NULL, "pccard")) { 200 printf("%s: can't create kernel thread\n", 201 device_xname(self)); 202 panic("pccard kthread_create() failed"); 203 } 204 205 gayle_intr_enable_set(GAYLE_INT_DETECT | GAYLE_INT_IREQ); 206 207 /* reset the card if it's already there */ 208 if (gayle_pcmcia_status_read() & GAYLE_CCMEM_DETECT) { 209 volatile u_int8_t x; 210 211 gayle_intr_ack(0xff); 212 delay(500); 213 gayle_intr_ack(0xfc); 214 215 delay(100*1000); 216 217 *reset_card_reg = 0x0; 218 delay(1000); 219 x = *reset_card_reg; 220 __USE(x); 221 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 222 } 223 224 pccard_attach_slot(&sc->devs[0]); 225 } 226 227 static int 228 pccard_intr6(void *arg) 229 { 230 struct pccard_softc *sc = arg; 231 232 if (gayle_intr_status() & GAYLE_INT_DETECT) { 233 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_STSCHG | 234 GAYLE_INT_SPKR | GAYLE_INT_WP | GAYLE_INT_IREQ); 235 sc->devs[0].flags |= SLOT_NEW_CARD_EVENT; 236 return 1; 237 } 238 return 0; 239 } 240 241 static int 242 pccard_intr2(void *arg) 243 { 244 struct pccard_softc *sc = arg; 245 struct pccard_slot *slot = &sc->devs[0]; 246 247 if (slot->flags & SLOT_NEW_CARD_EVENT) { 248 slot->flags &= ~SLOT_NEW_CARD_EVENT; 249 250 /* reset the registers */ 251 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_DETECT); 252 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 253 gayle_pcmcia_config_write(0); 254 pccard_attach_slot(&sc->devs[0]); 255 } else { 256 int intreq = gayle_intr_status() & 257 (GAYLE_INT_STSCHG | GAYLE_INT_WP | GAYLE_INT_IREQ); 258 if (intreq) { 259 gayle_intr_ack((intreq ^ 0x2c) | 0xc0); 260 261 return slot->flags & SLOT_OCCUPIED && 262 slot->intr_func != NULL && 263 slot->intr_func(slot->intr_arg); 264 } 265 } 266 return 0; 267 } 268 269 static void 270 pccard_kthread(void *arg) 271 { 272 struct pccard_softc *sc = arg; 273 struct pccard_slot *slot = &sc->devs[0]; 274 275 for (;;) { 276 int s = spl2(); 277 278 if (slot->flags & SLOT_NEW_CARD_EVENT) { 279 slot->flags &= ~SLOT_NEW_CARD_EVENT; 280 gayle_intr_ack(0xc0); 281 282 /* reset the registers */ 283 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_DETECT); 284 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 285 gayle_pcmcia_config_write(0); 286 pccard_attach_slot(&sc->devs[0]); 287 } 288 splx(s); 289 290 tsleep(slot, PWAIT, "pccthread", hz); 291 } 292 } 293 294 static void 295 pccard_attach_slot(struct pccard_slot *slot) 296 { 297 298 if (!(slot->flags & SLOT_OCCUPIED) && 299 gayle_pcmcia_status_read() & GAYLE_CCMEM_DETECT) { 300 if (pcmcia_card_attach(slot->card) == 0) 301 slot->flags |= SLOT_OCCUPIED; 302 } 303 } 304 305 static int 306 pcf_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t bsz, 307 struct pcmcia_mem_handle *pcmh) 308 { 309 struct pccard_slot *slot = (struct pccard_slot *) pch; 310 311 pcmh->memt = &slot->sc->attr_space; 312 pcmh->memh = pcmh->memt->base; 313 return 0; 314 } 315 316 static void 317 pcf_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *memh) 318 { 319 } 320 321 static int 322 pcf_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr, 323 bus_size_t size, struct pcmcia_mem_handle *pcmh, 324 bus_addr_t *offsetp, int *windowp) 325 { 326 struct pccard_slot *slot = (struct pccard_slot *) pch; 327 328 /* Ignore width requirements */ 329 kind &= ~PCMCIA_WIDTH_MEM_MASK; 330 331 switch (kind) { 332 case PCMCIA_MEM_ATTR: 333 pcmh->memt = &slot->sc->attr_space; 334 break; 335 case PCMCIA_MEM_COMMON: 336 pcmh->memt = &slot->sc->mem_space; 337 break; 338 default: 339 /* This means that this code needs an update/a bugfix */ 340 printf(__FILE__ ": unknown kind %d of PCMCIA memory\n", kind); 341 return 1; 342 } 343 344 bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh); 345 *offsetp = 0; 346 *windowp = 0; /* unused */ 347 348 return 0; 349 } 350 351 static void 352 pcf_mem_unmap(pcmcia_chipset_handle_t pch, int win) 353 { 354 } 355 356 static int 357 pcf_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size, 358 bus_size_t align, struct pcmcia_io_handle *pcihp) 359 { 360 struct pccard_slot *slot = (struct pccard_slot *) pch; 361 362 pcihp->iot = &slot->sc->io_space; 363 pcihp->ioh = pcihp->iot->base; 364 return 0; 365 } 366 367 static void 368 pcf_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pcihp) 369 { 370 } 371 372 static int 373 pcf_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 374 bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp) 375 { 376 struct pccard_slot *slot = (struct pccard_slot *) pch; 377 378 pcihp->iot = &slot->sc->io_space; 379 bus_space_map(pcihp->iot, offset, size, 0, &pcihp->ioh); 380 381 *windowp = 0; /* unused */ 382 return 0; 383 } 384 385 static void 386 pcf_io_unmap(pcmcia_chipset_handle_t pch, int win) 387 { 388 } 389 390 static void * 391 pcf_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf, 392 int ipl, int (*func)(void *), void *arg) 393 { 394 struct pccard_slot *slot = (struct pccard_slot *) pch; 395 int s; 396 397 s = splhigh(); 398 if (slot->intr_func == NULL) { 399 slot->intr_func = func; 400 slot->intr_arg = arg; 401 } else { 402 /* if we are here, we need to put intrs into a list */ 403 printf("ARGH! see " __FILE__ "\n"); 404 slot = NULL; 405 } 406 splx(s); 407 408 return slot; 409 } 410 411 static void 412 pcf_intr_disestablish(pcmcia_chipset_handle_t pch, void *intr_handler) 413 { 414 struct pccard_slot *slot = (struct pccard_slot *) intr_handler; 415 416 if (slot != NULL) { 417 slot->intr_func = NULL; 418 slot->intr_arg = NULL; 419 } 420 } 421 422 static void 423 pcf_socket_enable(pcmcia_chipset_handle_t pch) 424 { 425 } 426 427 static void 428 pcf_socket_disable(pcmcia_chipset_handle_t pch) 429 { 430 } 431 432 static void 433 pcf_socket_settype(pcmcia_chipset_handle_t pch, int type) { 434 } 435 436 static u_int8_t 437 pcmio_bsr1(bus_space_handle_t h, bus_size_t o) 438 { 439 440 return *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)); 441 } 442 443 static void 444 pcmio_bsw1(bus_space_handle_t h, bus_size_t o, unsigned v) 445 { 446 447 *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)) = v; 448 } 449 450 static void 451 pcmio_bsrm1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c) 452 { 453 volatile u_int8_t *src = (volatile u_int8_t *) 454 (h + o + (o & 1 ? 0xffff : 0)); 455 456 457 /* XXX we can (should, must) optimize this if c >= 4 */ 458 for (; c > 0; c--) 459 *p++ = *src; 460 } 461 462 463 static void 464 pcmio_bswm1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c) 465 { 466 volatile u_int8_t *dst = (volatile u_int8_t *) 467 (h + o + (o & 1 ? 0xffff : 0)); 468 469 470 /* XXX we can (should, must) optimize this if c >= 4 */ 471 for (; c > 0; c--) 472 *dst = *p++; 473 } 474 475 static void 476 pcmio_bsrr1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c) 477 { 478 volatile u_int8_t *cp1; 479 volatile u_int8_t *cp2; 480 volatile u_int8_t *temp; 481 482 if (o & 1) { 483 cp1 = (volatile u_int8_t *) h + o + 0x10000; 484 cp2 = (volatile u_int8_t *) h + o; 485 } else { 486 cp1 = (volatile u_int8_t *) h + o; 487 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2; 488 } 489 490 /* XXX we can (should, must) optimize this if c >= 4 */ 491 for (; c > 0; c--) { 492 *p++ = *cp1; 493 cp1 += 2; 494 495 /* swap pointers - hope gcc generates exg for this ;) */ 496 temp = cp1; 497 cp1 = cp2; 498 cp2 = temp; 499 } 500 } 501 502 503 static void 504 pcmio_bswr1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c) 505 { 506 volatile u_int8_t *cp1; 507 volatile u_int8_t *cp2; 508 volatile u_int8_t *temp; 509 510 if (o & 1) { 511 cp1 = (volatile u_int8_t *) h + o + 0x10000; 512 cp2 = (volatile u_int8_t *) h + o; 513 } else { 514 cp1 = (volatile u_int8_t *) h + o; 515 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2; 516 } 517 518 /* XXX we can (should, must) optimize this if c >= 4 */ 519 for (; c > 0; c--) { 520 *cp1 = *p++; 521 cp1 += 2; 522 523 /* swap pointers - hope gcc generates exg for this ;) */ 524 temp = cp1; 525 cp1 = cp2; 526 cp2 = temp; 527 } 528 } 529 530 void 531 pcmio_bssr1(bus_space_handle_t h, bus_size_t o, unsigned v, bus_size_t c) 532 { 533 534 panic("pcmio_bssr1 is not defined (" __FILE__ ")"); 535 } 536 537 void 538 pcmio_bscr1(bus_space_handle_t h, bus_size_t o, bus_space_handle_t g, 539 bus_size_t q, bus_size_t c) 540 { 541 542 panic("pcmio_bscr1 is not defined (" __FILE__ ")"); 543 } 544