diff options
Diffstat (limited to 'drivers/mmc/fsl_esdhc.c')
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c55eb28217..c5e270dd57 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -54,19 +54,21 @@ struct fsl_esdhc { uint fevt; /* Force event register */ uint admaes; /* ADMA error status register */ uint adsaddr; /* ADMA system address register */ - char reserved2[160]; /* reserved */ + char reserved2[100]; /* reserved */ + uint vendorspec; /* Vendor Specific register */ + char reserved3[59]; /* reserved */ uint hostver; /* Host controller version register */ - char reserved3[4]; /* reserved */ - uint dmaerraddr; /* DMA error address register */ char reserved4[4]; /* reserved */ - uint dmaerrattr; /* DMA error attribute register */ + uint dmaerraddr; /* DMA error address register */ char reserved5[4]; /* reserved */ + uint dmaerrattr; /* DMA error attribute register */ + char reserved6[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ - char reserved6[8]; /* reserved */ + char reserved7[8]; /* reserved */ uint tcr; /* Tuning control register */ - char reserved7[28]; /* reserved */ + char reserved8[28]; /* reserved */ uint sddirctl; /* SD direction control register */ - char reserved8[712]; /* reserved */ + char reserved9[712]; /* reserved */ uint scr; /* eSDHC control register */ }; @@ -319,7 +321,8 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) esdhc_write32(®s->cmdarg, cmd->cmdarg); #if defined(CONFIG_FSL_USDHC) esdhc_write32(®s->mixctrl, - (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F)); + (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F) + | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); #else esdhc_write32(®s->xfertyp, xfertyp); @@ -341,6 +344,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) goto out; } + /* Switch voltage to 1.8V if CMD11 succeeded */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); + + printf("Run CMD11 1.8V switch\n"); + /* Sleep for 5 ms - max time for card to switch to 1.8V */ + udelay(5000); + } + /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { int timeout = 2500; @@ -413,6 +425,10 @@ out: while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) ; } + + /* If this was CMD11, then notify that power cycle is needed */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) + printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); } esdhc_write32(®s->irqstat, -1); @@ -442,7 +458,7 @@ static void set_sysctl(struct mmc *mmc, uint clock) if ((sdhc_clk / (div * pre_div)) <= clock) break; - pre_div >>= 1; + pre_div >>= mmc->ddr_mode ? 2 : 1; div -= 1; clk = (pre_div << 8) | (div << 4); @@ -508,6 +524,10 @@ static int esdhc_init(struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); +#ifdef CONFIG_SYS_FSL_ESDHC_FORCE_VSELECT + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); +#endif + return 0; } @@ -601,6 +621,9 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) } cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; +#ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE + cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; +#endif if (cfg->max_bus_width > 0) { if (cfg->max_bus_width < 8) |