bcm2835_sdhci.c revision 247497
160484Sobrien/*-
278828Sobrien * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
360484Sobrien * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
733965Sjdp * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
960484Sobrien *    notice, this list of conditions and the following disclaimer.
1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer in the
1233965Sjdp *    documentation and/or other materials provided with the distribution.
1333965Sjdp *
1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1733965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838889Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938889Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038889Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277298Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2433965Sjdp * SUCH DAMAGE.
2533965Sjdp *
2633965Sjdp */
2733965Sjdp#include <sys/cdefs.h>
2833965Sjdp__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c 247497 2013-02-28 19:51:30Z gonzo $");
2933965Sjdp
3033965Sjdp#include <sys/param.h>
3133965Sjdp#include <sys/systm.h>
3233965Sjdp#include <sys/bio.h>
3333965Sjdp#include <sys/bus.h>
3433965Sjdp#include <sys/conf.h>
3533965Sjdp#include <sys/endian.h>
3678828Sobrien#include <sys/kernel.h>
3733965Sjdp#include <sys/kthread.h>
3833965Sjdp#include <sys/lock.h>
3933965Sjdp#include <sys/malloc.h>
4033965Sjdp#include <sys/module.h>
4133965Sjdp#include <sys/mutex.h>
4233965Sjdp#include <sys/queue.h>
4333965Sjdp#include <sys/resource.h>
4433965Sjdp#include <sys/rman.h>
4533965Sjdp#include <sys/taskqueue.h>
4633965Sjdp#include <sys/time.h>
4733965Sjdp#include <sys/timetc.h>
4833965Sjdp#include <sys/watchdog.h>
4933965Sjdp
5033965Sjdp#include <sys/kdb.h>
5138889Sjdp
5238889Sjdp#include <machine/bus.h>
5338889Sjdp#include <machine/cpu.h>
5433965Sjdp#include <machine/cpufunc.h>
5533965Sjdp#include <machine/resource.h>
5638889Sjdp#include <machine/frame.h>
5733965Sjdp#include <machine/intr.h>
5877298Sobrien
5933965Sjdp#include <dev/fdt/fdt_common.h>
6033965Sjdp#include <dev/ofw/ofw_bus.h>
6133965Sjdp#include <dev/ofw/ofw_bus_subr.h>
6233965Sjdp
6333965Sjdp#include <dev/mmc/bridge.h>
6433965Sjdp#include <dev/mmc/mmcreg.h>
6533965Sjdp#include <dev/mmc/mmcbrvar.h>
6677298Sobrien
6777298Sobrien#include <dev/sdhci/sdhci.h>
6833965Sjdp#include "sdhci_if.h"
6933965Sjdp
7033965Sjdp#include "bcm2835_dma.h"
7133965Sjdp#include "bcm2835_vcbus.h"
7233965Sjdp
7377298Sobrien#define	BCM2835_DEFAULT_SDHCI_FREQ	50
7433965Sjdp
7533965Sjdp#define	BCM_SDHCI_BUFFER_SIZE		512
7633965Sjdp
7733965Sjdp#define	DEBUG
7833965Sjdp
7933965Sjdp#ifdef DEBUG
8033965Sjdp#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
8133965Sjdp    printf(fmt,##args); } while (0)
8233965Sjdp#else
8333965Sjdp#define dprintf(fmt, args...)
8433965Sjdp#endif
8533965Sjdp
8633965Sjdp/*
8733965Sjdp * Arasan HC seems to have problem with Data CRC on lower frequencies.
8833965Sjdp * Use this tunable to cap initialization sequence frequency at higher
8933965Sjdp * value. Default is standard 400kHz
9033965Sjdp */
9133965Sjdpstatic int bcm2835_sdhci_min_freq = 400000;
9233965Sjdpstatic int bcm2835_sdhci_hs = 1;
9333965Sjdpstatic int bcm2835_sdhci_pio_mode = 0;
9433965Sjdp
9533965SjdpTUNABLE_INT("hw.bcm2835.sdhci.min_freq", &bcm2835_sdhci_min_freq);
9633965SjdpTUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs);
9733965SjdpTUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode);
9833965Sjdp
9933965Sjdpstruct bcm_sdhci_dmamap_arg {
10033965Sjdp	bus_addr_t		sc_dma_busaddr;
10160484Sobrien};
10260484Sobrien
10360484Sobrienstruct bcm_sdhci_softc {
10460484Sobrien	device_t		sc_dev;
10560484Sobrien	struct mtx		sc_mtx;
10660484Sobrien	struct resource *	sc_mem_res;
10733965Sjdp	struct resource *	sc_irq_res;
10860484Sobrien	bus_space_tag_t		sc_bst;
10933965Sjdp	bus_space_handle_t	sc_bsh;
11033965Sjdp	void *			sc_intrhand;
11160484Sobrien	struct mmc_request *	sc_req;
11233965Sjdp	struct mmc_data *	sc_data;
11333965Sjdp	uint32_t		sc_flags;
11460484Sobrien#define	LPC_SD_FLAGS_IGNORECRC		(1 << 0)
11560484Sobrien	int			sc_xfer_direction;
11660484Sobrien#define	DIRECTION_READ		0
11760484Sobrien#define	DIRECTION_WRITE		1
11860484Sobrien	int			sc_xfer_done;
11960484Sobrien	int			sc_bus_busy;
12060484Sobrien	struct sdhci_slot	sc_slot;
12160484Sobrien	int			sc_dma_inuse;
12260484Sobrien	int			sc_dma_ch;
12360484Sobrien	bus_dma_tag_t		sc_dma_tag;
12460484Sobrien	bus_dmamap_t		sc_dma_map;
12560484Sobrien	void			*sc_dma_buffer;
12660484Sobrien	vm_paddr_t		sc_dma_buffer_phys;
12760484Sobrien	vm_paddr_t		sc_sdhci_buffer_phys;;
12860484Sobrien};
12960484Sobrien
13060484Sobrienstatic int bcm_sdhci_probe(device_t);
13160484Sobrienstatic int bcm_sdhci_attach(device_t);
13260484Sobrienstatic int bcm_sdhci_detach(device_t);
13360484Sobrienstatic void bcm_sdhci_intr(void *);
13460484Sobrien
13577298Sobrienstatic int bcm_sdhci_get_ro(device_t, device_t);
13660484Sobrienstatic void bcm_sdhci_dma_intr(int ch, void *arg);
13760484Sobrien
13860484Sobrien#define	bcm_sdhci_lock(_sc)						\
13960484Sobrien    mtx_lock(&_sc->sc_mtx);
14060484Sobrien#define	bcm_sdhci_unlock(_sc)						\
14160484Sobrien    mtx_unlock(&_sc->sc_mtx);
14260484Sobrien
14360484Sobrienstatic void
14460484Sobrienbcm_dmamap_cb(void *arg, bus_dma_segment_t *segs,
14533965Sjdp	int nseg, int err)
14633965Sjdp{
14733965Sjdp        bus_addr_t *addr;
14833965Sjdp
14933965Sjdp        if (err)
15060484Sobrien                return;
15133965Sjdp
15233965Sjdp        addr = (bus_addr_t*)arg;
15333965Sjdp        *addr = segs[0].ds_addr;
15433965Sjdp}
15533965Sjdp
15633965Sjdpstatic int
15733965Sjdpbcm_sdhci_probe(device_t dev)
15833965Sjdp{
15933965Sjdp	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-sdhci"))
16033965Sjdp		return (ENXIO);
16133965Sjdp
16233965Sjdp	device_set_desc(dev, "Broadcom 2708 SDHCI controller");
16333965Sjdp	return (BUS_PROBE_DEFAULT);
16433965Sjdp}
16533965Sjdp
16633965Sjdpstatic int
16733965Sjdpbcm_sdhci_attach(device_t dev)
16877298Sobrien{
16977298Sobrien	struct bcm_sdhci_softc *sc = device_get_softc(dev);
17033965Sjdp	int rid, err;
17133965Sjdp	phandle_t node;
17233965Sjdp	pcell_t cell;
17333965Sjdp	int default_freq;
17433965Sjdp	void *buffer;
17533965Sjdp	vm_paddr_t buffer_phys;
17633965Sjdp	void *va;
17733965Sjdp
17833965Sjdp	sc->sc_dev = dev;
17933965Sjdp	sc->sc_req = NULL;
18033965Sjdp	err = 0;
18133965Sjdp
18233965Sjdp	default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
18333965Sjdp	node = ofw_bus_get_node(sc->sc_dev);
18433965Sjdp	if ((OF_getprop(node, "clock-frequency", &cell, sizeof(cell))) > 0)
18533965Sjdp		default_freq = (int)fdt32_to_cpu(cell)/1000000;
18633965Sjdp
18733965Sjdp	dprintf("SDHCI frequency: %dMHz\n", default_freq);
18833965Sjdp
18933965Sjdp	mtx_init(&sc->sc_mtx, "bcm sdhci", "sdhci", MTX_DEF);
19038889Sjdp
19138889Sjdp	rid = 0;
19277298Sobrien	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
19377298Sobrien	    RF_ACTIVE);
19438889Sjdp	if (!sc->sc_mem_res) {
19538889Sjdp		device_printf(dev, "cannot allocate memory window\n");
19638889Sjdp		err = ENXIO;
19733965Sjdp		goto fail;
19833965Sjdp	}
19933965Sjdp
20033965Sjdp	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
20133965Sjdp	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
20233965Sjdp
20333965Sjdp	rid = 0;
20433965Sjdp	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
20533965Sjdp	    RF_ACTIVE);
20633965Sjdp	if (!sc->sc_irq_res) {
20733965Sjdp		device_printf(dev, "cannot allocate interrupt\n");
20833965Sjdp		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
20933965Sjdp		err = ENXIO;
21033965Sjdp		goto fail;
21133965Sjdp	}
21233965Sjdp
21333965Sjdp	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
21433965Sjdp	    NULL, bcm_sdhci_intr, sc, &sc->sc_intrhand))
21533965Sjdp	{
21633965Sjdp		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
21733965Sjdp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
21833965Sjdp		device_printf(dev, "cannot setup interrupt handler\n");
21933965Sjdp		err = ENXIO;
22033965Sjdp		goto fail;
22133965Sjdp	}
22233965Sjdp
22333965Sjdp	if (!bcm2835_sdhci_pio_mode)
22433965Sjdp		sc->sc_slot.opt = SDHCI_PLATFORM_TRANSFER;
22533965Sjdp
22660484Sobrien	sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180;
22760484Sobrien	if (bcm2835_sdhci_hs)
22860484Sobrien		sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD;
22960484Sobrien	sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT);
23077298Sobrien	sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
23133965Sjdp		| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
23233965Sjdp		| SDHCI_QUIRK_MISSING_CAPS;
23333965Sjdp
23433965Sjdp	sdhci_init_slot(dev, &sc->sc_slot, 0);
23578828Sobrien
23633965Sjdp	sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST1);
23733965Sjdp	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
23833965Sjdp		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_FAST2);
23933965Sjdp	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
24033965Sjdp		sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY);
24133965Sjdp	if (sc->sc_dma_ch == BCM_DMA_CH_INVALID)
24278828Sobrien		goto fail;
24378828Sobrien
24478828Sobrien	bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc);
24533965Sjdp
24678828Sobrien	/* Allocate DMA buffers */
24778828Sobrien	err = bus_dma_tag_create(bus_get_dma_tag(dev),
24878828Sobrien	    1, 0, BUS_SPACE_MAXADDR_32BIT,
24933965Sjdp	    BUS_SPACE_MAXADDR, NULL, NULL,
25078828Sobrien	    BCM_SDHCI_BUFFER_SIZE, 1, BCM_SDHCI_BUFFER_SIZE,
25178828Sobrien	    BUS_DMA_ALLOCNOW, NULL, NULL,
25278828Sobrien	    &sc->sc_dma_tag);
25333965Sjdp
25477298Sobrien	if (err) {
25578828Sobrien		device_printf(dev, "failed allocate DMA tag");
25678828Sobrien		goto fail;
25778828Sobrien	}
25878828Sobrien
25978828Sobrien	err = bus_dmamem_alloc(sc->sc_dma_tag, &buffer,
26078828Sobrien	    BUS_DMA_WAITOK | BUS_DMA_COHERENT| BUS_DMA_ZERO,
26133965Sjdp	    &sc->sc_dma_map);
26233965Sjdp
26333965Sjdp	if (err) {
26433965Sjdp		device_printf(dev, "cannot allocate DMA memory\n");
26533965Sjdp		goto fail;
26633965Sjdp	}
26733965Sjdp
26833965Sjdp	err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, buffer,
26933965Sjdp	    BCM_SDHCI_BUFFER_SIZE, bcm_dmamap_cb, &buffer_phys,
27033965Sjdp	    BUS_DMA_WAITOK);
27133965Sjdp	if (err) {
27233965Sjdp		device_printf(dev, "cannot load DMA memory\n");
27333965Sjdp		goto fail;
27433965Sjdp	}
27577298Sobrien
27633965Sjdp	/*
27733965Sjdp	 * Sanity check: two least bits of address should be zero
27833965Sjdp	 */
27960484Sobrien	if ((uintptr_t)buffer & 3) {
28033965Sjdp		device_printf(dev,
28160484Sobrien		    "DMA address is not word-aligned\n");
28233965Sjdp		goto fail;
28333965Sjdp	}
28433965Sjdp
28533965Sjdp	sc->sc_dma_buffer = buffer;
28633965Sjdp	sc->sc_dma_buffer_phys = buffer_phys;
28733965Sjdp	va = (void*)rman_get_start(sc->sc_mem_res);
28833965Sjdp	sc->sc_sdhci_buffer_phys =
28933965Sjdp	    pmap_kextract((vm_offset_t)va) + SDHCI_BUFFER;
29033965Sjdp
29177298Sobrien	bus_generic_probe(dev);
29233965Sjdp	bus_generic_attach(dev);
29333965Sjdp
29433965Sjdp	sdhci_start_slot(&sc->sc_slot);
29560484Sobrien
29633965Sjdp	return (0);
29760484Sobrien
29833965Sjdpfail:
29933965Sjdp	if (sc->sc_intrhand)
30033965Sjdp		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
30133965Sjdp	if (sc->sc_irq_res)
30233965Sjdp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
30333965Sjdp	if (sc->sc_mem_res)
30433965Sjdp		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
30533965Sjdp
30633965Sjdp	return (err);
30733965Sjdp}
30833965Sjdp
30933965Sjdpstatic int
31033965Sjdpbcm_sdhci_detach(device_t dev)
31133965Sjdp{
31233965Sjdp
31333965Sjdp	return (EBUSY);
31433965Sjdp}
31533965Sjdp
31677298Sobrienstatic void
31777298Sobrienbcm_sdhci_intr(void *arg)
31877298Sobrien{
31977298Sobrien	struct bcm_sdhci_softc *sc = arg;
32077298Sobrien
32177298Sobrien	sdhci_generic_intr(&sc->sc_slot);
32277298Sobrien}
32377298Sobrien
32477298Sobrienstatic int
32577298Sobrienbcm_sdhci_get_ro(device_t bus, device_t child)
32677298Sobrien{
32777298Sobrien
32877298Sobrien	return (0);
32977298Sobrien}
33077298Sobrien
33133965Sjdpstatic inline uint32_t
33277298SobrienRD4(struct bcm_sdhci_softc *sc, bus_size_t off)
33333965Sjdp{
33433965Sjdp	uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
33533965Sjdp	return val;
33633965Sjdp}
33733965Sjdp
33833965Sjdpstatic inline void
33933965SjdpWR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val)
34033965Sjdp{
34177298Sobrien	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
34233965Sjdp
34377298Sobrien	if ((off != SDHCI_BUFFER && off != SDHCI_INT_STATUS && off != SDHCI_CLOCK_CONTROL))
34477298Sobrien	{
34577298Sobrien		int timeout = 100000;
34677298Sobrien		while (val != bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)
34777298Sobrien		    && --timeout > 0)
34877298Sobrien			continue;
34977298Sobrien
35077298Sobrien		if (timeout <= 0)
35133965Sjdp			printf("sdhci_brcm: writing 0x%X to reg 0x%X "
35233965Sjdp				"always gives 0x%X\n",
35333965Sjdp				val, (uint32_t)off,
35433965Sjdp				bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
35533965Sjdp	}
35633965Sjdp}
35777298Sobrien
35877298Sobrienstatic uint8_t
35977298Sobrienbcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
36033965Sjdp{
36133965Sjdp	struct bcm_sdhci_softc *sc = device_get_softc(dev);
36277298Sobrien	uint32_t val = RD4(sc, off & ~3);
36377298Sobrien
36433965Sjdp	return ((val >> (off & 3)*8) & 0xff);
36533965Sjdp}
36633965Sjdp
36733965Sjdpstatic uint16_t
36833965Sjdpbcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
36933965Sjdp{
37033965Sjdp	struct bcm_sdhci_softc *sc = device_get_softc(dev);
37133965Sjdp	uint32_t val = RD4(sc, off & ~3);
37233965Sjdp
37333965Sjdp	return ((val >> (off & 3)*8) & 0xffff);
37433965Sjdp}
37533965Sjdp
37677298Sobrienstatic uint32_t
37777298Sobrienbcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
37877298Sobrien{
37977298Sobrien	struct bcm_sdhci_softc *sc = device_get_softc(dev);
38033965Sjdp
38133965Sjdp	return RD4(sc, off);
38277298Sobrien}
38377298Sobrien
38477298Sobrienstatic void
38533965Sjdpbcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
38633965Sjdp    uint32_t *data, bus_size_t count)
38733965Sjdp{
38833965Sjdp	struct bcm_sdhci_softc *sc = device_get_softc(dev);
38977298Sobrien
39077298Sobrien	bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
39133965Sjdp}
39233965Sjdp
39377298Sobrienstatic void
39433965Sjdpbcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
39577298Sobrien{
39677298Sobrien	struct bcm_sdhci_softc *sc = device_get_softc(dev);
39777298Sobrien	uint32_t val32 = RD4(sc, off & ~3);
39877298Sobrien	val32 &= ~(0xff << (off & 3)*8);
39977298Sobrien	val32 |= (val << (off & 3)*8);
40077298Sobrien	WR4(sc, off & ~3, val32);
40177298Sobrien}
40233965Sjdp
40377298Sobrienstatic void
40433965Sjdpbcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
40533965Sjdp{
40677298Sobrien	struct bcm_sdhci_softc *sc = device_get_softc(dev);
40777298Sobrien	static uint32_t cmd_and_trandfer_mode;
40833965Sjdp	uint32_t val32;
40933965Sjdp	if (off == SDHCI_COMMAND_FLAGS)
41033965Sjdp		val32 = cmd_and_trandfer_mode;
41133965Sjdp	else
41277298Sobrien		val32 = RD4(sc, off & ~3);
41333965Sjdp	val32 &= ~(0xffff << (off & 3)*8);
41433965Sjdp	val32 |= (val << (off & 3)*8);
41533965Sjdp	if (off == SDHCI_TRANSFER_MODE)
41677298Sobrien		cmd_and_trandfer_mode = val32;
41733965Sjdp	else
41878828Sobrien		WR4(sc, off & ~3, val32);
41933965Sjdp}
42033965Sjdp
42133965Sjdpstatic void
42233965Sjdpbcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
42333965Sjdp{
42433965Sjdp	struct bcm_sdhci_softc *sc = device_get_softc(dev);
42577298Sobrien	WR4(sc, off, val);
42638889Sjdp}
42738889Sjdp
42838889Sjdpstatic void
42938889Sjdpbcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
43038889Sjdp    uint32_t *data, bus_size_t count)
43138889Sjdp{
43233965Sjdp	struct bcm_sdhci_softc *sc = device_get_softc(dev);
43333965Sjdp
43433965Sjdp	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
43533965Sjdp}
43633965Sjdp
43733965Sjdpstatic uint32_t
43877298Sobrienbcm_sdhci_min_freq(device_t dev, struct sdhci_slot *slot)
43977298Sobrien{
44033965Sjdp
44133965Sjdp	return bcm2835_sdhci_min_freq;
44233965Sjdp}
44333965Sjdp
44477298Sobrienstatic void
44533965Sjdpbcm_sdhci_dma_intr(int ch, void *arg)
44677298Sobrien{
44777298Sobrien	struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg;
44877298Sobrien	struct sdhci_slot *slot = &sc->sc_slot;
44977298Sobrien	uint32_t reg, mask;
45077298Sobrien	void *buffer;
45177298Sobrien	size_t len;
45277298Sobrien	int left;
45377298Sobrien
45477298Sobrien	mtx_lock(&slot->mtx);
45577298Sobrien
45633965Sjdp	/* copy DMA buffer to VA if READ */
457	len = bcm_dma_length(sc->sc_dma_ch);
458	if (slot->curcmd->data->flags & MMC_DATA_READ) {
459		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
460		    BUS_DMASYNC_POSTREAD);
461
462		mask = SDHCI_INT_DATA_AVAIL;
463		/* all dma data in single or contiguous page */
464		buffer = (uint8_t*)(slot->curcmd->data->data) + slot->offset;
465		memcpy(buffer, sc->sc_dma_buffer, len);
466	} else {
467		bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
468		    BUS_DMASYNC_POSTWRITE);
469		mask = SDHCI_INT_SPACE_AVAIL;
470	}
471
472	slot->offset += len;
473	sc->sc_dma_inuse = 0;
474
475	left = min(BCM_SDHCI_BUFFER_SIZE,
476	    slot->curcmd->data->len - slot->offset);
477
478	/* DATA END? */
479	reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS);
480
481	if (reg & SDHCI_INT_DATA_END) {
482		/* ACK for all outstanding interrupts */
483		bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg);
484
485		/* enable INT */
486		slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL
487		    | SDHCI_INT_DATA_END;
488		bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
489		    slot->intmask);
490
491		/* finish this data */
492		sdhci_finish_data(slot);
493	}
494	else {
495		/* already available? */
496		if (reg & mask) {
497			sc->sc_dma_inuse = 1;
498
499			/* ACK for DATA_AVAIL or SPACE_AVAIL */
500			bcm_sdhci_write_4(slot->bus, slot,
501			    SDHCI_INT_STATUS, mask);
502
503			/* continue next DMA transfer */
504			if (slot->curcmd->data->flags & MMC_DATA_READ) {
505				bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
506				    BUS_DMASYNC_PREREAD);
507
508				/* DMA start */
509				if (bcm_dma_start(sc->sc_dma_ch,
510				    sc->sc_sdhci_buffer_phys,
511				    sc->sc_dma_buffer_phys, left) != 0)
512					device_printf(sc->sc_dev, "failed DMA start\n");
513			} else {
514				buffer = (char*)slot->curcmd->data->data + slot->offset;
515				memcpy(sc->sc_dma_buffer, buffer, left);
516
517				bus_dmamap_sync(sc->sc_dma_tag,
518				    sc->sc_dma_map, BUS_DMASYNC_PREWRITE);
519
520				/* DMA start */
521				if (bcm_dma_start(sc->sc_dma_ch,
522				    sc->sc_dma_buffer_phys,
523				    sc->sc_sdhci_buffer_phys, left) != 0)
524					device_printf(sc->sc_dev, "failed DMA start\n");
525			}
526		} else {
527			/* wait for next data by INT */
528
529			/* enable INT */
530			slot->intmask |= SDHCI_INT_DATA_AVAIL |
531			    SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END;
532			bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE,
533			    slot->intmask);
534		}
535	}
536
537	mtx_unlock(&slot->mtx);
538}
539
540static void
541bcm_sdhci_read_dma(struct sdhci_slot *slot)
542{
543	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
544	size_t left;
545
546	if (sc->sc_dma_inuse) {
547		device_printf(sc->sc_dev, "DMA in use\n");
548		return;
549	}
550
551	sc->sc_dma_inuse = 1;
552
553	left = min(BCM_SDHCI_BUFFER_SIZE,
554	    slot->curcmd->data->len - slot->offset);
555
556	KASSERT((left & 3) == 0,
557	    ("%s: len = %d, not word-aligned", __func__, left));
558
559	bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
560	    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
561	bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
562	    BCM_DMA_INC_ADDR,
563	    (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
564
565	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
566	    BUS_DMASYNC_PREREAD);
567
568	/* DMA start */
569	if (bcm_dma_start(sc->sc_dma_ch, sc->sc_sdhci_buffer_phys,
570	    sc->sc_dma_buffer_phys, left) != 0)
571		device_printf(sc->sc_dev, "failed DMA start\n");
572}
573
574static void
575bcm_sdhci_write_dma(struct sdhci_slot *slot)
576{
577	struct bcm_sdhci_softc *sc = device_get_softc(slot->bus);
578	char *buffer;
579	size_t left;
580
581	if (sc->sc_dma_inuse) {
582		device_printf(sc->sc_dev, "DMA in use\n");
583		return;
584	}
585
586	sc->sc_dma_inuse = 1;
587
588	left = min(BCM_SDHCI_BUFFER_SIZE,
589	    slot->curcmd->data->len - slot->offset);
590
591	KASSERT((left & 3) == 0,
592	    ("%s: len = %d, not word-aligned", __func__, left));
593
594	buffer = (char*)slot->curcmd->data->data + slot->offset;
595	memcpy(sc->sc_dma_buffer, buffer, left);
596
597	bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE,
598	    BCM_DMA_INC_ADDR,
599	    (left & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT);
600	bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC,
601	    BCM_DMA_SAME_ADDR, BCM_DMA_32BIT);
602
603	bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map,
604	    BUS_DMASYNC_PREWRITE);
605
606	/* DMA start */
607	if (bcm_dma_start(sc->sc_dma_ch, sc->sc_dma_buffer_phys,
608	    sc->sc_sdhci_buffer_phys, left) != 0)
609		device_printf(sc->sc_dev, "failed DMA start\n");
610}
611
612static int
613bcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot)
614{
615	size_t left;
616
617	/* Do not use DMA for transfers less then block size */
618	left = min(BCM_DMA_BLOCK_SIZE,
619	    slot->curcmd->data->len - slot->offset);
620	if (left < BCM_DMA_BLOCK_SIZE)
621		return (0);
622
623	return (1);
624}
625
626static void
627bcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot,
628    uint32_t *intmask)
629{
630
631	/* Disable INT */
632	slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END);
633	bcm_sdhci_write_4(dev, slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
634
635	/* DMA transfer FIFO 1KB */
636	if (slot->curcmd->data->flags & MMC_DATA_READ)
637		bcm_sdhci_read_dma(slot);
638	else
639		bcm_sdhci_write_dma(slot);
640}
641
642static void
643bcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot)
644{
645
646	sdhci_finish_data(slot);
647}
648
649static device_method_t bcm_sdhci_methods[] = {
650	/* Device interface */
651	DEVMETHOD(device_probe,		bcm_sdhci_probe),
652	DEVMETHOD(device_attach,	bcm_sdhci_attach),
653	DEVMETHOD(device_detach,	bcm_sdhci_detach),
654
655	/* Bus interface */
656	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
657	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
658	DEVMETHOD(bus_print_child,	bus_generic_print_child),
659
660	/* MMC bridge interface */
661	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
662	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
663	DEVMETHOD(mmcbr_get_ro,		bcm_sdhci_get_ro),
664	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
665	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
666
667	DEVMETHOD(sdhci_min_freq,	bcm_sdhci_min_freq),
668	/* Platform transfer methods */
669	DEVMETHOD(sdhci_platform_will_handle,		bcm_sdhci_will_handle_transfer),
670	DEVMETHOD(sdhci_platform_start_transfer,	bcm_sdhci_start_transfer),
671	DEVMETHOD(sdhci_platform_finish_transfer,	bcm_sdhci_finish_transfer),
672	/* SDHCI registers accessors */
673	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
674	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
675	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
676	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhci_read_multi_4),
677	DEVMETHOD(sdhci_write_1,	bcm_sdhci_write_1),
678	DEVMETHOD(sdhci_write_2,	bcm_sdhci_write_2),
679	DEVMETHOD(sdhci_write_4,	bcm_sdhci_write_4),
680	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhci_write_multi_4),
681
682	{ 0, 0 }
683};
684
685static devclass_t bcm_sdhci_devclass;
686
687static driver_t bcm_sdhci_driver = {
688	"sdhci_bcm",
689	bcm_sdhci_methods,
690	sizeof(struct bcm_sdhci_softc),
691};
692
693DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
694MODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
695