1 /* $OpenBSD: puc_cardbus.c,v 1.8 2011/11/15 22:27:53 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/tty.h> 24 25 #include <machine/bus.h> 26 #include <dev/ic/comvar.h> 27 28 #include <dev/pci/pcireg.h> 29 #include <dev/pci/pcivar.h> 30 #include <dev/pci/pcidevs.h> 31 #include <dev/cardbus/cardbusvar.h> 32 33 #include <dev/pci/pucvar.h> 34 35 struct puc_cardbus_softc { 36 struct puc_softc sc_psc; 37 38 struct cardbus_devfunc *ct; 39 int intrline; 40 }; 41 42 int puc_cardbus_match(struct device *, void *, void *); 43 void puc_cardbus_attach(struct device *, struct device *, void *); 44 int puc_cardbus_detach(struct device *, int); 45 46 const char *puc_cardbus_intr_string(struct puc_attach_args *); 47 void *puc_cardbus_intr_establish(struct puc_attach_args *, int, 48 int (*)(void *), void *, char *); 49 50 struct cfattach puc_cardbus_ca = { 51 sizeof(struct puc_cardbus_softc), puc_cardbus_match, 52 puc_cardbus_attach, puc_cardbus_detach 53 }; 54 55 int 56 puc_cardbus_match(struct device *parent, void *match, void *aux) 57 { 58 struct cardbus_attach_args *ca = aux; 59 pci_chipset_tag_t pc = ca->ca_pc; 60 pcireg_t bhlc, reg; 61 62 bhlc = pci_conf_read(pc, ca->ca_tag, PCI_BHLC_REG); 63 if (PCI_HDRTYPE_TYPE(bhlc) != 0) 64 return(0); 65 66 /* this one is some sort of a bridge and not a puc */ 67 if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_OXFORD2 && 68 PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_OXFORD2_EXSYS_EX41098) 69 return (0); 70 71 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG); 72 if (puc_find_description(PCI_VENDOR(ca->ca_id), 73 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg))) 74 return (10); 75 76 return (0); 77 } 78 79 void 80 puc_cardbus_attach(struct device *parent, struct device *self, void *aux) 81 { 82 struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self; 83 struct puc_softc *sc = &csc->sc_psc; 84 struct cardbus_attach_args *ca = aux; 85 struct cardbus_devfunc *ct = ca->ca_ct; 86 cardbus_chipset_tag_t cc = ct->ct_cc; 87 pci_chipset_tag_t pc = ca->ca_pc; 88 cardbus_function_tag_t cf = ct->ct_cf; 89 struct puc_attach_args paa; 90 pcireg_t reg; 91 int i; 92 93 Cardbus_function_enable(ct); 94 95 csc->ct = ct; 96 97 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG); 98 sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id), 99 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg)); 100 101 puc_print_ports(sc->sc_desc); 102 103 /* the fifth one is some memory we dunno */ 104 for (i = 0; i < PUC_NBARS; i++) { 105 pcireg_t type; 106 int bar; 107 108 sc->sc_bar_mappings[i].mapped = 0; 109 bar = PCI_MAPREG_START + 4 * i; 110 if (!pci_mapreg_probe(pc, ca->ca_tag, bar, &type)) 111 continue; 112 113 if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct, 114 bar, type, 0, 115 &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h, 116 &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s))) 117 printf("%s: couldn't map BAR at offset 0x%lx\n", 118 sc->sc_dev.dv_xname, (long)bar); 119 sc->sc_bar_mappings[i].type = type; 120 } 121 122 csc->intrline = ca->ca_intrline; 123 124 if (pci_get_capability(pc, ca->ca_tag, PCI_CAP_PWRMGMT, ®, 125 0)) { 126 reg = pci_conf_read(pc, ca->ca_tag, reg + 4) & 3; 127 if (reg) { 128 printf("%s: awakening from state D%d\n", 129 sc->sc_dev.dv_xname, reg); 130 pci_conf_write(pc, ca->ca_tag, reg + 4, 0); 131 } 132 } 133 134 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 135 (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); 136 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 137 138 paa.puc = sc; 139 paa.intr_string = &puc_cardbus_intr_string; 140 paa.intr_establish = &puc_cardbus_intr_establish; 141 142 puc_common_attach(sc, &paa); 143 } 144 145 const char * 146 puc_cardbus_intr_string(struct puc_attach_args *paa) 147 { 148 struct puc_cardbus_softc *sc = paa->puc; 149 static char str[16]; 150 151 snprintf(str, sizeof str, "irq %d", sc->intrline); 152 return (str); 153 } 154 155 void * 156 puc_cardbus_intr_establish(struct puc_attach_args *paa, int type, 157 int (*func)(void *), void *arg, char *name) 158 { 159 struct puc_cardbus_softc *sc = paa->puc; 160 struct puc_softc *psc = &sc->sc_psc; 161 struct cardbus_devfunc *ct = sc->ct; 162 163 psc->sc_ports[paa->port].intrhand = 164 cardbus_intr_establish(ct->ct_cc, ct->ct_cf, sc->intrline, 165 type, func, arg, name); 166 167 return (psc->sc_ports[paa->port].intrhand); 168 } 169 170 int 171 puc_cardbus_detach(struct device *self, int flags) 172 { 173 struct puc_cardbus_softc *sc = (struct puc_cardbus_softc *)self; 174 struct puc_softc *psc = &sc->sc_psc; 175 struct cardbus_devfunc *ct = sc->ct; 176 int i, rv; 177 178 for (i = PUC_MAX_PORTS; i--; ) { 179 if (psc->sc_ports[i].intrhand) 180 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, 181 psc->sc_ports[i].intrhand); 182 if (psc->sc_ports[i].dev) 183 if ((rv = config_detach(psc->sc_ports[i].dev, flags))) 184 return (rv); 185 } 186 187 for (i = PUC_NBARS; i--; ) 188 if (psc->sc_bar_mappings[i].mapped) 189 Cardbus_mapreg_unmap(ct, psc->sc_bar_mappings[i].type, 190 psc->sc_bar_mappings[i].t, 191 psc->sc_bar_mappings[i].h, 192 psc->sc_bar_mappings[i].s); 193 194 return (0); 195 } 196