aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/sdhci.c3
-rw-r--r--drivers/mmc/zynq_sdhci.c406
2 files changed, 384 insertions, 25 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index d549a264d7..0628934312 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -812,7 +812,8 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
cfg->host_caps &= ~MMC_MODE_HS_52MHz;
}
- if (!(cfg->voltages & MMC_VDD_165_195))
+ if (!(cfg->voltages & MMC_VDD_165_195) ||
+ (host->quirks & SDHCI_QUIRK_NO_1_8_V))
caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 775c17baac..147ecc0d70 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -19,6 +19,20 @@
#include <sdhci.h>
#include <zynqmp_tap_delay.h>
+#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8
+#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC
+#define SDHCI_ITAPDLY_CHGWIN 0x200
+#define SDHCI_ITAPDLY_ENABLE 0x100
+#define SDHCI_OTAPDLY_ENABLE 0x40
+
+#define SDHCI_TUNING_LOOP_COUNT 40
+#define MMC_BANK2 0x2
+
+struct arasan_sdhci_clk_data {
+ int clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
+ int clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
+};
+
struct arasan_sdhci_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -26,29 +40,35 @@ struct arasan_sdhci_plat {
struct arasan_sdhci_priv {
struct sdhci_host *host;
+ struct arasan_sdhci_clk_data clk_data;
u8 deviceid;
u8 bank;
+ u8 no_1p8;
};
-#if defined(CONFIG_ARCH_ZYNQMP)
-#define MMC_HS200_BUS_SPEED 5
+#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
+/* Default settings for ZynqMP Clock Phases */
+const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0};
+const u32 zynqmp_oclk_phases[] = {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0};
+
+/* Default settings for Versal Clock Phases */
+const u32 versal_iclk_phases[] = {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0};
+const u32 versal_oclk_phases[] = {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0};
static const u8 mode2timing[] = {
- [MMC_LEGACY] = UHS_SDR12_BUS_SPEED,
- [MMC_HS] = HIGH_SPEED_BUS_SPEED,
- [SD_HS] = HIGH_SPEED_BUS_SPEED,
- [MMC_HS_52] = HIGH_SPEED_BUS_SPEED,
- [MMC_DDR_52] = HIGH_SPEED_BUS_SPEED,
- [UHS_SDR12] = UHS_SDR12_BUS_SPEED,
- [UHS_SDR25] = UHS_SDR25_BUS_SPEED,
- [UHS_SDR50] = UHS_SDR50_BUS_SPEED,
- [UHS_DDR50] = UHS_DDR50_BUS_SPEED,
- [UHS_SDR104] = UHS_SDR104_BUS_SPEED,
- [MMC_HS_200] = MMC_HS200_BUS_SPEED,
+ [MMC_LEGACY] = MMC_TIMING_LEGACY,
+ [MMC_HS] = MMC_TIMING_MMC_HS,
+ [SD_HS] = MMC_TIMING_SD_HS,
+ [MMC_HS_52] = MMC_TIMING_UHS_SDR50,
+ [MMC_DDR_52] = MMC_TIMING_UHS_DDR50,
+ [UHS_SDR12] = MMC_TIMING_UHS_SDR12,
+ [UHS_SDR25] = MMC_TIMING_UHS_SDR25,
+ [UHS_SDR50] = MMC_TIMING_UHS_SDR50,
+ [UHS_DDR50] = MMC_TIMING_UHS_DDR50,
+ [UHS_SDR104] = MMC_TIMING_UHS_SDR104,
+ [MMC_HS_200] = MMC_TIMING_MMC_HS200,
};
-#define SDHCI_TUNING_LOOP_COUNT 40
-
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
{
u16 clk;
@@ -156,17 +176,352 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
return 0;
}
+/**
+ * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
+ *
+ * Set the SD Output Clock Tap Delays for Output path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees: The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * ZynqMP does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 30 Taps are available */
+ tap_max = 30;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 15 Taps are available */
+ tap_max = 15;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 8 Taps are available */
+ tap_max = 8;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ arasan_zynqmp_set_tapdelay(priv->deviceid, 0, tap_delay);
+
+ return ret;
+}
+
+/**
+ * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
+ *
+ * Set the SD Input Clock Tap Delays for Input path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees: The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * ZynqMP does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 120 Taps are available */
+ tap_max = 120;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 60 Taps are available */
+ tap_max = 60;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 30 Taps are available */
+ tap_max = 30;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ arasan_zynqmp_set_tapdelay(priv->deviceid, tap_delay, 0);
+
+ return ret;
+}
+
+/**
+ * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
+ *
+ * Set the SD Output Clock Tap Delays for Output path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sdcardclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * Versal does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 30 Taps are available */
+ tap_max = 30;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 15 Taps are available */
+ tap_max = 15;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 8 Taps are available */
+ tap_max = 8;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ /* Set the Clock Phase */
+ if (tap_delay) {
+ u32 regval;
+
+ regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ regval |= SDHCI_OTAPDLY_ENABLE;
+ sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ regval |= tap_delay;
+ sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ }
+
+ return ret;
+}
+
+/**
+ * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
+ *
+ * Set the SD Input Clock Tap Delays for Input path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sampleclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * Versal does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 120 Taps are available */
+ tap_max = 120;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 60 Taps are available */
+ tap_max = 60;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 30 Taps are available */
+ tap_max = 30;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ /* Set the Clock Phase */
+ if (tap_delay) {
+ u32 regval;
+
+ regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= SDHCI_ITAPDLY_CHGWIN;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= SDHCI_ITAPDLY_ENABLE;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= tap_delay;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval &= ~SDHCI_ITAPDLY_CHGWIN;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ }
+
+ return ret;
+}
+
static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
{
struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
struct mmc *mmc = (struct mmc *)host->mmc;
- u8 uhsmode;
+ struct udevice *dev = mmc->dev;
+ u8 timing = mode2timing[mmc->selected_mode];
+ u32 iclk_phase = clk_data->clk_phase_in[timing];
+ u32 oclk_phase = clk_data->clk_phase_out[timing];
+
+ 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")) {
+ sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase);
+ sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase);
+ } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
+ device_is_compatible(dev, "xlnx,versal-8.9a")) {
+ sdhci_versal_sampleclk_set_phase(host, iclk_phase);
+ sdhci_versal_sdcardclk_set_phase(host, oclk_phase);
+ }
+}
- uhsmode = mode2timing[mmc->selected_mode];
+static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing,
+ const char *prop)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
+ u32 clk_phase[2] = {0};
+
+ /*
+ * Read Tap Delay values from DT, if the DT does not contain the
+ * Tap Values then use the pre-defined values
+ */
+ if (dev_read_u32_array(dev, prop, &clk_phase[0], 2)) {
+ dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
+ prop, clk_data->clk_phase_in[timing],
+ clk_data->clk_phase_out[timing]);
+ return;
+ }
- if (uhsmode >= UHS_SDR25_BUS_SPEED)
- arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
- priv->bank);
+ /* The values read are Input and Output Clock Delays in order */
+ clk_data->clk_phase_in[timing] = clk_phase[0];
+ clk_data->clk_phase_out[timing] = clk_phase[1];
+}
+
+/**
+ * arasan_dt_parse_clk_phases - Read Tap Delay values from DT
+ *
+ * Called at initialization to parse the values of Tap Delays.
+ *
+ * @dev: Pointer to our struct udevice.
+ */
+static void arasan_dt_parse_clk_phases(struct udevice *dev)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
+ int i;
+
+ if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) &&
+ device_is_compatible(dev, "xlnx,zynqmp-8.9a")) {
+ 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];
+ }
+
+ if (priv->bank == MMC_BANK2) {
+ clk_data->clk_phase_out[MMC_TIMING_UHS_SDR104] = 90;
+ clk_data->clk_phase_out[MMC_TIMING_MMC_HS200] = 90;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
+ device_is_compatible(dev, "xlnx,versal-8.9a")) {
+ 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];
+ }
+ }
+
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_LEGACY,
+ "clk-phase-legacy");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS,
+ "clk-phase-mmc-hs");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_SD_HS,
+ "clk-phase-sd-hs");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR12,
+ "clk-phase-uhs-sdr12");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR25,
+ "clk-phase-uhs-sdr25");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR50,
+ "clk-phase-uhs-sdr50");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR104,
+ "clk-phase-uhs-sdr104");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_DDR50,
+ "clk-phase-uhs-ddr50");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_DDR52,
+ "clk-phase-mmc-ddr52");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS200,
+ "clk-phase-mmc-hs200");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS400,
+ "clk-phase-mmc-hs400");
}
static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
@@ -184,12 +539,10 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
}
if (mmc->selected_mode > SD_HS &&
- mmc->selected_mode <= UHS_DDR50)
+ mmc->selected_mode <= MMC_HS_200)
sdhci_set_uhs_timing(host);
}
-#endif
-#if defined(CONFIG_ARCH_ZYNQMP)
const struct sdhci_ops arasan_ops = {
.platform_execute_tuning = &arasan_sdhci_execute_tuning,
.set_delay = &arasan_sdhci_set_tapdelay,
@@ -236,6 +589,9 @@ static int arasan_sdhci_probe(struct udevice *dev)
host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
#endif
+ if (priv->no_1p8)
+ host->quirks |= SDHCI_QUIRK_NO_1_8_V;
+
plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ;
ret = mmc_of_parse(dev, &plat->cfg);
@@ -267,8 +623,9 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
priv->host->name = dev->name;
-#if defined(CONFIG_ARCH_ZYNQMP)
+#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
priv->host->ops = &arasan_ops;
+ arasan_dt_parse_clk_phases(dev);
#endif
priv->host->ioaddr = (void *)dev_read_addr(dev);
@@ -277,6 +634,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1);
priv->bank = dev_read_u32_default(dev, "xlnx,mio-bank", 0);
+ priv->no_1p8 = dev_read_bool(dev, "no-1-8-v");
return 0;
}