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