On 17/10/18 1:36 PM, Yinbo Zhu wrote: > From: Yangbo Lu <yangbo.lu@xxxxxxx> > > There are timing violations in case of few division ratio options > are selected for card clock frequency. prescaler*divisor options > /3,/5,/6,/7,/9,/10,/11,/13,/14 and /15 are not available in LX2 > Rev1.0. prescaler*divisor options /4,/8 and /12 only available in > LX2 Rev1.0. Applicable only for HS400 mode. so by add the erratum > A011334 support to limit the prescaler*divisor in LX2 REV1.0 > > Signed-off-by: Yinbo Zhu <yinbo.zhu@xxxxxxx> If you still need this, please re-base > --- > Change in v2: > Changed some code row and column locations > > drivers/mmc/host/sdhci-of-esdhc.c | 39 +++++++++++++++++++++++++++++++++++++ > 1 files changed, 39 insertions(+), 0 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index c4e3aa5..94a36b7 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -33,6 +33,7 @@ struct sdhci_esdhc { > u8 vendor_ver; > u8 spec_ver; > bool quirk_incorrect_hostver; > + bool quirk_limited_clk_division; > unsigned int peripheral_clock; > }; > > @@ -466,6 +467,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > int pre_div = 1; > int div = 1; > + int division; > ktime_t timeout; > u32 temp; > > @@ -519,6 +521,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > while (host->max_clk / pre_div / div > clock && div < 16) > div++; > > + if (esdhc->quirk_limited_clk_division && > + clock == MMC_HS200_MAX_DTR && > + (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 || > + host->flags & SDHCI_HS400_TUNING)) { > + division = pre_div * div; > + if (division <= 4) { > + pre_div = 4; > + div = 1; > + } else if (division <= 8) { > + pre_div = 4; > + div = 2; > + } else if (division <= 12) { > + pre_div = 4; > + div = 3; > + } else { > + pr_warn("%s: using upsupported clock division.\n", > + mmc_hostname(host->mmc)); > + } > + } > + > dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", > clock, host->max_clk / pre_div / div); > host->mmc->actual_clock = host->max_clk / pre_div / div; > @@ -725,10 +747,16 @@ static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable) > static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) > { > struct sdhci_host *host = mmc_priv(mmc); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > bool hs400_tuning; > u32 val; > int ret; > > + if (esdhc->quirk_limited_clk_division && > + host->flags & SDHCI_HS400_TUNING) > + esdhc_of_set_clock(host, host->clock); > + > esdhc_tuning_block_enable(host, true); > > hs400_tuning = host->flags & SDHCI_HS400_TUNING; > @@ -838,6 +866,11 @@ static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, > { }, > }; > > +static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = { > + { .family = "QorIQ LX2160A", .revision = "1.0", }, > + { }, > +}; > + > static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) > { > struct sdhci_pltfm_host *pltfm_host; > @@ -859,6 +892,11 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) > else > esdhc->quirk_incorrect_hostver = false; > > + if (soc_device_match(soc_fixup_sdhc_clkdivs)) > + esdhc->quirk_limited_clk_division = true; > + else > + esdhc->quirk_limited_clk_division = false; > + > np = pdev->dev.of_node; > clk = of_clk_get(np, 0); > if (!IS_ERR(clk)) { > @@ -924,6 +962,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) > > pltfm_host = sdhci_priv(host); > esdhc = sdhci_pltfm_priv(pltfm_host); > + > if (esdhc->vendor_ver == VENDOR_V_22) > host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; > >