X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=e93e38ac4346fdebe203621aa5eac95e9355e660;hb=6acc7c3cbc05873d62118640cf964e9c9665804c;hp=a2f35e3e99159dc0481737a0bb4d1f1e55fc0da6;hpb=670c24f6f32c8320cbb950e19e75fa8cdc8af88c;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index a2f35e3..e93e38a 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -68,7 +68,7 @@ struct fsl_esdhc { }; /* Return the XFERTYP flags for a given command and data packet */ -uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) +static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp = 0; @@ -190,6 +190,10 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); esdhc_write32(®s->dsaddr, (u32)data->dest); } else { + flush_dcache_range((ulong)data->src, + (ulong)data->src+data->blocks + *data->blocksize); + if (wml_value > WML_WR_WML_MAX) wml_value = WML_WR_WML_MAX_VAL; if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { @@ -249,7 +253,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) return 0; } - +static void check_and_invalidate_dcache_range + (struct mmc_cmd *cmd, + struct mmc_data *data) { + unsigned start = (unsigned)data->dest ; + unsigned size = roundup(ARCH_DMA_MINALIGN, + data->blocks*data->blocksize); + unsigned end = start+size ; + invalidate_dcache_range(start, end); +} /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. @@ -307,19 +319,59 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) #else esdhc_write32(®s->xfertyp, xfertyp); #endif + + /* Mask all irqs */ + esdhc_write32(®s->irqsigen, 0); + /* Wait for the command to complete */ - while (!(esdhc_read32(®s->irqstat) & IRQSTAT_CC)) + while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) ; + if (data && (data->flags & MMC_DATA_READ)) + check_and_invalidate_dcache_range(cmd, data); + irqstat = esdhc_read32(®s->irqstat); esdhc_write32(®s->irqstat, irqstat); + /* Reset CMD and DATA portions on error */ + if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) { + esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | + SYSCTL_RSTC); + while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) + ; + + if (data) { + esdhc_write32(®s->sysctl, + esdhc_read32(®s->sysctl) | + SYSCTL_RSTD); + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) + ; + } + } + if (irqstat & CMD_ERR) return COMM_ERR; if (irqstat & IRQSTAT_CTOE) return TIMEOUT; + /* Workaround for ESDHC errata ENGcm03648 */ + if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { + int timeout = 2500; + + /* Poll on DATA0 line for cmd with busy signal for 250 ms */ + while (timeout > 0 && !(esdhc_read32(®s->prsstat) & + PRSSTAT_DAT0)) { + udelay(100); + timeout--; + } + + if (timeout <= 0) { + printf("Timeout waiting for DAT0 to go high!\n"); + return TIMEOUT; + } + } + /* Copy the response to the response buffer */ if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; @@ -358,12 +410,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) return 0; } -void set_sysctl(struct mmc *mmc, uint clock) +static void set_sysctl(struct mmc *mmc, uint clock) { - int sdhc_clk = gd->sdhc_clk; int div, pre_div; struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + int sdhc_clk = cfg->sdhc_clk; uint clk; if (clock < mmc->f_min) @@ -427,9 +479,10 @@ static int esdhc_init(struct mmc *mmc) while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) udelay(1000); +#ifndef ARCH_MXC /* Enable cache snooping */ - if (cfg && !cfg->no_snoop) - esdhc_write32(®s->scr, 0x00000040); + esdhc_write32(®s->scr, 0x00000040); +#endif esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); @@ -491,6 +544,9 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) /* First reset the eSDHC controller */ esdhc_reset(regs); + esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN + | SYSCTL_IPGEN | SYSCTL_CKEN); + mmc->priv = cfg; mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; @@ -542,6 +598,7 @@ int fsl_esdhc_mmc_init(bd_t *bis) cfg = malloc(sizeof(struct fsl_esdhc_cfg)); memset(cfg, 0, sizeof(struct fsl_esdhc_cfg)); cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + cfg->sdhc_clk = gd->sdhc_clk; return fsl_esdhc_initialize(bis, cfg); }