1/* $OpenBSD: puc_cardbus.c,v 1.10 2024/05/24 06:26:47 jsg 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 24#include <dev/pci/pcireg.h> 25#include <dev/pci/pcivar.h> 26#include <dev/pci/pcidevs.h> 27#include <dev/cardbus/cardbusvar.h> 28 29#include <dev/pci/pucvar.h> 30 31struct puc_cardbus_softc { 32 struct puc_softc sc_psc; 33 34 struct cardbus_devfunc *ct; 35 int intrline; 36}; 37 38int puc_cardbus_match(struct device *, void *, void *); 39void puc_cardbus_attach(struct device *, struct device *, void *); 40int puc_cardbus_detach(struct device *, int); 41 42const char *puc_cardbus_intr_string(struct puc_attach_args *); 43void *puc_cardbus_intr_establish(struct puc_attach_args *, int, 44 int (*)(void *), void *, char *); 45 46const struct cfattach puc_cardbus_ca = { 47 sizeof(struct puc_cardbus_softc), puc_cardbus_match, 48 puc_cardbus_attach, puc_cardbus_detach 49}; 50 51int 52puc_cardbus_match(struct device *parent, void *match, void *aux) 53{ 54 struct cardbus_attach_args *ca = aux; 55 pci_chipset_tag_t pc = ca->ca_pc; 56 pcireg_t bhlc, reg; 57 58 bhlc = pci_conf_read(pc, ca->ca_tag, PCI_BHLC_REG); 59 if (PCI_HDRTYPE_TYPE(bhlc) != 0) 60 return(0); 61 62 /* this one is some sort of a bridge and not a puc */ 63 if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_OXFORD2 && 64 PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_OXFORD2_EXSYS_EX41098) 65 return (0); 66 67 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG); 68 if (puc_find_description(PCI_VENDOR(ca->ca_id), 69 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg))) 70 return (10); 71 72 return (0); 73} 74 75void 76puc_cardbus_attach(struct device *parent, struct device *self, void *aux) 77{ 78 struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self; 79 struct puc_softc *sc = &csc->sc_psc; 80 struct cardbus_attach_args *ca = aux; 81 struct cardbus_devfunc *ct = ca->ca_ct; 82 cardbus_chipset_tag_t cc = ct->ct_cc; 83 pci_chipset_tag_t pc = ca->ca_pc; 84 cardbus_function_tag_t cf = ct->ct_cf; 85 struct puc_attach_args paa; 86 pcireg_t reg; 87 int i; 88 89 Cardbus_function_enable(ct); 90 91 csc->ct = ct; 92 93 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG); 94 sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id), 95 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg)); 96 97 puc_print_ports(sc->sc_desc); 98 99 /* the fifth one is some memory we dunno */ 100 for (i = 0; i < PUC_NBARS; i++) { 101 pcireg_t type; 102 int bar; 103 104 sc->sc_bar_mappings[i].mapped = 0; 105 bar = PCI_MAPREG_START + 4 * i; 106 if (!pci_mapreg_probe(pc, ca->ca_tag, bar, &type)) 107 continue; 108 109 if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct, 110 bar, type, 0, 111 &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h, 112 &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s))) 113 printf("%s: couldn't map BAR at offset 0x%lx\n", 114 sc->sc_dev.dv_xname, (long)bar); 115 sc->sc_bar_mappings[i].type = type; 116 } 117 118 csc->intrline = ca->ca_intrline; 119 120 if (pci_get_capability(pc, ca->ca_tag, PCI_CAP_PWRMGMT, ®, 121 0)) { 122 reg = pci_conf_read(pc, ca->ca_tag, reg + 4) & 3; 123 if (reg) { 124 printf("%s: awakening from state D%d\n", 125 sc->sc_dev.dv_xname, reg); 126 pci_conf_write(pc, ca->ca_tag, reg + 4, 0); 127 } 128 } 129 130 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 131 (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); 132 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 133 134 paa.puc = sc; 135 paa.intr_string = &puc_cardbus_intr_string; 136 paa.intr_establish = &puc_cardbus_intr_establish; 137 138 puc_common_attach(sc, &paa); 139} 140 141const char * 142puc_cardbus_intr_string(struct puc_attach_args *paa) 143{ 144 struct puc_cardbus_softc *sc = paa->puc; 145 static char str[16]; 146 147 snprintf(str, sizeof str, "irq %d", sc->intrline); 148 return (str); 149} 150 151void * 152puc_cardbus_intr_establish(struct puc_attach_args *paa, int type, 153 int (*func)(void *), void *arg, char *name) 154{ 155 struct puc_cardbus_softc *sc = paa->puc; 156 struct puc_softc *psc = &sc->sc_psc; 157 struct cardbus_devfunc *ct = sc->ct; 158 159 psc->sc_ports[paa->port].intrhand = 160 cardbus_intr_establish(ct->ct_cc, ct->ct_cf, sc->intrline, 161 type, func, arg, name); 162 163 return (psc->sc_ports[paa->port].intrhand); 164} 165 166int 167puc_cardbus_detach(struct device *self, int flags) 168{ 169 struct puc_cardbus_softc *sc = (struct puc_cardbus_softc *)self; 170 struct puc_softc *psc = &sc->sc_psc; 171 struct cardbus_devfunc *ct = sc->ct; 172 int i, rv; 173 174 for (i = PUC_MAX_PORTS; i--; ) { 175 if (psc->sc_ports[i].intrhand) 176 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, 177 psc->sc_ports[i].intrhand); 178 if (psc->sc_ports[i].dev) 179 if ((rv = config_detach(psc->sc_ports[i].dev, flags))) 180 return (rv); 181 } 182 183 for (i = PUC_NBARS; i--; ) 184 if (psc->sc_bar_mappings[i].mapped) 185 Cardbus_mapreg_unmap(ct, psc->sc_bar_mappings[i].type, 186 psc->sc_bar_mappings[i].t, 187 psc->sc_bar_mappings[i].h, 188 psc->sc_bar_mappings[i].s); 189 190 return (0); 191} 192