[PATCH 1/2] mmc: t210: Add autocal and tap/trim updates for SDMMC1/3
Jaehoon Chung
jh80.chung at samsung.com
Thu Apr 2 03:59:05 CEST 2020
Hi Tom,
On 3/27/20 7:30 AM, tomcwarren3959 at gmail.com wrote:
> From: Tom Warren <twarren at nvidia.com>
>
> As per the T210 TRM, when running at 3.3v, the SDMMC1 tap/trim and
> autocal values need to be set to condition the signals correctly before
> talking to the SD-card. This is the same as what's being done in CBoot,
> but it gets reset when the SDMMC1 HW is soft-reset during SD driver
> init, so needs to be repeated here. Also set autocal and tap/trim for
> SDMMC3, although no T210 boards use it for SD-card at this time.
>
> Signed-off-by: Tom Warren <twarren at nvidia.com>
Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>
Best Regards,
Jaehoon Chung
> ---
> Changes for v2:
> - Added clocks.h include for TEGRA30 to fix T30 32-bit builds
>
> arch/arm/include/asm/arch-tegra/tegra_mmc.h | 20 +++++--
> drivers/mmc/tegra_mmc.c | 84 ++++++++++++++++++++++++++---
> 2 files changed, 92 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm/include/asm/arch-tegra/tegra_mmc.h b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
> index a2b6f63..a8bfa46 100644
> --- a/arch/arm/include/asm/arch-tegra/tegra_mmc.h
> +++ b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
> @@ -2,7 +2,7 @@
> /*
> * (C) Copyright 2009 SAMSUNG Electronics
> * Minkyu Kang <mk7.kang at samsung.com>
> - * Portions Copyright (C) 2011-2012 NVIDIA Corporation
> + * Portions Copyright (C) 2011-2012,2019 NVIDIA Corporation
> */
>
> #ifndef __TEGRA_MMC_H_
> @@ -52,7 +52,7 @@ struct tegra_mmc {
> unsigned char admaerr; /* offset 54h */
> unsigned char res4[3]; /* RESERVED, offset 55h-57h */
> unsigned long admaaddr; /* offset 58h-5Fh */
> - unsigned char res5[0xa0]; /* RESERVED, offset 60h-FBh */
> + unsigned char res5[0x9c]; /* RESERVED, offset 60h-FBh */
> unsigned short slotintstatus; /* offset FCh */
> unsigned short hcver; /* HOST Version */
> unsigned int venclkctl; /* _VENDOR_CLOCK_CNTRL_0, 100h */
> @@ -127,11 +127,23 @@ struct tegra_mmc {
>
> #define TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE (1 << 1)
>
> -/* SDMMC1/3 settings from section 24.6 of T30 TRM */
> +/* SDMMC1/3 settings from SDMMCx Initialization Sequence of TRM */
> #define MEMCOMP_PADCTRL_VREF 7
> -#define AUTO_CAL_ENABLED (1 << 29)
> +#define AUTO_CAL_ENABLE (1 << 29)
> +#if defined(CONFIG_TEGRA210)
> +#define AUTO_CAL_ACTIVE (1 << 31)
> +#define AUTO_CAL_START (1 << 31)
> +#define AUTO_CAL_PD_OFFSET (0x7D << 8)
> +#define AUTO_CAL_PU_OFFSET (0 << 0)
> +#define IO_TRIM_BYPASS_MASK (1 << 2)
> +#define TRIM_VAL_SHIFT 24
> +#define TRIM_VAL_MASK (0x1F << TRIM_VAL_SHIFT)
> +#define TAP_VAL_SHIFT 16
> +#define TAP_VAL_MASK (0xFF << TAP_VAL_SHIFT)
> +#else
> #define AUTO_CAL_PD_OFFSET (0x70 << 8)
> #define AUTO_CAL_PU_OFFSET (0x62 << 0)
> +#endif
>
> #endif /* __ASSEMBLY__ */
> #endif /* __TEGRA_MMC_H_ */
> diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
> index f022e93..73ac58c 100644
> --- a/drivers/mmc/tegra_mmc.c
> +++ b/drivers/mmc/tegra_mmc.c
> @@ -3,7 +3,7 @@
> * (C) Copyright 2009 SAMSUNG Electronics
> * Minkyu Kang <mk7.kang at samsung.com>
> * Jaehoon Chung <jh80.chung at samsung.com>
> - * Portions Copyright 2011-2016 NVIDIA Corporation
> + * Portions Copyright 2011-2019 NVIDIA Corporation
> */
>
> #include <bouncebuf.h>
> @@ -15,6 +15,9 @@
> #include <asm/io.h>
> #include <asm/arch-tegra/tegra_mmc.h>
> #include <linux/err.h>
> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA210)
> +#include <asm/arch/clock.h>
> +#endif
>
> struct tegra_mmc_plat {
> struct mmc_config cfg;
> @@ -30,6 +33,7 @@ struct tegra_mmc_priv {
> struct gpio_desc wp_gpio; /* Write Protect GPIO */
> unsigned int version; /* SDHCI spec. version */
> unsigned int clock; /* Current clock (MHz) */
> + int mmc_id; /* peripheral id */
> };
>
> static void tegra_mmc_set_power(struct tegra_mmc_priv *priv,
> @@ -446,16 +450,19 @@ static int tegra_mmc_set_ios(struct udevice *dev)
>
> static void tegra_mmc_pad_init(struct tegra_mmc_priv *priv)
> {
> -#if defined(CONFIG_TEGRA30)
> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA210)
> u32 val;
> + u16 clk_con;
> + int timeout;
> + int id = priv->mmc_id;
>
> - debug("%s: sdmmc address = %08x\n", __func__, (unsigned int)priv->reg);
> + debug("%s: sdmmc address = %p, id = %d\n", __func__,
> + priv->reg, id);
>
> /* Set the pad drive strength for SDMMC1 or 3 only */
> - if (priv->reg != (void *)0x78000000 &&
> - priv->reg != (void *)0x78000400) {
> + if (id != PERIPH_ID_SDMMC1 && id != PERIPH_ID_SDMMC3) {
> debug("%s: settings are only valid for SDMMC1/SDMMC3!\n",
> - __func__);
> + __func__);
> return;
> }
>
> @@ -464,11 +471,65 @@ static void tegra_mmc_pad_init(struct tegra_mmc_priv *priv)
> val |= MEMCOMP_PADCTRL_VREF;
> writel(val, &priv->reg->sdmemcmppadctl);
>
> + /* Disable SD Clock Enable before running auto-cal as per TRM */
> + clk_con = readw(&priv->reg->clkcon);
> + debug("%s: CLOCK_CONTROL = 0x%04X\n", __func__, clk_con);
> + clk_con &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
> + writew(clk_con, &priv->reg->clkcon);
> +
> val = readl(&priv->reg->autocalcfg);
> val &= 0xFFFF0000;
> - val |= AUTO_CAL_PU_OFFSET | AUTO_CAL_PD_OFFSET | AUTO_CAL_ENABLED;
> + val |= AUTO_CAL_PU_OFFSET | AUTO_CAL_PD_OFFSET;
> writel(val, &priv->reg->autocalcfg);
> -#endif
> + val |= AUTO_CAL_START | AUTO_CAL_ENABLE;
> + writel(val, &priv->reg->autocalcfg);
> + debug("%s: AUTO_CAL_CFG = 0x%08X\n", __func__, val);
> + udelay(1);
> + timeout = 100; /* 10 mSec max (100*100uS) */
> + do {
> + val = readl(&priv->reg->autocalsts);
> + udelay(100);
> + } while ((val & AUTO_CAL_ACTIVE) && --timeout);
> + val = readl(&priv->reg->autocalsts);
> + debug("%s: Final AUTO_CAL_STATUS = 0x%08X, timeout = %d\n",
> + __func__, val, timeout);
> +
> + /* Re-enable SD Clock Enable when auto-cal is done */
> + clk_con |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
> + writew(clk_con, &priv->reg->clkcon);
> + clk_con = readw(&priv->reg->clkcon);
> + debug("%s: final CLOCK_CONTROL = 0x%04X\n", __func__, clk_con);
> +
> + if (timeout == 0) {
> + printf("%s: Warning: Autocal timed out!\n", __func__);
> + /* TBD: Set CFG2TMC_SDMMC1_PAD_CAL_DRV* regs here */
> + }
> +
> +#if defined(CONFIG_TEGRA210)
> + u32 tap_value, trim_value;
> +
> + /* Set tap/trim values for SDMMC1/3 @ <48MHz here */
> + val = readl(&priv->reg->venspictl); /* aka VENDOR_SYS_SW_CNTL */
> + val &= IO_TRIM_BYPASS_MASK;
> + if (id == PERIPH_ID_SDMMC1) {
> + tap_value = 4; /* default */
> + if (val)
> + tap_value = 3;
> + trim_value = 2;
> + } else { /* SDMMC3 */
> + tap_value = 3;
> + trim_value = 3;
> + }
> +
> + val = readl(&priv->reg->venclkctl);
> + val &= ~TRIM_VAL_MASK;
> + val |= (trim_value << TRIM_VAL_SHIFT);
> + val &= ~TAP_VAL_MASK;
> + val |= (tap_value << TAP_VAL_SHIFT);
> + writel(val, &priv->reg->venclkctl);
> + debug("%s: VENDOR_CLOCK_CNTRL = 0x%08X\n", __func__, val);
> +#endif /* T210 */
> +#endif /* T30/T210 */
> }
>
> static void tegra_mmc_reset(struct tegra_mmc_priv *priv, struct mmc *mmc)
> @@ -514,6 +575,13 @@ static int tegra_mmc_init(struct udevice *dev)
> unsigned int mask;
> debug(" tegra_mmc_init called\n");
>
> +#if defined(CONFIG_TEGRA210)
> + priv->mmc_id = clock_decode_periph_id(dev);
> + if (priv->mmc_id == PERIPH_ID_NONE) {
> + printf("%s: Missing/invalid peripheral ID\n", __func__);
> + return -EINVAL;
> + }
> +#endif
> tegra_mmc_reset(priv, mmc);
>
> #if defined(CONFIG_TEGRA124_MMC_DISABLE_EXT_LOOPBACK)
>
More information about the U-Boot
mailing list