]> git.sur5r.net Git - u-boot/blobdiff - drivers/mmc/fsl_esdhc.c
Merge git://git.denx.de/u-boot-fsl-qoriq
[u-boot] / drivers / mmc / fsl_esdhc.c
index 57ad9754f56a1af12f63576f190bf8a153ac88c3..73473c53a375fe679a6bd94a36301f1dbae6f383 100644 (file)
 #include <config.h>
 #include <common.h>
 #include <command.h>
+#include <errno.h>
 #include <hwconfig.h>
 #include <mmc.h>
 #include <part.h>
 #include <malloc.h>
-#include <mmc.h>
 #include <fsl_esdhc.h>
 #include <fdt_support.h>
 #include <asm/io.h>
@@ -56,21 +56,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 +91,9 @@ 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
  * @cd_gpio: gpio for card detection
+ * @wp_gpio: gpio for write protection
  */
 struct fsl_esdhc_priv {
        struct fsl_esdhc *esdhc_regs;
@@ -95,7 +103,11 @@ struct fsl_esdhc_priv {
        struct mmc *mmc;
        struct udevice *dev;
        int non_removable;
+       int wp_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 +220,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 +233,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
 
                esdhc_clrsetbits32(&regs->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 +251,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(&regs->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(&regs->prsstat) &
+                           PRSSTAT_WPSPL) == 0) {
+                               printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
+                               return -ETIMEDOUT;
+                       }
                }
 
                esdhc_clrsetbits32(&regs->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");
@@ -312,7 +327,7 @@ static void check_and_invalidate_dcache_range
        unsigned end = 0;
        unsigned size = roundup(ARCH_DMA_MINALIGN,
                                data->blocks*data->blocksize);
-#ifdef CONFIG_FSL_LAYERSCAPE
+#if defined(CONFIG_FSL_LAYERSCAPE) || defined(CONFIG_S32V234)
        dma_addr_t addr;
 
        addr = virt_to_phys((void *)(data->dest));
@@ -398,12 +413,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
        irqstat = esdhc_read32(&regs->irqstat);
 
        if (irqstat & CMD_ERR) {
-               err = COMM_ERR;
+               err = -ECOMM;
                goto out;
        }
 
        if (irqstat & IRQSTAT_CTOE) {
-               err = TIMEOUT;
+               err = -ETIMEDOUT;
                goto out;
        }
 
@@ -429,7 +444,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;
                }
        }
@@ -458,12 +473,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
                        irqstat = esdhc_read32(&regs->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);
@@ -532,7 +547,7 @@ static void set_sysctl(struct mmc *mmc, uint clock)
        clk = (pre_div << 8) | (div << 4);
 
 #ifdef CONFIG_FSL_USDHC
-       esdhc_setbits32(&regs->sysctl, SYSCTL_RSTA);
+       esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_CKEN);
 #else
        esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
 #endif
@@ -542,7 +557,7 @@ static void set_sysctl(struct mmc *mmc, uint clock)
        udelay(10000);
 
 #ifdef CONFIG_FSL_USDHC
-       esdhc_clrbits32(&regs->sysctl, SYSCTL_RSTA);
+       esdhc_setbits32(&regs->vendorspec, VENDORSPEC_PEREN | VENDORSPEC_CKEN);
 #else
        esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_CKEN);
 #endif
@@ -579,7 +594,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;
@@ -601,6 +616,7 @@ static void esdhc_set_ios(struct mmc *mmc)
        else if (mmc->bus_width == 8)
                esdhc_setbits32(&regs->proctl, PROCTL_DTW_8);
 
+       return 0;
 }
 
 static int esdhc_init(struct mmc *mmc)
@@ -616,6 +632,20 @@ static int esdhc_init(struct mmc *mmc)
        while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
                udelay(1000);
 
+#if defined(CONFIG_FSL_USDHC)
+       /* RSTA doesn't reset MMC_BOOT register, so manually reset it */
+       esdhc_write32(&regs->mmcboot, 0x0);
+       /* Reset MIX_CTRL and CLK_TUNE_CTRL_STATUS regs to 0 */
+       esdhc_write32(&regs->mixctrl, 0x0);
+       esdhc_write32(&regs->clktunectrlstatus, 0x0);
+
+       /* Put VEND_SPEC to default value */
+       esdhc_write32(&regs->vendorspec, VENDORSPEC_INIT);
+
+       /* Disable DLL_CTRL delay line */
+       esdhc_write32(&regs->dllctrl, 0x0);
+#endif
+
 #ifndef ARCH_MXC
        /* Enable cache snooping */
        esdhc_write32(&regs->scr, 0x00000040);
@@ -623,6 +653,8 @@ static int esdhc_init(struct mmc *mmc)
 
 #ifndef CONFIG_FSL_USDHC
        esdhc_setbits32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
+#else
+       esdhc_setbits32(&regs->vendorspec, VENDORSPEC_HCKEN | VENDORSPEC_IPGEN);
 #endif
 
        /* Set the initial clock speed */
@@ -658,9 +690,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(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
@@ -699,6 +732,7 @@ static int fsl_esdhc_cfg_to_priv(struct fsl_esdhc_cfg *cfg,
        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;
 
        return 0;
 };
@@ -720,6 +754,9 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv)
 #ifndef CONFIG_FSL_USDHC
        esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN
                                | SYSCTL_IPGEN | SYSCTL_CKEN);
+#else
+       esdhc_setbits32(&regs->vendorspec, VENDORSPEC_PEREN |
+                       VENDORSPEC_HCKEN | VENDORSPEC_IPGEN | VENDORSPEC_CKEN);
 #endif
 
        writel(SDHCI_IRQ_EN_BITS, &regs->irqstaten);
@@ -875,17 +912,26 @@ 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
+       do_fixup_by_compat(blob, compat, "status", "okay",
+                          sizeof("okay"), 1);
+       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",
@@ -898,8 +944,6 @@ 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
 
@@ -934,10 +978,20 @@ static int fsl_esdhc_probe(struct udevice *dev)
                priv->non_removable = 1;
         } else {
                priv->non_removable = 0;
+#ifdef CONFIG_DM_GPIO
                gpio_request_by_name_nodev(fdt, 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(fdt, node, "wp-gpios", 0,
+                                        &priv->wp_gpio, GPIOD_IS_IN);
+       if (ret)
+               priv->wp_enable = 0;
+#endif
        /*
         * TODO:
         * Because lack of clk driver, if SDHC clk is not enabled,
@@ -970,6 +1024,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
        }
 
        upriv->mmc = priv->mmc;
+       priv->mmc->dev = dev;
 
        return 0;
 }
@@ -980,6 +1035,7 @@ static const struct udevice_id fsl_esdhc_ids[] = {
        { .compatible = "fsl,imx6sl-usdhc", },
        { .compatible = "fsl,imx6q-usdhc", },
        { .compatible = "fsl,imx7d-usdhc", },
+       { .compatible = "fsl,esdhc", },
        { /* sentinel */ }
 };