X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=07370b57291daaded12e4da93edad61965f424f7;hb=6bc337fb13003a9a949dfb2713e308fb97faae8a;hp=40b136c17643cfce70a1740b23d06dc3aa936906;hpb=030955c2cad511e678b3804c7de650db6920de4e;p=oweals%2Fu-boot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 40b136c176..07370b5729 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -1,5 +1,5 @@ /* - * Copyright 2007,2010 Freescale Semiconductor, Inc + * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc * Andy Fleming * * Based vaguely on the pxa mmc code: @@ -58,7 +58,8 @@ struct fsl_esdhc { uint autoc12err; uint hostcapblt; uint wml; - char reserved1[8]; + uint mixctrl; + char reserved1[4]; uint fevt; char reserved2[168]; uint hostver; @@ -79,6 +80,9 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; xfertyp |= XFERTYP_BCEN; +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 + xfertyp |= XFERTYP_AC12EN; +#endif } if (data->flags & MMC_DATA_READ) @@ -96,6 +100,10 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= XFERTYP_RSPTYP_48; +#ifdef CONFIG_MX53 + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + xfertyp |= XFERTYP_CMDTYP_ABORT; +#endif return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } @@ -106,7 +114,8 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) static void esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint blocks; char *buffer; uint databuf; @@ -175,14 +184,14 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) wml_value = data->blocksize/4; if (data->flags & MMC_DATA_READ) { - if (wml_value > 0x10) - wml_value = 0x10; + if (wml_value > WML_RD_WML_MAX) + wml_value = WML_RD_WML_MAX_VAL; esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); esdhc_write32(®s->dsaddr, (u32)data->dest); } else { - if (wml_value > 0x80) - wml_value = 0x80; + if (wml_value > WML_WR_WML_MAX) + wml_value = WML_WR_WML_MAX_VAL; if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); return TIMEOUT; @@ -207,7 +216,21 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); /* Calculate the timeout period for data transactions */ - timeout = fls(mmc->tran_speed/10) - 1; + /* + * 1)Timeout period = (2^(timeout+13)) SD Clock cycles + * 2)Timeout period should be minimum 0.250sec as per SD Card spec + * So, Number of SD Clock cycles for 0.25sec should be minimum + * (SD Clock/sec * 0.25 sec) SD Clock cycles + * = (mmc->tran_speed * 1/4) SD Clock cycles + * As 1) >= 2) + * => (2^(timeout+13)) >= mmc->tran_speed * 1/4 + * Taking log2 both the sides + * => timeout + 13 >= log2(mmc->tran_speed/4) + * Rounding up to next power of 2 + * => timeout + 13 = log2(mmc->tran_speed/4) + 1 + * => timeout + 13 = fls(mmc->tran_speed/4) + */ + timeout = fls(mmc->tran_speed/4); timeout -= 13; if (timeout > 14) @@ -216,6 +239,11 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) if (timeout < 0) timeout = 0; +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 + if ((timeout == 4) || (timeout == 8) || (timeout == 12)) + timeout++; +#endif + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; @@ -234,6 +262,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + return 0; +#endif + esdhc_write32(®s->irqstat, -1); sync(); @@ -267,21 +300,63 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) /* Send the command */ esdhc_write32(®s->cmdarg, cmd->cmdarg); +#if defined(CONFIG_FSL_USDHC) + esdhc_write32(®s->mixctrl, + (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F)); + esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); +#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))) ; 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; @@ -305,11 +380,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) do { irqstat = esdhc_read32(®s->irqstat); - if (irqstat & DATA_ERR) - return COMM_ERR; - if (irqstat & IRQSTAT_DTOE) return TIMEOUT; + + if (irqstat & DATA_ERR) + return COMM_ERR; } while (!(irqstat & IRQSTAT_TC) && (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); #endif @@ -381,8 +456,6 @@ static int esdhc_init(struct mmc *mmc) struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; - int ret = 0; - u8 card_absent; /* Reset the entire host controller */ esdhc_write32(®s->sysctl, SYSCTL_RSTA); @@ -409,21 +482,19 @@ static int esdhc_init(struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); - /* Check if there is a callback for detecting the card */ - if (board_mmc_getcd(&card_absent, mmc)) { - timeout = 1000; - while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && - --timeout) - udelay(1000); + return 0; +} - if (timeout <= 0) - ret = NO_CARD_ERR; - } else { - if (card_absent) - ret = NO_CARD_ERR; - } +static int esdhc_getcd(struct mmc *mmc) +{ + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + int timeout = 1000; + + while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) + udelay(1000); - return ret; + return timeout > 0; } static void esdhc_reset(struct fsl_esdhc *regs) @@ -451,7 +522,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) mmc = malloc(sizeof(struct mmc)); - sprintf(mmc->name, "FSL_ESDHC"); + sprintf(mmc->name, "FSL_SDHC"); regs = (struct fsl_esdhc *)cfg->esdhc_base; /* First reset the eSDHC controller */ @@ -461,9 +532,15 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; mmc->init = esdhc_init; + mmc->getcd = esdhc_getcd; voltage_caps = 0; caps = regs->hostcapblt; + +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 + caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | + ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); +#endif if (caps & ESDHC_HOSTCAPBLT_VS18) voltage_caps |= MMC_VDD_165_195; if (caps & ESDHC_HOSTCAPBLT_VS30) @@ -489,6 +566,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) mmc->f_min = 400000; mmc->f_max = MIN(gd->sdhc_clk, 52000000); + mmc->b_max = 0; mmc_register(mmc); return 0; @@ -508,17 +586,19 @@ int fsl_esdhc_mmc_init(bd_t *bis) void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; - const char *status = "okay"; +#ifdef CONFIG_FSL_ESDHC_PIN_MUX if (!hwconfig("esdhc")) { - status = "disabled"; - goto out; + do_fixup_by_compat(blob, compat, "status", "disabled", + 8 + 1, 1); + return; } +#endif do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->sdhc_clk, 1); -out: - do_fixup_by_compat(blob, compat, "status", status, - strlen(status) + 1, 1); + + do_fixup_by_compat(blob, compat, "status", "okay", + 4 + 1, 1); } #endif