bcm2835_sdhci.c revision 248407
1/*-
2 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c 248407 2013-03-17 03:04:43Z ian $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bio.h>
33#include <sys/bus.h>
34#include <sys/conf.h>
35#include <sys/endian.h>
36#include <sys/kernel.h>
37#include <sys/kthread.h>
38#include <sys/lock.h>
39#include <sys/malloc.h>
40#include <sys/module.h>
41#include <sys/mutex.h>
42#include <sys/queue.h>
43#include <sys/resource.h>
44#include <sys/rman.h>
45#include <sys/taskqueue.h>
46#include <sys/time.h>
47#include <sys/timetc.h>
48#include <sys/watchdog.h>
49
50#include <sys/kdb.h>
51
52#include <machine/bus.h>
53#include <machine/cpu.h>
54#include <machine/cpufunc.h>
55#include <machine/resource.h>
56#include <machine/frame.h>
57#include <machine/intr.h>
58
59#include <dev/fdt/fdt_common.h>
60#include <dev/ofw/ofw_bus.h>
61#include <dev/ofw/ofw_bus_subr.h>
62
63#include <dev/mmc/bridge.h>
64#include <dev/mmc/mmcreg.h>
65#include <dev/mmc/mmcbrvar.h>
66
67#include <dev/sdhci/sdhci.h>
68#include "sdhci_if.h"
69
70#include "bcm2835_dma.h"
71#include "bcm2835_vcbus.h"
72
73#define	BCM2835_DEFAULT_SDHCI_FREQ	50
74
75#define	BCM_SDHCI_BUFFER_SIZE		512
76
77#define	DEBUG
78
79#ifdef DEBUG
80#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
81    printf(fmt,##args); } while (0)
82#else
83#define dprintf(fmt, args...)
84#endif
85
86/*
87 * Arasan HC seems to have problem with Data CRC on lower frequencies.
88 * Use this tunable to cap initialization sequence frequency at higher
89 * value. Default is standard 400kHz
90 */
91static int bcm2835_sdhci_min_freq = 400000;
92static int bcm2835_sdhci_hs = 1;
93static int bcm2835_sdhci_pio_mode = 0;
94
95TUNABLE_INT("hw.bcm2835.sdhci.min_freq", &bcm2835_sdhci_min_freq);
96TUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs);
97TUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode);
98
99struct bcm_sdhci_dmamap_arg {
100	bus_addr_t		sc_dma_busaddr;
101};
102
103struct bcm_sdhci_softc {
104	device_t		sc_dev;
105	struct mtx		sc_mtx;
106	struct resource *	sc_mem_res;
107	struct resource *	sc_irq_res;
108	bus_space_tag_t		sc_bst;
109	bus_space_handle_t	sc_bsh;
110	void *			sc_intrhand;
111	struct mmc_request *	sc_req;
112	struct mmc_data *	sc_data;
113	uint32_t		sc_flags;
114#define	LPC_SD_FLAGS_IGNORECRC		(1 << 0)
115	int			sc_xfer_direction;
116#define	DIRECTION_READ		0
117#define	DIRECTION_WRITE		1
118	int			sc_xfer_done;
119	int			sc_bus_busy;
120	struct sdhci_slot	sc_slot;
121	int			sc_dma_inuse;
122	int			sc_dma_ch;
123	bus_dma_tag_t		sc_dma_tag;
124	bus_dmamap_t		sc_dma_map;
125	void			*sc_dma_buffer;
126	vm_paddr_t		sc_dma_buffer_phys;
127	vm_paddr_t		sc_sdhci_buffer_phys;;
128};
129
130static int bcm_sdhci_probe(device_t);
131static int bcm_sdhci_attach(device_t);
132static int bcm_sdhci_detach(device_t);
133static void bcm_sdhci_intr(void *);
134
135static int bcm_sdhci_get_ro(device_t, device_t);
136static void bcm_sdhci_dma_intr(int ch, void *arg);
137
138#define	bcm_sdhci_lock(_sc)						\
139    mtx_lock(&_sc->sc_mtx);
140#define	bcm_sdhci_unlock(_sc)						\
141    mtx_unlock(&_sc->sc_mtx);
142
143static void
144bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs,
145	int nseg, int err)
146{
147        bus_addr_t *addr;
148
149        if (err)
150                return;
151
152        addr = (bus_addr_t*)arg;
153        *addr = segs[0].ds_addr;
154}
155
156static int
157bcm_sdhci_probe(device_t dev)
158{
159	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-sdhci"))
160		return (ENXIO);
161
162	device_set_desc(dev, "Broadcom 2708 SDHCI controller");
163	return (BUS_PROBE_DEFAULT);
164}
165
166static int
167bcm_sdhci_attach(device_t dev)
168{
169	struct bcm_sdhci_softc *sc = device_get_softc(dev);
170	int rid, err;
171	phandle_t node;
172	pcell_t cell;
173	int default_freq;
174	void *buffer;
175	vm_paddr_t buffer_phys;
176
177	sc->sc_dev = dev;
178	sc->sc_req = NULL;
179	err = 0;
180
181	default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
182	node = ofw_bus_get_node(sc->sc_dev);
183	if ((OF_getprop(node, "clock-frequency", &cell, sizeof(cell))) > 0)
184		default_freq = (int)fdt32_to_cpu(cell)/1000000;
185
186	dprintf("SDHCI frequency: %dMHz\n", default_freq);
187
188	mtx_init(&sc->sc_mtx, "bcm sdhci", "sdhci", MTX_DEF);
189
190	rid = 0;
191	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
192	    RF_ACTIVE);
193	if (!sc->sc_mem_res) {
194		device_printf(dev, "cannot allocate memory window\n");
195		err = ENXIO;
196		goto fail;
197	}
198
199	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
200	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
201
202	rid = 0;
203	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
204	    RF_ACTIVE);
205	if (!sc->sc_irq_res) {
206		device_printf(dev, "cannot allocate interrupt\n");
207		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
208		err = ENXIO;
209		goto fail;
210	}
211
212	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
213	    NULL, bcm_sdhci_intr, sc, &sc->sc_intrhand))
214	{
215		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
216		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
217		device_printf(dev, "cannot setup interrupt handler\n");
218		err = ENXIO;
219		goto fail;
220	}
221
222	if (!bcm2835_sdhci_pio_mode)
223		sc->sc_slot.opt = SDHCI_PLATFORM_TRANSFER;
224
225	sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180;
226	if (bcm2835_sdhci_hs)
227		sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD;
228	sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT);
229	sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
230		| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
231		| SDHCI_QUIRK_MISSING_CAPS;
232
233	sdhci_init_slot(dev, &sc->sc_slot, 0);
234
235	sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST1);
236	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
237		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST2);
238	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
239		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY);
240	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
241		goto fail;
242
243	bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc);
244
245	/* Allocate DMA buffers */
246	err = bus_dma_tag_create(bus_get_dma_tag(dev),
247	    1, 0, BUS_SPACE_MAXADDR_32BIT,
248	    BUS_SPACE_MAXADDR, NULL, NULL,
249	    BCM_SDHCI_BUFFER_SIZE, 1, BCM_SDHCI_BUFFER_SIZE,
250	    BUS_DMA_ALLOCNOW, NULL, NULL,
251	    &sc->sc_dma_tag);
252
253	if (err) {
254		device_printf(dev, "failed allocate DMA tag");
255		goto fail;
256	}
257
258	err = bus_dmamem_alloc(sc->sc_dma_tag, &buffer,
259	    BUS_DMA_WAITOK | BUS_DMA_COHERENT| BUS_DMA_ZERO,
260	    &sc->sc_dma_map);
261
262	if (err) {
263		device_printf(dev, "cannot allocate DMA memory\n");
264		goto fail;
265	}
266
267	err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, buffer,
268	    BCM_SDHCI_BUFFER_SIZE, bcm_dmamap_cb, &buffer_phys,
269	    BUS_DMA_WAITOK);
270	if (err) {
271		device_printf(dev, "cannot load DMA memory\n");
272		goto fail;
273	}
274
275	/*
276	 * Sanity check: two least bits of address should be zero
277	 */
278	if ((uintptr_t)buffer & 3) {
279		device_printf(dev,
280		    "DMA address is not word-aligned\n");
281		goto fail;
282	}
283
284	sc->sc_dma_buffer = buffer;
285	sc->sc_dma_buffer_phys = buffer_phys;
286	sc->sc_sdhci_buffer_phys = BUS_SPACE_PHYSADDR(sc->sc_mem_res,
287	    SDHCI_BUFFER);
288
289	bus_generic_probe(dev);
290	bus_generic_attach(dev);
291
292	sdhci_start_slot(&sc->sc_slot);
293
294	return (0);
295
296fail:
297	if (sc->sc_intrhand)
298		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
299	if (sc->sc_irq_res)
300		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
301	if (sc->sc_mem_res)
302		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
303
304	return (err);
305}
306
307static int
308bcm_sdhci_detach(device_t dev)
309{
310
311	return (EBUSY);
312}
313
314static void
315bcm_sdhci_intr(void *arg)
316{
317	struct bcm_sdhci_softc *sc = arg;
318
319	sdhci_generic_intr(&sc->sc_slot);
320}
321
322static int
323bcm_sdhci_get_ro(device_t bus, device_t child)
324{
325
326	return (0);
327}
328
329static inline uint32_t
330RD4(struct bcm_sdhci_softc *sc, bus_size_t off)
331{
332	uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
333	return val;
334}
335
336static inline void
337WR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val)
338{
339	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
340
341	if ((off != SDHCI_BUFFER && off != SDHCI_INT_STATUS && off != SDHCI_CLOCK_CONTROL))
342	{
343		int timeout = 100000;
344		while (val != bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)
345		    && --timeout > 0)
346			continue;
347
348		if (timeout <= 0)
349			printf("sdhci_brcm: writing 0x%X to reg 0x%X "
350				"always gives 0x%X\n",
351				val, (uint32_t)off,
352				bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
353	}
354}
355
356static uint8_t
357bcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
358{
359	struct bcm_sdhci_softc *sc = device_get_softc(dev);
360	uint32_t val = RD4(sc, off & ~3);
361
362	return ((val >> (off & 3)*8) & 0xff);
363}
364
365static uint16_t
366bcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
367{
368	struct bcm_sdhci_softc *sc = device_get_softc(dev);
369	uint32_t val = RD4(sc, off & ~3);
370
371	return ((val >> (off & 3)*8) & 0xffff);
372}
373
374static uint32_t
375bcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
376{
377	struct bcm_sdhci_softc *sc = device_get_softc(dev);
378
379	return RD4(sc, off);
380}
381
382static void
383bcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
384    uint32_t *data, bus_size_t count)
385{
386	struct bcm_sdhci_softc *sc = device_get_softc(dev);
387
388	bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
389}
390
391static void
392bcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
393{
394	struct bcm_sdhci_softc *sc = device_get_softc(dev);
395	uint32_t val32 = RD4(sc, off & ~3);
396	val32 &= ~(0xff << (off & 3)*8);
397	val32 |= (val << (off & 3)*8);
398	WR4(sc, off & ~3, val32);
399}
400
401static void
402bcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
403{
404	struct bcm_sdhci_softc *sc = device_get_softc(dev);
405	static uint32_t cmd_and_trandfer_mode;
406	uint32_t val32;
407	if (off == SDHCI_COMMAND_FLAGS)
408		val32 = cmd_and_trandfer_mode;
409	else
410		val32 = RD4(sc, off & ~3);
411	val32 &= ~(0xffff << (off & 3)*8);
412	val32 |= (val << (off & 3)*8);
413	if (off == SDHCI_TRANSFER_MODE)
414		cmd_and_trandfer_mode = val32;
415	else
416		WR4(sc, off & ~3, val32);
417}
418
419static void
420bcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
421{
422	struct bcm_sdhci_softc *sc = device_get_softc(dev);
423	WR4(sc, off, val);
424}
425
426static void
427bcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
428    uint32_t *data, bus_size_t count)
429{
430	struct bcm_sdhci_softc *sc = device_get_softc(dev);
431
432	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
433}
434
435static uint32_t
436bcm_sdhci_min_freq(device_t dev, struct sdhci_slot *slot)
437{
438
439	return bcm2835_sdhci_min_freq;
440}
441
442static void
443bcm_sdhci_dma_intr(int ch, void *arg)
444{
445	struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg;
446	struct sdhci_slot *slot = &sc->sc_slot;
447	uint32_t reg, mask;
448	void *buffer;
449	size_t len;
450	int left;
451
452	mtx_lock(&slot->mtx);
453
454	/* copy DMA buffer to VA if READ */
455	len = bcm_dma_length(sc->sc_dma_ch);
456	if (slot->curcmd->data->flags & MMC_DATA_READ) {
457		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
458		    BUS_DMASYNC_POSTREAD);
459
460		mask = SDHCI_INT_DATA_AVAIL;
461		/* all dma data in single or contiguous page */
462		buffer = (uint8_t*)(slot->curcmd->data->data) + slot->offset;
463		memcpy(buffer, sc->sc_dma_buffer, len);
464	} else {
465		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
466		    BUS_DMASYNC_POSTWRITE);
467		mask = SDHCI_INT_SPACE_AVAIL;
468	}
469
470	slot->offset += len;
471	sc->sc_dma_inuse = 0;
472
473	left = min(BCM_SDHCI_BUFFER_SIZE,
474	    slot->curcmd->data->len - slot->offset);
475
476	/* DATA END? */
477	reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS);
478
479	if (reg & SDHCI_INT_DATA_END) {
480		/* ACK for all outstanding interrupts */
481		bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg);
482
483		/* enable INT */
484		slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL
485		    | SDHCI_INT_DATA_END;
486		bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
487		    slot->intmask);
488
489		/* finish this data */
490		sdhci_finish_data(slot);
491	}
492	else {
493		/* already available? */
494		if (reg & mask) {
495			sc->sc_dma_inuse = 1;
496
497			/* ACK for DATA_AVAIL or SPACE_AVAIL */
498			bcm_sdhci_write_4(slot->bus, slot,
499			    SDHCI_INT_STATUS, mask);
500
501			/* continue next DMA transfer */
502			if (slot->curcmd->data->flags & MMC_DATA_READ) {
503				bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
504				    BUS_DMASYNC_PREREAD);
505
506				/* DMA start */
507				if (bcm_dma_start(sc->sc_dma_ch,
508				    sc->sc_sdhci_buffer_phys,
509				    sc->sc_dma_buffer_phys, left) != 0)
510					device_printf(sc->sc_dev, "failed DMA start\n");
511			} else {
512				buffer = (char*)slot->curcmd->data->data + slot->offset;
513				memcpy(sc->sc_dma_buffer, buffer, left);
514
515				bus_dmamap_sync(sc->sc_dma_tag,
516				    sc->sc_dma_map, BUS_DMASYNC_PREWRITE);
517
518				/* DMA start */
519				if (bcm_dma_start(sc->sc_dma_ch,
520				    sc->sc_dma_buffer_phys,
521				    sc->sc_sdhci_buffer_phys, left) != 0)
522					device_printf(sc->sc_dev, "failed DMA start\n");
523			}
524		} else {
525			/* wait for next data by INT */
526
527			/* enable INT */
528			slot->intmask |= SDHCI_INT_DATA_AVAIL |
529			    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END;
530			bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
531			    slot->intmask);
532		}
533	}
534
535	mtx_unlock(&slot->mtx);
536}
537
538static void
539bcm_sdhci_read_dma(struct sdhci_slot *slot)
540{
541	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
542	size_t left;
543
544	if (sc->sc_dma_inuse) {
545		device_printf(sc->sc_dev, "DMA in use\n");
546		return;
547	}
548
549	sc->sc_dma_inuse = 1;
550
551	left = min(BCM_SDHCI_BUFFER_SIZE,
552	    slot->curcmd->data->len - slot->offset);
553
554	KASSERT((left & 3) == 0,
555	    ("%s: len = %d, not word-aligned", __func__, left));
556
557	bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
558	    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
559	bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
560	    BCM_DMA_INC_ADDR,
561	    (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
562
563	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
564	    BUS_DMASYNC_PREREAD);
565
566	/* DMA start */
567	if (bcm_dma_start(sc->sc_dma_ch, sc->sc_sdhci_buffer_phys,
568	    sc->sc_dma_buffer_phys, left) != 0)
569		device_printf(sc->sc_dev, "failed DMA start\n");
570}
571
572static void
573bcm_sdhci_write_dma(struct sdhci_slot *slot)
574{
575	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
576	char *buffer;
577	size_t left;
578
579	if (sc->sc_dma_inuse) {
580		device_printf(sc->sc_dev, "DMA in use\n");
581		return;
582	}
583
584	sc->sc_dma_inuse = 1;
585
586	left = min(BCM_SDHCI_BUFFER_SIZE,
587	    slot->curcmd->data->len - slot->offset);
588
589	KASSERT((left & 3) == 0,
590	    ("%s: len = %d, not word-aligned", __func__, left));
591
592	buffer = (char*)slot->curcmd->data->data + slot->offset;
593	memcpy(sc->sc_dma_buffer, buffer, left);
594
595	bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
596	    BCM_DMA_INC_ADDR,
597	    (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
598	bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
599	    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
600
601	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
602	    BUS_DMASYNC_PREWRITE);
603
604	/* DMA start */
605	if (bcm_dma_start(sc->sc_dma_ch, sc->sc_dma_buffer_phys,
606	    sc->sc_sdhci_buffer_phys, left) != 0)
607		device_printf(sc->sc_dev, "failed DMA start\n");
608}
609
610static int
611bcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot)
612{
613	size_t left;
614
615	/* Do not use DMA for transfers less then block size */
616	left = min(BCM_DMA_BLOCK_SIZE,
617	    slot->curcmd->data->len - slot->offset);
618	if (left < BCM_DMA_BLOCK_SIZE)
619		return (0);
620
621	return (1);
622}
623
624static void
625bcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot,
626    uint32_t *intmask)
627{
628
629	/* Disable INT */
630	slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END);
631	bcm_sdhci_write_4(dev, slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
632
633	/* DMA transfer FIFO 1KB */
634	if (slot->curcmd->data->flags & MMC_DATA_READ)
635		bcm_sdhci_read_dma(slot);
636	else
637		bcm_sdhci_write_dma(slot);
638}
639
640static void
641bcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot)
642{
643
644	sdhci_finish_data(slot);
645}
646
647static device_method_t bcm_sdhci_methods[] = {
648	/* Device interface */
649	DEVMETHOD(device_probe,		bcm_sdhci_probe),
650	DEVMETHOD(device_attach,	bcm_sdhci_attach),
651	DEVMETHOD(device_detach,	bcm_sdhci_detach),
652
653	/* Bus interface */
654	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
655	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
656	DEVMETHOD(bus_print_child,	bus_generic_print_child),
657
658	/* MMC bridge interface */
659	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
660	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
661	DEVMETHOD(mmcbr_get_ro,		bcm_sdhci_get_ro),
662	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
663	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
664
665	DEVMETHOD(sdhci_min_freq,	bcm_sdhci_min_freq),
666	/* Platform transfer methods */
667	DEVMETHOD(sdhci_platform_will_handle,		bcm_sdhci_will_handle_transfer),
668	DEVMETHOD(sdhci_platform_start_transfer,	bcm_sdhci_start_transfer),
669	DEVMETHOD(sdhci_platform_finish_transfer,	bcm_sdhci_finish_transfer),
670	/* SDHCI registers accessors */
671	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
672	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
673	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
674	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhci_read_multi_4),
675	DEVMETHOD(sdhci_write_1,	bcm_sdhci_write_1),
676	DEVMETHOD(sdhci_write_2,	bcm_sdhci_write_2),
677	DEVMETHOD(sdhci_write_4,	bcm_sdhci_write_4),
678	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhci_write_multi_4),
679
680	{ 0, 0 }
681};
682
683static devclass_t bcm_sdhci_devclass;
684
685static driver_t bcm_sdhci_driver = {
686	"sdhci_bcm",
687	bcm_sdhci_methods,
688	sizeof(struct bcm_sdhci_softc),
689};
690
691DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
692MODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
693