1139749Simp/*- 2140022Simp * Copyright (c) 2002-2005 M Warner Losh. All rights reserved. 389948Simp * 489948Simp * Redistribution and use in source and binary forms, with or without 589948Simp * modification, are permitted provided that the following conditions 689948Simp * are met: 789948Simp * 1. Redistributions of source code must retain the above copyright 889948Simp * notice, this list of conditions and the following disclaimer. 989948Simp * 2. Redistributions in binary form must reproduce the above copyright 1089948Simp * notice, this list of conditions and the following disclaimer in the 1189948Simp * documentation and/or other materials provided with the distribution. 1289948Simp * 1389948Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1489948Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1589948Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1689948Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1789948Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1889948Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1989948Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2089948Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2189948Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2289948Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2389948Simp * 2489948Simp * This software may be derived from NetBSD i82365.c and other files with 2589948Simp * the following copyright: 2689948Simp * 2789948Simp * Copyright (c) 1997 Marc Horowitz. All rights reserved. 2889948Simp * 2989948Simp * Redistribution and use in source and binary forms, with or without 3089948Simp * modification, are permitted provided that the following conditions 3189948Simp * are met: 3289948Simp * 1. Redistributions of source code must retain the above copyright 3389948Simp * notice, this list of conditions and the following disclaimer. 3489948Simp * 2. Redistributions in binary form must reproduce the above copyright 3589948Simp * notice, this list of conditions and the following disclaimer in the 3689948Simp * documentation and/or other materials provided with the distribution. 3789948Simp * 3. All advertising materials mentioning features or use of this software 3889948Simp * must display the following acknowledgement: 3989948Simp * This product includes software developed by Marc Horowitz. 4089948Simp * 4. The name of the author may not be used to endorse or promote products 4189948Simp * derived from this software without specific prior written permission. 4289948Simp * 4389948Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4489948Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4589948Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4689948Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4789948Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4889948Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4989948Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5089948Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5189948Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5289948Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5389948Simp */ 5489948Simp 55119511Simp#include <sys/cdefs.h> 56119511Simp__FBSDID("$FreeBSD$"); 57119511Simp 5889948Simp#include <sys/param.h> 5989948Simp#include <sys/systm.h> 60115988Simp#include <sys/condvar.h> 6189948Simp#include <sys/errno.h> 6289948Simp#include <sys/kernel.h> 6389948Simp#include <sys/malloc.h> 6489948Simp#include <sys/queue.h> 6597613Stakawata#include <sys/module.h> 66115988Simp#include <sys/lock.h> 67115988Simp#include <sys/mutex.h> 6897613Stakawata#include <sys/conf.h> 6989948Simp 7089948Simp#include <sys/bus.h> 7189948Simp#include <machine/bus.h> 7289948Simp#include <sys/rman.h> 7389948Simp#include <machine/resource.h> 7489948Simp 7589948Simp#include <dev/pccard/pccardreg.h> 7689948Simp#include <dev/pccard/pccardvar.h> 7789948Simp 7889948Simp#include <dev/exca/excareg.h> 7989948Simp#include <dev/exca/excavar.h> 8089948Simp 8189948Simp#ifdef EXCA_DEBUG 8289948Simp#define DEVPRINTF(dev, fmt, args...) device_printf((dev), (fmt), ## args) 8389948Simp#define DPRINTF(fmt, args...) printf(fmt, ## args) 8489948Simp#else 8589948Simp#define DEVPRINTF(dev, fmt, args...) 8689948Simp#define DPRINTF(fmt, args...) 8789948Simp#endif 8889948Simp 89110841Simpstatic const char *chip_names[] = 90110841Simp{ 91110841Simp "CardBus socket", 92110841Simp "Intel i82365SL-A/B or clone", 93110841Simp "Intel i82365sl-DF step", 94110841Simp "VLSI chip", 95110841Simp "Cirrus Logic PD6710", 96110841Simp "Cirrus logic PD6722", 97110841Simp "Cirrus Logic PD6729", 98110841Simp "Vadem 365", 99110841Simp "Vadem 465", 100110841Simp "Vadem 468", 101110841Simp "Vadem 469", 102110841Simp "Ricoh RF5C296", 103110841Simp "Ricoh RF5C396", 104110841Simp "IBM clone", 105110841Simp "IBM KING PCMCIA Controller" 106110841Simp}; 107110841Simp 108110841Simpstatic exca_getb_fn exca_mem_getb; 109110841Simpstatic exca_putb_fn exca_mem_putb; 110110841Simpstatic exca_getb_fn exca_io_getb; 111110841Simpstatic exca_putb_fn exca_io_putb; 112110841Simp 11389948Simp/* memory */ 11489948Simp 11589948Simp#define EXCA_MEMINFO(NUM) { \ 11689948Simp EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ 11789948Simp EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ 11889948Simp EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ 11989948Simp EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ 12089948Simp EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ 12189948Simp EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ 12289948Simp EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ 12397708Salfred EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ 12489948Simp} 12589948Simp 12689948Simpstatic struct mem_map_index_st { 12789948Simp int sysmem_start_lsb; 12889948Simp int sysmem_start_msb; 12989948Simp int sysmem_stop_lsb; 13089948Simp int sysmem_stop_msb; 13189948Simp int sysmem_win; 13289948Simp int cardmem_lsb; 13389948Simp int cardmem_msb; 13489948Simp int memenable; 13589948Simp} mem_map_index[] = { 13689948Simp EXCA_MEMINFO(0), 13789948Simp EXCA_MEMINFO(1), 13889948Simp EXCA_MEMINFO(2), 13989948Simp EXCA_MEMINFO(3), 14089948Simp EXCA_MEMINFO(4) 14189948Simp}; 14289948Simp#undef EXCA_MEMINFO 14389948Simp 144110841Simpstatic uint8_t 145110841Simpexca_mem_getb(struct exca_softc *sc, int reg) 146110841Simp{ 147110841Simp return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg)); 148110841Simp} 149110841Simp 150110841Simpstatic void 151110841Simpexca_mem_putb(struct exca_softc *sc, int reg, uint8_t val) 152110841Simp{ 153115461Sphk bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val); 154110841Simp} 155110841Simp 156110841Simpstatic uint8_t 157110841Simpexca_io_getb(struct exca_softc *sc, int reg) 158110841Simp{ 159110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 160110841Simp return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA)); 161110841Simp} 162110841Simp 163110841Simpstatic void 164110841Simpexca_io_putb(struct exca_softc *sc, int reg, uint8_t val) 165110841Simp{ 166110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 167110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val); 168110841Simp} 169110841Simp 17089948Simp/* 17189948Simp * Helper function. This will map the requested memory slot. We setup the 17289948Simp * map before we call this function. This is used to initially force the 17389948Simp * mapping, as well as later restore the mapping after it has been destroyed 17489948Simp * in some fashion (due to a power event typically). 17589948Simp */ 17689948Simpstatic void 17789948Simpexca_do_mem_map(struct exca_softc *sc, int win) 17889948Simp{ 17989948Simp struct mem_map_index_st *map; 18089948Simp struct pccard_mem_handle *mem; 181140022Simp uint32_t offset; 182186796Simp uint32_t mem16; 183186796Simp uint32_t attrmem; 18489948Simp 18589948Simp map = &mem_map_index[win]; 18689948Simp mem = &sc->mem[win]; 187186796Simp mem16 = (mem->kind & PCCARD_MEM_16BIT) ? 188186796Simp EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT : 0; 189186796Simp attrmem = (mem->kind & PCCARD_MEM_ATTR) ? 190186796Simp EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0; 191140022Simp offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 192140022Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 193110841Simp exca_putb(sc, map->sysmem_start_lsb, 194186796Simp mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT); 195110841Simp exca_putb(sc, map->sysmem_start_msb, 19689948Simp ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 197186796Simp EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | mem16); 19889948Simp 199110841Simp exca_putb(sc, map->sysmem_stop_lsb, 200186796Simp (mem->addr + mem->realsize - 1) >> EXCA_SYSMEM_ADDRX_SHIFT); 201110841Simp exca_putb(sc, map->sysmem_stop_msb, 20289948Simp (((mem->addr + mem->realsize - 1) >> 20389948Simp (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 204133782Simp EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 205133782Simp EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 206186796Simp exca_putb(sc, map->sysmem_win, mem->addr >> EXCA_MEMREG_WIN_SHIFT); 20789948Simp 208140022Simp exca_putb(sc, map->cardmem_lsb, offset & 0xff); 209186796Simp exca_putb(sc, map->cardmem_msb, ((offset >> 8) & 210186796Simp EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | attrmem); 21189948Simp 212188167Simp DPRINTF("%s %d-bit memory", 213188220Simp mem->kind & PCCARD_MEM_ATTR ? "attribute" : "common", 214188167Simp mem->kind & PCCARD_MEM_16BIT ? 16 : 8); 215133782Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 216133782Simp EXCA_ADDRWIN_ENABLE_MEMCS16); 21789948Simp 21889948Simp DELAY(100); 21989948Simp#ifdef EXCA_DEBUG 22089948Simp { 22189948Simp int r1, r2, r3, r4, r5, r6, r7; 222110841Simp r1 = exca_getb(sc, map->sysmem_start_msb); 223110841Simp r2 = exca_getb(sc, map->sysmem_start_lsb); 224110841Simp r3 = exca_getb(sc, map->sysmem_stop_msb); 225110841Simp r4 = exca_getb(sc, map->sysmem_stop_lsb); 226110841Simp r5 = exca_getb(sc, map->cardmem_msb); 227110841Simp r6 = exca_getb(sc, map->cardmem_lsb); 228110841Simp r7 = exca_getb(sc, map->sysmem_win); 229188167Simp printf("exca_do_mem_map win %d: %#02x%#02x %#02x%#02x " 230188167Simp "%#02x%#02x %#02x (%#08x+%#06x.%#06x*%#06x) flags %#x\n", 23189948Simp win, r1, r2, r3, r4, r5, r6, r7, 23289948Simp mem->addr, mem->size, mem->realsize, 233188167Simp mem->cardaddr, mem->kind); 23489948Simp } 23589948Simp#endif 23689948Simp} 23789948Simp 23889948Simp/* 23989948Simp * public interface to map a resource. kind is the type of memory to 24089948Simp * map (either common or attribute). Memory created via this interface 24189948Simp * starts out at card address 0. Since the only way to set this is 24289948Simp * to set it on a struct resource after it has been mapped, we're safe 24389948Simp * in maping this assumption. Note that resources can be remapped using 24489948Simp * exca_do_mem_map so that's how the card address can be set later. 24589948Simp */ 24689948Simpint 24789948Simpexca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 24889948Simp{ 24989948Simp int win; 25089948Simp 25189948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 25289948Simp if ((sc->memalloc & (1 << win)) == 0) { 25389948Simp sc->memalloc |= (1 << win); 25489948Simp break; 25589948Simp } 25689948Simp } 25789948Simp if (win >= EXCA_MEM_WINS) 258167832Sjhb return (ENOSPC); 259188167Simp if (sc->flags & EXCA_HAS_MEMREG_WIN) { 260189579Simp#ifdef __LP64__ 261188167Simp if (rman_get_start(res) >> (EXCA_MEMREG_WIN_SHIFT + 8) != 0) { 262188167Simp device_printf(sc->dev, 263188167Simp "Does not support mapping above 4GB."); 264188167Simp return (EINVAL); 265188167Simp } 266188190Simp#endif 267188167Simp } else { 268188167Simp if (rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT != 0) { 269188167Simp device_printf(sc->dev, 270188167Simp "Does not support mapping above 16M."); 271188167Simp return (EINVAL); 272188167Simp } 273100703Simp } 27489948Simp 27589948Simp sc->mem[win].cardaddr = 0; 27689948Simp sc->mem[win].memt = rman_get_bustag(res); 27789948Simp sc->mem[win].memh = rman_get_bushandle(res); 27889948Simp sc->mem[win].addr = rman_get_start(res); 27989948Simp sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 28089948Simp sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 28189948Simp sc->mem[win].realsize = sc->mem[win].realsize - 28289948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 28389948Simp sc->mem[win].kind = kind; 284119520Simp DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 285119520Simp win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 28689948Simp exca_do_mem_map(sc, win); 28789948Simp 28889948Simp return (0); 28989948Simp} 29089948Simp 29189948Simp/* 29289948Simp * Private helper function. This turns off a given memory map that is in 29389948Simp * use. We do this by just clearing the enable bit in the pcic. If we needed 29489948Simp * to make memory unmapping/mapping pairs faster, we would have to store 29589948Simp * more state information about the pcic and then use that to intelligently 29689948Simp * to the map/unmap. However, since we don't do that sort of thing often 29789948Simp * (generally just at configure time), it isn't a case worth optimizing. 29889948Simp */ 29989948Simpstatic void 30089948Simpexca_mem_unmap(struct exca_softc *sc, int window) 30189948Simp{ 30289948Simp if (window < 0 || window >= EXCA_MEM_WINS) 30389948Simp panic("exca_mem_unmap: window out of range"); 30489948Simp 30589948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 30689948Simp sc->memalloc &= ~(1 << window); 30789948Simp} 30889948Simp 30989948Simp/* 310167832Sjhb * Find the map that we're using to hold the resource. This works well 31189948Simp * so long as the client drivers don't do silly things like map the same 31289948Simp * area mutliple times, or map both common and attribute memory at the 31389948Simp * same time. This latter restriction is a bug. We likely should just 31489948Simp * store a pointer to the res in the mem[x] data structure. 31589948Simp */ 31689948Simpstatic int 31789948Simpexca_mem_findmap(struct exca_softc *sc, struct resource *res) 31889948Simp{ 31989948Simp int win; 32089948Simp 32189948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 32289948Simp if (sc->mem[win].memt == rman_get_bustag(res) && 32389948Simp sc->mem[win].addr == rman_get_start(res) && 32489948Simp sc->mem[win].size == rman_get_size(res)) 32589948Simp return (win); 32689948Simp } 32789948Simp return (-1); 32889948Simp} 32989948Simp 33089948Simp/* 33189948Simp * Set the memory flag. This means that we are setting if the memory 33289948Simp * is coming from attribute memory or from common memory on the card. 33389948Simp * CIS entries are generally in attribute memory (although they can 33489948Simp * reside in common memory). Generally, this is the only use for attribute 33589948Simp * memory. However, some cards require their drivers to dance in both 33689948Simp * common and/or attribute memory and this interface (and setting the 33789948Simp * offset interface) exist for such cards. 33889948Simp */ 33989948Simpint 34089948Simpexca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 34189948Simp{ 34289948Simp int win; 34389948Simp 34489948Simp win = exca_mem_findmap(sc, res); 34589948Simp if (win < 0) { 34689948Simp device_printf(sc->dev, 34789948Simp "set_res_flags: specified resource not active\n"); 34889948Simp return (ENOENT); 34989948Simp } 35089948Simp 351186796Simp switch (flags) 352186796Simp { 353186796Simp case PCCARD_A_MEM_ATTR: 354186796Simp sc->mem[win].kind |= PCCARD_MEM_ATTR; 355186796Simp break; 356186796Simp case PCCARD_A_MEM_COM: 357186796Simp sc->mem[win].kind &= ~PCCARD_MEM_ATTR; 358186796Simp break; 359186796Simp case PCCARD_A_MEM_16BIT: 360186796Simp sc->mem[win].kind |= PCCARD_MEM_16BIT; 361186796Simp break; 362186796Simp case PCCARD_A_MEM_8BIT: 363186796Simp sc->mem[win].kind &= ~PCCARD_MEM_16BIT; 364186796Simp break; 365186796Simp } 36689948Simp exca_do_mem_map(sc, win); 36789948Simp return (0); 36889948Simp} 36989948Simp 37089948Simp/* 37189948Simp * Given a resource, go ahead and unmap it if we can find it in the 37289948Simp * resrouce list that's used. 37389948Simp */ 37489948Simpint 37589948Simpexca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 37689948Simp{ 37789948Simp int win; 37889948Simp 37989948Simp win = exca_mem_findmap(sc, res); 38089948Simp if (win < 0) 38189948Simp return (ENOENT); 38289948Simp exca_mem_unmap(sc, win); 38389948Simp return (0); 38489948Simp} 38589948Simp 38689948Simp/* 38789948Simp * Set the offset of the memory. We use this for reading the CIS and 388151410Simp * frobbing the pccard's pccard registers (CCR, etc). Some drivers 389151410Simp * need to access arbitrary attribute and common memory during their 390151410Simp * initialization and operation. 39189948Simp */ 39289948Simpint 39389948Simpexca_mem_set_offset(struct exca_softc *sc, struct resource *res, 39489948Simp uint32_t cardaddr, uint32_t *deltap) 39589948Simp{ 39689948Simp int win; 39789948Simp uint32_t delta; 39889948Simp 39989948Simp win = exca_mem_findmap(sc, res); 40089948Simp if (win < 0) { 40189948Simp device_printf(sc->dev, 40289948Simp "set_memory_offset: specified resource not active\n"); 40389948Simp return (ENOENT); 40489948Simp } 405119520Simp sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1); 40689948Simp delta = cardaddr % EXCA_MEM_PAGESIZE; 40789948Simp if (deltap) 40889948Simp *deltap = delta; 40989948Simp sc->mem[win].realsize = sc->mem[win].size + delta + 41089948Simp EXCA_MEM_PAGESIZE - 1; 41189948Simp sc->mem[win].realsize = sc->mem[win].realsize - 41289948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 41389948Simp exca_do_mem_map(sc, win); 41489948Simp return (0); 41589948Simp} 41689948Simp 41789948Simp 41889948Simp/* I/O */ 41989948Simp 42089948Simp#define EXCA_IOINFO(NUM) { \ 42189948Simp EXCA_IOADDR ## NUM ## _START_LSB, \ 42289948Simp EXCA_IOADDR ## NUM ## _START_MSB, \ 42389948Simp EXCA_IOADDR ## NUM ## _STOP_LSB, \ 42489948Simp EXCA_IOADDR ## NUM ## _STOP_MSB, \ 42597708Salfred EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 42689948Simp EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 42789948Simp | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 42889948Simp | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 42989948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 43089948Simp { \ 43189948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 43289948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 43389948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 43489948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 43589948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 43689948Simp } \ 43789948Simp} 43889948Simp 43989948Simpstatic struct io_map_index_st { 44089948Simp int start_lsb; 44189948Simp int start_msb; 44289948Simp int stop_lsb; 44389948Simp int stop_msb; 44489948Simp int ioenable; 44589948Simp int ioctlmask; 44689948Simp int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 44789948Simp} io_map_index[] = { 44889948Simp EXCA_IOINFO(0), 44989948Simp EXCA_IOINFO(1), 45089948Simp}; 45189948Simp#undef EXCA_IOINFO 45289948Simp 45389948Simpstatic void 45489948Simpexca_do_io_map(struct exca_softc *sc, int win) 45589948Simp{ 45689948Simp struct io_map_index_st *map; 45789948Simp 45889948Simp struct pccard_io_handle *io; 45989948Simp 46089948Simp map = &io_map_index[win]; 46189948Simp io = &sc->io[win]; 462110841Simp exca_putb(sc, map->start_lsb, io->addr & 0xff); 463110841Simp exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 46489948Simp 465110841Simp exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 466110841Simp exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 46789948Simp 46889948Simp exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 46989948Simp exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 47089948Simp 47189948Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 47289948Simp#ifdef EXCA_DEBUG 47389948Simp { 47489948Simp int r1, r2, r3, r4; 475110841Simp r1 = exca_getb(sc, map->start_msb); 476110841Simp r2 = exca_getb(sc, map->start_lsb); 477110841Simp r3 = exca_getb(sc, map->stop_msb); 478110841Simp r4 = exca_getb(sc, map->stop_lsb); 47989948Simp DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 48089948Simp "(%08x+%08x)\n", win, r1, r2, r3, r4, 48189948Simp io->addr, io->size); 48289948Simp } 48389948Simp#endif 48489948Simp} 48589948Simp 48689948Simpint 48789948Simpexca_io_map(struct exca_softc *sc, int width, struct resource *r) 48889948Simp{ 48989948Simp int win; 49089948Simp#ifdef EXCA_DEBUG 49189948Simp static char *width_names[] = { "auto", "io8", "io16"}; 49289948Simp#endif 49389948Simp for (win=0; win < EXCA_IO_WINS; win++) { 49489948Simp if ((sc->ioalloc & (1 << win)) == 0) { 49589948Simp sc->ioalloc |= (1 << win); 49689948Simp break; 49789948Simp } 49889948Simp } 49989948Simp if (win >= EXCA_IO_WINS) 500167832Sjhb return (ENOSPC); 50189948Simp 50289948Simp sc->io[win].iot = rman_get_bustag(r); 50389948Simp sc->io[win].ioh = rman_get_bushandle(r); 50489948Simp sc->io[win].addr = rman_get_start(r); 50589948Simp sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 50689948Simp sc->io[win].flags = 0; 50789948Simp sc->io[win].width = width; 50889948Simp DPRINTF("exca_io_map window %d %s port %x+%x\n", 50989948Simp win, width_names[width], sc->io[win].addr, 51089948Simp sc->io[win].size); 51189948Simp exca_do_io_map(sc, win); 51289948Simp 51389948Simp return (0); 51489948Simp} 51589948Simp 51689948Simpstatic void 51789948Simpexca_io_unmap(struct exca_softc *sc, int window) 51889948Simp{ 51989948Simp if (window >= EXCA_IO_WINS) 52089948Simp panic("exca_io_unmap: window out of range"); 52189948Simp 52289948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 52389948Simp 52489948Simp sc->ioalloc &= ~(1 << window); 52589948Simp 52689948Simp sc->io[window].iot = 0; 52789948Simp sc->io[window].ioh = 0; 52889948Simp sc->io[window].addr = 0; 52989948Simp sc->io[window].size = 0; 53089948Simp sc->io[window].flags = 0; 53189948Simp sc->io[window].width = 0; 53289948Simp} 53389948Simp 53489948Simpstatic int 53589948Simpexca_io_findmap(struct exca_softc *sc, struct resource *res) 53689948Simp{ 53789948Simp int win; 53889948Simp 53989948Simp for (win = 0; win < EXCA_IO_WINS; win++) { 54089948Simp if (sc->io[win].iot == rman_get_bustag(res) && 54189948Simp sc->io[win].addr == rman_get_start(res) && 54289948Simp sc->io[win].size == rman_get_size(res)) 54389948Simp return (win); 54489948Simp } 54589948Simp return (-1); 54689948Simp} 54789948Simp 54889948Simp 54989948Simpint 55089948Simpexca_io_unmap_res(struct exca_softc *sc, struct resource *res) 55189948Simp{ 55289948Simp int win; 55389948Simp 55489948Simp win = exca_io_findmap(sc, res); 55589948Simp if (win < 0) 55689948Simp return (ENOENT); 55789948Simp exca_io_unmap(sc, win); 55889948Simp return (0); 55989948Simp} 56089948Simp 56189948Simp/* Misc */ 56289948Simp 56389948Simp/* 56489948Simp * If interrupts are enabled, then we should be able to just wait for 56589948Simp * an interrupt routine to wake us up. Busy waiting shouldn't be 56689948Simp * necessary. Sadly, not all legacy ISA cards support an interrupt 56789948Simp * for the busy state transitions, at least according to their datasheets, 56889948Simp * so we busy wait a while here.. 56989948Simp */ 57089948Simpstatic void 57189948Simpexca_wait_ready(struct exca_softc *sc) 57289948Simp{ 57389948Simp int i; 57489948Simp DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 575110841Simp exca_getb(sc, EXCA_IF_STATUS)); 57689948Simp for (i = 0; i < 10000; i++) { 577110841Simp if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 57889948Simp return; 57989948Simp DELAY(500); 58089948Simp } 58189948Simp device_printf(sc->dev, "ready never happened, status = %02x\n", 582110841Simp exca_getb(sc, EXCA_IF_STATUS)); 58389948Simp} 58489948Simp 58589948Simp/* 58689948Simp * Reset the card. Ideally, we'd do a lot of this via interrupts. 58789948Simp * However, many PC Cards will deassert the ready signal. This means 58889948Simp * that they are asserting an interrupt. This makes it hard to 58989948Simp * do anything but a busy wait here. One could argue that these 59089948Simp * such cards are broken, or that the bridge that allows this sort 59189948Simp * of interrupt through isn't quite what you'd want (and may be a standards 592150460Simp * violation). However, such arguing would leave a huge class of PC Cards 593104601Simp * and bridges out of reach for use in the system. 594104601Simp * 595104601Simp * Maybe I should reevaluate the above based on the power bug I fixed 596104601Simp * in OLDCARD. 59789948Simp */ 59889948Simpvoid 59989948Simpexca_reset(struct exca_softc *sc, device_t child) 60089948Simp{ 60189948Simp int win; 60289948Simp 60389948Simp /* enable socket i/o */ 60489948Simp exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 60589948Simp 606110841Simp exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 60789948Simp /* hold reset for 30ms */ 60889948Simp DELAY(30*1000); 60989948Simp /* clear the reset flag */ 61089948Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 611150460Simp /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 61289948Simp DELAY(20*1000); 61389948Simp 61489948Simp exca_wait_ready(sc); 61589948Simp 61689948Simp /* disable all address windows */ 617110841Simp exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 61889948Simp 619120872Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 620120872Simp DEVPRINTF(sc->dev, "card type is io\n"); 62189948Simp 62289948Simp /* reinstall all the memory and io mappings */ 62389948Simp for (win = 0; win < EXCA_MEM_WINS; ++win) 62489948Simp if (sc->memalloc & (1 << win)) 62589948Simp exca_do_mem_map(sc, win); 62689948Simp for (win = 0; win < EXCA_IO_WINS; ++win) 62789948Simp if (sc->ioalloc & (1 << win)) 62889948Simp exca_do_io_map(sc, win); 62989948Simp} 63089948Simp 63189948Simp/* 63289948Simp * Initialize the exca_softc data structure for the first time. 63389948Simp */ 63489948Simpvoid 635100703Simpexca_init(struct exca_softc *sc, device_t dev, 636100703Simp bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 63789948Simp{ 63889948Simp sc->dev = dev; 63989948Simp sc->memalloc = 0; 64089948Simp sc->ioalloc = 0; 64189948Simp sc->bst = bst; 64289948Simp sc->bsh = bsh; 64389948Simp sc->offset = offset; 64489948Simp sc->flags = 0; 645110841Simp sc->getb = exca_mem_getb; 646110841Simp sc->putb = exca_mem_putb; 64789948Simp} 64889948Simp 64989948Simp/* 650110841Simp * Is this socket valid? 651110841Simp */ 652110841Simpstatic int 653110841Simpexca_valid_slot(struct exca_softc *exca) 654110841Simp{ 655110841Simp uint8_t c; 656110841Simp 657115988Simp /* Assume the worst */ 658115988Simp exca->chipset = EXCA_BOGUS; 659115988Simp 660110841Simp /* 661110841Simp * see if there's a PCMCIA controller here 662110841Simp * Intel PCMCIA controllers use 0x82 and 0x83 663110841Simp * IBM clone chips use 0x88 and 0x89, apparently 664110841Simp */ 665110841Simp c = exca_getb(exca, EXCA_IDENT); 666151309Simp DEVPRINTF(exca->dev, "Ident is %x\n", c); 667110841Simp if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 668110841Simp return (0); 669110841Simp if ((c & EXCA_IDENT_ZERO) != 0) 670110841Simp return (0); 671110841Simp switch (c & EXCA_IDENT_REV_MASK) { 672110841Simp /* 673110841Simp * 82365 or clones. 674110841Simp */ 675110841Simp case EXCA_IDENT_REV_I82365SLR0: 676110841Simp case EXCA_IDENT_REV_I82365SLR1: 677110841Simp exca->chipset = EXCA_I82365; 678110841Simp /* 679110841Simp * Check for Vadem chips by unlocking their extra 680110841Simp * registers and looking for valid ID. Bit 3 in 681110841Simp * the ID register is normally 0, except when 682110841Simp * EXCA_VADEMREV is set. Other bridges appear 683110841Simp * to ignore this frobbing. 684110841Simp */ 685110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 686110841Simp EXCA_VADEM_COOKIE1); 687110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 688110841Simp EXCA_VADEM_COOKIE2); 689110841Simp exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 690110841Simp c = exca_getb(exca, EXCA_IDENT); 691110841Simp if (c & 0x08) { 692110841Simp switch (c & 7) { 693110841Simp case 1: 694110841Simp exca->chipset = EXCA_VG365; 695110841Simp break; 696110841Simp case 2: 697110841Simp exca->chipset = EXCA_VG465; 698110841Simp break; 699110841Simp case 3: 700110841Simp exca->chipset = EXCA_VG468; 701110841Simp break; 702110841Simp default: 703110841Simp exca->chipset = EXCA_VG469; 704110841Simp break; 705110841Simp } 706110841Simp exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 707110841Simp break; 708110841Simp } 709110841Simp /* 710110841Simp * Check for RICOH RF5C[23]96 PCMCIA Controller 711110841Simp */ 712110841Simp c = exca_getb(exca, EXCA_RICOH_ID); 713110841Simp if (c == EXCA_RID_396) { 714110841Simp exca->chipset = EXCA_RF5C396; 715110841Simp break; 716110841Simp } else if (c == EXCA_RID_296) { 717110841Simp exca->chipset = EXCA_RF5C296; 718110841Simp break; 719110841Simp } 720110841Simp /* 721110841Simp * Check for Cirrus logic chips. 722110841Simp */ 723110841Simp exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 724110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 725110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 726110841Simp EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 727110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 728110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 729110841Simp if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 730110841Simp exca->chipset = EXCA_PD6722; 731110841Simp else 732110841Simp exca->chipset = EXCA_PD6710; 733110841Simp break; 734110841Simp } 735110841Simp } 736110841Simp break; 737110841Simp 738110841Simp case EXCA_IDENT_REV_I82365SLDF: 739110841Simp /* 740110841Simp * Intel i82365sl-DF step or maybe a vlsi 82c146 741110841Simp * we detected the vlsi case earlier, so if the controller 742110841Simp * isn't set, we know it is a i82365sl step D. 743110841Simp */ 744110841Simp exca->chipset = EXCA_I82365SL_DF; 745110841Simp break; 746110841Simp case EXCA_IDENT_REV_IBM1: 747110841Simp case EXCA_IDENT_REV_IBM2: 748110841Simp exca->chipset = EXCA_IBM; 749110841Simp break; 750110841Simp case EXCA_IDENT_REV_IBM_KING: 751110841Simp exca->chipset = EXCA_IBM_KING; 752110841Simp break; 753110841Simp default: 754110841Simp return (0); 755110841Simp } 756110841Simp return (1); 757110841Simp} 758110841Simp 759110841Simp/* 76089948Simp * Probe the expected slots. We maybe should set the ID for each of these 76189948Simp * slots too while we're at it. But maybe that belongs to a separate 76289948Simp * function. 76389948Simp * 764110841Simp * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 76589948Simp */ 76689948Simpint 767110841Simpexca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 768110841Simp bus_space_handle_t ioh) 76989948Simp{ 77089948Simp int err; 77189948Simp int i; 77289948Simp 77389948Simp err = ENXIO; 774110841Simp for (i = 0; i < EXCA_NSLOTS; i++) { 775100703Simp exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 776110841Simp exca->getb = exca_io_getb; 777110841Simp exca->putb = exca_io_putb; 778151458Simp if (exca_valid_slot(&exca[i])) { 779151458Simp device_set_desc(dev, chip_names[exca[i].chipset]); 78089948Simp err = 0; 781151458Simp } 78289948Simp } 78389948Simp return (err); 78489948Simp} 78589948Simp 786115988Simpvoid 787115988Simpexca_insert(struct exca_softc *exca) 788115988Simp{ 789166942Simp if (device_is_attached(exca->pccarddev)) { 790115988Simp if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 791115988Simp device_printf(exca->dev, 792115988Simp "PC Card card activation failed\n"); 793115988Simp } else { 794115988Simp device_printf(exca->dev, 795115988Simp "PC Card inserted, but no pccard bus.\n"); 796115988Simp } 797115988Simp} 798115988Simp 799115988Simp 800115988Simpvoid 801115988Simpexca_removal(struct exca_softc *exca) 802115988Simp{ 803166742Simp if (device_is_attached(exca->pccarddev)) 804115988Simp CARD_DETACH_CARD(exca->pccarddev); 805115988Simp} 806115988Simp 807115988Simpint 808115988Simpexca_activate_resource(struct exca_softc *exca, device_t child, int type, 809115988Simp int rid, struct resource *res) 810115988Simp{ 811115988Simp int err; 812115988Simp 813167832Sjhb if (rman_get_flags(res) & RF_ACTIVE) 814167832Sjhb return (0); 815167832Sjhb err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 816167832Sjhb type, rid, res); 817167832Sjhb if (err) 818167832Sjhb return (err); 819167832Sjhb switch (type) { 820167832Sjhb case SYS_RES_IOPORT: 821167832Sjhb err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 822167832Sjhb break; 823167832Sjhb case SYS_RES_MEMORY: 824186796Simp err = exca_mem_map(exca, 0, res); 825167832Sjhb break; 826115988Simp } 827167832Sjhb if (err) 828167832Sjhb BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 829167832Sjhb type, rid, res); 830167832Sjhb return (err); 831115988Simp} 832115988Simp 833115988Simpint 834115988Simpexca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 835115988Simp int rid, struct resource *res) 836115988Simp{ 837115988Simp if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 838115988Simp switch (type) { 839115988Simp case SYS_RES_IOPORT: 840115988Simp if (exca_io_unmap_res(exca, res)) 841115988Simp return (ENOENT); 842115988Simp break; 843115988Simp case SYS_RES_MEMORY: 844115988Simp if (exca_mem_unmap_res(exca, res)) 845115988Simp return (ENOENT); 846115988Simp break; 847115988Simp } 848115988Simp } 849115988Simp return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 850115988Simp type, rid, res)); 851115988Simp} 852115988Simp 853133782Simp#if 0 854133782Simpstatic struct resource * 855133782Simpexca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 856133782Simp u_long start, u_long end, u_long count, uint flags) 857133782Simp{ 858133782Simp struct resource *res = NULL; 859133782Simp int tmp; 860133782Simp 861133782Simp switch (type) { 862133782Simp case SYS_RES_MEMORY: 863133782Simp if (start < cbb_start_mem) 864133782Simp start = cbb_start_mem; 865133782Simp if (end < start) 866133782Simp end = start; 867133782Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 868133782Simp rman_make_alignment_flags(CBB_MEMALIGN); 869133782Simp break; 870133782Simp case SYS_RES_IOPORT: 871133782Simp if (start < cbb_start_16_io) 872133782Simp start = cbb_start_16_io; 873133782Simp if (end < start) 874133782Simp end = start; 875133782Simp break; 876133782Simp case SYS_RES_IRQ: 877133782Simp tmp = rman_get_start(sc->irq_res); 878133782Simp if (start > tmp || end < tmp || count != 1) { 879133782Simp device_printf(child, "requested interrupt %ld-%ld," 880133782Simp "count = %ld not supported by cbb\n", 881133782Simp start, end, count); 882133782Simp return (NULL); 883133782Simp } 884133782Simp flags |= RF_SHAREABLE; 885133782Simp start = end = rman_get_start(sc->irq_res); 886133782Simp break; 887133782Simp } 888133782Simp res = BUS_ALLOC_RESOURCE(up, child, type, rid, 889133782Simp start, end, count, flags & ~RF_ACTIVE); 890133782Simp if (res == NULL) 891133782Simp return (NULL); 892133782Simp cbb_insert_res(sc, res, type, *rid); 893133782Simp if (flags & RF_ACTIVE) { 894133782Simp if (bus_activate_resource(child, type, *rid, res) != 0) { 895133782Simp bus_release_resource(child, type, *rid, res); 896133782Simp return (NULL); 897133782Simp } 898133782Simp } 899133782Simp 900133782Simp return (res); 901133782Simp} 902133782Simp 903110841Simpstatic int 904133782Simpexca_release_resource(struct exca_softc *sc, device_t child, int type, 905133782Simp int rid, struct resource *res) 906133782Simp{ 907133782Simp int error; 908133782Simp 909133782Simp if (rman_get_flags(res) & RF_ACTIVE) { 910133782Simp error = bus_deactivate_resource(child, type, rid, res); 911133782Simp if (error != 0) 912133782Simp return (error); 913133782Simp } 914133782Simp cbb_remove_res(sc, res); 915133782Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 916133782Simp type, rid, res)); 917133782Simp} 918133782Simp#endif 919133782Simp 920133782Simpstatic int 921110841Simpexca_modevent(module_t mod, int cmd, void *arg) 92289948Simp{ 923110841Simp return 0; 92489948Simp} 92597613Stakawata 92697613StakawataDEV_MODULE(exca, exca_modevent, NULL); 92797613StakawataMODULE_VERSION(exca, 1); 928