On 12/06/18 07:50, Yinbo Zhu wrote: > From: yinbo.zhu <yinbo.zhu@xxxxxxx> > > Convert to use soc_device_match method to fix up eSDHC clock for > ls1046a/ls1012a/p1010. Also add eSDHC clock fixup for ls1021a > according to its datasheet. The maxmum speed for ls1021a eSDHC maxmum -> maximum > high speed mode is 46.5MHz. > > Signed-off-by: Yinbo Zhu <yinbo.zhu@xxxxxxx> Looks good. A couple of minor points below. > --- > Change in v4: > Add a special case in code logic for MMC_TIMING_LEGACY. > > drivers/mmc/host/sdhci-of-esdhc.c | 73 +++++++++++++++++++++++++++---------- > 1 files changed, 53 insertions(+), 20 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 4ffa6b1..a64ba6b 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -29,11 +29,52 @@ > #define VENDOR_V_22 0x12 > #define VENDOR_V_23 0x13 > > +#define MMC_TIMING_NUM (MMC_TIMING_MMC_HS400 + 1) > + > +struct esdhc_clk_fixup { > + const long sd_dflt_max_clk; > + const long max_clk[MMC_TIMING_NUM]; Why 'long' instead of 'unsigned int'? > +}; > + > +static const struct esdhc_clk_fixup ls1021a_esdhc_clk = { > + .sd_dflt_max_clk = 25000000, > + .max_clk[MMC_TIMING_MMC_HS] = 46500000, > + .max_clk[MMC_TIMING_SD_HS] = 46500000, > +}; > + > +static const struct esdhc_clk_fixup ls1046a_esdhc_clk = { > + .sd_dflt_max_clk = 25000000, > + .max_clk[MMC_TIMING_UHS_SDR104] = 167000000, > + .max_clk[MMC_TIMING_MMC_HS200] = 167000000, > +}; > + > +static const struct esdhc_clk_fixup ls1012a_esdhc_clk = { > + .sd_dflt_max_clk = 25000000, > + .max_clk[MMC_TIMING_UHS_SDR104] = 125000000, > + .max_clk[MMC_TIMING_MMC_HS200] = 125000000, > +}; > + > +static const struct esdhc_clk_fixup p1010_esdhc_clk = { > + .sd_dflt_max_clk = 20000000, > + .max_clk[MMC_TIMING_LEGACY] = 20000000, > + .max_clk[MMC_TIMING_MMC_HS] = 42000000, > + .max_clk[MMC_TIMING_SD_HS] = 40000000, > +}; > + > +static const struct soc_device_attribute soc_esdhc_clk_fixup[] = { > + { .family = "QorIQ LS1021A", .data = &ls1021a_esdhc_clk}, > + { .family = "QorIQ LS1046A", .data = &ls1046a_esdhc_clk}, > + { .family = "QorIQ LS1012A", .data = &ls1012a_esdhc_clk}, > + { .family = "QorIQ P1010", .data = &p1010_esdhc_clk}, > + {}, > +}; > + > struct sdhci_esdhc { > u8 vendor_ver; > u8 spec_ver; > bool quirk_incorrect_hostver; > unsigned int peripheral_clock; > + const struct esdhc_clk_fixup *clk_fixup; > }; > > /** > @@ -492,6 +533,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > int pre_div = 1; > int div = 1; > ktime_t timeout; > + long fixup; > u32 temp; > > host->mmc->actual_clock = 0; > @@ -505,27 +547,14 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > if (esdhc->vendor_ver < VENDOR_V_23) > pre_div = 2; > > - /* > - * Limit SD clock to 167MHz for ls1046a according to its datasheet > - */ > - if (clock > 167000000 && > - of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc")) > - clock = 167000000; > + if (host->mmc->card && mmc_card_sd(host->mmc->card) && > + host->mmc->ios.timing == MMC_TIMING_LEGACY) > + fixup = esdhc->clk_fixup->sd_dflt_max_clk; > + else > + fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing]; What if esdhc->clk_fixup is NULL? Also need to check if host->mmc->ios.timing >= MMC_TIMING_NUM > > - /* > - * Limit SD clock to 125MHz for ls1012a according to its datasheet > - */ > - if (clock > 125000000 && > - of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc")) > - clock = 125000000; > - > - /* Workaround to reduce the clock frequency for p1010 esdhc */ > - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { > - if (clock > 20000000) > - clock -= 5000000; > - if (clock > 40000000) > - clock -= 5000000; > - } > + if (fixup && clock > fixup) > + clock = fixup; > > temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | > @@ -783,6 +812,7 @@ static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, > > static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) > { > + const struct soc_device_attribute *matches; > struct sdhci_pltfm_host *pltfm_host; > struct sdhci_esdhc *esdhc; > struct device_node *np; > @@ -802,6 +832,9 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) > else > esdhc->quirk_incorrect_hostver = false; > > + matches = soc_device_match(soc_esdhc_clk_fixup); > + if (matches) > + esdhc->clk_fixup = matches->data; You could provide an all-zero esdhc_clk_fixup to avoid esdhc->clk_fixup being NULL, otherwise you should probably check whether it is NULL before using it. > np = pdev->dev.of_node; > clk = of_clk_get(np, 0); > if (!IS_ERR(clk)) { > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html