exca.c revision 151309
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 151309 2005-10-14 04:48:11Z 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; 184151309Simp int mem8 = (mem->kind == PCCARD_A_MEM_ATTR); 185151309Simp mem8 = 1; 18689948Simp 18789948Simp map = &mem_map_index[win]; 18889948Simp mem = &sc->mem[win]; 189140022Simp offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 190140022Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 191110841Simp exca_putb(sc, map->sysmem_start_lsb, 19289948Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 193110841Simp exca_putb(sc, map->sysmem_start_msb, 19489948Simp ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 195151309Simp EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 196151309Simp (mem8 ? 0 : EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT)); 19789948Simp 198110841Simp exca_putb(sc, map->sysmem_stop_lsb, 19989948Simp ((mem->addr + mem->realsize - 1) >> 20089948Simp EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 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); 20689948Simp 207110841Simp exca_putb(sc, map->sysmem_win, 20889948Simp (mem->addr >> EXCA_MEMREG_WIN_SHIFT) & 0xff); 20989948Simp 210140022Simp exca_putb(sc, map->cardmem_lsb, offset & 0xff); 211140022Simp exca_putb(sc, map->cardmem_msb, (((offset >> 8) & 0xff) & 21289948Simp EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | 213119551Simp ((mem->kind == PCCARD_A_MEM_ATTR) ? 21489948Simp EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); 21589948Simp 216119520Simp#ifdef EXCA_DEBUG 217119551Simp if (mem->kind == PCCARD_A_MEM_ATTR) 218119520Simp printf("attribtue memory\n"); 219119520Simp else 220119520Simp printf("common memory\n"); 221119520Simp#endif 222133782Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable | 223133782Simp EXCA_ADDRWIN_ENABLE_MEMCS16); 22489948Simp 22589948Simp DELAY(100); 22689948Simp#ifdef EXCA_DEBUG 22789948Simp { 22889948Simp int r1, r2, r3, r4, r5, r6, r7; 229110841Simp r1 = exca_getb(sc, map->sysmem_start_msb); 230110841Simp r2 = exca_getb(sc, map->sysmem_start_lsb); 231110841Simp r3 = exca_getb(sc, map->sysmem_stop_msb); 232110841Simp r4 = exca_getb(sc, map->sysmem_stop_lsb); 233110841Simp r5 = exca_getb(sc, map->cardmem_msb); 234110841Simp r6 = exca_getb(sc, map->cardmem_lsb); 235110841Simp r7 = exca_getb(sc, map->sysmem_win); 236133782Simp printf("exca_do_mem_map win %d: %02x%02x %02x%02x " 237133782Simp "%02x%02x %02x (%08x+%06x.%06x*%06x)\n", 23889948Simp win, r1, r2, r3, r4, r5, r6, r7, 23989948Simp mem->addr, mem->size, mem->realsize, 240119520Simp mem->cardaddr); 24189948Simp } 24289948Simp#endif 24389948Simp} 24489948Simp 24589948Simp/* 24689948Simp * public interface to map a resource. kind is the type of memory to 24789948Simp * map (either common or attribute). Memory created via this interface 24889948Simp * starts out at card address 0. Since the only way to set this is 24989948Simp * to set it on a struct resource after it has been mapped, we're safe 25089948Simp * in maping this assumption. Note that resources can be remapped using 25189948Simp * exca_do_mem_map so that's how the card address can be set later. 25289948Simp */ 25389948Simpint 25489948Simpexca_mem_map(struct exca_softc *sc, int kind, struct resource *res) 25589948Simp{ 25689948Simp int win; 25789948Simp 25889948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 25989948Simp if ((sc->memalloc & (1 << win)) == 0) { 26089948Simp sc->memalloc |= (1 << win); 26189948Simp break; 26289948Simp } 26389948Simp } 26489948Simp if (win >= EXCA_MEM_WINS) 26589948Simp return (1); 266120421Simp if (((rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT) & 0xff) != 0 && 267100703Simp (sc->flags & EXCA_HAS_MEMREG_WIN) == 0) { 268100703Simp device_printf(sc->dev, "Does not support mapping above 24M."); 269100703Simp return (1); 270100703Simp } 27189948Simp 27289948Simp sc->mem[win].cardaddr = 0; 27389948Simp sc->mem[win].memt = rman_get_bustag(res); 27489948Simp sc->mem[win].memh = rman_get_bushandle(res); 27589948Simp sc->mem[win].addr = rman_get_start(res); 27689948Simp sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; 27789948Simp sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1; 27889948Simp sc->mem[win].realsize = sc->mem[win].realsize - 27989948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 28089948Simp sc->mem[win].kind = kind; 281119520Simp DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n", 282119520Simp win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr); 28389948Simp exca_do_mem_map(sc, win); 28489948Simp 28589948Simp return (0); 28689948Simp} 28789948Simp 28889948Simp/* 28989948Simp * Private helper function. This turns off a given memory map that is in 29089948Simp * use. We do this by just clearing the enable bit in the pcic. If we needed 29189948Simp * to make memory unmapping/mapping pairs faster, we would have to store 29289948Simp * more state information about the pcic and then use that to intelligently 29389948Simp * to the map/unmap. However, since we don't do that sort of thing often 29489948Simp * (generally just at configure time), it isn't a case worth optimizing. 29589948Simp */ 29689948Simpstatic void 29789948Simpexca_mem_unmap(struct exca_softc *sc, int window) 29889948Simp{ 29989948Simp if (window < 0 || window >= EXCA_MEM_WINS) 30089948Simp panic("exca_mem_unmap: window out of range"); 30189948Simp 30289948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable); 30389948Simp sc->memalloc &= ~(1 << window); 30489948Simp} 30589948Simp 30689948Simp/* 30789948Simp * Find the map that we're using to hold the resoruce. This works well 30889948Simp * so long as the client drivers don't do silly things like map the same 30989948Simp * area mutliple times, or map both common and attribute memory at the 31089948Simp * same time. This latter restriction is a bug. We likely should just 31189948Simp * store a pointer to the res in the mem[x] data structure. 31289948Simp */ 31389948Simpstatic int 31489948Simpexca_mem_findmap(struct exca_softc *sc, struct resource *res) 31589948Simp{ 31689948Simp int win; 31789948Simp 31889948Simp for (win = 0; win < EXCA_MEM_WINS; win++) { 31989948Simp if (sc->mem[win].memt == rman_get_bustag(res) && 32089948Simp sc->mem[win].addr == rman_get_start(res) && 32189948Simp sc->mem[win].size == rman_get_size(res)) 32289948Simp return (win); 32389948Simp } 32489948Simp return (-1); 32589948Simp} 32689948Simp 32789948Simp/* 32889948Simp * Set the memory flag. This means that we are setting if the memory 32989948Simp * is coming from attribute memory or from common memory on the card. 33089948Simp * CIS entries are generally in attribute memory (although they can 33189948Simp * reside in common memory). Generally, this is the only use for attribute 33289948Simp * memory. However, some cards require their drivers to dance in both 33389948Simp * common and/or attribute memory and this interface (and setting the 33489948Simp * offset interface) exist for such cards. 33589948Simp */ 33689948Simpint 33789948Simpexca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags) 33889948Simp{ 33989948Simp int win; 34089948Simp 34189948Simp win = exca_mem_findmap(sc, res); 34289948Simp if (win < 0) { 34389948Simp device_printf(sc->dev, 34489948Simp "set_res_flags: specified resource not active\n"); 34589948Simp return (ENOENT); 34689948Simp } 34789948Simp 34889948Simp sc->mem[win].kind = flags; 34989948Simp exca_do_mem_map(sc, win); 35089948Simp return (0); 35189948Simp} 35289948Simp 35389948Simp/* 35489948Simp * Given a resource, go ahead and unmap it if we can find it in the 35589948Simp * resrouce list that's used. 35689948Simp */ 35789948Simpint 35889948Simpexca_mem_unmap_res(struct exca_softc *sc, struct resource *res) 35989948Simp{ 36089948Simp int win; 36189948Simp 36289948Simp win = exca_mem_findmap(sc, res); 36389948Simp if (win < 0) 36489948Simp return (ENOENT); 36589948Simp exca_mem_unmap(sc, win); 36689948Simp return (0); 36789948Simp} 36889948Simp 36989948Simp/* 37089948Simp * Set the offset of the memory. We use this for reading the CIS and 37189948Simp * frobbing the pccard's pccard registers (POR, etc). Some drivers 37289948Simp * need to access this functionality as well, since they have receive 373119520Simp * buffers defined in the attribute memory. 37489948Simp */ 37589948Simpint 37689948Simpexca_mem_set_offset(struct exca_softc *sc, struct resource *res, 37789948Simp uint32_t cardaddr, uint32_t *deltap) 37889948Simp{ 37989948Simp int win; 38089948Simp uint32_t delta; 38189948Simp 38289948Simp win = exca_mem_findmap(sc, res); 38389948Simp if (win < 0) { 38489948Simp device_printf(sc->dev, 38589948Simp "set_memory_offset: specified resource not active\n"); 38689948Simp return (ENOENT); 38789948Simp } 388119520Simp sc->mem[win].cardaddr = cardaddr & ~(EXCA_MEM_PAGESIZE - 1); 38989948Simp delta = cardaddr % EXCA_MEM_PAGESIZE; 39089948Simp if (deltap) 39189948Simp *deltap = delta; 39289948Simp sc->mem[win].realsize = sc->mem[win].size + delta + 39389948Simp EXCA_MEM_PAGESIZE - 1; 39489948Simp sc->mem[win].realsize = sc->mem[win].realsize - 39589948Simp (sc->mem[win].realsize % EXCA_MEM_PAGESIZE); 39689948Simp exca_do_mem_map(sc, win); 39789948Simp return (0); 39889948Simp} 39989948Simp 40089948Simp 40189948Simp/* I/O */ 40289948Simp 40389948Simp#define EXCA_IOINFO(NUM) { \ 40489948Simp EXCA_IOADDR ## NUM ## _START_LSB, \ 40589948Simp EXCA_IOADDR ## NUM ## _START_MSB, \ 40689948Simp EXCA_IOADDR ## NUM ## _STOP_LSB, \ 40789948Simp EXCA_IOADDR ## NUM ## _STOP_MSB, \ 40897708Salfred EXCA_ADDRWIN_ENABLE_IO ## NUM, \ 40989948Simp EXCA_IOCTL_IO ## NUM ## _WAITSTATE \ 41089948Simp | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT \ 41189948Simp | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ 41289948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ 41389948Simp { \ 41489948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ 41589948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 41689948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ 41789948Simp EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ 41889948Simp | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ 41989948Simp } \ 42089948Simp} 42189948Simp 42289948Simpstatic struct io_map_index_st { 42389948Simp int start_lsb; 42489948Simp int start_msb; 42589948Simp int stop_lsb; 42689948Simp int stop_msb; 42789948Simp int ioenable; 42889948Simp int ioctlmask; 42989948Simp int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ 43089948Simp} io_map_index[] = { 43189948Simp EXCA_IOINFO(0), 43289948Simp EXCA_IOINFO(1), 43389948Simp}; 43489948Simp#undef EXCA_IOINFO 43589948Simp 43689948Simpstatic void 43789948Simpexca_do_io_map(struct exca_softc *sc, int win) 43889948Simp{ 43989948Simp struct io_map_index_st *map; 44089948Simp 44189948Simp struct pccard_io_handle *io; 44289948Simp 44389948Simp map = &io_map_index[win]; 44489948Simp io = &sc->io[win]; 445110841Simp exca_putb(sc, map->start_lsb, io->addr & 0xff); 446110841Simp exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff); 44789948Simp 448110841Simp exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff); 449110841Simp exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff); 45089948Simp 45189948Simp exca_clrb(sc, EXCA_IOCTL, map->ioctlmask); 45289948Simp exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]); 45389948Simp 45489948Simp exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable); 45589948Simp#ifdef EXCA_DEBUG 45689948Simp { 45789948Simp int r1, r2, r3, r4; 458110841Simp r1 = exca_getb(sc, map->start_msb); 459110841Simp r2 = exca_getb(sc, map->start_lsb); 460110841Simp r3 = exca_getb(sc, map->stop_msb); 461110841Simp r4 = exca_getb(sc, map->stop_lsb); 46289948Simp DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x " 46389948Simp "(%08x+%08x)\n", win, r1, r2, r3, r4, 46489948Simp io->addr, io->size); 46589948Simp } 46689948Simp#endif 46789948Simp} 46889948Simp 46989948Simpint 47089948Simpexca_io_map(struct exca_softc *sc, int width, struct resource *r) 47189948Simp{ 47289948Simp int win; 47389948Simp#ifdef EXCA_DEBUG 47489948Simp static char *width_names[] = { "auto", "io8", "io16"}; 47589948Simp#endif 47689948Simp for (win=0; win < EXCA_IO_WINS; win++) { 47789948Simp if ((sc->ioalloc & (1 << win)) == 0) { 47889948Simp sc->ioalloc |= (1 << win); 47989948Simp break; 48089948Simp } 48189948Simp } 48289948Simp if (win >= EXCA_IO_WINS) 48389948Simp return (1); 48489948Simp 48589948Simp sc->io[win].iot = rman_get_bustag(r); 48689948Simp sc->io[win].ioh = rman_get_bushandle(r); 48789948Simp sc->io[win].addr = rman_get_start(r); 48889948Simp sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; 48989948Simp sc->io[win].flags = 0; 49089948Simp sc->io[win].width = width; 49189948Simp DPRINTF("exca_io_map window %d %s port %x+%x\n", 49289948Simp win, width_names[width], sc->io[win].addr, 49389948Simp sc->io[win].size); 49489948Simp exca_do_io_map(sc, win); 49589948Simp 49689948Simp return (0); 49789948Simp} 49889948Simp 49989948Simpstatic void 50089948Simpexca_io_unmap(struct exca_softc *sc, int window) 50189948Simp{ 50289948Simp if (window >= EXCA_IO_WINS) 50389948Simp panic("exca_io_unmap: window out of range"); 50489948Simp 50589948Simp exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable); 50689948Simp 50789948Simp sc->ioalloc &= ~(1 << window); 50889948Simp 50989948Simp sc->io[window].iot = 0; 51089948Simp sc->io[window].ioh = 0; 51189948Simp sc->io[window].addr = 0; 51289948Simp sc->io[window].size = 0; 51389948Simp sc->io[window].flags = 0; 51489948Simp sc->io[window].width = 0; 51589948Simp} 51689948Simp 51789948Simpstatic int 51889948Simpexca_io_findmap(struct exca_softc *sc, struct resource *res) 51989948Simp{ 52089948Simp int win; 52189948Simp 52289948Simp for (win = 0; win < EXCA_IO_WINS; win++) { 52389948Simp if (sc->io[win].iot == rman_get_bustag(res) && 52489948Simp sc->io[win].addr == rman_get_start(res) && 52589948Simp sc->io[win].size == rman_get_size(res)) 52689948Simp return (win); 52789948Simp } 52889948Simp return (-1); 52989948Simp} 53089948Simp 53189948Simp 53289948Simpint 53389948Simpexca_io_unmap_res(struct exca_softc *sc, struct resource *res) 53489948Simp{ 53589948Simp int win; 53689948Simp 53789948Simp win = exca_io_findmap(sc, res); 53889948Simp if (win < 0) 53989948Simp return (ENOENT); 54089948Simp exca_io_unmap(sc, win); 54189948Simp return (0); 54289948Simp} 54389948Simp 54489948Simp/* Misc */ 54589948Simp 54689948Simp/* 54789948Simp * If interrupts are enabled, then we should be able to just wait for 54889948Simp * an interrupt routine to wake us up. Busy waiting shouldn't be 54989948Simp * necessary. Sadly, not all legacy ISA cards support an interrupt 55089948Simp * for the busy state transitions, at least according to their datasheets, 55189948Simp * so we busy wait a while here.. 55289948Simp */ 55389948Simpstatic void 55489948Simpexca_wait_ready(struct exca_softc *sc) 55589948Simp{ 55689948Simp int i; 55789948Simp DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n", 558110841Simp exca_getb(sc, EXCA_IF_STATUS)); 55989948Simp for (i = 0; i < 10000; i++) { 560110841Simp if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY) 56189948Simp return; 56289948Simp DELAY(500); 56389948Simp } 56489948Simp device_printf(sc->dev, "ready never happened, status = %02x\n", 565110841Simp exca_getb(sc, EXCA_IF_STATUS)); 56689948Simp} 56789948Simp 56889948Simp/* 56989948Simp * Reset the card. Ideally, we'd do a lot of this via interrupts. 57089948Simp * However, many PC Cards will deassert the ready signal. This means 57189948Simp * that they are asserting an interrupt. This makes it hard to 57289948Simp * do anything but a busy wait here. One could argue that these 57389948Simp * such cards are broken, or that the bridge that allows this sort 57489948Simp * of interrupt through isn't quite what you'd want (and may be a standards 575150460Simp * violation). However, such arguing would leave a huge class of PC Cards 576104601Simp * and bridges out of reach for use in the system. 577104601Simp * 578104601Simp * Maybe I should reevaluate the above based on the power bug I fixed 579104601Simp * in OLDCARD. 58089948Simp */ 58189948Simpvoid 58289948Simpexca_reset(struct exca_softc *sc, device_t child) 58389948Simp{ 58489948Simp int win; 58589948Simp 58689948Simp /* enable socket i/o */ 58789948Simp exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE); 58889948Simp 589110841Simp exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE); 59089948Simp /* hold reset for 30ms */ 59189948Simp DELAY(30*1000); 59289948Simp /* clear the reset flag */ 59389948Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET); 594150460Simp /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */ 59589948Simp DELAY(20*1000); 59689948Simp 59789948Simp exca_wait_ready(sc); 59889948Simp 59989948Simp /* disable all address windows */ 600110841Simp exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0); 60189948Simp 602120872Simp exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO); 603120872Simp DEVPRINTF(sc->dev, "card type is io\n"); 60489948Simp 60589948Simp /* reinstall all the memory and io mappings */ 60689948Simp for (win = 0; win < EXCA_MEM_WINS; ++win) 60789948Simp if (sc->memalloc & (1 << win)) 60889948Simp exca_do_mem_map(sc, win); 60989948Simp for (win = 0; win < EXCA_IO_WINS; ++win) 61089948Simp if (sc->ioalloc & (1 << win)) 61189948Simp exca_do_io_map(sc, win); 61289948Simp} 61389948Simp 61489948Simp/* 61589948Simp * Initialize the exca_softc data structure for the first time. 61689948Simp */ 61789948Simpvoid 618100703Simpexca_init(struct exca_softc *sc, device_t dev, 619100703Simp bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset) 62089948Simp{ 62189948Simp sc->dev = dev; 62289948Simp sc->memalloc = 0; 62389948Simp sc->ioalloc = 0; 62489948Simp sc->bst = bst; 62589948Simp sc->bsh = bsh; 62689948Simp sc->offset = offset; 62789948Simp sc->flags = 0; 628110841Simp sc->getb = exca_mem_getb; 629110841Simp sc->putb = exca_mem_putb; 63089948Simp} 63189948Simp 63289948Simp/* 633110841Simp * Is this socket valid? 634110841Simp */ 635110841Simpstatic int 636110841Simpexca_valid_slot(struct exca_softc *exca) 637110841Simp{ 638110841Simp uint8_t c; 639110841Simp 640115988Simp /* Assume the worst */ 641115988Simp exca->chipset = EXCA_BOGUS; 642115988Simp 643110841Simp /* 644110841Simp * see if there's a PCMCIA controller here 645110841Simp * Intel PCMCIA controllers use 0x82 and 0x83 646110841Simp * IBM clone chips use 0x88 and 0x89, apparently 647110841Simp */ 648110841Simp c = exca_getb(exca, EXCA_IDENT); 649151309Simp DEVPRINTF(exca->dev, "Ident is %x\n", c); 650110841Simp if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 651110841Simp return (0); 652110841Simp if ((c & EXCA_IDENT_ZERO) != 0) 653110841Simp return (0); 654110841Simp switch (c & EXCA_IDENT_REV_MASK) { 655110841Simp /* 656110841Simp * 82365 or clones. 657110841Simp */ 658110841Simp case EXCA_IDENT_REV_I82365SLR0: 659110841Simp case EXCA_IDENT_REV_I82365SLR1: 660110841Simp exca->chipset = EXCA_I82365; 661110841Simp /* 662110841Simp * Check for Vadem chips by unlocking their extra 663110841Simp * registers and looking for valid ID. Bit 3 in 664110841Simp * the ID register is normally 0, except when 665110841Simp * EXCA_VADEMREV is set. Other bridges appear 666110841Simp * to ignore this frobbing. 667110841Simp */ 668110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 669110841Simp EXCA_VADEM_COOKIE1); 670110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 671110841Simp EXCA_VADEM_COOKIE2); 672110841Simp exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 673110841Simp c = exca_getb(exca, EXCA_IDENT); 674110841Simp if (c & 0x08) { 675110841Simp switch (c & 7) { 676110841Simp case 1: 677110841Simp exca->chipset = EXCA_VG365; 678110841Simp break; 679110841Simp case 2: 680110841Simp exca->chipset = EXCA_VG465; 681110841Simp break; 682110841Simp case 3: 683110841Simp exca->chipset = EXCA_VG468; 684110841Simp break; 685110841Simp default: 686110841Simp exca->chipset = EXCA_VG469; 687110841Simp break; 688110841Simp } 689110841Simp exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 690110841Simp break; 691110841Simp } 692110841Simp /* 693110841Simp * Check for RICOH RF5C[23]96 PCMCIA Controller 694110841Simp */ 695110841Simp c = exca_getb(exca, EXCA_RICOH_ID); 696110841Simp if (c == EXCA_RID_396) { 697110841Simp exca->chipset = EXCA_RF5C396; 698110841Simp break; 699110841Simp } else if (c == EXCA_RID_296) { 700110841Simp exca->chipset = EXCA_RF5C296; 701110841Simp break; 702110841Simp } 703110841Simp /* 704110841Simp * Check for Cirrus logic chips. 705110841Simp */ 706110841Simp exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 707110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 708110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 709110841Simp EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 710110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 711110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 712110841Simp if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 713110841Simp exca->chipset = EXCA_PD6722; 714110841Simp else 715110841Simp exca->chipset = EXCA_PD6710; 716110841Simp break; 717110841Simp } 718110841Simp } 719110841Simp break; 720110841Simp 721110841Simp case EXCA_IDENT_REV_I82365SLDF: 722110841Simp /* 723110841Simp * Intel i82365sl-DF step or maybe a vlsi 82c146 724110841Simp * we detected the vlsi case earlier, so if the controller 725110841Simp * isn't set, we know it is a i82365sl step D. 726110841Simp */ 727110841Simp exca->chipset = EXCA_I82365SL_DF; 728110841Simp break; 729110841Simp case EXCA_IDENT_REV_IBM1: 730110841Simp case EXCA_IDENT_REV_IBM2: 731110841Simp exca->chipset = EXCA_IBM; 732110841Simp break; 733110841Simp case EXCA_IDENT_REV_IBM_KING: 734110841Simp exca->chipset = EXCA_IBM_KING; 735110841Simp break; 736110841Simp default: 737110841Simp return (0); 738110841Simp } 739110841Simp return (1); 740110841Simp} 741110841Simp 742110841Simp/* 74389948Simp * Probe the expected slots. We maybe should set the ID for each of these 74489948Simp * slots too while we're at it. But maybe that belongs to a separate 74589948Simp * function. 74689948Simp * 747110841Simp * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 74889948Simp */ 74989948Simpint 750110841Simpexca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 751110841Simp bus_space_handle_t ioh) 75289948Simp{ 75389948Simp int err; 75489948Simp int i; 75589948Simp 75689948Simp err = ENXIO; 757110841Simp for (i = 0; i < EXCA_NSLOTS; i++) { 758100703Simp exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 759110841Simp exca->getb = exca_io_getb; 760110841Simp exca->putb = exca_io_putb; 761110841Simp if (exca_valid_slot(&exca[i])) 76289948Simp err = 0; 76389948Simp } 76489948Simp return (err); 76589948Simp} 76689948Simp 767115988Simpvoid 768115988Simpexca_insert(struct exca_softc *exca) 769115988Simp{ 770115988Simp if (exca->pccarddev != NULL) { 771115988Simp if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 772115988Simp device_printf(exca->dev, 773115988Simp "PC Card card activation failed\n"); 774115988Simp } else { 775115988Simp device_printf(exca->dev, 776115988Simp "PC Card inserted, but no pccard bus.\n"); 777115988Simp } 778115988Simp} 779115988Simp 780115988Simp 781115988Simpvoid 782115988Simpexca_removal(struct exca_softc *exca) 783115988Simp{ 784115988Simp if (exca->pccarddev != NULL) 785115988Simp CARD_DETACH_CARD(exca->pccarddev); 786115988Simp} 787115988Simp 788115988Simpint 789115988Simpexca_activate_resource(struct exca_softc *exca, device_t child, int type, 790115988Simp int rid, struct resource *res) 791115988Simp{ 792115988Simp int err; 793115988Simp if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */ 794115988Simp switch (type) { 795115988Simp case SYS_RES_IOPORT: 796119551Simp err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 797115988Simp break; 798115988Simp case SYS_RES_MEMORY: 799119551Simp err = exca_mem_map(exca, PCCARD_A_MEM_COM, res); 800115988Simp break; 801115988Simp default: 802115988Simp err = 0; 803115988Simp break; 804115988Simp } 805115988Simp if (err) 806115988Simp return (err); 807115988Simp 808115988Simp } 809115988Simp return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 810115988Simp type, rid, res)); 811115988Simp} 812115988Simp 813115988Simpint 814115988Simpexca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 815115988Simp int rid, struct resource *res) 816115988Simp{ 817115988Simp if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 818115988Simp switch (type) { 819115988Simp case SYS_RES_IOPORT: 820115988Simp if (exca_io_unmap_res(exca, res)) 821115988Simp return (ENOENT); 822115988Simp break; 823115988Simp case SYS_RES_MEMORY: 824115988Simp if (exca_mem_unmap_res(exca, res)) 825115988Simp return (ENOENT); 826115988Simp break; 827115988Simp } 828115988Simp } 829115988Simp return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 830115988Simp type, rid, res)); 831115988Simp} 832115988Simp 833133782Simp#if 0 834133782Simpstatic struct resource * 835133782Simpexca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 836133782Simp u_long start, u_long end, u_long count, uint flags) 837133782Simp{ 838133782Simp struct resource *res = NULL; 839133782Simp int tmp; 840133782Simp 841133782Simp switch (type) { 842133782Simp case SYS_RES_MEMORY: 843133782Simp if (start < cbb_start_mem) 844133782Simp start = cbb_start_mem; 845133782Simp if (end < start) 846133782Simp end = start; 847133782Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 848133782Simp rman_make_alignment_flags(CBB_MEMALIGN); 849133782Simp break; 850133782Simp case SYS_RES_IOPORT: 851133782Simp if (start < cbb_start_16_io) 852133782Simp start = cbb_start_16_io; 853133782Simp if (end < start) 854133782Simp end = start; 855133782Simp break; 856133782Simp case SYS_RES_IRQ: 857133782Simp tmp = rman_get_start(sc->irq_res); 858133782Simp if (start > tmp || end < tmp || count != 1) { 859133782Simp device_printf(child, "requested interrupt %ld-%ld," 860133782Simp "count = %ld not supported by cbb\n", 861133782Simp start, end, count); 862133782Simp return (NULL); 863133782Simp } 864133782Simp flags |= RF_SHAREABLE; 865133782Simp start = end = rman_get_start(sc->irq_res); 866133782Simp break; 867133782Simp } 868133782Simp res = BUS_ALLOC_RESOURCE(up, child, type, rid, 869133782Simp start, end, count, flags & ~RF_ACTIVE); 870133782Simp if (res == NULL) 871133782Simp return (NULL); 872133782Simp cbb_insert_res(sc, res, type, *rid); 873133782Simp if (flags & RF_ACTIVE) { 874133782Simp if (bus_activate_resource(child, type, *rid, res) != 0) { 875133782Simp bus_release_resource(child, type, *rid, res); 876133782Simp return (NULL); 877133782Simp } 878133782Simp } 879133782Simp 880133782Simp return (res); 881133782Simp} 882133782Simp 883110841Simpstatic int 884133782Simpexca_release_resource(struct exca_softc *sc, device_t child, int type, 885133782Simp int rid, struct resource *res) 886133782Simp{ 887133782Simp int error; 888133782Simp 889133782Simp if (rman_get_flags(res) & RF_ACTIVE) { 890133782Simp error = bus_deactivate_resource(child, type, rid, res); 891133782Simp if (error != 0) 892133782Simp return (error); 893133782Simp } 894133782Simp cbb_remove_res(sc, res); 895133782Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 896133782Simp type, rid, res)); 897133782Simp} 898133782Simp#endif 899133782Simp 900133782Simpstatic int 901110841Simpexca_modevent(module_t mod, int cmd, void *arg) 90289948Simp{ 903110841Simp return 0; 90489948Simp} 90597613Stakawata 90697613StakawataDEV_MODULE(exca, exca_modevent, NULL); 90797613StakawataMODULE_VERSION(exca, 1); 908