1 /* $NetBSD: gayle_pcmcia.c,v 1.30 2014/09/07 22:24:40 phx Exp $ */ 2 3 /* public domain */ 4 5 #include <sys/cdefs.h> 6 __KERNEL_RCSID(0, "$NetBSD: gayle_pcmcia.c,v 1.30 2014/09/07 22:24:40 phx 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_1; 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 if (sc->devs[0].card == NULL) { 178 printf("attach failed, config_found() returned NULL\n"); 179 pmap_remove(kernel_map->pmap, pcmcia_base, 180 pcmcia_base + (GAYLE_PCMCIA_END - GAYLE_PCMCIA_START)); 181 pmap_update(kernel_map->pmap); 182 uvm_deallocate(kernel_map, pcmcia_base, 183 GAYLE_PCMCIA_END - GAYLE_PCMCIA_START); 184 return; 185 } 186 187 sc->intr6.isr_intr = pccard_intr6; 188 sc->intr6.isr_arg = sc; 189 sc->intr6.isr_ipl = 6; 190 add_isr(&sc->intr6); 191 192 sc->intr2.isr_intr = pccard_intr2; 193 sc->intr2.isr_arg = sc; 194 sc->intr2.isr_ipl = 2; 195 add_isr(&sc->intr2); 196 197 if (kthread_create(PRI_NONE, 0, NULL, pccard_kthread, sc, 198 NULL, "pccard")) { 199 printf("%s: can't create kernel thread\n", 200 device_xname(self)); 201 panic("pccard kthread_create() failed"); 202 } 203 204 gayle_intr_enable_set(GAYLE_INT_DETECT | GAYLE_INT_IREQ); 205 206 /* reset the card if it's already there */ 207 if (gayle_pcmcia_status_read() & GAYLE_CCMEM_DETECT) { 208 volatile u_int8_t x; 209 210 gayle_intr_ack(0xff); 211 delay(500); 212 gayle_intr_ack(0xfc); 213 214 *reset_card_reg = 0x0; 215 delay(1000); 216 x = *reset_card_reg; 217 __USE(x); 218 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 219 } 220 221 pccard_attach_slot(&sc->devs[0]); 222 } 223 224 static int 225 pccard_intr6(void *arg) 226 { 227 struct pccard_softc *sc = arg; 228 229 if (gayle_intr_status() & GAYLE_INT_DETECT) { 230 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_STSCHG | 231 GAYLE_INT_SPKR | GAYLE_INT_WP | GAYLE_INT_IREQ); 232 sc->devs[0].flags |= SLOT_NEW_CARD_EVENT; 233 return 1; 234 } 235 return 0; 236 } 237 238 static int 239 pccard_intr2(void *arg) 240 { 241 struct pccard_softc *sc = arg; 242 struct pccard_slot *slot = &sc->devs[0]; 243 244 if (slot->flags & SLOT_NEW_CARD_EVENT) { 245 slot->flags &= ~SLOT_NEW_CARD_EVENT; 246 247 /* reset the registers */ 248 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_DETECT); 249 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 250 gayle_pcmcia_config_write(0); 251 pccard_attach_slot(&sc->devs[0]); 252 } else { 253 int intreq = gayle_intr_status() & 254 (GAYLE_INT_STSCHG | GAYLE_INT_WP | GAYLE_INT_IREQ); 255 if (intreq) { 256 gayle_intr_ack((intreq ^ 0x2c) | 0xc0); 257 258 return slot->flags & SLOT_OCCUPIED && 259 slot->intr_func != NULL && 260 slot->intr_func(slot->intr_arg); 261 } 262 } 263 return 0; 264 } 265 266 static void 267 pccard_kthread(void *arg) 268 { 269 struct pccard_softc *sc = arg; 270 struct pccard_slot *slot = &sc->devs[0]; 271 272 for (;;) { 273 int s = spl2(); 274 275 if (slot->flags & SLOT_NEW_CARD_EVENT) { 276 slot->flags &= ~SLOT_NEW_CARD_EVENT; 277 gayle_intr_ack(0xc0); 278 279 /* reset the registers */ 280 gayle_intr_ack(GAYLE_INT_IDE | GAYLE_INT_DETECT); 281 gayle_pcmcia_status_write(GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR); 282 gayle_pcmcia_config_write(0); 283 pccard_attach_slot(&sc->devs[0]); 284 } 285 splx(s); 286 287 tsleep(slot, PWAIT, "pccthread", hz); 288 } 289 } 290 291 static void 292 pccard_attach_slot(struct pccard_slot *slot) 293 { 294 295 if (!(slot->flags & SLOT_OCCUPIED) && 296 gayle_pcmcia_status_read() & GAYLE_CCMEM_DETECT) { 297 if (pcmcia_card_attach(slot->card) == 0) 298 slot->flags |= SLOT_OCCUPIED; 299 } 300 } 301 302 static int 303 pcf_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t bsz, 304 struct pcmcia_mem_handle *pcmh) 305 { 306 struct pccard_slot *slot = (struct pccard_slot *) pch; 307 308 pcmh->memt = &slot->sc->attr_space; 309 pcmh->memh = pcmh->memt->base; 310 return 0; 311 } 312 313 static void 314 pcf_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *memh) 315 { 316 } 317 318 static int 319 pcf_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr, 320 bus_size_t size, struct pcmcia_mem_handle *pcmh, 321 bus_addr_t *offsetp, int *windowp) 322 { 323 struct pccard_slot *slot = (struct pccard_slot *) pch; 324 325 /* Ignore width requirements */ 326 kind &= ~PCMCIA_WIDTH_MEM_MASK; 327 328 switch (kind) { 329 case PCMCIA_MEM_ATTR: 330 pcmh->memt = &slot->sc->attr_space; 331 break; 332 case PCMCIA_MEM_COMMON: 333 pcmh->memt = &slot->sc->mem_space; 334 break; 335 default: 336 /* This means that this code needs an update/a bugfix */ 337 printf(__FILE__ ": unknown kind %d of PCMCIA memory\n", kind); 338 return 1; 339 } 340 341 bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh); 342 *offsetp = 0; 343 *windowp = 0; /* unused */ 344 345 return 0; 346 } 347 348 static void 349 pcf_mem_unmap(pcmcia_chipset_handle_t pch, int win) 350 { 351 } 352 353 static int 354 pcf_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size, 355 bus_size_t align, struct pcmcia_io_handle *pcihp) 356 { 357 struct pccard_slot *slot = (struct pccard_slot *) pch; 358 359 pcihp->iot = &slot->sc->io_space; 360 pcihp->ioh = pcihp->iot->base; 361 return 0; 362 } 363 364 static void 365 pcf_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pcihp) 366 { 367 } 368 369 static int 370 pcf_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 371 bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp) 372 { 373 struct pccard_slot *slot = (struct pccard_slot *) pch; 374 375 pcihp->iot = &slot->sc->io_space; 376 bus_space_map(pcihp->iot, offset, size, 0, &pcihp->ioh); 377 378 *windowp = 0; /* unused */ 379 return 0; 380 } 381 382 static void 383 pcf_io_unmap(pcmcia_chipset_handle_t pch, int win) 384 { 385 } 386 387 static void * 388 pcf_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf, 389 int ipl, int (*func)(void *), void *arg) 390 { 391 struct pccard_slot *slot = (struct pccard_slot *) pch; 392 int s; 393 394 s = splhigh(); 395 if (slot->intr_func == NULL) { 396 slot->intr_func = func; 397 slot->intr_arg = arg; 398 } else { 399 /* if we are here, we need to put intrs into a list */ 400 printf("ARGH! see " __FILE__ "\n"); 401 slot = NULL; 402 } 403 splx(s); 404 405 return slot; 406 } 407 408 static void 409 pcf_intr_disestablish(pcmcia_chipset_handle_t pch, void *intr_handler) 410 { 411 struct pccard_slot *slot = (struct pccard_slot *) intr_handler; 412 413 if (slot != NULL) { 414 slot->intr_func = NULL; 415 slot->intr_arg = NULL; 416 } 417 } 418 419 static void 420 pcf_socket_enable(pcmcia_chipset_handle_t pch) 421 { 422 } 423 424 static void 425 pcf_socket_disable(pcmcia_chipset_handle_t pch) 426 { 427 } 428 429 static void 430 pcf_socket_settype(pcmcia_chipset_handle_t pch, int type) { 431 } 432 433 static u_int8_t 434 pcmio_bsr1(bus_space_handle_t h, bus_size_t o) 435 { 436 437 return *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)); 438 } 439 440 static void 441 pcmio_bsw1(bus_space_handle_t h, bus_size_t o, unsigned v) 442 { 443 444 *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)) = v; 445 } 446 447 static void 448 pcmio_bsrm1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c) 449 { 450 volatile u_int8_t *src = (volatile u_int8_t *) 451 (h + o + (o & 1 ? 0xffff : 0)); 452 453 454 /* XXX we can (should, must) optimize this if c >= 4 */ 455 for (; c > 0; c--) 456 *p++ = *src; 457 } 458 459 460 static void 461 pcmio_bswm1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c) 462 { 463 volatile u_int8_t *dst = (volatile u_int8_t *) 464 (h + o + (o & 1 ? 0xffff : 0)); 465 466 467 /* XXX we can (should, must) optimize this if c >= 4 */ 468 for (; c > 0; c--) 469 *dst = *p++; 470 } 471 472 static void 473 pcmio_bsrr1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c) 474 { 475 volatile u_int8_t *cp1; 476 volatile u_int8_t *cp2; 477 volatile u_int8_t *temp; 478 479 if (o & 1) { 480 cp1 = (volatile u_int8_t *) h + o + 0x10000; 481 cp2 = (volatile u_int8_t *) h + o; 482 } else { 483 cp1 = (volatile u_int8_t *) h + o; 484 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2; 485 } 486 487 /* XXX we can (should, must) optimize this if c >= 4 */ 488 for (; c > 0; c--) { 489 *p++ = *cp1; 490 cp1 += 2; 491 492 /* swap pointers - hope gcc generates exg for this ;) */ 493 temp = cp1; 494 cp1 = cp2; 495 cp2 = temp; 496 } 497 } 498 499 500 static void 501 pcmio_bswr1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c) 502 { 503 volatile u_int8_t *cp1; 504 volatile u_int8_t *cp2; 505 volatile u_int8_t *temp; 506 507 if (o & 1) { 508 cp1 = (volatile u_int8_t *) h + o + 0x10000; 509 cp2 = (volatile u_int8_t *) h + o; 510 } else { 511 cp1 = (volatile u_int8_t *) h + o; 512 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2; 513 } 514 515 /* XXX we can (should, must) optimize this if c >= 4 */ 516 for (; c > 0; c--) { 517 *cp1 = *p++; 518 cp1 += 2; 519 520 /* swap pointers - hope gcc generates exg for this ;) */ 521 temp = cp1; 522 cp1 = cp2; 523 cp2 = temp; 524 } 525 } 526 527 void 528 pcmio_bssr1(bus_space_handle_t h, bus_size_t o, unsigned v, bus_size_t c) 529 { 530 531 panic("pcmio_bssr1 is not defined (" __FILE__ ")"); 532 } 533 534 void 535 pcmio_bscr1(bus_space_handle_t h, bus_size_t o, bus_space_handle_t g, 536 bus_size_t q, bus_size_t c) 537 { 538 539 panic("pcmio_bscr1 is not defined (" __FILE__ ")"); 540 } 541