rtsx_pci.c revision 1.8
1/* $NetBSD: rtsx_pci.c,v 1.8 2018/12/09 11:14:02 jdolecek 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.8 2018/12/09 11:14:02 jdolecek 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 42struct 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 50static int rtsx_pci_match(device_t , cfdata_t, void *); 51static void rtsx_pci_attach(device_t, device_t, void *); 52static int rtsx_pci_detach(device_t, int); 53 54CFATTACH_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 58extern 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 64static int 65rtsx_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_RTS525A: 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 92static void 93rtsx_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 pcireg_t reg; 100 char const *intrstr; 101 bus_space_tag_t iot; 102 bus_space_handle_t ioh; 103 bus_size_t size; 104 uint32_t flags; 105 int bar = RTSX_PCI_BAR; 106 char intrbuf[PCI_INTRSTR_LEN]; 107 108 sc->sc.sc_dev = self; 109 sc->sc_pc = pc; 110 111 switch (PCI_PRODUCT(pa->pa_id)) { 112 case PCI_PRODUCT_REALTEK_RTS5209: 113 flags = RTSX_F_5209; 114 break; 115 case PCI_PRODUCT_REALTEK_RTS5227: 116 flags = RTSX_F_5227; 117 break; 118 case PCI_PRODUCT_REALTEK_RTS5229: 119 flags = RTSX_F_5229; 120 break; 121 case PCI_PRODUCT_REALTEK_RTS525A: 122 flags = RTSX_F_525A; 123 bar = RTSX_PCI_BAR_525A; 124 break; 125 case PCI_PRODUCT_REALTEK_RTL8402: 126 flags = RTSX_F_8402; 127 break; 128 case PCI_PRODUCT_REALTEK_RTL8411: 129 flags = RTSX_F_8411; 130 break; 131 case PCI_PRODUCT_REALTEK_RTL8411B: 132 flags = RTSX_F_8411B; 133 break; 134 default: 135 flags = 0; 136 break; 137 } 138 139 pci_aprint_devinfo(pa, NULL); 140 141 if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) { 142 aprint_error_dev(self, "no asic\n"); 143 return; 144 } 145 146 if (pci_mapreg_map(pa, bar, PCI_MAPREG_TYPE_MEM, 0, 147 &iot, &ioh, NULL, &size)) { 148 aprint_error_dev(self, "couldn't map registers\n"); 149 return; 150 } 151 152 if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 153 aprint_error_dev(self, "couldn't map interrupt\n"); 154 return; 155 } 156 intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 157 sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_SDMMC, 158 rtsx_intr, &sc->sc, device_xname(self)); 159 if (sc->sc_ih == NULL) { 160 aprint_error_dev(self, "couldn't establish interrupt\n"); 161 return; 162 } 163 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 164 165 /* Enable the device */ 166 reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 167 reg |= PCI_COMMAND_MASTER_ENABLE; 168 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); 169 170 /* Power up the device */ 171 pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0); 172 173 if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) { 174 aprint_error_dev(self, "couldn't initialize chip\n"); 175 return; 176 } 177 178 if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume, 179 rtsx_shutdown)) 180 aprint_error_dev(self, "couldn't establish powerhook\n"); 181} 182 183static int 184rtsx_pci_detach(device_t self, int flags) 185{ 186 struct rtsx_pci_softc *sc = device_private(self); 187 int rv; 188 189 rv = rtsx_detach(&sc->sc, flags); 190 if (rv) 191 return rv; 192 193 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 194 pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 195 196 return 0; 197} 198