1098ca2bdSWarner Losh /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 4f86e6000SWarner Losh * Copyright (c) 2000-2001 Jonathan Chen All rights reserved. 5f86e6000SWarner Losh * Copyright (c) 2002-2004 M. Warner Losh <imp@FreeBSD.org> 693185c74SWarner Losh * 793185c74SWarner Losh * Redistribution and use in source and binary forms, with or without 893185c74SWarner Losh * modification, are permitted provided that the following conditions 993185c74SWarner Losh * are met: 1093185c74SWarner Losh * 1. Redistributions of source code must retain the above copyright 11523675f6SWarner Losh * notice, this list of conditions and the following disclaimer. 1293185c74SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 13523675f6SWarner Losh * notice, this list of conditions and the following disclaimer in the 14523675f6SWarner Losh * documentation and/or other materials provided with the distribution. 1593185c74SWarner Losh * 1693185c74SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1793185c74SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1893185c74SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19523675f6SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20523675f6SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2193185c74SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2293185c74SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2393185c74SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2493185c74SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2593185c74SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2693185c74SWarner Losh * SUCH DAMAGE. 27523675f6SWarner Losh * 2893185c74SWarner Losh */ 2993185c74SWarner Losh 30afa87f87SWarner Losh /*- 3193185c74SWarner Losh * Copyright (c) 1998, 1999 and 2000 3293185c74SWarner Losh * HAYAKAWA Koichi. All rights reserved. 3393185c74SWarner Losh * 3493185c74SWarner Losh * Redistribution and use in source and binary forms, with or without 3593185c74SWarner Losh * modification, are permitted provided that the following conditions 3693185c74SWarner Losh * are met: 3793185c74SWarner Losh * 1. Redistributions of source code must retain the above copyright 3893185c74SWarner Losh * notice, this list of conditions and the following disclaimer. 3993185c74SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 4093185c74SWarner Losh * notice, this list of conditions and the following disclaimer in the 4193185c74SWarner Losh * documentation and/or other materials provided with the distribution. 4293185c74SWarner Losh * 3. All advertising materials mentioning features or use of this software 4393185c74SWarner Losh * must display the following acknowledgement: 4493185c74SWarner Losh * This product includes software developed by HAYAKAWA Koichi. 4593185c74SWarner Losh * 4. The name of the author may not be used to endorse or promote products 4693185c74SWarner Losh * derived from this software without specific prior written permission. 4793185c74SWarner Losh * 4893185c74SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4993185c74SWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5093185c74SWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 5193185c74SWarner Losh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5293185c74SWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5393185c74SWarner Losh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5493185c74SWarner Losh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5593185c74SWarner Losh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5693185c74SWarner Losh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5793185c74SWarner Losh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5893185c74SWarner Losh */ 5993185c74SWarner Losh 6093185c74SWarner Losh /* 6193185c74SWarner Losh * Driver for PCI to CardBus Bridge chips 6293185c74SWarner Losh * 6393185c74SWarner Losh * References: 6493185c74SWarner Losh * TI Datasheets: 6593185c74SWarner Losh * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS 6693185c74SWarner Losh * 6793185c74SWarner Losh * Written by Jonathan Chen <jon@freebsd.org> 6893185c74SWarner Losh * The author would like to acknowledge: 6993185c74SWarner Losh * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing 7093185c74SWarner Losh * * Warner Losh: Newbus/newcard guru and author of the pccard side of things 7193185c74SWarner Losh * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver 7293185c74SWarner Losh * * David Cross: Author of the initial ugly hack for a specific cardbus card 7393185c74SWarner Losh */ 7493185c74SWarner Losh 7593185c74SWarner Losh #include <sys/param.h> 7693185c74SWarner Losh #include <sys/systm.h> 7793185c74SWarner Losh #include <sys/proc.h> 7893185c74SWarner Losh #include <sys/condvar.h> 7993185c74SWarner Losh #include <sys/errno.h> 8093185c74SWarner Losh #include <sys/kernel.h> 8193185c74SWarner Losh #include <sys/lock.h> 8293185c74SWarner Losh #include <sys/malloc.h> 8393185c74SWarner Losh #include <sys/mutex.h> 8493185c74SWarner Losh #include <sys/sysctl.h> 8593185c74SWarner Losh #include <sys/kthread.h> 8693185c74SWarner Losh #include <sys/bus.h> 8793185c74SWarner Losh #include <machine/bus.h> 8893185c74SWarner Losh #include <sys/rman.h> 8993185c74SWarner Losh #include <machine/resource.h> 9093185c74SWarner Losh #include <sys/module.h> 9193185c74SWarner Losh 9293185c74SWarner Losh #include <dev/pci/pcireg.h> 9393185c74SWarner Losh #include <dev/pci/pcivar.h> 944edef187SJohn Baldwin #include <dev/pci/pcib_private.h> 9593185c74SWarner Losh 9693185c74SWarner Losh #include <dev/pccard/pccardreg.h> 9793185c74SWarner Losh #include <dev/pccard/pccardvar.h> 9893185c74SWarner Losh 9993185c74SWarner Losh #include <dev/exca/excareg.h> 10093185c74SWarner Losh #include <dev/exca/excavar.h> 10193185c74SWarner Losh 10293185c74SWarner Losh #include <dev/pccbb/pccbbreg.h> 10393185c74SWarner Losh #include <dev/pccbb/pccbbvar.h> 10493185c74SWarner Losh 10593185c74SWarner Losh #include "power_if.h" 10693185c74SWarner Losh #include "card_if.h" 10793185c74SWarner Losh #include "pcib_if.h" 10893185c74SWarner Losh 10993185c74SWarner Losh #define DPRINTF(x) do { if (cbb_debug) printf x; } while (0) 11093185c74SWarner Losh #define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0) 11193185c74SWarner Losh 11293185c74SWarner Losh #define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \ 11393185c74SWarner Losh pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE) 11493185c74SWarner Losh #define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \ 11593185c74SWarner Losh pci_write_config(DEV, REG, ( \ 11693185c74SWarner Losh pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE) 11793185c74SWarner Losh 11893185c74SWarner Losh static void cbb_chipinit(struct cbb_softc *sc); 1195b9ee137SWarner Losh static int cbb_pci_filt(void *arg); 12093185c74SWarner Losh 12193185c74SWarner Losh static struct yenta_chipinfo { 12293185c74SWarner Losh uint32_t yc_id; 12393185c74SWarner Losh const char *yc_name; 12493185c74SWarner Losh int yc_chiptype; 12593185c74SWarner Losh } yc_chipsets[] = { 12693185c74SWarner Losh /* Texas Instruments chips */ 12793185c74SWarner Losh {PCIC_ID_TI1031, "TI1031 PCI-PC Card Bridge", CB_TI113X}, 12893185c74SWarner Losh {PCIC_ID_TI1130, "TI1130 PCI-CardBus Bridge", CB_TI113X}, 12993185c74SWarner Losh {PCIC_ID_TI1131, "TI1131 PCI-CardBus Bridge", CB_TI113X}, 13093185c74SWarner Losh 13193185c74SWarner Losh {PCIC_ID_TI1210, "TI1210 PCI-CardBus Bridge", CB_TI12XX}, 13293185c74SWarner Losh {PCIC_ID_TI1211, "TI1211 PCI-CardBus Bridge", CB_TI12XX}, 13393185c74SWarner Losh {PCIC_ID_TI1220, "TI1220 PCI-CardBus Bridge", CB_TI12XX}, 13493185c74SWarner Losh {PCIC_ID_TI1221, "TI1221 PCI-CardBus Bridge", CB_TI12XX}, 13593185c74SWarner Losh {PCIC_ID_TI1225, "TI1225 PCI-CardBus Bridge", CB_TI12XX}, 13693185c74SWarner Losh {PCIC_ID_TI1250, "TI1250 PCI-CardBus Bridge", CB_TI125X}, 13793185c74SWarner Losh {PCIC_ID_TI1251, "TI1251 PCI-CardBus Bridge", CB_TI125X}, 13893185c74SWarner Losh {PCIC_ID_TI1251B,"TI1251B PCI-CardBus Bridge",CB_TI125X}, 13993185c74SWarner Losh {PCIC_ID_TI1260, "TI1260 PCI-CardBus Bridge", CB_TI12XX}, 14093185c74SWarner Losh {PCIC_ID_TI1260B,"TI1260B PCI-CardBus Bridge",CB_TI12XX}, 14193185c74SWarner Losh {PCIC_ID_TI1410, "TI1410 PCI-CardBus Bridge", CB_TI12XX}, 14293185c74SWarner Losh {PCIC_ID_TI1420, "TI1420 PCI-CardBus Bridge", CB_TI12XX}, 14393185c74SWarner Losh {PCIC_ID_TI1421, "TI1421 PCI-CardBus Bridge", CB_TI12XX}, 14493185c74SWarner Losh {PCIC_ID_TI1450, "TI1450 PCI-CardBus Bridge", CB_TI125X}, /*SIC!*/ 14593185c74SWarner Losh {PCIC_ID_TI1451, "TI1451 PCI-CardBus Bridge", CB_TI12XX}, 14693185c74SWarner Losh {PCIC_ID_TI1510, "TI1510 PCI-CardBus Bridge", CB_TI12XX}, 14793185c74SWarner Losh {PCIC_ID_TI1520, "TI1520 PCI-CardBus Bridge", CB_TI12XX}, 14893185c74SWarner Losh {PCIC_ID_TI4410, "TI4410 PCI-CardBus Bridge", CB_TI12XX}, 14993185c74SWarner Losh {PCIC_ID_TI4450, "TI4450 PCI-CardBus Bridge", CB_TI12XX}, 15093185c74SWarner Losh {PCIC_ID_TI4451, "TI4451 PCI-CardBus Bridge", CB_TI12XX}, 15193185c74SWarner Losh {PCIC_ID_TI4510, "TI4510 PCI-CardBus Bridge", CB_TI12XX}, 152aafbf20dSWarner Losh {PCIC_ID_TI6411, "TI6411 PCI-CardBus Bridge", CB_TI12XX}, 153aafbf20dSWarner Losh {PCIC_ID_TI6420, "TI6420 PCI-CardBus Bridge", CB_TI12XX}, 154aafbf20dSWarner Losh {PCIC_ID_TI6420SC, "TI6420 PCI-CardBus Bridge", CB_TI12XX}, 155aafbf20dSWarner Losh {PCIC_ID_TI7410, "TI7410 PCI-CardBus Bridge", CB_TI12XX}, 156aafbf20dSWarner Losh {PCIC_ID_TI7510, "TI7510 PCI-CardBus Bridge", CB_TI12XX}, 157aafbf20dSWarner Losh {PCIC_ID_TI7610, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, 158aafbf20dSWarner Losh {PCIC_ID_TI7610M, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, 159aafbf20dSWarner Losh {PCIC_ID_TI7610SD, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, 160aafbf20dSWarner Losh {PCIC_ID_TI7610MS, "TI7610 PCI-CardBus Bridge", CB_TI12XX}, 16193185c74SWarner Losh 16293185c74SWarner Losh /* ENE */ 16393185c74SWarner Losh {PCIC_ID_ENE_CB710, "ENE CB710 PCI-CardBus Bridge", CB_TI12XX}, 16493185c74SWarner Losh {PCIC_ID_ENE_CB720, "ENE CB720 PCI-CardBus Bridge", CB_TI12XX}, 16593185c74SWarner Losh {PCIC_ID_ENE_CB1211, "ENE CB1211 PCI-CardBus Bridge", CB_TI12XX}, 16693185c74SWarner Losh {PCIC_ID_ENE_CB1225, "ENE CB1225 PCI-CardBus Bridge", CB_TI12XX}, 16793185c74SWarner Losh {PCIC_ID_ENE_CB1410, "ENE CB1410 PCI-CardBus Bridge", CB_TI12XX}, 16893185c74SWarner Losh {PCIC_ID_ENE_CB1420, "ENE CB1420 PCI-CardBus Bridge", CB_TI12XX}, 16993185c74SWarner Losh 17093185c74SWarner Losh /* Ricoh chips */ 17193185c74SWarner Losh {PCIC_ID_RICOH_RL5C465, "RF5C465 PCI-CardBus Bridge", CB_RF5C46X}, 17293185c74SWarner Losh {PCIC_ID_RICOH_RL5C466, "RF5C466 PCI-CardBus Bridge", CB_RF5C46X}, 17393185c74SWarner Losh {PCIC_ID_RICOH_RL5C475, "RF5C475 PCI-CardBus Bridge", CB_RF5C47X}, 17493185c74SWarner Losh {PCIC_ID_RICOH_RL5C476, "RF5C476 PCI-CardBus Bridge", CB_RF5C47X}, 17593185c74SWarner Losh {PCIC_ID_RICOH_RL5C477, "RF5C477 PCI-CardBus Bridge", CB_RF5C47X}, 17693185c74SWarner Losh {PCIC_ID_RICOH_RL5C478, "RF5C478 PCI-CardBus Bridge", CB_RF5C47X}, 17793185c74SWarner Losh 17893185c74SWarner Losh /* Toshiba products */ 17993185c74SWarner Losh {PCIC_ID_TOPIC95, "ToPIC95 PCI-CardBus Bridge", CB_TOPIC95}, 18093185c74SWarner Losh {PCIC_ID_TOPIC95B, "ToPIC95B PCI-CardBus Bridge", CB_TOPIC95}, 18193185c74SWarner Losh {PCIC_ID_TOPIC97, "ToPIC97 PCI-CardBus Bridge", CB_TOPIC97}, 18293185c74SWarner Losh {PCIC_ID_TOPIC100, "ToPIC100 PCI-CardBus Bridge", CB_TOPIC97}, 18393185c74SWarner Losh 18493185c74SWarner Losh /* Cirrus Logic */ 18593185c74SWarner Losh {PCIC_ID_CLPD6832, "CLPD6832 PCI-CardBus Bridge", CB_CIRRUS}, 18693185c74SWarner Losh {PCIC_ID_CLPD6833, "CLPD6833 PCI-CardBus Bridge", CB_CIRRUS}, 18793185c74SWarner Losh {PCIC_ID_CLPD6834, "CLPD6834 PCI-CardBus Bridge", CB_CIRRUS}, 18893185c74SWarner Losh 18993185c74SWarner Losh /* 02Micro */ 19093185c74SWarner Losh {PCIC_ID_OZ6832, "O2Micro OZ6832/6833 PCI-CardBus Bridge", CB_O2MICRO}, 19193185c74SWarner Losh {PCIC_ID_OZ6860, "O2Micro OZ6836/6860 PCI-CardBus Bridge", CB_O2MICRO}, 19293185c74SWarner Losh {PCIC_ID_OZ6872, "O2Micro OZ6812/6872 PCI-CardBus Bridge", CB_O2MICRO}, 19393185c74SWarner Losh {PCIC_ID_OZ6912, "O2Micro OZ6912/6972 PCI-CardBus Bridge", CB_O2MICRO}, 19493185c74SWarner Losh {PCIC_ID_OZ6922, "O2Micro OZ6922 PCI-CardBus Bridge", CB_O2MICRO}, 19593185c74SWarner Losh {PCIC_ID_OZ6933, "O2Micro OZ6933 PCI-CardBus Bridge", CB_O2MICRO}, 19693185c74SWarner Losh {PCIC_ID_OZ711E1, "O2Micro OZ711E1 PCI-CardBus Bridge", CB_O2MICRO}, 197870d0014SWarner Losh {PCIC_ID_OZ711EC1, "O2Micro OZ711EC1/M1 PCI-CardBus Bridge", CB_O2MICRO}, 198870d0014SWarner Losh {PCIC_ID_OZ711E2, "O2Micro OZ711E2 PCI-CardBus Bridge", CB_O2MICRO}, 1992969a6a9SWarner Losh {PCIC_ID_OZ711M1, "O2Micro OZ711M1 PCI-CardBus Bridge", CB_O2MICRO}, 200870d0014SWarner Losh {PCIC_ID_OZ711M2, "O2Micro OZ711M2 PCI-CardBus Bridge", CB_O2MICRO}, 201870d0014SWarner Losh {PCIC_ID_OZ711M3, "O2Micro OZ711M3 PCI-CardBus Bridge", CB_O2MICRO}, 202870d0014SWarner Losh 203870d0014SWarner Losh /* SMC */ 204550a6248SWarner Losh {PCIC_ID_SMC_34C90, "SMC 34C90 PCI-CardBus Bridge", CB_CIRRUS}, 20593185c74SWarner Losh 20693185c74SWarner Losh /* sentinel */ 20793185c74SWarner Losh {0 /* null id */, "unknown", CB_UNKNOWN}, 20893185c74SWarner Losh }; 20993185c74SWarner Losh 21093185c74SWarner Losh /************************************************************************/ 21193185c74SWarner Losh /* Probe/Attach */ 21293185c74SWarner Losh /************************************************************************/ 21393185c74SWarner Losh 21493185c74SWarner Losh static int 21593185c74SWarner Losh cbb_chipset(uint32_t pci_id, const char **namep) 21693185c74SWarner Losh { 21793185c74SWarner Losh struct yenta_chipinfo *ycp; 21893185c74SWarner Losh 21993185c74SWarner Losh for (ycp = yc_chipsets; ycp->yc_id != 0 && pci_id != ycp->yc_id; ++ycp) 22093185c74SWarner Losh continue; 22193185c74SWarner Losh if (namep != NULL) 22293185c74SWarner Losh *namep = ycp->yc_name; 22393185c74SWarner Losh return (ycp->yc_chiptype); 22493185c74SWarner Losh } 22593185c74SWarner Losh 22693185c74SWarner Losh static int 22793185c74SWarner Losh cbb_pci_probe(device_t brdev) 22893185c74SWarner Losh { 22993185c74SWarner Losh const char *name; 23093185c74SWarner Losh uint32_t progif; 2316e31e5ebSWarner Losh uint32_t baseclass; 23293185c74SWarner Losh uint32_t subclass; 23393185c74SWarner Losh 23493185c74SWarner Losh /* 23593185c74SWarner Losh * Do we know that we support the chipset? If so, then we 23693185c74SWarner Losh * accept the device. 23793185c74SWarner Losh */ 23893185c74SWarner Losh if (cbb_chipset(pci_get_devid(brdev), &name) != CB_UNKNOWN) { 23993185c74SWarner Losh device_set_desc(brdev, name); 2406b9907e7SWarner Losh return (BUS_PROBE_DEFAULT); 24193185c74SWarner Losh } 24293185c74SWarner Losh 24393185c74SWarner Losh /* 24493185c74SWarner Losh * We do support generic CardBus bridges. All that we've seen 24593185c74SWarner Losh * to date have progif 0 (the Yenta spec, and successors mandate 2466b9907e7SWarner Losh * this). 24793185c74SWarner Losh */ 2486e31e5ebSWarner Losh baseclass = pci_get_class(brdev); 24993185c74SWarner Losh subclass = pci_get_subclass(brdev); 25093185c74SWarner Losh progif = pci_get_progif(brdev); 2516e31e5ebSWarner Losh if (baseclass == PCIC_BRIDGE && 2526e31e5ebSWarner Losh subclass == PCIS_BRIDGE_CARDBUS && progif == 0) { 25393185c74SWarner Losh device_set_desc(brdev, "PCI-CardBus Bridge"); 254a3f223e2SWarner Losh return (BUS_PROBE_GENERIC); 25593185c74SWarner Losh } 25693185c74SWarner Losh return (ENXIO); 25793185c74SWarner Losh } 25893185c74SWarner Losh 25993185c74SWarner Losh /* 26093185c74SWarner Losh * Print out the config space 26193185c74SWarner Losh */ 26293185c74SWarner Losh static void 26393185c74SWarner Losh cbb_print_config(device_t dev) 26493185c74SWarner Losh { 26593185c74SWarner Losh int i; 26693185c74SWarner Losh 26793185c74SWarner Losh device_printf(dev, "PCI Configuration space:"); 26893185c74SWarner Losh for (i = 0; i < 256; i += 4) { 26993185c74SWarner Losh if (i % 16 == 0) 27093185c74SWarner Losh printf("\n 0x%02x: ", i); 27193185c74SWarner Losh printf("0x%08x ", pci_read_config(dev, i, 4)); 27293185c74SWarner Losh } 27393185c74SWarner Losh printf("\n"); 27493185c74SWarner Losh } 27593185c74SWarner Losh 27693185c74SWarner Losh static int 27793185c74SWarner Losh cbb_pci_attach(device_t brdev) 27893185c74SWarner Losh { 27993185c74SWarner Losh struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); 280fef03554SWarner Losh struct sysctl_ctx_list *sctx; 281fef03554SWarner Losh struct sysctl_oid *soid; 282673c9ca9SWarner Losh int rid; 283673c9ca9SWarner Losh device_t parent; 28493185c74SWarner Losh 28593185c74SWarner Losh parent = device_get_parent(brdev); 28693185c74SWarner Losh mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF); 28793185c74SWarner Losh sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL); 28893185c74SWarner Losh sc->dev = brdev; 28993185c74SWarner Losh sc->cbdev = NULL; 29055aaf894SMarius Strobl sc->domain = pci_get_domain(brdev); 291673c9ca9SWarner Losh sc->pribus = pcib_get_bus(parent); 2924edef187SJohn Baldwin pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); 2934edef187SJohn Baldwin pcib_setup_secbus(brdev, &sc->bus, 1); 29493185c74SWarner Losh SLIST_INIT(&sc->rl); 29593185c74SWarner Losh 29693185c74SWarner Losh rid = CBBR_SOCKBASE; 29793185c74SWarner Losh sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid, 29893185c74SWarner Losh RF_ACTIVE); 29993185c74SWarner Losh if (!sc->base_res) { 30093185c74SWarner Losh device_printf(brdev, "Could not map register memory\n"); 30193185c74SWarner Losh mtx_destroy(&sc->mtx); 30293185c74SWarner Losh return (ENOMEM); 30393185c74SWarner Losh } else { 304da1b038aSJustin Hibbits DEVPRINTF((brdev, "Found memory at %jx\n", 30593185c74SWarner Losh rman_get_start(sc->base_res))); 30693185c74SWarner Losh } 30793185c74SWarner Losh 3082e1d04aeSWarner Losh /* attach children */ 309*5b56413dSWarner Losh sc->cbdev = device_add_child(brdev, "cardbus", DEVICE_UNIT_ANY); 3102e1d04aeSWarner Losh if (sc->cbdev == NULL) 3112e1d04aeSWarner Losh DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n")); 3122e1d04aeSWarner Losh else if (device_probe_and_attach(sc->cbdev) != 0) 3132e1d04aeSWarner Losh DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n")); 3142e1d04aeSWarner Losh 31593185c74SWarner Losh sc->bst = rman_get_bustag(sc->base_res); 31693185c74SWarner Losh sc->bsh = rman_get_bushandle(sc->base_res); 3177b9439d0SWarner Losh exca_init(&sc->exca, brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET); 3187b9439d0SWarner Losh sc->exca.flags |= EXCA_HAS_MEMREG_WIN; 3197b9439d0SWarner Losh sc->exca.chipset = EXCA_CARDBUS; 32093185c74SWarner Losh sc->chipinit = cbb_chipinit; 321b45c7d14SWarner Losh sc->chipinit(sc); 32293185c74SWarner Losh 323fef03554SWarner Losh /*Sysctls*/ 324fef03554SWarner Losh sctx = device_get_sysctl_ctx(brdev); 325fef03554SWarner Losh soid = device_get_sysctl_tree(brdev); 32655aaf894SMarius Strobl SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 32755aaf894SMarius Strobl CTLFLAG_RD, &sc->domain, 0, "Domain number"); 328fef03554SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 329fef03554SWarner Losh CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); 330fef03554SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 3314edef187SJohn Baldwin CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); 332fef03554SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 3334edef187SJohn Baldwin CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); 3346e878bc7SWarner Losh #if 0 3356e878bc7SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory", 3366e878bc7SWarner Losh CTLFLAG_RD, &sc->subbus, 0, "Memory window open"); 3376e878bc7SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "premem", 338b790c193SPedro F. Giffuni CTLFLAG_RD, &sc->subbus, 0, "Prefetch memory window open"); 3396e878bc7SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io1", 3406e878bc7SWarner Losh CTLFLAG_RD, &sc->subbus, 0, "io range 1 open"); 3416e878bc7SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io2", 3426e878bc7SWarner Losh CTLFLAG_RD, &sc->subbus, 0, "io range 2 open"); 3436e878bc7SWarner Losh #endif 344fef03554SWarner Losh 34593185c74SWarner Losh /* Map and establish the interrupt. */ 34693185c74SWarner Losh rid = 0; 34793185c74SWarner Losh sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid, 34893185c74SWarner Losh RF_SHAREABLE | RF_ACTIVE); 34993185c74SWarner Losh if (sc->irq_res == NULL) { 3507dcc4efbSWarner Losh device_printf(brdev, "Unable to map IRQ...\n"); 35193185c74SWarner Losh goto err; 35293185c74SWarner Losh } 35393185c74SWarner Losh 35493185c74SWarner Losh if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE, 3555b9ee137SWarner Losh cbb_pci_filt, NULL, sc, &sc->intrhand)) { 3567dcc4efbSWarner Losh device_printf(brdev, "couldn't establish interrupt\n"); 35793185c74SWarner Losh goto err; 35893185c74SWarner Losh } 35993185c74SWarner Losh 360b45c7d14SWarner Losh /* reset 16-bit pcmcia bus */ 3617b9439d0SWarner Losh exca_clrb(&sc->exca, EXCA_INTR, EXCA_INTR_RESET); 362b45c7d14SWarner Losh 363b45c7d14SWarner Losh /* turn off power */ 364b45c7d14SWarner Losh cbb_power(brdev, CARD_OFF); 365b45c7d14SWarner Losh 366b45c7d14SWarner Losh /* CSC Interrupt: Card detect interrupt on */ 367b45c7d14SWarner Losh cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); 368b45c7d14SWarner Losh 369b45c7d14SWarner Losh /* reset interrupt */ 370b45c7d14SWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT)); 37193185c74SWarner Losh 37293185c74SWarner Losh if (bootverbose) 37393185c74SWarner Losh cbb_print_config(brdev); 37493185c74SWarner Losh 37593185c74SWarner Losh /* Start the thread */ 3763745c395SJulian Elischer if (kproc_create(cbb_event_thread, sc, &sc->event_thread, 0, 0, 3777dcc4efbSWarner Losh "%s event thread", device_get_nameunit(brdev))) { 37893185c74SWarner Losh device_printf(brdev, "unable to create event thread.\n"); 37993185c74SWarner Losh panic("cbb_create_event_thread"); 38093185c74SWarner Losh } 381853a10a5SAndrew Thompson sc->sc_root_token = root_mount_hold(device_get_nameunit(sc->dev)); 38293185c74SWarner Losh return (0); 38393185c74SWarner Losh err: 38493185c74SWarner Losh if (sc->irq_res) 38593185c74SWarner Losh bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); 38693185c74SWarner Losh if (sc->base_res) { 38793185c74SWarner Losh bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, 38893185c74SWarner Losh sc->base_res); 38993185c74SWarner Losh } 39093185c74SWarner Losh mtx_destroy(&sc->mtx); 39193185c74SWarner Losh return (ENOMEM); 39293185c74SWarner Losh } 39393185c74SWarner Losh 3946f33eaa5SJohn Baldwin static int 3956f33eaa5SJohn Baldwin cbb_pci_detach(device_t brdev) 3966f33eaa5SJohn Baldwin { 3976f33eaa5SJohn Baldwin struct cbb_softc *sc = device_get_softc(brdev); 3986f33eaa5SJohn Baldwin int error; 3996f33eaa5SJohn Baldwin 4006f33eaa5SJohn Baldwin error = cbb_detach(brdev); 4016f33eaa5SJohn Baldwin if (error == 0) 4026f33eaa5SJohn Baldwin pcib_free_secbus(brdev, &sc->bus); 4036f33eaa5SJohn Baldwin return (error); 4046f33eaa5SJohn Baldwin } 4056f33eaa5SJohn Baldwin 40693185c74SWarner Losh static void 40793185c74SWarner Losh cbb_chipinit(struct cbb_softc *sc) 40893185c74SWarner Losh { 40993185c74SWarner Losh uint32_t mux, sysctrl, reg; 41093185c74SWarner Losh 41193185c74SWarner Losh /* Set CardBus latency timer */ 412f2d55827SJohn Baldwin if (pci_read_config(sc->dev, PCIR_SECLAT_2, 1) < 0x20) 413f2d55827SJohn Baldwin pci_write_config(sc->dev, PCIR_SECLAT_2, 0x20, 1); 41493185c74SWarner Losh 41593185c74SWarner Losh /* Set PCI latency timer */ 41693185c74SWarner Losh if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20) 41793185c74SWarner Losh pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1); 41893185c74SWarner Losh 419b790c193SPedro F. Giffuni /* Enable DMA, memory access for this card and I/O access for children */ 420c68534f1SScott Long pci_enable_busmaster(sc->dev); 421966e7298SWarner Losh pci_enable_io(sc->dev, SYS_RES_IOPORT); 422966e7298SWarner Losh pci_enable_io(sc->dev, SYS_RES_MEMORY); 42393185c74SWarner Losh 42493185c74SWarner Losh /* disable Legacy IO */ 42593185c74SWarner Losh switch (sc->chipset) { 42693185c74SWarner Losh case CB_RF5C46X: 42793185c74SWarner Losh PCI_MASK_CONFIG(sc->dev, CBBR_BRIDGECTRL, 42893185c74SWarner Losh & ~(CBBM_BRIDGECTRL_RL_3E0_EN | 42993185c74SWarner Losh CBBM_BRIDGECTRL_RL_3E2_EN), 2); 43093185c74SWarner Losh break; 43193185c74SWarner Losh default: 43293185c74SWarner Losh pci_write_config(sc->dev, CBBR_LEGACY, 0x0, 4); 43393185c74SWarner Losh break; 43493185c74SWarner Losh } 43593185c74SWarner Losh 43693185c74SWarner Losh /* Use PCI interrupt for interrupt routing */ 43793185c74SWarner Losh PCI_MASK2_CONFIG(sc->dev, CBBR_BRIDGECTRL, 43893185c74SWarner Losh & ~(CBBM_BRIDGECTRL_MASTER_ABORT | 439f99298f4SWarner Losh CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN), 44093185c74SWarner Losh | CBBM_BRIDGECTRL_WRITE_POST_EN, 44193185c74SWarner Losh 2); 44293185c74SWarner Losh 44393185c74SWarner Losh /* 44493185c74SWarner Losh * XXX this should be a function table, ala OLDCARD. This means 44593185c74SWarner Losh * that we could more easily support ISA interrupts for pccard 44693185c74SWarner Losh * cards if we had to. 44793185c74SWarner Losh */ 44893185c74SWarner Losh switch (sc->chipset) { 44993185c74SWarner Losh case CB_TI113X: 45093185c74SWarner Losh /* 45193185c74SWarner Losh * The TI 1031, TI 1130 and TI 1131 all require another bit 45293185c74SWarner Losh * be set to enable PCI routing of interrupts, and then 45393185c74SWarner Losh * a bit for each of the CSC and Function interrupts we 45493185c74SWarner Losh * want routed. 45593185c74SWarner Losh */ 45693185c74SWarner Losh PCI_MASK_CONFIG(sc->dev, CBBR_CBCTRL, 45793185c74SWarner Losh | CBBM_CBCTRL_113X_PCI_INTR | 45893185c74SWarner Losh CBBM_CBCTRL_113X_PCI_CSC | CBBM_CBCTRL_113X_PCI_IRQ_EN, 45993185c74SWarner Losh 1); 46093185c74SWarner Losh PCI_MASK_CONFIG(sc->dev, CBBR_DEVCTRL, 46193185c74SWarner Losh & ~(CBBM_DEVCTRL_INT_SERIAL | 46293185c74SWarner Losh CBBM_DEVCTRL_INT_PCI), 1); 46393185c74SWarner Losh break; 46493185c74SWarner Losh case CB_TI12XX: 46593185c74SWarner Losh /* 46693185c74SWarner Losh * Some TI 12xx (and [14][45]xx) based pci cards 46793185c74SWarner Losh * sometimes have issues with the MFUNC register not 46893185c74SWarner Losh * being initialized due to a bad EEPROM on board. 46993185c74SWarner Losh * Laptops that this matters on have this register 47093185c74SWarner Losh * properly initialized. 47193185c74SWarner Losh * 47293185c74SWarner Losh * The TI125X parts have a different register. 47355d793dcSWarner Losh * 47455d793dcSWarner Losh * Note: Only the lower two nibbles matter. When set 47555d793dcSWarner Losh * to 0, the MFUNC{0,1} pins are GPIO, which isn't 47655d793dcSWarner Losh * going to work out too well because we specifically 47755d793dcSWarner Losh * program these parts to parallel interrupt signalling 47855d793dcSWarner Losh * elsewhere. We preserve the upper bits of this 47955d793dcSWarner Losh * register since changing them have subtle side effects 48055d793dcSWarner Losh * for different variants of the card and are 48155d793dcSWarner Losh * extremely difficult to exaustively test. 482531258acSWarner Losh * 483531258acSWarner Losh * Also, the TI 1510/1520 changed the default for the MFUNC 484531258acSWarner Losh * register from 0x0 to 0x1000 to enable IRQSER by default. 485531258acSWarner Losh * We want to be careful to avoid overriding that, and the 486531258acSWarner Losh * below test will do that. Should this check prove to be 487531258acSWarner Losh * too permissive, we should just check against 0 and 0x1000 488531258acSWarner Losh * and not touch it otherwise. 48993185c74SWarner Losh */ 49093185c74SWarner Losh mux = pci_read_config(sc->dev, CBBR_MFUNC, 4); 49193185c74SWarner Losh sysctrl = pci_read_config(sc->dev, CBBR_SYSCTRL, 4); 49255d793dcSWarner Losh if ((mux & (CBBM_MFUNC_PIN0 | CBBM_MFUNC_PIN1)) == 0) { 49393185c74SWarner Losh mux = (mux & ~CBBM_MFUNC_PIN0) | 49493185c74SWarner Losh CBBM_MFUNC_PIN0_INTA; 49593185c74SWarner Losh if ((sysctrl & CBBM_SYSCTRL_INTRTIE) == 0) 49693185c74SWarner Losh mux = (mux & ~CBBM_MFUNC_PIN1) | 49793185c74SWarner Losh CBBM_MFUNC_PIN1_INTB; 49893185c74SWarner Losh pci_write_config(sc->dev, CBBR_MFUNC, mux, 4); 49993185c74SWarner Losh } 50093185c74SWarner Losh /*FALLTHROUGH*/ 50193185c74SWarner Losh case CB_TI125X: 50293185c74SWarner Losh /* 50393185c74SWarner Losh * Disable zoom video. Some machines initialize this 50493185c74SWarner Losh * improperly and exerpience has shown that this helps 50555d793dcSWarner Losh * prevent strange behavior. We don't support zoom 50655d793dcSWarner Losh * video anyway, so no harm can come from this. 50793185c74SWarner Losh */ 50893185c74SWarner Losh pci_write_config(sc->dev, CBBR_MMCTRL, 0, 4); 50993185c74SWarner Losh break; 51093185c74SWarner Losh case CB_O2MICRO: 51193185c74SWarner Losh /* 51293185c74SWarner Losh * Issue #1: INT# generated at the same time as 51393185c74SWarner Losh * selected ISA IRQ. When IREQ# or STSCHG# is active, 51493185c74SWarner Losh * in addition to the ISA IRQ being generated, INT# 51593185c74SWarner Losh * will also be generated at the same time. 51693185c74SWarner Losh * 51793185c74SWarner Losh * Some of the older controllers have an issue in 51893185c74SWarner Losh * which the slot's PCI INT# will be asserted whenever 51993185c74SWarner Losh * IREQ# or STSCGH# is asserted even if ExCA registers 52093185c74SWarner Losh * 03h or 05h have an ISA IRQ selected. 52193185c74SWarner Losh * 52293185c74SWarner Losh * The fix for this issue, which will work for any 52393185c74SWarner Losh * controller (old or new), is to set ExCA registers 52493185c74SWarner Losh * 3Ah (slot 0) & 7Ah (slot 1) bits 7:4 = 1010b. 52593185c74SWarner Losh * These bits are undocumented. By setting this 52693185c74SWarner Losh * register (of each slot) to '1010xxxxb' a routing of 52793185c74SWarner Losh * IREQ# to INTC# and STSCHG# to INTC# is selected. 52893185c74SWarner Losh * Since INTC# isn't connected there will be no 52993185c74SWarner Losh * unexpected PCI INT when IREQ# or STSCHG# is active. 53093185c74SWarner Losh * However, INTA# (slot 0) or INTB# (slot 1) will 53193185c74SWarner Losh * still be correctly generated if NO ISA IRQ is 53293185c74SWarner Losh * selected (ExCA regs 03h or 05h are cleared). 53393185c74SWarner Losh */ 5347b9439d0SWarner Losh reg = exca_getb(&sc->exca, EXCA_O2MICRO_CTRL_C); 53593185c74SWarner Losh reg = (reg & 0x0f) | 53693185c74SWarner Losh EXCA_O2CC_IREQ_INTC | EXCA_O2CC_STSCHG_INTC; 5377b9439d0SWarner Losh exca_putb(&sc->exca, EXCA_O2MICRO_CTRL_C, reg); 53893185c74SWarner Losh break; 53993185c74SWarner Losh case CB_TOPIC97: 54093185c74SWarner Losh /* 54193185c74SWarner Losh * Disable Zoom Video, ToPIC 97, 100. 54293185c74SWarner Losh */ 543673c9ca9SWarner Losh pci_write_config(sc->dev, TOPIC97_ZV_CONTROL, 0, 1); 54493185c74SWarner Losh /* 54593185c74SWarner Losh * ToPIC 97, 100 54693185c74SWarner Losh * At offset 0xa1: INTERRUPT CONTROL register 54793185c74SWarner Losh * 0x1: Turn on INT interrupts. 54893185c74SWarner Losh */ 549673c9ca9SWarner Losh PCI_MASK_CONFIG(sc->dev, TOPIC_INTCTRL, 550673c9ca9SWarner Losh | TOPIC97_INTCTRL_INTIRQSEL, 1); 551673c9ca9SWarner Losh /* 552673c9ca9SWarner Losh * ToPIC97, 100 553673c9ca9SWarner Losh * Need to assert support for low voltage cards 554673c9ca9SWarner Losh */ 5557b9439d0SWarner Losh exca_setb(&sc->exca, EXCA_TOPIC97_CTRL, 556673c9ca9SWarner Losh EXCA_TOPIC97_CTRL_LV_MASK); 55793185c74SWarner Losh goto topic_common; 55893185c74SWarner Losh case CB_TOPIC95: 55993185c74SWarner Losh /* 56093185c74SWarner Losh * SOCKETCTRL appears to be TOPIC 95/B specific 56193185c74SWarner Losh */ 562673c9ca9SWarner Losh PCI_MASK_CONFIG(sc->dev, TOPIC95_SOCKETCTRL, 563673c9ca9SWarner Losh | TOPIC95_SOCKETCTRL_SCR_IRQSEL, 4); 56493185c74SWarner Losh 56593185c74SWarner Losh topic_common:; 56693185c74SWarner Losh /* 56793185c74SWarner Losh * At offset 0xa0: SLOT CONTROL 56893185c74SWarner Losh * 0x80 Enable CardBus Functionality 56993185c74SWarner Losh * 0x40 Enable CardBus and PC Card registers 57093185c74SWarner Losh * 0x20 Lock ID in exca regs 57193185c74SWarner Losh * 0x10 Write protect ID in config regs 57293185c74SWarner Losh * Clear the rest of the bits, which defaults the slot 57393185c74SWarner Losh * in legacy mode to 0x3e0 and offset 0. (legacy 57493185c74SWarner Losh * mode is determined elsewhere) 57593185c74SWarner Losh */ 576673c9ca9SWarner Losh pci_write_config(sc->dev, TOPIC_SLOTCTRL, 577673c9ca9SWarner Losh TOPIC_SLOTCTRL_SLOTON | 578673c9ca9SWarner Losh TOPIC_SLOTCTRL_SLOTEN | 579673c9ca9SWarner Losh TOPIC_SLOTCTRL_ID_LOCK | 580673c9ca9SWarner Losh TOPIC_SLOTCTRL_ID_WP, 1); 58193185c74SWarner Losh 58293185c74SWarner Losh /* 58393185c74SWarner Losh * At offset 0xa3 Card Detect Control Register 58493185c74SWarner Losh * 0x80 CARDBUS enbale 58593185c74SWarner Losh * 0x01 Cleared for hardware change detect 58693185c74SWarner Losh */ 587673c9ca9SWarner Losh PCI_MASK2_CONFIG(sc->dev, TOPIC_CDC, 588673c9ca9SWarner Losh | TOPIC_CDC_CARDBUS, & ~TOPIC_CDC_SWDETECT, 4); 58993185c74SWarner Losh break; 59093185c74SWarner Losh } 59193185c74SWarner Losh 59293185c74SWarner Losh /* 59393185c74SWarner Losh * Need to tell ExCA registers to CSC interrupts route via PCI 59433d7325aSWarner Losh * interrupts. There are two ways to do this. One is to set 59593185c74SWarner Losh * INTR_ENABLE and the other is to set CSC to 0. Since both 59693185c74SWarner Losh * methods are mutually compatible, we do both. 59793185c74SWarner Losh */ 5987b9439d0SWarner Losh exca_putb(&sc->exca, EXCA_INTR, EXCA_INTR_ENABLE); 5997b9439d0SWarner Losh exca_putb(&sc->exca, EXCA_CSC_INTR, 0); 60093185c74SWarner Losh 60193185c74SWarner Losh cbb_disable_func_intr(sc); 60293185c74SWarner Losh 60393185c74SWarner Losh /* close all memory and io windows */ 60493185c74SWarner Losh pci_write_config(sc->dev, CBBR_MEMBASE0, 0xffffffff, 4); 60593185c74SWarner Losh pci_write_config(sc->dev, CBBR_MEMLIMIT0, 0, 4); 60693185c74SWarner Losh pci_write_config(sc->dev, CBBR_MEMBASE1, 0xffffffff, 4); 60793185c74SWarner Losh pci_write_config(sc->dev, CBBR_MEMLIMIT1, 0, 4); 60893185c74SWarner Losh pci_write_config(sc->dev, CBBR_IOBASE0, 0xffffffff, 4); 60993185c74SWarner Losh pci_write_config(sc->dev, CBBR_IOLIMIT0, 0, 4); 61093185c74SWarner Losh pci_write_config(sc->dev, CBBR_IOBASE1, 0xffffffff, 4); 61193185c74SWarner Losh pci_write_config(sc->dev, CBBR_IOLIMIT1, 0, 4); 61293185c74SWarner Losh } 61393185c74SWarner Losh 6143f7d3c1eSWarner Losh static int 6153f7d3c1eSWarner Losh cbb_route_interrupt(device_t pcib, device_t dev, int pin) 6163f7d3c1eSWarner Losh { 6173f7d3c1eSWarner Losh struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(pcib); 6183f7d3c1eSWarner Losh 6193f7d3c1eSWarner Losh return (rman_get_start(sc->irq_res)); 6203f7d3c1eSWarner Losh } 6213f7d3c1eSWarner Losh 6227490082fSWarner Losh static int 6237490082fSWarner Losh cbb_pci_shutdown(device_t brdev) 6247490082fSWarner Losh { 6257490082fSWarner Losh struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); 6267490082fSWarner Losh 6277490082fSWarner Losh /* 628e6830016SWarner Losh * We're about to pull the rug out from the card, so mark it as 629e6830016SWarner Losh * gone to prevent harm. 630e6830016SWarner Losh */ 631e6830016SWarner Losh sc->cardok = 0; 632e6830016SWarner Losh 633e6830016SWarner Losh /* 6347490082fSWarner Losh * Place the cards in reset, turn off the interrupts and power 6357490082fSWarner Losh * down the socket. 6367490082fSWarner Losh */ 6377490082fSWarner Losh PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2); 6387b9439d0SWarner Losh exca_clrb(&sc->exca, EXCA_INTR, EXCA_INTR_RESET); 6397490082fSWarner Losh cbb_set(sc, CBB_SOCKET_MASK, 0); 6407490082fSWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, 0xffffffff); 6417490082fSWarner Losh cbb_power(brdev, CARD_OFF); 6427490082fSWarner Losh 6437490082fSWarner Losh /* 6447490082fSWarner Losh * For paranoia, turn off all address decoding. Really not needed, 6457490082fSWarner Losh * it seems, but it can't hurt 6467490082fSWarner Losh */ 6477b9439d0SWarner Losh exca_putb(&sc->exca, EXCA_ADDRWIN_ENABLE, 0); 6487490082fSWarner Losh pci_write_config(brdev, CBBR_MEMBASE0, 0, 4); 6497490082fSWarner Losh pci_write_config(brdev, CBBR_MEMLIMIT0, 0, 4); 6507490082fSWarner Losh pci_write_config(brdev, CBBR_MEMBASE1, 0, 4); 6517490082fSWarner Losh pci_write_config(brdev, CBBR_MEMLIMIT1, 0, 4); 6527490082fSWarner Losh pci_write_config(brdev, CBBR_IOBASE0, 0, 4); 6537490082fSWarner Losh pci_write_config(brdev, CBBR_IOLIMIT0, 0, 4); 6547490082fSWarner Losh pci_write_config(brdev, CBBR_IOBASE1, 0, 4); 6557490082fSWarner Losh pci_write_config(brdev, CBBR_IOLIMIT1, 0, 4); 6567490082fSWarner Losh return (0); 6577490082fSWarner Losh } 6587490082fSWarner Losh 6595b9ee137SWarner Losh static int 6605b9ee137SWarner Losh cbb_pci_filt(void *arg) 661fc7119a7SWarner Losh { 662fc7119a7SWarner Losh struct cbb_softc *sc = arg; 663fc7119a7SWarner Losh uint32_t sockevent; 664d0493c85SWarner Losh uint8_t csc; 6655b9ee137SWarner Losh int retval = FILTER_STRAY; 666fc7119a7SWarner Losh 667fc7119a7SWarner Losh /* 668d0493c85SWarner Losh * Some chips also require us to read the old ExCA registe for card 669d0493c85SWarner Losh * status change when we route CSC vis PCI. This isn't supposed to be 670d0493c85SWarner Losh * required, but it clears the interrupt state on some chipsets. 671d0493c85SWarner Losh * Maybe there's a setting that would obviate its need. Maybe we 672d0493c85SWarner Losh * should test the status bits and deal with them, but so far we've 673d0493c85SWarner Losh * not found any machines that don't also give us the socket status 674d0493c85SWarner Losh * indication above. 675d0493c85SWarner Losh * 676d0493c85SWarner Losh * This call used to be unconditional. However, further research 677d0493c85SWarner Losh * suggests that we hit this condition when the card READY interrupt 678d0493c85SWarner Losh * fired. So now we only read it for 16-bit cards, and we only claim 679d0493c85SWarner Losh * the interrupt if READY is set. If this still causes problems, then 680d0493c85SWarner Losh * the next step would be to read this if we have a 16-bit card *OR* 681d0493c85SWarner Losh * we have no card. We treat the READY signal as if it were the power 682d0493c85SWarner Losh * completion signal. Some bridges may double signal things here, bit 683d0493c85SWarner Losh * signalling twice should be OK since we only sleep on the powerintr 684d0493c85SWarner Losh * in one place and a double wakeup would be benign there. 685d0493c85SWarner Losh */ 686d0493c85SWarner Losh if (sc->flags & CBB_16BIT_CARD) { 6877b9439d0SWarner Losh csc = exca_getb(&sc->exca, EXCA_CSC); 688d0493c85SWarner Losh if (csc & EXCA_CSC_READY) { 689d0493c85SWarner Losh atomic_add_int(&sc->powerintr, 1); 690d0493c85SWarner Losh wakeup((void *)&sc->powerintr); 691d0493c85SWarner Losh retval = FILTER_HANDLED; 692d0493c85SWarner Losh } 693d0493c85SWarner Losh } 694d0493c85SWarner Losh 695d0493c85SWarner Losh /* 696d0493c85SWarner Losh * Read the socket event. Sometimes, the theory goes, the PCI bus is 697d0493c85SWarner Losh * so loaded that it cannot satisfy the read request, so we get 698d0493c85SWarner Losh * garbage back from the following read. We have to filter out the 699d0493c85SWarner Losh * garbage so that we don't spontaneously reset the card under high 700d0493c85SWarner Losh * load. PCI isn't supposed to act like this. No doubt this is a bug 701d0493c85SWarner Losh * in the PCI bridge chipset (or cbb brige) that's being used in 702d0493c85SWarner Losh * certain amd64 laptops today. Work around the issue by assuming 703d0493c85SWarner Losh * that any bits we don't know about being set means that we got 704d0493c85SWarner Losh * garbage. 705fc7119a7SWarner Losh */ 706fc7119a7SWarner Losh sockevent = cbb_get(sc, CBB_SOCKET_EVENT); 707fc7119a7SWarner Losh if (sockevent != 0 && (sockevent & ~CBB_SOCKET_EVENT_VALID_MASK) == 0) { 708fc7119a7SWarner Losh /* 709d0493c85SWarner Losh * If anything has happened to the socket, we assume that the 710d0493c85SWarner Losh * card is no longer OK, and we shouldn't call its ISR. We 711d0493c85SWarner Losh * set cardok as soon as we've attached the card. This helps 712d0493c85SWarner Losh * in a noisy eject, which happens all too often when users 713d0493c85SWarner Losh * are ejecting their PC Cards. 714fc7119a7SWarner Losh * 715d0493c85SWarner Losh * We use this method in preference to checking to see if the 716d0493c85SWarner Losh * card is still there because the check suffers from a race 717d0493c85SWarner Losh * condition in the bouncing case. 718fc7119a7SWarner Losh */ 719d0493c85SWarner Losh #define DELTA (CBB_SOCKET_MASK_CD) 7205b9ee137SWarner Losh if (sockevent & DELTA) { 7215b9ee137SWarner Losh cbb_clrb(sc, CBB_SOCKET_MASK, DELTA); 7225b9ee137SWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, DELTA); 7236e878bc7SWarner Losh sc->cardok = 0; 724fc7119a7SWarner Losh cbb_disable_func_intr(sc); 7255b9ee137SWarner Losh wakeup(&sc->intrhand); 726fc7119a7SWarner Losh } 727d0493c85SWarner Losh #undef DELTA 728d0493c85SWarner Losh 729fc7119a7SWarner Losh /* 730d0493c85SWarner Losh * Wakeup anybody waiting for a power interrupt. We have to 731d0493c85SWarner Losh * use atomic_add_int for wakups on other cores. 732fc7119a7SWarner Losh */ 733fc7119a7SWarner Losh if (sockevent & CBB_SOCKET_EVENT_POWER) { 7345b9ee137SWarner Losh cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_EVENT_POWER); 7355b9ee137SWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, CBB_SOCKET_EVENT_POWER); 7363e7d0bebSWarner Losh atomic_add_int(&sc->powerintr, 1); 7375b9ee137SWarner Losh wakeup((void *)&sc->powerintr); 738fc7119a7SWarner Losh } 739d0493c85SWarner Losh 740d0493c85SWarner Losh /* 741d0493c85SWarner Losh * Status change interrupts aren't presently used in the 742d0493c85SWarner Losh * rest of the driver. For now, just ACK them. 743d0493c85SWarner Losh */ 744d0493c85SWarner Losh if (sockevent & CBB_SOCKET_EVENT_CSTS) 745d0493c85SWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, CBB_SOCKET_EVENT_CSTS); 7465b9ee137SWarner Losh retval = FILTER_HANDLED; 747fc7119a7SWarner Losh } 7485b9ee137SWarner Losh return retval; 749fc7119a7SWarner Losh } 750fc7119a7SWarner Losh 7514edef187SJohn Baldwin static struct resource * 7524edef187SJohn Baldwin cbb_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 7532dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 7544edef187SJohn Baldwin { 7554edef187SJohn Baldwin struct cbb_softc *sc; 7564edef187SJohn Baldwin 7574edef187SJohn Baldwin sc = device_get_softc(bus); 7584edef187SJohn Baldwin if (type == PCI_RES_BUS) 7594edef187SJohn Baldwin return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, 7604edef187SJohn Baldwin count, flags)); 7614edef187SJohn Baldwin return (cbb_alloc_resource(bus, child, type, rid, start, end, count, 7624edef187SJohn Baldwin flags)); 7634edef187SJohn Baldwin } 7644edef187SJohn Baldwin 7654edef187SJohn Baldwin static int 766fef01f04SJohn Baldwin cbb_pci_adjust_resource(device_t bus, device_t child, 7672dd1bdf1SJustin Hibbits struct resource *r, rman_res_t start, rman_res_t end) 7684edef187SJohn Baldwin { 7694edef187SJohn Baldwin struct cbb_softc *sc; 7704edef187SJohn Baldwin 7714edef187SJohn Baldwin sc = device_get_softc(bus); 772fef01f04SJohn Baldwin if (rman_get_type(r) == PCI_RES_BUS) { 7734edef187SJohn Baldwin if (!rman_is_region_manager(r, &sc->bus.rman)) 7744edef187SJohn Baldwin return (EINVAL); 7754edef187SJohn Baldwin return (rman_adjust_resource(r, start, end)); 7764edef187SJohn Baldwin } 777fef01f04SJohn Baldwin return (bus_generic_adjust_resource(bus, child, r, start, end)); 7784edef187SJohn Baldwin } 7794edef187SJohn Baldwin 7804edef187SJohn Baldwin static int 7819dbf5b0eSJohn Baldwin cbb_pci_release_resource(device_t bus, device_t child, struct resource *r) 7824edef187SJohn Baldwin { 7834edef187SJohn Baldwin struct cbb_softc *sc; 7844edef187SJohn Baldwin int error; 7854edef187SJohn Baldwin 7864edef187SJohn Baldwin sc = device_get_softc(bus); 7879dbf5b0eSJohn Baldwin if (rman_get_type(r) == PCI_RES_BUS) { 7884edef187SJohn Baldwin if (!rman_is_region_manager(r, &sc->bus.rman)) 7894edef187SJohn Baldwin return (EINVAL); 7904edef187SJohn Baldwin if (rman_get_flags(r) & RF_ACTIVE) { 7919dbf5b0eSJohn Baldwin error = bus_deactivate_resource(child, r); 7924edef187SJohn Baldwin if (error) 7934edef187SJohn Baldwin return (error); 7944edef187SJohn Baldwin } 7954edef187SJohn Baldwin return (rman_release_resource(r)); 7964edef187SJohn Baldwin } 7979dbf5b0eSJohn Baldwin return (cbb_release_resource(bus, child, r)); 7984edef187SJohn Baldwin } 7994edef187SJohn Baldwin 8007490082fSWarner Losh /************************************************************************/ 8017490082fSWarner Losh /* PCI compat methods */ 8027490082fSWarner Losh /************************************************************************/ 8037490082fSWarner Losh 8047490082fSWarner Losh static int 8057490082fSWarner Losh cbb_maxslots(device_t brdev) 8067490082fSWarner Losh { 8077490082fSWarner Losh return (0); 8087490082fSWarner Losh } 8097490082fSWarner Losh 8107490082fSWarner Losh static uint32_t 811a620f9a5SWarner Losh cbb_read_config(device_t brdev, u_int b, u_int s, u_int f, u_int reg, int width) 8127490082fSWarner Losh { 8137490082fSWarner Losh /* 8147490082fSWarner Losh * Pass through to the next ppb up the chain (i.e. our grandparent). 8157490082fSWarner Losh */ 816a620f9a5SWarner Losh return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)), 817a620f9a5SWarner Losh b, s, f, reg, width)); 8187490082fSWarner Losh } 8197490082fSWarner Losh 8207490082fSWarner Losh static void 821a620f9a5SWarner Losh cbb_write_config(device_t brdev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, 8227490082fSWarner Losh int width) 8237490082fSWarner Losh { 8247490082fSWarner Losh /* 8257490082fSWarner Losh * Pass through to the next ppb up the chain (i.e. our grandparent). 8267490082fSWarner Losh */ 8277490082fSWarner Losh PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(brdev)), 8287490082fSWarner Losh b, s, f, reg, val, width); 8297490082fSWarner Losh } 8307490082fSWarner Losh 83153d67399SWarner Losh static int 83253d67399SWarner Losh cbb_pci_suspend(device_t brdev) 83353d67399SWarner Losh { 83453d67399SWarner Losh int error = 0; 83553d67399SWarner Losh struct cbb_softc *sc = device_get_softc(brdev); 83653d67399SWarner Losh 83753d67399SWarner Losh error = bus_generic_suspend(brdev); 83853d67399SWarner Losh if (error != 0) 83953d67399SWarner Losh return (error); 84053d67399SWarner Losh cbb_set(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */ 84153d67399SWarner Losh sc->cardok = 0; /* Card is bogus now */ 84253d67399SWarner Losh return (0); 84353d67399SWarner Losh } 84453d67399SWarner Losh 84553d67399SWarner Losh static int 84653d67399SWarner Losh cbb_pci_resume(device_t brdev) 84753d67399SWarner Losh { 84853d67399SWarner Losh int error = 0; 84953d67399SWarner Losh struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); 85053d67399SWarner Losh uint32_t tmp; 85153d67399SWarner Losh 85253d67399SWarner Losh /* 85353d67399SWarner Losh * In the APM and early ACPI era, BIOSes saved the PCI config 85453d67399SWarner Losh * registers. As chips became more complicated, that functionality moved 85553d67399SWarner Losh * into the ACPI code / tables. We must therefore, restore the settings 85653d67399SWarner Losh * we made here to make sure the device come back. Transitions to Dx 85753d67399SWarner Losh * from D0 and back to D0 cause the bridge to lose its config space, so 85853d67399SWarner Losh * all the bus mappings and such are preserved. 85953d67399SWarner Losh * 860ad6f36f8SJohn Baldwin * The PCI layer handles standard PCI registers like the 861ad6f36f8SJohn Baldwin * command register and BARs, but cbb-specific registers are 862ad6f36f8SJohn Baldwin * handled here. 86353d67399SWarner Losh */ 86453d67399SWarner Losh sc->chipinit(sc); 86553d67399SWarner Losh 86653d67399SWarner Losh /* reset interrupt -- Do we really need to do this? */ 86753d67399SWarner Losh tmp = cbb_get(sc, CBB_SOCKET_EVENT); 86853d67399SWarner Losh cbb_set(sc, CBB_SOCKET_EVENT, tmp); 86953d67399SWarner Losh 87053d67399SWarner Losh /* CSC Interrupt: Card detect interrupt on */ 87153d67399SWarner Losh cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); 87253d67399SWarner Losh 87353d67399SWarner Losh /* Signal the thread to wakeup. */ 87453d67399SWarner Losh wakeup(&sc->intrhand); 87553d67399SWarner Losh 87653d67399SWarner Losh error = bus_generic_resume(brdev); 87753d67399SWarner Losh 87853d67399SWarner Losh return (error); 87953d67399SWarner Losh } 88053d67399SWarner Losh 88193185c74SWarner Losh static device_method_t cbb_methods[] = { 88293185c74SWarner Losh /* Device interface */ 88393185c74SWarner Losh DEVMETHOD(device_probe, cbb_pci_probe), 88493185c74SWarner Losh DEVMETHOD(device_attach, cbb_pci_attach), 8856f33eaa5SJohn Baldwin DEVMETHOD(device_detach, cbb_pci_detach), 8867490082fSWarner Losh DEVMETHOD(device_shutdown, cbb_pci_shutdown), 88753d67399SWarner Losh DEVMETHOD(device_suspend, cbb_pci_suspend), 88853d67399SWarner Losh DEVMETHOD(device_resume, cbb_pci_resume), 88993185c74SWarner Losh 89093185c74SWarner Losh /* bus methods */ 89193185c74SWarner Losh DEVMETHOD(bus_read_ivar, cbb_read_ivar), 89293185c74SWarner Losh DEVMETHOD(bus_write_ivar, cbb_write_ivar), 8934edef187SJohn Baldwin DEVMETHOD(bus_alloc_resource, cbb_pci_alloc_resource), 8944edef187SJohn Baldwin DEVMETHOD(bus_adjust_resource, cbb_pci_adjust_resource), 8954edef187SJohn Baldwin DEVMETHOD(bus_release_resource, cbb_pci_release_resource), 89693185c74SWarner Losh DEVMETHOD(bus_activate_resource, cbb_activate_resource), 89793185c74SWarner Losh DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource), 89893185c74SWarner Losh DEVMETHOD(bus_driver_added, cbb_driver_added), 89993185c74SWarner Losh DEVMETHOD(bus_child_detached, cbb_child_detached), 90093185c74SWarner Losh DEVMETHOD(bus_setup_intr, cbb_setup_intr), 90193185c74SWarner Losh DEVMETHOD(bus_teardown_intr, cbb_teardown_intr), 90293185c74SWarner Losh DEVMETHOD(bus_child_present, cbb_child_present), 90393185c74SWarner Losh 90493185c74SWarner Losh /* 16-bit card interface */ 90593185c74SWarner Losh DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags), 90693185c74SWarner Losh DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset), 90793185c74SWarner Losh 90893185c74SWarner Losh /* power interface */ 90993185c74SWarner Losh DEVMETHOD(power_enable_socket, cbb_power_enable_socket), 91093185c74SWarner Losh DEVMETHOD(power_disable_socket, cbb_power_disable_socket), 91193185c74SWarner Losh 91293185c74SWarner Losh /* pcib compatibility interface */ 91393185c74SWarner Losh DEVMETHOD(pcib_maxslots, cbb_maxslots), 91493185c74SWarner Losh DEVMETHOD(pcib_read_config, cbb_read_config), 91593185c74SWarner Losh DEVMETHOD(pcib_write_config, cbb_write_config), 9163f7d3c1eSWarner Losh DEVMETHOD(pcib_route_interrupt, cbb_route_interrupt), 9173f7d3c1eSWarner Losh 9184b7ec270SMarius Strobl DEVMETHOD_END 91993185c74SWarner Losh }; 92093185c74SWarner Losh 92193185c74SWarner Losh static driver_t cbb_driver = { 92293185c74SWarner Losh "cbb", 92393185c74SWarner Losh cbb_methods, 92493185c74SWarner Losh sizeof(struct cbb_softc) 92593185c74SWarner Losh }; 92693185c74SWarner Losh 9276ab0dfe5SJohn Baldwin DRIVER_MODULE(cbb, pci, cbb_driver, 0, 0); 9280dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device;D:#", pci, cbb, yc_chipsets, 9290dc34160SWarner Losh nitems(yc_chipsets) - 1); 93093185c74SWarner Losh MODULE_DEPEND(cbb, exca, 1, 1, 1); 931