mmc: fsl_esdhc: make sure delay chain locked for HS400
For eMMC HS400 mode, the DLL reset is a required step for mmc rescan. This step has not been documented in reference manual, but the RM will be fixed sooner or later. In previous commit to support eMMC HS400,db8f936mmc: fsl_esdhc: support eMMC HS400 mode the steps to configure DLL could be found in commit message, 13. Set DLLCFG0[DLL_ENABLE] and DLLCFG0[DLL_FREQ_SEL]. 14. Wait for delay chain to lock. these would be fixed as, 13. Set DLLCFG0[DLL_ENABLE] and DLLCFG0[DLL_FREQ_SEL]. 13.1 Write DLLCFG0[DLL_RESET] to 1 and wait for 1us, then write DLLCFG0[DLL_RESET] 14. Wait for delay chain to lock. This patch is to add the step of DLL reset, and make sure delay chain locked for HS400. Fixes:db8f93672b("mmc: fsl_esdhc: support eMMC HS400 mode") Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
This commit is contained in:
parent
263ddfc345
commit
8ee802f899
|
|
@ -70,7 +70,9 @@ struct fsl_esdhc {
|
|||
uint sdtimingctl; /* SD timing control register */
|
||||
char reserved8[20]; /* reserved */
|
||||
uint dllcfg0; /* DLL config 0 register */
|
||||
char reserved9[680]; /* reserved */
|
||||
char reserved9[12]; /* reserved */
|
||||
uint dllstat0; /* DLL status 0 register */
|
||||
char reserved10[664];/* reserved */
|
||||
uint esdhcctl; /* eSDHC control register */
|
||||
};
|
||||
|
||||
|
|
@ -617,9 +619,11 @@ static void esdhc_exit_hs400(struct fsl_esdhc_priv *priv)
|
|||
esdhc_tuning_block_enable(priv, false);
|
||||
}
|
||||
|
||||
static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
||||
static int esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
ulong start;
|
||||
u32 val;
|
||||
|
||||
/* Exit HS400 mode before setting any other mode */
|
||||
if (esdhc_read32(®s->tbctl) & HS400_MODE &&
|
||||
|
|
@ -640,17 +644,33 @@ static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
|||
esdhc_setbits32(®s->dllcfg0, DLL_FREQ_SEL);
|
||||
|
||||
esdhc_setbits32(®s->dllcfg0, DLL_ENABLE);
|
||||
|
||||
esdhc_setbits32(®s->dllcfg0, DLL_RESET);
|
||||
udelay(1);
|
||||
esdhc_clrbits32(®s->dllcfg0, DLL_RESET);
|
||||
|
||||
start = get_timer(0);
|
||||
val = DLL_STS_SLV_LOCK;
|
||||
while (!(esdhc_read32(®s->dllstat0) & val)) {
|
||||
if (get_timer(start) > 1000) {
|
||||
printf("fsl_esdhc: delay chain lock timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST);
|
||||
|
||||
esdhc_clock_control(priv, false);
|
||||
esdhc_flush_async_fifo(priv);
|
||||
}
|
||||
esdhc_clock_control(priv, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
int ret;
|
||||
|
||||
if (priv->is_sdhc_per_clk) {
|
||||
/* Select to use peripheral clock */
|
||||
|
|
@ -667,7 +687,9 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
|||
set_sysctl(priv, mmc, mmc->clock);
|
||||
|
||||
/* Set timing */
|
||||
esdhc_set_timing(priv, mmc->selected_mode);
|
||||
ret = esdhc_set_timing(priv, mmc->selected_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set the bus width */
|
||||
esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
|
||||
|
|
|
|||
|
|
@ -187,8 +187,12 @@
|
|||
|
||||
/* DLL config 0 register */
|
||||
#define DLL_ENABLE 0x80000000
|
||||
#define DLL_RESET 0x40000000
|
||||
#define DLL_FREQ_SEL 0x08000000
|
||||
|
||||
/* DLL status 0 register */
|
||||
#define DLL_STS_SLV_LOCK 0x08000000
|
||||
|
||||
#define MAX_TUNING_LOOP 40
|
||||
|
||||
#define HOSTVER_VENDOR(x) (((x) >> 8) & 0xff)
|
||||
|
|
|
|||
Loading…
Reference in New Issue