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