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