xref: /freebsd/sys/dev/sdhci/sdhci_fdt.c (revision 7e6ccea3)
1 /*-
2  * Copyright (c) 2012 Thomas Skibo
3  * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /* Generic driver to attach sdhci controllers on simplebus.
28  * Derived mainly from sdhci_pci.c
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/conf.h>
38 #include <sys/kernel.h>
39 #include <sys/lock.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/resource.h>
43 #include <sys/rman.h>
44 #include <sys/sysctl.h>
45 #include <sys/taskqueue.h>
46 
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <machine/stdarg.h>
50 
51 #include <dev/fdt/fdt_common.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 
55 #include <dev/mmc/bridge.h>
56 #include <dev/mmc/mmcreg.h>
57 #include <dev/mmc/mmcbrvar.h>
58 #include <dev/sdhci/sdhci.h>
59 
60 #include "mmcbr_if.h"
61 #include "sdhci_if.h"
62 
63 #define	MAX_SLOTS	6
64 
65 struct sdhci_fdt_softc {
66 	device_t	dev;		/* Controller device */
67 	u_int		quirks;		/* Chip specific quirks */
68 	u_int		caps;		/* If we override SDHCI_CAPABILITIES */
69 	uint32_t	max_clk;	/* Max possible freq */
70 	struct resource *irq_res;	/* IRQ resource */
71 	void		*intrhand;	/* Interrupt handle */
72 
73 	int		num_slots;	/* Number of slots on this controller*/
74 	struct sdhci_slot slots[MAX_SLOTS];
75 	struct resource	*mem_res[MAX_SLOTS];	/* Memory resource */
76 };
77 
78 static uint8_t
79 sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
80 {
81 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
82 
83 	return (bus_read_1(sc->mem_res[slot->num], off));
84 }
85 
86 static void
87 sdhci_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
88     uint8_t val)
89 {
90 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
91 
92 	bus_write_1(sc->mem_res[slot->num], off, val);
93 }
94 
95 static uint16_t
96 sdhci_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
97 {
98 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
99 
100 	return (bus_read_2(sc->mem_res[slot->num], off));
101 }
102 
103 static void
104 sdhci_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off,
105     uint16_t val)
106 {
107 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
108 
109 	bus_write_2(sc->mem_res[slot->num], off, val);
110 }
111 
112 static uint32_t
113 sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
114 {
115 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
116 
117 	return (bus_read_4(sc->mem_res[slot->num], off));
118 }
119 
120 static void
121 sdhci_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
122     uint32_t val)
123 {
124 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
125 
126 	bus_write_4(sc->mem_res[slot->num], off, val);
127 }
128 
129 static void
130 sdhci_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot,
131     bus_size_t off, uint32_t *data, bus_size_t count)
132 {
133 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
134 
135 	bus_read_multi_4(sc->mem_res[slot->num], off, data, count);
136 }
137 
138 static void
139 sdhci_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot,
140     bus_size_t off, uint32_t *data, bus_size_t count)
141 {
142 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
143 
144 	bus_write_multi_4(sc->mem_res[slot->num], off, data, count);
145 }
146 
147 static void
148 sdhci_fdt_intr(void *arg)
149 {
150 	struct sdhci_fdt_softc *sc = (struct sdhci_fdt_softc *)arg;
151 	int i;
152 
153 	for (i = 0; i < sc->num_slots; i++)
154 		sdhci_generic_intr(&sc->slots[i]);
155 }
156 
157 static int
158 sdhci_fdt_probe(device_t dev)
159 {
160 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
161 	phandle_t node;
162 	pcell_t cid;
163 
164 	sc->quirks = 0;
165 	sc->num_slots = 1;
166 	sc->max_clk = 0;
167 
168 	if (!ofw_bus_status_okay(dev))
169 		return (ENXIO);
170 
171 	if (ofw_bus_is_compatible(dev, "sdhci_generic")) {
172 		device_set_desc(dev, "generic fdt SDHCI controller");
173 	} else if (ofw_bus_is_compatible(dev, "xlnx,zy7_sdhci")) {
174 		sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
175 		device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller");
176 	} else
177 		return (ENXIO);
178 
179 	node = ofw_bus_get_node(dev);
180 
181 	/* Allow dts to patch quirks, slots, and max-frequency. */
182 	if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0)
183 		sc->quirks = cid;
184 	if ((OF_getencprop(node, "num-slots", &cid, sizeof(cid))) > 0)
185 		sc->num_slots = cid;
186 	if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0)
187 		sc->max_clk = cid;
188 
189 	return (0);
190 }
191 
192 static int
193 sdhci_fdt_attach(device_t dev)
194 {
195 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
196 	struct sdhci_slot *slot;
197 	int err, slots, rid, i;
198 
199 	sc->dev = dev;
200 
201 	/* Allocate IRQ. */
202 	rid = 0;
203 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
204 	    RF_ACTIVE);
205 	if (sc->irq_res == NULL) {
206 		device_printf(dev, "Can't allocate IRQ\n");
207 		return (ENOMEM);
208 	}
209 
210 	/* Scan all slots. */
211 	slots = sc->num_slots;	/* number of slots determined in probe(). */
212 	sc->num_slots = 0;
213 	for (i = 0; i < slots; i++) {
214 		slot = &sc->slots[sc->num_slots];
215 
216 		/* Allocate memory. */
217 		rid = 0;
218 		sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
219 							&rid, RF_ACTIVE);
220 		if (sc->mem_res[i] == NULL) {
221 			device_printf(dev,
222 			    "Can't allocate memory for slot %d\n", i);
223 			continue;
224 		}
225 
226 		slot->quirks = sc->quirks;
227 		slot->caps = sc->caps;
228 		slot->max_clk = sc->max_clk;
229 
230 		if (sdhci_init_slot(dev, slot, i) != 0)
231 			continue;
232 
233 		sc->num_slots++;
234 	}
235 	device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
236 
237 	/* Activate the interrupt */
238 	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
239 	    NULL, sdhci_fdt_intr, sc, &sc->intrhand);
240 	if (err) {
241 		device_printf(dev, "Cannot setup IRQ\n");
242 		return (err);
243 	}
244 
245 	/* Process cards detection. */
246 	for (i = 0; i < sc->num_slots; i++)
247 		sdhci_start_slot(&sc->slots[i]);
248 
249 	return (0);
250 }
251 
252 static int
253 sdhci_fdt_detach(device_t dev)
254 {
255 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
256 	int i;
257 
258 	bus_generic_detach(dev);
259 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
260 	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
261 	    sc->irq_res);
262 
263 	for (i = 0; i < sc->num_slots; i++) {
264 		sdhci_cleanup_slot(&sc->slots[i]);
265 		bus_release_resource(dev, SYS_RES_MEMORY,
266 		    rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
267 	}
268 
269 	return (0);
270 }
271 
272 static device_method_t sdhci_fdt_methods[] = {
273 	/* device_if */
274 	DEVMETHOD(device_probe,		sdhci_fdt_probe),
275 	DEVMETHOD(device_attach,	sdhci_fdt_attach),
276 	DEVMETHOD(device_detach,	sdhci_fdt_detach),
277 
278 	/* Bus interface */
279 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
280 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
281 
282 	/* mmcbr_if */
283 	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
284 	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
285 	DEVMETHOD(mmcbr_get_ro,		sdhci_generic_get_ro),
286 	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
287 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
288 
289 	/* SDHCI registers accessors */
290 	DEVMETHOD(sdhci_read_1,		sdhci_fdt_read_1),
291 	DEVMETHOD(sdhci_read_2,		sdhci_fdt_read_2),
292 	DEVMETHOD(sdhci_read_4,		sdhci_fdt_read_4),
293 	DEVMETHOD(sdhci_read_multi_4,	sdhci_fdt_read_multi_4),
294 	DEVMETHOD(sdhci_write_1,	sdhci_fdt_write_1),
295 	DEVMETHOD(sdhci_write_2,	sdhci_fdt_write_2),
296 	DEVMETHOD(sdhci_write_4,	sdhci_fdt_write_4),
297 	DEVMETHOD(sdhci_write_multi_4,	sdhci_fdt_write_multi_4),
298 
299 	DEVMETHOD_END
300 };
301 
302 static driver_t sdhci_fdt_driver = {
303 	"sdhci_fdt",
304 	sdhci_fdt_methods,
305 	sizeof(struct sdhci_fdt_softc),
306 };
307 static devclass_t sdhci_fdt_devclass;
308 
309 DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, sdhci_fdt_devclass,
310     NULL, NULL);
311 MODULE_DEPEND(sdhci_fdt, sdhci, 1, 1, 1);
312 DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL);
313 MODULE_DEPEND(sdhci_fdt, mmc, 1, 1, 1);
314