xref: /netbsd-src/sys/dev/pci/rtsx_pci.c (revision a6f3f22f245acb8ee3bbf6871d7dce989204fa97)
1 /*	$NetBSD: rtsx_pci.c,v 1.4 2015/09/05 04:56:53 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.4 2015/09/05 04:56:53 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 
41 struct rtsx_pci_softc {
42 	struct rtsx_softc sc;
43 	pci_chipset_tag_t sc_pc;
44 	void *sc_ih;
45 
46 #ifdef __HAVE_PCI_MSI_MSIX
47 	pci_intr_handle_t *sc_pihp;
48 #endif
49 };
50 
51 static int rtsx_pci_match(device_t , cfdata_t, void *);
52 static void rtsx_pci_attach(device_t, device_t, void *);
53 static int rtsx_pci_detach(device_t, int);
54 
55 CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc),
56     rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL);
57 
58 #ifdef RTSX_DEBUG
59 extern int rtsxdebug;
60 #define DPRINTF(n,s)	do { if ((n) <= rtsxdebug) printf s; } while (0)
61 #else
62 #define DPRINTF(n,s)	/**/
63 #endif
64 
65 static int
66 rtsx_pci_match(device_t parent, cfdata_t cf, void *aux)
67 {
68 	struct pci_attach_args *pa = aux;
69 
70 	/*
71 	 * Explicitly match the UNDEFINED device class only. Some RTS5902
72 	 * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED
73 	 * device class. Let sdhc(4) handle the SYSTEM/SDHC ones.
74 	 */
75 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK ||
76 	    PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED)
77 		return 0;
78 
79 	switch (PCI_PRODUCT(pa->pa_id)) {
80 	case PCI_PRODUCT_REALTEK_RTS5209:
81 	case PCI_PRODUCT_REALTEK_RTS5227:
82 	case PCI_PRODUCT_REALTEK_RTS5229:
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 
92 static void
93 rtsx_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 #ifndef __HAVE_PCI_MSI_MSIX
100 	pci_intr_handle_t ih;
101 #endif
102 	pcireg_t reg;
103 	char const *intrstr;
104 	bus_space_tag_t iot;
105 	bus_space_handle_t ioh;
106 	bus_size_t size;
107 	uint32_t flags;
108 	char intrbuf[PCI_INTRSTR_LEN];
109 
110 	sc->sc.sc_dev = self;
111 	sc->sc_pc = pc;
112 
113 	pci_aprint_devinfo(pa, NULL);
114 
115 	if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) {
116 		aprint_error_dev(self, "no asic\n");
117 		return;
118 	}
119 
120 	if (pci_mapreg_map(pa, RTSX_PCI_BAR, PCI_MAPREG_TYPE_MEM, 0,
121 	    &iot, &ioh, NULL, &size)) {
122 		aprint_error_dev(self, "couldn't map registers\n");
123 		return;
124 	}
125 
126 #ifdef __HAVE_PCI_MSI_MSIX
127 	if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) {
128 		aprint_error_dev(self, "couldn't map interrupt\n");
129 		return;
130 	}
131 	intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf));
132 	sc->sc_ih = pci_intr_establish(pc, sc->sc_pihp[0], IPL_SDMMC, rtsx_intr,
133 	    &sc->sc);
134 #else	/* !__HAVE_PCI_MSI_MSIX */
135 	if (pci_intr_map(pa, &ih)) {
136 		aprint_error_dev(self, "couldn't map interrupt\n");
137 		return;
138 	}
139 	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
140 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, rtsx_intr, &sc->sc);
141 #endif	/* __HAVE_PCI_MSI_MSIX */
142 	if (sc->sc_ih == NULL) {
143 		aprint_error_dev(self, "couldn't establish interrupt\n");
144 		return;
145 	}
146 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
147 
148 	/* Enable the device */
149 	reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
150 	reg |= PCI_COMMAND_MASTER_ENABLE;
151 	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg);
152 
153 	/* Power up the device */
154 	pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0);
155 
156 	switch (PCI_PRODUCT(pa->pa_id)) {
157 	case PCI_PRODUCT_REALTEK_RTS5209:
158 		flags = RTSX_F_5209;
159 		break;
160 	case PCI_PRODUCT_REALTEK_RTS5227:
161 		flags = RTSX_F_5227;
162 		break;
163 	case PCI_PRODUCT_REALTEK_RTS5229:
164 		flags = RTSX_F_5229;
165 		break;
166 	case PCI_PRODUCT_REALTEK_RTL8402:
167 		flags = RTSX_F_8402;
168 		break;
169 	case PCI_PRODUCT_REALTEK_RTL8411:
170 		flags = RTSX_F_8411;
171 		break;
172 	case PCI_PRODUCT_REALTEK_RTL8411B:
173 		flags = RTSX_F_8411B;
174 		break;
175 	default:
176 		flags = 0;
177 		break;
178 	}
179 
180 	if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) {
181 		aprint_error_dev(self, "couldn't initialize chip\n");
182 		return;
183 	}
184 
185 	if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume,
186 	    rtsx_shutdown))
187 		aprint_error_dev(self, "couldn't establish powerhook\n");
188 }
189 
190 static int
191 rtsx_pci_detach(device_t self, int flags)
192 {
193 	struct rtsx_pci_softc *sc = device_private(self);
194 	int rv;
195 
196 	rv = rtsx_detach(&sc->sc, flags);
197 	if (rv)
198 		return rv;
199 
200 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
201 #ifdef __HAVE_PCI_MSI_MSIX
202 	pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
203 #endif	/* __HAVE_PCI_MSI_MSIX */
204 
205 	return 0;
206 }
207