Message ID | 04ef5d01dd208c2985ea45e92e89a3ca4a386481.1603712577.git.michal.simek@xilinx.com |
---|---|
State | Accepted |
Commit | 80355ae40dfceb2304ed287846a3d3292e65d323 |
Delegated to: | Michal Simek |
Headers | show |
Series | mmc: zynqmp_sdhci: Add support for Tap delay | expand |
On 10/26/20 8:42 PM, Michal Simek wrote: > Define input and output clock phase delays with pre-defined values. > > Define arasan_sdhci_clk_data type structure and add it to priv > structure and store these clock phase delays in it. > > Read input and output clock phase delays from dt. If these values are > not passed through dt, use pre-defined values. > > 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 > --- > > (no changes since v1) > > drivers/mmc/zynq_sdhci.c | 85 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 85 insertions(+) > > diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c > index 998a38450680..e69f375cce07 100644 > --- a/drivers/mmc/zynq_sdhci.c > +++ b/drivers/mmc/zynq_sdhci.c > @@ -20,6 +20,12 @@ > #include <zynqmp_tap_delay.h> > > #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; > @@ -28,12 +34,17 @@ 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) > +/* 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}; > + > static const u8 mode2timing[] = { > [MMC_LEGACY] = MMC_TIMING_LEGACY, > [MMC_HS] = MMC_TIMING_MMC_HS, > @@ -168,6 +179,79 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) > priv->bank); > } > > +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; > + } > + > + /* 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; > + } > + } > + > + 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) > { > struct mmc *mmc = (struct mmc *)host->mmc; > @@ -271,6 +355,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) > > #if defined(CONFIG_ARCH_ZYNQMP) > priv->host->ops = &arasan_ops; > + arasan_dt_parse_clk_phases(dev); > #endif > > priv->host->ioaddr = (void *)dev_read_addr(dev); >
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 998a38450680..e69f375cce07 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -20,6 +20,12 @@ #include <zynqmp_tap_delay.h> #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; @@ -28,12 +34,17 @@ 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) +/* 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}; + static const u8 mode2timing[] = { [MMC_LEGACY] = MMC_TIMING_LEGACY, [MMC_HS] = MMC_TIMING_MMC_HS, @@ -168,6 +179,79 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) priv->bank); } +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; + } + + /* 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; + } + } + + 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) { struct mmc *mmc = (struct mmc *)host->mmc; @@ -271,6 +355,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) #if defined(CONFIG_ARCH_ZYNQMP) priv->host->ops = &arasan_ops; + arasan_dt_parse_clk_phases(dev); #endif priv->host->ioaddr = (void *)dev_read_addr(dev);