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