diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/dw_mmc.c | 140 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/rockchip_dw_mmc.c | 26 | ||||
-rw-r--r-- | drivers/mmc/socfpga_dw_mmc.c | 142 | ||||
-rw-r--r-- | drivers/mmc/zynq_sdhci.c | 67 |
5 files changed, 222 insertions, 157 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 4375abc9406..909e3caf18b 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -94,6 +94,81 @@ static void dwmci_prepare_data(struct dwmci_host *host, dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); } +static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) +{ + int ret = 0; + u32 timeout = 240000; + u32 mask, size, i, len = 0; + u32 *buf = NULL; + ulong start = get_timer(0); + u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >> + RX_WMARK_SHIFT) + 1) * 2; + + size = data->blocksize * data->blocks / 4; + if (data->flags == MMC_DATA_READ) + buf = (unsigned int *)data->dest; + else + buf = (unsigned int *)data->src; + + for (;;) { + mask = dwmci_readl(host, DWMCI_RINTSTS); + /* Error during data transfer. */ + if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { + debug("%s: DATA ERROR!\n", __func__); + ret = -EINVAL; + break; + } + + if (host->fifo_mode && size) { + if (data->flags == MMC_DATA_READ) { + if ((dwmci_readl(host, DWMCI_RINTSTS) && + DWMCI_INTMSK_RXDR)) { + len = dwmci_readl(host, DWMCI_STATUS); + len = (len >> DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK; + for (i = 0; i < len; i++) + *buf++ = + dwmci_readl(host, DWMCI_DATA); + dwmci_writel(host, DWMCI_RINTSTS, + DWMCI_INTMSK_RXDR); + } + } else { + if ((dwmci_readl(host, DWMCI_RINTSTS) && + DWMCI_INTMSK_TXDR)) { + len = dwmci_readl(host, DWMCI_STATUS); + len = fifo_depth - ((len >> + DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK); + for (i = 0; i < len; i++) + dwmci_writel(host, DWMCI_DATA, + *buf++); + dwmci_writel(host, DWMCI_RINTSTS, + DWMCI_INTMSK_TXDR); + } + } + size = size > len ? (size - len) : 0; + } + + /* Data arrived correctly. */ + if (mask & DWMCI_INTMSK_DTO) { + ret = 0; + break; + } + + /* Check for timeout. */ + if (get_timer(start) > timeout) { + debug("%s: Timeout waiting for data!\n", + __func__); + ret = TIMEOUT; + break; + } + } + + dwmci_writel(host, DWMCI_RINTSTS, mask); + + return ret; +} + static int dwmci_set_transfer_mode(struct dwmci_host *host, struct mmc_data *data) { @@ -129,17 +204,24 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); if (data) { - if (data->flags == MMC_DATA_READ) { - bounce_buffer_start(&bbstate, (void*)data->dest, - data->blocksize * - data->blocks, GEN_BB_WRITE); + if (host->fifo_mode) { + dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); + dwmci_writel(host, DWMCI_BYTCNT, + data->blocksize * data->blocks); + dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); } else { - bounce_buffer_start(&bbstate, (void*)data->src, - data->blocksize * - data->blocks, GEN_BB_READ); + if (data->flags == MMC_DATA_READ) { + bounce_buffer_start(&bbstate, (void*)data->dest, + data->blocksize * + data->blocks, GEN_BB_WRITE); + } else { + bounce_buffer_start(&bbstate, (void*)data->src, + data->blocksize * + data->blocks, GEN_BB_READ); + } + dwmci_prepare_data(host, data, cur_idmac, + bbstate.bounce_buffer); } - dwmci_prepare_data(host, data, cur_idmac, - bbstate.bounce_buffer); } dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); @@ -213,39 +295,15 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (data) { - start = get_timer(0); - timeout = 240000; - for (;;) { - mask = dwmci_readl(host, DWMCI_RINTSTS); - /* Error during data transfer. */ - if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { - debug("%s: DATA ERROR!\n", __func__); - ret = -EINVAL; - break; - } - - /* Data arrived correctly. */ - if (mask & DWMCI_INTMSK_DTO) { - ret = 0; - break; - } - - /* Check for timeout. */ - if (get_timer(start) > timeout) { - debug("%s: Timeout waiting for data!\n", - __func__); - ret = TIMEOUT; - break; - } + ret = dwmci_data_transfer(host, data); + + /* only dma mode need it */ + if (!host->fifo_mode) { + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl &= ~(DWMCI_DMA_EN); + dwmci_writel(host, DWMCI_CTRL, ctrl); + bounce_buffer_stop(&bbstate); } - - dwmci_writel(host, DWMCI_RINTSTS, mask); - - ctrl = dwmci_readl(host, DWMCI_CTRL); - ctrl &= ~(DWMCI_DMA_EN); - dwmci_writel(host, DWMCI_CTRL, ctrl); - - bounce_buffer_stop(&bbstate); } udelay(100); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2a58702848b..3a34028c917 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1469,7 +1469,9 @@ static int mmc_startup(struct mmc *mmc) mmc->block_dev.blksz = mmc->read_bl_len; mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_SPL_BUILD) || \ + (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ + !defined(CONFIG_USE_TINY_PRINTF)) sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), (mmc->cid[3] >> 16) & 0xffff); diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index f11c8e00395..aeaec6c8658 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -50,8 +50,9 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk; host->priv = dev; - /* TODO(sjg@chromium.org): Remove the need for this hack */ - host->dev_index = (ulong)host->ioaddr == 0xff0f0000 ? 0 : 1; + /* use non-removeable as sdcard and emmc as judgement */ + if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "non-removable")) + host->dev_index = 1; return 0; } @@ -63,6 +64,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) struct dwmci_host *host = &priv->host; u32 minmax[2]; int ret; + int fifo_depth; priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); if (IS_ERR(priv->grf)) @@ -71,10 +73,22 @@ static int rockchip_dwmmc_probe(struct udevice *dev) if (ret) return ret; - ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, - "clock-freq-min-max", minmax, 2); - if (!ret) - ret = add_dwmci(host, minmax[1], minmax[0]); + if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "clock-freq-min-max", minmax, 2)) + return -EINVAL; + + fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); + if (fifo_depth < 0) + return -EINVAL; + + host->fifoth_val = MSIZE(0x2) | + RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + + if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode")) + host->fifo_mode = true; + + ret = add_dwmci(host, minmax[1], minmax[0]); if (ret) return ret; diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 8076761e06e..43a7e7ea324 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -5,36 +5,44 @@ */ #include <common.h> -#include <malloc.h> -#include <fdtdec.h> -#include <libfdt.h> -#include <dwmmc.h> -#include <errno.h> -#include <asm/arch/dwmmc.h> #include <asm/arch/clock_manager.h> +#include <asm/arch/dwmmc.h> #include <asm/arch/system_manager.h> +#include <dm.h> +#include <dwmmc.h> +#include <errno.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <linux/err.h> +#include <malloc.h> + +DECLARE_GLOBAL_DATA_PTR; static const struct socfpga_clock_manager *clock_manager_base = (void *)SOCFPGA_CLKMGR_ADDRESS; static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; +/* socfpga implmentation specific driver private data */ +struct dwmci_socfpga_priv_data { + struct dwmci_host host; + unsigned int drvsel; + unsigned int smplsel; +}; + static void socfpga_dwmci_clksel(struct dwmci_host *host) { - unsigned int drvsel; - unsigned int smplsel; + struct dwmci_socfpga_priv_data *priv = host->priv; + u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | + ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); /* Disable SDMMC clock. */ clrbits_le32(&clock_manager_base->per_pll.en, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); - /* Configures drv_sel and smpl_sel */ - drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL; - smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL; - - debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel); - writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel), - &system_manager_base->sdmmcgrp_ctrl); + debug("%s: drvsel %d smplsel %d\n", __func__, + priv->drvsel, priv->smplsel); + writel(sdmmc_mask, &system_manager_base->sdmmcgrp_ctrl); debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, readl(&system_manager_base->sdmmcgrp_ctrl)); @@ -44,87 +52,77 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host) CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); } -static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx) +static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) { /* FIXME: probe from DT eventually too/ */ const unsigned long clk = cm_get_mmc_controller_clk_hz(); - struct dwmci_host *host; - fdt_addr_t reg_base; - int bus_width, fifo_depth; + struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int fifo_depth; if (clk == 0) { - printf("DWMMC%d: MMC clock is zero!", idx); + printf("DWMMC: MMC clock is zero!"); return -EINVAL; } - /* Get the register address from the device node */ - reg_base = fdtdec_get_addr(blob, node, "reg"); - if (!reg_base) { - printf("DWMMC%d: Can't get base address\n", idx); - return -EINVAL; - } - - /* Get the bus width from the device node */ - bus_width = fdtdec_get_int(blob, node, "bus-width", 0); - if (bus_width <= 0) { - printf("DWMMC%d: Can't get bus-width\n", idx); - return -EINVAL; - } - - fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); + fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); if (fifo_depth < 0) { - printf("DWMMC%d: Can't get FIFO depth\n", idx); + printf("DWMMC: Can't get FIFO depth\n"); return -EINVAL; } - /* Allocate the host */ - host = calloc(1, sizeof(*host)); - if (!host) - return -ENOMEM; - - host->name = "SOCFPGA DWMMC"; - host->ioaddr = (void *)reg_base; - host->buswidth = bus_width; + host->name = dev->name; + host->ioaddr = (void *)dev_get_addr(dev); + host->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "bus-width", 4); host->clksel = socfpga_dwmci_clksel; - host->dev_index = idx; + + /* + * TODO(sjg@chromium.org): Remove the need for this hack. + * We only have one dwmmc block on gen5 SoCFPGA. + */ + host->dev_index = 0; /* Fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "drvsel", 3); + priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "smplsel", 0); + host->priv = priv; - return add_dwmci(host, host->bus_hz, 400000); -} - -static int socfpga_dwmci_process_node(const void *blob, int nodes[], - int count) -{ - int i, node, ret; - - for (i = 0; i < count; i++) { - node = nodes[i]; - if (node <= 0) - continue; - - ret = socfpga_dwmci_of_probe(blob, node, i); - if (ret) { - printf("%s: failed to decode dev %d\n", __func__, i); - return ret; - } - } return 0; } -int socfpga_dwmmc_init(const void *blob) +static int socfpga_dwmmc_probe(struct udevice *dev) { - int nodes[2]; /* Max. two controllers. */ - int ret, count; + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int ret; - count = fdtdec_find_aliases_for_id(blob, "mmc", - COMPAT_ALTERA_SOCFPGA_DWMMC, - nodes, ARRAY_SIZE(nodes)); + ret = add_dwmci(host, host->bus_hz, 400000); + if (ret) + return ret; - ret = socfpga_dwmci_process_node(blob, nodes, count); + upriv->mmc = host->mmc; - return ret; + return 0; } + +static const struct udevice_id socfpga_dwmmc_ids[] = { + { .compatible = "altr,socfpga-dw-mshc" }, + { } +}; + +U_BOOT_DRIVER(socfpga_dwmmc_drv) = { + .name = "socfpga_dwmmc", + .id = UCLASS_MMC, + .of_match = socfpga_dwmmc_ids, + .ofdata_to_platdata = socfpga_dwmmc_ofdata_to_platdata, + .probe = socfpga_dwmmc_probe, + .priv_auto_alloc_size = sizeof(struct dwmci_socfpga_priv_data), +}; diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e169b774932..4fe3da93b20 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2013 Inc. + * (C) Copyright 2013 - 2015 Xilinx, Inc. * * Xilinx Zynq SD Host Controller Interface * @@ -7,55 +7,48 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> #include <libfdt.h> #include <malloc.h> #include <sdhci.h> -#include <asm/arch/sys_proto.h> -int zynq_sdhci_init(phys_addr_t regbase) +static int arasan_sdhci_probe(struct udevice *dev) { - struct sdhci_host *host = NULL; + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct sdhci_host *host = dev_get_priv(dev); - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("zynq_sdhci_init: sdhci_host malloc fail\n"); - return 1; - } - - host->name = "zynq_sdhci"; - host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 52000000 >> 9); + add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 0); + + upriv->mmc = host->mmc; + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int zynq_sdhci_of_init(const void *blob) +static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) { - int offset = 0; - u32 ret = 0; - phys_addr_t reg; - - debug("ZYNQ SDHCI: Initialization\n"); - - do { - offset = fdt_node_offset_by_compatible(blob, offset, - "arasan,sdhci-8.9a"); - if (offset != -1) { - reg = fdtdec_get_addr(blob, offset, "reg"); - if (reg != FDT_ADDR_T_NONE) { - ret |= zynq_sdhci_init(reg); - } else { - debug("ZYNQ SDHCI: Can't get base address\n"); - return -1; - } - } - } while (offset != -1); - - return ret; + struct sdhci_host *host = dev_get_priv(dev); + + host->name = (char *)dev->name; + host->ioaddr = (void *)dev_get_addr(dev); + + return 0; } -#endif + +static const struct udevice_id arasan_sdhci_ids[] = { + { .compatible = "arasan,sdhci-8.9a" }, + { } +}; + +U_BOOT_DRIVER(arasan_sdhci_drv) = { + .name = "arasan_sdhci", + .id = UCLASS_MMC, + .of_match = arasan_sdhci_ids, + .ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata, + .probe = arasan_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), +}; |