X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmmc%2Ffsl_esdhc.c;h=b69c9b71e4c833c3bedb2cea8b399e7593dc9352;hb=390194d43fa4478ddb638164ddb114c979f3e57a;hp=3acf9e88202f6c253f9ada4ea08cce3041ff1c09;hpb=e16e137c377c8b96d8d91263d0b6d8470169f841;p=u-boot diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 3acf9e8820..b69c9b71e4 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -12,11 +12,12 @@ #include #include #include +#include #include #include #include +#include #include -#include #include #include #include @@ -56,21 +57,27 @@ struct fsl_esdhc { uint fevt; /* Force event register */ uint admaes; /* ADMA error status register */ uint adsaddr; /* ADMA system address register */ - char reserved2[100]; /* reserved */ - uint vendorspec; /* Vendor Specific register */ - char reserved3[56]; /* reserved */ + char reserved2[4]; + uint dllctrl; + uint dllstat; + uint clktunectrlstatus; + char reserved3[84]; + uint vendorspec; + uint mmcboot; + uint vendorspec2; + char reserved4[48]; uint hostver; /* Host controller version register */ - char reserved4[4]; /* reserved */ - uint dmaerraddr; /* DMA error address register */ char reserved5[4]; /* reserved */ - uint dmaerrattr; /* DMA error attribute register */ + uint dmaerraddr; /* DMA error address register */ char reserved6[4]; /* reserved */ + uint dmaerrattr; /* DMA error attribute register */ + char reserved7[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ - char reserved7[8]; /* reserved */ + char reserved8[8]; /* reserved */ uint tcr; /* Tuning control register */ - char reserved8[28]; /* reserved */ + char reserved9[28]; /* reserved */ uint sddirctl; /* SD direction control register */ - char reserved9[712]; /* reserved */ + char reserved10[712];/* reserved */ uint scr; /* eSDHC control register */ }; @@ -85,7 +92,10 @@ struct fsl_esdhc { * Following is used when Driver Model is enabled for MMC * @dev: pointer for the device * @non_removable: 0: removable; 1: non-removable + * @wp_enable: 1: enable checking wp; 0: no check + * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V * @cd_gpio: gpio for card detection + * @wp_gpio: gpio for write protection */ struct fsl_esdhc_priv { struct fsl_esdhc *esdhc_regs; @@ -95,7 +105,12 @@ struct fsl_esdhc_priv { struct mmc *mmc; struct udevice *dev; int non_removable; + int wp_enable; + int vs18_enable; +#ifdef CONFIG_DM_GPIO struct gpio_desc cd_gpio; + struct gpio_desc wp_gpio; +#endif }; /* Return the XFERTYP flags for a given command and data packet */ @@ -208,7 +223,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) int timeout; struct fsl_esdhc_priv *priv = mmc->priv; struct fsl_esdhc *regs = priv->esdhc_regs; -#ifdef CONFIG_FSL_LAYERSCAPE +#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) dma_addr_t addr; #endif uint wml_value; @@ -221,7 +236,7 @@ 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 +#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) addr = virt_to_phys((void *)(data->dest)); if (upper_32_bits(addr)) printf("Error found for upper 32 bits\n"); @@ -239,15 +254,18 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) #endif 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; + if (priv->wp_enable) { + if ((esdhc_read32(®s->prsstat) & + PRSSTAT_WPSPL) == 0) { + printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); + return -ETIMEDOUT; + } } esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#ifdef CONFIG_FSL_LAYERSCAPE +#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) addr = virt_to_phys((void *)(data->src)); if (upper_32_bits(addr)) printf("Error found for upper 32 bits\n"); @@ -308,15 +326,11 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) 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 end = 0; unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); - unsigned end = start+size ; -#ifdef CONFIG_FSL_LAYERSCAPE +#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) dma_addr_t addr; addr = virt_to_phys((void *)(data->dest)); @@ -324,7 +338,10 @@ static void check_and_invalidate_dcache_range printf("Error found for upper 32 bits\n"); else start = lower_32_bits(addr); +#else + start = (unsigned)data->dest; #endif + end = start + size; invalidate_dcache_range(start, end); } @@ -399,12 +416,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) irqstat = esdhc_read32(®s->irqstat); if (irqstat & CMD_ERR) { - err = COMM_ERR; + err = -ECOMM; goto out; } if (irqstat & IRQSTAT_CTOE) { - err = TIMEOUT; + err = -ETIMEDOUT; goto out; } @@ -430,7 +447,7 @@ 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"); - err = TIMEOUT; + err = -ETIMEDOUT; goto out; } } @@ -459,12 +476,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) irqstat = esdhc_read32(®s->irqstat); if (irqstat & IRQSTAT_DTOE) { - err = TIMEOUT; + err = -ETIMEDOUT; goto out; } if (irqstat & DATA_ERR) { - err = COMM_ERR; + err = -ECOMM; goto out; } } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); @@ -507,7 +524,13 @@ out: static void set_sysctl(struct mmc *mmc, uint clock) { - int div, pre_div; + int div = 1; +#ifdef ARCH_MXC + int pre_div = 1; +#else + int pre_div = 2; +#endif + int ddr_pre_div = mmc->ddr_mode ? 2 : 1; struct fsl_esdhc_priv *priv = mmc->priv; struct fsl_esdhc *regs = priv->esdhc_regs; int sdhc_clk = priv->sdhc_clk; @@ -516,24 +539,19 @@ static void set_sysctl(struct mmc *mmc, uint clock) 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) - if ((sdhc_clk / pre_div) <= (clock * 16)) - break; - } else - pre_div = 2; + while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256) + pre_div *= 2; - for (div = 1; div <= 16; div++) - if ((sdhc_clk / (div * pre_div)) <= clock) - break; + while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16) + div++; - pre_div >>= mmc->ddr_mode ? 2 : 1; + pre_div >>= 1; div -= 1; clk = (pre_div << 8) | (div << 4); #ifdef CONFIG_FSL_USDHC - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_CKEN); #else esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); #endif @@ -543,7 +561,7 @@ static void set_sysctl(struct mmc *mmc, uint clock) udelay(10000); #ifdef CONFIG_FSL_USDHC - esdhc_clrbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | VENDORSPEC_CKEN); #else esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); #endif @@ -580,7 +598,7 @@ static void esdhc_clock_control(struct mmc *mmc, bool enable) } #endif -static void esdhc_set_ios(struct mmc *mmc) +static int esdhc_set_ios(struct mmc *mmc) { struct fsl_esdhc_priv *priv = mmc->priv; struct fsl_esdhc *regs = priv->esdhc_regs; @@ -602,6 +620,7 @@ static void esdhc_set_ios(struct mmc *mmc) else if (mmc->bus_width == 8) esdhc_setbits32(®s->proctl, PROCTL_DTW_8); + return 0; } static int esdhc_init(struct mmc *mmc) @@ -617,6 +636,20 @@ static int esdhc_init(struct mmc *mmc) while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) udelay(1000); +#if defined(CONFIG_FSL_USDHC) + /* RSTA doesn't reset MMC_BOOT register, so manually reset it */ + esdhc_write32(®s->mmcboot, 0x0); + /* Reset MIX_CTRL and CLK_TUNE_CTRL_STATUS regs to 0 */ + esdhc_write32(®s->mixctrl, 0x0); + esdhc_write32(®s->clktunectrlstatus, 0x0); + + /* Put VEND_SPEC to default value */ + esdhc_write32(®s->vendorspec, VENDORSPEC_INIT); + + /* Disable DLL_CTRL delay line */ + esdhc_write32(®s->dllctrl, 0x0); +#endif + #ifndef ARCH_MXC /* Enable cache snooping */ esdhc_write32(®s->scr, 0x00000040); @@ -624,6 +657,8 @@ static int esdhc_init(struct mmc *mmc) #ifndef CONFIG_FSL_USDHC esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); +#else + esdhc_setbits32(®s->vendorspec, VENDORSPEC_HCKEN | VENDORSPEC_IPGEN); #endif /* Set the initial clock speed */ @@ -638,9 +673,8 @@ 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 + if (priv->vs18_enable) + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); return 0; } @@ -659,9 +693,10 @@ static int esdhc_getcd(struct mmc *mmc) #ifdef CONFIG_DM_MMC if (priv->non_removable) return 1; - +#ifdef CONFIG_DM_GPIO if (dm_gpio_is_valid(&priv->cd_gpio)) return dm_gpio_get_value(&priv->cd_gpio); +#endif #endif while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) @@ -691,19 +726,6 @@ static const struct mmc_ops esdhc_ops = { .getcd = esdhc_getcd, }; -static int fsl_esdhc_cfg_to_priv(struct fsl_esdhc_cfg *cfg, - struct fsl_esdhc_priv *priv) -{ - if (!cfg || !priv) - return -EINVAL; - - priv->esdhc_regs = (struct fsl_esdhc *)(unsigned long)(cfg->esdhc_base); - priv->bus_width = cfg->max_bus_width; - priv->sdhc_clk = cfg->sdhc_clk; - - return 0; -}; - static int fsl_esdhc_init(struct fsl_esdhc_priv *priv) { struct fsl_esdhc *regs; @@ -721,8 +743,14 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv) #ifndef CONFIG_FSL_USDHC esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN | SYSCTL_CKEN); +#else + esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | + VENDORSPEC_HCKEN | VENDORSPEC_IPGEN | VENDORSPEC_CKEN); #endif + if (priv->vs18_enable) + esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); + writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); memset(&priv->cfg, 0, sizeof(priv->cfg)); @@ -797,6 +825,22 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv) return 0; } +#ifndef CONFIG_DM_MMC +static int fsl_esdhc_cfg_to_priv(struct fsl_esdhc_cfg *cfg, + struct fsl_esdhc_priv *priv) +{ + if (!cfg || !priv) + return -EINVAL; + + priv->esdhc_regs = (struct fsl_esdhc *)(unsigned long)(cfg->esdhc_base); + priv->bus_width = cfg->max_bus_width; + priv->sdhc_clk = cfg->sdhc_clk; + priv->wp_enable = cfg->wp_enable; + priv->vs18_enable = cfg->vs18_enable; + + return 0; +}; + int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { struct fsl_esdhc_priv *priv; @@ -835,6 +879,7 @@ int fsl_esdhc_mmc_init(bd_t *bis) cfg->sdhc_clk = gd->arch.sdhc_clk; return fsl_esdhc_initialize(bis, cfg); } +#endif #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT void mmc_adapter_card_type_ident(void) @@ -876,17 +921,24 @@ void mmc_adapter_card_type_ident(void) #endif #ifdef CONFIG_OF_LIBFDT -void fdt_fixup_esdhc(void *blob, bd_t *bd) +__weak int esdhc_status_fixup(void *blob, const char *compat) { - const char *compat = "fsl,esdhc"; - #ifdef CONFIG_FSL_ESDHC_PIN_MUX if (!hwconfig("esdhc")) { do_fixup_by_compat(blob, compat, "status", "disabled", - 8 + 1, 1); - return; + sizeof("disabled"), 1); + return 1; } #endif + return 0; +} + +void fdt_fixup_esdhc(void *blob, bd_t *bd) +{ + const char *compat = "fsl,esdhc"; + + if (esdhc_status_fixup(blob, compat)) + return; #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK do_fixup_by_compat_u32(blob, compat, "peripheral-frequency", @@ -899,24 +951,29 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd) 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); } #endif #ifdef CONFIG_DM_MMC #include +__weak void init_clk_usdhc(u32 index) +{ +} + static int fsl_esdhc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct fsl_esdhc_priv *priv = dev_get_priv(dev); const void *fdt = gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); +#ifdef CONFIG_DM_REGULATOR + struct udevice *vqmmc_dev; +#endif fdt_addr_t addr; unsigned int val; int ret; - addr = dev_get_addr(dev); + addr = devfdt_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; @@ -935,9 +992,42 @@ static int fsl_esdhc_probe(struct udevice *dev) priv->non_removable = 1; } else { priv->non_removable = 0; - gpio_request_by_name_nodev(fdt, node, "cd-gpios", 0, - &priv->cd_gpio, GPIOD_IS_IN); +#ifdef CONFIG_DM_GPIO + gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", + 0, &priv->cd_gpio, GPIOD_IS_IN); +#endif + } + + priv->wp_enable = 1; + +#ifdef CONFIG_DM_GPIO + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "wp-gpios", 0, + &priv->wp_gpio, GPIOD_IS_IN); + if (ret) + priv->wp_enable = 0; +#endif + + priv->vs18_enable = 0; + +#ifdef CONFIG_DM_REGULATOR + /* + * If emmc I/O has a fixed voltage at 1.8V, this must be provided, + * otherwise, emmc will work abnormally. + */ + ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev); + if (ret) { + dev_dbg(dev, "no vqmmc-supply\n"); + } else { + ret = regulator_set_enable(vqmmc_dev, true); + if (ret) { + dev_err(dev, "fail to enable vqmmc-supply\n"); + return ret; + } + + if (regulator_get_value(vqmmc_dev) == 1800000) + priv->vs18_enable = 1; } +#endif /* * TODO: @@ -958,6 +1048,9 @@ static int fsl_esdhc_probe(struct udevice *dev) * correctly get the seq as 2 and 3, then let mxc_get_clock * work as expected. */ + + init_clk_usdhc(dev->seq); + priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq); if (priv->sdhc_clk <= 0) { dev_err(dev, "Unable to get clk for %s\n", dev->name); @@ -971,6 +1064,7 @@ static int fsl_esdhc_probe(struct udevice *dev) } upriv->mmc = priv->mmc; + priv->mmc->dev = dev; return 0; } @@ -981,6 +1075,8 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx6sl-usdhc", }, { .compatible = "fsl,imx6q-usdhc", }, { .compatible = "fsl,imx7d-usdhc", }, + { .compatible = "fsl,imx7ulp-usdhc", }, + { .compatible = "fsl,esdhc", }, { /* sentinel */ } };