diff options
-rw-r--r-- | arch/arm/dts/fsl-lx2160a-rdb.dts | 2 | ||||
-rw-r--r-- | configs/lx2160ardb_tfa_SECURE_BOOT_defconfig | 1 | ||||
-rw-r--r-- | configs/lx2160ardb_tfa_defconfig | 1 | ||||
-rw-r--r-- | configs/lx2160ardb_tfa_stmm_defconfig | 1 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 439 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 71 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 30 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 18 | ||||
-rw-r--r-- | drivers/mmc/sdhci-adma.c | 73 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 63 | ||||
-rw-r--r-- | drivers/mmc/sh_sdhi.c | 3 | ||||
-rw-r--r-- | include/fsl_esdhc.h | 43 | ||||
-rw-r--r-- | include/mmc.h | 26 | ||||
-rw-r--r-- | include/sdhci.h | 8 |
16 files changed, 556 insertions, 237 deletions
diff --git a/arch/arm/dts/fsl-lx2160a-rdb.dts b/arch/arm/dts/fsl-lx2160a-rdb.dts index d787778de84..5fbdd907017 100644 --- a/arch/arm/dts/fsl-lx2160a-rdb.dts +++ b/arch/arm/dts/fsl-lx2160a-rdb.dts @@ -80,6 +80,8 @@ &esdhc1 { status = "okay"; mmc-hs200-1_8v; + mmc-hs400-1_8v; + bus-width = <8>; }; &fspi { diff --git a/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig b/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig index 5e30890d487..159ae9d97f1 100644 --- a/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig +++ b/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig @@ -41,6 +41,7 @@ CONFIG_DM_I2C=y CONFIG_I2C_SET_DEFAULT_BUS_NUM=y CONFIG_I2C_DEFAULT_BUS_NUMBER=0 CONFIG_DM_MMC=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_FSL_ESDHC=y CONFIG_MTD=y CONFIG_DM_SPI_FLASH=y diff --git a/configs/lx2160ardb_tfa_defconfig b/configs/lx2160ardb_tfa_defconfig index 702122318e6..8a4e6efc90b 100644 --- a/configs/lx2160ardb_tfa_defconfig +++ b/configs/lx2160ardb_tfa_defconfig @@ -48,6 +48,7 @@ CONFIG_DM_I2C=y CONFIG_I2C_SET_DEFAULT_BUS_NUM=y CONFIG_I2C_DEFAULT_BUS_NUMBER=0 CONFIG_DM_MMC=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_FSL_ESDHC=y CONFIG_MTD=y CONFIG_DM_SPI_FLASH=y diff --git a/configs/lx2160ardb_tfa_stmm_defconfig b/configs/lx2160ardb_tfa_stmm_defconfig index b0dc3c0edee..bd9c1e9bf0d 100644 --- a/configs/lx2160ardb_tfa_stmm_defconfig +++ b/configs/lx2160ardb_tfa_stmm_defconfig @@ -49,6 +49,7 @@ CONFIG_DM_I2C=y CONFIG_I2C_SET_DEFAULT_BUS_NUM=y CONFIG_I2C_DEFAULT_BUS_NUMBER=0 CONFIG_DM_MMC=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_FSL_ESDHC=y CONFIG_MTD=y diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 0c252e34c74..14d79139864 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,9 @@ config SPL_DM_MMC if MMC +config MMC_SDHCI_ADMA_HELPERS + bool + config MMC_SPI bool "Support for SPI-based MMC controller" depends on DM_MMC && DM_SPI @@ -445,6 +448,7 @@ config MMC_SDHCI_SDMA config MMC_SDHCI_ADMA bool "Support SDHCI ADMA2" depends on MMC_SDHCI + select MMC_SDHCI_ADMA_HELPERS help This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 @@ -452,6 +456,7 @@ config MMC_SDHCI_ADMA config SPL_MMC_SDHCI_ADMA bool "Support SDHCI ADMA2 in SPL" depends on MMC_SDHCI + select MMC_SDHCI_ADMA_HELPERS help This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 in SPL. @@ -750,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 diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 22266ec8ece..1c849cbab2f 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -6,6 +6,7 @@ obj-y += mmc.o obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o +obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o ifndef CONFIG_$(SPL_)BLK obj-y += mmc_legacy.o diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index de9fe01bc5c..642784e1f35 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -26,6 +26,8 @@ #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <sdhci.h> DECLARE_GLOBAL_DATA_PTR; @@ -51,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 */ @@ -60,7 +63,14 @@ struct fsl_esdhc { uint dmaerrattr; /* DMA error attribute register */ char reserved5[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ - char reserved6[756]; /* reserved */ + char reserved6[8]; /* reserved */ + uint tbctl; /* Tuning block control register */ + char reserved7[32]; /* reserved */ + uint sdclkctl; /* SD clock control register */ + uint sdtimingctl; /* SD timing control register */ + char reserved8[20]; /* reserved */ + uint dllcfg0; /* DLL config 0 register */ + char reserved9[680]; /* reserved */ uint esdhcctl; /* eSDHC control register */ }; @@ -91,6 +101,8 @@ struct fsl_esdhc_priv { struct mmc *mmc; #endif struct udevice *dev; + struct sdhci_adma_desc *adma_desc_table; + dma_addr_t dma_addr; }; /* Return the XFERTYP flags for a given command and data packet */ @@ -100,15 +112,15 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) if (data) { xfertyp |= XFERTYP_DPSEL; -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - xfertyp |= XFERTYP_DMAEN; -#endif + if (!IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO) && + cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK && + cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200) + xfertyp |= XFERTYP_DMAEN; if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; xfertyp |= XFERTYP_BCEN; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 - xfertyp |= XFERTYP_AC12EN; -#endif + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC111)) + xfertyp |= XFERTYP_AC12EN; } if (data->flags & MMC_DATA_READ) @@ -132,7 +144,6 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO /* * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. */ @@ -195,66 +206,83 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, } } } -#endif -static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, - struct mmc_data *data) +static void esdhc_setup_watermark_level(struct fsl_esdhc_priv *priv, + struct mmc_data *data) { - int timeout; struct fsl_esdhc *regs = priv->esdhc_regs; -#if defined(CONFIG_FSL_LAYERSCAPE) - dma_addr_t addr; -#endif - uint wml_value; - - wml_value = data->blocksize/4; + uint wml_value = data->blocksize / 4; if (data->flags & MMC_DATA_READ) { if (wml_value > WML_RD_WML_MAX) wml_value = WML_RD_WML_MAX_VAL; esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#if defined(CONFIG_FSL_LAYERSCAPE) - addr = virt_to_phys((void *)(data->dest)); - if (upper_32_bits(addr)) - printf("Error found for upper 32 bits\n"); - else - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); -#else - esdhc_write32(®s->dsaddr, (u32)data->dest); -#endif -#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)) { - printf("Can not write to locked SD card.\n"); - return -EINVAL; - } - esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, - wml_value << 16); -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#if defined(CONFIG_FSL_LAYERSCAPE) - addr = virt_to_phys((void *)(data->src)); - if (upper_32_bits(addr)) - printf("Error found for upper 32 bits\n"); - else - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); -#else - esdhc_write32(®s->dsaddr, (u32)data->src); -#endif -#endif + wml_value << 16); + } +} + +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) + buf = (void *)data->src; + else + buf = data->dest; + + priv->dma_addr = dma_map_single(buf, trans_bytes, + mmc_get_dma_dir(data)); + + 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(®s->adsaddrl, lower_32_bits(adma_addr)); + if (IS_ENABLED(CONFIG_DMA_ADDR_T_64BIT)) + esdhc_write32(®s->adsaddrh, upper_32_bits(adma_addr)); + esdhc_clrsetbits32(®s->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(®s->dsaddr, lower_32_bits(priv->dma_addr)); + esdhc_clrsetbits32(®s->proctl, PROCTL_DMAS_MASK, + PROCTL_DMAS_SDMA); } esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); +} + +static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, + struct mmc_data *data) +{ + int timeout; + bool is_write = data->flags & MMC_DATA_WRITE; + struct fsl_esdhc *regs = priv->esdhc_regs; + + if (is_write && !(esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL)) { + printf("Can not write to locked SD card.\n"); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO)) + esdhc_setup_watermark_level(priv, data); + else + esdhc_setup_dma(priv, data); /* Calculate the timeout period for data transactions */ /* @@ -287,41 +315,18 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, if (timeout < 0) timeout = 0; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 - if ((timeout == 4) || (timeout == 8) || (timeout == 12)) + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC_A001) && + (timeout == 4 || timeout == 8 || timeout == 12)) timeout++; -#endif -#ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE - timeout = 0xE; -#endif + if (IS_ENABLED(ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE)) + timeout = 0xE; + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; } -static void check_and_invalidate_dcache_range - (struct mmc_cmd *cmd, - struct mmc_data *data) { - unsigned start = 0; - unsigned end = 0; - unsigned size = roundup(ARCH_DMA_MINALIGN, - data->blocks*data->blocksize); -#if defined(CONFIG_FSL_LAYERSCAPE) - dma_addr_t addr; - - addr = virt_to_phys((void *)(data->dest)); - if (upper_32_bits(addr)) - 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); -} - /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. @@ -336,10 +341,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, struct fsl_esdhc *regs = priv->esdhc_regs; unsigned long start; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC111) && + cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) return 0; -#endif esdhc_write32(®s->irqstat, -1); @@ -365,9 +369,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = esdhc_setup_data(priv, mmc, data); if(err) return err; - - if (data->flags & MMC_DATA_READ) - check_and_invalidate_dcache_range(cmd, data); } /* Figure out the transfer arguments */ @@ -380,6 +381,10 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_write32(®s->cmdarg, cmd->cmdarg); esdhc_write32(®s->xfertyp, xfertyp); + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + flags = IRQSTAT_BRR; + /* Wait for the command to complete */ start = get_timer(0); while (!(esdhc_read32(®s->irqstat) & flags)) { @@ -436,32 +441,37 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, /* Wait until all of the blocks are transferred */ if (data) { -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO - esdhc_pio_read_write(priv, data); -#else - do { - irqstat = esdhc_read32(®s->irqstat); - - if (irqstat & IRQSTAT_DTOE) { - err = -ETIMEDOUT; - goto out; - } + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO)) { + esdhc_pio_read_write(priv, data); + } else { + flags = DATA_COMPLETE; + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + flags = IRQSTAT_BRR; + + do { + irqstat = esdhc_read32(®s->irqstat); - if (irqstat & DATA_ERR) { - err = -ECOMM; - goto out; - } - } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); + if (irqstat & IRQSTAT_DTOE) { + err = -ETIMEDOUT; + goto out; + } - /* - * Need invalidate the dcache here again to avoid any - * cache-fill during the DMA operations such as the - * speculative pre-fetching etc. - */ - if (data->flags & MMC_DATA_READ) { - check_and_invalidate_dcache_range(cmd, data); + if (irqstat & DATA_ERR) { + err = -ECOMM; + goto out; + } + } while ((irqstat & flags) != flags); + + /* + * Need invalidate the dcache here again to avoid any + * cache-fill during the DMA operations such as the + * speculative pre-fetching etc. + */ + dma_unmap_single(priv->dma_addr, + data->blocks * data->blocksize, + mmc_get_dma_dir(data)); } -#endif } out: @@ -505,6 +515,9 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) while (sdhc_clk / (div * pre_div) > clock && div < 16) div++; + mmc->clock = sdhc_clk / pre_div / div; + priv->clock = mmc->clock; + pre_div >>= 1; div -= 1; @@ -555,6 +568,86 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) } } +static void esdhc_flush_async_fifo(struct fsl_esdhc_priv *priv) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + u32 time_out; + + esdhc_setbits32(®s->esdhcctl, ESDHCCTL_FAF); + + time_out = 20; + while (esdhc_read32(®s->esdhcctl) & ESDHCCTL_FAF) { + if (time_out == 0) { + printf("fsl_esdhc: Flush asynchronous FIFO timeout.\n"); + break; + } + time_out--; + mdelay(1); + } +} + +static void esdhc_tuning_block_enable(struct fsl_esdhc_priv *priv, + bool en) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + + esdhc_clock_control(priv, false); + esdhc_flush_async_fifo(priv); + if (en) + esdhc_setbits32(®s->tbctl, TBCTL_TB_EN); + else + esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN); + esdhc_clock_control(priv, true); +} + +static void esdhc_exit_hs400(struct fsl_esdhc_priv *priv) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + + esdhc_clrbits32(®s->sdtimingctl, FLW_CTL_BG); + esdhc_clrbits32(®s->sdclkctl, CMD_CLK_CTL); + + esdhc_clock_control(priv, false); + esdhc_clrbits32(®s->tbctl, HS400_MODE); + esdhc_clock_control(priv, true); + + esdhc_clrbits32(®s->dllcfg0, DLL_FREQ_SEL | DLL_ENABLE); + esdhc_clrbits32(®s->tbctl, HS400_WNDW_ADJUST); + + esdhc_tuning_block_enable(priv, false); +} + +static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + + /* Exit HS400 mode before setting any other mode */ + if (esdhc_read32(®s->tbctl) & HS400_MODE && + mode != MMC_HS_400) + esdhc_exit_hs400(priv); + + esdhc_clock_control(priv, false); + + if (mode == MMC_HS_200) + esdhc_clrsetbits32(®s->autoc12err, UHSM_MASK, + UHSM_SDR104_HS200); + if (mode == MMC_HS_400) { + esdhc_setbits32(®s->tbctl, HS400_MODE); + esdhc_setbits32(®s->sdclkctl, CMD_CLK_CTL); + esdhc_clock_control(priv, true); + + if (priv->clock == 200000000) + esdhc_setbits32(®s->dllcfg0, DLL_FREQ_SEL); + + esdhc_setbits32(®s->dllcfg0, DLL_ENABLE); + esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST); + + esdhc_clock_control(priv, false); + esdhc_flush_async_fifo(priv); + } + esdhc_clock_control(priv, true); +} + static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) { struct fsl_esdhc *regs = priv->esdhc_regs; @@ -566,10 +659,16 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) esdhc_clock_control(priv, true); } + if (mmc->selected_mode == MMC_HS_400) + esdhc_tuning_block_enable(priv, true); + /* Set the clock speed */ if (priv->clock != mmc->clock) set_sysctl(priv, mmc, mmc->clock); + /* Set timing */ + esdhc_set_timing(priv, mmc->selected_mode); + /* Set the bus width */ esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); @@ -608,6 +707,9 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) return -ETIMEDOUT; } + /* Clean TBCTL[TB_EN] which is not able to be reset by reset all */ + esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN); + esdhc_enable_cache_snooping(regs); esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); @@ -648,12 +750,10 @@ static void fsl_esdhc_get_cfg_common(struct fsl_esdhc_priv *priv, u32 caps; caps = esdhc_read32(®s->hostcapblt); -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 - caps &= ~(HOSTCAPBLT_SRS | HOSTCAPBLT_VS18 | HOSTCAPBLT_VS30); -#endif -#ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 - caps |= HOSTCAPBLT_VS33; -#endif + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC135)) + caps &= ~(HOSTCAPBLT_SRS | HOSTCAPBLT_VS18 | HOSTCAPBLT_VS30); + if (IS_ENABLED(CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33)) + caps |= HOSTCAPBLT_VS33; if (caps & HOSTCAPBLT_VS18) cfg->voltages |= MMC_VDD_165_195; if (caps & HOSTCAPBLT_VS30) @@ -674,19 +774,18 @@ static void fsl_esdhc_get_cfg_common(struct fsl_esdhc_priv *priv, #ifdef CONFIG_OF_LIBFDT __weak int esdhc_status_fixup(void *blob, const char *compat) { -#ifdef CONFIG_FSL_ESDHC_PIN_MUX - if (!hwconfig("esdhc")) { + if (IS_ENABLED(CONFIG_FSL_ESDHC_PIN_MUX) && !hwconfig("esdhc")) { do_fixup_by_compat(blob, compat, "status", "disabled", sizeof("disabled"), 1); return 1; } -#endif + return 0; } -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND -static int fsl_esdhc_get_cd(struct udevice *dev); +#if CONFIG_IS_ENABLED(DM_MMC) +static int fsl_esdhc_get_cd(struct udevice *dev); static void esdhc_disable_for_no_card(void *blob) { struct udevice *dev; @@ -705,6 +804,10 @@ static void esdhc_disable_for_no_card(void *blob) sizeof("disabled"), 1); } } +#else +static void esdhc_disable_for_no_card(void *blob) +{ +} #endif void fdt_fixup_esdhc(void *blob, struct bd_info *bd) @@ -713,9 +816,10 @@ void fdt_fixup_esdhc(void *blob, struct bd_info *bd) if (esdhc_status_fixup(blob, compat)) return; -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND - esdhc_disable_for_no_card(blob); -#endif + + if (IS_ENABLED(CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND)) + esdhc_disable_for_no_card(blob); + do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->arch.sdhc_clk, 1); } @@ -797,10 +901,9 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) printf("No max bus width provided. Assume 8-bit supported.\n"); } -#ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK - if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) + if (IS_ENABLED(CONFIG_ESDHC_DETECT_8_BIT_QUIRK)) mmc_cfg->host_caps &= ~MMC_MODE_8BIT; -#endif + mmc_cfg->ops = &esdhc_ops; fsl_esdhc_get_cfg_common(priv, mmc_cfg); @@ -832,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; @@ -846,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; @@ -872,10 +991,10 @@ static int fsl_esdhc_probe(struct udevice *dev) if (ret) return ret; -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND - if (!fsl_esdhc_get_cd(dev)) + if (IS_ENABLED(CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND) && + !fsl_esdhc_get_cd(dev)) esdhc_setbits32(&priv->esdhc_regs->proctl, PROCTL_VOLT_SEL); -#endif + return 0; } @@ -907,6 +1026,64 @@ static int fsl_esdhc_set_ios(struct udevice *dev) return esdhc_set_ios_common(priv, &plat->mmc); } +static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_platdata(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + return esdhc_init_common(priv, &plat->mmc); +} + +#ifdef MMC_SUPPORTS_TUNING +static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) +{ + struct fsl_esdhc_plat *plat = dev_get_platdata(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + struct fsl_esdhc *regs = priv->esdhc_regs; + u32 val, irqstaten; + int i; + + esdhc_tuning_block_enable(priv, true); + esdhc_setbits32(®s->autoc12err, EXECUTE_TUNING); + + irqstaten = esdhc_read32(®s->irqstaten); + esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); + + for (i = 0; i < MAX_TUNING_LOOP; i++) { + mmc_send_tuning(&plat->mmc, opcode, NULL); + mdelay(1); + + val = esdhc_read32(®s->autoc12err); + if (!(val & EXECUTE_TUNING)) { + if (val & SMPCLKSEL) + break; + } + } + + esdhc_write32(®s->irqstaten, irqstaten); + + if (i != MAX_TUNING_LOOP) { + if (plat->mmc.hs400_tuning) + esdhc_setbits32(®s->sdtimingctl, FLW_CTL_BG); + return 0; + } + + printf("fsl_esdhc: tuning failed!\n"); + esdhc_clrbits32(®s->autoc12err, SMPCLKSEL); + esdhc_clrbits32(®s->autoc12err, EXECUTE_TUNING); + esdhc_tuning_block_enable(priv, false); + return -ETIMEDOUT; +} +#endif + +int fsl_esdhc_hs400_prepare_ddr(struct udevice *dev) +{ + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + esdhc_tuning_block_enable(priv, false); + return 0; +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -914,6 +1091,8 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = fsl_esdhc_execute_tuning, #endif + .reinit = fsl_esdhc_reinit, + .hs400_prepare_ddr = fsl_esdhc_hs400_prepare_ddr, }; static const struct udevice_id fsl_esdhc_ids[] = { diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 0c866b168f9..1c015ab7646 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -462,13 +462,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) ; - /* Wait at least 8 SD clock cycles before the next command */ - /* - * Note: This is way more than 8 cycles, but 1ms seems to - * resolve timing issues with some cards - */ - udelay(1000); - /* Set up for a data transfer if we have one */ if (data) { err = esdhc_setup_data(priv, mmc, data); @@ -729,7 +722,7 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) u32 val; if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) { - writel(ESDHC_STROBE_DLL_CTRL_RESET, ®s->strobe_dllctrl); + esdhc_write32(®s->strobe_dllctrl, ESDHC_STROBE_DLL_CTRL_RESET); /* * enable strobe dll ctrl and adjust the delay target @@ -738,10 +731,10 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) val = ESDHC_STROBE_DLL_CTRL_ENABLE | (priv->strobe_dll_delay_target << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); - writel(val, ®s->strobe_dllctrl); + esdhc_write32(®s->strobe_dllctrl, val); /* wait 1us to make sure strobe dll status register stable */ mdelay(1); - val = readl(®s->strobe_dllstat); + val = esdhc_read32(®s->strobe_dllstat); if (!(val & ESDHC_STROBE_DLL_STS_REF_LOCK)) pr_warn("HS400 strobe DLL status REF not lock!\n"); if (!(val & ESDHC_STROBE_DLL_STS_SLV_LOCK)) @@ -755,18 +748,18 @@ static int esdhc_set_timing(struct mmc *mmc) struct fsl_esdhc *regs = priv->esdhc_regs; u32 mixctrl; - mixctrl = readl(®s->mixctrl); + mixctrl = esdhc_read32(®s->mixctrl); mixctrl &= ~(MIX_CTRL_DDREN | MIX_CTRL_HS400_EN); switch (mmc->selected_mode) { case MMC_LEGACY: esdhc_reset_tuning(mmc); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; case MMC_HS_400: case MMC_HS_400_ES: mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN; - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); esdhc_set_strobe_dll(mmc); break; case MMC_HS: @@ -777,12 +770,12 @@ static int esdhc_set_timing(struct mmc *mmc) case UHS_SDR25: case UHS_SDR50: case UHS_SDR104: - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; case UHS_DDR50: case MMC_DDR_52: mixctrl |= MIX_CTRL_DDREN; - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; default: printf("Not supported %d\n", mmc->selected_mode); @@ -862,8 +855,8 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) struct fsl_esdhc_priv *priv = dev_get_priv(dev); struct fsl_esdhc *regs = priv->esdhc_regs; struct mmc *mmc = &plat->mmc; - u32 irqstaten = readl(®s->irqstaten); - u32 irqsigen = readl(®s->irqsigen); + u32 irqstaten = esdhc_read32(®s->irqstaten); + u32 irqsigen = esdhc_read32(®s->irqsigen); int i, ret = -ETIMEDOUT; u32 val, mixctrl; @@ -873,25 +866,25 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) /* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ if (priv->flags & ESDHC_FLAG_STD_TUNING) { - val = readl(®s->autoc12err); - mixctrl = readl(®s->mixctrl); + val = esdhc_read32(®s->autoc12err); + mixctrl = esdhc_read32(®s->mixctrl); val &= ~MIX_CTRL_SMPCLK_SEL; mixctrl &= ~(MIX_CTRL_FBCLK_SEL | MIX_CTRL_AUTO_TUNE_EN); val |= MIX_CTRL_EXE_TUNE; mixctrl |= MIX_CTRL_FBCLK_SEL | MIX_CTRL_AUTO_TUNE_EN; - writel(val, ®s->autoc12err); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->autoc12err, val); + esdhc_write32(®s->mixctrl, mixctrl); } /* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); */ - mixctrl = readl(®s->mixctrl); + mixctrl = esdhc_read32(®s->mixctrl); mixctrl = MIX_CTRL_DTDSEL_READ | (mixctrl & ~MIX_CTRL_SDHCI_MASK); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); - writel(IRQSTATEN_BRR, ®s->irqstaten); - writel(IRQSTATEN_BRR, ®s->irqsigen); + esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); + esdhc_write32(®s->irqsigen, IRQSTATEN_BRR); /* * Issue opcode repeatedly till Execute Tuning is set to 0 or the number @@ -902,22 +895,22 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200) { if (mmc->bus_width == 8) - writel(0x7080, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7080); else if (mmc->bus_width == 4) - writel(0x7040, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7040); } else { - writel(0x7040, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7040); } /* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE) */ - val = readl(®s->mixctrl); + val = esdhc_read32(®s->mixctrl); val = MIX_CTRL_DTDSEL_READ | (val & ~MIX_CTRL_SDHCI_MASK); - writel(val, ®s->mixctrl); + esdhc_write32(®s->mixctrl, val); /* We are using STD tuning, no need to check return value */ mmc_send_tuning(mmc, opcode, NULL); - ctrl = readl(®s->autoc12err); + ctrl = esdhc_read32(®s->autoc12err); if ((!(ctrl & MIX_CTRL_EXE_TUNE)) && (ctrl & MIX_CTRL_SMPCLK_SEL)) { ret = 0; @@ -925,8 +918,8 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) } } - writel(irqstaten, ®s->irqstaten); - writel(irqsigen, ®s->irqsigen); + esdhc_write32(®s->irqstaten, irqstaten); + esdhc_write32(®s->irqsigen, irqsigen); esdhc_stop_tuning(mmc); @@ -1179,7 +1172,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, if (priv->vs18_enable) esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); - writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); + esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; #ifndef CONFIG_DM_MMC memset(cfg, '\0', sizeof(*cfg)); @@ -1260,10 +1253,10 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - writel(0, ®s->dllctrl); + esdhc_write32(®s->dllctrl, 0); if (priv->flags & ESDHC_FLAG_USDHC) { if (priv->flags & ESDHC_FLAG_STD_TUNING) { - u32 val = readl(®s->tuning_ctrl); + u32 val = esdhc_read32(®s->tuning_ctrl); val |= ESDHC_STD_TUNING_EN; val &= ~ESDHC_TUNING_START_TAP_MASK; @@ -1282,7 +1275,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, * after the whole tuning procedure always can't get any response. */ val |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; - writel(val, ®s->tuning_ctrl); + esdhc_write32(®s->tuning_ctrl, val); } } @@ -1648,9 +1641,9 @@ static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev) struct fsl_esdhc *regs = priv->esdhc_regs; u32 m; - m = readl(®s->mixctrl); + m = esdhc_read32(®s->mixctrl); m |= MIX_CTRL_HS400_ES; - writel(m, ®s->mixctrl); + esdhc_write32(®s->mixctrl, m); return 0; } diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 90690c8d1e3..ec59bcd8566 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -142,6 +142,21 @@ int mmc_set_enhanced_strobe(struct mmc *mmc) } #endif +int dm_mmc_hs400_prepare_ddr(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->hs400_prepare_ddr) + return ops->hs400_prepare_ddr(dev); + + return 0; +} + +int mmc_hs400_prepare_ddr(struct mmc *mmc) +{ + return dm_mmc_hs400_prepare_ddr(mmc->dev); +} + int dm_mmc_host_power_cycle(struct udevice *dev) { struct dm_mmc_ops *ops = mmc_get_ops(dev); @@ -171,6 +186,21 @@ int mmc_deferred_probe(struct mmc *mmc) return dm_mmc_deferred_probe(mmc->dev); } +int dm_mmc_reinit(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->reinit) + return ops->reinit(dev); + + return 0; +} + +int mmc_reinit(struct mmc *mmc) +{ + return dm_mmc_reinit(mmc->dev); +} + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 11ce110df3e..c46fa4efc5a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -805,8 +805,10 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, * capable of polling by using mmc_wait_dat0, then rely on waiting the * stated timeout to be sufficient. */ - if (ret == -ENOSYS && !send_status) + if (ret == -ENOSYS && !send_status) { mdelay(timeout_ms); + return 0; + } /* Finally wait until the card is ready or indicates a failure * to switch. It doesn't hurt to use CMD13 here even if send_status @@ -1982,7 +1984,9 @@ static int mmc_select_hs400(struct mmc *mmc) mmc_set_clock(mmc, mmc->tran_speed, false); /* execute tuning if needed */ + mmc->hs400_tuning = 1; err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); + mmc->hs400_tuning = 0; if (err) { debug("tuning failed\n"); return err; @@ -1991,6 +1995,10 @@ static int mmc_select_hs400(struct mmc *mmc) /* Set back to HS */ mmc_set_card_speed(mmc, MMC_HS, true); + err = mmc_hs400_prepare_ddr(mmc); + if (err) + return err; + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG); if (err) @@ -2816,13 +2824,17 @@ int mmc_get_op_cond(struct mmc *mmc) return err; #if CONFIG_IS_ENABLED(DM_MMC) - /* The device has already been probed ready for use */ + /* + * Re-initialization is needed to clear old configuration for + * mmc rescan. + */ + err = mmc_reinit(mmc); #else /* made sure it's not NULL earlier */ err = mmc->cfg->ops->init(mmc); +#endif if (err) return err; -#endif mmc->ddr_mode = 0; retry: diff --git a/drivers/mmc/sdhci-adma.c b/drivers/mmc/sdhci-adma.c new file mode 100644 index 00000000000..2ec057fbb19 --- /dev/null +++ b/drivers/mmc/sdhci-adma.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SDHCI ADMA2 helper functions. + */ + +#include <common.h> +#include <cpu_func.h> +#include <sdhci.h> +#include <malloc.h> +#include <asm/cache.h> + +static void sdhci_adma_desc(struct sdhci_adma_desc *desc, + dma_addr_t addr, u16 len, bool end) +{ + u8 attr; + + attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + if (end) + attr |= ADMA_DESC_ATTR_END; + + desc->attr = attr; + desc->len = len; + desc->reserved = 0; + desc->addr_lo = lower_32_bits(addr); +#ifdef CONFIG_DMA_ADDR_T_64BIT + desc->addr_hi = upper_32_bits(addr); +#endif +} + +/** + * sdhci_prepare_adma_table() - Populate the ADMA table + * + * @table: Pointer to the ADMA table + * @data: Pointer to MMC data + * @addr: DMA address to write to or read from + * + * Fill the ADMA table according to the MMC data to read from or write to the + * given DMA address. + * Please note, that the table size depends on CONFIG_SYS_MMC_MAX_BLK_COUNT and + * we don't have to check for overflow. + */ +void sdhci_prepare_adma_table(struct sdhci_adma_desc *table, + struct mmc_data *data, dma_addr_t addr) +{ + uint trans_bytes = data->blocksize * data->blocks; + uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); + struct sdhci_adma_desc *desc = table; + int i = desc_count; + + while (--i) { + sdhci_adma_desc(desc, addr, ADMA_MAX_LEN, false); + addr += ADMA_MAX_LEN; + trans_bytes -= ADMA_MAX_LEN; + desc++; + } + + sdhci_adma_desc(desc, addr, trans_bytes, true); + + flush_cache((dma_addr_t)table, + ROUND(desc_count * sizeof(struct sdhci_adma_desc), + ARCH_DMA_MINALIGN)); +} + +/** + * sdhci_adma_init() - initialize the ADMA descriptor table + * + * @return pointer to the allocated descriptor table or NULL in case of an + * error. + */ +struct sdhci_adma_desc *sdhci_adma_init(void) +{ + return memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); +} diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 7673219fb33..d549a264d73 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -69,57 +69,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) } } -#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) -static void sdhci_adma_desc(struct sdhci_host *host, dma_addr_t dma_addr, - u16 len, bool end) -{ - struct sdhci_adma_desc *desc; - u8 attr; - - desc = &host->adma_desc_table[host->desc_slot]; - - attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; - if (!end) - host->desc_slot++; - else - attr |= ADMA_DESC_ATTR_END; - - desc->attr = attr; - desc->len = len; - desc->reserved = 0; - desc->addr_lo = lower_32_bits(dma_addr); -#ifdef CONFIG_DMA_ADDR_T_64BIT - desc->addr_hi = upper_32_bits(dma_addr); -#endif -} - -static void sdhci_prepare_adma_table(struct sdhci_host *host, - struct mmc_data *data) -{ - uint trans_bytes = data->blocksize * data->blocks; - uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); - int i = desc_count; - dma_addr_t dma_addr = host->start_addr; - - host->desc_slot = 0; - - while (--i) { - sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false); - dma_addr += ADMA_MAX_LEN; - trans_bytes -= ADMA_MAX_LEN; - } - - sdhci_adma_desc(host, dma_addr, trans_bytes, true); - - flush_cache((dma_addr_t)host->adma_desc_table, - ROUND(desc_count * sizeof(struct sdhci_adma_desc), - ARCH_DMA_MINALIGN)); -} -#elif defined(CONFIG_MMC_SDHCI_SDMA) -static void sdhci_prepare_adma_table(struct sdhci_host *host, - struct mmc_data *data) -{} -#endif #if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)) static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, int *is_aligned, int trans_bytes) @@ -156,8 +105,11 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, if (host->flags & USE_SDMA) { sdhci_writel(host, phys_to_bus((ulong)host->start_addr), SDHCI_DMA_ADDRESS); - } else if (host->flags & (USE_ADMA | USE_ADMA64)) { - sdhci_prepare_adma_table(host, data); + } +#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) + else if (host->flags & (USE_ADMA | USE_ADMA64)) { + sdhci_prepare_adma_table(host->adma_desc_table, data, + host->start_addr); sdhci_writel(host, lower_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS); @@ -165,6 +117,7 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, sdhci_writel(host, upper_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS_HI); } +#endif } #else static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, @@ -770,9 +723,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, __func__); return -EINVAL; } - host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); - + host->adma_desc_table = sdhci_adma_init(); host->adma_addr = (dma_addr_t)host->adma_desc_table; + #ifdef CONFIG_DMA_ADDR_T_64BIT host->flags |= USE_ADMA64; #else diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c index 315f95cce82..29f83b65542 100644 --- a/drivers/mmc/sh_sdhi.c +++ b/drivers/mmc/sh_sdhi.c @@ -784,8 +784,7 @@ int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks) return ret; error: - if (host) - free(host); + free(host); return ret; } diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index 7f8f8edc621..e6f1c75e27c 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -74,8 +74,10 @@ #define IRQSTATEN_TC (0x00000002) #define IRQSTATEN_CC (0x00000001) +/* eSDHC control register */ #define ESDHCCTL 0x0002e40c #define ESDHCCTL_PCS (0x00080000) +#define ESDHCCTL_FAF (0x00040000) #define PRSSTAT 0x0002e024 #define PRSSTAT_DAT0 (0x01000000) @@ -95,6 +97,10 @@ #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 @@ -154,6 +160,12 @@ #define BLKATTR_SIZE(x) (x & 0x1fff) #define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */ +/* Auto CMD error status register / system control 2 register */ +#define EXECUTE_TUNING 0x00400000 +#define SMPCLKSEL 0x00800000 +#define UHSM_MASK 0x00070000 +#define UHSM_SDR104_HS200 0x00030000 + /* Host controller capabilities register */ #define HOSTCAPBLT_VS18 0x04000000 #define HOSTCAPBLT_VS30 0x02000000 @@ -162,6 +174,33 @@ #define HOSTCAPBLT_DMAS 0x00400000 #define HOSTCAPBLT_HSS 0x00200000 +/* Tuning block control register */ +#define TBCTL_TB_EN 0x00000004 +#define HS400_MODE 0x00000010 +#define HS400_WNDW_ADJUST 0x00000040 + +/* SD clock control register */ +#define CMD_CLK_CTL 0x00008000 + +/* SD timing control register */ +#define FLW_CTL_BG 0x00008000 + +/* DLL config 0 register */ +#define DLL_ENABLE 0x80000000 +#define DLL_FREQ_SEL 0x08000000 + +#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; @@ -203,10 +242,6 @@ struct fsl_esdhc_cfg { int fsl_esdhc_mmc_init(struct bd_info *bis); int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg); void fdt_fixup_esdhc(void *blob, struct bd_info *bd); -#ifdef MMC_SUPPORTS_TUNING -static inline int fsl_esdhc_execute_tuning(struct udevice *dev, - uint32_t opcode) {return 0; } -#endif #else static inline int fsl_esdhc_mmc_init(struct bd_info *bis) { return -ENOSYS; } static inline void fdt_fixup_esdhc(void *blob, struct bd_info *bd) {} diff --git a/include/mmc.h b/include/mmc.h index 75bcaaf6b35..ac7b54f1a7e 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -422,6 +422,14 @@ struct dm_mmc_ops { */ int (*deferred_probe)(struct udevice *dev); /** + * reinit() - Re-initialization to clear old configuration for + * mmc rescan. + * + * @dev: Device to reinit + * @return 0 if Ok, -ve if error + */ + int (*reinit)(struct udevice *dev); + /** * send_cmd() - Send a command to the MMC device * * @dev: Device to receive the command @@ -505,6 +513,14 @@ struct dm_mmc_ops { * @return maximum number of blocks for this transfer */ int (*get_b_max)(struct udevice *dev, void *dst, lbaint_t blkcnt); + + /** + * hs400_prepare_ddr - prepare to switch to DDR mode + * + * @dev: Device to check + * @return 0 if success, -ve on error + */ + int (*hs400_prepare_ddr)(struct udevice *dev); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -518,6 +534,7 @@ int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us); int dm_mmc_host_power_cycle(struct udevice *dev); int dm_mmc_deferred_probe(struct udevice *dev); +int dm_mmc_reinit(struct udevice *dev); int dm_mmc_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt); /* Transition functions for compatibility */ @@ -529,8 +546,9 @@ int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us); int mmc_set_enhanced_strobe(struct mmc *mmc); int mmc_host_power_cycle(struct mmc *mmc); int mmc_deferred_probe(struct mmc *mmc); +int mmc_reinit(struct mmc *mmc); int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt); - +int mmc_hs400_prepare_ddr(struct mmc *mmc); #else struct mmc_ops { int (*send_cmd)(struct mmc *mmc, @@ -542,6 +560,11 @@ struct mmc_ops { int (*host_power_cycle)(struct mmc *mmc); int (*get_b_max)(struct mmc *mmc, void *dst, lbaint_t blkcnt); }; + +static inline int mmc_hs400_prepare_ddr(struct mmc *mmc) +{ + return 0; +} #endif struct mmc_config { @@ -697,6 +720,7 @@ struct mmc { * accessing the boot partitions */ u32 quirks; + u8 hs400_tuning; }; struct mmc_hwpart_conf { diff --git a/include/sdhci.h b/include/sdhci.h index 94fc3ed56ac..f69d5f81fb1 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -271,7 +271,6 @@ struct sdhci_ops { int (*deferred_probe)(struct sdhci_host *host); }; -#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) #define ADMA_MAX_LEN 65532 #ifdef CONFIG_DMA_ADDR_T_64BIT #define ADMA_DESC_LEN 16 @@ -302,7 +301,7 @@ struct sdhci_adma_desc { u32 addr_hi; #endif } __packed; -#endif + struct sdhci_host { const char *name; void *ioaddr; @@ -334,7 +333,6 @@ struct sdhci_host { dma_addr_t adma_addr; #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) struct sdhci_adma_desc *adma_desc_table; - uint desc_slot; #endif }; @@ -496,4 +494,8 @@ extern const struct dm_mmc_ops sdhci_ops; #else #endif +struct sdhci_adma_desc *sdhci_adma_init(void); +void sdhci_prepare_adma_table(struct sdhci_adma_desc *table, + struct mmc_data *data, dma_addr_t addr); + #endif /* __SDHCI_HW_H */ |