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