exca.c revision 166742
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 166742 2007-02-15 07:22:27Z 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 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; 182162591Simp int mem8 = 1 /* mem->kind == PCCARD_A_MEM_ATTR */; 18389948Simp 18489948Simp map = &mem_map_index[win]; 18589948Simp mem = &sc->mem[win]; 186140022Simp offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) - 187140022Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff; 188110841Simp exca_putb(sc, map->sysmem_start_lsb, 18989948Simp (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT) & 0xff); 190110841Simp exca_putb(sc, map->sysmem_start_msb, 19189948Simp ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) & 192151309Simp EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | 193151309Simp (mem8 ? 0 : EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT)); 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 368151410Simp * frobbing the pccard's pccard registers (CCR, etc). Some drivers 369151410Simp * need to access arbitrary attribute and common memory during their 370151410Simp * initialization and operation. 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); 646151309Simp DEVPRINTF(exca->dev, "Ident is %x\n", c); 647110841Simp if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO) 648110841Simp return (0); 649110841Simp if ((c & EXCA_IDENT_ZERO) != 0) 650110841Simp return (0); 651110841Simp switch (c & EXCA_IDENT_REV_MASK) { 652110841Simp /* 653110841Simp * 82365 or clones. 654110841Simp */ 655110841Simp case EXCA_IDENT_REV_I82365SLR0: 656110841Simp case EXCA_IDENT_REV_I82365SLR1: 657110841Simp exca->chipset = EXCA_I82365; 658110841Simp /* 659110841Simp * Check for Vadem chips by unlocking their extra 660110841Simp * registers and looking for valid ID. Bit 3 in 661110841Simp * the ID register is normally 0, except when 662110841Simp * EXCA_VADEMREV is set. Other bridges appear 663110841Simp * to ignore this frobbing. 664110841Simp */ 665110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 666110841Simp EXCA_VADEM_COOKIE1); 667110841Simp bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX, 668110841Simp EXCA_VADEM_COOKIE2); 669110841Simp exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 670110841Simp c = exca_getb(exca, EXCA_IDENT); 671110841Simp if (c & 0x08) { 672110841Simp switch (c & 7) { 673110841Simp case 1: 674110841Simp exca->chipset = EXCA_VG365; 675110841Simp break; 676110841Simp case 2: 677110841Simp exca->chipset = EXCA_VG465; 678110841Simp break; 679110841Simp case 3: 680110841Simp exca->chipset = EXCA_VG468; 681110841Simp break; 682110841Simp default: 683110841Simp exca->chipset = EXCA_VG469; 684110841Simp break; 685110841Simp } 686110841Simp exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV); 687110841Simp break; 688110841Simp } 689110841Simp /* 690110841Simp * Check for RICOH RF5C[23]96 PCMCIA Controller 691110841Simp */ 692110841Simp c = exca_getb(exca, EXCA_RICOH_ID); 693110841Simp if (c == EXCA_RID_396) { 694110841Simp exca->chipset = EXCA_RF5C396; 695110841Simp break; 696110841Simp } else if (c == EXCA_RID_296) { 697110841Simp exca->chipset = EXCA_RF5C296; 698110841Simp break; 699110841Simp } 700110841Simp /* 701110841Simp * Check for Cirrus logic chips. 702110841Simp */ 703110841Simp exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0); 704110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 705110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 706110841Simp EXCA_CIRRUS_CHIP_INFO_CHIP_ID) { 707110841Simp c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO); 708110841Simp if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) { 709110841Simp if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS) 710110841Simp exca->chipset = EXCA_PD6722; 711110841Simp else 712110841Simp exca->chipset = EXCA_PD6710; 713110841Simp break; 714110841Simp } 715110841Simp } 716110841Simp break; 717110841Simp 718110841Simp case EXCA_IDENT_REV_I82365SLDF: 719110841Simp /* 720110841Simp * Intel i82365sl-DF step or maybe a vlsi 82c146 721110841Simp * we detected the vlsi case earlier, so if the controller 722110841Simp * isn't set, we know it is a i82365sl step D. 723110841Simp */ 724110841Simp exca->chipset = EXCA_I82365SL_DF; 725110841Simp break; 726110841Simp case EXCA_IDENT_REV_IBM1: 727110841Simp case EXCA_IDENT_REV_IBM2: 728110841Simp exca->chipset = EXCA_IBM; 729110841Simp break; 730110841Simp case EXCA_IDENT_REV_IBM_KING: 731110841Simp exca->chipset = EXCA_IBM_KING; 732110841Simp break; 733110841Simp default: 734110841Simp return (0); 735110841Simp } 736110841Simp return (1); 737110841Simp} 738110841Simp 739110841Simp/* 74089948Simp * Probe the expected slots. We maybe should set the ID for each of these 74189948Simp * slots too while we're at it. But maybe that belongs to a separate 74289948Simp * function. 74389948Simp * 744110841Simp * The caller must guarantee that at least EXCA_NSLOTS are present in exca. 74589948Simp */ 74689948Simpint 747110841Simpexca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot, 748110841Simp bus_space_handle_t ioh) 74989948Simp{ 75089948Simp int err; 75189948Simp int i; 75289948Simp 75389948Simp err = ENXIO; 754110841Simp for (i = 0; i < EXCA_NSLOTS; i++) { 755100703Simp exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE); 756110841Simp exca->getb = exca_io_getb; 757110841Simp exca->putb = exca_io_putb; 758151458Simp if (exca_valid_slot(&exca[i])) { 759151458Simp device_set_desc(dev, chip_names[exca[i].chipset]); 76089948Simp err = 0; 761151458Simp } 76289948Simp } 76389948Simp return (err); 76489948Simp} 76589948Simp 766115988Simpvoid 767115988Simpexca_insert(struct exca_softc *exca) 768115988Simp{ 769115988Simp if (exca->pccarddev != NULL) { 770115988Simp if (CARD_ATTACH_CARD(exca->pccarddev) != 0) 771115988Simp device_printf(exca->dev, 772115988Simp "PC Card card activation failed\n"); 773115988Simp } else { 774115988Simp device_printf(exca->dev, 775115988Simp "PC Card inserted, but no pccard bus.\n"); 776115988Simp } 777115988Simp} 778115988Simp 779115988Simp 780115988Simpvoid 781115988Simpexca_removal(struct exca_softc *exca) 782115988Simp{ 783166742Simp if (device_is_attached(exca->pccarddev)) 784115988Simp CARD_DETACH_CARD(exca->pccarddev); 785115988Simp} 786115988Simp 787115988Simpint 788115988Simpexca_activate_resource(struct exca_softc *exca, device_t child, int type, 789115988Simp int rid, struct resource *res) 790115988Simp{ 791115988Simp int err; 792115988Simp if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */ 793115988Simp switch (type) { 794115988Simp case SYS_RES_IOPORT: 795119551Simp err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res); 796115988Simp break; 797115988Simp case SYS_RES_MEMORY: 798119551Simp err = exca_mem_map(exca, PCCARD_A_MEM_COM, res); 799115988Simp break; 800115988Simp default: 801115988Simp err = 0; 802115988Simp break; 803115988Simp } 804115988Simp if (err) 805115988Simp return (err); 806115988Simp 807115988Simp } 808115988Simp return (BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 809115988Simp type, rid, res)); 810115988Simp} 811115988Simp 812115988Simpint 813115988Simpexca_deactivate_resource(struct exca_softc *exca, device_t child, int type, 814115988Simp int rid, struct resource *res) 815115988Simp{ 816115988Simp if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ 817115988Simp switch (type) { 818115988Simp case SYS_RES_IOPORT: 819115988Simp if (exca_io_unmap_res(exca, res)) 820115988Simp return (ENOENT); 821115988Simp break; 822115988Simp case SYS_RES_MEMORY: 823115988Simp if (exca_mem_unmap_res(exca, res)) 824115988Simp return (ENOENT); 825115988Simp break; 826115988Simp } 827115988Simp } 828115988Simp return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child, 829115988Simp type, rid, res)); 830115988Simp} 831115988Simp 832133782Simp#if 0 833133782Simpstatic struct resource * 834133782Simpexca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid, 835133782Simp u_long start, u_long end, u_long count, uint flags) 836133782Simp{ 837133782Simp struct resource *res = NULL; 838133782Simp int tmp; 839133782Simp 840133782Simp switch (type) { 841133782Simp case SYS_RES_MEMORY: 842133782Simp if (start < cbb_start_mem) 843133782Simp start = cbb_start_mem; 844133782Simp if (end < start) 845133782Simp end = start; 846133782Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 847133782Simp rman_make_alignment_flags(CBB_MEMALIGN); 848133782Simp break; 849133782Simp case SYS_RES_IOPORT: 850133782Simp if (start < cbb_start_16_io) 851133782Simp start = cbb_start_16_io; 852133782Simp if (end < start) 853133782Simp end = start; 854133782Simp break; 855133782Simp case SYS_RES_IRQ: 856133782Simp tmp = rman_get_start(sc->irq_res); 857133782Simp if (start > tmp || end < tmp || count != 1) { 858133782Simp device_printf(child, "requested interrupt %ld-%ld," 859133782Simp "count = %ld not supported by cbb\n", 860133782Simp start, end, count); 861133782Simp return (NULL); 862133782Simp } 863133782Simp flags |= RF_SHAREABLE; 864133782Simp start = end = rman_get_start(sc->irq_res); 865133782Simp break; 866133782Simp } 867133782Simp res = BUS_ALLOC_RESOURCE(up, child, type, rid, 868133782Simp start, end, count, flags & ~RF_ACTIVE); 869133782Simp if (res == NULL) 870133782Simp return (NULL); 871133782Simp cbb_insert_res(sc, res, type, *rid); 872133782Simp if (flags & RF_ACTIVE) { 873133782Simp if (bus_activate_resource(child, type, *rid, res) != 0) { 874133782Simp bus_release_resource(child, type, *rid, res); 875133782Simp return (NULL); 876133782Simp } 877133782Simp } 878133782Simp 879133782Simp return (res); 880133782Simp} 881133782Simp 882110841Simpstatic int 883133782Simpexca_release_resource(struct exca_softc *sc, device_t child, int type, 884133782Simp int rid, struct resource *res) 885133782Simp{ 886133782Simp int error; 887133782Simp 888133782Simp if (rman_get_flags(res) & RF_ACTIVE) { 889133782Simp error = bus_deactivate_resource(child, type, rid, res); 890133782Simp if (error != 0) 891133782Simp return (error); 892133782Simp } 893133782Simp cbb_remove_res(sc, res); 894133782Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 895133782Simp type, rid, res)); 896133782Simp} 897133782Simp#endif 898133782Simp 899133782Simpstatic int 900110841Simpexca_modevent(module_t mod, int cmd, void *arg) 90189948Simp{ 902110841Simp return 0; 90389948Simp} 90497613Stakawata 90597613StakawataDEV_MODULE(exca, exca_modevent, NULL); 90697613StakawataMODULE_VERSION(exca, 1); 907