exca.c revision 150460
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: head/sys/dev/exca/exca.c 150460 2005-09-22 06:01:44Z imp $"); 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 89110841Simp#if 0 90110841Simpstatic const char *chip_names[] = 91110841Simp{ 92110841Simp "CardBus socket", 93110841Simp "Intel i82365SL-A/B or clone", 94110841Simp "Intel i82365sl-DF step", 95110841Simp "VLSI chip", 96110841Simp "Cirrus Logic PD6710", 97110841Simp "Cirrus logic PD6722", 98110841Simp "Cirrus Logic PD6729", 99110841Simp "Vadem 365", 100110841Simp "Vadem 465", 101110841Simp "Vadem 468", 102110841Simp "Vadem 469", 103110841Simp "Ricoh RF5C296", 104110841Simp "Ricoh RF5C396", 105110841Simp "IBM clone", 106110841Simp "IBM KING PCMCIA Controller" 107110841Simp}; 108110841Simp#endif 109110841Simp 110110841Simpstatic exca_getb_fn exca_mem_getb; 111110841Simpstatic exca_putb_fn exca_mem_putb; 112110841Simpstatic exca_getb_fn exca_io_getb; 113110841Simpstatic exca_putb_fn exca_io_putb; 114110841Simp 11589948Simp/* memory */ 11689948Simp 11789948Simp#define EXCA_MEMINFO(NUM) { \ 11889948Simp EXCA_SYSMEM_ADDR ## NUM ## _START_LSB, \ 11989948Simp EXCA_SYSMEM_ADDR ## NUM ## _START_MSB, \ 12089948Simp EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ 12189948Simp EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ 12289948Simp EXCA_SYSMEM_ADDR ## NUM ## _WIN, \ 12389948Simp EXCA_CARDMEM_ADDR ## NUM ## _LSB, \ 12489948Simp EXCA_CARDMEM_ADDR ## NUM ## _MSB, \ 12597708Salfred EXCA_ADDRWIN_ENABLE_MEM ## NUM, \ 12689948Simp} 12789948Simp 12889948Simpstatic struct mem_map_index_st { 12989948Simp int sysmem_start_lsb; 13089948Simp int sysmem_start_msb; 13189948Simp int sysmem_stop_lsb; 13289948Simp int sysmem_stop_msb; 13389948Simp int sysmem_win; 13489948Simp int cardmem_lsb; 13589948Simp int cardmem_msb; 13689948Simp int memenable; 13789948Simp} mem_map_index[] = { 13889948Simp EXCA_MEMINFO(0), 13989948Simp EXCA_MEMINFO(1), 14089948Simp EXCA_MEMINFO(2), 14189948Simp EXCA_MEMINFO(3), 14289948Simp EXCA_MEMINFO(4) 14389948Simp}; 14489948Simp#undef EXCA_MEMINFO 14589948Simp 146110841Simpstatic uint8_t 147110841Simpexca_mem_getb(struct exca_softc *sc, int reg) 148110841Simp{ 149110841Simp return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg)); 150110841Simp} 151110841Simp 152110841Simpstatic void 153110841Simpexca_mem_putb(struct exca_softc *sc, int reg, uint8_t val) 154110841Simp{ 155115461Sphk bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val); 156110841Simp} 157110841Simp 158110841Simpstatic uint8_t 159110841Simpexca_io_getb(struct exca_softc *sc, int reg) 160110841Simp{ 161110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 162110841Simp return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA)); 163110841Simp} 164110841Simp 165110841Simpstatic void 166110841Simpexca_io_putb(struct exca_softc *sc, int reg, uint8_t val) 167110841Simp{ 168110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset); 169110841Simp bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val); 170110841Simp} 171110841Simp 17289948Simp/* 17389948Simp * Helper function. This will map the requested memory slot. We setup the 17489948Simp * map before we call this function. This is used to initially force the 17589948Simp * mapping, as well as later restore the mapping after it has been destroyed 17689948Simp * in some fashion (due to a power event typically). 17789948Simp */ 17889948Simpstatic void 17989948Simpexca_do_mem_map(struct exca_softc *sc, int win) 18089948Simp{ 18189948Simp struct mem_map_index_st *map; 18289948Simp struct pccard_mem_handle *mem; 183140022Simp uint32_t offset; 18489948Simp 18589948Simp map = &mem_map_index[win]; 18689948Simp mem = &sc->mem[win]; 187140022Simp offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 188140022Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 189110841Simp exca_putb(sc, map->sysmem_start_lsb, 19089948Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 191110841Simp exca_putb(sc, map->sysmem_start_msb, 19289948Simp ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 193119520Simp EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK)); 19489948Simp 195110841Simp exca_putb(sc, map->sysmem_stop_lsb, 19689948Simp ((mem->addr + mem->realsize - 1) >> 19789948Simp EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 198110841Simp exca_putb(sc, map->sysmem_stop_msb, 19989948Simp (((mem->addr + mem->realsize - 1) >> 20089948Simp (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 201133782Simp EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | 202133782Simp EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2); 20389948Simp 204110841Simp exca_putb(sc, map->sysmem_win, 20589948Simp (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff); 20689948Simp 207140022Simp exca_putb(sc, map->cardmem_lsb, offset & 0xff); 208140022Simp exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) & 20989948Simp EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | 210119551Simp ((mem->kind == PCCARD_A_MEM_ATTR) ? 21189948Simp EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); 21289948Simp 213119520Simp#ifdef EXCA_DEBUG 214119551Simp if (mem->kind == PCCARD_A_MEM_ATTR) 215119520Simp printf("attribtue memory\n"); 216119520Simp else 217119520Simp printf("common memory\n"); 218119520Simp#endif 219133782Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 220133782Simp EXCA_ADDRWIN_ENABLE_MEMCS16); 22189948Simp 22289948Simp DELAY(100); 22389948Simp#ifdef EXCA_DEBUG 22489948Simp { 22589948Simp int r1, r2, r3, r4, r5, r6, r7; 226110841Simp r1 = exca_getb(sc, map->sysmem_start_msb); 227110841Simp r2 = exca_getb(sc, map->sysmem_start_lsb); 228110841Simp r3 = exca_getb(sc, map->sysmem_stop_msb); 229110841Simp r4 = exca_getb(sc, map->sysmem_stop_lsb); 230110841Simp r5 = exca_getb(sc, map->cardmem_msb); 231110841Simp r6 = exca_getb(sc, map->cardmem_lsb); 232110841Simp r7 = exca_getb(sc, map->sysmem_win); 233133782Simp printf("exca_do_mem_map win %d: %02x%02x %02x%02x " 234133782Simp "%02x%02x %02x (%08x+%06x.%06x*%06x)\n", 23589948Simp win, r1, r2, r3, r4, r5, r6, r7, 23689948Simp mem->addr, mem->size, mem->realsize, 237119520Simp mem->cardaddr); 23889948Simp } 23989948Simp#endif 24089948Simp} 24189948Simp 24289948Simp/* 24389948Simp * public interface to map a resource. kind is the type of memory to 24489948Simp * map (either common or attribute). Memory created via this interface 24589948Simp * starts out at card address 0. Since the only way to set this is 24689948Simp * to set it on a struct resource after it has been mapped, we're safe 24789948Simp * in maping this assumption. Note that resources can be remapped using 24889948Simp * exca_do_mem_map so that's how the card address can be set later. 24989948Simp */ 25089948Simpint 25189948Simpexca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 25289948Simp{ 25389948Simp int win; 25489948Simp 25589948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 25689948Simp if ((sc->memalloc & (1 << win)) == 0) { 25789948Simp sc->memalloc |= (1 << win); 25889948Simp break; 25989948Simp } 26089948Simp } 26189948Simp if (win >= EXCA_MEM_WINS) 26289948Simp return (1); 263120421Simp if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 && 264100703Simp (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) { 265100703Simp device_printf(sc->dev, "Does not support mapping above 24M."); 266100703Simp return (1); 267100703Simp } 26889948Simp 26989948Simp sc->mem[win].cardaddr = 0; 27089948Simp sc->mem[win].memt = rman_get_bustag(res); 27189948Simp sc->mem[win].memh = rman_get_bushandle(res); 27289948Simp sc->mem[win].addr = rman_get_start(res); 27389948Simp sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 27489948Simp sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 27589948Simp sc->mem[win].realsize = sc->mem[win].realsize - 27689948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 27789948Simp sc->mem[win].kind = kind; 278119520Simp DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 279119520Simp win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 28089948Simp exca_do_mem_map(sc, win); 28189948Simp 28289948Simp return (0); 28389948Simp} 28489948Simp 28589948Simp/* 28689948Simp * Private helper function. This turns off a given memory map that is in 28789948Simp * use. We do this by just clearing the enable bit in the pcic. If we needed 28889948Simp * to make memory unmapping/mapping pairs faster, we would have to store 28989948Simp * more state information about the pcic and then use that to intelligently 29089948Simp * to the map/unmap. However, since we don't do that sort of thing often 29189948Simp * (generally just at configure time), it isn't a case worth optimizing. 29289948Simp */ 29389948Simpstatic void 29489948Simpexca_mem_unmap(struct exca_softc *sc, int window) 29589948Simp{ 29689948Simp if (window < 0 || window >= EXCA_MEM_WINS) 29789948Simp panic("exca_mem_unmap: window out of range"); 29889948Simp 29989948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 30089948Simp sc->memalloc &= ~(1 << window); 30189948Simp} 30289948Simp 30389948Simp/* 30489948Simp * Find the map that we're using to hold the resoruce. This works well 30589948Simp * so long as the client drivers don't do silly things like map the same 30689948Simp * area mutliple times, or map both common and attribute memory at the 30789948Simp * same time. This latter restriction is a bug. We likely should just 30889948Simp * store a pointer to the res in the mem[x] data structure. 30989948Simp */ 31089948Simpstatic int 31189948Simpexca_mem_findmap(struct exca_softc *sc, struct resource *res) 31289948Simp{ 31389948Simp int win; 31489948Simp 31589948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 31689948Simp if (sc->mem[win].memt == rman_get_bustag(res) && 31789948Simp sc->mem[win].addr == rman_get_start(res) && 31889948Simp sc->mem[win].size == rman_get_size(res)) 31989948Simp return (win); 32089948Simp } 32189948Simp return (-1); 32289948Simp} 32389948Simp 32489948Simp/* 32589948Simp * Set the memory flag. This means that we are setting if the memory 32689948Simp * is coming from attribute memory or from common memory on the card. 32789948Simp * CIS entries are generally in attribute memory (although they can 32889948Simp * reside in common memory). Generally, this is the only use for attribute 32989948Simp * memory. However, some cards require their drivers to dance in both 33089948Simp * common and/or attribute memory and this interface (and setting the 33189948Simp * offset interface) exist for such cards. 33289948Simp */ 33389948Simpint 33489948Simpexca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 33589948Simp{ 33689948Simp int win; 33789948Simp 33889948Simp win = exca_mem_findmap(sc, res); 33989948Simp if (win < 0) { 34089948Simp device_printf(sc->dev, 34189948Simp "set_res_flags: specified resource not active\n"); 34289948Simp return (ENOENT); 34389948Simp } 34489948Simp 34589948Simp sc->mem[win].kind = flags; 34689948Simp exca_do_mem_map(sc, win); 34789948Simp return (0); 34889948Simp} 34989948Simp 35089948Simp/* 35189948Simp * Given a resource, go ahead and unmap it if we can find it in the 35289948Simp * resrouce list that's used. 35389948Simp */ 35489948Simpint 35589948Simpexca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 35689948Simp{ 35789948Simp int win; 35889948Simp 35989948Simp win = exca_mem_findmap(sc, res); 36089948Simp if (win < 0) 36189948Simp return (ENOENT); 36289948Simp exca_mem_unmap(sc, win); 36389948Simp return (0); 36489948Simp} 36589948Simp 36689948Simp/* 36789948Simp * Set the offset of the memory. We use this for reading the CIS and 36889948Simp * frobbing the pccard's pccard registers (POR, etc). Some drivers 36989948Simp * need to access this functionality as well, since they have receive 370119520Simp * buffers defined in the attribute memory. 37189948Simp */ 37289948Simpint 37389948Simpexca_mem_set_offset(struct exca_softc *sc, struct resource *res, 37489948Simp uint32_t cardaddr, uint32_t *deltap) 37589948Simp{ 37689948Simp int win; 37789948Simp uint32_t delta; 37889948Simp 37989948Simp win = exca_mem_findmap(sc, res); 38089948Simp if (win < 0) { 38189948Simp device_printf(sc->dev, 38289948Simp "set_memory_offset: specified resource not active\n"); 38389948Simp return (ENOENT); 38489948Simp } 385119520Simp sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1); 38689948Simp delta = cardaddr % EXCA_MEM_PAGESIZE; 38789948Simp if (deltap) 38889948Simp *deltap = delta; 38989948Simp sc->mem[win].realsize = sc->mem[win].size + delta + 39089948Simp EXCA_MEM_PAGESIZE - 1; 39189948Simp sc->mem[win].realsize = sc->mem[win].realsize - 39289948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 39389948Simp exca_do_mem_map(sc, win); 39489948Simp return (0); 39589948Simp} 39689948Simp 39789948Simp 39889948Simp/* I/O */ 39989948Simp 40089948Simp#define EXCA_IOINFO(NUM) { \ 40189948Simp EXCA_IOADDR ## NUM ## _START_LSB, \ 40289948Simp EXCA_IOADDR ## NUM ## _START_MSB, \ 40389948Simp EXCA_IOADDR ## NUM ## _STOP_LSB, \ 40489948Simp EXCA_IOADDR ## NUM ## _STOP_MSB, \ 40597708Salfred EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 40689948Simp EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 40789948Simp | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 40889948Simp | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 40989948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 41089948Simp { \ 41189948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 41289948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 41389948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 41489948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 41589948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 41689948Simp } \ 41789948Simp} 41889948Simp 41989948Simpstatic struct io_map_index_st { 42089948Simp int start_lsb; 42189948Simp int start_msb; 42289948Simp int stop_lsb; 42389948Simp int stop_msb; 42489948Simp int ioenable; 42589948Simp int ioctlmask; 42689948Simp int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 42789948Simp} io_map_index[] = { 42889948Simp EXCA_IOINFO(0), 42989948Simp EXCA_IOINFO(1), 43089948Simp}; 43189948Simp#undef EXCA_IOINFO 43289948Simp 43389948Simpstatic void 43489948Simpexca_do_io_map(struct exca_softc *sc, int win) 43589948Simp{ 43689948Simp struct io_map_index_st *map; 43789948Simp 43889948Simp struct pccard_io_handle *io; 43989948Simp 44089948Simp map = &io_map_index[win]; 44189948Simp io = &sc->io[win]; 442110841Simp exca_putb(sc, map->start_lsb, io->addr & 0xff); 443110841Simp exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 44489948Simp 445110841Simp exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 446110841Simp exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 44789948Simp 44889948Simp exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 44989948Simp exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 45089948Simp 45189948Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 45289948Simp#ifdef EXCA_DEBUG 45389948Simp { 45489948Simp int r1, r2, r3, r4; 455110841Simp r1 = exca_getb(sc, map->start_msb); 456110841Simp r2 = exca_getb(sc, map->start_lsb); 457110841Simp r3 = exca_getb(sc, map->stop_msb); 458110841Simp r4 = exca_getb(sc, map->stop_lsb); 45989948Simp DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 46089948Simp "(%08x+%08x)\n", win, r1, r2, r3, r4, 46189948Simp io->addr, io->size); 46289948Simp } 46389948Simp#endif 46489948Simp} 46589948Simp 46689948Simpint 46789948Simpexca_io_map(struct exca_softc *sc, int width, struct resource *r) 46889948Simp{ 46989948Simp int win; 47089948Simp#ifdef EXCA_DEBUG 47189948Simp static char *width_names[] = { "auto", "io8", "io16"}; 47289948Simp#endif 47389948Simp for (win=0; win < EXCA_IO_WINS; win++) { 47489948Simp if ((sc->ioalloc & (1 << win)) == 0) { 47589948Simp sc->ioalloc |= (1 << win); 47689948Simp break; 47789948Simp } 47889948Simp } 47989948Simp if (win >= EXCA_IO_WINS) 48089948Simp return (1); 48189948Simp 48289948Simp sc->io[win].iot = rman_get_bustag(r); 48389948Simp sc->io[win].ioh = rman_get_bushandle(r); 48489948Simp sc->io[win].addr = rman_get_start(r); 48589948Simp sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 48689948Simp sc->io[win].flags = 0; 48789948Simp sc->io[win].width = width; 48889948Simp DPRINTF("exca_io_map window %d %s port %x+%x\n", 48989948Simp win, width_names[width], sc->io[win].addr, 49089948Simp sc->io[win].size); 49189948Simp exca_do_io_map(sc, win); 49289948Simp 49389948Simp return (0); 49489948Simp} 49589948Simp 49689948Simpstatic void 49789948Simpexca_io_unmap(struct exca_softc *sc, int window) 49889948Simp{ 49989948Simp if (window >= EXCA_IO_WINS) 50089948Simp panic("exca_io_unmap: window out of range"); 50189948Simp 50289948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 50389948Simp 50489948Simp sc->ioalloc &= ~(1 << window); 50589948Simp 50689948Simp sc->io[window].iot = 0; 50789948Simp sc->io[window].ioh = 0; 50889948Simp sc->io[window].addr = 0; 50989948Simp sc->io[window].size = 0; 51089948Simp sc->io[window].flags = 0; 51189948Simp sc->io[window].width = 0; 51289948Simp} 51389948Simp 51489948Simpstatic int 51589948Simpexca_io_findmap(struct exca_softc *sc, struct resource *res) 51689948Simp{ 51789948Simp int win; 51889948Simp 51989948Simp for (win = 0; win < EXCA_IO_WINS; win++) { 52089948Simp if (sc->io[win].iot == rman_get_bustag(res) && 52189948Simp sc->io[win].addr == rman_get_start(res) && 52289948Simp sc->io[win].size == rman_get_size(res)) 52389948Simp return (win); 52489948Simp } 52589948Simp return (-1); 52689948Simp} 52789948Simp 52889948Simp 52989948Simpint 53089948Simpexca_io_unmap_res(struct exca_softc *sc, struct resource *res) 53189948Simp{ 53289948Simp int win; 53389948Simp 53489948Simp win = exca_io_findmap(sc, res); 53589948Simp if (win < 0) 53689948Simp return (ENOENT); 53789948Simp exca_io_unmap(sc, win); 53889948Simp return (0); 53989948Simp} 54089948Simp 54189948Simp/* Misc */ 54289948Simp 54389948Simp/* 54489948Simp * If interrupts are enabled, then we should be able to just wait for 54589948Simp * an interrupt routine to wake us up. Busy waiting shouldn't be 54689948Simp * necessary. Sadly, not all legacy ISA cards support an interrupt 54789948Simp * for the busy state transitions, at least according to their datasheets, 54889948Simp * so we busy wait a while here.. 54989948Simp */ 55089948Simpstatic void 55189948Simpexca_wait_ready(struct exca_softc *sc) 55289948Simp{ 55389948Simp int i; 55489948Simp DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 555110841Simp exca_getb(sc, EXCA_IF_STATUS)); 55689948Simp for (i = 0; i < 10000; i++) { 557110841Simp if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 55889948Simp return; 55989948Simp DELAY(500); 56089948Simp } 56189948Simp device_printf(sc->dev, "ready never happened, status = %02x\n", 562110841Simp exca_getb(sc, EXCA_IF_STATUS)); 56389948Simp} 56489948Simp 56589948Simp/* 56689948Simp * Reset the card. Ideally, we'd do a lot of this via interrupts. 56789948Simp * However, many PC Cards will deassert the ready signal. This means 56889948Simp * that they are asserting an interrupt. This makes it hard to 56989948Simp * do anything but a busy wait here. One could argue that these 57089948Simp * such cards are broken, or that the bridge that allows this sort 57189948Simp * of interrupt through isn't quite what you'd want (and may be a standards 572150460Simp * violation). However, such arguing would leave a huge class of PC Cards 573104601Simp * and bridges out of reach for use in the system. 574104601Simp * 575104601Simp * Maybe I should reevaluate the above based on the power bug I fixed 576104601Simp * in OLDCARD. 57789948Simp */ 57889948Simpvoid 57989948Simpexca_reset(struct exca_softc *sc, device_t child) 58089948Simp{ 58189948Simp int win; 58289948Simp 58389948Simp /* enable socket i/o */ 58489948Simp exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 58589948Simp 586110841Simp exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 58789948Simp /* hold reset for 30ms */ 58889948Simp DELAY(30*1000); 58989948Simp /* clear the reset flag */ 59089948Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 591150460Simp /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 59289948Simp DELAY(20*1000); 59389948Simp 59489948Simp exca_wait_ready(sc); 59589948Simp 59689948Simp /* disable all address windows */ 597110841Simp exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 59889948Simp 599120872Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 600120872Simp DEVPRINTF(sc->dev, "card type is io\n"); 60189948Simp 60289948Simp /* reinstall all the memory and io mappings */ 60389948Simp for (win = 0; win < EXCA_MEM_WINS; ++win) 60489948Simp if (sc->memalloc & (1 << win)) 60589948Simp exca_do_mem_map(sc, win); 60689948Simp for (win = 0; win < EXCA_IO_WINS; ++win) 60789948Simp if (sc->ioalloc & (1 << win)) 60889948Simp exca_do_io_map(sc, win); 60989948Simp} 61089948Simp 61189948Simp/* 61289948Simp * Initialize the exca_softc data structure for the first time. 61389948Simp */ 61489948Simpvoid 615100703Simpexca_init(struct exca_softc *sc, device_t dev, 616100703Simp bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 61789948Simp{ 61889948Simp sc->dev = dev; 61989948Simp sc->memalloc = 0; 62089948Simp sc->ioalloc = 0; 62189948Simp sc->bst = bst; 62289948Simp sc->bsh = bsh; 62389948Simp sc->offset = offset; 62489948Simp sc->flags = 0; 625110841Simp sc->getb = exca_mem_getb; 626110841Simp sc->putb = exca_mem_putb; 62789948Simp} 62889948Simp 62989948Simp/* 630110841Simp * Is this socket valid? 631110841Simp */ 632110841Simpstatic int 633110841Simpexca_valid_slot(struct exca_softc *exca) 634110841Simp{ 635110841Simp uint8_t c; 636110841Simp 637115988Simp /* Assume the worst */ 638115988Simp exca->chipset = EXCA_BOGUS; 639115988Simp 640110841Simp /* 641110841Simp * see if there's a PCMCIA controller here 642110841Simp * Intel PCMCIA controllers use 0x82 and 0x83 643110841Simp * IBM clone chips use 0x88 and 0x89, apparently 644110841Simp */ 645110841Simp c = exca_getb(exca, EXCA_IDENT); 646110841Simp if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 647110841Simp return (0); 648110841Simp if ((c & EXCA_IDENT_ZERO) != 0) 649110841Simp return (0); 650110841Simp switch (c & EXCA_IDENT_REV_MASK) { 651110841Simp /* 652110841Simp * 82365 or clones. 653110841Simp */ 654110841Simp case EXCA_IDENT_REV_I82365SLR0: 655110841Simp case EXCA_IDENT_REV_I82365SLR1: 656110841Simp exca->chipset = EXCA_I82365; 657110841Simp /* 658110841Simp * Check for Vadem chips by unlocking their extra 659110841Simp * registers and looking for valid ID. Bit 3 in 660110841Simp * the ID register is normally 0, except when 661110841Simp * EXCA_VADEMREV is set. Other bridges appear 662110841Simp * to ignore this frobbing. 663110841Simp */ 664110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 665110841Simp EXCA_VADEM_COOKIE1); 666110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 667110841Simp EXCA_VADEM_COOKIE2); 668110841Simp exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 669110841Simp c = exca_getb(exca, EXCA_IDENT); 670110841Simp if (c & 0x08) { 671110841Simp switch (c & 7) { 672110841Simp case 1: 673110841Simp exca->chipset = EXCA_VG365; 674110841Simp break; 675110841Simp case 2: 676110841Simp exca->chipset = EXCA_VG465; 677110841Simp break; 678110841Simp case 3: 679110841Simp exca->chipset = EXCA_VG468; 680110841Simp break; 681110841Simp default: 682110841Simp exca->chipset = EXCA_VG469; 683110841Simp break; 684110841Simp } 685110841Simp exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 686110841Simp break; 687110841Simp } 688110841Simp /* 689110841Simp * Check for RICOH RF5C[23]96 PCMCIA Controller 690110841Simp */ 691110841Simp c = exca_getb(exca, EXCA_RICOH_ID); 692110841Simp if (c == EXCA_RID_396) { 693110841Simp exca->chipset = EXCA_RF5C396; 694110841Simp break; 695110841Simp } else if (c == EXCA_RID_296) { 696110841Simp exca->chipset = EXCA_RF5C296; 697110841Simp break; 698110841Simp } 699110841Simp /* 700110841Simp * Check for Cirrus logic chips. 701110841Simp */ 702110841Simp exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 703110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 704110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 705110841Simp EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 706110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 707110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 708110841Simp if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 709110841Simp exca->chipset = EXCA_PD6722; 710110841Simp else 711110841Simp exca->chipset = EXCA_PD6710; 712110841Simp break; 713110841Simp } 714110841Simp } 715110841Simp break; 716110841Simp 717110841Simp case EXCA_IDENT_REV_I82365SLDF: 718110841Simp /* 719110841Simp * Intel i82365sl-DF step or maybe a vlsi 82c146 720110841Simp * we detected the vlsi case earlier, so if the controller 721110841Simp * isn't set, we know it is a i82365sl step D. 722110841Simp */ 723110841Simp exca->chipset = EXCA_I82365SL_DF; 724110841Simp break; 725110841Simp case EXCA_IDENT_REV_IBM1: 726110841Simp case EXCA_IDENT_REV_IBM2: 727110841Simp exca->chipset = EXCA_IBM; 728110841Simp break; 729110841Simp case EXCA_IDENT_REV_IBM_KING: 730110841Simp exca->chipset = EXCA_IBM_KING; 731110841Simp break; 732110841Simp default: 733110841Simp return (0); 734110841Simp } 735110841Simp return (1); 736110841Simp} 737110841Simp 738110841Simp/* 73989948Simp * Probe the expected slots. We maybe should set the ID for each of these 74089948Simp * slots too while we're at it. But maybe that belongs to a separate 74189948Simp * function. 74289948Simp * 743110841Simp * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 74489948Simp */ 74589948Simpint 746110841Simpexca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 747110841Simp bus_space_handle_t ioh) 74889948Simp{ 74989948Simp int err; 75089948Simp int i; 75189948Simp 75289948Simp err = ENXIO; 753110841Simp for (i = 0; i < EXCA_NSLOTS; i++) { 754100703Simp exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 755110841Simp exca->getb = exca_io_getb; 756110841Simp exca->putb = exca_io_putb; 757110841Simp if (exca_valid_slot(&exca[i])) 75889948Simp err = 0; 75989948Simp } 76089948Simp return (err); 76189948Simp} 76289948Simp 763115988Simpvoid 764115988Simpexca_insert(struct exca_softc *exca) 765115988Simp{ 766115988Simp if (exca->pccarddev != NULL) { 767115988Simp if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 768115988Simp device_printf(exca->dev, 769115988Simp "PC Card card activation failed\n"); 770115988Simp } else { 771115988Simp device_printf(exca->dev, 772115988Simp "PC Card inserted, but no pccard bus.\n"); 773115988Simp } 774115988Simp} 775115988Simp 776115988Simp 777115988Simpvoid 778115988Simpexca_removal(struct exca_softc *exca) 779115988Simp{ 780115988Simp if (exca->pccarddev != NULL) 781115988Simp CARD_DETACH_CARD(exca->pccarddev); 782115988Simp} 783115988Simp 784115988Simpint 785115988Simpexca_activate_resource(struct exca_softc *exca, device_t child, int type, 786115988Simp int rid, struct resource *res) 787115988Simp{ 788115988Simp int err; 789115988Simp if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */ 790115988Simp switch (type) { 791115988Simp case SYS_RES_IOPORT: 792119551Simp err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 793115988Simp break; 794115988Simp case SYS_RES_MEMORY: 795119551Simp err = exca_mem_map(exca, PCCARD_A_MEM_COM, res); 796115988Simp break; 797115988Simp default: 798115988Simp err = 0; 799115988Simp break; 800115988Simp } 801115988Simp if (err) 802115988Simp return (err); 803115988Simp 804115988Simp } 805115988Simp return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 806115988Simp type, rid, res)); 807115988Simp} 808115988Simp 809115988Simpint 810115988Simpexca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 811115988Simp int rid, struct resource *res) 812115988Simp{ 813115988Simp if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 814115988Simp switch (type) { 815115988Simp case SYS_RES_IOPORT: 816115988Simp if (exca_io_unmap_res(exca, res)) 817115988Simp return (ENOENT); 818115988Simp break; 819115988Simp case SYS_RES_MEMORY: 820115988Simp if (exca_mem_unmap_res(exca, res)) 821115988Simp return (ENOENT); 822115988Simp break; 823115988Simp } 824115988Simp } 825115988Simp return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 826115988Simp type, rid, res)); 827115988Simp} 828115988Simp 829133782Simp#if 0 830133782Simpstatic struct resource * 831133782Simpexca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 832133782Simp u_long start, u_long end, u_long count, uint flags) 833133782Simp{ 834133782Simp struct resource *res = NULL; 835133782Simp int tmp; 836133782Simp 837133782Simp switch (type) { 838133782Simp case SYS_RES_MEMORY: 839133782Simp if (start < cbb_start_mem) 840133782Simp start = cbb_start_mem; 841133782Simp if (end < start) 842133782Simp end = start; 843133782Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 844133782Simp rman_make_alignment_flags(CBB_MEMALIGN); 845133782Simp break; 846133782Simp case SYS_RES_IOPORT: 847133782Simp if (start < cbb_start_16_io) 848133782Simp start = cbb_start_16_io; 849133782Simp if (end < start) 850133782Simp end = start; 851133782Simp break; 852133782Simp case SYS_RES_IRQ: 853133782Simp tmp = rman_get_start(sc->irq_res); 854133782Simp if (start > tmp || end < tmp || count != 1) { 855133782Simp device_printf(child, "requested interrupt %ld-%ld," 856133782Simp "count = %ld not supported by cbb\n", 857133782Simp start, end, count); 858133782Simp return (NULL); 859133782Simp } 860133782Simp flags |= RF_SHAREABLE; 861133782Simp start = end = rman_get_start(sc->irq_res); 862133782Simp break; 863133782Simp } 864133782Simp res = BUS_ALLOC_RESOURCE(up, child, type, rid, 865133782Simp start, end, count, flags & ~RF_ACTIVE); 866133782Simp if (res == NULL) 867133782Simp return (NULL); 868133782Simp cbb_insert_res(sc, res, type, *rid); 869133782Simp if (flags & RF_ACTIVE) { 870133782Simp if (bus_activate_resource(child, type, *rid, res) != 0) { 871133782Simp bus_release_resource(child, type, *rid, res); 872133782Simp return (NULL); 873133782Simp } 874133782Simp } 875133782Simp 876133782Simp return (res); 877133782Simp} 878133782Simp 879110841Simpstatic int 880133782Simpexca_release_resource(struct exca_softc *sc, device_t child, int type, 881133782Simp int rid, struct resource *res) 882133782Simp{ 883133782Simp int error; 884133782Simp 885133782Simp if (rman_get_flags(res) & RF_ACTIVE) { 886133782Simp error = bus_deactivate_resource(child, type, rid, res); 887133782Simp if (error != 0) 888133782Simp return (error); 889133782Simp } 890133782Simp cbb_remove_res(sc, res); 891133782Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 892133782Simp type, rid, res)); 893133782Simp} 894133782Simp#endif 895133782Simp 896133782Simpstatic int 897110841Simpexca_modevent(module_t mod, int cmd, void *arg) 89889948Simp{ 899110841Simp return 0; 90089948Simp} 90197613Stakawata 90297613StakawataDEV_MODULE(exca, exca_modevent, NULL); 90397613StakawataMODULE_VERSION(exca, 1); 904