X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=ea5f4bf6c0e2fdad333019576a9732e6690f515a;hb=25503443eee0c539e3d566d5aa59410562599f18;hp=10ec216d2c5a9c844955c324089839221068ba84;hpb=8b06460e5518eeec449298c91fb1424b36c9b305;p=oweals%2Fu-boot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 10ec216d2c..ea5f4bf6c0 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -105,11 +105,9 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= XFERTYP_RSPTYP_48; -#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || \ - defined(CONFIG_LS102XA) || defined(CONFIG_LS2085A) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; -#endif + return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } @@ -184,7 +182,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) int timeout; struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; -#ifdef CONFIG_LS2085A +#ifdef CONFIG_FSL_LAYERSCAPE dma_addr_t addr; #endif uint wml_value; @@ -197,7 +195,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#ifdef CONFIG_LS2085A +#ifdef CONFIG_FSL_LAYERSCAPE addr = virt_to_phys((void *)(data->dest)); if (upper_32_bits(addr)) printf("Error found for upper 32 bits\n"); @@ -223,7 +221,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#ifdef CONFIG_LS2085A +#ifdef CONFIG_FSL_LAYERSCAPE addr = virt_to_phys((void *)(data->src)); if (upper_32_bits(addr)) printf("Error found for upper 32 bits\n"); @@ -251,8 +249,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) * Rounding up to next power of 2 * => timeout + 13 = log2(mmc->clock/4) + 1 * => timeout + 13 = fls(mmc->clock/4) + * + * However, the MMC spec "It is strongly recommended for hosts to + * implement more than 500ms timeout value even if the card + * indicates the 250ms maximum busy length." Even the previous + * value of 300ms is known to be insufficient for some cards. + * So, we use + * => timeout + 13 = fls(mmc->clock/2) */ - timeout = fls(mmc->clock/4); + timeout = fls(mmc->clock/2); timeout -= 13; if (timeout > 14) @@ -274,11 +279,10 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) return 0; } -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO static void check_and_invalidate_dcache_range (struct mmc_cmd *cmd, struct mmc_data *data) { -#ifdef CONFIG_LS2085A +#ifdef CONFIG_FSL_LAYERSCAPE unsigned start = 0; #else unsigned start = (unsigned)data->dest ; @@ -286,7 +290,7 @@ static void check_and_invalidate_dcache_range unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); unsigned end = start+size ; -#ifdef CONFIG_LS2085A +#ifdef CONFIG_FSL_LAYERSCAPE dma_addr_t addr; addr = virt_to_phys((void *)(data->dest)); @@ -297,7 +301,6 @@ static void check_and_invalidate_dcache_range #endif invalidate_dcache_range(start, end); } -#endif /* * Sends a command out on the bus. Takes the mmc pointer, @@ -341,6 +344,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) err = esdhc_setup_data(mmc, data); if(err) return err; + + if (data->flags & MMC_DATA_READ) + check_and_invalidate_dcache_range(cmd, data); } /* Figure out the transfer arguments */ @@ -387,9 +393,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - int timeout = 2500; + int timeout = 6000; - /* Poll on DATA0 line for cmd with busy signal for 250 ms */ + /* Poll on DATA0 line for cmd with busy signal for 600 ms */ while (timeout > 0 && !(esdhc_read32(®s->prsstat) & PRSSTAT_DAT0)) { udelay(100); @@ -437,6 +443,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) } } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); + /* + * Need invalidate the dcache here again to avoid any + * cache-fill during the DMA operations such as the + * speculative pre-fetching etc. + */ if (data->flags & MMC_DATA_READ) check_and_invalidate_dcache_range(cmd, data); #endif @@ -495,22 +506,65 @@ static void set_sysctl(struct mmc *mmc, uint clock) clk = (pre_div << 8) | (div << 4); +#ifdef CONFIG_FSL_USDHC + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); +#else esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); +#endif esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); udelay(10000); - clk = SYSCTL_PEREN | SYSCTL_CKEN; +#ifdef CONFIG_FSL_USDHC + esdhc_clrbits32(®s->sysctl, SYSCTL_RSTA); +#else + esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); +#endif - esdhc_setbits32(®s->sysctl, clk); } +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK +static void esdhc_clock_control(struct mmc *mmc, bool enable) +{ + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + u32 value; + u32 time_out; + + value = esdhc_read32(®s->sysctl); + + if (enable) + value |= SYSCTL_CKEN; + else + value &= ~SYSCTL_CKEN; + + esdhc_write32(®s->sysctl, value); + + time_out = 20; + value = PRSSTAT_SDSTB; + while (!(esdhc_read32(®s->prsstat) & value)) { + if (time_out == 0) { + printf("fsl_esdhc: Internal clock never stabilised.\n"); + break; + } + time_out--; + mdelay(1); + } +} +#endif + static void esdhc_set_ios(struct mmc *mmc) { struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK + /* Select to use peripheral clock */ + esdhc_clock_control(mmc, false); + esdhc_setbits32(®s->scr, ESDHCCTL_PCS); + esdhc_clock_control(mmc, true); +#endif /* Set the clock speed */ set_sysctl(mmc, mmc->clock); @@ -542,7 +596,9 @@ static int esdhc_init(struct mmc *mmc) esdhc_write32(®s->scr, 0x00000040); #endif +#ifndef CONFIG_FSL_USDHC esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); +#endif /* Set the initial clock speed */ mmc_set_clock(mmc, 400000); @@ -614,8 +670,10 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) /* First reset the eSDHC controller */ esdhc_reset(regs); +#ifndef CONFIG_FSL_USDHC esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN | SYSCTL_CKEN); +#endif writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); memset(&cfg->cfg, 0, sizeof(cfg->cfg)); @@ -652,7 +710,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) return -1; } - cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; + cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; #ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; #endif @@ -694,6 +752,45 @@ int fsl_esdhc_mmc_init(bd_t *bis) return fsl_esdhc_initialize(bis, cfg); } +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT +void mmc_adapter_card_type_ident(void) +{ + u8 card_id; + u8 value; + + card_id = QIXIS_READ(present) & QIXIS_SDID_MASK; + gd->arch.sdhc_adapter = card_id; + + switch (card_id) { + case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45: + value = QIXIS_READ(brdcfg[5]); + value |= (QIXIS_DAT4 | QIXIS_DAT5_6_7); + QIXIS_WRITE(brdcfg[5], value); + break; + case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY: + value = QIXIS_READ(pwr_ctl[1]); + value |= QIXIS_EVDD_BY_SDHC_VS; + QIXIS_WRITE(pwr_ctl[1], value); + break; + case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44: + value = QIXIS_READ(brdcfg[5]); + value |= (QIXIS_SDCLKIN | QIXIS_SDCLKOUT); + QIXIS_WRITE(brdcfg[5], value); + break; + case QIXIS_ESDHC_ADAPTER_TYPE_RSV: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_MMC: + break; + case QIXIS_ESDHC_ADAPTER_TYPE_SD: + break; + case QIXIS_ESDHC_NO_ADAPTER: + break; + default: + break; + } +} +#endif + #ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { @@ -707,9 +804,17 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd) } #endif +#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK + do_fixup_by_compat_u32(blob, compat, "peripheral-frequency", + gd->arch.sdhc_clk, 1); +#else do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->arch.sdhc_clk, 1); - +#endif +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT + do_fixup_by_compat_u32(blob, compat, "adapter-type", + (u32)(gd->arch.sdhc_adapter), 1); +#endif do_fixup_by_compat(blob, compat, "status", "okay", 4 + 1, 1); }