
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