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