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