1*c429df4aSmrg /* $NetBSD: rtsx_pci.c,v 1.11 2025/01/18 08:12:45 mrg Exp $ */ 28fdb68d7Snonaka /* $OpenBSD: rtsx_pci.c,v 1.7 2014/08/19 17:55:03 phessler Exp $ */ 38fdb68d7Snonaka 4c3077021Snonaka 5c3077021Snonaka /* 6c3077021Snonaka * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> 7c3077021Snonaka * Copyright (c) 2012 Stefan Sperling <stsp@openbsd.org> 8c3077021Snonaka * 9c3077021Snonaka * Permission to use, copy, modify, and distribute this software for any 10c3077021Snonaka * purpose with or without fee is hereby granted, provided that the above 11c3077021Snonaka * copyright notice and this permission notice appear in all copies. 12c3077021Snonaka * 13c3077021Snonaka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14c3077021Snonaka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15c3077021Snonaka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16c3077021Snonaka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17c3077021Snonaka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18c3077021Snonaka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19c3077021Snonaka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20c3077021Snonaka */ 21c3077021Snonaka 22c3077021Snonaka #include <sys/cdefs.h> 23*c429df4aSmrg __KERNEL_RCSID(0, "$NetBSD: rtsx_pci.c,v 1.11 2025/01/18 08:12:45 mrg Exp $"); 24c3077021Snonaka 25c3077021Snonaka #include <sys/param.h> 26c3077021Snonaka #include <sys/device.h> 27c3077021Snonaka #include <sys/systm.h> 28c3077021Snonaka #include <sys/pmf.h> 29c3077021Snonaka 30c3077021Snonaka #include <dev/pci/pcivar.h> 31c3077021Snonaka #include <dev/pci/pcidevs.h> 32c3077021Snonaka 33c3077021Snonaka #include <dev/ic/rtsxreg.h> 34c3077021Snonaka #include <dev/ic/rtsxvar.h> 35c3077021Snonaka 36c3077021Snonaka #include <dev/sdmmc/sdmmcvar.h> 37c3077021Snonaka 38c3077021Snonaka #define RTSX_PCI_BAR 0x10 39ddb8613dSmaya #define RTSX_PCI_BAR_525A 0x14 40c3077021Snonaka 41c3077021Snonaka struct rtsx_pci_softc { 42c3077021Snonaka struct rtsx_softc sc; 43c3077021Snonaka pci_chipset_tag_t sc_pc; 44c3077021Snonaka void *sc_ih; 45eff3c0ecSnonaka 46eff3c0ecSnonaka pci_intr_handle_t *sc_pihp; 47c3077021Snonaka }; 48c3077021Snonaka 49c3077021Snonaka static int rtsx_pci_match(device_t , cfdata_t, void *); 50c3077021Snonaka static void rtsx_pci_attach(device_t, device_t, void *); 51c3077021Snonaka static int rtsx_pci_detach(device_t, int); 52c3077021Snonaka 53c3077021Snonaka CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc), 54c3077021Snonaka rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL); 55c3077021Snonaka 56c3077021Snonaka #ifdef RTSX_DEBUG 57c3077021Snonaka extern int rtsxdebug; 58c3077021Snonaka #define DPRINTF(n,s) do { if ((n) <= rtsxdebug) printf s; } while (0) 59c3077021Snonaka #else 60c3077021Snonaka #define DPRINTF(n,s) /**/ 61c3077021Snonaka #endif 62c3077021Snonaka 63c3077021Snonaka static int 64c3077021Snonaka rtsx_pci_match(device_t parent, cfdata_t cf, void *aux) 65c3077021Snonaka { 66c3077021Snonaka struct pci_attach_args *pa = aux; 67c3077021Snonaka 68c3077021Snonaka /* 69*c429df4aSmrg * Explicitly match the UNDEFINED device class only. Some RTS5209 70c3077021Snonaka * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED 71c3077021Snonaka * device class. Let sdhc(4) handle the SYSTEM/SDHC ones. 72c3077021Snonaka */ 73c3077021Snonaka if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK || 74c3077021Snonaka PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED) 75c3077021Snonaka return 0; 76c3077021Snonaka 778fdb68d7Snonaka switch (PCI_PRODUCT(pa->pa_id)) { 788fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTS5209: 798fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTS5227: 808fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTS5229: 81c2bf22a2Sjmcneill case PCI_PRODUCT_REALTEK_RTS522A: 82*c429df4aSmrg case PCI_PRODUCT_REALTEK_RTS5249: 83ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTS525A: 848fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTL8402: 858fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTL8411: 868fdb68d7Snonaka case PCI_PRODUCT_REALTEK_RTL8411B: 87c3077021Snonaka return 1; 888fdb68d7Snonaka } 89c3077021Snonaka 90c3077021Snonaka return 0; 91c3077021Snonaka } 92c3077021Snonaka 93c3077021Snonaka static void 94c3077021Snonaka rtsx_pci_attach(device_t parent, device_t self, void *aux) 95c3077021Snonaka { 96c3077021Snonaka struct rtsx_pci_softc *sc = device_private(self); 97c3077021Snonaka struct pci_attach_args *pa = (struct pci_attach_args *)aux; 98c3077021Snonaka pci_chipset_tag_t pc = pa->pa_pc; 99c3077021Snonaka pcitag_t tag = pa->pa_tag; 100c3077021Snonaka pcireg_t reg; 101c3077021Snonaka char const *intrstr; 102c3077021Snonaka bus_space_tag_t iot; 103c3077021Snonaka bus_space_handle_t ioh; 104c3077021Snonaka bus_size_t size; 105c3077021Snonaka uint32_t flags; 106ddb8613dSmaya int bar = RTSX_PCI_BAR; 107e58a356cSchristos char intrbuf[PCI_INTRSTR_LEN]; 108c3077021Snonaka 109c3077021Snonaka sc->sc.sc_dev = self; 110c3077021Snonaka sc->sc_pc = pc; 111c3077021Snonaka 112ddb8613dSmaya switch (PCI_PRODUCT(pa->pa_id)) { 113ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTS5209: 114ddb8613dSmaya flags = RTSX_F_5209; 115ddb8613dSmaya break; 116ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTS5227: 117ddb8613dSmaya flags = RTSX_F_5227; 118ddb8613dSmaya break; 119ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTS5229: 120*c429df4aSmrg case PCI_PRODUCT_REALTEK_RTS5249: 121ddb8613dSmaya flags = RTSX_F_5229; 122ddb8613dSmaya break; 123ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTS525A: 124ddb8613dSmaya flags = RTSX_F_525A; 125ddb8613dSmaya bar = RTSX_PCI_BAR_525A; 126ddb8613dSmaya break; 127ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTL8402: 128ddb8613dSmaya flags = RTSX_F_8402; 129ddb8613dSmaya break; 130ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTL8411: 131ddb8613dSmaya flags = RTSX_F_8411; 132ddb8613dSmaya break; 133ddb8613dSmaya case PCI_PRODUCT_REALTEK_RTL8411B: 134ddb8613dSmaya flags = RTSX_F_8411B; 135ddb8613dSmaya break; 136ddb8613dSmaya default: 137ddb8613dSmaya flags = 0; 138ddb8613dSmaya break; 139ddb8613dSmaya } 140ddb8613dSmaya 141c3077021Snonaka pci_aprint_devinfo(pa, NULL); 142c3077021Snonaka 143c3077021Snonaka if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) { 144c3077021Snonaka aprint_error_dev(self, "no asic\n"); 145c3077021Snonaka return; 146c3077021Snonaka } 147c3077021Snonaka 148ddb8613dSmaya if (pci_mapreg_map(pa, bar, PCI_MAPREG_TYPE_MEM, 0, 149c3077021Snonaka &iot, &ioh, NULL, &size)) { 150c3077021Snonaka aprint_error_dev(self, "couldn't map registers\n"); 151c3077021Snonaka return; 152c3077021Snonaka } 153c3077021Snonaka 154eff3c0ecSnonaka if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) { 155eff3c0ecSnonaka aprint_error_dev(self, "couldn't map interrupt\n"); 156eff3c0ecSnonaka return; 157eff3c0ecSnonaka } 158eff3c0ecSnonaka intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 159d3cda613Sjdolecek sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_SDMMC, 160d3cda613Sjdolecek rtsx_intr, &sc->sc, device_xname(self)); 161c3077021Snonaka if (sc->sc_ih == NULL) { 162c3077021Snonaka aprint_error_dev(self, "couldn't establish interrupt\n"); 163c3077021Snonaka return; 164c3077021Snonaka } 165c3077021Snonaka aprint_normal_dev(self, "interrupting at %s\n", intrstr); 166c3077021Snonaka 167c3077021Snonaka /* Enable the device */ 168c3077021Snonaka reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 169c3077021Snonaka reg |= PCI_COMMAND_MASTER_ENABLE; 170c3077021Snonaka pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); 171c3077021Snonaka 172c3077021Snonaka /* Power up the device */ 173c3077021Snonaka pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0); 174c3077021Snonaka 175c3077021Snonaka if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) { 176c3077021Snonaka aprint_error_dev(self, "couldn't initialize chip\n"); 177c3077021Snonaka return; 178c3077021Snonaka } 179c3077021Snonaka 180c3077021Snonaka if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume, 181c3077021Snonaka rtsx_shutdown)) 182c3077021Snonaka aprint_error_dev(self, "couldn't establish powerhook\n"); 183c3077021Snonaka } 184c3077021Snonaka 185c3077021Snonaka static int 186c3077021Snonaka rtsx_pci_detach(device_t self, int flags) 187c3077021Snonaka { 188c3077021Snonaka struct rtsx_pci_softc *sc = device_private(self); 189c3077021Snonaka int rv; 190c3077021Snonaka 191c3077021Snonaka rv = rtsx_detach(&sc->sc, flags); 192c3077021Snonaka if (rv) 193c3077021Snonaka return rv; 194c3077021Snonaka 195c3077021Snonaka pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 196eff3c0ecSnonaka pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 197c3077021Snonaka 198c3077021Snonaka return 0; 199c3077021Snonaka } 200