X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=c5e270dd57df6ba67b4a4c71ff08b9d7705d375e;hb=b9cb64825b5e6efeb715abd8b48d9b12f98973e9;hp=a9fe911c8b313340a5a049ac1025464d403999f4;hpb=511948b2cb1105fbec3e0f4cfb215e266860ae71;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index a9fe911..c5e270d 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -23,6 +23,13 @@ DECLARE_GLOBAL_DATA_PTR; +#define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ + IRQSTATEN_CINT | \ + IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ + IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ + IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ + IRQSTATEN_DINT) + struct fsl_esdhc { uint dsaddr; /* SDMA system address register */ uint blkattr; /* Block attributes register */ @@ -47,19 +54,21 @@ struct fsl_esdhc { uint fevt; /* Force event register */ uint admaes; /* ADMA error status register */ uint adsaddr; /* ADMA system address register */ - char reserved2[160]; /* reserved */ + char reserved2[100]; /* reserved */ + uint vendorspec; /* Vendor Specific register */ + char reserved3[59]; /* reserved */ uint hostver; /* Host controller version register */ - char reserved3[4]; /* reserved */ - uint dmaerraddr; /* DMA error address register */ char reserved4[4]; /* reserved */ - uint dmaerrattr; /* DMA error attribute register */ + uint dmaerraddr; /* DMA error address register */ char reserved5[4]; /* reserved */ + uint dmaerrattr; /* DMA error attribute register */ + char reserved6[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ - char reserved6[8]; /* reserved */ + char reserved7[8]; /* reserved */ uint tcr; /* Tuning control register */ - char reserved7[28]; /* reserved */ + char reserved8[28]; /* reserved */ uint sddirctl; /* SD direction control register */ - char reserved8[712]; /* reserved */ + char reserved9[712]; /* reserved */ uint scr; /* eSDHC control register */ }; @@ -96,7 +105,7 @@ 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_T4240QDS) +#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || defined(CONFIG_LS102XA) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; #endif @@ -172,9 +181,9 @@ esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { int timeout; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO + uint wml_value; wml_value = data->blocksize/4; @@ -184,12 +193,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) wml_value = WML_RD_WML_MAX_VAL; esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_write32(®s->dsaddr, (u32)data->dest); +#endif } else { +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO flush_dcache_range((ulong)data->src, (ulong)data->src+data->blocks *data->blocksize); - +#endif if (wml_value > WML_WR_WML_MAX) wml_value = WML_WR_WML_MAX_VAL; if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { @@ -199,19 +211,10 @@ 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 esdhc_write32(®s->dsaddr, (u32)data->src); +#endif } -#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ - if (!(data->flags & MMC_DATA_READ)) { - 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; - } - esdhc_write32(®s->dsaddr, (u32)data->src); - } else - esdhc_write32(®s->dsaddr, (u32)data->dest); -#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); @@ -221,16 +224,16 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) * 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 + * = (mmc->clock * 1/4) SD Clock cycles * As 1) >= 2) - * => (2^(timeout+13)) >= mmc->tran_speed * 1/4 + * => (2^(timeout+13)) >= mmc->clock * 1/4 * Taking log2 both the sides - * => timeout + 13 >= log2(mmc->tran_speed/4) + * => timeout + 13 >= log2(mmc->clock/4) * Rounding up to next power of 2 - * => timeout + 13 = log2(mmc->tran_speed/4) + 1 - * => timeout + 13 = fls(mmc->tran_speed/4) + * => timeout + 13 = log2(mmc->clock/4) + 1 + * => timeout + 13 = fls(mmc->clock/4) */ - timeout = fls(mmc->tran_speed/4); + timeout = fls(mmc->clock/4); timeout -= 13; if (timeout > 14) @@ -244,11 +247,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) timeout++; #endif +#ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE + timeout = 0xE; +#endif esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; } +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO static void check_and_invalidate_dcache_range (struct mmc_cmd *cmd, struct mmc_data *data) { @@ -258,6 +265,8 @@ static void check_and_invalidate_dcache_range unsigned end = start+size ; invalidate_dcache_range(start, end); } +#endif + /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. @@ -265,9 +274,10 @@ static void check_and_invalidate_dcache_range static int esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { + int err = 0; uint xfertyp; uint irqstat; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 @@ -296,8 +306,6 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) /* Set up for a data transfer if we have one */ if (data) { - int err; - err = esdhc_setup_data(mmc, data); if(err) return err; @@ -313,7 +321,8 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) esdhc_write32(®s->cmdarg, cmd->cmdarg); #if defined(CONFIG_FSL_USDHC) esdhc_write32(®s->mixctrl, - (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F)); + (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F) + | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); #else esdhc_write32(®s->xfertyp, xfertyp); @@ -325,27 +334,24 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) irqstat = esdhc_read32(®s->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 (irqstat & CMD_ERR) { + err = COMM_ERR; + goto out; + } - if (data) { - esdhc_write32(®s->sysctl, - esdhc_read32(®s->sysctl) | - SYSCTL_RSTD); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) - ; - } + if (irqstat & IRQSTAT_CTOE) { + err = TIMEOUT; + goto out; } - if (irqstat & CMD_ERR) - return COMM_ERR; + /* Switch voltage to 1.8V if CMD11 succeeded */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); - if (irqstat & IRQSTAT_CTOE) - return TIMEOUT; + printf("Run CMD11 1.8V switch\n"); + /* Sleep for 5 ms - max time for card to switch to 1.8V */ + udelay(5000); + } /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { @@ -360,7 +366,8 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (timeout <= 0) { printf("Timeout waiting for DAT0 to go high!\n"); - return TIMEOUT; + err = TIMEOUT; + goto out; } } @@ -387,32 +394,58 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) do { irqstat = esdhc_read32(®s->irqstat); - if (irqstat & IRQSTAT_DTOE) - return TIMEOUT; + if (irqstat & IRQSTAT_DTOE) { + err = TIMEOUT; + goto out; + } - if (irqstat & DATA_ERR) - return COMM_ERR; + if (irqstat & DATA_ERR) { + err = COMM_ERR; + goto out; + } } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); -#endif + if (data->flags & MMC_DATA_READ) check_and_invalidate_dcache_range(cmd, data); +#endif + } + +out: + /* Reset CMD and DATA portions on error */ + if (err) { + 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 this was CMD11, then notify that power cycle is needed */ + if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) + printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); } esdhc_write32(®s->irqstat, -1); - return 0; + return err; } static void set_sysctl(struct mmc *mmc, uint clock) { int div, pre_div; - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *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) - clock = mmc->f_min; + if (clock < mmc->cfg->f_min) + clock = mmc->cfg->f_min; if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) @@ -425,7 +458,7 @@ static void set_sysctl(struct mmc *mmc, uint clock) if ((sdhc_clk / (div * pre_div)) <= clock) break; - pre_div >>= 1; + pre_div >>= mmc->ddr_mode ? 2 : 1; div -= 1; clk = (pre_div << 8) | (div << 4); @@ -443,7 +476,7 @@ static void set_sysctl(struct mmc *mmc, uint clock) static void esdhc_set_ios(struct mmc *mmc) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; /* Set the clock speed */ @@ -461,7 +494,7 @@ static void esdhc_set_ios(struct mmc *mmc) static int esdhc_init(struct mmc *mmc) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; @@ -491,15 +524,23 @@ static int esdhc_init(struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); +#ifdef CONFIG_SYS_FSL_ESDHC_FORCE_VSELECT + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); +#endif + return 0; } static int esdhc_getcd(struct mmc *mmc) { - struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; +#ifdef CONFIG_ESDHC_DETECT_QUIRK + if (CONFIG_ESDHC_DETECT_QUIRK) + return 1; +#endif while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) udelay(1000); @@ -520,6 +561,13 @@ static void esdhc_reset(struct fsl_esdhc *regs) printf("MMC/SD: Reset never completed.\n"); } +static const struct mmc_ops esdhc_ops = { + .send_cmd = esdhc_send_cmd, + .set_ios = esdhc_set_ios, + .init = esdhc_init, + .getcd = esdhc_getcd, +}; + int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { struct fsl_esdhc *regs; @@ -529,11 +577,6 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) if (!cfg) return -1; - mmc = malloc(sizeof(struct mmc)); - if (!mmc) - return -ENOMEM; - - sprintf(mmc->name, "FSL_SDHC"); regs = (struct fsl_esdhc *)cfg->esdhc_base; /* First reset the eSDHC controller */ @@ -542,20 +585,22 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) 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; - mmc->init = esdhc_init; - mmc->getcd = esdhc_getcd; - mmc->getwp = NULL; + writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); + memset(&cfg->cfg, 0, sizeof(cfg->cfg)); voltage_caps = 0; - caps = regs->hostcapblt; + caps = esdhc_read32(®s->hostcapblt); #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); #endif + +/* T4240 host controller capabilities register should have VS33 bit */ +#ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 + caps = caps | ESDHC_HOSTCAPBLT_VS33; +#endif + if (caps & ESDHC_HOSTCAPBLT_VS18) voltage_caps |= MMC_VDD_165_195; if (caps & ESDHC_HOSTCAPBLT_VS30) @@ -563,33 +608,46 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) if (caps & ESDHC_HOSTCAPBLT_VS33) voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->cfg.name = "FSL_SDHC"; + cfg->cfg.ops = &esdhc_ops; #ifdef CONFIG_SYS_SD_VOLTAGE - mmc->voltages = CONFIG_SYS_SD_VOLTAGE; + cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE; #else - mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; #endif - if ((mmc->voltages & voltage_caps) == 0) { + if ((cfg->cfg.voltages & voltage_caps) == 0) { printf("voltage not supported by controller\n"); return -1; } - mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; + cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; +#ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE + cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; +#endif if (cfg->max_bus_width > 0) { if (cfg->max_bus_width < 8) - mmc->host_caps &= ~MMC_MODE_8BIT; + cfg->cfg.host_caps &= ~MMC_MODE_8BIT; if (cfg->max_bus_width < 4) - mmc->host_caps &= ~MMC_MODE_4BIT; + cfg->cfg.host_caps &= ~MMC_MODE_4BIT; } if (caps & ESDHC_HOSTCAPBLT_HSS) - mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + +#ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK + if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) + cfg->cfg.host_caps &= ~MMC_MODE_8BIT; +#endif - mmc->f_min = 400000; - mmc->f_max = MIN(gd->arch.sdhc_clk, 52000000); + cfg->cfg.f_min = 400000; + cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000); - mmc->b_max = 0; - mmc_register(mmc); + cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + mmc = mmc_create(&cfg->cfg, cfg); + if (mmc == NULL) + return -1; return 0; }