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 } 650 651 /* 652 * Is this socket valid? 653 */ 654 static int 655 exca_valid_slot(struct exca_softc *exca) 656 { 657 uint8_t c; 658 659 /* Assume the worst */ 660 exca->chipset = EXCA_BOGUS; 661 662 /* 663 * see if there's a PCMCIA controller here 664 * Intel PCMCIA controllers use 0x82 and 0x83 665 * IBM clone chips use 0x88 and 0x89, apparently 666 */ 667 c = exca_getb(exca, EXCA_IDENT); 668 DEVPRINTF(exca->dev, "Ident is %x\n", c); 669 if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 670 return (0); 671 if ((c & EXCA_IDENT_ZERO) != 0) 672 return (0); 673 switch (c & EXCA_IDENT_REV_MASK) { 674 /* 675 * 82365 or clones. 676 */ 677 case EXCA_IDENT_REV_I82365SLR0: 678 case EXCA_IDENT_REV_I82365SLR1: 679 exca->chipset = EXCA_I82365; 680 /* 681 * Check for Vadem chips by unlocking their extra 682 * registers and looking for valid ID. Bit 3 in 683 * the ID register is normally 0, except when 684 * EXCA_VADEMREV is set. Other bridges appear 685 * to ignore this frobbing. 686 */ 687 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 688 EXCA_VADEM_COOKIE1); 689 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 690 EXCA_VADEM_COOKIE2); 691 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 692 c = exca_getb(exca, EXCA_IDENT); 693 if (c & 0x08) { 694 switch (c & 7) { 695 case 1: 696 exca->chipset = EXCA_VG365; 697 break; 698 case 2: 699 exca->chipset = EXCA_VG465; 700 break; 701 case 3: 702 exca->chipset = EXCA_VG468; 703 break; 704 default: 705 exca->chipset = EXCA_VG469; 706 break; 707 } 708 exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 709 break; 710 } 711 /* 712 * Check for RICOH RF5C[23]96 PCMCIA Controller 713 */ 714 c = exca_getb(exca, EXCA_RICOH_ID); 715 if (c == EXCA_RID_396) { 716 exca->chipset = EXCA_RF5C396; 717 break; 718 } else if (c == EXCA_RID_296) { 719 exca->chipset = EXCA_RF5C296; 720 break; 721 } 722 /* 723 * Check for Cirrus logic chips. 724 */ 725 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 726 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 727 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 728 EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 729 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 730 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 731 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 732 exca->chipset = EXCA_PD6722; 733 else 734 exca->chipset = EXCA_PD6710; 735 break; 736 } 737 } 738 break; 739 740 case EXCA_IDENT_REV_I82365SLDF: 741 /* 742 * Intel i82365sl-DF step or maybe a vlsi 82c146 743 * we detected the vlsi case earlier, so if the controller 744 * isn't set, we know it is a i82365sl step D. 745 */ 746 exca->chipset = EXCA_I82365SL_DF; 747 break; 748 case EXCA_IDENT_REV_IBM1: 749 case EXCA_IDENT_REV_IBM2: 750 exca->chipset = EXCA_IBM; 751 break; 752 case EXCA_IDENT_REV_IBM_KING: 753 exca->chipset = EXCA_IBM_KING; 754 break; 755 default: 756 return (0); 757 } 758 return (1); 759 } 760 761 /* 762 * Probe the expected slots. We maybe should set the ID for each of these 763 * slots too while we're at it. But maybe that belongs to a separate 764 * function. 765 * 766 * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 767 */ 768 int 769 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 770 bus_space_handle_t ioh) 771 { 772 int err; 773 int i; 774 775 err = ENXIO; 776 for (i = 0; i < EXCA_NSLOTS; i++) { 777 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 778 exca->getb = exca_io_getb; 779 exca->putb = exca_io_putb; 780 if (exca_valid_slot(&exca[i])) { 781 device_set_desc(dev, chip_names[exca[i].chipset]); 782 err = 0; 783 } 784 } 785 return (err); 786 } 787 788 void 789 exca_insert(struct exca_softc *exca) 790 { 791 if (device_is_attached(exca->pccarddev)) { 792 if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 793 device_printf(exca->dev, 794 "PC Card card activation failed\n"); 795 } else { 796 device_printf(exca->dev, 797 "PC Card inserted, but no pccard bus.\n"); 798 } 799 } 800 801 802 void 803 exca_removal(struct exca_softc *exca) 804 { 805 if (device_is_attached(exca->pccarddev)) 806 CARD_DETACH_CARD(exca->pccarddev); 807 } 808 809 int 810 exca_activate_resource(struct exca_softc *exca, device_t child, int type, 811 int rid, struct resource *res) 812 { 813 int err; 814 815 if (rman_get_flags(res) & RF_ACTIVE) 816 return (0); 817 err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 818 type, rid, res); 819 if (err) 820 return (err); 821 switch (type) { 822 case SYS_RES_IOPORT: 823 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 824 break; 825 case SYS_RES_MEMORY: 826 err = exca_mem_map(exca, 0, res); 827 break; 828 } 829 if (err) 830 BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 831 type, rid, res); 832 return (err); 833 } 834 835 int 836 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 837 int rid, struct resource *res) 838 { 839 if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 840 switch (type) { 841 case SYS_RES_IOPORT: 842 if (exca_io_unmap_res(exca, res)) 843 return (ENOENT); 844 break; 845 case SYS_RES_MEMORY: 846 if (exca_mem_unmap_res(exca, res)) 847 return (ENOENT); 848 break; 849 } 850 } 851 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 852 type, rid, res)); 853 } 854 855 #if 0 856 static struct resource * 857 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 858 u_long start, u_long end, u_long count, uint flags) 859 { 860 struct resource *res = NULL; 861 int tmp; 862 863 switch (type) { 864 case SYS_RES_MEMORY: 865 if (start < cbb_start_mem) 866 start = cbb_start_mem; 867 if (end < start) 868 end = start; 869 flags = (flags & ~RF_ALIGNMENT_MASK) | 870 rman_make_alignment_flags(CBB_MEMALIGN); 871 break; 872 case SYS_RES_IOPORT: 873 if (start < cbb_start_16_io) 874 start = cbb_start_16_io; 875 if (end < start) 876 end = start; 877 break; 878 case SYS_RES_IRQ: 879 tmp = rman_get_start(sc->irq_res); 880 if (start > tmp || end < tmp || count != 1) { 881 device_printf(child, "requested interrupt %ld-%ld," 882 "count = %ld not supported by cbb\n", 883 start, end, count); 884 return (NULL); 885 } 886 flags |= RF_SHAREABLE; 887 start = end = rman_get_start(sc->irq_res); 888 break; 889 } 890 res = BUS_ALLOC_RESOURCE(up, child, type, rid, 891 start, end, count, flags & ~RF_ACTIVE); 892 if (res == NULL) 893 return (NULL); 894 cbb_insert_res(sc, res, type, *rid); 895 if (flags & RF_ACTIVE) { 896 if (bus_activate_resource(child, type, *rid, res) != 0) { 897 bus_release_resource(child, type, *rid, res); 898 return (NULL); 899 } 900 } 901 902 return (res); 903 } 904 905 static int 906 exca_release_resource(struct exca_softc *sc, device_t child, int type, 907 int rid, struct resource *res) 908 { 909 int error; 910 911 if (rman_get_flags(res) & RF_ACTIVE) { 912 error = bus_deactivate_resource(child, type, rid, res); 913 if (error != 0) 914 return (error); 915 } 916 cbb_remove_res(sc, res); 917 return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 918 type, rid, res)); 919 } 920 #endif 921 922 static int 923 exca_modevent(module_t mod, int cmd, void *arg) 924 { 925 return 0; 926 } 927 928 DEV_MODULE(exca, exca_modevent, NULL); 929 MODULE_VERSION(exca, 1); 930