summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/mmc.c25
-rw-r--r--drivers/mmc/msm_sdhci.c11
-rw-r--r--drivers/mmc/snps_dw_mmc.c9
-rw-r--r--drivers/mmc/zynq_sdhci.c39
4 files changed, 71 insertions, 13 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e8870e30689..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))
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index f5e9930c799..4e5c932c071 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -32,6 +32,8 @@
#define SDCC_MCI_STATUS2_MCI_ACT 0x1
#define SDCC_MCI_HC_MODE 0x78
+#define CORE_VENDOR_SPEC_POR_VAL 0xa9c
+
struct msm_sdhc_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -46,6 +48,7 @@ struct msm_sdhc {
struct msm_sdhc_variant_info {
bool mci_removed;
+ u32 core_vendor_spec;
u32 core_vendor_spec_capabilities0;
};
@@ -54,11 +57,14 @@ DECLARE_GLOBAL_DATA_PTR;
static int msm_sdc_clk_init(struct udevice *dev)
{
struct msm_sdhc *prv = dev_get_priv(dev);
+ const struct msm_sdhc_variant_info *var_info;
ofnode node = dev_ofnode(dev);
ulong clk_rate;
int ret, i = 0, n_clks;
const char *clk_name;
+ var_info = (void *)dev_get_driver_data(dev);
+
ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate));
if (ret)
clk_rate = 201500000;
@@ -105,6 +111,9 @@ static int msm_sdc_clk_init(struct udevice *dev)
return -EINVAL;
}
+ writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
+ prv->host.ioaddr + var_info->core_vendor_spec);
+
return 0;
}
@@ -254,12 +263,14 @@ static int msm_sdc_bind(struct udevice *dev)
static const struct msm_sdhc_variant_info msm_sdhc_mci_var = {
.mci_removed = false,
+ .core_vendor_spec = 0x10c,
.core_vendor_spec_capabilities0 = 0x11c,
};
static const struct msm_sdhc_variant_info msm_sdhc_v5_var = {
.mci_removed = true,
+ .core_vendor_spec = 0x20c,
.core_vendor_spec_capabilities0 = 0x21c,
};
diff --git a/drivers/mmc/snps_dw_mmc.c b/drivers/mmc/snps_dw_mmc.c
index f30331e51f7..47ab5654bd6 100644
--- a/drivers/mmc/snps_dw_mmc.c
+++ b/drivers/mmc/snps_dw_mmc.c
@@ -12,6 +12,7 @@
#include <dwmmc.h>
#include <errno.h>
#include <fdtdec.h>
+#include <asm/gpio.h>
#include <dm/device_compat.h>
#include <linux/libfdt.h>
#include <linux/err.h>
@@ -29,6 +30,7 @@ struct snps_dwmci_plat {
struct snps_dwmci_priv_data {
struct dwmci_host host;
u32 f_max;
+ struct gpio_desc cd_gpio;
};
static int snps_dwmmc_clk_setup(struct udevice *dev)
@@ -104,6 +106,10 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev)
if (!ret && priv->f_max < CLOCK_MIN)
return -EINVAL;
+ if (CONFIG_IS_ENABLED(DM_GPIO))
+ gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
+ GPIOD_IS_IN);
+
host->fifo_mode = dev_read_bool(dev, "fifo-mode");
host->name = dev->name;
host->dev_index = 0;
@@ -117,6 +123,9 @@ int snps_dwmmc_getcd(struct udevice *dev)
struct snps_dwmci_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&priv->cd_gpio))
+ return dm_gpio_get_value(&priv->cd_gpio);
+
return !(dwmci_readl(host, DWMCI_CDETECT) & 1);
}
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 },
{ }
};