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