mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-27 15:10:26 +09:00
mmc: fsl_esdhc: support tuning for eMMC HS200
Support tuning process for eMMC HS200 for eSDHC. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
parent
1fdefd1d0d
commit
b1a4247b41
@ -60,7 +60,9 @@ struct fsl_esdhc {
|
||||
uint dmaerrattr; /* DMA error attribute register */
|
||||
char reserved5[4]; /* reserved */
|
||||
uint hostcapblt2; /* Host controller capabilities register 2 */
|
||||
char reserved6[756]; /* reserved */
|
||||
char reserved6[8]; /* reserved */
|
||||
uint tbctl; /* Tuning block control register */
|
||||
char reserved7[744]; /* reserved */
|
||||
uint esdhcctl; /* eSDHC control register */
|
||||
};
|
||||
|
||||
@ -101,7 +103,9 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
|
||||
if (data) {
|
||||
xfertyp |= XFERTYP_DPSEL;
|
||||
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
|
||||
xfertyp |= XFERTYP_DMAEN;
|
||||
if (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK &&
|
||||
cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200)
|
||||
xfertyp |= XFERTYP_DMAEN;
|
||||
#endif
|
||||
if (data->blocks > 1) {
|
||||
xfertyp |= XFERTYP_MSBSEL;
|
||||
@ -380,6 +384,10 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
|
||||
esdhc_write32(®s->cmdarg, cmd->cmdarg);
|
||||
esdhc_write32(®s->xfertyp, xfertyp);
|
||||
|
||||
if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK ||
|
||||
cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200)
|
||||
flags = IRQSTAT_BRR;
|
||||
|
||||
/* Wait for the command to complete */
|
||||
start = get_timer(0);
|
||||
while (!(esdhc_read32(®s->irqstat) & flags)) {
|
||||
@ -439,6 +447,11 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
|
||||
#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
|
||||
esdhc_pio_read_write(priv, data);
|
||||
#else
|
||||
flags = DATA_COMPLETE;
|
||||
if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK ||
|
||||
cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200)
|
||||
flags = IRQSTAT_BRR;
|
||||
|
||||
do {
|
||||
irqstat = esdhc_read32(®s->irqstat);
|
||||
|
||||
@ -451,7 +464,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
|
||||
err = -ECOMM;
|
||||
goto out;
|
||||
}
|
||||
} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
|
||||
} while ((irqstat & flags) != flags);
|
||||
|
||||
/*
|
||||
* Need invalidate the dcache here again to avoid any
|
||||
@ -555,6 +568,19 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
|
||||
esdhc_clock_control(priv, false);
|
||||
|
||||
if (mode == MMC_HS_200)
|
||||
esdhc_clrsetbits32(®s->autoc12err, UHSM_MASK,
|
||||
UHSM_SDR104_HS200);
|
||||
|
||||
esdhc_clock_control(priv, true);
|
||||
}
|
||||
|
||||
static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
@ -570,6 +596,9 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
||||
if (priv->clock != mmc->clock)
|
||||
set_sysctl(priv, mmc, mmc->clock);
|
||||
|
||||
/* Set timing */
|
||||
esdhc_set_timing(priv, mmc->selected_mode);
|
||||
|
||||
/* Set the bus width */
|
||||
esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
|
||||
|
||||
@ -915,6 +944,77 @@ static int fsl_esdhc_reinit(struct udevice *dev)
|
||||
return esdhc_init_common(priv, &plat->mmc);
|
||||
}
|
||||
|
||||
#ifdef MMC_SUPPORTS_TUNING
|
||||
static void esdhc_flush_async_fifo(struct fsl_esdhc_priv *priv)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
u32 time_out;
|
||||
|
||||
esdhc_setbits32(®s->esdhcctl, ESDHCCTL_FAF);
|
||||
|
||||
time_out = 20;
|
||||
while (esdhc_read32(®s->esdhcctl) & ESDHCCTL_FAF) {
|
||||
if (time_out == 0) {
|
||||
printf("fsl_esdhc: Flush asynchronous FIFO timeout.\n");
|
||||
break;
|
||||
}
|
||||
time_out--;
|
||||
mdelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void esdhc_tuning_block_enable(struct fsl_esdhc_priv *priv,
|
||||
bool en)
|
||||
{
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
|
||||
esdhc_clock_control(priv, false);
|
||||
esdhc_flush_async_fifo(priv);
|
||||
if (en)
|
||||
esdhc_setbits32(®s->tbctl, TBCTL_TB_EN);
|
||||
else
|
||||
esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN);
|
||||
esdhc_clock_control(priv, true);
|
||||
}
|
||||
|
||||
static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
|
||||
{
|
||||
struct fsl_esdhc_plat *plat = dev_get_platdata(dev);
|
||||
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
u32 val, irqstaten;
|
||||
int i;
|
||||
|
||||
esdhc_tuning_block_enable(priv, true);
|
||||
esdhc_setbits32(®s->autoc12err, EXECUTE_TUNING);
|
||||
|
||||
irqstaten = esdhc_read32(®s->irqstaten);
|
||||
esdhc_write32(®s->irqstaten, IRQSTATEN_BRR);
|
||||
|
||||
for (i = 0; i < MAX_TUNING_LOOP; i++) {
|
||||
mmc_send_tuning(&plat->mmc, opcode, NULL);
|
||||
mdelay(1);
|
||||
|
||||
val = esdhc_read32(®s->autoc12err);
|
||||
if (!(val & EXECUTE_TUNING)) {
|
||||
if (val & SMPCLKSEL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esdhc_write32(®s->irqstaten, irqstaten);
|
||||
|
||||
if (i != MAX_TUNING_LOOP)
|
||||
return 0;
|
||||
|
||||
printf("fsl_esdhc: tuning failed!\n");
|
||||
esdhc_clrbits32(®s->autoc12err, SMPCLKSEL);
|
||||
esdhc_clrbits32(®s->autoc12err, EXECUTE_TUNING);
|
||||
esdhc_tuning_block_enable(priv, false);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dm_mmc_ops fsl_esdhc_ops = {
|
||||
.get_cd = fsl_esdhc_get_cd,
|
||||
.send_cmd = fsl_esdhc_send_cmd,
|
||||
|
@ -74,8 +74,10 @@
|
||||
#define IRQSTATEN_TC (0x00000002)
|
||||
#define IRQSTATEN_CC (0x00000001)
|
||||
|
||||
/* eSDHC control register */
|
||||
#define ESDHCCTL 0x0002e40c
|
||||
#define ESDHCCTL_PCS (0x00080000)
|
||||
#define ESDHCCTL_FAF (0x00040000)
|
||||
|
||||
#define PRSSTAT 0x0002e024
|
||||
#define PRSSTAT_DAT0 (0x01000000)
|
||||
@ -154,6 +156,12 @@
|
||||
#define BLKATTR_SIZE(x) (x & 0x1fff)
|
||||
#define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */
|
||||
|
||||
/* Auto CMD error status register / system control 2 register */
|
||||
#define EXECUTE_TUNING 0x00400000
|
||||
#define SMPCLKSEL 0x00800000
|
||||
#define UHSM_MASK 0x00070000
|
||||
#define UHSM_SDR104_HS200 0x00030000
|
||||
|
||||
/* Host controller capabilities register */
|
||||
#define HOSTCAPBLT_VS18 0x04000000
|
||||
#define HOSTCAPBLT_VS30 0x02000000
|
||||
@ -162,6 +170,11 @@
|
||||
#define HOSTCAPBLT_DMAS 0x00400000
|
||||
#define HOSTCAPBLT_HSS 0x00200000
|
||||
|
||||
/* Tuning block control register */
|
||||
#define TBCTL_TB_EN 0x00000004
|
||||
|
||||
#define MAX_TUNING_LOOP 40
|
||||
|
||||
struct fsl_esdhc_cfg {
|
||||
phys_addr_t esdhc_base;
|
||||
u32 sdhc_clk;
|
||||
@ -203,10 +216,6 @@ struct fsl_esdhc_cfg {
|
||||
int fsl_esdhc_mmc_init(struct bd_info *bis);
|
||||
int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg);
|
||||
void fdt_fixup_esdhc(void *blob, struct bd_info *bd);
|
||||
#ifdef MMC_SUPPORTS_TUNING
|
||||
static inline int fsl_esdhc_execute_tuning(struct udevice *dev,
|
||||
uint32_t opcode) {return 0; }
|
||||
#endif
|
||||
#else
|
||||
static inline int fsl_esdhc_mmc_init(struct bd_info *bis) { return -ENOSYS; }
|
||||
static inline void fdt_fixup_esdhc(void *blob, struct bd_info *bd) {}
|
||||
|
Loading…
Reference in New Issue
Block a user