diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 44 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 27 | ||||
-rw-r--r-- | drivers/mmc/rockchip_dw_mmc.c | 10 | ||||
-rw-r--r-- | drivers/mmc/rockchip_sdhci.c | 11 | ||||
-rw-r--r-- | drivers/mmc/zynq_sdhci.c | 39 |
6 files changed, 105 insertions, 37 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 982e84dc3bc..22c65681f0a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -61,6 +61,17 @@ config SPL_DM_MMC appear as block devices in U-Boot and can support filesystems such as EXT4 and FAT. +config TPL_DM_MMC + bool "Enable MMC controllers using Driver Model in TPL" + depends on TPL_DM && DM_MMC + select TPL_BLK + help + This enables the MultiMediaCard (MMC) uclass which supports MMC and + Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.) + and non-removable (e.g. eMMC chip) devices are supported. These + appear as block devices in U-Boot and can support filesystems such + as EXT4 and FAT. + if MMC config MMC_SDHCI_ADMA_HELPERS diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 03de7dcd505..fb410104c1f 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -148,6 +148,7 @@ struct fsl_esdhc_priv { struct fsl_esdhc *esdhc_regs; unsigned int sdhc_clk; struct clk per_clk; + struct clk_bulk clk_bulk; unsigned int clock; unsigned int mode; #if !CONFIG_IS_ENABLED(DM_MMC) @@ -986,11 +987,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) ulong start; /* Reset the entire host controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* Wait until the controller is available */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 1000) return -ETIMEDOUT; } @@ -1034,6 +1035,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + /* max 1ms delay with clock on for initialization */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + udelay(1000); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + return 0; } @@ -1089,11 +1095,11 @@ static int esdhc_reset(struct fsl_esdhc *regs) ulong start; /* reset the controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* hardware clears the bit when it is done */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 100) { printf("MMC/SD: Reset never completed.\n"); return -ETIMEDOUT; @@ -1188,8 +1194,6 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; - if (!CONFIG_IS_ENABLED(DM_MMC)) - memset(cfg, '\0', sizeof(*cfg)); caps = esdhc_read32(®s->hostcapblt); @@ -1323,6 +1327,8 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) break; default: printf("invalid max bus width %u\n", cfg->max_bus_width); + free(plat); + free(priv); return -EINVAL; } @@ -1521,14 +1527,21 @@ static int fsl_esdhc_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */ - ret = clk_get_by_name(dev, "per", &priv->per_clk); + ret = clk_get_bulk(dev, &priv->clk_bulk); if (ret) { - printf("Failed to get per_clk\n"); + dev_err(dev, "Failed to get clks: %d\n", ret); + return ret; + } + + ret = clk_enable_bulk(&priv->clk_bulk); + if (ret) { + dev_err(dev, "Failed to enable clks: %d\n", ret); return ret; } - ret = clk_enable(&priv->per_clk); + + ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { - printf("Failed to enable per_clk\n"); + printf("Failed to get per_clk\n"); return ret; } @@ -1561,7 +1574,7 @@ static int fsl_esdhc_probe(struct udevice *dev) upriv->mmc = mmc; - return esdhc_init_common(priv, mmc); + return 0; } static int fsl_esdhc_get_cd(struct udevice *dev) @@ -1613,6 +1626,14 @@ static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, return esdhc_wait_dat0_common(priv, state, timeout_us); } +static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_plat(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + return esdhc_init_common(priv, &plat->mmc); +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1624,6 +1645,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, #endif .wait_dat0 = fsl_esdhc_wait_dat0, + .reinit = fsl_esdhc_reinit, }; static struct esdhc_soc_data usdhc_imx7d_data = { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7e702c3ae85..d4f2fd5bf89 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3039,6 +3039,20 @@ static int mmc_complete_init(struct mmc *mmc) return err; } +static void __maybe_unused mmc_cyclic_cd_poll(struct cyclic_info *c) +{ + struct mmc *m = CONFIG_IS_ENABLED(CYCLIC, (container_of(c, struct mmc, cyclic)), (NULL)); + + if (!m->has_init) + return; + + if (mmc_getcd(m)) + return; + + mmc_deinit(m); + m->has_init = 0; +} + int mmc_init(struct mmc *mmc) { int err = 0; @@ -3061,6 +3075,14 @@ int mmc_init(struct mmc *mmc) if (err) pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); + if (CONFIG_IS_ENABLED(CYCLIC, (!mmc->cyclic.func), (NULL))) { + /* Register cyclic function for card detect polling */ + CONFIG_IS_ENABLED(CYCLIC, (cyclic_register(&mmc->cyclic, + mmc_cyclic_cd_poll, + 100 * 1000, + mmc->cfg->name))); + } + return err; } @@ -3068,6 +3090,9 @@ int mmc_deinit(struct mmc *mmc) { u32 caps_filtered; + if (CONFIG_IS_ENABLED(CYCLIC, (mmc->cyclic.func), (NULL))) + CONFIG_IS_ENABLED(CYCLIC, (cyclic_unregister(&mmc->cyclic))); + if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) && !CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) && !CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) @@ -3188,7 +3213,7 @@ int mmc_init_device(int num) if (uclass_get_device_by_seq(UCLASS_MMC, num, &dev)) { ret = uclass_get_device(UCLASS_MMC, num, &dev); if (ret) - return ret; + return log_msg_ret("ini", ret); } m = mmc_get_mmc_dev(dev); diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index fb77b049834..5ba99d68b7d 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -80,7 +80,7 @@ static int rockchip_dwmmc_of_to_plat(struct udevice *dev) priv->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0); if (priv->fifo_depth < 0) - return -EINVAL; + return log_msg_ret("rkp", -EINVAL); priv->fifo_mode = dev_read_bool(dev, "fifo-mode"); #ifdef CONFIG_SPL_BUILD @@ -96,7 +96,7 @@ static int rockchip_dwmmc_of_to_plat(struct udevice *dev) int val = dev_read_u32_default(dev, "max-frequency", -EINVAL); if (val < 0) - return val; + return log_msg_ret("rkc", val); priv->minmax[0] = 400000; /* 400 kHz */ priv->minmax[1] = val; @@ -131,13 +131,11 @@ static int rockchip_dwmmc_probe(struct udevice *dev) priv->minmax[1] = dtplat->max_frequency; ret = clk_get_by_phandle(dev, &dtplat->clocks[1], &priv->clk); - if (ret < 0) - return ret; #else ret = clk_get_by_index(dev, 1, &priv->clk); - if (ret < 0) - return ret; #endif + if (ret < 0 && ret != -ENOSYS) + return log_msg_ret("clk", ret); host->fifo_depth = priv->fifo_depth; host->fifo_mode = priv->fifo_mode; diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index 35667b86b50..4ea3307ed9c 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -230,7 +230,7 @@ static int rk3399_emmc_get_phy(struct udevice *dev) grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); if (IS_ERR_OR_NULL(grf_base)) { - printf("%s Get syscon grf failed", __func__); + printf("%s: Get syscon grf failed\n", __func__); return -ENODEV; } grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0); @@ -571,20 +571,19 @@ static int rockchip_sdhci_probe(struct udevice *dev) struct rockchip_sdhc *priv = dev_get_priv(dev); struct mmc_config *cfg = &plat->cfg; struct sdhci_host *host = &priv->host; - struct clk clk; + struct clk *clk = &priv->emmc_clk; int ret; host->max_clk = cfg->f_max; - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, clk); if (!ret) { - ret = clk_set_rate(&clk, host->max_clk); + ret = clk_set_rate(clk, host->max_clk); if (IS_ERR_VALUE(ret)) printf("%s clk set rate fail!\n", __func__); - } else { + } else if (ret != -ENOSYS) { printf("%s fail to get clk\n", __func__); } - priv->emmc_clk = clk; priv->dev = dev; if (data->get_phy) { diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 28d2b456fbf..24d0556cd37 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -105,6 +105,19 @@ struct arasan_sdhci_priv { struct reset_ctl_bulk resets; }; +enum arasan_sdhci_compatible { + SDHCI_COMPATIBLE_SDHCI_89A, + SDHCI_COMPATIBLE_VERSAL_NET_EMMC, +}; + +static bool arasan_sdhci_is_compatible(struct udevice *dev, + enum arasan_sdhci_compatible family) +{ + enum arasan_sdhci_compatible compat = dev_get_driver_data(dev); + + return compat == family; +} + /* For Versal platforms zynqmp_mmio_write() won't be available */ __weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) { @@ -422,7 +435,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) mdelay(1); - if (device_is_compatible(mmc->dev, "xlnx,zynqmp-8.9a")) + if (arasan_sdhci_is_compatible(mmc->dev, SDHCI_COMPATIBLE_SDHCI_89A)) arasan_zynqmp_dll_reset(host, priv->node_id); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); @@ -470,7 +483,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) udelay(1); - if (device_is_compatible(mmc->dev, "xlnx,zynqmp-8.9a")) + if (arasan_sdhci_is_compatible(mmc->dev, SDHCI_COMPATIBLE_SDHCI_89A)) arasan_zynqmp_dll_reset(host, priv->node_id); /* Enable only interrupts served by the SD controller */ @@ -858,7 +871,7 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing); if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && - device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); if (ret) return ret; @@ -869,7 +882,7 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) } else if ((IS_ENABLED(CONFIG_ARCH_VERSAL) || IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || IS_ENABLED(CONFIG_ARCH_VERSAL2)) && - device_is_compatible(dev, "xlnx,versal-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = sdhci_versal_sampleclk_set_phase(host, iclk_phase); if (ret) return ret; @@ -879,7 +892,7 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) return ret; } else if ((IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || IS_ENABLED(CONFIG_ARCH_VERSAL2)) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) { if (mmc->clock >= MIN_PHY_CLK_HZ) if (iclk_phase == VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLY_CHAIN) iclk_phase = VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLL; @@ -933,7 +946,7 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) int i; if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && - device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = zynqmp_iclk_phases[i]; clk_data->clk_phase_out[i] = zynqmp_oclk_phases[i]; @@ -948,7 +961,7 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) if ((IS_ENABLED(CONFIG_ARCH_VERSAL) || IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || IS_ENABLED(CONFIG_ARCH_VERSAL2)) && - device_is_compatible(dev, "xlnx,versal-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = versal_iclk_phases[i]; clk_data->clk_phase_out[i] = versal_oclk_phases[i]; @@ -957,7 +970,7 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) if ((IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || IS_ENABLED(CONFIG_ARCH_VERSAL2)) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = versal_net_emmc_iclk_phases[i]; clk_data->clk_phase_out[i] = versal_net_emmc_oclk_phases[i]; @@ -1101,7 +1114,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host = priv->host; #if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) - if (device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + if (arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG); if (!ret) { @@ -1111,7 +1124,7 @@ static int arasan_sdhci_probe(struct udevice *dev) } } #endif - if (device_is_compatible(dev, "xlnx,versal-net-emmc")) + if (arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) priv->internal_phy_reg = true; ret = clk_get_by_index(dev, 0, &clk); @@ -1145,7 +1158,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host->quirks |= SDHCI_QUIRK_NO_1_8_V; if (CONFIG_IS_ENABLED(ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) host->quirks |= SDHCI_QUIRK_CAPS_BIT63_FOR_HS400; plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ; @@ -1228,8 +1241,8 @@ static int arasan_sdhci_bind(struct udevice *dev) } static const struct udevice_id arasan_sdhci_ids[] = { - { .compatible = "arasan,sdhci-8.9a" }, - { .compatible = "xlnx,versal-net-emmc" }, + { .compatible = "arasan,sdhci-8.9a", .data = SDHCI_COMPATIBLE_SDHCI_89A }, + { .compatible = "xlnx,versal-net-emmc", .data = SDHCI_COMPATIBLE_VERSAL_NET_EMMC }, { } }; |