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: stable/11/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c 346397 2019-04-19 15:54:32Z bz $");
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
51242321Sgonzo#include <dev/sdhci/sdhci.h>
52318197Smarius
53318197Smarius#include "mmcbr_if.h"
54242321Sgonzo#include "sdhci_if.h"
55242321Sgonzo
56247497Sgonzo#include "bcm2835_dma.h"
57280294Sandrew#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
58247497Sgonzo#include "bcm2835_vcbus.h"
59247497Sgonzo
60243688Sgonzo#define	BCM2835_DEFAULT_SDHCI_FREQ	50
61243688Sgonzo
62247497Sgonzo#define	BCM_SDHCI_BUFFER_SIZE		512
63277038Sian#define	NUM_DMA_SEGS			2
64247497Sgonzo
65242321Sgonzo#ifdef DEBUG
66346397Sbzstatic int bcm2835_sdhci_debug = 0;
67346397Sbz
68346397SbzTUNABLE_INT("hw.bcm2835.sdhci.debug", &bcm2835_sdhci_debug);
69346397SbzSYSCTL_INT(_hw_sdhci, OID_AUTO, bcm2835_sdhci_debug, CTLFLAG_RWTUN,
70346397Sbz    &bcm2835_sdhci_debug, 0, "bcm2835 SDHCI debug level");
71346397Sbz
72346397Sbz#define	dprintf(fmt, args...)					\
73346397Sbz	do {							\
74346397Sbz		if (bcm2835_sdhci_debug)			\
75346397Sbz			printf("%s: " fmt, __func__, ##args);	\
76346397Sbz	}  while (0)
77242321Sgonzo#else
78242321Sgonzo#define dprintf(fmt, args...)
79242321Sgonzo#endif
80242321Sgonzo
81277307Sianstatic int bcm2835_sdhci_hs = 1;
82282441Sloosstatic int bcm2835_sdhci_pio_mode = 0;
83246888Sgonzo
84307575Sgonzostatic struct ofw_compat_data compat_data[] = {
85307575Sgonzo	{"broadcom,bcm2835-sdhci",	1},
86307575Sgonzo	{"brcm,bcm2835-mmc",		1},
87307575Sgonzo	{NULL,				0}
88307575Sgonzo};
89307575Sgonzo
90246888SgonzoTUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs);
91247497SgonzoTUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode);
92246888Sgonzo
93242321Sgonzostruct bcm_sdhci_softc {
94242321Sgonzo	device_t		sc_dev;
95242321Sgonzo	struct resource *	sc_mem_res;
96242321Sgonzo	struct resource *	sc_irq_res;
97242321Sgonzo	bus_space_tag_t		sc_bst;
98242321Sgonzo	bus_space_handle_t	sc_bsh;
99242321Sgonzo	void *			sc_intrhand;
100242321Sgonzo	struct mmc_request *	sc_req;
101242321Sgonzo	struct sdhci_slot	sc_slot;
102247497Sgonzo	int			sc_dma_ch;
103247497Sgonzo	bus_dma_tag_t		sc_dma_tag;
104247497Sgonzo	bus_dmamap_t		sc_dma_map;
105248430Sian	vm_paddr_t		sc_sdhci_buffer_phys;
106276985Sian	uint32_t		cmd_and_mode;
107277038Sian	bus_addr_t		dmamap_seg_addrs[NUM_DMA_SEGS];
108277038Sian	bus_size_t		dmamap_seg_sizes[NUM_DMA_SEGS];
109277028Sian	int			dmamap_seg_count;
110277038Sian	int			dmamap_seg_index;
111277028Sian	int			dmamap_status;
112242321Sgonzo};
113242321Sgonzo
114242321Sgonzostatic int bcm_sdhci_probe(device_t);
115242321Sgonzostatic int bcm_sdhci_attach(device_t);
116242321Sgonzostatic int bcm_sdhci_detach(device_t);
117242321Sgonzostatic void bcm_sdhci_intr(void *);
118242321Sgonzo
119242321Sgonzostatic int bcm_sdhci_get_ro(device_t, device_t);
120247497Sgonzostatic void bcm_sdhci_dma_intr(int ch, void *arg);
121242321Sgonzo
122247497Sgonzostatic void
123277028Sianbcm_sdhci_dmacb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
124247497Sgonzo{
125277028Sian	struct bcm_sdhci_softc *sc = arg;
126277028Sian	int i;
127247497Sgonzo
128277028Sian	sc->dmamap_status = err;
129277028Sian	sc->dmamap_seg_count = nseg;
130247497Sgonzo
131277028Sian	/* Note nseg is guaranteed to be zero if err is non-zero. */
132277028Sian	for (i = 0; i < nseg; i++) {
133277028Sian		sc->dmamap_seg_addrs[i] = segs[i].ds_addr;
134277028Sian		sc->dmamap_seg_sizes[i] = segs[i].ds_len;
135277028Sian	}
136247497Sgonzo}
137247497Sgonzo
138242321Sgonzostatic int
139242321Sgonzobcm_sdhci_probe(device_t dev)
140242321Sgonzo{
141261410Sian
142261410Sian	if (!ofw_bus_status_okay(dev))
143261410Sian		return (ENXIO);
144261410Sian
145307575Sgonzo	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
146242321Sgonzo		return (ENXIO);
147242321Sgonzo
148242321Sgonzo	device_set_desc(dev, "Broadcom 2708 SDHCI controller");
149307575Sgonzo
150242321Sgonzo	return (BUS_PROBE_DEFAULT);
151242321Sgonzo}
152242321Sgonzo
153242321Sgonzostatic int
154242321Sgonzobcm_sdhci_attach(device_t dev)
155242321Sgonzo{
156242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
157242321Sgonzo	int rid, err;
158243688Sgonzo	phandle_t node;
159243688Sgonzo	pcell_t cell;
160280294Sandrew	u_int default_freq;
161242321Sgonzo
162242321Sgonzo	sc->sc_dev = dev;
163242321Sgonzo	sc->sc_req = NULL;
164242321Sgonzo
165290381Sgonzo	err = bcm2835_mbox_set_power_state(BCM2835_MBOX_POWER_ID_EMMC,
166280294Sandrew	    TRUE);
167280294Sandrew	if (err != 0) {
168280294Sandrew		if (bootverbose)
169280294Sandrew			device_printf(dev, "Unable to enable the power\n");
170280294Sandrew		return (err);
171280294Sandrew	}
172280294Sandrew
173280294Sandrew	default_freq = 0;
174290381Sgonzo	err = bcm2835_mbox_get_clock_rate(BCM2835_MBOX_CLOCK_ID_EMMC,
175280294Sandrew	    &default_freq);
176280294Sandrew	if (err == 0) {
177280294Sandrew		/* Convert to MHz */
178280294Sandrew		default_freq /= 1000000;
179280294Sandrew	}
180281863Sloos	if (default_freq == 0) {
181281863Sloos		node = ofw_bus_get_node(sc->sc_dev);
182281863Sloos		if ((OF_getencprop(node, "clock-frequency", &cell,
183281863Sloos		    sizeof(cell))) > 0)
184281863Sloos			default_freq = cell / 1000000;
185281863Sloos	}
186280294Sandrew	if (default_freq == 0)
187280294Sandrew		default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
188280294Sandrew
189280294Sandrew	if (bootverbose)
190280294Sandrew		device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq);
191243688Sgonzo
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
234295659Sskra	sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY);
235247497Sgonzo	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
236247497Sgonzo		goto fail;
237247497Sgonzo
238247497Sgonzo	bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc);
239247497Sgonzo
240248430Sian	/* Allocate bus_dma resources. */
241247497Sgonzo	err = bus_dma_tag_create(bus_get_dma_tag(dev),
242247497Sgonzo	    1, 0, BUS_SPACE_MAXADDR_32BIT,
243247497Sgonzo	    BUS_SPACE_MAXADDR, NULL, NULL,
244277038Sian	    BCM_SDHCI_BUFFER_SIZE, NUM_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE,
245247497Sgonzo	    BUS_DMA_ALLOCNOW, NULL, NULL,
246247497Sgonzo	    &sc->sc_dma_tag);
247247497Sgonzo
248247497Sgonzo	if (err) {
249247497Sgonzo		device_printf(dev, "failed allocate DMA tag");
250247497Sgonzo		goto fail;
251247497Sgonzo	}
252247497Sgonzo
253248430Sian	err = bus_dmamap_create(sc->sc_dma_tag, 0, &sc->sc_dma_map);
254247497Sgonzo	if (err) {
255248430Sian		device_printf(dev, "bus_dmamap_create failed\n");
256247497Sgonzo		goto fail;
257247497Sgonzo	}
258247497Sgonzo
259307601Sgonzo	/* FIXME: Fix along with other BUS_SPACE_PHYSADDR instances */
260307601Sgonzo	sc->sc_sdhci_buffer_phys = rman_get_start(sc->sc_mem_res) +
261307601Sgonzo	    SDHCI_BUFFER;
262247497Sgonzo
263242321Sgonzo	bus_generic_probe(dev);
264242321Sgonzo	bus_generic_attach(dev);
265242321Sgonzo
266242321Sgonzo	sdhci_start_slot(&sc->sc_slot);
267242321Sgonzo
268242321Sgonzo	return (0);
269242321Sgonzo
270242321Sgonzofail:
271242321Sgonzo	if (sc->sc_intrhand)
272242321Sgonzo		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
273242321Sgonzo	if (sc->sc_irq_res)
274242321Sgonzo		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
275242321Sgonzo	if (sc->sc_mem_res)
276242321Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
277242321Sgonzo
278242321Sgonzo	return (err);
279242321Sgonzo}
280242321Sgonzo
281242321Sgonzostatic int
282242321Sgonzobcm_sdhci_detach(device_t dev)
283242321Sgonzo{
284242321Sgonzo
285242321Sgonzo	return (EBUSY);
286242321Sgonzo}
287242321Sgonzo
288242321Sgonzostatic void
289242321Sgonzobcm_sdhci_intr(void *arg)
290242321Sgonzo{
291242321Sgonzo	struct bcm_sdhci_softc *sc = arg;
292242321Sgonzo
293242321Sgonzo	sdhci_generic_intr(&sc->sc_slot);
294242321Sgonzo}
295242321Sgonzo
296242321Sgonzostatic int
297242321Sgonzobcm_sdhci_get_ro(device_t bus, device_t child)
298242321Sgonzo{
299242321Sgonzo
300242321Sgonzo	return (0);
301242321Sgonzo}
302242321Sgonzo
303242321Sgonzostatic inline uint32_t
304242321SgonzoRD4(struct bcm_sdhci_softc *sc, bus_size_t off)
305242321Sgonzo{
306242321Sgonzo	uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
307242321Sgonzo	return val;
308242321Sgonzo}
309242321Sgonzo
310242321Sgonzostatic inline void
311242321SgonzoWR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val)
312242321Sgonzo{
313273264Sloos
314242321Sgonzo	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
315273264Sloos	/*
316273264Sloos	 * The Arasan HC has a bug where it may lose the content of
317273264Sloos	 * consecutive writes to registers that are within two SD-card
318273264Sloos	 * clock cycles of each other (a clock domain crossing problem).
319273264Sloos	 */
320273264Sloos	if (sc->sc_slot.clock > 0)
321273264Sloos		DELAY(((2 * 1000000) / sc->sc_slot.clock) + 1);
322242321Sgonzo}
323242321Sgonzo
324242321Sgonzostatic uint8_t
325242321Sgonzobcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
326242321Sgonzo{
327242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
328242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
329242321Sgonzo
330242321Sgonzo	return ((val >> (off & 3)*8) & 0xff);
331242321Sgonzo}
332242321Sgonzo
333242321Sgonzostatic uint16_t
334242321Sgonzobcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
335242321Sgonzo{
336242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
337242321Sgonzo	uint32_t val = RD4(sc, off & ~3);
338242321Sgonzo
339276985Sian	/*
340276985Sian	 * Standard 32-bit handling of command and transfer mode.
341276985Sian	 */
342276985Sian	if (off == SDHCI_TRANSFER_MODE) {
343276985Sian		return (sc->cmd_and_mode >> 16);
344276985Sian	} else if (off == SDHCI_COMMAND_FLAGS) {
345276985Sian		return (sc->cmd_and_mode & 0x0000ffff);
346276985Sian	}
347242321Sgonzo	return ((val >> (off & 3)*8) & 0xffff);
348242321Sgonzo}
349242321Sgonzo
350242321Sgonzostatic uint32_t
351242321Sgonzobcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
352242321Sgonzo{
353242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
354242321Sgonzo
355242321Sgonzo	return RD4(sc, off);
356242321Sgonzo}
357242321Sgonzo
358242321Sgonzostatic void
359242321Sgonzobcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
360242321Sgonzo    uint32_t *data, bus_size_t count)
361242321Sgonzo{
362242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
363242321Sgonzo
364242321Sgonzo	bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
365242321Sgonzo}
366242321Sgonzo
367242321Sgonzostatic void
368242321Sgonzobcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
369242321Sgonzo{
370242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
371242321Sgonzo	uint32_t val32 = RD4(sc, off & ~3);
372242321Sgonzo	val32 &= ~(0xff << (off & 3)*8);
373242321Sgonzo	val32 |= (val << (off & 3)*8);
374242321Sgonzo	WR4(sc, off & ~3, val32);
375242321Sgonzo}
376242321Sgonzo
377242321Sgonzostatic void
378242321Sgonzobcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
379242321Sgonzo{
380242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
381242321Sgonzo	uint32_t val32;
382242321Sgonzo	if (off == SDHCI_COMMAND_FLAGS)
383276985Sian		val32 = sc->cmd_and_mode;
384242321Sgonzo	else
385242321Sgonzo		val32 = RD4(sc, off & ~3);
386242321Sgonzo	val32 &= ~(0xffff << (off & 3)*8);
387242321Sgonzo	val32 |= (val << (off & 3)*8);
388242321Sgonzo	if (off == SDHCI_TRANSFER_MODE)
389276985Sian		sc->cmd_and_mode = val32;
390277346Sian	else {
391242321Sgonzo		WR4(sc, off & ~3, val32);
392277346Sian		if (off == SDHCI_COMMAND_FLAGS)
393277346Sian			sc->cmd_and_mode = val32;
394277346Sian	}
395242321Sgonzo}
396242321Sgonzo
397242321Sgonzostatic void
398242321Sgonzobcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
399242321Sgonzo{
400242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
401242321Sgonzo	WR4(sc, off, val);
402242321Sgonzo}
403242321Sgonzo
404242321Sgonzostatic void
405242321Sgonzobcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
406242321Sgonzo    uint32_t *data, bus_size_t count)
407242321Sgonzo{
408242321Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(dev);
409242321Sgonzo
410242321Sgonzo	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
411242321Sgonzo}
412242321Sgonzo
413247497Sgonzostatic void
414277038Sianbcm_sdhci_start_dma_seg(struct bcm_sdhci_softc *sc)
415277038Sian{
416277038Sian	struct sdhci_slot *slot;
417277038Sian	vm_paddr_t pdst, psrc;
418277038Sian	int err, idx, len, sync_op;
419277038Sian
420277038Sian	slot = &sc->sc_slot;
421277038Sian	idx = sc->dmamap_seg_index++;
422277038Sian	len = sc->dmamap_seg_sizes[idx];
423277038Sian	slot->offset += len;
424277038Sian
425277038Sian	if (slot->curcmd->data->flags & MMC_DATA_READ) {
426277038Sian		bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
427277038Sian		    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
428277038Sian		bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
429277038Sian		    BCM_DMA_INC_ADDR,
430277038Sian		    (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
431277038Sian		psrc = sc->sc_sdhci_buffer_phys;
432277038Sian		pdst = sc->dmamap_seg_addrs[idx];
433277038Sian		sync_op = BUS_DMASYNC_PREREAD;
434277038Sian	} else {
435277038Sian		bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
436277038Sian		    BCM_DMA_INC_ADDR,
437277038Sian		    (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
438277038Sian		bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
439277038Sian		    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
440277038Sian		psrc = sc->dmamap_seg_addrs[idx];
441277038Sian		pdst = sc->sc_sdhci_buffer_phys;
442277038Sian		sync_op = BUS_DMASYNC_PREWRITE;
443277038Sian	}
444277038Sian
445277038Sian	/*
446277038Sian	 * When starting a new DMA operation do the busdma sync operation, and
447277038Sian	 * disable SDCHI data interrrupts because we'll be driven by DMA
448277038Sian	 * interrupts (or SDHCI error interrupts) until the IO is done.
449277038Sian	 */
450277038Sian	if (idx == 0) {
451277038Sian		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op);
452277038Sian		slot->intmask &= ~(SDHCI_INT_DATA_AVAIL |
453277038Sian		    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END);
454277038Sian		bcm_sdhci_write_4(sc->sc_dev, &sc->sc_slot, SDHCI_SIGNAL_ENABLE,
455277038Sian		    slot->intmask);
456277038Sian	}
457277038Sian
458277038Sian	/*
459277038Sian	 * Start the DMA transfer.  Only programming errors (like failing to
460277038Sian	 * allocate a channel) cause a non-zero return from bcm_dma_start().
461277038Sian	 */
462277038Sian	err = bcm_dma_start(sc->sc_dma_ch, psrc, pdst, len);
463277038Sian	KASSERT((err == 0), ("bcm2835_sdhci: failed DMA start"));
464277038Sian}
465277038Sian
466277038Sianstatic void
467247497Sgonzobcm_sdhci_dma_intr(int ch, void *arg)
468247497Sgonzo{
469247497Sgonzo	struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg;
470247497Sgonzo	struct sdhci_slot *slot = &sc->sc_slot;
471247497Sgonzo	uint32_t reg, mask;
472248430Sian	int left, sync_op;
473247497Sgonzo
474247497Sgonzo	mtx_lock(&slot->mtx);
475247497Sgonzo
476277038Sian	/*
477277038Sian	 * If there are more segments for the current dma, start the next one.
478277038Sian	 * Otherwise unload the dma map and decide what to do next based on the
479277038Sian	 * status of the sdhci controller and whether there's more data left.
480277038Sian	 */
481277038Sian	if (sc->dmamap_seg_index < sc->dmamap_seg_count) {
482277038Sian		bcm_sdhci_start_dma_seg(sc);
483277038Sian		mtx_unlock(&slot->mtx);
484277038Sian		return;
485277038Sian	}
486277038Sian
487247497Sgonzo	if (slot->curcmd->data->flags & MMC_DATA_READ) {
488248430Sian		sync_op = BUS_DMASYNC_POSTREAD;
489247497Sgonzo		mask = SDHCI_INT_DATA_AVAIL;
490247497Sgonzo	} else {
491248430Sian		sync_op = BUS_DMASYNC_POSTWRITE;
492247497Sgonzo		mask = SDHCI_INT_SPACE_AVAIL;
493247497Sgonzo	}
494248430Sian	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op);
495248430Sian	bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map);
496247497Sgonzo
497277038Sian	sc->dmamap_seg_count = 0;
498277038Sian	sc->dmamap_seg_index = 0;
499247497Sgonzo
500247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
501247497Sgonzo	    slot->curcmd->data->len - slot->offset);
502247497Sgonzo
503247497Sgonzo	/* DATA END? */
504247497Sgonzo	reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS);
505247497Sgonzo
506247497Sgonzo	if (reg & SDHCI_INT_DATA_END) {
507247497Sgonzo		/* ACK for all outstanding interrupts */
508247497Sgonzo		bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg);
509247497Sgonzo
510247497Sgonzo		/* enable INT */
511247497Sgonzo		slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL
512247497Sgonzo		    | SDHCI_INT_DATA_END;
513247497Sgonzo		bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
514247497Sgonzo		    slot->intmask);
515247497Sgonzo
516247497Sgonzo		/* finish this data */
517247497Sgonzo		sdhci_finish_data(slot);
518247497Sgonzo	}
519247497Sgonzo	else {
520247497Sgonzo		/* already available? */
521247497Sgonzo		if (reg & mask) {
522247497Sgonzo
523247497Sgonzo			/* ACK for DATA_AVAIL or SPACE_AVAIL */
524247497Sgonzo			bcm_sdhci_write_4(slot->bus, slot,
525247497Sgonzo			    SDHCI_INT_STATUS, mask);
526247497Sgonzo
527247497Sgonzo			/* continue next DMA transfer */
528277028Sian			if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
529248430Sian			    (uint8_t *)slot->curcmd->data->data +
530277028Sian			    slot->offset, left, bcm_sdhci_dmacb, sc,
531277028Sian			    BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) {
532277028Sian				slot->curcmd->error = MMC_ERR_NO_MEMORY;
533277028Sian				sdhci_finish_data(slot);
534247497Sgonzo			} else {
535277038Sian				bcm_sdhci_start_dma_seg(sc);
536247497Sgonzo			}
537247497Sgonzo		} else {
538247497Sgonzo			/* wait for next data by INT */
539247497Sgonzo
540247497Sgonzo			/* enable INT */
541247497Sgonzo			slot->intmask |= SDHCI_INT_DATA_AVAIL |
542247497Sgonzo			    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END;
543247497Sgonzo			bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
544247497Sgonzo			    slot->intmask);
545247497Sgonzo		}
546247497Sgonzo	}
547247497Sgonzo
548247497Sgonzo	mtx_unlock(&slot->mtx);
549247497Sgonzo}
550247497Sgonzo
551247497Sgonzostatic void
552277028Sianbcm_sdhci_read_dma(device_t dev, struct sdhci_slot *slot)
553247497Sgonzo{
554247497Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
555247497Sgonzo	size_t left;
556247497Sgonzo
557277038Sian	if (sc->dmamap_seg_count != 0) {
558247497Sgonzo		device_printf(sc->sc_dev, "DMA in use\n");
559247497Sgonzo		return;
560247497Sgonzo	}
561247497Sgonzo
562247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
563247497Sgonzo	    slot->curcmd->data->len - slot->offset);
564247497Sgonzo
565247497Sgonzo	KASSERT((left & 3) == 0,
566307601Sgonzo	    ("%s: len = %zu, not word-aligned", __func__, left));
567247497Sgonzo
568277028Sian	if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
569277028Sian	    (uint8_t *)slot->curcmd->data->data + slot->offset, left,
570277028Sian	    bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 ||
571277028Sian	    sc->dmamap_status != 0) {
572277028Sian		slot->curcmd->error = MMC_ERR_NO_MEMORY;
573277028Sian		return;
574277028Sian	}
575277028Sian
576247497Sgonzo	/* DMA start */
577277038Sian	bcm_sdhci_start_dma_seg(sc);
578247497Sgonzo}
579247497Sgonzo
580247497Sgonzostatic void
581277028Sianbcm_sdhci_write_dma(device_t dev, struct sdhci_slot *slot)
582247497Sgonzo{
583247497Sgonzo	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
584247497Sgonzo	size_t left;
585247497Sgonzo
586277038Sian	if (sc->dmamap_seg_count != 0) {
587247497Sgonzo		device_printf(sc->sc_dev, "DMA in use\n");
588247497Sgonzo		return;
589247497Sgonzo	}
590247497Sgonzo
591247497Sgonzo	left = min(BCM_SDHCI_BUFFER_SIZE,
592247497Sgonzo	    slot->curcmd->data->len - slot->offset);
593247497Sgonzo
594247497Sgonzo	KASSERT((left & 3) == 0,
595307601Sgonzo	    ("%s: len = %zu, not word-aligned", __func__, left));
596247497Sgonzo
597277028Sian	if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map,
598248430Sian	    (uint8_t *)slot->curcmd->data->data + slot->offset, left,
599277028Sian	    bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 ||
600277028Sian	    sc->dmamap_status != 0) {
601277028Sian		slot->curcmd->error = MMC_ERR_NO_MEMORY;
602277028Sian		return;
603277028Sian	}
604247497Sgonzo
605247497Sgonzo	/* DMA start */
606277038Sian	bcm_sdhci_start_dma_seg(sc);
607247497Sgonzo}
608247497Sgonzo
609247497Sgonzostatic int
610247497Sgonzobcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot)
611247497Sgonzo{
612247497Sgonzo	size_t left;
613247497Sgonzo
614248430Sian	/*
615248430Sian	 * Do not use DMA for transfers less than block size or with a length
616248430Sian	 * that is not a multiple of four.
617248430Sian	 */
618247497Sgonzo	left = min(BCM_DMA_BLOCK_SIZE,
619247497Sgonzo	    slot->curcmd->data->len - slot->offset);
620247497Sgonzo	if (left < BCM_DMA_BLOCK_SIZE)
621247497Sgonzo		return (0);
622248430Sian	if (left & 0x03)
623248430Sian		return (0);
624247497Sgonzo
625247497Sgonzo	return (1);
626247497Sgonzo}
627247497Sgonzo
628247497Sgonzostatic void
629247497Sgonzobcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot,
630247497Sgonzo    uint32_t *intmask)
631247497Sgonzo{
632247497Sgonzo
633247497Sgonzo	/* DMA transfer FIFO 1KB */
634247497Sgonzo	if (slot->curcmd->data->flags & MMC_DATA_READ)
635277028Sian		bcm_sdhci_read_dma(dev, slot);
636247497Sgonzo	else
637277028Sian		bcm_sdhci_write_dma(dev, slot);
638247497Sgonzo}
639247497Sgonzo
640247497Sgonzostatic void
641247497Sgonzobcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot)
642247497Sgonzo{
643247497Sgonzo
644247497Sgonzo	sdhci_finish_data(slot);
645247497Sgonzo}
646247497Sgonzo
647242321Sgonzostatic device_method_t bcm_sdhci_methods[] = {
648242321Sgonzo	/* Device interface */
649242321Sgonzo	DEVMETHOD(device_probe,		bcm_sdhci_probe),
650242321Sgonzo	DEVMETHOD(device_attach,	bcm_sdhci_attach),
651242321Sgonzo	DEVMETHOD(device_detach,	bcm_sdhci_detach),
652242321Sgonzo
653242321Sgonzo	/* Bus interface */
654242321Sgonzo	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
655242321Sgonzo	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
656242321Sgonzo
657242321Sgonzo	/* MMC bridge interface */
658242321Sgonzo	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
659242321Sgonzo	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
660242321Sgonzo	DEVMETHOD(mmcbr_get_ro,		bcm_sdhci_get_ro),
661242321Sgonzo	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
662242321Sgonzo	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
663242321Sgonzo
664247497Sgonzo	/* Platform transfer methods */
665247497Sgonzo	DEVMETHOD(sdhci_platform_will_handle,		bcm_sdhci_will_handle_transfer),
666247497Sgonzo	DEVMETHOD(sdhci_platform_start_transfer,	bcm_sdhci_start_transfer),
667247497Sgonzo	DEVMETHOD(sdhci_platform_finish_transfer,	bcm_sdhci_finish_transfer),
668242321Sgonzo	/* SDHCI registers accessors */
669242321Sgonzo	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
670242321Sgonzo	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
671242321Sgonzo	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
672242321Sgonzo	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhci_read_multi_4),
673242321Sgonzo	DEVMETHOD(sdhci_write_1,	bcm_sdhci_write_1),
674242321Sgonzo	DEVMETHOD(sdhci_write_2,	bcm_sdhci_write_2),
675242321Sgonzo	DEVMETHOD(sdhci_write_4,	bcm_sdhci_write_4),
676242321Sgonzo	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhci_write_multi_4),
677242321Sgonzo
678318197Smarius	DEVMETHOD_END
679242321Sgonzo};
680242321Sgonzo
681242321Sgonzostatic devclass_t bcm_sdhci_devclass;
682242321Sgonzo
683242321Sgonzostatic driver_t bcm_sdhci_driver = {
684242321Sgonzo	"sdhci_bcm",
685242321Sgonzo	bcm_sdhci_methods,
686242321Sgonzo	sizeof(struct bcm_sdhci_softc),
687242321Sgonzo};
688242321Sgonzo
689318197SmariusDRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass,
690318197Smarius    NULL, NULL);
691343504SmariusSDHCI_DEPEND(sdhci_bcm);
692318197SmariusMMC_DECLARE_BRIDGE(sdhci_bcm);
693