bcm2835_sdhci.c revision 247010
1242321Sgonzo/*-
2242321Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3242321Sgonzo * All rights reserved.
4242321Sgonzo *
5242321Sgonzo * Redistribution and use in source and binary forms, with or without
6242321Sgonzo * modification, are permitted provided that the following conditions
7242321Sgonzo * are met:
8242321Sgonzo * 1. Redistributions of source code must retain the above copyright
9242321Sgonzo *    notice, this list of conditions and the following disclaimer.
10242321Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11242321Sgonzo *    notice, this list of conditions and the following disclaimer in the
12242321Sgonzo *    documentation and/or other materials provided with the distribution.
13242321Sgonzo *
14242321Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15242321Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16242321Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17242321Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18242321Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19242321Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20242321Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21242321Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22242321Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23242321Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24242321Sgonzo * SUCH DAMAGE.
25242321Sgonzo *
26242321Sgonzo */
27242321Sgonzo#include <sys/cdefs.h>
28242321Sgonzo__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c 247010 2013-02-19 21:24:52Z gonzo $");
29242321Sgonzo
30242321Sgonzo#include <sys/param.h>
31242321Sgonzo#include <sys/systm.h>
32242321Sgonzo#include <sys/bio.h>
33242321Sgonzo#include <sys/bus.h>
34242321Sgonzo#include <sys/conf.h>
35242321Sgonzo#include <sys/endian.h>
36242321Sgonzo#include <sys/kernel.h>
37242321Sgonzo#include <sys/kthread.h>
38242321Sgonzo#include <sys/lock.h>
39242321Sgonzo#include <sys/malloc.h>
40242321Sgonzo#include <sys/module.h>
41242321Sgonzo#include <sys/mutex.h>
42242321Sgonzo#include <sys/queue.h>
43242321Sgonzo#include <sys/resource.h>
44242321Sgonzo#include <sys/rman.h>
45242321Sgonzo#include <sys/taskqueue.h>
46242321Sgonzo#include <sys/time.h>
47242321Sgonzo#include <sys/timetc.h>
48242321Sgonzo#include <sys/watchdog.h>
49242321Sgonzo
50242321Sgonzo#include <sys/kdb.h>
51242321Sgonzo
52242321Sgonzo#include <machine/bus.h>
53242321Sgonzo#include <machine/cpu.h>
54242321Sgonzo#include <machine/cpufunc.h>
55242321Sgonzo#include <machine/resource.h>
56242321Sgonzo#include <machine/frame.h>
57242321Sgonzo#include <machine/intr.h>
58242321Sgonzo
59243688Sgonzo#include <dev/fdt/fdt_common.h>
60242321Sgonzo#include <dev/ofw/ofw_bus.h>
61242321Sgonzo#include <dev/ofw/ofw_bus_subr.h>
62242321Sgonzo
63242321Sgonzo#include <dev/mmc/bridge.h>
64242321Sgonzo#include <dev/mmc/mmcreg.h>
65242321Sgonzo#include <dev/mmc/mmcbrvar.h>
66242321Sgonzo
67242321Sgonzo#include <dev/sdhci/sdhci.h>
68242321Sgonzo#include "sdhci_if.h"
69242321Sgonzo
70243688Sgonzo#define	BCM2835_DEFAULT_SDHCI_FREQ	50
71243688Sgonzo
72242321Sgonzo#define	DEBUG
73242321Sgonzo
74242321Sgonzo#ifdef DEBUG
75242321Sgonzo#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
76242321Sgonzo    printf(fmt,##args); } while (0)
77242321Sgonzo#else
78242321Sgonzo#define dprintf(fmt, args...)
79242321Sgonzo#endif
80242321Sgonzo
81247009Sgonzo/*
82247009Sgonzo * Arasan HC seems to have problem with Data CRC on lower frequencies.
83247010Sgonzo * Use this tunable to cap initialization sequence frequency at higher
84247010Sgonzo * value. Default is standard 400kHz
85247009Sgonzo */
86247009Sgonzostatic int bcm2835_sdhci_min_freq = 400000;
87246888Sgonzostatic int bcm2835_sdhci_hs = 1;
88246888Sgonzo
89246888SgonzoTUNABLE_INT("hw.bcm2835.sdhci.min_freq", &bcm2835_sdhci_min_freq);
90246888SgonzoTUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs);
91246888Sgonzo
92242321Sgonzostruct bcm_sdhci_dmamap_arg {
93242321Sgonzo	bus_addr_t		sc_dma_busaddr;
94242321Sgonzo};
95242321Sgonzo
96242321Sgonzostruct bcm_sdhci_softc {
97242321Sgonzo	device_t		sc_dev;
98242321Sgonzo	struct mtx		sc_mtx;
99242321Sgonzo	struct resource *	sc_mem_res;
100242321Sgonzo	struct resource *	sc_irq_res;
101242321Sgonzo	bus_space_tag_t		sc_bst;
102242321Sgonzo	bus_space_handle_t	sc_bsh;
103242321Sgonzo	void *			sc_intrhand;
104242321Sgonzo	struct mmc_request *	sc_req;
105242321Sgonzo	struct mmc_data *	sc_data;
106242321Sgonzo	uint32_t		sc_flags;
107242321Sgonzo#define	LPC_SD_FLAGS_IGNORECRC		(1 << 0)
108242321Sgonzo	int			sc_xfer_direction;
109242321Sgonzo#define	DIRECTION_READ		0
110242321Sgonzo#define	DIRECTION_WRITE		1
111242321Sgonzo	int			sc_xfer_done;
112242321Sgonzo	int			sc_bus_busy;
113242321Sgonzo	struct sdhci_slot	sc_slot;
114242321Sgonzo};
115242321Sgonzo
116242321Sgonzo#define	SD_MAX_BLOCKSIZE	1024
117242321Sgonzo/* XXX */
118242321Sgonzo
119242321Sgonzostatic int bcm_sdhci_probe(device_t);
120242321Sgonzostatic int bcm_sdhci_attach(device_t);
121242321Sgonzostatic int bcm_sdhci_detach(device_t);
122242321Sgonzostatic void bcm_sdhci_intr(void *);
123242321Sgonzo
124242321Sgonzostatic int bcm_sdhci_get_ro(device_t, device_t);
125242321Sgonzo
126242321Sgonzo#define	bcm_sdhci_lock(_sc)						\
127242321Sgonzo    mtx_lock(&_sc->sc_mtx);
128242321Sgonzo#define	bcm_sdhci_unlock(_sc)						\
129242321Sgonzo    mtx_unlock(&_sc->sc_mtx);
130242321Sgonzo
131242321Sgonzostatic int
132242321Sgonzobcm_sdhci_probe(device_t dev)
133242321Sgonzo{
134242321Sgonzo	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-sdhci"))
135242321Sgonzo		return (ENXIO);
136242321Sgonzo
137242321Sgonzo	device_set_desc(dev, "Broadcom 2708 SDHCI controller");
138242321Sgonzo	return (BUS_PROBE_DEFAULT);
139242321Sgonzo}
140242321Sgonzo
141242321Sgonzostatic int
142242321Sgonzobcm_sdhci_attach(device_t dev)
143242321Sgonzo{
144242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
145242321Sgonzo	int rid, err;
146243688Sgonzo	phandle_t node;
147243688Sgonzo	pcell_t cell;
148243688Sgonzo	int default_freq;
149242321Sgonzo
150242321Sgonzo	sc->sc_dev = dev;
151242321Sgonzo	sc->sc_req = NULL;
152242321Sgonzo
153243688Sgonzo	default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
154243688Sgonzo	node = ofw_bus_get_node(sc->sc_dev);
155243688Sgonzo	if ((OF_getprop(node, "clock-frequency", &cell, sizeof(cell))) > 0)
156243688Sgonzo		default_freq = (int)fdt32_to_cpu(cell)/1000000;
157243688Sgonzo
158243688Sgonzo	dprintf("SDHCI frequency: %dMHz\n", default_freq);
159243688Sgonzo
160242321Sgonzo	mtx_init(&sc->sc_mtx, "bcm sdhci", "sdhci", MTX_DEF);
161242321Sgonzo
162242321Sgonzo	rid = 0;
163242321Sgonzo	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
164242321Sgonzo	    RF_ACTIVE);
165242321Sgonzo	if (!sc->sc_mem_res) {
166242321Sgonzo		device_printf(dev, "cannot allocate memory window\n");
167242321Sgonzo		err = ENXIO;
168242321Sgonzo		goto fail;
169242321Sgonzo	}
170242321Sgonzo
171242321Sgonzo	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
172242321Sgonzo	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
173242321Sgonzo
174242321Sgonzo	rid = 0;
175242321Sgonzo	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
176242321Sgonzo	    RF_ACTIVE);
177242321Sgonzo	if (!sc->sc_irq_res) {
178242321Sgonzo		device_printf(dev, "cannot allocate interrupt\n");
179242321Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
180242321Sgonzo		err = ENXIO;
181242321Sgonzo		goto fail;
182242321Sgonzo	}
183242321Sgonzo
184242321Sgonzo	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
185242321Sgonzo	    NULL, bcm_sdhci_intr, sc, &sc->sc_intrhand))
186242321Sgonzo	{
187242321Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
188242321Sgonzo		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
189242321Sgonzo		device_printf(dev, "cannot setup interrupt handler\n");
190242321Sgonzo		err = ENXIO;
191242321Sgonzo		goto fail;
192242321Sgonzo	}
193242321Sgonzo
194246888Sgonzo	sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180;
195246888Sgonzo	if (bcm2835_sdhci_hs)
196246888Sgonzo		sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD;
197243688Sgonzo	sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT);
198242321Sgonzo	sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
199242321Sgonzo		| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
200242321Sgonzo		| SDHCI_QUIRK_MISSING_CAPS;
201242321Sgonzo
202242321Sgonzo	sdhci_init_slot(dev, &sc->sc_slot, 0);
203242321Sgonzo
204242321Sgonzo	bus_generic_probe(dev);
205242321Sgonzo	bus_generic_attach(dev);
206242321Sgonzo
207242321Sgonzo	sdhci_start_slot(&sc->sc_slot);
208242321Sgonzo
209242321Sgonzo	return (0);
210242321Sgonzo
211242321Sgonzofail:
212242321Sgonzo	if (sc->sc_intrhand)
213242321Sgonzo		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
214242321Sgonzo	if (sc->sc_irq_res)
215242321Sgonzo		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
216242321Sgonzo	if (sc->sc_mem_res)
217242321Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
218242321Sgonzo
219242321Sgonzo	return (err);
220242321Sgonzo}
221242321Sgonzo
222242321Sgonzostatic int
223242321Sgonzobcm_sdhci_detach(device_t dev)
224242321Sgonzo{
225242321Sgonzo
226242321Sgonzo	return (EBUSY);
227242321Sgonzo}
228242321Sgonzo
229242321Sgonzostatic void
230242321Sgonzobcm_sdhci_intr(void *arg)
231242321Sgonzo{
232242321Sgonzo	struct bcm_sdhci_softc *sc = arg;
233242321Sgonzo
234242321Sgonzo	sdhci_generic_intr(&sc->sc_slot);
235242321Sgonzo}
236242321Sgonzo
237242321Sgonzostatic int
238242321Sgonzobcm_sdhci_get_ro(device_t bus, device_t child)
239242321Sgonzo{
240242321Sgonzo
241242321Sgonzo	return (0);
242242321Sgonzo}
243242321Sgonzo
244242321Sgonzostatic inline uint32_t
245242321SgonzoRD4(struct bcm_sdhci_softc *sc, bus_size_t off)
246242321Sgonzo{
247242321Sgonzo	uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
248242321Sgonzo	return val;
249242321Sgonzo}
250242321Sgonzo
251242321Sgonzostatic inline void
252242321SgonzoWR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val)
253242321Sgonzo{
254242321Sgonzo	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
255242321Sgonzo
256242321Sgonzo	if ((off != SDHCI_BUFFER && off != SDHCI_INT_STATUS && off != SDHCI_CLOCK_CONTROL))
257242321Sgonzo	{
258242321Sgonzo		int timeout = 100000;
259242321Sgonzo		while (val != bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)
260242321Sgonzo		    && --timeout > 0)
261242321Sgonzo			continue;
262242321Sgonzo
263242321Sgonzo		if (timeout <= 0)
264242321Sgonzo			printf("sdhci_brcm: writing 0x%X to reg 0x%X "
265242321Sgonzo				"always gives 0x%X\n",
266242321Sgonzo				val, (uint32_t)off,
267242321Sgonzo				bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
268242321Sgonzo	}
269242321Sgonzo}
270242321Sgonzo
271242321Sgonzostatic uint8_t
272242321Sgonzobcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
273242321Sgonzo{
274242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
275242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
276242321Sgonzo
277242321Sgonzo	return ((val >> (off & 3)*8) & 0xff);
278242321Sgonzo}
279242321Sgonzo
280242321Sgonzostatic uint16_t
281242321Sgonzobcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
282242321Sgonzo{
283242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
284242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
285242321Sgonzo
286242321Sgonzo	return ((val >> (off & 3)*8) & 0xffff);
287242321Sgonzo}
288242321Sgonzo
289242321Sgonzostatic uint32_t
290242321Sgonzobcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
291242321Sgonzo{
292242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
293242321Sgonzo
294242321Sgonzo	return RD4(sc, off);
295242321Sgonzo}
296242321Sgonzo
297242321Sgonzostatic void
298242321Sgonzobcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
299242321Sgonzo    uint32_t *data, bus_size_t count)
300242321Sgonzo{
301242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
302242321Sgonzo
303242321Sgonzo	bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
304242321Sgonzo}
305242321Sgonzo
306242321Sgonzostatic void
307242321Sgonzobcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
308242321Sgonzo{
309242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
310242321Sgonzo	uint32_t val32 = RD4(sc, off & ~3);
311242321Sgonzo	val32 &= ~(0xff << (off & 3)*8);
312242321Sgonzo	val32 |= (val << (off & 3)*8);
313242321Sgonzo	WR4(sc, off & ~3, val32);
314242321Sgonzo}
315242321Sgonzo
316242321Sgonzostatic void
317242321Sgonzobcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
318242321Sgonzo{
319242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
320242321Sgonzo	static uint32_t cmd_and_trandfer_mode;
321242321Sgonzo	uint32_t val32;
322242321Sgonzo	if (off == SDHCI_COMMAND_FLAGS)
323242321Sgonzo		val32 = cmd_and_trandfer_mode;
324242321Sgonzo	else
325242321Sgonzo		val32 = RD4(sc, off & ~3);
326242321Sgonzo	val32 &= ~(0xffff << (off & 3)*8);
327242321Sgonzo	val32 |= (val << (off & 3)*8);
328242321Sgonzo	if (off == SDHCI_TRANSFER_MODE)
329242321Sgonzo		cmd_and_trandfer_mode = val32;
330242321Sgonzo	else
331242321Sgonzo		WR4(sc, off & ~3, val32);
332242321Sgonzo}
333242321Sgonzo
334242321Sgonzostatic void
335242321Sgonzobcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
336242321Sgonzo{
337242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
338242321Sgonzo	WR4(sc, off, val);
339242321Sgonzo}
340242321Sgonzo
341242321Sgonzostatic void
342242321Sgonzobcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
343242321Sgonzo    uint32_t *data, bus_size_t count)
344242321Sgonzo{
345242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
346242321Sgonzo
347242321Sgonzo	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
348242321Sgonzo}
349242321Sgonzo
350246888Sgonzostatic uint32_t
351246888Sgonzobcm_sdhci_min_freq(device_t dev, struct sdhci_slot *slot)
352246888Sgonzo{
353246888Sgonzo
354246888Sgonzo	return bcm2835_sdhci_min_freq;
355246888Sgonzo}
356246888Sgonzo
357242321Sgonzostatic device_method_t bcm_sdhci_methods[] = {
358242321Sgonzo	/* Device interface */
359242321Sgonzo	DEVMETHOD(device_probe,		bcm_sdhci_probe),
360242321Sgonzo	DEVMETHOD(device_attach,	bcm_sdhci_attach),
361242321Sgonzo	DEVMETHOD(device_detach,	bcm_sdhci_detach),
362242321Sgonzo
363242321Sgonzo	/* Bus interface */
364242321Sgonzo	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
365242321Sgonzo	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
366242321Sgonzo	DEVMETHOD(bus_print_child,	bus_generic_print_child),
367242321Sgonzo
368242321Sgonzo	/* MMC bridge interface */
369242321Sgonzo	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
370242321Sgonzo	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
371242321Sgonzo	DEVMETHOD(mmcbr_get_ro,		bcm_sdhci_get_ro),
372242321Sgonzo	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
373242321Sgonzo	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
374242321Sgonzo
375242321Sgonzo	/* SDHCI registers accessors */
376246888Sgonzo	DEVMETHOD(sdhci_min_freq,	bcm_sdhci_min_freq),
377242321Sgonzo	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
378242321Sgonzo	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
379242321Sgonzo	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
380242321Sgonzo	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhci_read_multi_4),
381242321Sgonzo	DEVMETHOD(sdhci_write_1,	bcm_sdhci_write_1),
382242321Sgonzo	DEVMETHOD(sdhci_write_2,	bcm_sdhci_write_2),
383242321Sgonzo	DEVMETHOD(sdhci_write_4,	bcm_sdhci_write_4),
384242321Sgonzo	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhci_write_multi_4),
385242321Sgonzo
386242321Sgonzo	{ 0, 0 }
387242321Sgonzo};
388242321Sgonzo
389242321Sgonzostatic devclass_t bcm_sdhci_devclass;
390242321Sgonzo
391242321Sgonzostatic driver_t bcm_sdhci_driver = {
392242321Sgonzo	"sdhci_bcm",
393242321Sgonzo	bcm_sdhci_methods,
394242321Sgonzo	sizeof(struct bcm_sdhci_softc),
395242321Sgonzo};
396242321Sgonzo
397242321SgonzoDRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
398242321SgonzoMODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
399