xref: /netbsd-src/sys/dev/pci/rtsx_pci.c (revision c429df4aa04571cc2f301eddc9180027ae029374)
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