1 /* $NetBSD: rtsx_pci.c,v 1.9 2020/04/27 23:06:34 jmcneill Exp $ */ 2 /* $OpenBSD: rtsx_pci.c,v 1.7 2014/08/19 17:55:03 phessler Exp $ */ 3 4 5 /* 6 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> 7 * Copyright (c) 2012 Stefan Sperling <stsp@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/cdefs.h> 23 __KERNEL_RCSID(0, "$NetBSD: rtsx_pci.c,v 1.9 2020/04/27 23:06:34 jmcneill Exp $"); 24 25 #include <sys/param.h> 26 #include <sys/device.h> 27 #include <sys/systm.h> 28 #include <sys/malloc.h> 29 #include <sys/pmf.h> 30 31 #include <dev/pci/pcivar.h> 32 #include <dev/pci/pcidevs.h> 33 34 #include <dev/ic/rtsxreg.h> 35 #include <dev/ic/rtsxvar.h> 36 37 #include <dev/sdmmc/sdmmcvar.h> 38 39 #define RTSX_PCI_BAR 0x10 40 #define RTSX_PCI_BAR_525A 0x14 41 42 struct rtsx_pci_softc { 43 struct rtsx_softc sc; 44 pci_chipset_tag_t sc_pc; 45 void *sc_ih; 46 47 pci_intr_handle_t *sc_pihp; 48 }; 49 50 static int rtsx_pci_match(device_t , cfdata_t, void *); 51 static void rtsx_pci_attach(device_t, device_t, void *); 52 static int rtsx_pci_detach(device_t, int); 53 54 CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc), 55 rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL); 56 57 #ifdef RTSX_DEBUG 58 extern int rtsxdebug; 59 #define DPRINTF(n,s) do { if ((n) <= rtsxdebug) printf s; } while (0) 60 #else 61 #define DPRINTF(n,s) /**/ 62 #endif 63 64 static int 65 rtsx_pci_match(device_t parent, cfdata_t cf, void *aux) 66 { 67 struct pci_attach_args *pa = aux; 68 69 /* 70 * Explicitly match the UNDEFINED device class only. Some RTS5902 71 * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED 72 * device class. Let sdhc(4) handle the SYSTEM/SDHC ones. 73 */ 74 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK || 75 PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED) 76 return 0; 77 78 switch (PCI_PRODUCT(pa->pa_id)) { 79 case PCI_PRODUCT_REALTEK_RTS5209: 80 case PCI_PRODUCT_REALTEK_RTS5227: 81 case PCI_PRODUCT_REALTEK_RTS5229: 82 case PCI_PRODUCT_REALTEK_RTS522A: 83 case PCI_PRODUCT_REALTEK_RTS525A: 84 case PCI_PRODUCT_REALTEK_RTL8402: 85 case PCI_PRODUCT_REALTEK_RTL8411: 86 case PCI_PRODUCT_REALTEK_RTL8411B: 87 return 1; 88 } 89 90 return 0; 91 } 92 93 static void 94 rtsx_pci_attach(device_t parent, device_t self, void *aux) 95 { 96 struct rtsx_pci_softc *sc = device_private(self); 97 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 98 pci_chipset_tag_t pc = pa->pa_pc; 99 pcitag_t tag = pa->pa_tag; 100 pcireg_t reg; 101 char const *intrstr; 102 bus_space_tag_t iot; 103 bus_space_handle_t ioh; 104 bus_size_t size; 105 uint32_t flags; 106 int bar = RTSX_PCI_BAR; 107 char intrbuf[PCI_INTRSTR_LEN]; 108 109 sc->sc.sc_dev = self; 110 sc->sc_pc = pc; 111 112 switch (PCI_PRODUCT(pa->pa_id)) { 113 case PCI_PRODUCT_REALTEK_RTS5209: 114 flags = RTSX_F_5209; 115 break; 116 case PCI_PRODUCT_REALTEK_RTS5227: 117 flags = RTSX_F_5227; 118 break; 119 case PCI_PRODUCT_REALTEK_RTS5229: 120 flags = RTSX_F_5229; 121 break; 122 case PCI_PRODUCT_REALTEK_RTS525A: 123 flags = RTSX_F_525A; 124 bar = RTSX_PCI_BAR_525A; 125 break; 126 case PCI_PRODUCT_REALTEK_RTL8402: 127 flags = RTSX_F_8402; 128 break; 129 case PCI_PRODUCT_REALTEK_RTL8411: 130 flags = RTSX_F_8411; 131 break; 132 case PCI_PRODUCT_REALTEK_RTL8411B: 133 flags = RTSX_F_8411B; 134 break; 135 default: 136 flags = 0; 137 break; 138 } 139 140 pci_aprint_devinfo(pa, NULL); 141 142 if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) { 143 aprint_error_dev(self, "no asic\n"); 144 return; 145 } 146 147 if (pci_mapreg_map(pa, bar, PCI_MAPREG_TYPE_MEM, 0, 148 &iot, &ioh, NULL, &size)) { 149 aprint_error_dev(self, "couldn't map registers\n"); 150 return; 151 } 152 153 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 154 aprint_error_dev(self, "couldn't map interrupt\n"); 155 return; 156 } 157 intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 158 sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_SDMMC, 159 rtsx_intr, &sc->sc, device_xname(self)); 160 if (sc->sc_ih == NULL) { 161 aprint_error_dev(self, "couldn't establish interrupt\n"); 162 return; 163 } 164 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 165 166 /* Enable the device */ 167 reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 168 reg |= PCI_COMMAND_MASTER_ENABLE; 169 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); 170 171 /* Power up the device */ 172 pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0); 173 174 if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) { 175 aprint_error_dev(self, "couldn't initialize chip\n"); 176 return; 177 } 178 179 if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume, 180 rtsx_shutdown)) 181 aprint_error_dev(self, "couldn't establish powerhook\n"); 182 } 183 184 static int 185 rtsx_pci_detach(device_t self, int flags) 186 { 187 struct rtsx_pci_softc *sc = device_private(self); 188 int rv; 189 190 rv = rtsx_detach(&sc->sc, flags); 191 if (rv) 192 return rv; 193 194 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 195 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 196 197 return 0; 198 } 199