bcm2835_sdhci.c revision 282441
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 282441 2015-05-05 00:27:55Z loos $");
29242321Sgonzo
30242321Sgonzo#include <sys/param.h>
31242321Sgonzo#include <sys/systm.h>
32242321Sgonzo#include <sys/bus.h>
33242321Sgonzo#include <sys/kernel.h>
34242321Sgonzo#include <sys/lock.h>
35242321Sgonzo#include <sys/malloc.h>
36242321Sgonzo#include <sys/module.h>
37242321Sgonzo#include <sys/mutex.h>
38242321Sgonzo#include <sys/rman.h>
39270948Sian#include <sys/sysctl.h>
40242321Sgonzo#include <sys/taskqueue.h>
41242321Sgonzo
42242321Sgonzo#include <machine/bus.h>
43242321Sgonzo
44243688Sgonzo#include <dev/fdt/fdt_common.h>
45242321Sgonzo#include <dev/ofw/ofw_bus.h>
46242321Sgonzo#include <dev/ofw/ofw_bus_subr.h>
47242321Sgonzo
48242321Sgonzo#include <dev/mmc/bridge.h>
49242321Sgonzo#include <dev/mmc/mmcreg.h>
50242321Sgonzo#include <dev/mmc/mmcbrvar.h>
51242321Sgonzo
52242321Sgonzo#include <dev/sdhci/sdhci.h>
53242321Sgonzo#include "sdhci_if.h"
54242321Sgonzo
55247497Sgonzo#include "bcm2835_dma.h"
56280294Sandrew#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
57247497Sgonzo#include "bcm2835_vcbus.h"
58247497Sgonzo
59243688Sgonzo#define	BCM2835_DEFAULT_SDHCI_FREQ	50
60243688Sgonzo
61247497Sgonzo#define	BCM_SDHCI_BUFFER_SIZE		512
62277038Sian#define	NUM_DMA_SEGS			2
63247497Sgonzo
64242321Sgonzo#ifdef DEBUG
65242321Sgonzo#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
66242321Sgonzo    printf(fmt,##args); } while (0)
67242321Sgonzo#else
68242321Sgonzo#define dprintf(fmt, args...)
69242321Sgonzo#endif
70242321Sgonzo
71277307Sianstatic int bcm2835_sdhci_hs = 1;
72282441Sloosstatic int bcm2835_sdhci_pio_mode = 0;
73246888Sgonzo
74246888SgonzoTUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs);
75247497SgonzoTUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode);
76246888Sgonzo
77242321Sgonzostruct bcm_sdhci_softc {
78242321Sgonzo	device_t		sc_dev;
79242321Sgonzo	struct mtx		sc_mtx;
80242321Sgonzo	struct resource *	sc_mem_res;
81242321Sgonzo	struct resource *	sc_irq_res;
82242321Sgonzo	bus_space_tag_t		sc_bst;
83242321Sgonzo	bus_space_handle_t	sc_bsh;
84242321Sgonzo	void *			sc_intrhand;
85242321Sgonzo	struct mmc_request *	sc_req;
86242321Sgonzo	struct mmc_data *	sc_data;
87242321Sgonzo	uint32_t		sc_flags;
88242321Sgonzo#define	LPC_SD_FLAGS_IGNORECRC		(1 << 0)
89242321Sgonzo	int			sc_xfer_direction;
90242321Sgonzo#define	DIRECTION_READ		0
91242321Sgonzo#define	DIRECTION_WRITE		1
92242321Sgonzo	int			sc_xfer_done;
93242321Sgonzo	int			sc_bus_busy;
94242321Sgonzo	struct sdhci_slot	sc_slot;
95247497Sgonzo	int			sc_dma_inuse;
96247497Sgonzo	int			sc_dma_ch;
97247497Sgonzo	bus_dma_tag_t		sc_dma_tag;
98247497Sgonzo	bus_dmamap_t		sc_dma_map;
99248430Sian	vm_paddr_t		sc_sdhci_buffer_phys;
100276985Sian	uint32_t		cmd_and_mode;
101277038Sian	bus_addr_t		dmamap_seg_addrs[NUM_DMA_SEGS];
102277038Sian	bus_size_t		dmamap_seg_sizes[NUM_DMA_SEGS];
103277028Sian	int			dmamap_seg_count;
104277038Sian	int			dmamap_seg_index;
105277028Sian	int			dmamap_status;
106242321Sgonzo};
107242321Sgonzo
108242321Sgonzostatic int bcm_sdhci_probe(device_t);
109242321Sgonzostatic int bcm_sdhci_attach(device_t);
110242321Sgonzostatic int bcm_sdhci_detach(device_t);
111242321Sgonzostatic void bcm_sdhci_intr(void *);
112242321Sgonzo
113242321Sgonzostatic int bcm_sdhci_get_ro(device_t, device_t);
114247497Sgonzostatic void bcm_sdhci_dma_intr(int ch, void *arg);
115242321Sgonzo
116242321Sgonzo#define	bcm_sdhci_lock(_sc)						\
117242321Sgonzo    mtx_lock(&_sc->sc_mtx);
118242321Sgonzo#define	bcm_sdhci_unlock(_sc)						\
119242321Sgonzo    mtx_unlock(&_sc->sc_mtx);
120242321Sgonzo
121247497Sgonzostatic void
122277028Sianbcm_sdhci_dmacb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
123247497Sgonzo{
124277028Sian	struct bcm_sdhci_softc *sc = arg;
125277028Sian	int i;
126247497Sgonzo
127277028Sian	sc->dmamap_status = err;
128277028Sian	sc->dmamap_seg_count = nseg;
129247497Sgonzo
130277028Sian	/* Note nseg is guaranteed to be zero if err is non-zero. */
131277028Sian	for (i = 0; i < nseg; i++) {
132277028Sian		sc->dmamap_seg_addrs[i] = segs[i].ds_addr;
133277028Sian		sc->dmamap_seg_sizes[i] = segs[i].ds_len;
134277028Sian	}
135247497Sgonzo}
136247497Sgonzo
137242321Sgonzostatic int
138242321Sgonzobcm_sdhci_probe(device_t dev)
139242321Sgonzo{
140261410Sian
141261410Sian	if (!ofw_bus_status_okay(dev))
142261410Sian		return (ENXIO);
143261410Sian
144242321Sgonzo	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-sdhci"))
145242321Sgonzo		return (ENXIO);
146242321Sgonzo
147242321Sgonzo	device_set_desc(dev, "Broadcom 2708 SDHCI controller");
148242321Sgonzo	return (BUS_PROBE_DEFAULT);
149242321Sgonzo}
150242321Sgonzo
151242321Sgonzostatic int
152242321Sgonzobcm_sdhci_attach(device_t dev)
153242321Sgonzo{
154242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
155242321Sgonzo	int rid, err;
156243688Sgonzo	phandle_t node;
157243688Sgonzo	pcell_t cell;
158280294Sandrew	u_int default_freq;
159242321Sgonzo
160242321Sgonzo	sc->sc_dev = dev;
161242321Sgonzo	sc->sc_req = NULL;
162242321Sgonzo
163280294Sandrew	err = bcm2835_mbox_set_power_state(dev, BCM2835_MBOX_POWER_ID_EMMC,
164280294Sandrew	    TRUE);
165280294Sandrew	if (err != 0) {
166280294Sandrew		if (bootverbose)
167280294Sandrew			device_printf(dev, "Unable to enable the power\n");
168280294Sandrew		return (err);
169280294Sandrew	}
170280294Sandrew
171280294Sandrew	default_freq = 0;
172280294Sandrew	err = bcm2835_mbox_get_clock_rate(dev, BCM2835_MBOX_CLOCK_ID_EMMC,
173280294Sandrew	    &default_freq);
174280294Sandrew	if (err == 0) {
175280294Sandrew		/* Convert to MHz */
176280294Sandrew		default_freq /= 1000000;
177280294Sandrew	}
178281863Sloos	if (default_freq == 0) {
179281863Sloos		node = ofw_bus_get_node(sc->sc_dev);
180281863Sloos		if ((OF_getencprop(node, "clock-frequency", &cell,
181281863Sloos		    sizeof(cell))) > 0)
182281863Sloos			default_freq = cell / 1000000;
183281863Sloos	}
184280294Sandrew	if (default_freq == 0)
185280294Sandrew		default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
186280294Sandrew
187280294Sandrew	if (bootverbose)
188280294Sandrew		device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq);
189243688Sgonzo
190242321Sgonzo	mtx_init(&sc->sc_mtx, "bcm sdhci", "sdhci", MTX_DEF);
191242321Sgonzo
192242321Sgonzo	rid = 0;
193242321Sgonzo	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
194242321Sgonzo	    RF_ACTIVE);
195242321Sgonzo	if (!sc->sc_mem_res) {
196242321Sgonzo		device_printf(dev, "cannot allocate memory window\n");
197242321Sgonzo		err = ENXIO;
198242321Sgonzo		goto fail;
199242321Sgonzo	}
200242321Sgonzo
201242321Sgonzo	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
202242321Sgonzo	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
203242321Sgonzo
204242321Sgonzo	rid = 0;
205242321Sgonzo	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
206242321Sgonzo	    RF_ACTIVE);
207242321Sgonzo	if (!sc->sc_irq_res) {
208242321Sgonzo		device_printf(dev, "cannot allocate interrupt\n");
209242321Sgonzo		err = ENXIO;
210242321Sgonzo		goto fail;
211242321Sgonzo	}
212242321Sgonzo
213248430Sian	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
214278212Sloos	    NULL, bcm_sdhci_intr, sc, &sc->sc_intrhand)) {
215242321Sgonzo		device_printf(dev, "cannot setup interrupt handler\n");
216242321Sgonzo		err = ENXIO;
217242321Sgonzo		goto fail;
218242321Sgonzo	}
219242321Sgonzo
220247497Sgonzo	if (!bcm2835_sdhci_pio_mode)
221247497Sgonzo		sc->sc_slot.opt = SDHCI_PLATFORM_TRANSFER;
222247497Sgonzo
223246888Sgonzo	sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180;
224246888Sgonzo	if (bcm2835_sdhci_hs)
225246888Sgonzo		sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD;
226243688Sgonzo	sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT);
227242321Sgonzo	sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
228242321Sgonzo		| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
229277307Sian		| SDHCI_QUIRK_DONT_SET_HISPD_BIT
230242321Sgonzo		| SDHCI_QUIRK_MISSING_CAPS;
231242321Sgonzo
232242321Sgonzo	sdhci_init_slot(dev, &sc->sc_slot, 0);
233242321Sgonzo
234247497Sgonzo	sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST1);
235247497Sgonzo	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
236247497Sgonzo		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST2);
237247497Sgonzo	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
238247497Sgonzo		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY);
239247497Sgonzo	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
240247497Sgonzo		goto fail;
241247497Sgonzo
242247497Sgonzo	bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc);
243247497Sgonzo
244248430Sian	/* Allocate bus_dma resources. */
245247497Sgonzo	err = bus_dma_tag_create(bus_get_dma_tag(dev),
246247497Sgonzo	    1, 0, BUS_SPACE_MAXADDR_32BIT,
247247497Sgonzo	    BUS_SPACE_MAXADDR, NULL, NULL,
248277038Sian	    BCM_SDHCI_BUFFER_SIZE, NUM_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE,
249247497Sgonzo	    BUS_DMA_ALLOCNOW, NULL, NULL,
250247497Sgonzo	    &sc->sc_dma_tag);
251247497Sgonzo
252247497Sgonzo	if (err) {
253247497Sgonzo		device_printf(dev, "failed allocate DMA tag");
254247497Sgonzo		goto fail;
255247497Sgonzo	}
256247497Sgonzo
257248430Sian	err = bus_dmamap_create(sc->sc_dma_tag, 0, &sc->sc_dma_map);
258247497Sgonzo	if (err) {
259248430Sian		device_printf(dev, "bus_dmamap_create failed\n");
260247497Sgonzo		goto fail;
261247497Sgonzo	}
262247497Sgonzo
263248407Sian	sc->sc_sdhci_buffer_phys = BUS_SPACE_PHYSADDR(sc->sc_mem_res,
264248407Sian	    SDHCI_BUFFER);
265247497Sgonzo
266242321Sgonzo	bus_generic_probe(dev);
267242321Sgonzo	bus_generic_attach(dev);
268242321Sgonzo
269242321Sgonzo	sdhci_start_slot(&sc->sc_slot);
270242321Sgonzo
271242321Sgonzo	return (0);
272242321Sgonzo
273242321Sgonzofail:
274242321Sgonzo	if (sc->sc_intrhand)
275242321Sgonzo		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
276242321Sgonzo	if (sc->sc_irq_res)
277242321Sgonzo		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
278242321Sgonzo	if (sc->sc_mem_res)
279242321Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
280278212Sloos	mtx_destroy(&sc->sc_mtx);
281242321Sgonzo
282242321Sgonzo	return (err);
283242321Sgonzo}
284242321Sgonzo
285242321Sgonzostatic int
286242321Sgonzobcm_sdhci_detach(device_t dev)
287242321Sgonzo{
288242321Sgonzo
289242321Sgonzo	return (EBUSY);
290242321Sgonzo}
291242321Sgonzo
292242321Sgonzostatic void
293242321Sgonzobcm_sdhci_intr(void *arg)
294242321Sgonzo{
295242321Sgonzo	struct bcm_sdhci_softc *sc = arg;
296242321Sgonzo
297242321Sgonzo	sdhci_generic_intr(&sc->sc_slot);
298242321Sgonzo}
299242321Sgonzo
300242321Sgonzostatic int
301242321Sgonzobcm_sdhci_get_ro(device_t bus, device_t child)
302242321Sgonzo{
303242321Sgonzo
304242321Sgonzo	return (0);
305242321Sgonzo}
306242321Sgonzo
307242321Sgonzostatic inline uint32_t
308242321SgonzoRD4(struct bcm_sdhci_softc *sc, bus_size_t off)
309242321Sgonzo{
310242321Sgonzo	uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
311242321Sgonzo	return val;
312242321Sgonzo}
313242321Sgonzo
314242321Sgonzostatic inline void
315242321SgonzoWR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val)
316242321Sgonzo{
317273264Sloos
318242321Sgonzo	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
319273264Sloos	/*
320273264Sloos	 * The Arasan HC has a bug where it may lose the content of
321273264Sloos	 * consecutive writes to registers that are within two SD-card
322273264Sloos	 * clock cycles of each other (a clock domain crossing problem).
323273264Sloos	 */
324273264Sloos	if (sc->sc_slot.clock > 0)
325273264Sloos		DELAY(((2 * 1000000) / sc->sc_slot.clock) + 1);
326242321Sgonzo}
327242321Sgonzo
328242321Sgonzostatic uint8_t
329242321Sgonzobcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
330242321Sgonzo{
331242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
332242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
333242321Sgonzo
334242321Sgonzo	return ((val >> (off & 3)*8) & 0xff);
335242321Sgonzo}
336242321Sgonzo
337242321Sgonzostatic uint16_t
338242321Sgonzobcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
339242321Sgonzo{
340242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
341242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
342242321Sgonzo
343276985Sian	/*
344276985Sian	 * Standard 32-bit handling of command and transfer mode.
345276985Sian	 */
346276985Sian	if (off == SDHCI_TRANSFER_MODE) {
347276985Sian		return (sc->cmd_and_mode >> 16);
348276985Sian	} else if (off == SDHCI_COMMAND_FLAGS) {
349276985Sian		return (sc->cmd_and_mode & 0x0000ffff);
350276985Sian	}
351242321Sgonzo	return ((val >> (off & 3)*8) & 0xffff);
352242321Sgonzo}
353242321Sgonzo
354242321Sgonzostatic uint32_t
355242321Sgonzobcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
356242321Sgonzo{
357242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
358242321Sgonzo
359242321Sgonzo	return RD4(sc, off);
360242321Sgonzo}
361242321Sgonzo
362242321Sgonzostatic void
363242321Sgonzobcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
364242321Sgonzo    uint32_t *data, bus_size_t count)
365242321Sgonzo{
366242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
367242321Sgonzo
368242321Sgonzo	bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
369242321Sgonzo}
370242321Sgonzo
371242321Sgonzostatic void
372242321Sgonzobcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
373242321Sgonzo{
374242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
375242321Sgonzo	uint32_t val32 = RD4(sc, off & ~3);
376242321Sgonzo	val32 &= ~(0xff << (off & 3)*8);
377242321Sgonzo	val32 |= (val << (off & 3)*8);
378242321Sgonzo	WR4(sc, off & ~3, val32);
379242321Sgonzo}
380242321Sgonzo
381242321Sgonzostatic void
382242321Sgonzobcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
383242321Sgonzo{
384242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
385242321Sgonzo	uint32_t val32;
386242321Sgonzo	if (off == SDHCI_COMMAND_FLAGS)
387276985Sian		val32 = sc->cmd_and_mode;
388242321Sgonzo	else
389242321Sgonzo		val32 = RD4(sc, off & ~3);
390242321Sgonzo	val32 &= ~(0xffff << (off & 3)*8);
391242321Sgonzo	val32 |= (val << (off & 3)*8);
392242321Sgonzo	if (off == SDHCI_TRANSFER_MODE)
393276985Sian		sc->cmd_and_mode = val32;
394277346Sian	else {
395242321Sgonzo		WR4(sc, off & ~3, val32);
396277346Sian		if (off == SDHCI_COMMAND_FLAGS)
397277346Sian			sc->cmd_and_mode = val32;
398277346Sian	}
399242321Sgonzo}
400242321Sgonzo
401242321Sgonzostatic void
402242321Sgonzobcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
403242321Sgonzo{
404242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
405242321Sgonzo	WR4(sc, off, val);
406242321Sgonzo}
407242321Sgonzo
408242321Sgonzostatic void
409242321Sgonzobcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
410242321Sgonzo    uint32_t *data, bus_size_t count)
411242321Sgonzo{
412242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
413242321Sgonzo
414242321Sgonzo	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
415242321Sgonzo}
416242321Sgonzo
417247497Sgonzostatic void
418277038Sianbcm_sdhci_start_dma_seg(struct bcm_sdhci_softc *sc)
419277038Sian{
420277038Sian	struct sdhci_slot *slot;
421277038Sian	vm_paddr_t pdst, psrc;
422277038Sian	int err, idx, len, sync_op;
423277038Sian
424277038Sian	slot = &sc->sc_slot;
425277038Sian	idx = sc->dmamap_seg_index++;
426277038Sian	len = sc->dmamap_seg_sizes[idx];
427277038Sian	slot->offset += len;
428277038Sian
429277038Sian	if (slot->curcmd->data->flags & MMC_DATA_READ) {
430277038Sian		bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
431277038Sian		    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
432277038Sian		bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
433277038Sian		    BCM_DMA_INC_ADDR,
434277038Sian		    (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
435277038Sian		psrc = sc->sc_sdhci_buffer_phys;
436277038Sian		pdst = sc->dmamap_seg_addrs[idx];
437277038Sian		sync_op = BUS_DMASYNC_PREREAD;
438277038Sian	} else {
439277038Sian		bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
440277038Sian		    BCM_DMA_INC_ADDR,
441277038Sian		    (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
442277038Sian		bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
443277038Sian		    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
444277038Sian		psrc = sc->dmamap_seg_addrs[idx];
445277038Sian		pdst = sc->sc_sdhci_buffer_phys;
446277038Sian		sync_op = BUS_DMASYNC_PREWRITE;
447277038Sian	}
448277038Sian
449277038Sian	/*
450277038Sian	 * When starting a new DMA operation do the busdma sync operation, and
451277038Sian	 * disable SDCHI data interrrupts because we'll be driven by DMA
452277038Sian	 * interrupts (or SDHCI error interrupts) until the IO is done.
453277038Sian	 */
454277038Sian	if (idx == 0) {
455277038Sian		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op);
456277038Sian		slot->intmask &= ~(SDHCI_INT_DATA_AVAIL |
457277038Sian		    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END);
458277038Sian		bcm_sdhci_write_4(sc->sc_dev, &sc->sc_slot, SDHCI_SIGNAL_ENABLE,
459277038Sian		    slot->intmask);
460277038Sian	}
461277038Sian
462277038Sian	/*
463277038Sian	 * Start the DMA transfer.  Only programming errors (like failing to
464277038Sian	 * allocate a channel) cause a non-zero return from bcm_dma_start().
465277038Sian	 */
466277038Sian	err = bcm_dma_start(sc->sc_dma_ch, psrc, pdst, len);
467277038Sian	KASSERT((err == 0), ("bcm2835_sdhci: failed DMA start"));
468277038Sian}
469277038Sian
470277038Sianstatic void
471247497Sgonzobcm_sdhci_dma_intr(int ch, void *arg)
472247497Sgonzo{
473247497Sgonzo	struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg;
474247497Sgonzo	struct sdhci_slot *slot = &sc->sc_slot;
475247497Sgonzo	uint32_t reg, mask;
476248430Sian	int left, sync_op;
477247497Sgonzo
478247497Sgonzo	mtx_lock(&slot->mtx);
479247497Sgonzo
480277038Sian	/*
481277038Sian	 * If there are more segments for the current dma, start the next one.
482277038Sian	 * Otherwise unload the dma map and decide what to do next based on the
483277038Sian	 * status of the sdhci controller and whether there's more data left.
484277038Sian	 */
485277038Sian	if (sc->dmamap_seg_index < sc->dmamap_seg_count) {
486277038Sian		bcm_sdhci_start_dma_seg(sc);
487277038Sian		mtx_unlock(&slot->mtx);
488277038Sian		return;
489277038Sian	}
490277038Sian
491247497Sgonzo	if (slot->curcmd->data->flags & MMC_DATA_READ) {
492248430Sian		sync_op = BUS_DMASYNC_POSTREAD;
493247497Sgonzo		mask = SDHCI_INT_DATA_AVAIL;
494247497Sgonzo	} else {
495248430Sian		sync_op = BUS_DMASYNC_POSTWRITE;
496247497Sgonzo		mask = SDHCI_INT_SPACE_AVAIL;
497247497Sgonzo	}
498248430Sian	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op);
499248430Sian	bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map);
500247497Sgonzo
501277038Sian	sc->dmamap_seg_count = 0;
502277038Sian	sc->dmamap_seg_index = 0;
503247497Sgonzo
504247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
505247497Sgonzo	    slot->curcmd->data->len - slot->offset);
506247497Sgonzo
507247497Sgonzo	/* DATA END? */
508247497Sgonzo	reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS);
509247497Sgonzo
510247497Sgonzo	if (reg & SDHCI_INT_DATA_END) {
511247497Sgonzo		/* ACK for all outstanding interrupts */
512247497Sgonzo		bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg);
513247497Sgonzo
514247497Sgonzo		/* enable INT */
515247497Sgonzo		slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL
516247497Sgonzo		    | SDHCI_INT_DATA_END;
517247497Sgonzo		bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
518247497Sgonzo		    slot->intmask);
519247497Sgonzo
520247497Sgonzo		/* finish this data */
521247497Sgonzo		sdhci_finish_data(slot);
522247497Sgonzo	}
523247497Sgonzo	else {
524247497Sgonzo		/* already available? */
525247497Sgonzo		if (reg & mask) {
526247497Sgonzo
527247497Sgonzo			/* ACK for DATA_AVAIL or SPACE_AVAIL */
528247497Sgonzo			bcm_sdhci_write_4(slot->bus, slot,
529247497Sgonzo			    SDHCI_INT_STATUS, mask);
530247497Sgonzo
531247497Sgonzo			/* continue next DMA transfer */
532277028Sian			if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
533248430Sian			    (uint8_t *)slot->curcmd->data->data +
534277028Sian			    slot->offset, left, bcm_sdhci_dmacb, sc,
535277028Sian			    BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) {
536277028Sian				slot->curcmd->error = MMC_ERR_NO_MEMORY;
537277028Sian				sdhci_finish_data(slot);
538247497Sgonzo			} else {
539277038Sian				bcm_sdhci_start_dma_seg(sc);
540247497Sgonzo			}
541247497Sgonzo		} else {
542247497Sgonzo			/* wait for next data by INT */
543247497Sgonzo
544247497Sgonzo			/* enable INT */
545247497Sgonzo			slot->intmask |= SDHCI_INT_DATA_AVAIL |
546247497Sgonzo			    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END;
547247497Sgonzo			bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
548247497Sgonzo			    slot->intmask);
549247497Sgonzo		}
550247497Sgonzo	}
551247497Sgonzo
552247497Sgonzo	mtx_unlock(&slot->mtx);
553247497Sgonzo}
554247497Sgonzo
555247497Sgonzostatic void
556277028Sianbcm_sdhci_read_dma(device_t dev, struct sdhci_slot *slot)
557247497Sgonzo{
558247497Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
559247497Sgonzo	size_t left;
560247497Sgonzo
561277038Sian	if (sc->dmamap_seg_count != 0) {
562247497Sgonzo		device_printf(sc->sc_dev, "DMA in use\n");
563247497Sgonzo		return;
564247497Sgonzo	}
565247497Sgonzo
566247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
567247497Sgonzo	    slot->curcmd->data->len - slot->offset);
568247497Sgonzo
569247497Sgonzo	KASSERT((left & 3) == 0,
570247497Sgonzo	    ("%s: len = %d, not word-aligned", __func__, left));
571247497Sgonzo
572277028Sian	if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
573277028Sian	    (uint8_t *)slot->curcmd->data->data + slot->offset, left,
574277028Sian	    bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 ||
575277028Sian	    sc->dmamap_status != 0) {
576277028Sian		slot->curcmd->error = MMC_ERR_NO_MEMORY;
577277028Sian		return;
578277028Sian	}
579277028Sian
580247497Sgonzo	/* DMA start */
581277038Sian	bcm_sdhci_start_dma_seg(sc);
582247497Sgonzo}
583247497Sgonzo
584247497Sgonzostatic void
585277028Sianbcm_sdhci_write_dma(device_t dev, struct sdhci_slot *slot)
586247497Sgonzo{
587247497Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
588247497Sgonzo	size_t left;
589247497Sgonzo
590277038Sian	if (sc->dmamap_seg_count != 0) {
591247497Sgonzo		device_printf(sc->sc_dev, "DMA in use\n");
592247497Sgonzo		return;
593247497Sgonzo	}
594247497Sgonzo
595247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
596247497Sgonzo	    slot->curcmd->data->len - slot->offset);
597247497Sgonzo
598247497Sgonzo	KASSERT((left & 3) == 0,
599247497Sgonzo	    ("%s: len = %d, not word-aligned", __func__, left));
600247497Sgonzo
601277028Sian	if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
602248430Sian	    (uint8_t *)slot->curcmd->data->data + slot->offset, left,
603277028Sian	    bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 ||
604277028Sian	    sc->dmamap_status != 0) {
605277028Sian		slot->curcmd->error = MMC_ERR_NO_MEMORY;
606277028Sian		return;
607277028Sian	}
608247497Sgonzo
609247497Sgonzo	/* DMA start */
610277038Sian	bcm_sdhci_start_dma_seg(sc);
611247497Sgonzo}
612247497Sgonzo
613247497Sgonzostatic int
614247497Sgonzobcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot)
615247497Sgonzo{
616247497Sgonzo	size_t left;
617247497Sgonzo
618248430Sian	/*
619248430Sian	 * Do not use DMA for transfers less than block size or with a length
620248430Sian	 * that is not a multiple of four.
621248430Sian	 */
622247497Sgonzo	left = min(BCM_DMA_BLOCK_SIZE,
623247497Sgonzo	    slot->curcmd->data->len - slot->offset);
624247497Sgonzo	if (left < BCM_DMA_BLOCK_SIZE)
625247497Sgonzo		return (0);
626248430Sian	if (left & 0x03)
627248430Sian		return (0);
628247497Sgonzo
629247497Sgonzo	return (1);
630247497Sgonzo}
631247497Sgonzo
632247497Sgonzostatic void
633247497Sgonzobcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot,
634247497Sgonzo    uint32_t *intmask)
635247497Sgonzo{
636247497Sgonzo
637247497Sgonzo	/* DMA transfer FIFO 1KB */
638247497Sgonzo	if (slot->curcmd->data->flags & MMC_DATA_READ)
639277028Sian		bcm_sdhci_read_dma(dev, slot);
640247497Sgonzo	else
641277028Sian		bcm_sdhci_write_dma(dev, slot);
642247497Sgonzo}
643247497Sgonzo
644247497Sgonzostatic void
645247497Sgonzobcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot)
646247497Sgonzo{
647247497Sgonzo
648247497Sgonzo	sdhci_finish_data(slot);
649247497Sgonzo}
650247497Sgonzo
651242321Sgonzostatic device_method_t bcm_sdhci_methods[] = {
652242321Sgonzo	/* Device interface */
653242321Sgonzo	DEVMETHOD(device_probe,		bcm_sdhci_probe),
654242321Sgonzo	DEVMETHOD(device_attach,	bcm_sdhci_attach),
655242321Sgonzo	DEVMETHOD(device_detach,	bcm_sdhci_detach),
656242321Sgonzo
657242321Sgonzo	/* Bus interface */
658242321Sgonzo	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
659242321Sgonzo	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
660242321Sgonzo	DEVMETHOD(bus_print_child,	bus_generic_print_child),
661242321Sgonzo
662242321Sgonzo	/* MMC bridge interface */
663242321Sgonzo	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
664242321Sgonzo	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
665242321Sgonzo	DEVMETHOD(mmcbr_get_ro,		bcm_sdhci_get_ro),
666242321Sgonzo	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
667242321Sgonzo	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
668242321Sgonzo
669247497Sgonzo	/* Platform transfer methods */
670247497Sgonzo	DEVMETHOD(sdhci_platform_will_handle,		bcm_sdhci_will_handle_transfer),
671247497Sgonzo	DEVMETHOD(sdhci_platform_start_transfer,	bcm_sdhci_start_transfer),
672247497Sgonzo	DEVMETHOD(sdhci_platform_finish_transfer,	bcm_sdhci_finish_transfer),
673242321Sgonzo	/* SDHCI registers accessors */
674242321Sgonzo	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
675242321Sgonzo	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
676242321Sgonzo	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
677242321Sgonzo	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhci_read_multi_4),
678242321Sgonzo	DEVMETHOD(sdhci_write_1,	bcm_sdhci_write_1),
679242321Sgonzo	DEVMETHOD(sdhci_write_2,	bcm_sdhci_write_2),
680242321Sgonzo	DEVMETHOD(sdhci_write_4,	bcm_sdhci_write_4),
681242321Sgonzo	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhci_write_multi_4),
682242321Sgonzo
683242321Sgonzo	{ 0, 0 }
684242321Sgonzo};
685242321Sgonzo
686242321Sgonzostatic devclass_t bcm_sdhci_devclass;
687242321Sgonzo
688242321Sgonzostatic driver_t bcm_sdhci_driver = {
689242321Sgonzo	"sdhci_bcm",
690242321Sgonzo	bcm_sdhci_methods,
691242321Sgonzo	sizeof(struct bcm_sdhci_softc),
692242321Sgonzo};
693242321Sgonzo
694242321SgonzoDRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
695242321SgonzoMODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
696