1139749Simp/*- 2124137Simp * Copyright (c) 2002-2004 M. Warner Losh. 3124137Simp * Copyright (c) 2000-2001 Jonathan Chen. 467276Sjon * All rights reserved. 567276Sjon * 667276Sjon * Redistribution and use in source and binary forms, with or without 767276Sjon * modification, are permitted provided that the following conditions 867276Sjon * are met: 967276Sjon * 1. Redistributions of source code must retain the above copyright 10140197Simp * notice, this list of conditions and the following disclaimer. 1167276Sjon * 2. Redistributions in binary form must reproduce the above copyright 12140197Simp * notice, this list of conditions and the following disclaimer in the 13140197Simp * documentation and/or other materials provided with the distribution. 1467276Sjon * 1567276Sjon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667276Sjon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767276Sjon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18140197Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19140197Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067276Sjon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167276Sjon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267276Sjon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367276Sjon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467276Sjon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567276Sjon * SUCH DAMAGE. 26140197Simp * 2767276Sjon */ 2867276Sjon 29140036Simp/*- 3094570Simp * Copyright (c) 1998, 1999 and 2000 3194570Simp * HAYAKAWA Koichi. All rights reserved. 3294570Simp * 3394570Simp * Redistribution and use in source and binary forms, with or without 3494570Simp * modification, are permitted provided that the following conditions 3594570Simp * are met: 3694570Simp * 1. Redistributions of source code must retain the above copyright 3794570Simp * notice, this list of conditions and the following disclaimer. 3894570Simp * 2. Redistributions in binary form must reproduce the above copyright 3994570Simp * notice, this list of conditions and the following disclaimer in the 4094570Simp * documentation and/or other materials provided with the distribution. 4194570Simp * 3. All advertising materials mentioning features or use of this software 4294570Simp * must display the following acknowledgement: 4394570Simp * This product includes software developed by HAYAKAWA Koichi. 4494570Simp * 4. The name of the author may not be used to endorse or promote products 4594570Simp * derived from this software without specific prior written permission. 4694570Simp * 4794570Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4894570Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4994570Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 5094570Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5194570Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5294570Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5394570Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5494570Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5594570Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5694570Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5794570Simp */ 5894570Simp 5994570Simp/* 60104830Simp * Driver for PCI to CardBus Bridge chips 61133553Simp * and PCI to PCMCIA Bridge chips 62133553Simp * and ISA to PCMCIA host adapters 63133553Simp * and C Bus to PCMCIA host adapters 6467276Sjon * 6567276Sjon * References: 6667276Sjon * TI Datasheets: 6767276Sjon * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS 6867276Sjon * 6967276Sjon * Written by Jonathan Chen <jon@freebsd.org> 7067276Sjon * The author would like to acknowledge: 7167276Sjon * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing 7267276Sjon * * Warner Losh: Newbus/newcard guru and author of the pccard side of things 7367276Sjon * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver 7467276Sjon * * David Cross: Author of the initial ugly hack for a specific cardbus card 7567276Sjon */ 7667276Sjon 77122534Simp#include <sys/cdefs.h> 78122534Simp__FBSDID("$FreeBSD$"); 79122534Simp 8067276Sjon#include <sys/param.h> 81133553Simp#include <sys/bus.h> 8298156Simp#include <sys/condvar.h> 8367276Sjon#include <sys/errno.h> 8467276Sjon#include <sys/kernel.h> 85129876Sphk#include <sys/module.h> 86133553Simp#include <sys/kthread.h> 87170163Spiso#include <sys/interrupt.h> 8875021Sjesper#include <sys/lock.h> 8967276Sjon#include <sys/malloc.h> 9069288Sjon#include <sys/mutex.h> 91133553Simp#include <sys/proc.h> 92133553Simp#include <sys/rman.h> 9386908Simp#include <sys/sysctl.h> 94133553Simp#include <sys/systm.h> 9567276Sjon#include <machine/bus.h> 9667276Sjon#include <machine/resource.h> 9767276Sjon 98119285Simp#include <dev/pci/pcireg.h> 99119285Simp#include <dev/pci/pcivar.h> 10067276Sjon 10167276Sjon#include <dev/pccard/pccardreg.h> 10267276Sjon#include <dev/pccard/pccardvar.h> 10367276Sjon 10489949Simp#include <dev/exca/excareg.h> 10589949Simp#include <dev/exca/excavar.h> 10689949Simp 10767276Sjon#include <dev/pccbb/pccbbreg.h> 10867276Sjon#include <dev/pccbb/pccbbvar.h> 10967276Sjon 11067276Sjon#include "power_if.h" 11167276Sjon#include "card_if.h" 11267276Sjon#include "pcib_if.h" 11367276Sjon 11490751Simp#define DPRINTF(x) do { if (cbb_debug) printf x; } while (0) 11590751Simp#define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0) 11667276Sjon 11782378Sjon#define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \ 11867276Sjon pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE) 11967276Sjon#define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \ 12067276Sjon pci_write_config(DEV, REG, ( \ 12167276Sjon pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE) 12267276Sjon 123119165Simp#define CBB_CARD_PRESENT(s) ((s & CBB_STATE_CD) == 0) 124119165Simp 125101904Simp#define CBB_START_MEM 0x88000000 126101904Simp#define CBB_START_32_IO 0x1000 127101904Simp#define CBB_START_16_IO 0x100 12886899Simp 129133553Simpdevclass_t cbb_devclass; 13067276Sjon 13186908Simp/* sysctl vars */ 132227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cbb, CTLFLAG_RD, 0, "CBB parameters"); 13386908Simp 13486908Simp/* There's no way to say TUNEABLE_LONG to get the right types */ 135101904Simpu_long cbb_start_mem = CBB_START_MEM; 136155316SimpTUNABLE_ULONG("hw.cbb.start_memory", &cbb_start_mem); 13795709SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_memory, CTLFLAG_RW, 138101904Simp &cbb_start_mem, CBB_START_MEM, 13986908Simp "Starting address for memory allocations"); 14086908Simp 141101904Simpu_long cbb_start_16_io = CBB_START_16_IO; 142155316SimpTUNABLE_ULONG("hw.cbb.start_16_io", &cbb_start_16_io); 14395708SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_16_io, CTLFLAG_RW, 144101904Simp &cbb_start_16_io, CBB_START_16_IO, 14590751Simp "Starting ioport for 16-bit cards"); 14690751Simp 147101904Simpu_long cbb_start_32_io = CBB_START_32_IO; 148155316SimpTUNABLE_ULONG("hw.cbb.start_32_io", &cbb_start_32_io); 14995708SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_32_io, CTLFLAG_RW, 150101904Simp &cbb_start_32_io, CBB_START_32_IO, 15190751Simp "Starting ioport for 32-bit cards"); 15290751Simp 15390751Simpint cbb_debug = 0; 15490751SimpTUNABLE_INT("hw.cbb.debug", &cbb_debug); 155217323SmdfSYSCTL_INT(_hw_cbb, OID_AUTO, debug, CTLFLAG_RW, &cbb_debug, 0, 15690751Simp "Verbose cardbus bridge debugging"); 15790751Simp 158101904Simpstatic void cbb_insert(struct cbb_softc *sc); 159101904Simpstatic void cbb_removal(struct cbb_softc *sc); 160148013Simpstatic uint32_t cbb_detect_voltage(device_t brdev); 161189723Simpstatic void cbb_cardbus_reset_power(device_t brdev, device_t child, int on); 162101904Simpstatic int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start, 16389326Simp uint32_t end); 164101904Simpstatic int cbb_cardbus_mem_open(device_t brdev, int win, 16589326Simp uint32_t start, uint32_t end); 166101904Simpstatic void cbb_cardbus_auto_open(struct cbb_softc *sc, int type); 167101904Simpstatic int cbb_cardbus_activate_resource(device_t brdev, device_t child, 16882378Sjon int type, int rid, struct resource *res); 169101904Simpstatic int cbb_cardbus_deactivate_resource(device_t brdev, 17082378Sjon device_t child, int type, int rid, struct resource *res); 171101904Simpstatic struct resource *cbb_cardbus_alloc_resource(device_t brdev, 17282375Sjon device_t child, int type, int *rid, u_long start, 173118607Sjhb u_long end, u_long count, u_int flags); 174101904Simpstatic int cbb_cardbus_release_resource(device_t brdev, device_t child, 17582378Sjon int type, int rid, struct resource *res); 176133553Simpstatic int cbb_cardbus_power_enable_socket(device_t brdev, 177133553Simp device_t child); 178188129Simpstatic int cbb_cardbus_power_disable_socket(device_t brdev, 179133553Simp device_t child); 180170163Spisostatic int cbb_func_filt(void *arg); 181133553Simpstatic void cbb_func_intr(void *arg); 18267276Sjon 18389949Simpstatic void 184101904Simpcbb_remove_res(struct cbb_softc *sc, struct resource *res) 18589949Simp{ 186101904Simp struct cbb_reslist *rle; 18789949Simp 18889949Simp SLIST_FOREACH(rle, &sc->rl, link) { 18989949Simp if (rle->res == res) { 190101904Simp SLIST_REMOVE(&sc->rl, rle, cbb_reslist, link); 19189949Simp free(rle, M_DEVBUF); 19289949Simp return; 19389949Simp } 19489949Simp } 19589949Simp} 19689949Simp 19789949Simpstatic struct resource * 198101904Simpcbb_find_res(struct cbb_softc *sc, int type, int rid) 19989949Simp{ 200101904Simp struct cbb_reslist *rle; 20189949Simp 20289949Simp SLIST_FOREACH(rle, &sc->rl, link) 20389949Simp if (SYS_RES_MEMORY == rle->type && rid == rle->rid) 20489949Simp return (rle->res); 20589949Simp return (NULL); 20689949Simp} 20789949Simp 20889949Simpstatic void 209101904Simpcbb_insert_res(struct cbb_softc *sc, struct resource *res, int type, 21089949Simp int rid) 21189949Simp{ 212101904Simp struct cbb_reslist *rle; 21389949Simp 21489949Simp /* 21589949Simp * Need to record allocated resource so we can iterate through 21689949Simp * it later. 21789949Simp */ 218101904Simp rle = malloc(sizeof(struct cbb_reslist), M_DEVBUF, M_NOWAIT); 219122534Simp if (rle == NULL) 220101904Simp panic("cbb_cardbus_alloc_resource: can't record entry!"); 22189949Simp rle->res = res; 22289949Simp rle->type = type; 22389949Simp rle->rid = rid; 22489949Simp SLIST_INSERT_HEAD(&sc->rl, rle, link); 22589949Simp} 22689949Simp 22789949Simpstatic void 228101904Simpcbb_destroy_res(struct cbb_softc *sc) 22989949Simp{ 230101904Simp struct cbb_reslist *rle; 23189949Simp 23289949Simp while ((rle = SLIST_FIRST(&sc->rl)) != NULL) { 23390751Simp device_printf(sc->dev, "Danger Will Robinson: Resource " 23489949Simp "left allocated! This is a bug... " 23589949Simp "(rid=%x, type=%d, addr=%lx)\n", rle->rid, rle->type, 23689949Simp rman_get_start(rle->res)); 23789949Simp SLIST_REMOVE_HEAD(&sc->rl, link); 23889949Simp free(rle, M_DEVBUF); 23989949Simp } 24089949Simp} 24189949Simp 242118713Simp/* 243118713Simp * Disable function interrupts by telling the bridge to generate IRQ1 244118713Simp * interrupts. These interrupts aren't really generated by the chip, since 245118713Simp * IRQ1 is reserved. Some chipsets assert INTA# inappropriately during 246118713Simp * initialization, so this helps to work around the problem. 247122263Simp * 248122263Simp * XXX We can't do this workaround for all chipsets, because this 249122263Simp * XXX causes interference with the keyboard because somechipsets will 250122263Simp * XXX actually signal IRQ1 over their serial interrupt connections to 251122263Simp * XXX the south bridge. Disable it it for now. 252118713Simp */ 253133553Simpvoid 254118713Simpcbb_disable_func_intr(struct cbb_softc *sc) 255118713Simp{ 256122291Simp#if 0 257118713Simp uint8_t reg; 258118713Simp 259133553Simp reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | 260118713Simp EXCA_INTR_IRQ_RESERVED1; 261133553Simp exca_putb(&sc->exca[0], EXCA_INTR, reg); 262122263Simp#endif 263118713Simp} 264118713Simp 265118713Simp/* 266118713Simp * Enable function interrupts. We turn on function interrupts when the card 267118713Simp * requests an interrupt. The PCMCIA standard says that we should set 268118713Simp * the lower 4 bits to 0 to route via PCI. Note: we call this for both 269118713Simp * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus 270118713Simp * cards. 271118713Simp */ 272118713Simpstatic void 273118713Simpcbb_enable_func_intr(struct cbb_softc *sc) 274118713Simp{ 275118713Simp uint8_t reg; 276118713Simp 277133553Simp reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | 278118713Simp EXCA_INTR_IRQ_NONE; 279133553Simp exca_putb(&sc->exca[0], EXCA_INTR, reg); 280118713Simp} 281118713Simp 282133553Simpint 283101904Simpcbb_detach(device_t brdev) 28469288Sjon{ 285101904Simp struct cbb_softc *sc = device_get_softc(brdev); 28669288Sjon device_t *devlist; 287166741Simp int tmp, tries, error, numdevs; 28869288Sjon 289155434Simp /* 290155434Simp * Before we delete the children (which we have to do because 291155434Simp * attach doesn't check for children busses correctly), we have 292155434Simp * to detach the children. Even if we didn't need to delete the 293155434Simp * children, we have to detach them. 294155434Simp */ 295155434Simp error = bus_generic_detach(brdev); 296155434Simp if (error != 0) 297155434Simp return (error); 298155434Simp 299155434Simp /* 300155434Simp * Since the attach routine doesn't search for children before it 301155434Simp * attaches them to this device, we must delete them here in order 302155434Simp * for the kldload/unload case to work. If we failed to do that, then 303155434Simp * we'd get duplicate devices when cbb.ko was reloaded. 304155434Simp */ 305166741Simp tries = 10; 306166741Simp do { 307166741Simp error = device_get_children(brdev, &devlist, &numdevs); 308166741Simp if (error == 0) 309166741Simp break; 310166741Simp /* 311166741Simp * Try hard to cope with low memory. 312166741Simp */ 313166741Simp if (error == ENOMEM) { 314167087Sjhb pause("cbbnomem", 1); 315166741Simp continue; 316166741Simp } 317166741Simp } while (tries-- > 0); 318155434Simp for (tmp = 0; tmp < numdevs; tmp++) 319155434Simp device_delete_child(brdev, devlist[tmp]); 32072189Simp free(devlist, M_TEMP); 32169288Sjon 322151837Simp /* Turn off the interrupts */ 323151837Simp cbb_set(sc, CBB_SOCKET_MASK, 0); 324151837Simp 325151837Simp /* reset 16-bit pcmcia bus */ 326151837Simp exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET); 327151837Simp 328151837Simp /* turn off power */ 329151837Simp cbb_power(brdev, CARD_OFF); 330151837Simp 331151837Simp /* Ack the interrupt */ 332151837Simp cbb_set(sc, CBB_SOCKET_EVENT, 0xffffffff); 333151837Simp 334151078Simp /* 335172836Sjulian * Wait for the thread to die. kproc_exit will do a wakeup 336151078Simp * on the event thread's struct thread * so that we know it is 337169618Simp * safe to proceed. IF the thread is running, set the please 338151078Simp * die flag and wait for it to comply. Since the wakeup on 339172836Sjulian * the event thread happens only in kproc_exit, we don't 340151078Simp * need to loop here. 341151078Simp */ 342169618Simp bus_teardown_intr(brdev, sc->irq_res, sc->intrhand); 343151837Simp mtx_lock(&sc->mtx); 344101904Simp sc->flags |= CBB_KTHREAD_DONE; 345158891Simp while (sc->flags & CBB_KTHREAD_RUNNING) { 346158891Simp DEVPRINTF((sc->dev, "Waiting for thread to die\n")); 347185625Simp wakeup(&sc->intrhand); 348104651Simp msleep(sc->event_thread, &sc->mtx, PWAIT, "cbbun", 0); 34986904Simp } 350104651Simp mtx_unlock(&sc->mtx); 35169288Sjon 35290751Simp bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); 353129531Simp bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, 354129531Simp sc->base_res); 35590751Simp mtx_destroy(&sc->mtx); 35686904Simp return (0); 35769288Sjon} 35869288Sjon 359133553Simpint 360101904Simpcbb_setup_intr(device_t dev, device_t child, struct resource *irq, 361166901Spiso int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 362166901Spiso void **cookiep) 36390444Simp{ 364104642Simp struct cbb_intrhand *ih; 365104642Simp struct cbb_softc *sc = device_get_softc(dev); 366133553Simp int err; 36790444Simp 368170163Spiso if (filt == NULL && intr == NULL) 369170163Spiso return (EINVAL); 370104642Simp ih = malloc(sizeof(struct cbb_intrhand), M_DEVBUF, M_NOWAIT); 371104642Simp if (ih == NULL) 372104642Simp return (ENOMEM); 373104642Simp *cookiep = ih; 374170163Spiso ih->filt = filt; 375104642Simp ih->intr = intr; 376104642Simp ih->arg = arg; 377133553Simp ih->sc = sc; 37890444Simp /* 37990444Simp * XXX need to turn on ISA interrupts, if we ever support them, but 38090444Simp * XXX for now that's all we need to do. 38190444Simp */ 382133553Simp err = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, 383170270Simp filt ? cbb_func_filt : NULL, intr ? cbb_func_intr : NULL, ih, 384170270Simp &ih->cookie); 385133553Simp if (err != 0) { 386133553Simp free(ih, M_DEVBUF); 387133553Simp return (err); 388133553Simp } 389133553Simp cbb_enable_func_intr(sc); 390170272Simp sc->cardok = 1; 391133553Simp return 0; 39290444Simp} 39390444Simp 394133553Simpint 395101904Simpcbb_teardown_intr(device_t dev, device_t child, struct resource *irq, 39690444Simp void *cookie) 39790444Simp{ 398104642Simp struct cbb_intrhand *ih; 399133553Simp int err; 400104642Simp 40190444Simp /* XXX Need to do different things for ISA interrupts. */ 402104642Simp ih = (struct cbb_intrhand *) cookie; 403133553Simp err = BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, 404133553Simp ih->cookie); 405133553Simp if (err != 0) 406133553Simp return (err); 407104642Simp free(ih, M_DEVBUF); 408104642Simp return (0); 40990444Simp} 41090444Simp 41190444Simp 412133553Simpvoid 413101904Simpcbb_driver_added(device_t brdev, driver_t *driver) 41469288Sjon{ 415101904Simp struct cbb_softc *sc = device_get_softc(brdev); 41669288Sjon device_t *devlist; 417113239Simp device_t dev; 41869288Sjon int tmp; 41969288Sjon int numdevs; 420113239Simp int wake = 0; 42170715Sjon 42282375Sjon DEVICE_IDENTIFY(driver, brdev); 423166741Simp tmp = device_get_children(brdev, &devlist, &numdevs); 424166741Simp if (tmp != 0) { 425166741Simp device_printf(brdev, "Cannot get children list, no reprobe\n"); 426166741Simp return; 427166741Simp } 42869288Sjon for (tmp = 0; tmp < numdevs; tmp++) { 429113239Simp dev = devlist[tmp]; 430113239Simp if (device_get_state(dev) == DS_NOTPRESENT && 431166742Simp device_probe_and_attach(dev) == 0) 432113239Simp wake++; 43369288Sjon } 43472189Simp free(devlist, M_TEMP); 43582378Sjon 436185625Simp if (wake > 0) 437185625Simp wakeup(&sc->intrhand); 43869288Sjon} 43969288Sjon 440133553Simpvoid 441101904Simpcbb_child_detached(device_t brdev, device_t child) 44269288Sjon{ 443101904Simp struct cbb_softc *sc = device_get_softc(brdev); 44486904Simp 445166742Simp /* I'm not sure we even need this */ 446166742Simp if (child != sc->cbdev && child != sc->exca[0].pccarddev) 447113239Simp device_printf(brdev, "Unknown child detached: %s\n", 448113239Simp device_get_nameunit(child)); 44969288Sjon} 45069288Sjon 45167276Sjon/************************************************************************/ 45267276Sjon/* Kthreads */ 45367276Sjon/************************************************************************/ 45467276Sjon 455133553Simpvoid 456101904Simpcbb_event_thread(void *arg) 45767276Sjon{ 458101904Simp struct cbb_softc *sc = arg; 45989326Simp uint32_t status; 46090751Simp int err; 461118706Simp int not_a_card = 0; 46267276Sjon 463230626Simp /* 464230626Simp * We need to act as a power sequencer on startup. Delay 2s/channel 465230626Simp * to ensure the other channels have had a chance to come up. We likely 466230626Simp * should add a lock that's shared on a per-slot basis so that only 467230626Simp * one power event can happen per slot at a time. 468230626Simp */ 469230626Simp pause("cbbstart", hz * device_get_unit(sc->dev) * 2); 470158891Simp mtx_lock(&sc->mtx); 471101904Simp sc->flags |= CBB_KTHREAD_RUNNING; 472116232Simp while ((sc->flags & CBB_KTHREAD_DONE) == 0) { 473169618Simp mtx_unlock(&sc->mtx); 474196403Sjhb /* 475196403Sjhb * We take out Giant here because we need it deep, 476196403Sjhb * down in the bowels of the vm system for mapping the 477196403Sjhb * memory we need to read the CIS. In addition, since 478196403Sjhb * we are adding/deleting devices from the dev tree, 479196403Sjhb * and that code isn't MP safe, we have to hold Giant. 480196403Sjhb */ 481196403Sjhb mtx_lock(&Giant); 482101904Simp status = cbb_get(sc, CBB_SOCKET_STATE); 483153945Simp DPRINTF(("Status is 0x%x\n", status)); 484119165Simp if (!CBB_CARD_PRESENT(status)) { 485118713Simp not_a_card = 0; /* We know card type */ 486118713Simp cbb_removal(sc); 487118713Simp } else if (status & CBB_STATE_NOT_A_CARD) { 488118706Simp /* 489167208Simp * Up to 10 times, try to rescan the card when we see 490167208Simp * NOT_A_CARD. 10 is somehwat arbitrary. When this 491167208Simp * pathology hits, there's a ~40% chance each try will 492167208Simp * fail. 10 tries takes about 5s and results in a 493167208Simp * 99.99% certainty of the results. 494118706Simp */ 495167208Simp if (not_a_card++ < 10) { 496118706Simp DEVPRINTF((sc->dev, 497118706Simp "Not a card bit set, rescanning\n")); 498118706Simp cbb_setb(sc, CBB_SOCKET_FORCE, CBB_FORCE_CV_TEST); 499118706Simp } else { 500118706Simp device_printf(sc->dev, 501118706Simp "Can't determine card type\n"); 502118706Simp } 503118706Simp } else { 504118706Simp not_a_card = 0; /* We know card type */ 505118713Simp cbb_insert(sc); 506118706Simp } 507196403Sjhb mtx_unlock(&Giant); 508104651Simp 50990981Simp /* 510188701Simp * First time through we need to tell mountroot that we're 511188701Simp * done. 512188701Simp */ 513188701Simp if (sc->sc_root_token) { 514188701Simp root_mount_rel(sc->sc_root_token); 515188701Simp sc->sc_root_token = NULL; 516188701Simp } 517188701Simp 518188701Simp /* 519167208Simp * Wait until it has been 250ms since the last time we 52090981Simp * get an interrupt. We handle the rest of the interrupt 521116232Simp * at the top of the loop. Although we clear the bit in the 522116232Simp * ISR, we signal sc->cv from the detach path after we've 523116232Simp * set the CBB_KTHREAD_DONE bit, so we can't do a simple 524167208Simp * 250ms sleep here. 525119061Simp * 526119061Simp * In our ISR, we turn off the card changed interrupt. Turn 527119061Simp * them back on here before we wait for them to happen. We 528119061Simp * turn them on/off so that we can tolerate a large latency 529119061Simp * between the time we signal cbb_event_thread and it gets 530119061Simp * a chance to run. 53190981Simp */ 53298156Simp mtx_lock(&sc->mtx); 533185625Simp cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD | CBB_SOCKET_MASK_CSTS); 534185741Simp msleep(&sc->intrhand, &sc->mtx, 0, "-", 0); 535104642Simp err = 0; 536116232Simp while (err != EWOULDBLOCK && 537104642Simp (sc->flags & CBB_KTHREAD_DONE) == 0) 538185741Simp err = msleep(&sc->intrhand, &sc->mtx, 0, "-", hz / 5); 53967276Sjon } 540158891Simp DEVPRINTF((sc->dev, "Thread terminating\n")); 541101904Simp sc->flags &= ~CBB_KTHREAD_RUNNING; 542158891Simp mtx_unlock(&sc->mtx); 543172836Sjulian kproc_exit(0); 54467276Sjon} 54567276Sjon 54667276Sjon/************************************************************************/ 54767276Sjon/* Insert/removal */ 54867276Sjon/************************************************************************/ 54967276Sjon 55067276Sjonstatic void 551101904Simpcbb_insert(struct cbb_softc *sc) 55267276Sjon{ 55389326Simp uint32_t sockevent, sockstate; 55467276Sjon 555104642Simp sockevent = cbb_get(sc, CBB_SOCKET_EVENT); 556104642Simp sockstate = cbb_get(sc, CBB_SOCKET_STATE); 55767276Sjon 55890751Simp DEVPRINTF((sc->dev, "card inserted: event=0x%08x, state=%08x\n", 55982375Sjon sockevent, sockstate)); 56067276Sjon 561118705Simp if (sockstate & CBB_STATE_R2_CARD) { 562166742Simp if (device_is_attached(sc->exca[0].pccarddev)) { 563133553Simp sc->flags |= CBB_16BIT_CARD; 564133553Simp exca_insert(&sc->exca[0]); 565148090Simp } else { 566148090Simp device_printf(sc->dev, 567148090Simp "16-bit card inserted, but no pccard bus.\n"); 568133553Simp } 569118705Simp } else if (sockstate & CBB_STATE_CB_CARD) { 570166742Simp if (device_is_attached(sc->cbdev)) { 571101904Simp sc->flags &= ~CBB_16BIT_CARD; 572140037Simp CARD_ATTACH_CARD(sc->cbdev); 57390751Simp } else { 57490751Simp device_printf(sc->dev, 575104830Simp "CardBus card inserted, but no cardbus bus.\n"); 57690751Simp } 57767276Sjon } else { 57890751Simp /* 57990751Simp * We should power the card down, and try again a couple of 58090751Simp * times if this happens. XXX 58190751Simp */ 582110842Simp device_printf(sc->dev, "Unsupported card type detected\n"); 58367276Sjon } 58467276Sjon} 58567276Sjon 58667276Sjonstatic void 587101904Simpcbb_removal(struct cbb_softc *sc) 58867276Sjon{ 589170272Simp sc->cardok = 0; 590106899Simp if (sc->flags & CBB_16BIT_CARD) { 591133553Simp exca_removal(&sc->exca[0]); 592106899Simp } else { 593166742Simp if (device_is_attached(sc->cbdev)) 594106899Simp CARD_DETACH_CARD(sc->cbdev); 595106899Simp } 596101904Simp cbb_destroy_res(sc); 59767276Sjon} 59867276Sjon 59967276Sjon/************************************************************************/ 60067276Sjon/* Interrupt Handler */ 60167276Sjon/************************************************************************/ 60267276Sjon 603170163Spisostatic int 604170163Spisocbb_func_filt(void *arg) 605133553Simp{ 606133553Simp struct cbb_intrhand *ih = (struct cbb_intrhand *)arg; 607133553Simp struct cbb_softc *sc = ih->sc; 608133553Simp 609133553Simp /* 610133553Simp * Make sure that the card is really there. 611133553Simp */ 612170272Simp if (!sc->cardok) 613170163Spiso return (FILTER_STRAY); 614133553Simp if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { 615170272Simp sc->cardok = 0; 616170232Simp return (FILTER_HANDLED); 617133553Simp } 618133553Simp 619133553Simp /* 620170232Simp * nb: don't have to check for giant or not, since that's done in the 621170232Simp * ISR dispatch and one can't hold Giant in a filter anyway... 622133553Simp */ 623170270Simp return ((*ih->filt)(ih->arg)); 624133553Simp} 625133553Simp 626170163Spisostatic void 627170163Spisocbb_func_intr(void *arg) 628170163Spiso{ 629170163Spiso struct cbb_intrhand *ih = (struct cbb_intrhand *)arg; 630170232Simp struct cbb_softc *sc = ih->sc; 631170163Spiso 632170232Simp /* 633170232Simp * While this check may seem redundant, it helps close a race 634170232Simp * condition. If the card is ejected after the filter runs, but 635170232Simp * before this ISR can be scheduled, then we need to do the same 636170232Simp * filtering to prevent the card's ISR from being called. One could 637170232Simp * argue that the card's ISR should be able to cope, but experience 638170232Simp * has shown they can't always. This mitigates the problem by making 639170232Simp * the race quite a bit smaller. Properly written client ISRs should 640170232Simp * cope with the card going away in the middle of the ISR. We assume 641170232Simp * that drivers that are sophisticated enough to use filters don't 642170232Simp * need our protection. This also allows us to ensure they *ARE* 643170232Simp * called if their filter said they needed to be called. 644170232Simp */ 645170232Simp if (ih->filt == NULL) { 646170272Simp if (!sc->cardok) 647170232Simp return; 648170232Simp if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { 649170272Simp sc->cardok = 0; 650170232Simp return; 651170232Simp } 652170232Simp } 653170232Simp 654170232Simp /* 655170232Simp * Call the registered ithread interrupt handler. This entire routine 656170232Simp * will be called with Giant if this isn't an MP safe driver, or not 657170232Simp * if it is. Either way, we don't have to worry. 658170232Simp */ 659170163Spiso ih->intr(ih->arg); 660170163Spiso} 661170163Spiso 66267276Sjon/************************************************************************/ 66369288Sjon/* Generic Power functions */ 66467276Sjon/************************************************************************/ 66567276Sjon 666148013Simpstatic uint32_t 667101904Simpcbb_detect_voltage(device_t brdev) 66867276Sjon{ 669101904Simp struct cbb_softc *sc = device_get_softc(brdev); 67089326Simp uint32_t psr; 671148013Simp uint32_t vol = CARD_UKN_CARD; 67267276Sjon 673101904Simp psr = cbb_get(sc, CBB_SOCKET_STATE); 67467276Sjon 675157092Simp if (psr & CBB_STATE_5VCARD && psr & CBB_STATE_5VSOCK) 67667276Sjon vol |= CARD_5V_CARD; 677157092Simp if (psr & CBB_STATE_3VCARD && psr & CBB_STATE_3VSOCK) 67867276Sjon vol |= CARD_3V_CARD; 679157092Simp if (psr & CBB_STATE_XVCARD && psr & CBB_STATE_XVSOCK) 68067276Sjon vol |= CARD_XV_CARD; 681157092Simp if (psr & CBB_STATE_YVCARD && psr & CBB_STATE_YVSOCK) 68267276Sjon vol |= CARD_YV_CARD; 68367276Sjon 68486904Simp return (vol); 68567276Sjon} 68667276Sjon 687115887Simpstatic uint8_t 688115887Simpcbb_o2micro_power_hack(struct cbb_softc *sc) 689115887Simp{ 690115887Simp uint8_t reg; 691115887Simp 692115887Simp /* 693115887Simp * Issue #2: INT# not qualified with IRQ Routing Bit. An 694150460Simp * unexpected PCI INT# may be generated during PC Card 695115887Simp * initialization even with the IRQ Routing Bit Set with some 696150460Simp * PC Cards. 697115887Simp * 698115887Simp * This is a two part issue. The first part is that some of 699115887Simp * our older controllers have an issue in which the slot's PCI 700115887Simp * INT# is NOT qualified by the IRQ routing bit (PCI reg. 3Eh 701115887Simp * bit 7). Regardless of the IRQ routing bit, if NO ISA IRQ 702115887Simp * is selected (ExCA register 03h bits 3:0, of the slot, are 703115887Simp * cleared) we will generate INT# if IREQ# is asserted. The 704150460Simp * second part is because some PC Cards prematurally assert 705115887Simp * IREQ# before the ExCA registers are fully programmed. This 706115887Simp * in turn asserts INT# because ExCA register 03h bits 3:0 707115887Simp * (ISA IRQ Select) are not yet programmed. 708115887Simp * 709115887Simp * The fix for this issue, which will work for any controller 710115887Simp * (old or new), is to set ExCA register 03h bits 3:0 = 0001b 711115887Simp * (select IRQ1), of the slot, before turning on slot power. 712115887Simp * Selecting IRQ1 will result in INT# NOT being asserted 713115887Simp * (because IRQ1 is selected), and IRQ1 won't be asserted 714115887Simp * because our controllers don't generate IRQ1. 715148090Simp * 716148090Simp * Other, non O2Micro controllers will generate irq 1 in some 717148105Simp * situations, so we can't do this hack for everybody. Reports of 718148105Simp * keyboard controller's interrupts being suppressed occurred when 719148105Simp * we did this. 720115887Simp */ 721133553Simp reg = exca_getb(&sc->exca[0], EXCA_INTR); 722133553Simp exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1); 723115887Simp return (reg); 724115887Simp} 725115887Simp 726115887Simp/* 727115887Simp * Restore the damage that cbb_o2micro_power_hack does to EXCA_INTR so 728115887Simp * we don't have an interrupt storm on power on. This has the efect of 729115887Simp * disabling card status change interrupts for the duration of poweron. 730115887Simp */ 731115887Simpstatic void 732115887Simpcbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg) 733115887Simp{ 734133553Simp exca_putb(&sc->exca[0], EXCA_INTR, reg); 735115887Simp} 736115887Simp 737133553Simpint 738101904Simpcbb_power(device_t brdev, int volts) 73967276Sjon{ 740161241Simp uint32_t status, sock_ctrl, reg_ctrl, mask; 741101904Simp struct cbb_softc *sc = device_get_softc(brdev); 742148090Simp int cnt, sane; 743115887Simp int retval = 0; 744148013Simp int on = 0; 745115887Simp uint8_t reg = 0; 74667276Sjon 747101904Simp sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); 74867276Sjon 749115986Simp sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; 75067276Sjon switch (volts & CARD_VCCMASK) { 751115986Simp case 5: 752115986Simp sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V; 753148013Simp on++; 75467276Sjon break; 755115986Simp case 3: 756115986Simp sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V; 757148013Simp on++; 75867276Sjon break; 759115986Simp case XV: 760115986Simp sock_ctrl |= CBB_SOCKET_CTRL_VCC_XV; 761148013Simp on++; 76267276Sjon break; 763115986Simp case YV: 764115986Simp sock_ctrl |= CBB_SOCKET_CTRL_VCC_YV; 765148013Simp on++; 76667276Sjon break; 767115986Simp case 0: 768115986Simp break; 76967276Sjon default: 77086904Simp return (0); /* power NEVER changed */ 77167276Sjon } 77267276Sjon 773115986Simp /* VPP == VCC */ 774115986Simp sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; 775115986Simp sock_ctrl |= ((sock_ctrl >> 4) & 0x07); 77667276Sjon 777101904Simp if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl) 77886904Simp return (1); /* no change necessary */ 779115986Simp DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts)); 780115887Simp if (volts != 0 && sc->chipset == CB_O2MICRO) 781115887Simp reg = cbb_o2micro_power_hack(sc); 78270715Sjon 783148090Simp /* 784185749Simp * We have to mask the card change detect interrupt while we're 785185749Simp * messing with the power. It is allowed to bounce while we're 786185749Simp * messing with power as things settle down. In addition, we mask off 787185749Simp * the card's function interrupt by routing it via the ISA bus. This 788185749Simp * bit generally only affects 16-bit cards. Some bridges allow one to 789185749Simp * set another bit to have it also affect 32-bit cards. Since 32-bit 790185749Simp * cards are required to be better behaved, we don't bother to get 791185749Simp * into those bridge specific features. 792185749Simp * 793185749Simp * XXX I wonder if we need to enable the READY bit interrupt in the 794185749Simp * EXCA CSC register for 16-bit cards, and disable the CD bit? 795148090Simp */ 796148090Simp mask = cbb_get(sc, CBB_SOCKET_MASK); 797148090Simp mask |= CBB_SOCKET_MASK_POWER; 798148090Simp mask &= ~CBB_SOCKET_MASK_CD; 799148090Simp cbb_set(sc, CBB_SOCKET_MASK, mask); 800148105Simp PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, 801148105Simp |CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2); 802101904Simp cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); 803148013Simp if (on) { 804148013Simp mtx_lock(&sc->mtx); 805148013Simp cnt = sc->powerintr; 806161241Simp /* 807185749Simp * We have a shortish timeout of 500ms here. Some bridges do 808185749Simp * not generate a POWER_CYCLE event for 16-bit cards. In 809185749Simp * those cases, we have to cope the best we can, and having 810223218Simp * only a short delay is better than the alternatives. Others 811223218Simp * raise the power cycle a smidge before it is really ready. 812223218Simp * We deal with those below. 813161241Simp */ 814161241Simp sane = 10; 815148090Simp while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) && 816148090Simp cnt == sc->powerintr && sane-- > 0) 817185741Simp msleep(&sc->powerintr, &sc->mtx, 0, "-", hz / 20); 818148013Simp mtx_unlock(&sc->mtx); 819223218Simp 820161241Simp /* 821223219Simp * Relax for 100ms. Some bridges appear to assert this signal 822223218Simp * right away, but before the card has stabilized. Other 823223218Simp * cards need need more time to cope up reliabily. 824223218Simp * Experiments with troublesome setups show this to be a 825223218Simp * "cheap" way to enhance reliabilty. We need not do this for 826223218Simp * "off" since we don't touch the card after we turn it off. 827223218Simp */ 828223219Simp pause("cbbPwr", min(hz / 10, 1)); 829223218Simp 830223218Simp /* 831185749Simp * The TOPIC95B requires a little bit extra time to get its 832185749Simp * act together, so delay for an additional 100ms. Also as 833185749Simp * documented below, it doesn't seem to set the POWER_CYCLE 834161241Simp * bit, so don't whine if it never came on. 835161241Simp */ 836223218Simp if (sc->chipset == CB_TOPIC95) 837167087Sjhb pause("cbb95B", hz / 10); 838223218Simp else if (sane <= 0) 839148090Simp device_printf(sc->dev, "power timeout, doom?\n"); 840148013Simp } 841148090Simp 842148090Simp /* 843148105Simp * After the power is good, we can turn off the power interrupt. 844148105Simp * However, the PC Card standard says that we must delay turning the 845148105Simp * CD bit back on for a bit to allow for bouncyness on power down 846148105Simp * (recall that we don't wait above for a power down, since we don't 847148105Simp * get an interrupt for that). We're called either from the suspend 848148105Simp * code in which case we don't want to turn card change on again, or 849148105Simp * we're called from the card insertion code, in which case the cbb 850148105Simp * thread will turn it on for us before it waits to be woken by a 851148105Simp * change event. 852161241Simp * 853161241Simp * NB: Topic95B doesn't set the power cycle bit. we assume that 854161241Simp * both it and the TOPIC95 behave the same. 855148090Simp */ 856148013Simp cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER); 857101904Simp status = cbb_get(sc, CBB_SOCKET_STATE); 858161241Simp if (on && sc->chipset != CB_TOPIC95) { 859148013Simp if ((status & CBB_STATE_POWER_CYCLE) == 0) 860148013Simp device_printf(sc->dev, "Power not on?\n"); 86167276Sjon } 862118705Simp if (status & CBB_STATE_BAD_VCC_REQ) { 863148013Simp device_printf(sc->dev, "Bad Vcc requested\n"); 864185622Simp /* 865185622Simp * Turn off the power, and try again. Retrigger other 866185622Simp * active interrupts via force register. From NetBSD 867185622Simp * PR 36652, coded by me to description there. 868185622Simp */ 869185622Simp sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK; 870185622Simp sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK; 871185622Simp cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl); 872185622Simp status &= ~CBB_STATE_BAD_VCC_REQ; 873185622Simp status &= ~CBB_STATE_DATA_LOST; 874185622Simp status |= CBB_FORCE_CV_TEST; 875185622Simp cbb_set(sc, CBB_SOCKET_FORCE, status); 876115887Simp goto done; 87767276Sjon } 878161241Simp if (sc->chipset == CB_TOPIC97) { 879161241Simp reg_ctrl = pci_read_config(sc->dev, TOPIC_REG_CTRL, 4); 880161241Simp reg_ctrl &= ~TOPIC97_REG_CTRL_TESTMODE; 881161241Simp if (on) 882161241Simp reg_ctrl |= TOPIC97_REG_CTRL_CLKRUN_ENA; 883161241Simp else 884161241Simp reg_ctrl &= ~TOPIC97_REG_CTRL_CLKRUN_ENA; 885161241Simp pci_write_config(sc->dev, TOPIC_REG_CTRL, reg_ctrl, 4); 886161241Simp } 887148105Simp PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, 888148105Simp & ~CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2); 889115887Simp retval = 1; 890115887Simpdone:; 891115887Simp if (volts != 0 && sc->chipset == CB_O2MICRO) 892115887Simp cbb_o2micro_power_hack2(sc, reg); 893115887Simp return (retval); 89467276Sjon} 89567276Sjon 896148013Simpstatic int 897148013Simpcbb_current_voltage(device_t brdev) 898148013Simp{ 899148013Simp struct cbb_softc *sc = device_get_softc(brdev); 900148013Simp uint32_t ctrl; 901148013Simp 902148013Simp ctrl = cbb_get(sc, CBB_SOCKET_CONTROL); 903148013Simp switch (ctrl & CBB_SOCKET_CTRL_VCCMASK) { 904148013Simp case CBB_SOCKET_CTRL_VCC_5V: 905148013Simp return CARD_5V_CARD; 906148013Simp case CBB_SOCKET_CTRL_VCC_3V: 907148013Simp return CARD_3V_CARD; 908148013Simp case CBB_SOCKET_CTRL_VCC_XV: 909148013Simp return CARD_XV_CARD; 910148013Simp case CBB_SOCKET_CTRL_VCC_YV: 911148013Simp return CARD_YV_CARD; 912148013Simp } 913148013Simp return 0; 914148013Simp} 915148013Simp 91690751Simp/* 91790751Simp * detect the voltage for the card, and set it. Since the power 91890751Simp * used is the square of the voltage, lower voltages is a big win 91990751Simp * and what Windows does (and what Microsoft prefers). The MS paper 920148013Simp * also talks about preferring the CIS entry as well, but that has 921148013Simp * to be done elsewhere. We also optimize power sequencing here 922148013Simp * and don't change things if we're already powered up at a supported 923148013Simp * voltage. 924148013Simp * 925148013Simp * In addition, we power up with OE disabled. We'll set it later 926148013Simp * in the power up sequence. 92790751Simp */ 92890751Simpstatic int 929101904Simpcbb_do_power(device_t brdev) 93090751Simp{ 931127965Simp struct cbb_softc *sc = device_get_softc(brdev); 932148013Simp uint32_t voltage, curpwr; 933148013Simp uint32_t status; 93490751Simp 935148013Simp /* Don't enable OE (output enable) until power stable */ 936133553Simp exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE); 937127960Simp 938148013Simp voltage = cbb_detect_voltage(brdev); 939148013Simp curpwr = cbb_current_voltage(brdev); 940148013Simp status = cbb_get(sc, CBB_SOCKET_STATE); 941148013Simp if ((status & CBB_STATE_POWER_CYCLE) && (voltage & curpwr)) 942148013Simp return 0; 94390751Simp /* Prefer lowest voltage supported */ 944115986Simp cbb_power(brdev, CARD_OFF); 94590751Simp if (voltage & CARD_YV_CARD) 946115986Simp cbb_power(brdev, CARD_VCC(YV)); 94790751Simp else if (voltage & CARD_XV_CARD) 948115986Simp cbb_power(brdev, CARD_VCC(XV)); 94990751Simp else if (voltage & CARD_3V_CARD) 950115986Simp cbb_power(brdev, CARD_VCC(3)); 95190751Simp else if (voltage & CARD_5V_CARD) 952115986Simp cbb_power(brdev, CARD_VCC(5)); 95390751Simp else { 95490751Simp device_printf(brdev, "Unknown card voltage\n"); 95590751Simp return (ENXIO); 95690751Simp } 95790751Simp return (0); 95890751Simp} 95990751Simp 96067276Sjon/************************************************************************/ 961104830Simp/* CardBus power functions */ 96267276Sjon/************************************************************************/ 96367276Sjon 96469288Sjonstatic void 965189723Simpcbb_cardbus_reset_power(device_t brdev, device_t child, int on) 96667276Sjon{ 967101904Simp struct cbb_softc *sc = device_get_softc(brdev); 968181453Simp uint32_t b; 969181453Simp int delay, count; 97067276Sjon 971148025Simp /* 972181458Simp * Asserting reset for 20ms is necessary for most bridges. For some 973185623Simp * reason, the Ricoh RF5C47x bridges need it asserted for 400ms. The 974185623Simp * root cause of this is unknown, and NetBSD does the same thing. 975148025Simp */ 976181453Simp delay = sc->chipset == CB_RF5C47X ? 400 : 20; 97790751Simp PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2); 978167087Sjhb pause("cbbP3", hz * delay / 1000); 97967276Sjon 980181458Simp /* 981185623Simp * If a card exists and we're turning it on, take it out of reset. 982185623Simp * After clearing reset, wait up to 1.1s for the first configuration 983185623Simp * register (vendor/product) configuration register of device 0.0 to 984185623Simp * become != 0xffffffff. The PCMCIA PC Card Host System Specification 985185623Simp * says that when powering up the card, the PCI Spec v2.1 must be 986185623Simp * followed. In PCI spec v2.2 Table 4-6, Trhfa (Reset High to first 987185623Simp * Config Access) is at most 2^25 clocks, or just over 1s. Section 988185623Simp * 2.2.1 states any card not ready to participate in bus transactions 989185623Simp * must tristate its outputs. Therefore, any access to its 990185623Simp * configuration registers must be ignored. In that state, the config 991185623Simp * reg will read 0xffffffff. Section 6.2.1 states a vendor id of 992185623Simp * 0xffff is invalid, so this can never match a real card. Print a 993185623Simp * warning if it never returns a real id. The PCMCIA PC Card 994185623Simp * Electrical Spec Section 5.2.7.1 implies only device 0 is present on 995185623Simp * a cardbus bus, so that's the only register we check here. 996181458Simp */ 997181453Simp if (on && CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) { 998181458Simp /* 999181458Simp */ 100090751Simp PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, 100190751Simp &~CBBM_BRIDGECTRL_RESET, 2); 1002181523Simp b = pcib_get_bus(child); 1003181458Simp count = 1100 / 20; 1004181453Simp do { 1005181453Simp pause("cbbP4", hz * 2 / 100); 1006181470Simp } while (PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_DEVVENDOR, 4) == 1007181470Simp 0xfffffffful && --count >= 0); 1008181453Simp if (count < 0) 1009181458Simp device_printf(brdev, "Warning: Bus reset timeout\n"); 101067276Sjon } 101167276Sjon} 101267276Sjon 101369288Sjonstatic int 1014101904Simpcbb_cardbus_power_enable_socket(device_t brdev, device_t child) 101569288Sjon{ 1016101904Simp struct cbb_softc *sc = device_get_softc(brdev); 101790751Simp int err; 101870715Sjon 1019119191Simp if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) 102086904Simp return (ENODEV); 102170715Sjon 1022101904Simp err = cbb_do_power(brdev); 102390751Simp if (err) 102490751Simp return (err); 1025189723Simp cbb_cardbus_reset_power(brdev, child, 1); 102686904Simp return (0); 102769288Sjon} 102869288Sjon 1029188129Simpstatic int 1030101904Simpcbb_cardbus_power_disable_socket(device_t brdev, device_t child) 103169288Sjon{ 1032115986Simp cbb_power(brdev, CARD_OFF); 1033189723Simp cbb_cardbus_reset_power(brdev, child, 0); 1034188129Simp return (0); 103569288Sjon} 103669288Sjon 103767276Sjon/************************************************************************/ 1038104830Simp/* CardBus Resource */ 103967276Sjon/************************************************************************/ 104067276Sjon 104167276Sjonstatic int 1042101904Simpcbb_cardbus_io_open(device_t brdev, int win, uint32_t start, uint32_t end) 104367276Sjon{ 104467276Sjon int basereg; 104567276Sjon int limitreg; 104667276Sjon 104767276Sjon if ((win < 0) || (win > 1)) { 104882375Sjon DEVPRINTF((brdev, 1049101904Simp "cbb_cardbus_io_open: window out of range %d\n", win)); 105086904Simp return (EINVAL); 105167276Sjon } 105267276Sjon 105390751Simp basereg = win * 8 + CBBR_IOBASE0; 105490751Simp limitreg = win * 8 + CBBR_IOLIMIT0; 105567276Sjon 105682375Sjon pci_write_config(brdev, basereg, start, 4); 105782375Sjon pci_write_config(brdev, limitreg, end, 4); 105886904Simp return (0); 105967276Sjon} 106067276Sjon 106167276Sjonstatic int 1062101904Simpcbb_cardbus_mem_open(device_t brdev, int win, uint32_t start, uint32_t end) 106367276Sjon{ 106467276Sjon int basereg; 106567276Sjon int limitreg; 106667276Sjon 106767276Sjon if ((win < 0) || (win > 1)) { 106882375Sjon DEVPRINTF((brdev, 1069101904Simp "cbb_cardbus_mem_open: window out of range %d\n", win)); 107086904Simp return (EINVAL); 107167276Sjon } 107267276Sjon 1073185624Simp basereg = win * 8 + CBBR_MEMBASE0; 1074185624Simp limitreg = win * 8 + CBBR_MEMLIMIT0; 107567276Sjon 107682375Sjon pci_write_config(brdev, basereg, start, 4); 107782375Sjon pci_write_config(brdev, limitreg, end, 4); 107886904Simp return (0); 107967276Sjon} 108067276Sjon 1081153860Simp#define START_NONE 0xffffffff 1082153860Simp#define END_NONE 0 1083153860Simp 108467276Sjonstatic void 1085101904Simpcbb_cardbus_auto_open(struct cbb_softc *sc, int type) 108667276Sjon{ 108789326Simp uint32_t starts[2]; 108889326Simp uint32_t ends[2]; 1089101904Simp struct cbb_reslist *rle; 1090153860Simp int align, i; 109189326Simp uint32_t reg; 109267276Sjon 1093153860Simp starts[0] = starts[1] = START_NONE; 1094153860Simp ends[0] = ends[1] = END_NONE; 109567276Sjon 109682378Sjon if (type == SYS_RES_MEMORY) 109790751Simp align = CBB_MEMALIGN; 109882378Sjon else if (type == SYS_RES_IOPORT) 109990751Simp align = CBB_IOALIGN; 110082378Sjon else 110182378Sjon align = 1; 110282378Sjon 110382378Sjon SLIST_FOREACH(rle, &sc->rl, link) { 110467276Sjon if (rle->type != type) 1105153860Simp continue; 1106153860Simp if (rle->res == NULL) 1107153860Simp continue; 1108153860Simp if (!(rman_get_flags(rle->res) & RF_ACTIVE)) 1109153860Simp continue; 1110153860Simp if (rman_get_flags(rle->res) & RF_PREFETCHABLE) 1111153860Simp i = 1; 1112153860Simp else 1113153860Simp i = 0; 1114153860Simp if (rman_get_start(rle->res) < starts[i]) 1115153860Simp starts[i] = rman_get_start(rle->res); 1116153860Simp if (rman_get_end(rle->res) > ends[i]) 1117153860Simp ends[i] = rman_get_end(rle->res); 1118153860Simp } 1119153860Simp for (i = 0; i < 2; i++) { 1120153860Simp if (starts[i] == START_NONE) 1121153860Simp continue; 1122153860Simp starts[i] &= ~(align - 1); 1123153860Simp ends[i] = ((ends[i] + align - 1) & ~(align - 1)) - 1; 1124153860Simp } 1125153860Simp if (starts[0] != START_NONE && starts[1] != START_NONE) { 1126153860Simp if (starts[0] < starts[1]) { 1127153860Simp if (ends[0] > starts[1]) { 1128153860Simp device_printf(sc->dev, "Overlapping ranges" 1129153860Simp " for prefetch and non-prefetch memory\n"); 1130153860Simp return; 1131153860Simp } 113267276Sjon } else { 1133153860Simp if (ends[1] > starts[0]) { 1134153860Simp device_printf(sc->dev, "Overlapping ranges" 1135153860Simp " for prefetch and non-prefetch memory\n"); 1136153860Simp return; 1137153860Simp } 113867276Sjon } 113967276Sjon } 114067276Sjon 114182378Sjon if (type == SYS_RES_MEMORY) { 1142101904Simp cbb_cardbus_mem_open(sc->dev, 0, starts[0], ends[0]); 1143101904Simp cbb_cardbus_mem_open(sc->dev, 1, starts[1], ends[1]); 114490751Simp reg = pci_read_config(sc->dev, CBBR_BRIDGECTRL, 2); 1145153860Simp reg &= ~(CBBM_BRIDGECTRL_PREFETCH_0 | 114690751Simp CBBM_BRIDGECTRL_PREFETCH_1); 1147153860Simp if (starts[1] != START_NONE) 1148153860Simp reg |= CBBM_BRIDGECTRL_PREFETCH_1; 114990751Simp pci_write_config(sc->dev, CBBR_BRIDGECTRL, reg, 2); 1150153860Simp if (bootverbose) { 1151153860Simp device_printf(sc->dev, "Opening memory:\n"); 1152153860Simp if (starts[0] != START_NONE) 1153153860Simp device_printf(sc->dev, "Normal: %#x-%#x\n", 1154153860Simp starts[0], ends[0]); 1155153860Simp if (starts[1] != START_NONE) 1156153860Simp device_printf(sc->dev, "Prefetch: %#x-%#x\n", 1157153860Simp starts[1], ends[1]); 1158153757Simp } 115967276Sjon } else if (type == SYS_RES_IOPORT) { 1160101904Simp cbb_cardbus_io_open(sc->dev, 0, starts[0], ends[0]); 1161101904Simp cbb_cardbus_io_open(sc->dev, 1, starts[1], ends[1]); 1162153860Simp if (bootverbose && starts[0] != START_NONE) 1163153860Simp device_printf(sc->dev, "Opening I/O: %#x-%#x\n", 1164153860Simp starts[0], ends[0]); 116567276Sjon } 116667276Sjon} 116767276Sjon 116867276Sjonstatic int 1169101904Simpcbb_cardbus_activate_resource(device_t brdev, device_t child, int type, 117082378Sjon int rid, struct resource *res) 117167276Sjon{ 117282378Sjon int ret; 117367276Sjon 117482378Sjon ret = BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child, 117582378Sjon type, rid, res); 117686904Simp if (ret != 0) 117786904Simp return (ret); 1178101904Simp cbb_cardbus_auto_open(device_get_softc(brdev), type); 117986904Simp return (0); 118067276Sjon} 118167276Sjon 118267276Sjonstatic int 1183101904Simpcbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type, 118482378Sjon int rid, struct resource *res) 118567276Sjon{ 118682378Sjon int ret; 118767276Sjon 118882378Sjon ret = BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child, 118982378Sjon type, rid, res); 119086904Simp if (ret != 0) 119186904Simp return (ret); 1192101904Simp cbb_cardbus_auto_open(device_get_softc(brdev), type); 119386904Simp return (0); 119467276Sjon} 119567276Sjon 119682375Sjonstatic struct resource * 1197101904Simpcbb_cardbus_alloc_resource(device_t brdev, device_t child, int type, 1198118607Sjhb int *rid, u_long start, u_long end, u_long count, u_int flags) 119967276Sjon{ 1200101904Simp struct cbb_softc *sc = device_get_softc(brdev); 120182378Sjon int tmp; 120282378Sjon struct resource *res; 1203127965Simp u_long align; 120482378Sjon 120582378Sjon switch (type) { 120682378Sjon case SYS_RES_IRQ: 120790751Simp tmp = rman_get_start(sc->irq_res); 120882378Sjon if (start > tmp || end < tmp || count != 1) { 120982378Sjon device_printf(child, "requested interrupt %ld-%ld," 1210101904Simp "count = %ld not supported by cbb\n", 121182378Sjon start, end, count); 121286904Simp return (NULL); 121367276Sjon } 121482378Sjon start = end = tmp; 1215114169Simp flags |= RF_SHAREABLE; 121682378Sjon break; 121782378Sjon case SYS_RES_IOPORT: 1218101904Simp if (start <= cbb_start_32_io) 1219101904Simp start = cbb_start_32_io; 122082378Sjon if (end < start) 122182378Sjon end = start; 1222153757Simp if (count > (1 << RF_ALIGNMENT(flags))) 1223153757Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 1224153757Simp rman_make_alignment_flags(count); 122582378Sjon break; 122682378Sjon case SYS_RES_MEMORY: 1227101904Simp if (start <= cbb_start_mem) 1228101904Simp start = cbb_start_mem; 122982378Sjon if (end < start) 123082378Sjon end = start; 1231127966Simp if (count < CBB_MEMALIGN) 1232127966Simp align = CBB_MEMALIGN; 1233127966Simp else 1234127966Simp align = count; 1235127966Simp if (align > (1 << RF_ALIGNMENT(flags))) 1236127966Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 1237127965Simp rman_make_alignment_flags(align); 123882378Sjon break; 123982378Sjon } 124082378Sjon res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, 124182378Sjon start, end, count, flags & ~RF_ACTIVE); 124282378Sjon if (res == NULL) { 1243169617Simp printf("cbb alloc res fail type %d rid %x\n", type, *rid); 124486904Simp return (NULL); 124582378Sjon } 1246101904Simp cbb_insert_res(sc, res, type, *rid); 124782378Sjon if (flags & RF_ACTIVE) 124882378Sjon if (bus_activate_resource(child, type, *rid, res) != 0) { 124982378Sjon bus_release_resource(child, type, *rid, res); 125086904Simp return (NULL); 125167276Sjon } 125282378Sjon 125386904Simp return (res); 125467276Sjon} 125567276Sjon 125667276Sjonstatic int 1257101904Simpcbb_cardbus_release_resource(device_t brdev, device_t child, int type, 125882378Sjon int rid, struct resource *res) 125967276Sjon{ 1260101904Simp struct cbb_softc *sc = device_get_softc(brdev); 126186904Simp int error; 126282378Sjon 126382378Sjon if (rman_get_flags(res) & RF_ACTIVE) { 126482378Sjon error = bus_deactivate_resource(child, type, rid, res); 126582378Sjon if (error != 0) 126686904Simp return (error); 126782378Sjon } 1268101904Simp cbb_remove_res(sc, res); 126986904Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 127086904Simp type, rid, res)); 127167276Sjon} 127267276Sjon 127367276Sjon/************************************************************************/ 127469288Sjon/* PC Card Power Functions */ 127567276Sjon/************************************************************************/ 127667276Sjon 127769288Sjonstatic int 1278101904Simpcbb_pcic_power_enable_socket(device_t brdev, device_t child) 127969288Sjon{ 1280101904Simp struct cbb_softc *sc = device_get_softc(brdev); 128190751Simp int err; 128269288Sjon 1283101904Simp DPRINTF(("cbb_pcic_socket_enable:\n")); 128469288Sjon 128569288Sjon /* power down/up the socket to reset */ 1286101904Simp err = cbb_do_power(brdev); 128790751Simp if (err) 128890751Simp return (err); 1289133553Simp exca_reset(&sc->exca[0], child); 129069288Sjon 129186904Simp return (0); 129269288Sjon} 129369288Sjon 1294188129Simpstatic int 1295101904Simpcbb_pcic_power_disable_socket(device_t brdev, device_t child) 129669288Sjon{ 1297101904Simp struct cbb_softc *sc = device_get_softc(brdev); 129869288Sjon 1299101904Simp DPRINTF(("cbb_pcic_socket_disable\n")); 130069288Sjon 1301167217Simp /* Turn off the card's interrupt and leave it in reset, wait 10ms */ 1302151080Simp exca_putb(&sc->exca[0], EXCA_INTR, 0); 1303167087Sjhb pause("cbbP1", hz / 100); 130469288Sjon 130569288Sjon /* power down the socket */ 1306115986Simp cbb_power(brdev, CARD_OFF); 1307151080Simp exca_putb(&sc->exca[0], EXCA_PWRCTL, 0); 130869288Sjon 130969288Sjon /* wait 300ms until power fails (Tpf). */ 1310167217Simp pause("cbbP2", hz * 300 / 1000); 1311166786Simp 1312166786Simp /* enable CSC interrupts */ 1313166786Simp exca_putb(&sc->exca[0], EXCA_INTR, EXCA_INTR_ENABLE); 1314188129Simp return (0); 131569288Sjon} 131669288Sjon 131769288Sjon/************************************************************************/ 131889949Simp/* POWER methods */ 131969288Sjon/************************************************************************/ 132069288Sjon 1321133553Simpint 1322101904Simpcbb_power_enable_socket(device_t brdev, device_t child) 132367276Sjon{ 1324101904Simp struct cbb_softc *sc = device_get_softc(brdev); 132567276Sjon 1326101904Simp if (sc->flags & CBB_16BIT_CARD) 1327101904Simp return (cbb_pcic_power_enable_socket(brdev, child)); 1328188129Simp return (cbb_cardbus_power_enable_socket(brdev, child)); 132967276Sjon} 133067276Sjon 1331188129Simpint 1332101904Simpcbb_power_disable_socket(device_t brdev, device_t child) 133367276Sjon{ 1334101904Simp struct cbb_softc *sc = device_get_softc(brdev); 1335101904Simp if (sc->flags & CBB_16BIT_CARD) 1336188129Simp return (cbb_pcic_power_disable_socket(brdev, child)); 1337188129Simp return (cbb_cardbus_power_disable_socket(brdev, child)); 133867276Sjon} 1339115989Simp 134082378Sjonstatic int 1341101904Simpcbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid, 134282378Sjon struct resource *res) 134367276Sjon{ 1344101904Simp struct cbb_softc *sc = device_get_softc(brdev); 1345133553Simp return (exca_activate_resource(&sc->exca[0], child, type, rid, res)); 134667276Sjon} 134767276Sjon 134867276Sjonstatic int 1349101904Simpcbb_pcic_deactivate_resource(device_t brdev, device_t child, int type, 135082378Sjon int rid, struct resource *res) 135167276Sjon{ 1352101904Simp struct cbb_softc *sc = device_get_softc(brdev); 1353133553Simp return (exca_deactivate_resource(&sc->exca[0], child, type, rid, res)); 135467276Sjon} 135567276Sjon 135682375Sjonstatic struct resource * 1357101904Simpcbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid, 1358118607Sjhb u_long start, u_long end, u_long count, u_int flags) 135967276Sjon{ 136082378Sjon struct resource *res = NULL; 1361101904Simp struct cbb_softc *sc = device_get_softc(brdev); 1362128170Simp int align; 136382378Sjon int tmp; 136467276Sjon 136567423Simp switch (type) { 136667423Simp case SYS_RES_MEMORY: 1367101904Simp if (start < cbb_start_mem) 1368101904Simp start = cbb_start_mem; 136982378Sjon if (end < start) 137082378Sjon end = start; 1371128170Simp if (count < CBB_MEMALIGN) 1372128170Simp align = CBB_MEMALIGN; 1373128170Simp else 1374128170Simp align = count; 1375128170Simp if (align > (1 << RF_ALIGNMENT(flags))) 1376128170Simp flags = (flags & ~RF_ALIGNMENT_MASK) | 1377128170Simp rman_make_alignment_flags(align); 137867423Simp break; 137967423Simp case SYS_RES_IOPORT: 1380101904Simp if (start < cbb_start_16_io) 1381101904Simp start = cbb_start_16_io; 138267423Simp if (end < start) 138367423Simp end = start; 138467423Simp break; 138567423Simp case SYS_RES_IRQ: 138690751Simp tmp = rman_get_start(sc->irq_res); 138782378Sjon if (start > tmp || end < tmp || count != 1) { 138882378Sjon device_printf(child, "requested interrupt %ld-%ld," 1389101904Simp "count = %ld not supported by cbb\n", 139082378Sjon start, end, count); 139186904Simp return (NULL); 139282378Sjon } 139367423Simp flags |= RF_SHAREABLE; 139490751Simp start = end = rman_get_start(sc->irq_res); 139567423Simp break; 139667423Simp } 139782378Sjon res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, 139882378Sjon start, end, count, flags & ~RF_ACTIVE); 139982378Sjon if (res == NULL) 140086904Simp return (NULL); 1401101904Simp cbb_insert_res(sc, res, type, *rid); 140267276Sjon if (flags & RF_ACTIVE) { 140382378Sjon if (bus_activate_resource(child, type, *rid, res) != 0) { 140482378Sjon bus_release_resource(child, type, *rid, res); 140586904Simp return (NULL); 140667276Sjon } 140767276Sjon } 140867276Sjon 140986904Simp return (res); 141067276Sjon} 141167276Sjon 141267276Sjonstatic int 1413101904Simpcbb_pcic_release_resource(device_t brdev, device_t child, int type, 141482375Sjon int rid, struct resource *res) 141567276Sjon{ 1416101904Simp struct cbb_softc *sc = device_get_softc(brdev); 141786904Simp int error; 141867276Sjon 141970715Sjon if (rman_get_flags(res) & RF_ACTIVE) { 142070715Sjon error = bus_deactivate_resource(child, type, rid, res); 142170715Sjon if (error != 0) 142286904Simp return (error); 142370715Sjon } 1424101904Simp cbb_remove_res(sc, res); 142586904Simp return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, 142686904Simp type, rid, res)); 142767276Sjon} 142867276Sjon 142967276Sjon/************************************************************************/ 143067276Sjon/* PC Card methods */ 143167276Sjon/************************************************************************/ 143267276Sjon 1433133553Simpint 1434101904Simpcbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid, 1435188129Simp u_long flags) 143667276Sjon{ 1437101904Simp struct cbb_softc *sc = device_get_softc(brdev); 143882378Sjon struct resource *res; 143967276Sjon 144067276Sjon if (type != SYS_RES_MEMORY) 144167276Sjon return (EINVAL); 1442101904Simp res = cbb_find_res(sc, type, rid); 144382378Sjon if (res == NULL) { 144482378Sjon device_printf(brdev, 144582378Sjon "set_res_flags: specified rid not found\n"); 144686904Simp return (ENOENT); 144782378Sjon } 1448133553Simp return (exca_mem_set_flags(&sc->exca[0], res, flags)); 144967276Sjon} 145067276Sjon 1451133553Simpint 1452101904Simpcbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid, 145389326Simp uint32_t cardaddr, uint32_t *deltap) 145467276Sjon{ 1455101904Simp struct cbb_softc *sc = device_get_softc(brdev); 145682378Sjon struct resource *res; 145767276Sjon 1458101904Simp res = cbb_find_res(sc, SYS_RES_MEMORY, rid); 145982378Sjon if (res == NULL) { 146082378Sjon device_printf(brdev, 146182378Sjon "set_memory_offset: specified rid not found\n"); 146286904Simp return (ENOENT); 146370715Sjon } 1464133553Simp return (exca_mem_set_offset(&sc->exca[0], res, cardaddr, deltap)); 146567276Sjon} 146667276Sjon 146769288Sjon/************************************************************************/ 146869288Sjon/* BUS Methods */ 146967276Sjon/************************************************************************/ 147067276Sjon 147167276Sjon 1472133553Simpint 1473101904Simpcbb_activate_resource(device_t brdev, device_t child, int type, int rid, 147482375Sjon struct resource *r) 147567276Sjon{ 1476101904Simp struct cbb_softc *sc = device_get_softc(brdev); 147767276Sjon 1478101904Simp if (sc->flags & CBB_16BIT_CARD) 1479101904Simp return (cbb_pcic_activate_resource(brdev, child, type, rid, r)); 148067276Sjon else 1481101904Simp return (cbb_cardbus_activate_resource(brdev, child, type, rid, 148286904Simp r)); 148367276Sjon} 148467276Sjon 1485133553Simpint 1486101904Simpcbb_deactivate_resource(device_t brdev, device_t child, int type, 148782375Sjon int rid, struct resource *r) 148867276Sjon{ 1489101904Simp struct cbb_softc *sc = device_get_softc(brdev); 149067276Sjon 1491101904Simp if (sc->flags & CBB_16BIT_CARD) 1492101904Simp return (cbb_pcic_deactivate_resource(brdev, child, type, 149386904Simp rid, r)); 149467276Sjon else 1495101904Simp return (cbb_cardbus_deactivate_resource(brdev, child, type, 149686904Simp rid, r)); 149767276Sjon} 149867276Sjon 1499133553Simpstruct resource * 1500101904Simpcbb_alloc_resource(device_t brdev, device_t child, int type, int *rid, 1501118607Sjhb u_long start, u_long end, u_long count, u_int flags) 150267276Sjon{ 1503101904Simp struct cbb_softc *sc = device_get_softc(brdev); 150467276Sjon 1505101904Simp if (sc->flags & CBB_16BIT_CARD) 1506101904Simp return (cbb_pcic_alloc_resource(brdev, child, type, rid, 150786904Simp start, end, count, flags)); 150867276Sjon else 1509101904Simp return (cbb_cardbus_alloc_resource(brdev, child, type, rid, 151086904Simp start, end, count, flags)); 151167276Sjon} 151267276Sjon 1513133553Simpint 1514101904Simpcbb_release_resource(device_t brdev, device_t child, int type, int rid, 151582375Sjon struct resource *r) 151667276Sjon{ 1517101904Simp struct cbb_softc *sc = device_get_softc(brdev); 151867276Sjon 1519101904Simp if (sc->flags & CBB_16BIT_CARD) 1520101904Simp return (cbb_pcic_release_resource(brdev, child, type, 152186904Simp rid, r)); 152267276Sjon else 1523101904Simp return (cbb_cardbus_release_resource(brdev, child, type, 152486904Simp rid, r)); 152567276Sjon} 152667276Sjon 1527133553Simpint 1528101904Simpcbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result) 152969954Smsmith{ 1530101904Simp struct cbb_softc *sc = device_get_softc(brdev); 153170715Sjon 153269954Smsmith switch (which) { 1533172394Smarius case PCIB_IVAR_DOMAIN: 1534172394Smarius *result = sc->domain; 1535172394Smarius return (0); 153669954Smsmith case PCIB_IVAR_BUS: 153790751Simp *result = sc->secbus; 153886904Simp return (0); 153969954Smsmith } 154086904Simp return (ENOENT); 154169954Smsmith} 154269954Smsmith 1543133553Simpint 1544101904Simpcbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value) 154569954Smsmith{ 1546101904Simp struct cbb_softc *sc = device_get_softc(brdev); 154769954Smsmith 154869954Smsmith switch (which) { 1549172394Smarius case PCIB_IVAR_DOMAIN: 1550172394Smarius return (EINVAL); 155169954Smsmith case PCIB_IVAR_BUS: 155290751Simp sc->secbus = value; 1553159194Simp return (0); 155469954Smsmith } 155586904Simp return (ENOENT); 155669954Smsmith} 155769954Smsmith 1558133553Simpint 1559101904Simpcbb_suspend(device_t self) 156087975Simp{ 156187975Simp int error = 0; 1562104642Simp struct cbb_softc *sc = device_get_softc(self); 156387975Simp 1564158892Simp error = bus_generic_suspend(self); 1565158892Simp if (error != 0) 1566158892Simp return (error); 1567116232Simp cbb_set(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */ 1568170272Simp sc->cardok = 0; /* Card is bogus now */ 1569158892Simp return (0); 157087975Simp} 157187975Simp 1572133553Simpint 1573101904Simpcbb_resume(device_t self) 157487975Simp{ 157587975Simp int error = 0; 1576101904Simp struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self); 157789326Simp uint32_t tmp; 157887975Simp 1579104642Simp /* 1580104642Simp * Some BIOSes will not save the BARs for the pci chips, so we 1581104642Simp * must do it ourselves. If the BAR is reset to 0 for an I/O 1582104642Simp * device, it will read back as 0x1, so no explicit test for 1583104642Simp * memory devices are needed. 1584104642Simp * 1585104642Simp * Note: The PCI bus code should do this automatically for us on 1586104642Simp * suspend/resume, but until it does, we have to cope. 1587104642Simp */ 158890751Simp pci_write_config(self, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4); 158987975Simp DEVPRINTF((self, "PCI Memory allocated: %08lx\n", 159090751Simp rman_get_start(sc->base_res))); 159187975Simp 1592133553Simp sc->chipinit(sc); 159387975Simp 1594104642Simp /* reset interrupt -- Do we really need to do this? */ 1595104642Simp tmp = cbb_get(sc, CBB_SOCKET_EVENT); 1596104642Simp cbb_set(sc, CBB_SOCKET_EVENT, tmp); 1597104642Simp 159887975Simp /* CSC Interrupt: Card detect interrupt on */ 1599101904Simp cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); 160087975Simp 1601106362Simp /* Signal the thread to wakeup. */ 1602185625Simp wakeup(&sc->intrhand); 160387975Simp 160490444Simp error = bus_generic_resume(self); 160590444Simp 160687975Simp return (error); 160787975Simp} 160887975Simp 1609133553Simpint 1610188129Simpcbb_child_present(device_t parent, device_t child) 1611106900Simp{ 1612188129Simp struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(parent); 1613106900Simp uint32_t sockstate; 1614106900Simp 1615106900Simp sockstate = cbb_get(sc, CBB_SOCKET_STATE); 1616170272Simp return (CBB_CARD_PRESENT(sockstate) && sc->cardok); 1617106900Simp} 1618