summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig11
-rw-r--r--drivers/mmc/fsl_esdhc_imx.c44
-rw-r--r--drivers/mmc/mmc.c27
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c10
-rw-r--r--drivers/mmc/rockchip_sdhci.c11
-rw-r--r--drivers/mmc/zynq_sdhci.c39
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(&regs->sysctl, SYSCTL_RSTA);
+ esdhc_setbits32(&regs->sysctl, SYSCTL_RSTA | SYSCTL_RSTT);
/* Wait until the controller is available */
start = get_timer(0);
- while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA)) {
+ while ((esdhc_read32(&regs->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(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
+ /* max 1ms delay with clock on for initialization */
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
+ udelay(1000);
+ esdhc_clrbits32(&regs->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(&regs->sysctl, SYSCTL_RSTA);
+ esdhc_setbits32(&regs->sysctl, SYSCTL_RSTA | SYSCTL_RSTT);
/* hardware clears the bit when it is done */
start = get_timer(0);
- while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA)) {
+ while ((esdhc_read32(&regs->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(&regs->irqstaten, SDHCI_IRQ_EN_BITS);
cfg = &plat->cfg;
- if (!CONFIG_IS_ENABLED(DM_MMC))
- memset(cfg, '\0', sizeof(*cfg));
caps = esdhc_read32(&regs->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 },
{ }
};