X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=ea5f4bf6c0e2fdad333019576a9732e6690f515a;hb=25503443eee0c539e3d566d5aa59410562599f18;hp=c5e270dd57df6ba67b4a4c71ff08b9d7705d375e;hpb=b79dadf846e5e140e261bbfa4decd024357702d7;p=oweals%2Fu-boot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c5e270dd57..ea5f4bf6c0 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -56,7 +56,7 @@ struct fsl_esdhc { uint adsaddr; /* ADMA system address register */ char reserved2[100]; /* reserved */ uint vendorspec; /* Vendor Specific register */ - char reserved3[59]; /* reserved */ + char reserved3[56]; /* reserved */ uint hostver; /* Host controller version register */ char reserved4[4]; /* reserved */ uint dmaerraddr; /* DMA error address register */ @@ -105,10 +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) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; -#endif + return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } @@ -183,7 +182,9 @@ 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_FSL_LAYERSCAPE + dma_addr_t addr; +#endif uint wml_value; wml_value = data->blocksize/4; @@ -194,7 +195,15 @@ 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_FSL_LAYERSCAPE + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->dest); +#endif #endif } else { #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO @@ -212,7 +221,15 @@ 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_FSL_LAYERSCAPE + addr = virt_to_phys((void *)(data->src)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->src); +#endif #endif } @@ -232,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) @@ -255,17 +279,28 @@ 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_FSL_LAYERSCAPE + unsigned start = 0; +#else unsigned start = (unsigned)data->dest ; +#endif unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); unsigned end = start+size ; +#ifdef CONFIG_FSL_LAYERSCAPE + dma_addr_t addr; + + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + start = lower_32_bits(addr); +#endif invalidate_dcache_range(start, end); } -#endif /* * Sends a command out on the bus. Takes the mmc pointer, @@ -309,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 */ @@ -355,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); @@ -405,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 @@ -463,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); @@ -510,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); @@ -582,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)); @@ -620,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 @@ -662,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) { @@ -675,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); }