diff mbox series

[v3,6/8] mmc: zynq_sdhci: Add clock phase delays for Versal

Message ID ae3cd62a883165850201a2d5dc266eb1e3d7e40b.1603712577.git.michal.simek@xilinx.com
State Accepted
Commit 2e819a77b9f5c011fd4ec9ac575494f9b77b1ac7
Delegated to: Michal Simek
Headers show
Series mmc: zynqmp_sdhci: Add support for Tap delay | expand

Commit Message

Michal Simek Oct. 26, 2020, 11:42 a.m. UTC
From: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>

Define default values for input and output clock phase delays for
Versal. Also define functions for setting tapdelays based on these
clock phase delays.

Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
---

Changes in v3:
 - replace host->version by SDHCI_GET_VERSION(host) reported by Jaehoon

 drivers/mmc/zynq_sdhci.c | 160 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 156 insertions(+), 4 deletions(-)

Comments

Jaehoon Chung Oct. 26, 2020, 9:38 p.m. UTC | #1
On 10/26/20 8:42 PM, Michal Simek wrote:
> From: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> 
> Define default values for input and output clock phase delays for
> Versal. Also define functions for setting tapdelays based on these
> clock phase delays.
> 
> Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> Reviewed-by: Peng Fan <peng.fan@nxp.com>

Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>

Best Regards,
Jaehoon Chung

> ---
> 
> Changes in v3:
>  - replace host->version by SDHCI_GET_VERSION(host) reported by Jaehoon
> 
>  drivers/mmc/zynq_sdhci.c | 160 ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 156 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
> index 8871765711d4..d55ba74b2c38 100644
> --- a/drivers/mmc/zynq_sdhci.c
> +++ b/drivers/mmc/zynq_sdhci.c
> @@ -19,6 +19,12 @@
>  #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
>  
> @@ -40,11 +46,15 @@ struct arasan_sdhci_priv {
>  	u8 no_1p8;
>  };
>  
> -#if defined(CONFIG_ARCH_ZYNQMP)
> +#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] = MMC_TIMING_LEGACY,
>  	[MMC_HS] = MMC_TIMING_MMC_HS,
> @@ -278,6 +288,138 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host,
>  	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);
> @@ -294,6 +436,10 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
>  	    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);
>  	}
>  }
>  
> @@ -346,6 +492,14 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev)
>  		}
>  	}
>  
> +	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,
> @@ -388,9 +542,7 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
>  	    mmc->selected_mode <= UHS_DDR50)
>  		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,
> @@ -471,7 +623,7 @@ 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
>
diff mbox series

Patch

diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 8871765711d4..d55ba74b2c38 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -19,6 +19,12 @@ 
 #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
 
@@ -40,11 +46,15 @@  struct arasan_sdhci_priv {
 	u8 no_1p8;
 };
 
-#if defined(CONFIG_ARCH_ZYNQMP)
+#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] = MMC_TIMING_LEGACY,
 	[MMC_HS] = MMC_TIMING_MMC_HS,
@@ -278,6 +288,138 @@  static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host,
 	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);
@@ -294,6 +436,10 @@  static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
 	    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);
 	}
 }
 
@@ -346,6 +492,14 @@  static void arasan_dt_parse_clk_phases(struct udevice *dev)
 		}
 	}
 
+	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,
@@ -388,9 +542,7 @@  static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
 	    mmc->selected_mode <= UHS_DDR50)
 		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,
@@ -471,7 +623,7 @@  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