1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2002-2005 M. Warner Losh <imp@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * This software may be derived from NetBSD i82365.c and other files with 27 * the following copyright: 28 * 29 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 3. All advertising materials mentioning features or use of this software 40 * must display the following acknowledgement: 41 * This product includes software developed by Marc Horowitz. 42 * 4. The name of the author may not be used to endorse or promote products 43 * derived from this software without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 #include <sys/cdefs.h> 58 __FBSDID("$FreeBSD$"); 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/condvar.h> 63 #include <sys/errno.h> 64 #include <sys/kernel.h> 65 #include <sys/malloc.h> 66 #include <sys/queue.h> 67 #include <sys/module.h> 68 #include <sys/lock.h> 69 #include <sys/mutex.h> 70 #include <sys/conf.h> 71 72 #include <sys/bus.h> 73 #include <machine/bus.h> 74 #include <sys/rman.h> 75 #include <machine/resource.h> 76 77 #include <dev/pccard/pccardreg.h> 78 #include <dev/pccard/pccardvar.h> 79 80 #include <dev/exca/excareg.h> 81 #include <dev/exca/excavar.h> 82 83 #ifdef EXCA_DEBUG 84 #define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args) 85 #define DPRINTF(fmt, args...) printf(fmt, ## args) 86 #else 87 #define DEVPRINTF(dev, fmt, args...) 88 #define DPRINTF(fmt, args...) 89 #endif 90 91 static const char *chip_names[] = 92 { 93 "CardBus socket", 94 "Intel i82365SL-A/B or clone", 95 "Intel i82365sl-DF step", 96 "VLSI chip", 97 "Cirrus Logic PD6710", 98 "Cirrus logic PD6722", 99 "Cirrus Logic PD6729", 100 "Vadem 365", 101 "Vadem 465", 102 "Vadem 468", 103 "Vadem 469", 104 "Ricoh RF5C296", 105 "Ricoh RF5C396", 106 "IBM clone", 107 "IBM KING PCMCIA Controller" 108 }; 109 110 static exca_getb_fn exca_mem_getb; 111 static exca_putb_fn exca_mem_putb; 112 static exca_getb_fn exca_io_getb; 113 static exca_putb_fn exca_io_putb; 114 115 /* memory */ 116 117 #define EXCA_MEMINFO(NUM) { \ 118 EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ 119 EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ 120 EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ 121 EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ 122 EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ 123 EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ 124 EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ 125 EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ 126 } 127 128 static struct mem_map_index_st { 129 int sysmem_start_lsb; 130 int sysmem_start_msb; 131 int sysmem_stop_lsb; 132 int sysmem_stop_msb; 133 int sysmem_win; 134 int cardmem_lsb; 135 int cardmem_msb; 136 int memenable; 137 } mem_map_index[] = { 138 EXCA_MEMINFO(0), 139 EXCA_MEMINFO(1), 140 EXCA_MEMINFO(2), 141 EXCA_MEMINFO(3), 142 EXCA_MEMINFO(4) 143 }; 144 #undef EXCA_MEMINFO 145 146 static uint8_t 147 exca_mem_getb(struct exca_softc *sc, int reg) 148 { 149 return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg)); 150 } 151 152 static void 153 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val) 154 { 155 bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val); 156 } 157 158 static uint8_t 159 exca_io_getb(struct exca_softc *sc, int reg) 160 { 161 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 162 return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA)); 163 } 164 165 static void 166 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val) 167 { 168 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 169 bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val); 170 } 171 172 /* 173 * Helper function. This will map the requested memory slot. We setup the 174 * map before we call this function. This is used to initially force the 175 * mapping, as well as later restore the mapping after it has been destroyed 176 * in some fashion (due to a power event typically). 177 */ 178 static void 179 exca_do_mem_map(struct exca_softc *sc, int win) 180 { 181 struct mem_map_index_st *map; 182 struct pccard_mem_handle *mem; 183 uint32_t offset; 184 uint32_t mem16; 185 uint32_t attrmem; 186 187 map = &mem_map_index[win]; 188 mem = &sc->mem[win]; 189 mem16 = (mem->kind & PCCARD_MEM_16BIT) ? 190 EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT : 0; 191 attrmem = (mem->kind & PCCARD_MEM_ATTR) ? 192 EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0; 193 offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 194 (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 195 exca_putb(sc, map->sysmem_start_lsb, 196 mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT); 197 exca_putb(sc, map->sysmem_start_msb, 198 ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 199 EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | mem16); 200 201 exca_putb(sc, map->sysmem_stop_lsb, 202 (mem->addr + mem->realsize - 1) >> EXCA_SYSMEM_ADDRX_SHIFT); 203 exca_putb(sc, map->sysmem_stop_msb, 204 (((mem->addr + mem->realsize - 1) >> 205 (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 206 EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 207 EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 208 exca_putb(sc, map->sysmem_win, mem->addr >> EXCA_MEMREG_WIN_SHIFT); 209 210 exca_putb(sc, map->cardmem_lsb, offset & 0xff); 211 exca_putb(sc, map->cardmem_msb, ((offset >> 8) & 212 EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | attrmem); 213 214 DPRINTF("%s %d-bit memory", 215 mem->kind & PCCARD_MEM_ATTR ? "attribute" : "common", 216 mem->kind & PCCARD_MEM_16BIT ? 16 : 8); 217 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 218 EXCA_ADDRWIN_ENABLE_MEMCS16); 219 220 DELAY(100); 221 #ifdef EXCA_DEBUG 222 { 223 int r1, r2, r3, r4, r5, r6, r7; 224 r1 = exca_getb(sc, map->sysmem_start_msb); 225 r2 = exca_getb(sc, map->sysmem_start_lsb); 226 r3 = exca_getb(sc, map->sysmem_stop_msb); 227 r4 = exca_getb(sc, map->sysmem_stop_lsb); 228 r5 = exca_getb(sc, map->cardmem_msb); 229 r6 = exca_getb(sc, map->cardmem_lsb); 230 r7 = exca_getb(sc, map->sysmem_win); 231 printf("exca_do_mem_map win %d: %#02x%#02x %#02x%#02x " 232 "%#02x%#02x %#02x (%#08x+%#06x.%#06x*%#06x) flags %#x\n", 233 win, r1, r2, r3, r4, r5, r6, r7, 234 mem->addr, mem->size, mem->realsize, 235 mem->cardaddr, mem->kind); 236 } 237 #endif 238 } 239 240 /* 241 * public interface to map a resource. kind is the type of memory to 242 * map (either common or attribute). Memory created via this interface 243 * starts out at card address 0. Since the only way to set this is 244 * to set it on a struct resource after it has been mapped, we're safe 245 * in maping this assumption. Note that resources can be remapped using 246 * exca_do_mem_map so that's how the card address can be set later. 247 */ 248 int 249 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 250 { 251 int win; 252 253 for (win = 0; win < EXCA_MEM_WINS; win++) { 254 if ((sc->memalloc & (1 << win)) == 0) { 255 sc->memalloc |= (1 << win); 256 break; 257 } 258 } 259 if (win >= EXCA_MEM_WINS) 260 return (ENOSPC); 261 if (sc->flags & EXCA_HAS_MEMREG_WIN) { 262 #ifdef __LP64__ 263 if (rman_get_start(res) >> (EXCA_MEMREG_WIN_SHIFT + 8) != 0) { 264 device_printf(sc->dev, 265 "Does not support mapping above 4GB."); 266 return (EINVAL); 267 } 268 #endif 269 } else { 270 if (rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT != 0) { 271 device_printf(sc->dev, 272 "Does not support mapping above 16M."); 273 return (EINVAL); 274 } 275 } 276 277 sc->mem[win].cardaddr = 0; 278 sc->mem[win].memt = rman_get_bustag(res); 279 sc->mem[win].memh = rman_get_bushandle(res); 280 sc->mem[win].addr = rman_get_start(res); 281 sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 282 sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 283 sc->mem[win].realsize = sc->mem[win].realsize - 284 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 285 sc->mem[win].kind = kind; 286 DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 287 win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 288 exca_do_mem_map(sc, win); 289 290 return (0); 291 } 292 293 /* 294 * Private helper function. This turns off a given memory map that is in 295 * use. We do this by just clearing the enable bit in the pcic. If we needed 296 * to make memory unmapping/mapping pairs faster, we would have to store 297 * more state information about the pcic and then use that to intelligently 298 * to the map/unmap. However, since we don't do that sort of thing often 299 * (generally just at configure time), it isn't a case worth optimizing. 300 */ 301 static void 302 exca_mem_unmap(struct exca_softc *sc, int window) 303 { 304 if (window < 0 || window >= EXCA_MEM_WINS) 305 panic("exca_mem_unmap: window out of range"); 306 307 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 308 sc->memalloc &= ~(1 << window); 309 } 310 311 /* 312 * Find the map that we're using to hold the resource. This works well 313 * so long as the client drivers don't do silly things like map the same 314 * area mutliple times, or map both common and attribute memory at the 315 * same time. This latter restriction is a bug. We likely should just 316 * store a pointer to the res in the mem[x] data structure. 317 */ 318 static int 319 exca_mem_findmap(struct exca_softc *sc, struct resource *res) 320 { 321 int win; 322 323 for (win = 0; win < EXCA_MEM_WINS; win++) { 324 if (sc->mem[win].memt == rman_get_bustag(res) && 325 sc->mem[win].addr == rman_get_start(res) && 326 sc->mem[win].size == rman_get_size(res)) 327 return (win); 328 } 329 return (-1); 330 } 331 332 /* 333 * Set the memory flag. This means that we are setting if the memory 334 * is coming from attribute memory or from common memory on the card. 335 * CIS entries are generally in attribute memory (although they can 336 * reside in common memory). Generally, this is the only use for attribute 337 * memory. However, some cards require their drivers to dance in both 338 * common and/or attribute memory and this interface (and setting the 339 * offset interface) exist for such cards. 340 */ 341 int 342 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 343 { 344 int win; 345 346 win = exca_mem_findmap(sc, res); 347 if (win < 0) { 348 device_printf(sc->dev, 349 "set_res_flags: specified resource not active\n"); 350 return (ENOENT); 351 } 352 353 switch (flags) 354 { 355 case PCCARD_A_MEM_ATTR: 356 sc->mem[win].kind |= PCCARD_MEM_ATTR; 357 break; 358 case PCCARD_A_MEM_COM: 359 sc->mem[win].kind &= ~PCCARD_MEM_ATTR; 360 break; 361 case PCCARD_A_MEM_16BIT: 362 sc->mem[win].kind |= PCCARD_MEM_16BIT; 363 break; 364 case PCCARD_A_MEM_8BIT: 365 sc->mem[win].kind &= ~PCCARD_MEM_16BIT; 366 break; 367 } 368 exca_do_mem_map(sc, win); 369 return (0); 370 } 371 372 /* 373 * Given a resource, go ahead and unmap it if we can find it in the 374 * resrouce list that's used. 375 */ 376 int 377 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 378 { 379 int win; 380 381 win = exca_mem_findmap(sc, res); 382 if (win < 0) 383 return (ENOENT); 384 exca_mem_unmap(sc, win); 385 return (0); 386 } 387 388 /* 389 * Set the offset of the memory. We use this for reading the CIS and 390 * frobbing the pccard's pccard registers (CCR, etc). Some drivers 391 * need to access arbitrary attribute and common memory during their 392 * initialization and operation. 393 */ 394 int 395 exca_mem_set_offset(struct exca_softc *sc, struct resource *res, 396 uint32_t cardaddr, uint32_t *deltap) 397 { 398 int win; 399 uint32_t delta; 400 401 win = exca_mem_findmap(sc, res); 402 if (win < 0) { 403 device_printf(sc->dev, 404 "set_memory_offset: specified resource not active\n"); 405 return (ENOENT); 406 } 407 sc->mem[win].cardaddr = rounddown2(cardaddr, EXCA_MEM_PAGESIZE); 408 delta = cardaddr % EXCA_MEM_PAGESIZE; 409 if (deltap) 410 *deltap = delta; 411 sc->mem[win].realsize = sc->mem[win].size + delta + 412 EXCA_MEM_PAGESIZE - 1; 413 sc->mem[win].realsize = sc->mem[win].realsize - 414 (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 415 exca_do_mem_map(sc, win); 416 return (0); 417 } 418 419 420 /* I/O */ 421 422 #define EXCA_IOINFO(NUM) { \ 423 EXCA_IOADDR ## NUM ## _START_LSB, \ 424 EXCA_IOADDR ## NUM ## _START_MSB, \ 425 EXCA_IOADDR ## NUM ## _STOP_LSB, \ 426 EXCA_IOADDR ## NUM ## _STOP_MSB, \ 427 EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 428 EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 429 | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 430 | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 431 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 432 { \ 433 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 434 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 435 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 436 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 437 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 438 } \ 439 } 440 441 static struct io_map_index_st { 442 int start_lsb; 443 int start_msb; 444 int stop_lsb; 445 int stop_msb; 446 int ioenable; 447 int ioctlmask; 448 int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 449 } io_map_index[] = { 450 EXCA_IOINFO(0), 451 EXCA_IOINFO(1), 452 }; 453 #undef EXCA_IOINFO 454 455 static void 456 exca_do_io_map(struct exca_softc *sc, int win) 457 { 458 struct io_map_index_st *map; 459 460 struct pccard_io_handle *io; 461 462 map = &io_map_index[win]; 463 io = &sc->io[win]; 464 exca_putb(sc, map->start_lsb, io->addr & 0xff); 465 exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 466 467 exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 468 exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 469 470 exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 471 exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 472 473 exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 474 #ifdef EXCA_DEBUG 475 { 476 int r1, r2, r3, r4; 477 r1 = exca_getb(sc, map->start_msb); 478 r2 = exca_getb(sc, map->start_lsb); 479 r3 = exca_getb(sc, map->stop_msb); 480 r4 = exca_getb(sc, map->stop_lsb); 481 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 482 "(%08x+%08x)\n", win, r1, r2, r3, r4, 483 io->addr, io->size); 484 } 485 #endif 486 } 487 488 int 489 exca_io_map(struct exca_softc *sc, int width, struct resource *r) 490 { 491 int win; 492 #ifdef EXCA_DEBUG 493 static char *width_names[] = { "auto", "io8", "io16"}; 494 #endif 495 for (win=0; win < EXCA_IO_WINS; win++) { 496 if ((sc->ioalloc & (1 << win)) == 0) { 497 sc->ioalloc |= (1 << win); 498 break; 499 } 500 } 501 if (win >= EXCA_IO_WINS) 502 return (ENOSPC); 503 504 sc->io[win].iot = rman_get_bustag(r); 505 sc->io[win].ioh = rman_get_bushandle(r); 506 sc->io[win].addr = rman_get_start(r); 507 sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 508 sc->io[win].flags = 0; 509 sc->io[win].width = width; 510 DPRINTF("exca_io_map window %d %s port %x+%x\n", 511 win, width_names[width], sc->io[win].addr, 512 sc->io[win].size); 513 exca_do_io_map(sc, win); 514 515 return (0); 516 } 517 518 static void 519 exca_io_unmap(struct exca_softc *sc, int window) 520 { 521 if (window >= EXCA_IO_WINS) 522 panic("exca_io_unmap: window out of range"); 523 524 exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 525 526 sc->ioalloc &= ~(1 << window); 527 528 sc->io[window].iot = 0; 529 sc->io[window].ioh = 0; 530 sc->io[window].addr = 0; 531 sc->io[window].size = 0; 532 sc->io[window].flags = 0; 533 sc->io[window].width = 0; 534 } 535 536 static int 537 exca_io_findmap(struct exca_softc *sc, struct resource *res) 538 { 539 int win; 540 541 for (win = 0; win < EXCA_IO_WINS; win++) { 542 if (sc->io[win].iot == rman_get_bustag(res) && 543 sc->io[win].addr == rman_get_start(res) && 544 sc->io[win].size == rman_get_size(res)) 545 return (win); 546 } 547 return (-1); 548 } 549 550 551 int 552 exca_io_unmap_res(struct exca_softc *sc, struct resource *res) 553 { 554 int win; 555 556 win = exca_io_findmap(sc, res); 557 if (win < 0) 558 return (ENOENT); 559 exca_io_unmap(sc, win); 560 return (0); 561 } 562 563 /* Misc */ 564 565 /* 566 * If interrupts are enabled, then we should be able to just wait for 567 * an interrupt routine to wake us up. Busy waiting shouldn't be 568 * necessary. Sadly, not all legacy ISA cards support an interrupt 569 * for the busy state transitions, at least according to their datasheets, 570 * so we busy wait a while here.. 571 */ 572 static void 573 exca_wait_ready(struct exca_softc *sc) 574 { 575 int i; 576 DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 577 exca_getb(sc, EXCA_IF_STATUS)); 578 for (i = 0; i < 10000; i++) { 579 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 580 return; 581 DELAY(500); 582 } 583 device_printf(sc->dev, "ready never happened, status = %02x\n", 584 exca_getb(sc, EXCA_IF_STATUS)); 585 } 586 587 /* 588 * Reset the card. Ideally, we'd do a lot of this via interrupts. 589 * However, many PC Cards will deassert the ready signal. This means 590 * that they are asserting an interrupt. This makes it hard to 591 * do anything but a busy wait here. One could argue that these 592 * such cards are broken, or that the bridge that allows this sort 593 * of interrupt through isn't quite what you'd want (and may be a standards 594 * violation). However, such arguing would leave a huge class of PC Cards 595 * and bridges out of reach for use in the system. 596 * 597 * Maybe I should reevaluate the above based on the power bug I fixed 598 * in OLDCARD. 599 */ 600 void 601 exca_reset(struct exca_softc *sc, device_t child) 602 { 603 int win; 604 605 /* enable socket i/o */ 606 exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 607 608 exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 609 /* hold reset for 30ms */ 610 DELAY(30*1000); 611 /* clear the reset flag */ 612 exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 613 /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 614 DELAY(20*1000); 615 616 exca_wait_ready(sc); 617 618 /* disable all address windows */ 619 exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 620 621 exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 622 DEVPRINTF(sc->dev, "card type is io\n"); 623 624 /* reinstall all the memory and io mappings */ 625 for (win = 0; win < EXCA_MEM_WINS; ++win) 626 if (sc->memalloc & (1 << win)) 627 exca_do_mem_map(sc, win); 628 for (win = 0; win < EXCA_IO_WINS; ++win) 629 if (sc->ioalloc & (1 << win)) 630 exca_do_io_map(sc, win); 631 } 632 633 /* 634 * Initialize the exca_softc data structure for the first time. 635 */ 636 void 637 exca_init(struct exca_softc *sc, device_t dev, 638 bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 639 { 640 sc->dev = dev; 641 sc->memalloc = 0; 642 sc->ioalloc = 0; 643 sc->bst = bst; 644 sc->bsh = bsh; 645 sc->offset = offset; 646 sc->flags = 0; 647 sc->getb = exca_mem_getb; 648 sc->putb = exca_mem_putb; 649 sc->pccarddev = device_add_child(dev, "pccard", -1); 650 if (sc->pccarddev == NULL) 651 DEVPRINTF(brdev, "WARNING: cannot add pccard bus.\n"); 652 else if (device_probe_and_attach(sc->pccarddev) != 0) 653 DEVPRINTF(brdev, "WARNING: cannot attach pccard bus.\n"); 654 } 655 656 /* 657 * Is this socket valid? 658 */ 659 static int 660 exca_valid_slot(struct exca_softc *exca) 661 { 662 uint8_t c; 663 664 /* Assume the worst */ 665 exca->chipset = EXCA_BOGUS; 666 667 /* 668 * see if there's a PCMCIA controller here 669 * Intel PCMCIA controllers use 0x82 and 0x83 670 * IBM clone chips use 0x88 and 0x89, apparently 671 */ 672 c = exca_getb(exca, EXCA_IDENT); 673 DEVPRINTF(exca->dev, "Ident is %x\n", c); 674 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 675 return (0); 676 if ((c & EXCA_IDENT_ZERO) != 0) 677 return (0); 678 switch (c & EXCA_IDENT_REV_MASK) { 679 /* 680 * 82365 or clones. 681 */ 682 case EXCA_IDENT_REV_I82365SLR0: 683 case EXCA_IDENT_REV_I82365SLR1: 684 exca->chipset = EXCA_I82365; 685 /* 686 * Check for Vadem chips by unlocking their extra 687 * registers and looking for valid ID. Bit 3 in 688 * the ID register is normally 0, except when 689 * EXCA_VADEMREV is set. Other bridges appear 690 * to ignore this frobbing. 691 */ 692 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 693 EXCA_VADEM_COOKIE1); 694 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 695 EXCA_VADEM_COOKIE2); 696 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 697 c = exca_getb(exca, EXCA_IDENT); 698 if (c & 0x08) { 699 switch (c & 7) { 700 case 1: 701 exca->chipset = EXCA_VG365; 702 break; 703 case 2: 704 exca->chipset = EXCA_VG465; 705 break; 706 case 3: 707 exca->chipset = EXCA_VG468; 708 break; 709 default: 710 exca->chipset = EXCA_VG469; 711 break; 712 } 713 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 714 break; 715 } 716 /* 717 * Check for RICOH RF5C[23]96 PCMCIA Controller 718 */ 719 c = exca_getb(exca, EXCA_RICOH_ID); 720 if (c == EXCA_RID_396) { 721 exca->chipset = EXCA_RF5C396; 722 break; 723 } else if (c == EXCA_RID_296) { 724 exca->chipset = EXCA_RF5C296; 725 break; 726 } 727 /* 728 * Check for Cirrus logic chips. 729 */ 730 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 731 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 732 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 733 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 734 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 735 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 736 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 737 exca->chipset = EXCA_PD6722; 738 else 739 exca->chipset = EXCA_PD6710; 740 break; 741 } 742 } 743 break; 744 745 case EXCA_IDENT_REV_I82365SLDF: 746 /* 747 * Intel i82365sl-DF step or maybe a vlsi 82c146 748 * we detected the vlsi case earlier, so if the controller 749 * isn't set, we know it is a i82365sl step D. 750 * XXXX Except we didn't -- this is a regression but VLSI 751 * controllers are super hard to find these days for testing. 752 */ 753 exca->chipset = EXCA_I82365SL_DF; 754 break; 755 case EXCA_IDENT_REV_IBM1: 756 case EXCA_IDENT_REV_IBM2: 757 exca->chipset = EXCA_IBM; 758 break; 759 case EXCA_IDENT_REV_IBM_KING: 760 exca->chipset = EXCA_IBM_KING; 761 break; 762 default: 763 return (0); 764 } 765 return (1); 766 } 767 768 /* 769 * Probe the expected slots. We maybe should set the ID for each of these 770 * slots too while we're at it. But maybe that belongs to a separate 771 * function. 772 * 773 * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 774 */ 775 int 776 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 777 bus_space_handle_t ioh) 778 { 779 int err; 780 int i; 781 782 err = ENXIO; 783 for (i = 0; i < EXCA_NSLOTS; i++) { 784 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 785 exca->getb = exca_io_getb; 786 exca->putb = exca_io_putb; 787 if (exca_valid_slot(&exca[i])) { 788 device_set_desc(dev, chip_names[exca[i].chipset]); 789 err = 0; 790 } 791 } 792 return (err); 793 } 794 795 void 796 exca_insert(struct exca_softc *exca) 797 { 798 if (device_is_attached(exca->pccarddev)) { 799 if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 800 device_printf(exca->dev, 801 "PC Card card activation failed\n"); 802 } else { 803 device_printf(exca->dev, 804 "PC Card inserted, but no pccard bus.\n"); 805 } 806 } 807 808 809 void 810 exca_removal(struct exca_softc *exca) 811 { 812 if (device_is_attached(exca->pccarddev)) 813 CARD_DETACH_CARD(exca->pccarddev); 814 } 815 816 int 817 exca_activate_resource(struct exca_softc *exca, device_t child, int type, 818 int rid, struct resource *res) 819 { 820 int err; 821 822 if (rman_get_flags(res) & RF_ACTIVE) 823 return (0); 824 err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 825 type, rid, res); 826 if (err) 827 return (err); 828 switch (type) { 829 case SYS_RES_IOPORT: 830 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 831 break; 832 case SYS_RES_MEMORY: 833 err = exca_mem_map(exca, 0, res); 834 break; 835 } 836 if (err) 837 BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 838 type, rid, res); 839 return (err); 840 } 841 842 int 843 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 844 int rid, struct resource *res) 845 { 846 if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 847 switch (type) { 848 case SYS_RES_IOPORT: 849 if (exca_io_unmap_res(exca, res)) 850 return (ENOENT); 851 break; 852 case SYS_RES_MEMORY: 853 if (exca_mem_unmap_res(exca, res)) 854 return (ENOENT); 855 break; 856 } 857 } 858 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 859 type, rid, res)); 860 } 861 862 #if 0 863 static struct resource * 864 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 865 u_long start, u_long end, u_long count, uint flags) 866 { 867 struct resource *res = NULL; 868 int tmp; 869 870 switch (type) { 871 case SYS_RES_MEMORY: 872 if (start < cbb_start_mem) 873 start = cbb_start_mem; 874 if (end < start) 875 end = start; 876 flags = (flags & ~RF_ALIGNMENT_MASK) | 877 rman_make_alignment_flags(CBB_MEMALIGN); 878 break; 879 case SYS_RES_IOPORT: 880 if (start < cbb_start_16_io) 881 start = cbb_start_16_io; 882 if (end < start) 883 end = start; 884 break; 885 case SYS_RES_IRQ: 886 tmp = rman_get_start(sc->irq_res); 887 if (start > tmp || end < tmp || count != 1) { 888 device_printf(child, "requested interrupt %ld-%ld," 889 "count = %ld not supported by cbb\n", 890 start, end, count); 891 return (NULL); 892 } 893 flags |= RF_SHAREABLE; 894 start = end = rman_get_start(sc->irq_res); 895 break; 896 } 897 res = BUS_ALLOC_RESOURCE(up, child, type, rid, 898 start, end, count, flags & ~RF_ACTIVE); 899 if (res == NULL) 900 return (NULL); 901 cbb_insert_res(sc, res, type, *rid); 902 if (flags & RF_ACTIVE) { 903 if (bus_activate_resource(child, type, *rid, res) != 0) { 904 bus_release_resource(child, type, *rid, res); 905 return (NULL); 906 } 907 } 908 909 return (res); 910 } 911 912 static int 913 exca_release_resource(struct exca_softc *sc, device_t child, int type, 914 int rid, struct resource *res) 915 { 916 int error; 917 918 if (rman_get_flags(res) & RF_ACTIVE) { 919 error = bus_deactivate_resource(child, type, rid, res); 920 if (error != 0) 921 return (error); 922 } 923 cbb_remove_res(sc, res); 924 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 925 type, rid, res)); 926 } 927 #endif 928 929 static int 930 exca_modevent(module_t mod, int cmd, void *arg) 931 { 932 return 0; 933 } 934 935 DEV_MODULE(exca, exca_modevent, NULL); 936 MODULE_VERSION(exca, 1); 937