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