1 /* $NetBSD: rtsx_pci.c,v 1.11 2025/01/18 08:12:45 mrg 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.11 2025/01/18 08:12:45 mrg Exp $"); 24 25 #include <sys/param.h> 26 #include <sys/device.h> 27 #include <sys/systm.h> 28 #include <sys/pmf.h> 29 30 #include <dev/pci/pcivar.h> 31 #include <dev/pci/pcidevs.h> 32 33 #include <dev/ic/rtsxreg.h> 34 #include <dev/ic/rtsxvar.h> 35 36 #include <dev/sdmmc/sdmmcvar.h> 37 38 #define RTSX_PCI_BAR 0x10 39 #define RTSX_PCI_BAR_525A 0x14 40 41 struct rtsx_pci_softc { 42 struct rtsx_softc sc; 43 pci_chipset_tag_t sc_pc; 44 void *sc_ih; 45 46 pci_intr_handle_t *sc_pihp; 47 }; 48 49 static int rtsx_pci_match(device_t , cfdata_t, void *); 50 static void rtsx_pci_attach(device_t, device_t, void *); 51 static int rtsx_pci_detach(device_t, int); 52 53 CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc), 54 rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL); 55 56 #ifdef RTSX_DEBUG 57 extern int rtsxdebug; 58 #define DPRINTF(n,s) do { if ((n) <= rtsxdebug) printf s; } while (0) 59 #else 60 #define DPRINTF(n,s) /**/ 61 #endif 62 63 static int 64 rtsx_pci_match(device_t parent, cfdata_t cf, void *aux) 65 { 66 struct pci_attach_args *pa = aux; 67 68 /* 69 * Explicitly match the UNDEFINED device class only. Some RTS5209 70 * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED 71 * device class. Let sdhc(4) handle the SYSTEM/SDHC ones. 72 */ 73 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK || 74 PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED) 75 return 0; 76 77 switch (PCI_PRODUCT(pa->pa_id)) { 78 case PCI_PRODUCT_REALTEK_RTS5209: 79 case PCI_PRODUCT_REALTEK_RTS5227: 80 case PCI_PRODUCT_REALTEK_RTS5229: 81 case PCI_PRODUCT_REALTEK_RTS522A: 82 case PCI_PRODUCT_REALTEK_RTS5249: 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 case PCI_PRODUCT_REALTEK_RTS5249: 121 flags = RTSX_F_5229; 122 break; 123 case PCI_PRODUCT_REALTEK_RTS525A: 124 flags = RTSX_F_525A; 125 bar = RTSX_PCI_BAR_525A; 126 break; 127 case PCI_PRODUCT_REALTEK_RTL8402: 128 flags = RTSX_F_8402; 129 break; 130 case PCI_PRODUCT_REALTEK_RTL8411: 131 flags = RTSX_F_8411; 132 break; 133 case PCI_PRODUCT_REALTEK_RTL8411B: 134 flags = RTSX_F_8411B; 135 break; 136 default: 137 flags = 0; 138 break; 139 } 140 141 pci_aprint_devinfo(pa, NULL); 142 143 if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) { 144 aprint_error_dev(self, "no asic\n"); 145 return; 146 } 147 148 if (pci_mapreg_map(pa, bar, PCI_MAPREG_TYPE_MEM, 0, 149 &iot, &ioh, NULL, &size)) { 150 aprint_error_dev(self, "couldn't map registers\n"); 151 return; 152 } 153 154 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 155 aprint_error_dev(self, "couldn't map interrupt\n"); 156 return; 157 } 158 intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 159 sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_SDMMC, 160 rtsx_intr, &sc->sc, device_xname(self)); 161 if (sc->sc_ih == NULL) { 162 aprint_error_dev(self, "couldn't establish interrupt\n"); 163 return; 164 } 165 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 166 167 /* Enable the device */ 168 reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 169 reg |= PCI_COMMAND_MASTER_ENABLE; 170 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); 171 172 /* Power up the device */ 173 pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0); 174 175 if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) { 176 aprint_error_dev(self, "couldn't initialize chip\n"); 177 return; 178 } 179 180 if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume, 181 rtsx_shutdown)) 182 aprint_error_dev(self, "couldn't establish powerhook\n"); 183 } 184 185 static int 186 rtsx_pci_detach(device_t self, int flags) 187 { 188 struct rtsx_pci_softc *sc = device_private(self); 189 int rv; 190 191 rv = rtsx_detach(&sc->sc, flags); 192 if (rv) 193 return rv; 194 195 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 196 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 197 198 return 0; 199 } 200