1 /* $NetBSD: aupcmcia.c,v 1.10 2015/08/30 04:09:21 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Written by Garrett D'Amore for Itronix Inc. 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. The name of Itronix Inc. may not be used to endorse 18 * or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* #include "opt_pci.h" */ 35 /* #include "pci.h" */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: aupcmcia.c,v 1.10 2015/08/30 04:09:21 dholland Exp $"); 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/errno.h> 44 #include <sys/kernel.h> 45 #include <sys/kthread.h> 46 #include <sys/intr.h> 47 #include <sys/device.h> 48 49 #include <dev/pcmcia/pcmciareg.h> 50 #include <dev/pcmcia/pcmciavar.h> 51 #include <dev/pcmcia/pcmciachip.h> 52 53 #include <mips/alchemy/include/au_himem_space.h> 54 #include <mips/alchemy/include/aubusvar.h> 55 #include <mips/alchemy/include/aureg.h> 56 #include <mips/alchemy/include/auvar.h> 57 58 #include <mips/alchemy/dev/aupcmciareg.h> 59 #include <mips/alchemy/dev/aupcmciavar.h> 60 61 /* 62 * Borrow PCMCIADEBUG for now. Generally aupcmcia is the only PCMCIA 63 * host on these machines anyway. 64 */ 65 #ifdef PCMCIADEBUG 66 int aupcm_debug = 1; 67 #define DPRINTF(arg) if (aupcm_debug) printf arg 68 #else 69 #define DPRINTF(arg) 70 #endif 71 72 /* 73 * And for information about mappings, etc. use this one. 74 */ 75 #ifdef AUPCMCIANOISY 76 #define NOISY(arg) printf arg 77 #else 78 #define NOISY(arg) 79 #endif 80 81 /* 82 * Note, we use prefix "aupcm" instead of "aupcmcia", even though our 83 * driver is the latter, mostly because my fingers have trouble typing 84 * the former. "aupcm" should be sufficiently unique to avoid 85 * confusion. 86 */ 87 88 static int aupcm_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 89 struct pcmcia_mem_handle *); 90 static void aupcm_mem_free(pcmcia_chipset_handle_t, 91 struct pcmcia_mem_handle *); 92 static int aupcm_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 93 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 94 static void aupcm_mem_unmap(pcmcia_chipset_handle_t, int); 95 96 static int aupcm_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, 97 bus_size_t, struct pcmcia_io_handle *); 98 static void aupcm_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *); 99 static int aupcm_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 100 bus_size_t, struct pcmcia_io_handle *, int *); 101 static void aupcm_io_unmap(pcmcia_chipset_handle_t, int); 102 static void *aupcm_intr_establish(pcmcia_chipset_handle_t, 103 struct pcmcia_function *, int, int (*)(void *), void *); 104 static void aupcm_intr_disestablish(pcmcia_chipset_handle_t, void *); 105 106 static void aupcm_slot_enable(pcmcia_chipset_handle_t); 107 static void aupcm_slot_disable(pcmcia_chipset_handle_t); 108 static void aupcm_slot_settype(pcmcia_chipset_handle_t, int); 109 110 static int aupcm_match(device_t, struct cfdata *, void *); 111 static void aupcm_attach(device_t, device_t, void *); 112 113 static void aupcm_event_thread(void *); 114 static int aupcm_card_intr(void *); 115 static void aupcm_softintr(void *); 116 static int aupcm_print(void *, const char *); 117 118 struct aupcm_slot { 119 struct aupcm_softc *as_softc; 120 int as_slot; 121 int as_status; 122 int as_enabled; 123 int (*as_intr)(void *); 124 int as_card_irq; 125 int as_status_irq; 126 void *as_intrarg; 127 void *as_softint; 128 void *as_hardint; 129 const char *as_name; 130 bus_addr_t as_offset; 131 struct mips_bus_space as_iot; 132 struct mips_bus_space as_attrt; 133 struct mips_bus_space as_memt; 134 void *as_wins[AUPCMCIA_NWINS]; 135 136 device_t as_pcmcia; 137 }; 138 139 /* this structure needs to be exposed... */ 140 struct aupcm_softc { 141 device_t sc_dev; 142 pcmcia_chipset_tag_t sc_pct; 143 144 void (*sc_slot_enable)(int); 145 void (*sc_slot_disable)(int); 146 int (*sc_slot_status)(int); 147 148 paddr_t sc_base; 149 150 int sc_wake; 151 lwp_t *sc_thread; 152 153 int sc_nslots; 154 struct aupcm_slot sc_slots[AUPCMCIA_NSLOTS]; 155 }; 156 157 static struct pcmcia_chip_functions aupcm_functions = { 158 aupcm_mem_alloc, 159 aupcm_mem_free, 160 aupcm_mem_map, 161 aupcm_mem_unmap, 162 163 aupcm_io_alloc, 164 aupcm_io_free, 165 aupcm_io_map, 166 aupcm_io_unmap, 167 168 aupcm_intr_establish, 169 aupcm_intr_disestablish, 170 171 aupcm_slot_enable, 172 aupcm_slot_disable, 173 aupcm_slot_settype, 174 }; 175 176 static struct mips_bus_space aupcm_memt; 177 178 CFATTACH_DECL_NEW(aupcmcia, sizeof (struct aupcm_softc), 179 aupcm_match, aupcm_attach, NULL, NULL); 180 181 int 182 aupcm_match(device_t parent, struct cfdata *cf, void *aux) 183 { 184 struct aubus_attach_args *aa = aux; 185 static int found = 0; 186 187 if (found) 188 return 0; 189 190 if (strcmp(aa->aa_name, "aupcmcia") != 0) 191 return 0; 192 193 found = 1; 194 195 return 1; 196 } 197 198 void 199 aupcm_attach(device_t parent, device_t self, void *aux) 200 { 201 /* struct aubus_attach_args *aa = aux; */ 202 struct aupcm_softc *sc = device_private(self); 203 static int done = 0; 204 int slot; 205 struct aupcmcia_machdep *md; 206 207 sc->sc_dev = self; 208 209 /* initialize bus space */ 210 if (done) { 211 /* there can be only one. */ 212 return; 213 } 214 215 done = 1; 216 /* 217 * PCMCIA memory can live within pretty much the entire 32-bit 218 * space, modulo 64 MB wraps. We don't have to support coexisting 219 * DMA. 220 */ 221 au_himem_space_init(&aupcm_memt, "pcmciamem", 222 PCMCIA_BASE, AUPCMCIA_ATTR_OFFSET, 0xffffffff, 223 AU_HIMEM_SPACE_LITTLE_ENDIAN); 224 225 if ((md = aupcmcia_machdep()) == NULL) { 226 aprint_error(": unable to get machdep structure\n"); 227 return; 228 } 229 230 sc->sc_nslots = md->am_nslots; 231 sc->sc_slot_enable = md->am_slot_enable; 232 sc->sc_slot_disable = md->am_slot_disable; 233 sc->sc_slot_status = md->am_slot_status; 234 235 aprint_normal(": Alchemy PCMCIA, %d slots\n", sc->sc_nslots); 236 aprint_naive("\n"); 237 238 sc->sc_pct = (pcmcia_chipset_tag_t)&aupcm_functions; 239 240 for (slot = 0; slot < sc->sc_nslots; slot++) { 241 struct aupcm_slot *sp; 242 struct pcmciabus_attach_args paa; 243 244 sp = &sc->sc_slots[slot]; 245 sp->as_softc = sc; 246 247 sp->as_slot = slot; 248 sp->as_name = md->am_slot_name(slot); 249 sp->as_offset = md->am_slot_offset(slot); 250 sp->as_card_irq = md->am_slot_irq(slot, AUPCMCIA_IRQ_CARD); 251 sp->as_status_irq = md->am_slot_irq(slot, 252 AUPCMCIA_IRQ_INSERT); 253 254 au_himem_space_init(&sp->as_attrt, "pcmciaattr", 255 PCMCIA_BASE + sp->as_offset + AUPCMCIA_ATTR_OFFSET, 256 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 257 258 au_himem_space_init(&sp->as_memt, "pcmciamem", 259 PCMCIA_BASE + sp->as_offset + AUPCMCIA_MEM_OFFSET, 260 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 261 262 au_himem_space_init(&sp->as_iot, "pcmciaio", 263 PCMCIA_BASE + sp->as_offset + AUPCMCIA_IO_OFFSET, 264 0, AUPCMCIA_MAP_SIZE, 265 AU_HIMEM_SPACE_LITTLE_ENDIAN | AU_HIMEM_SPACE_IO); 266 267 sp->as_status = 0; 268 269 paa.paa_busname = "pcmcia"; 270 paa.pct = sc->sc_pct; 271 paa.pch = (pcmcia_chipset_handle_t)sp; 272 273 sp->as_pcmcia = config_found(self, &paa, aupcm_print); 274 275 /* if no pcmcia, make sure slot is powered down */ 276 if (sp->as_pcmcia == NULL) { 277 aupcm_slot_disable(sp); 278 continue; 279 } 280 281 /* this makes sure we probe the slot */ 282 sc->sc_wake |= (1 << slot); 283 } 284 285 /* 286 * XXX: this would be an excellent time time to establish a handler 287 * for the card insertion interrupt, but that's edge triggered, and 288 * au_icu.c won't support it right now. We poll in the event thread 289 * for now. Start by initializing it now. 290 */ 291 if (kthread_create(PRI_NONE, 0, NULL, aupcm_event_thread, sc, 292 &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) 293 panic("%s: unable to create event kthread", 294 device_xname(sc->sc_dev)); 295 } 296 297 int 298 aupcm_print(void *aux, const char *pnp) 299 { 300 struct pcmciabus_attach_args *paa = aux; 301 struct aupcm_slot *sp = paa->pch; 302 303 printf(" socket %d irq %d, %s", sp->as_slot, sp->as_card_irq, 304 sp->as_name); 305 306 return (UNCONF); 307 } 308 309 void * 310 aupcm_intr_establish(pcmcia_chipset_handle_t pch, 311 struct pcmcia_function *pf, int level, int (*handler)(void *), void *arg) 312 { 313 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 314 int s; 315 316 /* 317 * Hmm. perhaps this intr should be a list. well, PCMCIA 318 * devices generally only have one interrupt, and so should 319 * generally have only one handler. So we leave it for now. 320 * (Other PCMCIA bus drivers do it this way.) 321 */ 322 sp->as_intr = handler; 323 sp->as_intrarg = arg; 324 sp->as_softint = softint_establish(IPL_SOFTNET, aupcm_softintr, sp); 325 326 /* set up hard interrupt handler for the card IRQs */ 327 s = splhigh(); 328 sp->as_hardint = au_intr_establish(sp->as_card_irq, 0, 329 IPL_TTY, IST_LEVEL_LOW, aupcm_card_intr, sp); 330 /* if card is not powered up, then leave the IRQ masked */ 331 if (!sp->as_enabled) { 332 au_intr_disable(sp->as_card_irq); 333 } 334 splx(s); 335 336 return (sp->as_softint); 337 } 338 339 void 340 aupcm_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 341 { 342 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 343 344 KASSERT(sp->as_softint == ih); 345 /* KASSERT(sp->as_hardint); */ 346 /* set up hard interrupt handler for the card IRQs */ 347 348 au_intr_disestablish(sp->as_hardint); 349 sp->as_hardint = 0; 350 351 softint_disestablish(ih); 352 sp->as_softint = 0; 353 sp->as_intr = NULL; 354 sp->as_intrarg = NULL; 355 } 356 357 /* 358 * FYI: Hot detach of PCMCIA is supposedly safe because H/W doesn't 359 * fault on accesses to missing hardware. 360 */ 361 void 362 aupcm_event_thread(void *arg) 363 { 364 struct aupcm_softc *sc = arg; 365 struct aupcm_slot *sp; 366 int s, i, attach, detach; 367 368 for (;;) { 369 s = splhigh(); 370 if (sc->sc_wake == 0) { 371 splx(s); 372 /* 373 * XXX: Currently, the au_icu.c lacks support 374 * for edge-triggered interrupts. So we 375 * cannot really use the status change 376 * inerrupts. For now we poll (once per sec). 377 * FYI, Linux does it this way, and they *do* 378 * have support for edge triggered interrupts. 379 * Go figure. 380 */ 381 tsleep(&sc->sc_wake, PWAIT, "aupcm_event", hz); 382 s = splhigh(); 383 } 384 sc->sc_wake = 0; 385 386 attach = detach = 0; 387 for (i = 0; i < sc->sc_nslots; i++) { 388 sp = &sc->sc_slots[i]; 389 390 if (sc->sc_slot_status(sp->as_slot) != 0) { 391 if (!sp->as_status) { 392 DPRINTF(("%s: card %d insertion\n", 393 device_xname(sc->sc_dev), i)); 394 attach |= (1 << i); 395 sp->as_status = 1; 396 } 397 } else { 398 if (sp->as_status) { 399 DPRINTF(("%s: card %d removal\n", 400 device_xname(sc->sc_dev), i)); 401 detach |= (1 << i); 402 sp->as_status = 0; 403 } 404 } 405 } 406 splx(s); 407 408 for (i = 0; i < sc->sc_nslots; i++) { 409 sp = &sc->sc_slots[i]; 410 411 if (detach & (1 << i)) { 412 aupcm_slot_disable(sp); 413 pcmcia_card_detach(sp->as_pcmcia, DETACH_FORCE); 414 } else if (attach & (1 << i)) { 415 /* 416 * until the function is enabled, don't 417 * honor interrupts 418 */ 419 sp->as_enabled = 0; 420 au_intr_disable(sp->as_card_irq); 421 pcmcia_card_attach(sp->as_pcmcia); 422 } 423 } 424 } 425 } 426 427 #if 0 428 void 429 aupcm_status_intr(void *arg) 430 { 431 int s; 432 struct aupcm_softc *sc = arg; 433 434 s = splhigh(); 435 436 /* kick the status thread so it does its bit */ 437 sc->sc_wake = 1; 438 wakeup(&sc->sc_wake); 439 440 splx(s); 441 } 442 #endif 443 444 int 445 aupcm_card_intr(void *arg) 446 { 447 struct aupcm_slot *sp = arg; 448 449 /* disable the hard interrupt for now */ 450 au_intr_disable(sp->as_card_irq); 451 452 if (sp->as_intr != NULL) { 453 softint_schedule(sp->as_softint); 454 } 455 456 return 1; 457 } 458 459 void 460 aupcm_softintr(void *arg) 461 { 462 struct aupcm_slot *sp = arg; 463 int s; 464 465 sp->as_intr(sp->as_intrarg); 466 467 s = splhigh(); 468 469 if (sp->as_intr && sp->as_enabled) { 470 au_intr_enable(sp->as_card_irq); 471 } 472 473 splx(s); 474 } 475 476 void 477 aupcm_slot_enable(pcmcia_chipset_handle_t pch) 478 { 479 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 480 int s; 481 482 /* no interrupts while we reset the card, please */ 483 if (sp->as_intr) 484 au_intr_disable(sp->as_card_irq); 485 486 /* 487 * XXX: should probably lock to make sure slot_disable and 488 * enable not called together. However, i believe that the 489 * event thread basically serializes them anyway. 490 */ 491 492 sp->as_softc->sc_slot_enable(sp->as_slot); 493 /* card is powered up now, honor device interrupts */ 494 495 s = splhigh(); 496 sp->as_enabled = 1; 497 if (sp->as_intr) 498 au_intr_enable(sp->as_card_irq); 499 splx(s); 500 } 501 502 void 503 aupcm_slot_disable(pcmcia_chipset_handle_t pch) 504 { 505 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 506 int s; 507 508 s = splhigh(); 509 au_intr_disable(sp->as_card_irq); 510 sp->as_enabled = 0; 511 splx(s); 512 513 sp->as_softc->sc_slot_disable(sp->as_slot); 514 } 515 516 void 517 aupcm_slot_settype(pcmcia_chipset_handle_t pch, int type) 518 { 519 /* we do nothing now : type == PCMCIA_IFTYPE_IO */ 520 } 521 522 int 523 aupcm_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 524 struct pcmcia_mem_handle *pcmh) 525 { 526 pcmh->memt = NULL; 527 pcmh->size = pcmh->realsize = size; 528 pcmh->addr = 0; 529 pcmh->mhandle = 0; 530 531 return 0; 532 } 533 534 void 535 aupcm_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmh) 536 { 537 /* nothing to do */ 538 } 539 540 int 541 aupcm_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr, 542 bus_size_t size, struct pcmcia_mem_handle *pcmh, bus_size_t *offsetp, 543 int *windowp) 544 { 545 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 546 int win, err; 547 int s; 548 549 s = splhigh(); 550 for (win = 0; win < AUPCMCIA_NWINS; win++) { 551 if (sp->as_wins[win] == NULL) { 552 sp->as_wins[win] = pcmh; 553 break; 554 } 555 } 556 splx(s); 557 558 if (win >= AUPCMCIA_NWINS) { 559 return ENOMEM; 560 } 561 562 if (kind & PCMCIA_MEM_ATTR) { 563 pcmh->memt = &sp->as_attrt; 564 NOISY(("mapping ATTR addr %x size %x\n", (uint32_t)addr, 565 (uint32_t)size)); 566 } else { 567 pcmh->memt = &sp->as_memt; 568 NOISY(("mapping MEMORY addr %x size %x\n", (uint32_t)addr, 569 (uint32_t)size)); 570 } 571 572 if ((size + addr) > (64 * 1024 * 1024)) 573 return EINVAL; 574 575 pcmh->size = size; 576 577 err = bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh); 578 if (err != 0) { 579 sp->as_wins[win] = NULL; 580 return err; 581 } 582 *offsetp = 0; 583 *windowp = win; 584 585 return 0; 586 } 587 588 void 589 aupcm_mem_unmap(pcmcia_chipset_handle_t pch, int win) 590 { 591 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 592 struct pcmcia_mem_handle *pcmh; 593 594 pcmh = (struct pcmcia_mem_handle *)sp->as_wins[win]; 595 sp->as_wins[win] = NULL; 596 597 NOISY(("memory umap virtual %x\n", (uint32_t)pcmh->memh)); 598 bus_space_unmap(pcmh->memt, pcmh->memh, pcmh->size); 599 pcmh->memt = NULL; 600 } 601 602 int 603 aupcm_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 604 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih) 605 { 606 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 607 bus_space_handle_t bush; 608 int err; 609 610 pih->iot = &sp->as_iot; 611 pih->size = size; 612 pih->flags = 0; 613 614 /* 615 * start from the initial offset - this gets us a slot 616 * specific address, while still leaving the addresses more or 617 * less zero-based which is required for x86-style device 618 * drivers. 619 */ 620 err = bus_space_alloc(pih->iot, start, 0x100000, 621 size, align, 0, 0, &pih->addr, &bush); 622 NOISY(("start = %x, addr = %x, size = %x, bush = %x\n", 623 (uint32_t)start, (uint32_t)pih->addr, (uint32_t)size, 624 (uint32_t)bush)); 625 626 /* and we convert it back */ 627 if (err == 0) { 628 pih->ihandle = (void *)bush; 629 } 630 631 return (err); 632 } 633 634 void 635 aupcm_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih) 636 { 637 bus_space_free(pih->iot, (bus_space_handle_t)pih->ihandle, 638 pih->size); 639 } 640 641 int 642 aupcm_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 643 bus_size_t size, struct pcmcia_io_handle *pih, int *windowp) 644 { 645 int err; 646 647 err = bus_space_subregion(pih->iot, (bus_space_handle_t)pih->ihandle, 648 offset, size, &pih->ioh); 649 NOISY(("io map offset = %x, size = %x, ih = %x, hdl=%x\n", 650 (uint32_t)offset, (uint32_t)size, 651 (uint32_t)pih->ihandle, (uint32_t)pih->ioh)); 652 653 return err; 654 } 655 656 void 657 aupcm_io_unmap(pcmcia_chipset_handle_t pch, int win) 658 { 659 /* We mustn't unmap/free subregion bus space! */ 660 NOISY(("io unmap\n")); 661 } 662