Commit 6079e63c authored by Yangbo Lu's avatar Yangbo Lu Committed by Ulf Hansson

mmc: sdhci-of-esdhc: add erratum A011334 support

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: default avatarYangbo Lu <yangbo.lu@nxp.com>
Signed-off-by: default avatarYinbo Zhu <yinbo.zhu@nxp.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 54e08d9a
...@@ -78,6 +78,7 @@ struct sdhci_esdhc { ...@@ -78,6 +78,7 @@ struct sdhci_esdhc {
u8 vendor_ver; u8 vendor_ver;
u8 spec_ver; u8 spec_ver;
bool quirk_incorrect_hostver; bool quirk_incorrect_hostver;
bool quirk_limited_clk_division;
bool quirk_fixup_tuning; bool quirk_fixup_tuning;
unsigned int peripheral_clock; unsigned int peripheral_clock;
const struct esdhc_clk_fixup *clk_fixup; const struct esdhc_clk_fixup *clk_fixup;
...@@ -544,6 +545,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -544,6 +545,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
int pre_div = 1; int pre_div = 1;
int div = 1; int div = 1;
int division;
ktime_t timeout; ktime_t timeout;
long fixup = 0; long fixup = 0;
u32 temp; u32 temp;
...@@ -579,6 +581,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -579,6 +581,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
while (host->max_clk / pre_div / div > clock && div < 16) while (host->max_clk / pre_div / div > clock && div < 16)
div++; 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", dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div); clock, host->max_clk / pre_div / div);
host->mmc->actual_clock = host->max_clk / pre_div / div; host->mmc->actual_clock = host->max_clk / pre_div / div;
...@@ -778,6 +800,10 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -778,6 +800,10 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
u32 val; u32 val;
int ret; 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); esdhc_tuning_block_enable(host, true);
hs400_tuning = host->flags & SDHCI_HS400_TUNING; hs400_tuning = host->flags & SDHCI_HS400_TUNING;
...@@ -908,6 +934,11 @@ static struct soc_device_attribute soc_incorrect_hostver[] = { ...@@ -908,6 +934,11 @@ static struct soc_device_attribute soc_incorrect_hostver[] = {
{ }, { },
}; };
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) static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
{ {
const struct of_device_id *match; const struct of_device_id *match;
...@@ -930,6 +961,11 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) ...@@ -930,6 +961,11 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
else else
esdhc->quirk_incorrect_hostver = false; 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;
match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node); match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node);
if (match) if (match)
esdhc->clk_fixup = match->data; esdhc->clk_fixup = match->data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment