diff options
author | Tom Rini <trini@konsulko.com> | 2019-09-08 21:14:22 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-09-08 21:15:13 -0400 |
commit | 40e362a9ab5f1d409822942ee89d4473c2e01ee6 (patch) | |
tree | ad63f4fdcc210a0a758e41528fb2f15ecedf6a31 /drivers/mmc | |
parent | 2f760735c170c854ffca76be5607cec5c56fdc4f (diff) | |
parent | cd45d6f3955c919b7f10793014db3dbcfd7df3bb (diff) | |
download | u-boot-40e362a9ab5f1d409822942ee89d4473c2e01ee6.tar.gz |
Merge tag 'mmc-9-6-2019' of https://gitlab.denx.de/u-boot/custodians/u-boot-mmcWIP/08Sep2019
Bug fixes to mmc_spi
Add Aspeed SD driver
Fix dw_mmc timeout calculation
Fix timeout values passed to mmc_wait_dat0
sdhci dt caps/mask update
[trini: Fix evb-ast2500_defconfig CONFIG_MMC line]
Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/aspeed_sdhci.c | 90 | ||||
-rw-r--r-- | drivers/mmc/dw_mmc.c | 5 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 12 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 24 | ||||
-rw-r--r-- | drivers/mmc/mmc_spi.c | 35 | ||||
-rw-r--r-- | drivers/mmc/mmc_write.c | 8 | ||||
-rw-r--r-- | drivers/mmc/omap_hsmmc.c | 6 | ||||
-rw-r--r-- | drivers/mmc/renesas-sdhi.c | 7 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 23 |
11 files changed, 166 insertions, 56 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 0ccb1ea701..8fb2bfa444 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -421,6 +421,17 @@ config SPL_MMC_SDHCI_ADMA This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 in SPL. +config MMC_SDHCI_ASPEED + bool "Aspeed SDHCI controller" + depends on ARCH_ASPEED + depends on DM_MMC + depends on MMC_SDHCI + help + Enables support for the Aspeed SDHCI 2.0 controller present on Aspeed + SoCs. This device is compatible with SD 3.0 and/or MMC 4.3 + specifications. On the AST2600, the device is also compatible with + MMC 5.1 and eMMC 3.0. + config MMC_SDHCI_ATMEL bool "Atmel SDHCI controller support" depends on ARCH_AT91 diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6cc018bb67..5594195528 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_SDHCI_ASPEED) += aspeed_sdhci.o obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o diff --git a/drivers/mmc/aspeed_sdhci.c b/drivers/mmc/aspeed_sdhci.c new file mode 100644 index 0000000000..1321ec37e1 --- /dev/null +++ b/drivers/mmc/aspeed_sdhci.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 IBM Corp. + * Eddie James <eajames@linux.ibm.com> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <malloc.h> +#include <sdhci.h> + +struct aspeed_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +static int aspeed_sdhci_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct aspeed_sdhci_plat *plat = dev_get_platdata(dev); + struct sdhci_host *host = dev_get_priv(dev); + u32 max_clk; + struct clk clk; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + goto free; + + host->name = dev->name; + host->ioaddr = (void *)devfdt_get_addr(dev); + + max_clk = clk_get_rate(&clk); + if (IS_ERR_VALUE(max_clk)) { + ret = max_clk; + goto err; + } + + host->max_clk = max_clk; + host->mmc = &plat->mmc; + host->mmc->dev = dev; + host->mmc->priv = host; + upriv->mmc = host->mmc; + + ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); + if (ret) + goto err; + + ret = sdhci_probe(dev); + if (ret) + goto err; + + return 0; + +err: + clk_disable(&clk); +free: + clk_free(&clk); + return ret; +} + +static int aspeed_sdhci_bind(struct udevice *dev) +{ + struct aspeed_sdhci_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id aspeed_sdhci_ids[] = { + { .compatible = "aspeed,ast2400-sdhci" }, + { .compatible = "aspeed,ast2500-sdhci" }, + { .compatible = "aspeed,ast2600-sdhci" }, + { } +}; + +U_BOOT_DRIVER(aspeed_sdhci_drv) = { + .name = "aspeed_sdhci", + .id = UCLASS_MMC, + .of_match = aspeed_sdhci_ids, + .ops = &sdhci_ops, + .bind = aspeed_sdhci_bind, + .probe = aspeed_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct aspeed_sdhci_plat), +}; diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 22f6c7eefd..ebe7bcdd90 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -119,11 +119,12 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) { unsigned int timeout; - timeout = size * 8 * 1000; /* counting in bits and msec */ - timeout *= 2; /* wait twice as long */ + timeout = size * 8; /* counting in bits */ + timeout *= 10; /* wait 10 times as long */ timeout /= mmc->clock; timeout /= mmc->bus_width; timeout /= mmc->ddr_mode ? 2 : 1; + timeout *= 1000; /* counting in msec */ timeout = (timeout < 1000) ? 1000 : timeout; return timeout; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 2b146ea43c..37c3843902 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -47,18 +47,18 @@ int mmc_set_ios(struct mmc *mmc) return dm_mmc_set_ios(mmc->dev); } -int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us) { struct dm_mmc_ops *ops = mmc_get_ops(dev); if (!ops->wait_dat0) return -ENOSYS; - return ops->wait_dat0(dev, state, timeout); + return ops->wait_dat0(dev, state, timeout_us); } -int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) { - return dm_mmc_wait_dat0(mmc->dev, state, timeout); + return dm_mmc_wait_dat0(mmc->dev, state, timeout_us); } int dm_mmc_get_wp(struct udevice *dev) @@ -427,10 +427,6 @@ U_BOOT_DRIVER(mmc_blk) = { }; #endif /* CONFIG_BLK */ -U_BOOT_DRIVER(mmc) = { - .name = "mmc", - .id = UCLASS_MMC, -}; UCLASS_DRIVER(mmc) = { .id = UCLASS_MMC, diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eecc7d687e..c8f71cd0c1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -31,7 +31,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); #if !CONFIG_IS_ENABLED(DM_MMC) -static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) { return -ENOSYS; } @@ -230,12 +230,12 @@ int mmc_send_status(struct mmc *mmc, unsigned int *status) return -ECOMM; } -int mmc_poll_for_busy(struct mmc *mmc, int timeout) +int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) { unsigned int status; int err; - err = mmc_wait_dat0(mmc, 1, timeout); + err = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (err != -ENOSYS) return err; @@ -256,13 +256,13 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout) return -ECOMM; } - if (timeout-- <= 0) + if (timeout_ms-- <= 0) break; udelay(1000); } - if (timeout <= 0) { + if (timeout_ms <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) pr_err("Timeout waiting card ready\n"); #endif @@ -750,17 +750,17 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, { unsigned int status, start; struct mmc_cmd cmd; - int timeout = DEFAULT_CMD6_TIMEOUT_MS; + int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS; bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) && (index == EXT_CSD_PART_CONF); int retries = 3; int ret; if (mmc->gen_cmd6_time) - timeout = mmc->gen_cmd6_time * 10; + timeout_ms = mmc->gen_cmd6_time * 10; if (is_part_switch && mmc->part_switch_time) - timeout = mmc->part_switch_time * 10; + timeout_ms = mmc->part_switch_time * 10; cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; @@ -778,7 +778,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, start = get_timer(0); /* poll dat0 for rdy/buys status */ - ret = mmc_wait_dat0(mmc, 1, timeout); + ret = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (ret && ret != -ENOSYS) return ret; @@ -788,11 +788,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, * stated timeout to be sufficient. */ if (ret == -ENOSYS && !send_status) - mdelay(timeout); + mdelay(timeout_ms); /* Finally wait until the card is ready or indicates a failure * to switch. It doesn't hurt to use CMD13 here even if send_status - * is false, because by now (after 'timeout' ms) the bus should be + * is false, because by now (after 'timeout_ms' ms) the bus should be * reliable. */ do { @@ -806,7 +806,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, if (!ret && (status & MMC_STATUS_RDY_FOR_DATA)) return 0; udelay(100); - } while (get_timer(start) < timeout); + } while (get_timer(start) < timeout_ms); return -ETIMEDOUT; } diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 350812a04b..c693fb2d17 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -58,12 +58,15 @@ #define READ_TIMEOUT 3000000 /* 1 sec */ #define WRITE_TIMEOUT 3000000 /* 1 sec */ -struct mmc_spi_priv { - struct spi_slave *spi; +struct mmc_spi_plat { struct mmc_config cfg; struct mmc mmc; }; +struct mmc_spi_priv { + struct spi_slave *spi; +}; + static int mmc_spi_sendcmd(struct udevice *dev, ushort cmdidx, u32 cmdarg, u32 resp_type, u8 *resp, u32 resp_size, @@ -370,6 +373,7 @@ done: static int mmc_spi_probe(struct udevice *dev) { struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_spi_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); char *name; @@ -385,28 +389,28 @@ static int mmc_spi_probe(struct udevice *dev) return -ENOMEM; sprintf(name, "%s:%s", dev->parent->name, dev->name); - priv->cfg.name = name; - priv->cfg.host_caps = MMC_MODE_SPI; - priv->cfg.voltages = MMC_SPI_VOLTAGE; - priv->cfg.f_min = MMC_SPI_MIN_CLOCK; - priv->cfg.f_max = priv->spi->max_hz; - priv->cfg.part_type = PART_TYPE_DOS; - priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + plat->cfg.name = name; + plat->cfg.host_caps = MMC_MODE_SPI; + plat->cfg.voltages = MMC_SPI_VOLTAGE; + plat->cfg.f_min = MMC_SPI_MIN_CLOCK; + plat->cfg.f_max = priv->spi->max_hz; + plat->cfg.part_type = PART_TYPE_DOS; + plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - priv->mmc.cfg = &priv->cfg; - priv->mmc.priv = priv; - priv->mmc.dev = dev; + plat->mmc.cfg = &plat->cfg; + plat->mmc.priv = priv; + plat->mmc.dev = dev; - upriv->mmc = &priv->mmc; + upriv->mmc = &plat->mmc; return 0; } static int mmc_spi_bind(struct udevice *dev) { - struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_spi_plat *plat = dev_get_platdata(dev); - return mmc_bind(dev, &priv->mmc, &priv->cfg); + return mmc_bind(dev, &plat->mmc, &plat->cfg); } static const struct dm_mmc_ops mmc_spi_ops = { @@ -426,5 +430,6 @@ U_BOOT_DRIVER(mmc_spi) = { .ops = &mmc_spi_ops, .probe = mmc_spi_probe, .bind = mmc_spi_bind, + .platdata_auto_alloc_size = sizeof(struct mmc_spi_plat), .priv_auto_alloc_size = sizeof(struct mmc_spi_priv), }; diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 02648b0f50..b52ff9f3bc 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -79,7 +79,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) u32 start_rem, blkcnt_rem; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; - int timeout = 1000; + int timeout_ms = 1000; if (!mmc) return -1; @@ -119,7 +119,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) blk += blk_r; /* Waiting for the ready status */ - if (mmc_poll_for_busy(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout_ms)) return 0; } @@ -131,7 +131,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, { struct mmc_cmd cmd; struct mmc_data data; - int timeout = 1000; + int timeout_ms = 1000; if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) { printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", @@ -177,7 +177,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, } /* Waiting for the ready status */ - if (mmc_poll_for_busy(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout_ms)) return 0; return blkcnt; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 3ea7f4e173..bade129aea 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -430,7 +430,7 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage) writel(ac12, &mmc_base->ac12); } -static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) +static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout_us) { int ret = -ETIMEDOUT; u32 con; @@ -442,8 +442,8 @@ static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) con = readl(&mmc_base->con); writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con); - timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */ - while (timeout--) { + timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */ + while (timeout_us--) { dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0); if (dat0_high == target_dat0_high) { ret = 0; diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 7c53aa221e..0cb65b480d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -499,15 +499,16 @@ static int renesas_sdhi_set_ios(struct udevice *dev) } #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) -static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, int timeout) +static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, + int timeout_us) { int ret = -ETIMEDOUT; bool dat0_high; bool target_dat0_high = !!state; struct tmio_sd_priv *priv = dev_get_priv(dev); - timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */ - while (timeout--) { + timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */ + while (timeout_us--) { dat0_high = !!(tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_DAT0); if (dat0_high == target_dat0_high) { ret = 0; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 2779bca93f..fbc576fd72 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -711,17 +711,19 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, { u32 caps, caps_1 = 0; #if CONFIG_IS_ENABLED(DM_MMC) - u32 mask[2] = {0}; - int ret; - ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask", - mask, 2); - if (ret && ret != -1) - return ret; - - caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES); + u64 dt_caps, dt_caps_mask; + + dt_caps_mask = dev_read_u64_default(host->mmc->dev, + "sdhci-caps-mask", 0); + dt_caps = dev_read_u64_default(host->mmc->dev, + "sdhci-caps", 0); + caps = ~(u32)dt_caps_mask & + sdhci_readl(host, SDHCI_CAPABILITIES); + caps |= (u32)dt_caps; #else caps = sdhci_readl(host, SDHCI_CAPABILITIES); #endif + debug("%s, caps: 0x%x\n", __func__, caps); #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -762,10 +764,13 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { #if CONFIG_IS_ENABLED(DM_MMC) - caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps_1 = ~(u32)(dt_caps_mask >> 32) & + sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps_1 |= (u32)(dt_caps >> 32); #else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); #endif + debug("%s, caps_1: 0x%x\n", __func__, caps_1); host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } |