1 /* $NetBSD: plumpcmcia.c,v 1.14 2002/10/02 05:26:46 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000 UCHIYAMA Yasushi. All rights reserved. 5 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Marc Horowitz. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/kthread.h> 37 38 #include <machine/bus.h> 39 #include <machine/config_hook.h> 40 #include <machine/bus_space_hpcmips.h> 41 42 #include <dev/pcmcia/pcmciareg.h> 43 #include <dev/pcmcia/pcmciavar.h> 44 #include <dev/pcmcia/pcmciachip.h> 45 46 #include <hpcmips/tx/tx39var.h> 47 #include <hpcmips/dev/plumvar.h> 48 #include <hpcmips/dev/plumicuvar.h> 49 #include <hpcmips/dev/plumpowervar.h> 50 #include <hpcmips/dev/plumpcmciareg.h> 51 52 #ifdef PLUMPCMCIA_DEBUG 53 #define DPRINTF_ENABLE 54 #define DPRINTF_DEBUG plumpcmcia_debug 55 #endif 56 #include <machine/debug.h> 57 58 int plumpcmcia_match(struct device *, struct cfdata *, void *); 59 void plumpcmcia_attach(struct device *, struct device *, void *); 60 int plumpcmcia_print(void *, const char *); 61 int plumpcmcia_submatch(struct device *, struct cfdata *, void *); 62 63 int plumpcmcia_power(void *, int, long, void *); 64 65 struct plumpcmcia_softc; 66 67 struct plumpcmcia_handle { 68 /* parent */ 69 struct device *ph_parent; 70 /* child */ 71 struct device *ph_pcmcia; 72 73 /* PCMCIA controller register space */ 74 bus_space_tag_t ph_regt; 75 bus_space_handle_t ph_regh; 76 77 /* I/O port space */ 78 int ph_ioarea; /* not PCMCIA window */ 79 struct { 80 bus_addr_t pi_addr; 81 bus_size_t pi_size; 82 int pi_width; 83 } ph_io[PLUM_PCMCIA_IO_WINS]; 84 int ph_ioalloc; 85 bus_space_tag_t ph_iot; 86 bus_space_handle_t ph_ioh; 87 bus_addr_t ph_iobase; 88 bus_size_t ph_iosize; 89 90 /* I/O Memory space */ 91 int ph_memarea; /* not PCMCIA window */ 92 struct { 93 bus_addr_t pm_addr; 94 bus_size_t pm_size; 95 int32_t pm_offset; 96 int pm_kind; 97 } ph_mem[PLUM_PCMCIA_MEM_WINS]; 98 int ph_memalloc; 99 bus_space_tag_t ph_memt; 100 bus_space_handle_t ph_memh; 101 bus_addr_t ph_membase; 102 bus_size_t ph_memsize; 103 104 /* Card interrupt handler */ 105 int ph_plum_irq; 106 void *ph_card_ih; 107 }; 108 109 enum plumpcmcia_event_type { 110 PLUM_PCMCIA_EVENT_INSERT, 111 PLUM_PCMCIA_EVENT_REMOVE, 112 }; 113 114 struct plumpcmcia_event { 115 int __queued; 116 enum plumpcmcia_event_type pe_type; 117 struct plumpcmcia_handle *pe_ph; 118 SIMPLEQ_ENTRY(plumpcmcia_event) pe_link; 119 }; 120 121 struct plumpcmcia_softc { 122 struct device sc_dev; 123 plum_chipset_tag_t sc_pc; 124 125 /* Register space */ 126 bus_space_tag_t sc_regt; 127 bus_space_handle_t sc_regh; 128 129 /* power management hook */ 130 void *sc_powerhook; 131 132 /* CSC event */ 133 struct proc *sc_event_thread; 134 SIMPLEQ_HEAD (, plumpcmcia_event) sc_event_head; 135 136 /* for each slot */ 137 struct plumpcmcia_handle sc_ph[PLUMPCMCIA_NSLOTS]; 138 }; 139 140 static void plumpcmcia_attach_socket(struct plumpcmcia_handle *); 141 static int plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 142 struct pcmcia_mem_handle *); 143 static void plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t, 144 struct pcmcia_mem_handle *); 145 static int plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 146 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 147 static void plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int); 148 static int plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, 149 bus_size_t, bus_size_t, struct pcmcia_io_handle *); 150 static void plumpcmcia_chip_io_free(pcmcia_chipset_handle_t, 151 struct pcmcia_io_handle *); 152 static int plumpcmcia_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 153 bus_size_t, struct pcmcia_io_handle *, int *); 154 static void plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int); 155 static void plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t); 156 static void plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t); 157 static void *plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t, 158 struct pcmcia_function *, int, int (*)(void *), void *); 159 static void plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, void *); 160 static void plumpcmcia_wait_ready( struct plumpcmcia_handle *); 161 static void plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle *, int); 162 static void plumpcmcia_chip_do_io_map(struct plumpcmcia_handle *, int); 163 164 static struct pcmcia_chip_functions plumpcmcia_functions = { 165 plumpcmcia_chip_mem_alloc, 166 plumpcmcia_chip_mem_free, 167 plumpcmcia_chip_mem_map, 168 plumpcmcia_chip_mem_unmap, 169 plumpcmcia_chip_io_alloc, 170 plumpcmcia_chip_io_free, 171 plumpcmcia_chip_io_map, 172 plumpcmcia_chip_io_unmap, 173 plumpcmcia_chip_intr_establish, 174 plumpcmcia_chip_intr_disestablish, 175 plumpcmcia_chip_socket_enable, 176 plumpcmcia_chip_socket_disable 177 }; 178 179 /* CSC */ 180 #define PLUM_PCMCIA_EVENT_QUEUE_MAX 5 181 static struct plumpcmcia_event __event_queue_pool[PLUM_PCMCIA_EVENT_QUEUE_MAX]; 182 static struct plumpcmcia_event *plumpcmcia_event_alloc(void); 183 static void plumpcmcia_event_free(struct plumpcmcia_event *); 184 static void plum_csc_intr_setup(struct plumpcmcia_softc *, 185 struct plumpcmcia_handle *, int); 186 static int plum_csc_intr(void *); 187 static void plumpcmcia_create_event_thread(void *); 188 static void plumpcmcia_event_thread(void *); 189 190 #ifdef PLUMPCMCIA_DEBUG 191 /* debug */ 192 #define __DEBUG_FUNC __attribute__((__unused__)) 193 static void __ioareadump(plumreg_t) __DEBUG_FUNC; 194 static void __memareadump(plumreg_t) __DEBUG_FUNC; 195 static void plumpcmcia_dump(struct plumpcmcia_softc *) __DEBUG_FUNC; 196 #endif /* PLUMPCMCIA_DEBUG */ 197 198 CFATTACH_DECL(plumpcmcia, sizeof(struct plumpcmcia_softc), 199 plumpcmcia_match, plumpcmcia_attach, NULL, NULL); 200 201 int 202 plumpcmcia_match(struct device *parent, struct cfdata *cf, void *aux) 203 { 204 return (1); 205 } 206 207 void 208 plumpcmcia_attach(struct device *parent, struct device *self, void *aux) 209 { 210 struct plum_attach_args *pa = aux; 211 struct plumpcmcia_softc *sc = (void*)self; 212 struct plumpcmcia_handle *ph; 213 214 sc->sc_pc = pa->pa_pc; 215 sc->sc_regt = pa->pa_regt; 216 217 /* map register area */ 218 if (bus_space_map(sc->sc_regt, PLUM_PCMCIA_REGBASE, 219 PLUM_PCMCIA_REGSIZE, 0, &sc->sc_regh)) { 220 printf(": register map failed\n"); 221 } 222 223 /* power control */ 224 plumpcmcia_power(sc, 0, 0, (void *)PWR_RESUME); 225 /* Add a hard power hook to power saving */ 226 #if notyet 227 sc->sc_powerhook = config_hook(CONFIG_HOOK_PMEVENT, 228 CONFIG_HOOK_PMEVENT_HARDPOWER, 229 CONFIG_HOOK_SHARE, 230 plumpcmcia_power, sc); 231 if (sc->sc_powerhook == 0) 232 printf(": WARNING unable to establish hard power hook"); 233 #endif 234 printf("\n"); 235 236 /* Slot0/1 CSC event queue */ 237 SIMPLEQ_INIT (&sc->sc_event_head); 238 kthread_create(plumpcmcia_create_event_thread, sc); 239 240 /* Slot 0 */ 241 ph = &sc->sc_ph[0]; 242 ph->ph_plum_irq = PLUM_INT_C1IO; 243 ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1; 244 ph->ph_membase = PLUM_PCMCIA_MEMBASE1; 245 ph->ph_memsize = PLUM_PCMCIA_MEMSIZE1; 246 ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA1; 247 ph->ph_iobase = PLUM_PCMCIA_IOBASE1; 248 ph->ph_iosize = PLUM_PCMCIA_IOSIZE1; 249 ph->ph_regt = sc->sc_regt; 250 bus_space_subregion(sc->sc_regt, sc->sc_regh, 251 PLUM_PCMCIA_REGSPACE_SLOT0, 252 PLUM_PCMCIA_REGSPACE_SIZE, 253 &ph->ph_regh); 254 ph->ph_iot = pa->pa_iot; 255 ph->ph_memt = pa->pa_iot; 256 ph->ph_parent = (void*)sc; 257 258 plum_csc_intr_setup(sc, ph, PLUM_INT_C1SC); 259 plum_power_establish(sc->sc_pc, PLUM_PWR_PCC1); 260 plumpcmcia_attach_socket(ph); 261 262 /* Slot 1 */ 263 ph = &sc->sc_ph[1]; 264 ph->ph_plum_irq = PLUM_INT_C2IO; 265 ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2; 266 ph->ph_membase = PLUM_PCMCIA_MEMBASE2; 267 ph->ph_memsize = PLUM_PCMCIA_MEMSIZE2; 268 ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA2; 269 ph->ph_iobase = PLUM_PCMCIA_IOBASE2; 270 ph->ph_iosize = PLUM_PCMCIA_IOSIZE2; 271 ph->ph_regt = sc->sc_regt; 272 bus_space_subregion(sc->sc_regt, sc->sc_regh, 273 PLUM_PCMCIA_REGSPACE_SLOT1, 274 PLUM_PCMCIA_REGSPACE_SIZE, 275 &ph->ph_regh); 276 ph->ph_iot = pa->pa_iot; 277 ph->ph_memt = pa->pa_iot; 278 ph->ph_parent = (void*)sc; 279 280 plum_csc_intr_setup(sc, ph, PLUM_INT_C2SC); 281 plum_power_establish(sc->sc_pc, PLUM_PWR_PCC2); 282 plumpcmcia_attach_socket(ph); 283 } 284 285 int 286 plumpcmcia_print(void *arg, const char *pnp) 287 { 288 if (pnp) { 289 printf("pcmcia at %s", pnp); 290 } 291 292 return (UNCONF); 293 } 294 295 int 296 plumpcmcia_submatch(struct device *parent, struct cfdata *cf, void *aux) 297 { 298 return (config_match(parent, cf, aux)); 299 } 300 301 static void 302 plumpcmcia_attach_socket(struct plumpcmcia_handle *ph) 303 { 304 struct pcmciabus_attach_args paa; 305 struct plumpcmcia_softc *sc = (void*)ph->ph_parent; 306 307 paa.paa_busname = "pcmcia"; 308 paa.pct = (pcmcia_chipset_tag_t)&plumpcmcia_functions; 309 paa.pch = (pcmcia_chipset_handle_t)ph; 310 paa.iobase = 0; 311 paa.iosize = ph->ph_iosize; 312 313 if ((ph->ph_pcmcia = config_found_sm((void*)sc, &paa, 314 plumpcmcia_print, 315 plumpcmcia_submatch))) { 316 /* Enable slot */ 317 plum_conf_write(ph->ph_regt, ph->ph_regh, 318 PLUM_PCMCIA_SLOTCTRL, 319 PLUM_PCMCIA_SLOTCTRL_ENABLE); 320 /* Support 3.3V card & enable Voltage Sense Status */ 321 plum_conf_write(ph->ph_regt, ph->ph_regh, 322 PLUM_PCMCIA_FUNCCTRL, 323 PLUM_PCMCIA_FUNCCTRL_VSSEN | 324 PLUM_PCMCIA_FUNCCTRL_3VSUPPORT); 325 pcmcia_card_attach(ph->ph_pcmcia); 326 } 327 } 328 329 static void * 330 plumpcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch, 331 struct pcmcia_function *pf, int ipl, 332 int (*ih_fun)(void *), void *ih_arg) 333 { 334 struct plumpcmcia_handle *ph = (void*)pch; 335 struct plumpcmcia_softc *sc = (void*)ph->ph_parent; 336 337 if (!(ph->ph_card_ih = 338 plum_intr_establish(sc->sc_pc, ph->ph_plum_irq, 339 IST_EDGE, IPL_BIO, ih_fun, ih_arg))) { 340 printf("plumpcmcia_chip_intr_establish: can't establish\n"); 341 return (0); 342 } 343 344 return (ph->ph_card_ih); 345 } 346 347 static void 348 plumpcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 349 { 350 struct plumpcmcia_handle *ph = (void*)pch; 351 struct plumpcmcia_softc *sc = (void*)ph->ph_parent; 352 353 plum_intr_disestablish(sc->sc_pc, ih); 354 } 355 356 static int 357 plumpcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 358 struct pcmcia_mem_handle *pcmhp) 359 { 360 struct plumpcmcia_handle *ph = (void*)pch; 361 bus_size_t realsize; 362 363 /* convert size to PCIC pages */ 364 realsize = ((size + (PLUM_PCMCIA_MEM_PAGESIZE - 1)) / 365 PLUM_PCMCIA_MEM_PAGESIZE) * PLUM_PCMCIA_MEM_PAGESIZE; 366 367 if (bus_space_alloc(ph->ph_memt, ph->ph_membase, 368 ph->ph_membase + ph->ph_memsize, 369 realsize, PLUM_PCMCIA_MEM_PAGESIZE, 370 0, 0, 0, &pcmhp->memh)) { 371 return (1); 372 } 373 374 pcmhp->memt = ph->ph_memt; 375 /* Address offset from MEM area base */ 376 pcmhp->addr = pcmhp->memh - ph->ph_membase - 377 ((struct bus_space_tag_hpcmips*)ph->ph_memt)->base; 378 pcmhp->size = size; 379 pcmhp->realsize = realsize; 380 381 DPRINTF(("plumpcmcia_chip_mem_alloc: size %#x->%#x addr %#x->%#x\n", 382 (unsigned)size, (unsigned)realsize, (unsigned)pcmhp->addr, 383 (unsigned)pcmhp->memh)); 384 385 return (0); 386 } 387 388 static void 389 plumpcmcia_chip_mem_free(pcmcia_chipset_handle_t pch, 390 struct pcmcia_mem_handle *pcmhp) 391 { 392 393 bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->size); 394 } 395 396 static int 397 plumpcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, 398 bus_addr_t card_addr, bus_size_t size, 399 struct pcmcia_mem_handle *pcmhp, 400 bus_size_t *offsetp, int *windowp) 401 { 402 struct plumpcmcia_handle *ph = (void*)pch; 403 bus_addr_t busaddr; 404 int32_t card_offset; 405 int i, win; 406 407 for (win = -1, i = 0; i < PLUM_PCMCIA_MEM_WINS; i++) { 408 if ((ph->ph_memalloc & (1 << i)) == 0) { 409 win = i; 410 ph->ph_memalloc |= (1 << i); 411 break; 412 } 413 } 414 if (win == -1) { 415 DPRINTF(("plumpcmcia_chip_mem_map: no window\n")); 416 return (1); 417 } 418 419 busaddr = pcmhp->addr; 420 421 *offsetp = card_addr % PLUM_PCMCIA_MEM_PAGESIZE; 422 card_addr -= *offsetp; 423 size += *offsetp - 1; 424 *windowp = win; 425 card_offset = (((int32_t)card_addr) - ((int32_t)busaddr)); 426 427 DPRINTF(("plumpcmcia_chip_mem_map window %d bus %#x(kv:%#x)+%#x" 428 " size %#x at card addr %#x offset %#x\n", win, 429 (unsigned)busaddr, (unsigned)pcmhp->memh, (unsigned)*offsetp, 430 (unsigned)size, (unsigned)card_addr, (unsigned)card_offset)); 431 432 ph->ph_mem[win].pm_addr = busaddr; 433 ph->ph_mem[win].pm_size = size; 434 ph->ph_mem[win].pm_offset = card_offset; 435 ph->ph_mem[win].pm_kind = kind; 436 ph->ph_memalloc |= (1 << win); 437 438 plumpcmcia_chip_do_mem_map(ph, win); 439 440 return (0); 441 } 442 443 static void 444 plumpcmcia_chip_do_mem_map(struct plumpcmcia_handle *ph, int win) 445 { 446 bus_space_tag_t regt = ph->ph_regt; 447 bus_space_handle_t regh = ph->ph_regh; 448 plumreg_t reg, addr, offset, size; 449 450 if (win < 0 || win > 4) { 451 panic("plumpcmcia_chip_do_mem_map: bogus window %d", win); 452 } 453 454 addr = (ph->ph_mem[win].pm_addr) >> PLUM_PCMCIA_MEM_SHIFT; 455 size = (ph->ph_mem[win].pm_size) >> PLUM_PCMCIA_MEM_SHIFT; 456 offset = (ph->ph_mem[win].pm_offset) >> PLUM_PCMCIA_MEM_SHIFT; 457 458 /* Attribute memory or not */ 459 reg = ph->ph_mem[win].pm_kind == PCMCIA_MEM_ATTR ? 460 PLUM_PCMCIA_MEMWINCTRL_REGACTIVE : 0; 461 462 /* Notify I/O area to select for PCMCIA controller */ 463 reg = PLUM_PCMCIA_MEMWINCTRL_MAP_SET(reg, ph->ph_memarea); 464 465 /* Zero wait & 16bit access */ 466 reg |= (PLUM_PCMCIA_MEMWINCTRL_ZERO_WS | 467 PLUM_PCMCIA_MEMWINCTRL_DATASIZE16); 468 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINCTRL(win), reg); 469 470 /* Map Host <-> PC-Card address */ 471 472 /* host-side */ 473 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTARTADDR(win), 474 addr); 475 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTOPADDR(win), 476 addr + size); 477 478 /* card-side */ 479 plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINOFSADDR(win), offset); 480 481 /* Enable memory window */ 482 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN); 483 reg |= PLUM_PCMCIA_WINEN_MEM(win); 484 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg); 485 486 DPRINTF(("plumpcmcia_chip_do_mem_map: window:%d %#x(%#x)+%#x\n", 487 win, offset, addr, size)); 488 489 delay(100); 490 } 491 492 static void 493 plumpcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window) 494 { 495 struct plumpcmcia_handle *ph = (void*)pch; 496 bus_space_tag_t regt = ph->ph_regt; 497 bus_space_handle_t regh = ph->ph_regh; 498 plumreg_t reg; 499 500 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN); 501 reg &= ~PLUM_PCMCIA_WINEN_MEM(window); 502 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg); 503 504 ph->ph_memalloc &= ~(1 << window); 505 } 506 507 static int 508 plumpcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 509 bus_size_t size, bus_size_t align, 510 struct pcmcia_io_handle *pcihp) 511 { 512 struct plumpcmcia_handle *ph = (void*)pch; 513 514 DPRINTF(("plumpcmcia_chip_io_alloc: start=%#x size=%#x ", 515 (unsigned)start, (unsigned)size)); 516 if (start) { 517 if (bus_space_map(ph->ph_iot, ph->ph_iobase + start, 518 size, 0, &pcihp->ioh)) { 519 DPRINTF(("bus_space_map failed\n")); 520 return (1); 521 } 522 pcihp->flags = 0; 523 pcihp->addr = start; 524 DPRINTF(("(mapped) %#x+%#x\n", (unsigned)start, 525 (unsigned)size)); 526 } else { 527 if (bus_space_alloc(ph->ph_iot, ph->ph_iobase, 528 ph->ph_iobase + ph->ph_iosize, size, 529 align, 0, 0, 0, &pcihp->ioh)) { 530 DPRINTF(("bus_space_alloc failed\n")); 531 return 1; 532 } 533 /* Address offset from IO area base */ 534 pcihp->addr = pcihp->ioh - ph->ph_iobase - 535 ((struct bus_space_tag_hpcmips*)ph->ph_iot)->base; 536 pcihp->flags = PCMCIA_IO_ALLOCATED; 537 DPRINTF(("(allocated) %#x+%#x\n", (unsigned)pcihp->addr, 538 (unsigned)size)); 539 } 540 541 pcihp->iot = ph->ph_iot; 542 pcihp->size = size; 543 544 return (0); 545 } 546 547 static int 548 plumpcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width, 549 bus_addr_t offset, bus_size_t size, 550 struct pcmcia_io_handle *pcihp, int *windowp) 551 { 552 #ifdef PLUMPCMCIA_DEBUG 553 static char *width_names[] = { "auto", "io8", "io16" }; 554 #endif /* PLUMPCMCIA_DEBUG */ 555 struct plumpcmcia_handle *ph = (void*)pch; 556 bus_addr_t winofs; 557 int i, win; 558 559 winofs = pcihp->addr + offset; 560 561 if (winofs > 0x3ff) { 562 printf("plumpcmcia_chip_io_map: WARNING port %#lx > 0x3ff\n", 563 winofs); 564 } 565 566 for (win = -1, i = 0; i < PLUM_PCMCIA_IO_WINS; i++) { 567 if ((ph->ph_ioalloc & (1 << i)) == 0) { 568 win = i; 569 ph->ph_ioalloc |= (1 << i); 570 break; 571 } 572 } 573 if (win == -1) { 574 DPRINTF(("plumpcmcia_chip_io_map: no window\n")); 575 return (1); 576 } 577 *windowp = win; 578 579 ph->ph_io[win].pi_addr = winofs; 580 ph->ph_io[win].pi_size = size; 581 ph->ph_io[win].pi_width = width; 582 583 plumpcmcia_chip_do_io_map(ph, win); 584 585 DPRINTF(("plumpcmcia_chip_io_map: %#x(kv:%#x)+%#x %s\n", 586 (unsigned)offset, (unsigned)pcihp->ioh, (unsigned)size, 587 width_names[width])); 588 589 return (0); 590 } 591 592 static void 593 plumpcmcia_chip_do_io_map(struct plumpcmcia_handle *ph, int win) 594 { 595 bus_space_tag_t regt = ph->ph_regt; 596 bus_space_handle_t regh = ph->ph_regh; 597 plumreg_t reg; 598 bus_addr_t addr; 599 bus_size_t size; 600 int shift; 601 plumreg_t ioctlbits[3] = { 602 PLUM_PCMCIA_IOWINCTRL_IOCS16SRC, 603 0, 604 PLUM_PCMCIA_IOWINCTRL_DATASIZE16 605 }; 606 607 if (win < 0 || win > 1) { 608 panic("plumpcmcia_chip_do_io_map: bogus window %d", win); 609 } 610 611 addr = ph->ph_io[win].pi_addr; 612 size = ph->ph_io[win].pi_size; 613 614 /* Notify I/O area to select for PCMCIA controller */ 615 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINADDRCTRL(win), 616 ph->ph_ioarea); 617 618 /* Start/Stop addr */ 619 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTARTADDR(win), addr); 620 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTOPADDR(win), 621 addr + size - 1); 622 623 /* Set bus width */ 624 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_IOWINCTRL); 625 shift = win == 0 ? PLUM_PCMCIA_IOWINCTRL_WIN0SHIFT : 626 PLUM_PCMCIA_IOWINCTRL_WIN1SHIFT; 627 628 reg &= ~(PLUM_PCMCIA_IOWINCTRL_WINMASK << shift); 629 reg |= ((ioctlbits[ph->ph_io[win].pi_width] | 630 PLUM_PCMCIA_IOWINCTRL_ZEROWAIT) << shift); 631 plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINCTRL, reg); 632 633 /* Enable window */ 634 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN); 635 reg |= (win == 0 ? PLUM_PCMCIA_WINEN_IO0 : 636 PLUM_PCMCIA_WINEN_IO1); 637 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg); 638 639 delay(100); 640 } 641 642 static void 643 plumpcmcia_chip_io_free(pcmcia_chipset_handle_t pch, 644 struct pcmcia_io_handle *pcihp) 645 { 646 if (pcihp->flags & PCMCIA_IO_ALLOCATED) { 647 bus_space_free(pcihp->iot, pcihp->ioh, pcihp->size); 648 } else { 649 bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size); 650 } 651 652 DPRINTF(("plumpcmcia_chip_io_free %#x+%#x\n", pcihp->ioh, 653 (unsigned)pcihp->size)); 654 } 655 656 static void 657 plumpcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window) 658 { 659 struct plumpcmcia_handle *ph = (void*)pch; 660 bus_space_tag_t regt = ph->ph_regt; 661 bus_space_handle_t regh = ph->ph_regh; 662 plumreg_t reg; 663 664 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN); 665 switch (window) { 666 default: 667 panic("plumpcmcia_chip_io_unmap: bogus window"); 668 case 0: 669 reg &= ~PLUM_PCMCIA_WINEN_IO0; 670 break; 671 case 1: 672 reg &= ~PLUM_PCMCIA_WINEN_IO1; 673 break; 674 } 675 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg); 676 ph->ph_ioalloc &= ~(1 << window); 677 } 678 679 static void 680 plumpcmcia_wait_ready(struct plumpcmcia_handle *ph) 681 { 682 bus_space_tag_t regt = ph->ph_regt; 683 bus_space_handle_t regh = ph->ph_regh; 684 int i; 685 686 for (i = 0; i < 10000; i++) { 687 if ((plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) & 688 PLUM_PCMCIA_STATUS_READY) && 689 (plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) & 690 PLUM_PCMCIA_STATUS_PWROK)) { 691 return; 692 } 693 delay(500); 694 695 if ((i > 5000) && (i % 100 == 99)) { 696 printf("."); 697 } 698 } 699 printf("plumpcmcia_wait_ready: failed\n"); 700 } 701 702 static void 703 plumpcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch) 704 { 705 struct plumpcmcia_handle *ph = (void*)pch; 706 bus_space_tag_t regt = ph->ph_regt; 707 bus_space_handle_t regh = ph->ph_regh; 708 plumreg_t reg, power; 709 int win, cardtype; 710 711 /* this bit is mostly stolen from pcic_attach_card */ 712 713 /* power down the socket to reset it, clear the card reset pin */ 714 715 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0); 716 717 /* 718 * wait 300ms until power fails (Tpf). Then, wait 100ms since 719 * we are changing Vcc (Toff). 720 */ 721 delay((300 + 100) * 1000); 722 723 /* 724 * power up the socket 725 */ 726 /* detect voltage */ 727 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL2); 728 if ((reg & PLUM_PCMCIA_GENCTRL2_VCC5V) == 729 PLUM_PCMCIA_GENCTRL2_VCC5V) { 730 power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT1; /* 5V */ 731 } else { 732 power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT0; /* 3.3V */ 733 } 734 735 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 736 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV | 737 power | 738 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE); 739 740 /* 741 * wait 100ms until power raise (Tpr) and 20ms to become 742 * stable (Tsu(Vcc)). 743 * 744 * some machines require some more time to be settled 745 * (300ms is added here). 746 */ 747 delay((100 + 20 + 300) * 1000); 748 749 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 750 PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV | 751 power | 752 PLUM_PCMCIA_PWRCTRL_OE | 753 PLUM_PCMCIA_PWRCTRL_PWR_ENABLE); 754 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, 0); 755 756 /* 757 * hold RESET at least 10us. 758 */ 759 delay(10); 760 761 /* clear the reset flag */ 762 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, 763 PLUM_PCMCIA_GENCTRL_RESET); 764 765 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 766 767 delay(20000); 768 769 /* wait for the chip to finish initializing */ 770 plumpcmcia_wait_ready(ph); 771 772 /* zero out the address windows */ 773 774 plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, 0); 775 776 /* set the card type */ 777 778 cardtype = pcmcia_card_gettype(ph->ph_pcmcia); 779 780 reg = (cardtype == PCMCIA_IFTYPE_IO) ? 781 PLUM_PCMCIA_GENCTRL_CARDTYPE_IO : 782 PLUM_PCMCIA_GENCTRL_CARDTYPE_MEM; 783 reg |= plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL); 784 DPRINTF(("%s: plumpcmcia_chip_socket_enable cardtype %s\n", 785 ph->ph_parent->dv_xname, 786 ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"))); 787 788 plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, reg); 789 790 /* reinstall all the memory and io mappings */ 791 792 for (win = 0; win < PLUM_PCMCIA_MEM_WINS; win++) { 793 if (ph->ph_memalloc & (1 << win)) { 794 plumpcmcia_chip_do_mem_map(ph, win); 795 } 796 } 797 798 for (win = 0; win < PLUM_PCMCIA_IO_WINS; win++) { 799 if (ph->ph_ioalloc & (1 << win)) { 800 plumpcmcia_chip_do_io_map(ph, win); 801 } 802 } 803 804 } 805 806 static void 807 plumpcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch) 808 { 809 struct plumpcmcia_handle *ph = (void*)pch; 810 bus_space_tag_t regt = ph->ph_regt; 811 bus_space_handle_t regh = ph->ph_regh; 812 813 /* power down the socket */ 814 plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0); 815 816 /* 817 * wait 300ms until power fails (Tpf). 818 */ 819 delay(300 * 1000); 820 } 821 822 static void 823 plum_csc_intr_setup(struct plumpcmcia_softc *sc, struct plumpcmcia_handle *ph, 824 int irq) 825 { 826 bus_space_tag_t regt = ph->ph_regt; 827 bus_space_handle_t regh = ph->ph_regh; 828 plumreg_t reg; 829 void *ih; 830 831 /* enable CARD DETECT ENABLE only */ 832 plum_conf_write(regt, regh, PLUM_PCMCIA_CSCINT, 833 PLUM_PCMCIA_CSCINT_CARD_DETECT); 834 835 /* don't use explicit writeback csc interrupt status */ 836 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_GLOBALCTRL); 837 reg &= ~PLUM_PCMCIA_GLOBALCTRL_EXPLICIT_WB_CSC_INT; 838 plum_conf_write(regt, regh, PLUM_PCMCIA_GLOBALCTRL, reg); 839 840 /* install interrupt handler (don't fail) */ 841 ih = plum_intr_establish(sc->sc_pc, irq, IST_EDGE, IPL_TTY, 842 plum_csc_intr, ph); 843 KASSERT(ih != 0); 844 } 845 846 static int 847 plum_csc_intr(void *arg) 848 { 849 struct plumpcmcia_handle *ph = arg; 850 struct plumpcmcia_softc *sc = (void *)ph->ph_parent; 851 struct plumpcmcia_event *pe; 852 bus_space_tag_t regt = ph->ph_regt; 853 bus_space_handle_t regh = ph->ph_regh; 854 plumreg_t reg; 855 int flag; 856 857 /* read and clear interrupt status */ 858 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_CSCINT_STAT); 859 if (reg & PLUM_PCMCIA_CSCINT_CARD_DETECT) { 860 DPRINTF(("%s: card status change.\n", __FUNCTION__)); 861 } else { 862 DPRINTF(("%s: unhandled csc event. 0x%02x\n", 863 __FUNCTION__, reg)); 864 return (0); 865 } 866 867 /* inquire card status (insert or remove) */ 868 reg = plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS); 869 reg &= (PLUM_PCMCIA_STATUS_CD1 | PLUM_PCMCIA_STATUS_CD2); 870 if (reg == (PLUM_PCMCIA_STATUS_CD1 | PLUM_PCMCIA_STATUS_CD2)) { 871 /* insert */ 872 flag = PLUM_PCMCIA_EVENT_INSERT; 873 } else { 874 /* remove */ 875 flag = PLUM_PCMCIA_EVENT_REMOVE; 876 } 877 878 /* queue event to event thread and wakeup. */ 879 pe = plumpcmcia_event_alloc(); 880 if (pe == 0) { 881 printf("%s: event FIFO overflow (%d).\n", __FUNCTION__, 882 PLUM_PCMCIA_EVENT_QUEUE_MAX); 883 return (0); 884 } 885 pe->pe_type = flag; 886 pe->pe_ph = ph; 887 SIMPLEQ_INSERT_TAIL(&sc->sc_event_head, pe, pe_link); 888 wakeup(sc); 889 890 return (0); 891 } 892 893 static struct plumpcmcia_event * 894 plumpcmcia_event_alloc() 895 { 896 int i; 897 /* I assume called from interrupt context only. so don't lock */ 898 for (i = 0; i < PLUM_PCMCIA_EVENT_QUEUE_MAX; i++) { 899 if (!__event_queue_pool[i].__queued) { 900 __event_queue_pool[i].__queued = 1; 901 return (&__event_queue_pool[i]); 902 } 903 } 904 905 return (0); 906 } 907 908 static void 909 plumpcmcia_event_free(struct plumpcmcia_event *pe) 910 { 911 /* I assume context is already locked */ 912 pe->__queued = 0; 913 } 914 915 static void 916 plumpcmcia_create_event_thread(void *arg) 917 { 918 struct plumpcmcia_softc *sc = arg; 919 int error; 920 921 error = kthread_create1(plumpcmcia_event_thread, sc, 922 &sc->sc_event_thread, "%s", 923 sc->sc_dev.dv_xname); 924 KASSERT(error == 0); 925 } 926 927 static void 928 plumpcmcia_event_thread(void *arg) 929 { 930 struct plumpcmcia_softc *sc = arg; 931 struct plumpcmcia_event *pe; 932 int s; 933 934 while (/*CONSTCOND*/1) { /* XXX shutdown. -uch */ 935 tsleep(sc, PWAIT, "CSC wait", 0); 936 s = spltty(); 937 while ((pe = SIMPLEQ_FIRST(&sc->sc_event_head))) { 938 splx(s); 939 switch (pe->pe_type) { 940 default: 941 printf("%s: unknown event.\n", __FUNCTION__); 942 break; 943 case PLUM_PCMCIA_EVENT_INSERT: 944 DPRINTF(("%s: insert event.\n", __FUNCTION__)); 945 pcmcia_card_attach(pe->pe_ph->ph_pcmcia); 946 break; 947 case PLUM_PCMCIA_EVENT_REMOVE: 948 DPRINTF(("%s: remove event.\n", __FUNCTION__)); 949 pcmcia_card_detach(pe->pe_ph->ph_pcmcia, 950 DETACH_FORCE); 951 break; 952 } 953 s = spltty(); 954 SIMPLEQ_REMOVE_HEAD(&sc->sc_event_head, pe_link); 955 plumpcmcia_event_free(pe); 956 } 957 splx(s); 958 } 959 /* NOTREACHED */ 960 } 961 962 /* power XXX notyet */ 963 int 964 plumpcmcia_power(void *ctx, int type, long id, void *msg) 965 { 966 struct plumpcmcia_softc *sc = ctx; 967 bus_space_tag_t regt = sc->sc_regt; 968 bus_space_handle_t regh = sc->sc_regh; 969 int why = (int)msg; 970 971 switch (why) { 972 case PWR_RESUME: 973 DPRINTF(("%s: ON\n", sc->sc_dev.dv_xname)); 974 /* power on */ 975 plum_conf_write(regt, regh, PLUM_PCMCIA_CARDPWRCTRL, 976 PLUM_PCMCIA_CARDPWRCTRL_ON); 977 break; 978 case PWR_SUSPEND: 979 /* FALLTHROUGH */ 980 case PWR_STANDBY: 981 plum_conf_write(regt, regh, PLUM_PCMCIA_CARDPWRCTRL, 982 PLUM_PCMCIA_CARDPWRCTRL_OFF); 983 DPRINTF(("%s: OFF\n", sc->sc_dev.dv_xname)); 984 break; 985 } 986 987 return (0); 988 } 989 990 #ifdef PLUMPCMCIA_DEBUG 991 static void 992 __ioareadump(plumreg_t reg) 993 { 994 995 if (reg & PLUM_PCMCIA_IOWINADDRCTRL_AREA2) { 996 printf("I/O Area 2\n"); 997 } else { 998 printf("I/O Area 1\n"); 999 } 1000 } 1001 1002 static void 1003 __memareadump(plumreg_t reg) 1004 { 1005 int maparea; 1006 1007 maparea = PLUM_PCMCIA_MEMWINCTRL_MAP(reg); 1008 switch (maparea) { 1009 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1: 1010 printf("MEM Area1\n"); 1011 break; 1012 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2: 1013 printf("MEM Area2\n"); 1014 break; 1015 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA3: 1016 printf("MEM Area3\n"); 1017 break; 1018 case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA4: 1019 printf("MEM Area4\n"); 1020 break; 1021 } 1022 } 1023 1024 static void 1025 plumpcmcia_dump(struct plumpcmcia_softc *sc) 1026 { 1027 bus_space_tag_t regt = sc->sc_regt; 1028 bus_space_handle_t regh = sc->sc_regh; 1029 plumreg_t reg; 1030 1031 int i, j; 1032 1033 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN0CTRL)); 1034 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN1CTRL)); 1035 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN2CTRL)); 1036 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN3CTRL)); 1037 __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN4CTRL)); 1038 1039 __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN0ADDRCTRL)); 1040 __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN1ADDRCTRL)); 1041 1042 for (j = 0; j < 2; j++) { 1043 printf("[slot %d]\n", j); 1044 for (i = 0; i < 0x120; i += 4) { 1045 reg = plum_conf_read(sc->sc_regt, sc->sc_regh, 1046 i + 0x800 * j); 1047 printf("%03x %08x", i, reg); 1048 dbg_bit_print(reg); 1049 } 1050 } 1051 printf("\n"); 1052 } 1053 #endif /* PLUMPCMCIA_DEBUG */ 1054