diff mbox series

[v2,5/8] mmc: zynq_sdhci: Set tapdelays based on clk phase delays

Message ID a2e96fb2e750d7ac5938cd24edcfc966f75a05f0.1603451681.git.michal.simek@xilinx.com
State Superseded
Delegated to: Michal Simek
Headers show
Series mmc: zynqmp_sdhci: Add support for Tap delay | expand

Commit Message

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

Define and use functions for setting input and output tapdelays
based on clk phase delays.

Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---

(no changes since v1)

 drivers/mmc/zynq_sdhci.c | 128 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 123 insertions(+), 5 deletions(-)

Comments

Jaehoon Chung Oct. 26, 2020, 9:48 a.m. UTC | #1
Hi Michal,

On 10/23/20 8:14 PM, Michal Simek wrote:
> From: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> 
> Define and use functions for setting input and output tapdelays
> based on clk phase delays.
> 
> Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/mmc/zynq_sdhci.c | 128 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 123 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
> index e69f375cce07..49ae607f9f71 100644
> --- a/drivers/mmc/zynq_sdhci.c
> +++ b/drivers/mmc/zynq_sdhci.c
> @@ -166,17 +166,135 @@ 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 (host->version < SDHCI_SPEC_300 ||

SDHCI_GET_VERSION(host) instead of host->version?

> +	    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 (host->version < SDHCI_SPEC_300 ||

Ditto.


Best Regards,
Jaehoon Chung


> +	    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;
> +}
> +
>  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];
>  
> -	uhsmode = mode2timing[mmc->selected_mode];
> +	dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing);
>  
> -	if (uhsmode >= UHS_SDR25_BUS_SPEED)
> -		arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
> -					   priv->bank);
> +	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);
> +	}
>  }
>  
>  static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing,
>
Ashok Reddy Soma Oct. 26, 2020, 11:21 a.m. UTC | #2
Hi Jaehoon,

> -----Original Message-----
> From: Jaehoon Chung <jh80.chung@samsung.com>
> Sent: Monday, October 26, 2020 3:19 PM
> To: Michal Simek <michals@xilinx.com>; u-boot@lists.denx.de; git
> <git@xilinx.com>
> Cc: Ashok Reddy Soma <ashokred@xilinx.com>; Peng Fan
> <peng.fan@nxp.com>
> Subject: Re: [PATCH v2 5/8] mmc: zynq_sdhci: Set tapdelays based on clk phase
> delays
> 
> Hi Michal,
> 
> On 10/23/20 8:14 PM, Michal Simek wrote:
> > From: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> >
> > Define and use functions for setting input and output tapdelays based
> > on clk phase delays.
> >
> > Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > ---
> >
> > (no changes since v1)
> >
> >  drivers/mmc/zynq_sdhci.c | 128
> > +++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 123 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index
> > e69f375cce07..49ae607f9f71 100644
> > --- a/drivers/mmc/zynq_sdhci.c
> > +++ b/drivers/mmc/zynq_sdhci.c
> > @@ -166,17 +166,135 @@ 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 (host->version < SDHCI_SPEC_300 ||
> 
> SDHCI_GET_VERSION(host) instead of host->version?

Sure I will change and send V3.

> 
> > +	    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 (host->version < SDHCI_SPEC_300 ||
> 
> Ditto. 

Wherever applicable I will change with SDHCI_GET_VERSION(host) and send V3.

Thanks for the review!

Thanks,
Ashok

> 
> 
> Best Regards,
> Jaehoon Chung
> 
> 
> > +	    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;
> > +}
> > +
> >  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];
> >
> > -	uhsmode = mode2timing[mmc->selected_mode];
> > +	dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name,
> > +timing);
> >
> > -	if (uhsmode >= UHS_SDR25_BUS_SPEED)
> > -		arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
> > -					   priv->bank);
> > +	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);
> > +	}
> >  }
> >
> >  static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned
> > char timing,
> >
diff mbox series

Patch

diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index e69f375cce07..49ae607f9f71 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -166,17 +166,135 @@  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 (host->version < 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 (host->version < 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;
+}
+
 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];
 
-	uhsmode = mode2timing[mmc->selected_mode];
+	dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing);
 
-	if (uhsmode >= UHS_SDR25_BUS_SPEED)
-		arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
-					   priv->bank);
+	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);
+	}
 }
 
 static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing,