]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mmc: fsl_esdhc: add ADMA2 support
authorMichael Walle <michael@walle.cc>
Mon, 12 Oct 2020 08:07:14 +0000 (10:07 +0200)
committerPeng Fan <peng.fan@nxp.com>
Wed, 14 Oct 2020 06:00:44 +0000 (14:00 +0800)
Newer eSDHC controllers support ADMA2 descriptor tables which support
64bit DMA addresses. One notable user of addresses in the upper memory
segment is the EFI loader.

If support is enabled, but the controller doesn't support ADMA2, we
will fall back to SDMA (and thus 32 bit DMA addresses only).

Signed-off-by: Michael Walle <michael@walle.cc>
drivers/mmc/Kconfig
drivers/mmc/fsl_esdhc.c
include/fsl_esdhc.h

index 88582db58c9341ea06fef2e54c3bb3a993a29f24..14d79139864abc2c2b1856924fe667fab5bdf906 100644 (file)
@@ -755,6 +755,14 @@ config FSL_ESDHC
          This selects support for the eSDHC (Enhanced Secure Digital Host
          Controller) found on numerous Freescale/NXP SoCs.
 
+config FSL_ESDHC_SUPPORT_ADMA2
+       bool "enable ADMA2 support"
+       depends on FSL_ESDHC
+       select MMC_SDHCI_ADMA_HELPERS
+       help
+         This enables support for the ADMA2 transfer mode. If supported by the
+         eSDHC it will allow 64bit DMA addresses.
+
 config FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND
        bool "enable eSDHC workaround for 3.3v IO reliability issue"
        depends on FSL_ESDHC && DM_MMC
index 15f8175660f7fbc82b0881aa0eb501b454e64155..642784e1f350930b783168d5411cb4f25b0023c7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <sdhci.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -52,8 +53,9 @@ struct fsl_esdhc {
        char    reserved1[8];   /* reserved */
        uint    fevt;           /* Force event register */
        uint    admaes;         /* ADMA error status register */
-       uint    adsaddr;        /* ADMA system address register */
-       char    reserved2[160];
+       uint    adsaddrl;       /* ADMA system address low register */
+       uint    adsaddrh;       /* ADMA system address high register */
+       char    reserved2[156];
        uint    hostver;        /* Host controller version register */
        char    reserved3[4];   /* reserved */
        uint    dmaerraddr;     /* DMA error address register */
@@ -99,6 +101,7 @@ struct fsl_esdhc_priv {
        struct mmc *mmc;
 #endif
        struct udevice *dev;
+       struct sdhci_adma_desc *adma_desc_table;
        dma_addr_t dma_addr;
 };
 
@@ -228,6 +231,7 @@ static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data)
 {
        uint trans_bytes = data->blocksize * data->blocks;
        struct fsl_esdhc *regs = priv->esdhc_regs;
+       phys_addr_t adma_addr;
        void *buf;
 
        if (data->flags & MMC_DATA_WRITE)
@@ -237,9 +241,29 @@ static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data)
 
        priv->dma_addr = dma_map_single(buf, trans_bytes,
                                        mmc_get_dma_dir(data));
-       if (upper_32_bits(priv->dma_addr))
-               printf("Cannot use 64 bit addresses with SDMA\n");
-       esdhc_write32(&regs->dsaddr, lower_32_bits(priv->dma_addr));
+
+       if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2) &&
+           priv->adma_desc_table) {
+               debug("Using ADMA2\n");
+               /* prefer ADMA2 if it is available */
+               sdhci_prepare_adma_table(priv->adma_desc_table, data,
+                                        priv->dma_addr);
+
+               adma_addr = virt_to_phys(priv->adma_desc_table);
+               esdhc_write32(&regs->adsaddrl, lower_32_bits(adma_addr));
+               if (IS_ENABLED(CONFIG_DMA_ADDR_T_64BIT))
+                       esdhc_write32(&regs->adsaddrh, upper_32_bits(adma_addr));
+               esdhc_clrsetbits32(&regs->proctl, PROCTL_DMAS_MASK,
+                                  PROCTL_DMAS_ADMA2);
+       } else {
+               debug("Using SDMA\n");
+               if (upper_32_bits(priv->dma_addr))
+                       printf("Cannot use 64 bit addresses with SDMA\n");
+               esdhc_write32(&regs->dsaddr, lower_32_bits(priv->dma_addr));
+               esdhc_clrsetbits32(&regs->proctl, PROCTL_DMAS_MASK,
+                                  PROCTL_DMAS_SDMA);
+       }
+
        esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
 }
 
@@ -911,6 +935,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
        struct fsl_esdhc_plat *plat = dev_get_platdata(dev);
        struct fsl_esdhc_priv *priv = dev_get_priv(dev);
+       u32 caps, hostver;
        fdt_addr_t addr;
        struct mmc *mmc;
        int ret;
@@ -925,6 +950,21 @@ static int fsl_esdhc_probe(struct udevice *dev)
 #endif
        priv->dev = dev;
 
+       if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2)) {
+               /*
+                * Only newer eSDHC controllers can do ADMA2 if the ADMA flag
+                * is set in the host capabilities register.
+                */
+               caps = esdhc_read32(&priv->esdhc_regs->hostcapblt);
+               hostver = esdhc_read32(&priv->esdhc_regs->hostver);
+               if (caps & HOSTCAPBLT_DMAS &&
+                   HOSTVER_VENDOR(hostver) > VENDOR_V_22) {
+                       priv->adma_desc_table = sdhci_adma_init();
+                       if (!priv->adma_desc_table)
+                               debug("Could not allocate ADMA tables, falling back to SDMA\n");
+               }
+       }
+
        if (gd->arch.sdhc_per_clk) {
                priv->sdhc_clk = gd->arch.sdhc_per_clk;
                priv->is_sdhc_per_clk = true;
index cc119668d6a380ca0a41ef68d303c5ec7ed4a230..e6f1c75e27ca8ed471cae1915ef55648223a5080 100644 (file)
 #define PROCTL_DTW_4           0x00000002
 #define PROCTL_DTW_8           0x00000004
 #define PROCTL_D3CD            0x00000008
+#define PROCTL_DMAS_MASK       0x00000300
+#define PROCTL_DMAS_SDMA       0x00000000
+#define PROCTL_DMAS_ADMA1      0x00000100
+#define PROCTL_DMAS_ADMA2      0x00000300
 #define PROCTL_VOLT_SEL                0x00000400
 
 #define CMDARG                 0x0002e008
 
 #define MAX_TUNING_LOOP                40
 
+#define HOSTVER_VENDOR(x)      (((x) >> 8) & 0xff)
+#define VENDOR_V_10            0x00
+#define VENDOR_V_20            0x10
+#define VENDOR_V_21            0x11
+#define VENDOR_V_22            0x12
+#define VENDOR_V_23            0x13
+#define VENDOR_V_30            0x20
+#define VENDOR_V_31            0x21
+#define VENDOR_V_32            0x22
+
 struct fsl_esdhc_cfg {
        phys_addr_t esdhc_base;
        u32     sdhc_clk;