1 /* $NetBSD: rtsx_pci.c,v 1.4 2015/09/05 04:56:53 nonaka 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.4 2015/09/05 04:56:53 nonaka 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 41 struct rtsx_pci_softc { 42 struct rtsx_softc sc; 43 pci_chipset_tag_t sc_pc; 44 void *sc_ih; 45 46 #ifdef __HAVE_PCI_MSI_MSIX 47 pci_intr_handle_t *sc_pihp; 48 #endif 49 }; 50 51 static int rtsx_pci_match(device_t , cfdata_t, void *); 52 static void rtsx_pci_attach(device_t, device_t, void *); 53 static int rtsx_pci_detach(device_t, int); 54 55 CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc), 56 rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL); 57 58 #ifdef RTSX_DEBUG 59 extern int rtsxdebug; 60 #define DPRINTF(n,s) do { if ((n) <= rtsxdebug) printf s; } while (0) 61 #else 62 #define DPRINTF(n,s) /**/ 63 #endif 64 65 static int 66 rtsx_pci_match(device_t parent, cfdata_t cf, void *aux) 67 { 68 struct pci_attach_args *pa = aux; 69 70 /* 71 * Explicitly match the UNDEFINED device class only. Some RTS5902 72 * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED 73 * device class. Let sdhc(4) handle the SYSTEM/SDHC ones. 74 */ 75 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK || 76 PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED) 77 return 0; 78 79 switch (PCI_PRODUCT(pa->pa_id)) { 80 case PCI_PRODUCT_REALTEK_RTS5209: 81 case PCI_PRODUCT_REALTEK_RTS5227: 82 case PCI_PRODUCT_REALTEK_RTS5229: 83 case PCI_PRODUCT_REALTEK_RTL8402: 84 case PCI_PRODUCT_REALTEK_RTL8411: 85 case PCI_PRODUCT_REALTEK_RTL8411B: 86 return 1; 87 } 88 89 return 0; 90 } 91 92 static void 93 rtsx_pci_attach(device_t parent, device_t self, void *aux) 94 { 95 struct rtsx_pci_softc *sc = device_private(self); 96 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 97 pci_chipset_tag_t pc = pa->pa_pc; 98 pcitag_t tag = pa->pa_tag; 99 #ifndef __HAVE_PCI_MSI_MSIX 100 pci_intr_handle_t ih; 101 #endif 102 pcireg_t reg; 103 char const *intrstr; 104 bus_space_tag_t iot; 105 bus_space_handle_t ioh; 106 bus_size_t size; 107 uint32_t flags; 108 char intrbuf[PCI_INTRSTR_LEN]; 109 110 sc->sc.sc_dev = self; 111 sc->sc_pc = pc; 112 113 pci_aprint_devinfo(pa, NULL); 114 115 if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) { 116 aprint_error_dev(self, "no asic\n"); 117 return; 118 } 119 120 if (pci_mapreg_map(pa, RTSX_PCI_BAR, PCI_MAPREG_TYPE_MEM, 0, 121 &iot, &ioh, NULL, &size)) { 122 aprint_error_dev(self, "couldn't map registers\n"); 123 return; 124 } 125 126 #ifdef __HAVE_PCI_MSI_MSIX 127 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 128 aprint_error_dev(self, "couldn't map interrupt\n"); 129 return; 130 } 131 intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 132 sc->sc_ih = pci_intr_establish(pc, sc->sc_pihp[0], IPL_SDMMC, rtsx_intr, 133 &sc->sc); 134 #else /* !__HAVE_PCI_MSI_MSIX */ 135 if (pci_intr_map(pa, &ih)) { 136 aprint_error_dev(self, "couldn't map interrupt\n"); 137 return; 138 } 139 intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); 140 sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, rtsx_intr, &sc->sc); 141 #endif /* __HAVE_PCI_MSI_MSIX */ 142 if (sc->sc_ih == NULL) { 143 aprint_error_dev(self, "couldn't establish interrupt\n"); 144 return; 145 } 146 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 147 148 /* Enable the device */ 149 reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 150 reg |= PCI_COMMAND_MASTER_ENABLE; 151 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); 152 153 /* Power up the device */ 154 pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0); 155 156 switch (PCI_PRODUCT(pa->pa_id)) { 157 case PCI_PRODUCT_REALTEK_RTS5209: 158 flags = RTSX_F_5209; 159 break; 160 case PCI_PRODUCT_REALTEK_RTS5227: 161 flags = RTSX_F_5227; 162 break; 163 case PCI_PRODUCT_REALTEK_RTS5229: 164 flags = RTSX_F_5229; 165 break; 166 case PCI_PRODUCT_REALTEK_RTL8402: 167 flags = RTSX_F_8402; 168 break; 169 case PCI_PRODUCT_REALTEK_RTL8411: 170 flags = RTSX_F_8411; 171 break; 172 case PCI_PRODUCT_REALTEK_RTL8411B: 173 flags = RTSX_F_8411B; 174 break; 175 default: 176 flags = 0; 177 break; 178 } 179 180 if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) { 181 aprint_error_dev(self, "couldn't initialize chip\n"); 182 return; 183 } 184 185 if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume, 186 rtsx_shutdown)) 187 aprint_error_dev(self, "couldn't establish powerhook\n"); 188 } 189 190 static int 191 rtsx_pci_detach(device_t self, int flags) 192 { 193 struct rtsx_pci_softc *sc = device_private(self); 194 int rv; 195 196 rv = rtsx_detach(&sc->sc, flags); 197 if (rv) 198 return rv; 199 200 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 201 #ifdef __HAVE_PCI_MSI_MSIX 202 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 203 #endif /* __HAVE_PCI_MSI_MSIX */ 204 205 return 0; 206 } 207