Merge https://gitlab.denx.de/u-boot/custodians/u-boot-spi into next
[platform/kernel/u-boot.git] / drivers / mmc / fsl_esdhc_imx.c
index 797bdbb..f42e018 100644 (file)
 #include <common.h>
 #include <command.h>
 #include <clk.h>
+#include <cpu_func.h>
 #include <errno.h>
 #include <hwconfig.h>
+#include <log.h>
 #include <mmc.h>
 #include <part.h>
+#include <asm/cache.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
 #include <power/regulator.h>
 #include <malloc.h>
 #include <fsl_esdhc_imx.h>
@@ -77,7 +84,7 @@ struct fsl_esdhc {
        uint    vendorspec;
        uint    mmcboot;
        uint    vendorspec2;
-       uint    tuning_ctrl;    /* on i.MX6/7/8 */
+       uint    tuning_ctrl;    /* on i.MX6/7/8/RT */
        char    reserved5[44];
        uint    hostver;        /* Host controller version register */
        char    reserved6[4];   /* reserved */
@@ -101,7 +108,6 @@ struct fsl_esdhc_plat {
 
 struct esdhc_soc_data {
        u32 flags;
-       u32 caps;
 };
 
 /**
@@ -115,6 +121,7 @@ struct esdhc_soc_data {
  * Following is used when Driver Model is enabled for MMC
  * @dev: pointer for the device
  * @non_removable: 0: removable; 1: non-removable
+ * @broken_cd: 0: use GPIO for card detect; 1: Do not use GPIO for card detect
  * @wp_enable: 1: enable checking wp; 0: no check
  * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V
  * @flags: ESDHC_FLAG_xx in include/fsl_esdhc_imx.h
@@ -138,6 +145,7 @@ struct fsl_esdhc_priv {
 #endif
        struct udevice *dev;
        int non_removable;
+       int broken_cd;
        int wp_enable;
        int vs18_enable;
        u32 flags;
@@ -146,11 +154,11 @@ struct fsl_esdhc_priv {
        u32 tuning_start_tap;
        u32 strobe_dll_delay_target;
        u32 signal_voltage;
-#if IS_ENABLED(CONFIG_DM_REGULATOR)
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
        struct udevice *vqmmc_dev;
        struct udevice *vmmc_dev;
 #endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
        struct gpio_desc cd_gpio;
        struct gpio_desc wp_gpio;
 #endif
@@ -265,8 +273,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
 {
        int timeout;
        struct fsl_esdhc *regs = priv->esdhc_regs;
-#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) || \
-       defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
+#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
        dma_addr_t addr;
 #endif
        uint wml_value;
@@ -279,8 +286,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
 
                esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
 #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
-#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) || \
-       defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
+#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
                addr = virt_to_phys((void *)(data->dest));
                if (upper_32_bits(addr))
                        printf("Error found for upper 32 bits\n");
@@ -305,8 +311,9 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
                                return -ETIMEDOUT;
                        }
                } else {
-#ifdef CONFIG_DM_GPIO
-                       if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) {
+#if CONFIG_IS_ENABLED(DM_GPIO)
+                       if (dm_gpio_is_valid(&priv->wp_gpio) &&
+                           dm_gpio_get_value(&priv->wp_gpio)) {
                                printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
                                return -ETIMEDOUT;
                        }
@@ -316,8 +323,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
                esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
                                        wml_value << 16);
 #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
-#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) || \
-       defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
+#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
                addr = virt_to_phys((void *)(data->src));
                if (upper_32_bits(addr))
                        printf("Error found for upper 32 bits\n");
@@ -382,8 +388,7 @@ static void check_and_invalidate_dcache_range
        unsigned end = 0;
        unsigned size = roundup(ARCH_DMA_MINALIGN,
                                data->blocks*data->blocksize);
-#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234) || \
-       defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
+#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
        dma_addr_t addr;
 
        addr = virt_to_phys((void *)(data->dest));
@@ -518,9 +523,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
 
        /* Workaround for ESDHC errata ENGcm03648 */
        if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
-               int timeout = 6000;
+               int timeout = 50000;
 
-               /* Poll on DATA0 line for cmd with busy signal for 600 ms */
+               /* Poll on DATA0 line for cmd with busy signal for 5000 ms */
                while (timeout > 0 && !(esdhc_read32(&regs->prsstat) &
                                        PRSSTAT_DAT0)) {
                        udelay(100);
@@ -632,9 +637,6 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
        int sdhc_clk = priv->sdhc_clk;
        uint clk;
 
-       if (clock < mmc->cfg->f_min)
-               clock = mmc->cfg->f_min;
-
        while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
                pre_div *= 2;
 
@@ -665,35 +667,6 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
        priv->clock = clock;
 }
 
-#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
-static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable)
-{
-       struct fsl_esdhc *regs = priv->esdhc_regs;
-       u32 value;
-       u32 time_out;
-
-       value = esdhc_read32(&regs->sysctl);
-
-       if (enable)
-               value |= SYSCTL_CKEN;
-       else
-               value &= ~SYSCTL_CKEN;
-
-       esdhc_write32(&regs->sysctl, value);
-
-       time_out = 20;
-       value = PRSSTAT_SDSTB;
-       while (!(esdhc_read32(&regs->prsstat) & value)) {
-               if (time_out == 0) {
-                       printf("fsl_esdhc: Internal clock never stabilised.\n");
-                       break;
-               }
-               time_out--;
-               mdelay(1);
-       }
-}
-#endif
-
 #ifdef MMC_SUPPORTS_TUNING
 static int esdhc_change_pinstate(struct udevice *dev)
 {
@@ -708,6 +681,7 @@ static int esdhc_change_pinstate(struct udevice *dev)
        case UHS_SDR104:
        case MMC_HS_200:
        case MMC_HS_400:
+       case MMC_HS_400_ES:
                ret = pinctrl_select_state(dev, "state_200mhz");
                break;
        default:
@@ -773,11 +747,11 @@ static int esdhc_set_timing(struct mmc *mmc)
 
        switch (mmc->selected_mode) {
        case MMC_LEGACY:
-       case SD_LEGACY:
                esdhc_reset_tuning(mmc);
                writel(mixctrl, &regs->mixctrl);
                break;
        case MMC_HS_400:
+       case MMC_HS_400_ES:
                mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN;
                writel(mixctrl, &regs->mixctrl);
                esdhc_set_strobe_dll(mmc);
@@ -817,7 +791,7 @@ static int esdhc_set_voltage(struct mmc *mmc)
        switch (mmc->signal_voltage) {
        case MMC_SIGNAL_VOLTAGE_330:
                if (priv->vs18_enable)
-                       return -EIO;
+                       return -ENOTSUPP;
 #if CONFIG_IS_ENABLED(DM_REGULATOR)
                if (!IS_ERR_OR_NULL(priv->vqmmc_dev)) {
                        ret = regulator_set_value(priv->vqmmc_dev, 3300000);
@@ -961,16 +935,15 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
 {
        struct fsl_esdhc *regs = priv->esdhc_regs;
        int ret __maybe_unused;
+       u32 clock;
 
-#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
-       /* Select to use peripheral clock */
-       esdhc_clock_control(priv, false);
-       esdhc_setbits32(&regs->scr, ESDHCCTL_PCS);
-       esdhc_clock_control(priv, true);
-#endif
        /* Set the clock speed */
-       if (priv->clock != mmc->clock)
-               set_sysctl(priv, mmc, mmc->clock);
+       clock = mmc->clock;
+       if (clock < mmc->cfg->f_min)
+               clock = mmc->cfg->f_min;
+
+       if (priv->clock != clock)
+               set_sysctl(priv, mmc, clock);
 
 #ifdef MMC_SUPPORTS_TUNING
        if (mmc->clk_disable) {
@@ -999,7 +972,8 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
        if (priv->signal_voltage != mmc->signal_voltage) {
                ret = esdhc_set_voltage(mmc);
                if (ret) {
-                       printf("esdhc_set_voltage error %d\n", ret);
+                       if (ret != -ENOTSUPP)
+                               printf("esdhc_set_voltage error %d\n", ret);
                        return ret;
                }
        }
@@ -1092,7 +1066,10 @@ static int esdhc_getcd_common(struct fsl_esdhc_priv *priv)
 #if CONFIG_IS_ENABLED(DM_MMC)
        if (priv->non_removable)
                return 1;
-#ifdef CONFIG_DM_GPIO
+
+       if (priv->broken_cd)
+               return 1;
+#if CONFIG_IS_ENABLED(DM_GPIO)
        if (dm_gpio_is_valid(&priv->cd_gpio))
                return dm_gpio_get_value(&priv->cd_gpio);
 #endif
@@ -1368,45 +1345,6 @@ int fsl_esdhc_mmc_init(bd_t *bis)
 }
 #endif
 
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
-void mmc_adapter_card_type_ident(void)
-{
-       u8 card_id;
-       u8 value;
-
-       card_id = QIXIS_READ(present) & QIXIS_SDID_MASK;
-       gd->arch.sdhc_adapter = card_id;
-
-       switch (card_id) {
-       case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45:
-               value = QIXIS_READ(brdcfg[5]);
-               value |= (QIXIS_DAT4 | QIXIS_DAT5_6_7);
-               QIXIS_WRITE(brdcfg[5], value);
-               break;
-       case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY:
-               value = QIXIS_READ(pwr_ctl[1]);
-               value |= QIXIS_EVDD_BY_SDHC_VS;
-               QIXIS_WRITE(pwr_ctl[1], value);
-               break;
-       case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44:
-               value = QIXIS_READ(brdcfg[5]);
-               value |= (QIXIS_SDCLKIN | QIXIS_SDCLKOUT);
-               QIXIS_WRITE(brdcfg[5], value);
-               break;
-       case QIXIS_ESDHC_ADAPTER_TYPE_RSV:
-               break;
-       case QIXIS_ESDHC_ADAPTER_TYPE_MMC:
-               break;
-       case QIXIS_ESDHC_ADAPTER_TYPE_SD:
-               break;
-       case QIXIS_ESDHC_NO_ADAPTER:
-               break;
-       default:
-               break;
-       }
-}
-#endif
-
 #ifdef CONFIG_OF_LIBFDT
 __weak int esdhc_status_fixup(void *blob, const char *compat)
 {
@@ -1427,24 +1365,13 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd)
        if (esdhc_status_fixup(blob, compat))
                return;
 
-#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
-       do_fixup_by_compat_u32(blob, compat, "peripheral-frequency",
-                              gd->arch.sdhc_clk, 1);
-#else
        do_fixup_by_compat_u32(blob, compat, "clock-frequency",
                               gd->arch.sdhc_clk, 1);
-#endif
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
-       do_fixup_by_compat_u32(blob, compat, "adapter-type",
-                              (u32)(gd->arch.sdhc_adapter), 1);
-#endif
 }
 #endif
 
 #if CONFIG_IS_ENABLED(DM_MMC)
-#ifndef CONFIG_PPC
 #include <asm/arch/clock.h>
-#endif
 __weak void init_clk_usdhc(u32 index)
 {
 }
@@ -1472,17 +1399,11 @@ static int fsl_esdhc_probe(struct udevice *dev)
        addr = dev_read_addr(dev);
        if (addr == FDT_ADDR_T_NONE)
                return -EINVAL;
-#ifdef CONFIG_PPC
-       priv->esdhc_regs = (struct fsl_esdhc *)lower_32_bits(addr);
-#else
        priv->esdhc_regs = (struct fsl_esdhc *)addr;
-#endif
        priv->dev = dev;
        priv->mode = -1;
-       if (data) {
+       if (data)
                priv->flags = data->flags;
-               priv->caps = data->caps;
-       }
 
        val = dev_read_u32_default(dev, "bus-width", -1);
        if (val == 8)
@@ -1501,11 +1422,14 @@ static int fsl_esdhc_probe(struct udevice *dev)
                             ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT);
        priv->strobe_dll_delay_target = val;
 
+       if (dev_read_bool(dev, "broken-cd"))
+               priv->broken_cd = 1;
+
        if (dev_read_bool(dev, "non-removable")) {
                priv->non_removable = 1;
         } else {
                priv->non_removable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
                gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
                                     GPIOD_IS_IN);
 #endif
@@ -1515,7 +1439,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
                priv->wp_enable = 1;
        } else {
                priv->wp_enable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
                gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
                                   GPIOD_IS_IN);
 #endif
@@ -1532,6 +1456,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
        if (ret) {
                dev_dbg(dev, "no vqmmc-supply\n");
        } else {
+               priv->vqmmc_dev = vqmmc_dev;
                ret = regulator_set_enable(vqmmc_dev, true);
                if (ret) {
                        dev_err(dev, "fail to enable vqmmc-supply\n");
@@ -1543,9 +1468,6 @@ static int fsl_esdhc_probe(struct udevice *dev)
        }
 #endif
 
-       if (fdt_get_property(fdt, node, "no-1-8-v", NULL))
-               priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400);
-
        /*
         * TODO:
         * Because lack of clk driver, if SDHC clk is not enabled,
@@ -1568,31 +1490,27 @@ static int fsl_esdhc_probe(struct udevice *dev)
 
        init_clk_usdhc(dev->seq);
 
-       if (IS_ENABLED(CONFIG_CLK)) {
-               /* Assigned clock already set clock */
-               ret = clk_get_by_name(dev, "per", &priv->per_clk);
-               if (ret) {
-                       printf("Failed to get per_clk\n");
-                       return ret;
-               }
-               ret = clk_enable(&priv->per_clk);
-               if (ret) {
-                       printf("Failed to enable per_clk\n");
-                       return ret;
-               }
+#if CONFIG_IS_ENABLED(CLK)
+       /* Assigned clock already set clock */
+       ret = clk_get_by_name(dev, "per", &priv->per_clk);
+       if (ret) {
+               printf("Failed to get per_clk\n");
+               return ret;
+       }
+       ret = clk_enable(&priv->per_clk);
+       if (ret) {
+               printf("Failed to enable per_clk\n");
+               return ret;
+       }
 
-               priv->sdhc_clk = clk_get_rate(&priv->per_clk);
-       } else {
-#ifndef CONFIG_PPC
-               priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq);
+       priv->sdhc_clk = clk_get_rate(&priv->per_clk);
 #else
-               priv->sdhc_clk = gd->arch.sdhc_clk;
-#endif
-               if (priv->sdhc_clk <= 0) {
-                       dev_err(dev, "Unable to get clk for %s\n", dev->name);
-                       return -EINVAL;
-               }
+       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);
+               return -EINVAL;
        }
+#endif
 
        ret = fsl_esdhc_init(priv, plat);
        if (ret) {
@@ -1600,6 +1518,10 @@ static int fsl_esdhc_probe(struct udevice *dev)
                return ret;
        }
 
+       ret = mmc_of_parse(dev, &plat->cfg);
+       if (ret)
+               return ret;
+
        mmc = &plat->mmc;
        mmc->cfg = &plat->cfg;
        mmc->dev = dev;
@@ -1653,6 +1575,21 @@ static int fsl_esdhc_set_ios(struct udevice *dev)
        return esdhc_set_ios_common(priv, &plat->mmc);
 }
 
+#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
+static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev)
+{
+       struct fsl_esdhc_priv *priv = dev_get_priv(dev);
+       struct fsl_esdhc *regs = priv->esdhc_regs;
+       u32 m;
+
+       m = readl(&regs->mixctrl);
+       m |= MIX_CTRL_HS400_ES;
+       writel(m, &regs->mixctrl);
+
+       return 0;
+}
+#endif
+
 static const struct dm_mmc_ops fsl_esdhc_ops = {
        .get_cd         = fsl_esdhc_get_cd,
        .send_cmd       = fsl_esdhc_send_cmd,
@@ -1660,6 +1597,9 @@ static const struct dm_mmc_ops fsl_esdhc_ops = {
 #ifdef MMC_SUPPORTS_TUNING
        .execute_tuning = fsl_esdhc_execute_tuning,
 #endif
+#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
+       .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe,
+#endif
 };
 #endif
 
@@ -1667,8 +1607,12 @@ static struct esdhc_soc_data usdhc_imx7d_data = {
        .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
                        | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
                        | ESDHC_FLAG_HS400,
-       .caps = UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_DDR_52MHz |
-               MMC_MODE_HS_52MHz | MMC_MODE_HS,
+};
+
+static struct esdhc_soc_data usdhc_imx8qm_data = {
+       .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
+               ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
+               ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES,
 };
 
 static const struct udevice_id fsl_esdhc_ids[] = {
@@ -1679,6 +1623,11 @@ static const struct udevice_id fsl_esdhc_ids[] = {
        { .compatible = "fsl,imx6q-usdhc", },
        { .compatible = "fsl,imx7d-usdhc", .data = (ulong)&usdhc_imx7d_data,},
        { .compatible = "fsl,imx7ulp-usdhc", },
+       { .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,},
+       { .compatible = "fsl,imx8mm-usdhc", .data = (ulong)&usdhc_imx8qm_data,},
+       { .compatible = "fsl,imx8mn-usdhc", .data = (ulong)&usdhc_imx8qm_data,},
+       { .compatible = "fsl,imx8mq-usdhc", .data = (ulong)&usdhc_imx8qm_data,},
+       { .compatible = "fsl,imxrt-usdhc", },
        { .compatible = "fsl,esdhc", },
        { /* sentinel */ }
 };