aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMichael Walle <michael@walle.cc>2021-03-17 15:01:36 +0100
committerPeng Fan <peng.fan@nxp.com>2021-04-06 18:35:55 +0800
commitbd7b8505f2c0c87785488a040ff7d2711465b401 (patch)
tree18339f5edd994fa13dee06a4b2bc2aa50ad97209 /drivers/mmc
parente9978b17cd7bc19f0459b2829756f1d891382bf9 (diff)
downloadu-boot-bd7b8505f2c0c87785488a040ff7d2711465b401.zip
u-boot-bd7b8505f2c0c87785488a040ff7d2711465b401.tar.gz
u-boot-bd7b8505f2c0c87785488a040ff7d2711465b401.tar.bz2
mmc: fsl_esdhc: add workaround for erratum A-011334
LS1028A SoCs are restricted in what divider values are allowed for HS400 mode. This is basically a port from the corresponding linux driver. Signed-off-by: Michael Walle <michael@walle.cc>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig3
-rw-r--r--drivers/mmc/fsl_esdhc.c25
2 files changed, 27 insertions, 1 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c34fce3..b0ff92b 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -813,3 +813,6 @@ config SYS_FSL_ERRATUM_ESDHC135
config SYS_FSL_ERRATUM_ESDHC_A001
bool
+
+config SYS_FSL_ERRATUM_A011334
+ bool
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 6014e1c..09ea1a9 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -518,6 +518,24 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
while (sdhc_clk / (div * pre_div) > clock && div < 16)
div++;
+ if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) &&
+ clock == 200000000 && mmc->selected_mode == MMC_HS_400) {
+ u32 div_ratio = pre_div * div;
+
+ if (div_ratio <= 4) {
+ pre_div = 4;
+ div = 1;
+ } else if (div_ratio <= 8) {
+ pre_div = 4;
+ div = 2;
+ } else if (div_ratio <= 12) {
+ pre_div = 4;
+ div = 3;
+ } else {
+ printf("unsupported clock division.\n");
+ }
+ }
+
mmc->clock = sdhc_clk / pre_div / div;
priv->clock = mmc->clock;
@@ -1063,9 +1081,14 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
struct fsl_esdhc_plat *plat = dev_get_plat(dev);
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
struct fsl_esdhc *regs = priv->esdhc_regs;
+ struct mmc *mmc = &plat->mmc;
u32 val, irqstaten;
int i;
+ if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) &&
+ plat->mmc.hs400_tuning)
+ set_sysctl(priv, mmc, mmc->clock);
+
esdhc_tuning_block_enable(priv, true);
esdhc_setbits32(&regs->autoc12err, EXECUTE_TUNING);
@@ -1073,7 +1096,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
esdhc_write32(&regs->irqstaten, IRQSTATEN_BRR);
for (i = 0; i < MAX_TUNING_LOOP; i++) {
- mmc_send_tuning(&plat->mmc, opcode, NULL);
+ mmc_send_tuning(mmc, opcode, NULL);
mdelay(1);
val = esdhc_read32(&regs->autoc12err);