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