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