diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 149 |
1 files changed, 101 insertions, 48 deletions
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c6e9e6e..e665b5e 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -37,7 +37,6 @@ #include <fdt_support.h> #include <asm/io.h> - DECLARE_GLOBAL_DATA_PTR; struct fsl_esdhc { @@ -102,7 +101,8 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; int timeout; - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; wml_value = data->blocksize/4; @@ -112,24 +112,24 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) wml_value = 0x100000 | wml_value; - out_be32(®s->dsaddr, (u32)data->dest); + esdhc_write32(®s->dsaddr, (u32)data->dest); } else { if (wml_value > 0x80) wml_value = 0x80; - if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + 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; } wml_value = wml_value << 16 | 0x10; - out_be32(®s->dsaddr, (u32)data->src); + esdhc_write32(®s->dsaddr, (u32)data->src); } - out_be32(®s->wml, wml_value); + esdhc_write32(®s->wml, wml_value); - out_be32(®s->blkattr, data->blocks << 16 | data->blocksize); + esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); /* Calculate the timeout period for data transactions */ - timeout = __ilog2(mmc->tran_speed/10); + timeout = fls(mmc->tran_speed/10) - 1; timeout -= 13; if (timeout > 14) @@ -138,7 +138,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) if (timeout < 0) timeout = 0; - clrsetbits_be32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; } @@ -153,17 +153,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; uint irqstat; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; - out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1); sync(); /* Wait for the bus to be idle */ - while ((in_be32(®s->prsstat) & PRSSTAT_CICHB) || - (in_be32(®s->prsstat) & PRSSTAT_CIDHB)); + while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || + (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) + ; - while (in_be32(®s->prsstat) & PRSSTAT_DLA); + while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) + ; /* Wait at least 8 SD clock cycles before the next command */ /* @@ -185,14 +188,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) xfertyp = esdhc_xfertyp(cmd, data); /* Send the command */ - out_be32(®s->cmdarg, cmd->cmdarg); - out_be32(®s->xfertyp, xfertyp); + esdhc_write32(®s->cmdarg, cmd->cmdarg); + esdhc_write32(®s->xfertyp, xfertyp); /* Wait for the command to complete */ - while (!(in_be32(®s->irqstat) & IRQSTAT_CC)); + while (!(esdhc_read32(®s->irqstat) & IRQSTAT_CC)) + ; - irqstat = in_be32(®s->irqstat); - out_be32(®s->irqstat, irqstat); + irqstat = esdhc_read32(®s->irqstat); + esdhc_write32(®s->irqstat, irqstat); if (irqstat & CMD_ERR) return COMM_ERR; @@ -204,21 +208,21 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; - cmdrsp3 = in_be32(®s->cmdrsp3); - cmdrsp2 = in_be32(®s->cmdrsp2); - cmdrsp1 = in_be32(®s->cmdrsp1); - cmdrsp0 = in_be32(®s->cmdrsp0); + cmdrsp3 = esdhc_read32(®s->cmdrsp3); + cmdrsp2 = esdhc_read32(®s->cmdrsp2); + cmdrsp1 = esdhc_read32(®s->cmdrsp1); + cmdrsp0 = esdhc_read32(®s->cmdrsp0); cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); cmd->response[3] = (cmdrsp0 << 8); } else - cmd->response[0] = in_be32(®s->cmdrsp0); + cmd->response[0] = esdhc_read32(®s->cmdrsp0); /* Wait until all of the blocks are transferred */ if (data) { do { - irqstat = in_be32(®s->irqstat); + irqstat = esdhc_read32(®s->irqstat); if (irqstat & DATA_ERR) return COMM_ERR; @@ -226,10 +230,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (irqstat & IRQSTAT_DTOE) return TIMEOUT; } while (!(irqstat & IRQSTAT_TC) && - (in_be32(®s->prsstat) & PRSSTAT_DLA)); + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); } - out_be32(®s->irqstat, -1); + esdhc_write32(®s->irqstat, -1); return 0; } @@ -238,9 +242,13 @@ void set_sysctl(struct mmc *mmc, uint clock) { int sdhc_clk = gd->sdhc_clk; int div, pre_div; - volatile struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint clk; + if (clock < mmc->f_min) + clock = mmc->f_min; + if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) if ((sdhc_clk / pre_div) <= (clock * 16)) @@ -257,67 +265,105 @@ void set_sysctl(struct mmc *mmc, uint clock) clk = (pre_div << 8) | (div << 4); - clrsetbits_be32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); + /* On imx the clock must be stopped before changing frequency */ + if (cfg->clk_enable) + esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); + + esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); udelay(10000); - setbits_be32(®s->sysctl, SYSCTL_PEREN); + clk = SYSCTL_PEREN; + /* On imx systems the clock must be explicitely enabled */ + if (cfg->clk_enable) + clk |= SYSCTL_CKEN; + + esdhc_setbits32(®s->sysctl, clk); } static void esdhc_set_ios(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; /* Set the clock speed */ set_sysctl(mmc, mmc->clock); /* Set the bus width */ - clrbits_be32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); + esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); if (mmc->bus_width == 4) - setbits_be32(®s->proctl, PROCTL_DTW_4); + esdhc_setbits32(®s->proctl, PROCTL_DTW_4); else if (mmc->bus_width == 8) - setbits_be32(®s->proctl, PROCTL_DTW_8); + esdhc_setbits32(®s->proctl, PROCTL_DTW_8); + } static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc *regs = mmc->priv; + 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; /* Enable cache snooping */ - out_be32(®s->scr, 0x00000040); + if (cfg && !cfg->no_snoop) + esdhc_write32(®s->scr, 0x00000040); + + /* Reset the entire host controller */ + esdhc_write32(®s->sysctl, SYSCTL_RSTA); + + /* Wait until the controller is available */ + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) + udelay(1000); - out_be32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); /* Set the initial clock speed */ set_sysctl(mmc, 400000); /* Disable the BRR and BWR bits in IRQSTAT */ - clrbits_be32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); + esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); /* Put the PROCTL reg back to the default */ - out_be32(®s->proctl, PROCTL_INIT); + esdhc_write32(®s->proctl, PROCTL_INIT); - while (!(in_be32(®s->prsstat) & PRSSTAT_CINS) && --timeout) - udelay(1000); + /* Set timout to the maximum value */ + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); - if (timeout <= 0) - return NO_CARD_ERR; + /* 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; + } + + return ret; } -static int esdhc_initialize(bd_t *bis) +int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { - struct fsl_esdhc *regs = (struct fsl_esdhc *)CONFIG_SYS_FSL_ESDHC_ADDR; + struct fsl_esdhc *regs; struct mmc *mmc; u32 caps; + if (!cfg) + return -1; + mmc = malloc(sizeof(struct mmc)); sprintf(mmc->name, "FSL_ESDHC"); - mmc->priv = regs; + regs = (struct fsl_esdhc *)cfg->esdhc_base; + + mmc->priv = cfg; mmc->send_cmd = esdhc_send_cmd; mmc->set_ios = esdhc_set_ios; mmc->init = esdhc_init; @@ -346,9 +392,15 @@ static int esdhc_initialize(bd_t *bis) int fsl_esdhc_mmc_init(bd_t *bis) { - return esdhc_initialize(bis); + struct fsl_esdhc_cfg *cfg; + + cfg = malloc(sizeof(struct fsl_esdhc_cfg)); + memset(cfg, 0, sizeof(struct fsl_esdhc_cfg)); + cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; + return fsl_esdhc_initialize(bis, cfg); } +#ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; @@ -365,3 +417,4 @@ out: do_fixup_by_compat(blob, compat, "status", status, strlen(status) + 1, 1); } +#endif |