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