From 5e965e814067e7539943bbaeb47d7bf9738a701b Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Wed, 29 May 2019 09:30:01 -0700 Subject: mmc: t210: Add autocal and tap/trim updates for SDMMC1/3 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 Reviewed-by: Jaehoon Chung --- drivers/mmc/tegra_mmc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index f022e935525..73ac58c6c8d 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -3,7 +3,7 @@ * (C) Copyright 2009 SAMSUNG Electronics * Minkyu Kang * Jaehoon Chung - * Portions Copyright 2011-2016 NVIDIA Corporation + * Portions Copyright 2011-2019 NVIDIA Corporation */ #include @@ -15,6 +15,9 @@ #include #include #include +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA210) +#include +#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) -- cgit v1.2.3 From a482f32992230d8bdae2caa72056ab7d9208d5f0 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 3 Jun 2019 16:06:34 -0700 Subject: mmc: t210: Fix 'bad' SD-card clock when doing 400KHz card detect According to the HW team, for some reason the normal clock select code picks what appears to be a perfectly valid 375KHz SD card clock, based on the CAR clock source and SDMMC1 controller register settings (CAR = 408MHz PLLP0 divided by 68 for 6MHz, then a SD Clock Control register divisor of 16 = 375KHz). But the resulting SD card clock, as measured by the HW team, is 700KHz, which is out-of-spec. So the WAR is to use the values given in the TRM PLLP table to generate a 400KHz SD-clock (CAR clock of 24.7MHz, SD Clock Control divisor of 62) only for SDMMC1 on T210 when the requested clock is <= 400KHz. Note that as far as I can tell, the other requests for clocks in the Tegra MMC driver result in valid SD clocks. Signed-off-by: Tom Warren Reviewed-by: Jaehoon Chung --- arch/arm/include/asm/arch-tegra/tegra_mmc.h | 2 +- drivers/mmc/tegra_mmc.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/arm/include/asm/arch-tegra/tegra_mmc.h b/arch/arm/include/asm/arch-tegra/tegra_mmc.h index a8bfa466c02..70dcf4aa663 100644 --- a/arch/arm/include/asm/arch-tegra/tegra_mmc.h +++ b/arch/arm/include/asm/arch-tegra/tegra_mmc.h @@ -130,9 +130,9 @@ struct tegra_mmc { /* SDMMC1/3 settings from SDMMCx Initialization Sequence of TRM */ #define MEMCOMP_PADCTRL_VREF 7 #define AUTO_CAL_ENABLE (1 << 29) -#if defined(CONFIG_TEGRA210) #define AUTO_CAL_ACTIVE (1 << 31) #define AUTO_CAL_START (1 << 31) +#if defined(CONFIG_TEGRA210) #define AUTO_CAL_PD_OFFSET (0x7D << 8) #define AUTO_CAL_PU_OFFSET (0 << 0) #define IO_TRIM_BYPASS_MASK (1 << 2) diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 73ac58c6c8d..2b041562a63 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -376,6 +376,25 @@ static void tegra_mmc_change_clock(struct tegra_mmc_priv *priv, uint clock) rate = clk_set_rate(&priv->clk, clock); div = (rate + clock - 1) / clock; + +#if defined(CONFIG_TEGRA210) + if (priv->mmc_id == PERIPH_ID_SDMMC1 && clock <= 400000) { + /* clock_adjust_periph_pll_div() chooses a 'bad' clock + * on SDMMC1 T210, so skip it here and force a clock + * that's been spec'd in the table in the TRM for + * card-detect (400KHz). + */ + uint effective_rate = clock_adjust_periph_pll_div(priv->mmc_id, + CLOCK_ID_PERIPH, 24727273, NULL); + div = 62; + + debug("%s: WAR: Using SDMMC1 clock of %u, div %d to achieve %dHz card clock ...\n", + __func__, effective_rate, div, clock); + } else { + clock_adjust_periph_pll_div(priv->mmc_id, CLOCK_ID_PERIPH, + clock, &div); + } +#endif debug("div = %d\n", div); writew(0, &priv->reg->clkcon); -- cgit v1.2.3 From 3c8cf240322e76eebbb31593c96f0754092df91f Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Tue, 12 Nov 2019 13:17:37 -0700 Subject: qspi: t210: Fix claim_bus's use of the wrong bus/device claim_bus() is passed a udevice *dev, which is the bus device's parent. In this driver, claim_bus assumed it was the bus, which caused the 'priv' info pointer to be wrong, and periph_id was incorrect. This in turn caused the periph clock call to assign the wrong clock (PLLM instead of PLLP0), which caused a kernel warning. I only saw the 'bad' periph_id when enabling DEBUG due to an assert. Not sure how QSPI was working w/this errant clock, but it was moot as QSPI wasn't active unless you probed it, and that wasn't happening until I posted a patch to enable env save to QSPI for Nano (coming soon). Signed-off-by: Tom Warren --- drivers/spi/tegra210_qspi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/tegra210_qspi.c b/drivers/spi/tegra210_qspi.c index d82ecaa61fa..2a77126d04f 100644 --- a/drivers/spi/tegra210_qspi.c +++ b/drivers/spi/tegra210_qspi.c @@ -2,7 +2,8 @@ /* * NVIDIA Tegra210 QSPI controller driver * - * (C) Copyright 2015 NVIDIA Corporation + * (C) Copyright 2015-2019 NVIDIA Corporation + * */ #include @@ -137,8 +138,9 @@ static int tegra210_qspi_probe(struct udevice *bus) return 0; } -static int tegra210_qspi_claim_bus(struct udevice *bus) +static int tegra210_qspi_claim_bus(struct udevice *dev) { + struct udevice *bus = dev->parent; struct tegra210_qspi_priv *priv = dev_get_priv(bus); struct qspi_regs *regs = priv->regs; -- cgit v1.2.3 From 2fcc3ba1b766df5f8cfbf35cb2cc88edff94d0f3 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 25 Nov 2019 14:43:50 -0700 Subject: qspi: t210: Fix QSPI clock and tap delays When claim_bus was setting the clock, it reset the QSPI controller, which wipes out any tap delays set by previous bootloaders (nvtboot, CBoot for example on Nano). Instead of doing that in claim_bus, which gets called a lot, moved clock setting to probe(), and set tap delays there, too. Also updated clock to 80MHz to match CBoot. Now QSPI env save works reliably again. Signed-off-by: Tom Warren --- drivers/spi/tegra210_qspi.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/tegra210_qspi.c b/drivers/spi/tegra210_qspi.c index 2a77126d04f..d914337d662 100644 --- a/drivers/spi/tegra210_qspi.c +++ b/drivers/spi/tegra210_qspi.c @@ -42,10 +42,10 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_CMD1_BITLEN_SHIFT 0 /* COMMAND2 */ -#define QSPI_CMD2_TX_CLK_TAP_DELAY BIT(6) -#define QSPI_CMD2_TX_CLK_TAP_DELAY_MASK GENMASK(11,6) -#define QSPI_CMD2_RX_CLK_TAP_DELAY BIT(0) -#define QSPI_CMD2_RX_CLK_TAP_DELAY_MASK GENMASK(5,0) +#define QSPI_CMD2_TX_CLK_TAP_DELAY_SHIFT 10 +#define QSPI_CMD2_TX_CLK_TAP_DELAY_MASK GENMASK(14,10) +#define QSPI_CMD2_RX_CLK_TAP_DELAY_SHIFT 0 +#define QSPI_CMD2_RX_CLK_TAP_DELAY_MASK GENMASK(7,0) /* TRANSFER STATUS */ #define QSPI_XFER_STS_RDY BIT(30) @@ -111,9 +111,9 @@ static int tegra210_qspi_ofdata_to_platdata(struct udevice *bus) /* Use 500KHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", - 500000); + 500000); plat->deactivate_delay_us = fdtdec_get_int(blob, node, - "spi-deactivate-delay", 0); + "spi-deactivate-delay", 0); debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", __func__, plat->base, plat->periph_id, plat->frequency, plat->deactivate_delay_us); @@ -127,14 +127,23 @@ static int tegra210_qspi_probe(struct udevice *bus) struct tegra210_qspi_priv *priv = dev_get_priv(bus); priv->regs = (struct qspi_regs *)plat->base; + struct qspi_regs *regs = priv->regs; priv->last_transaction_us = timer_get_us(); priv->freq = plat->frequency; priv->periph_id = plat->periph_id; + debug("%s: Freq = %u, id = %d\n", __func__, priv->freq, + priv->periph_id); /* Change SPI clock to correct frequency, PLLP_OUT0 source */ clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq); + /* Set tap delays here, clock change above resets QSPI controller */ + u32 reg = (0x09 << QSPI_CMD2_TX_CLK_TAP_DELAY_SHIFT) | + (0x0C << QSPI_CMD2_RX_CLK_TAP_DELAY_SHIFT); + writel(reg, ®s->command2); + debug("%s: COMMAND2 = %08x\n", __func__, readl(®s->command2)); + return 0; } @@ -144,9 +153,6 @@ static int tegra210_qspi_claim_bus(struct udevice *dev) struct tegra210_qspi_priv *priv = dev_get_priv(bus); struct qspi_regs *regs = priv->regs; - /* Change SPI clock to correct frequency, PLLP_OUT0 source */ - clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq); - debug("%s: FIFO STATUS = %08x\n", __func__, readl(®s->fifo_status)); /* Set master mode and sw controlled CS */ -- cgit v1.2.3 From b1747fdb82e9a2befb65b762ba7579b3870d47cb Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Fri, 20 Mar 2020 14:33:00 -0700 Subject: qspi: t210: Use dev_read calls to get FDT data like base, freq This Tegra QSPI driver hadn't been brought up to date with how DM drivers are fetching data from the FDT now, and was pulling in bogus data for base, max freq, etc. Fixed ofdata_to_platdata to work the same way it does in the tegra114 SPI driver, using dev_read_ functions. Signed-off-by: Tom Warren --- drivers/spi/tegra210_qspi.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/tegra210_qspi.c b/drivers/spi/tegra210_qspi.c index d914337d662..6e540e97df4 100644 --- a/drivers/spi/tegra210_qspi.c +++ b/drivers/spi/tegra210_qspi.c @@ -2,7 +2,7 @@ /* * NVIDIA Tegra210 QSPI controller driver * - * (C) Copyright 2015-2019 NVIDIA Corporation + * (C) Copyright 2015-2020 NVIDIA Corporation * */ @@ -97,10 +97,8 @@ struct tegra210_qspi_priv { static int tegra210_qspi_ofdata_to_platdata(struct udevice *bus) { struct tegra_spi_platdata *plat = bus->platdata; - const void *blob = gd->fdt_blob; - int node = dev_of_offset(bus); - plat->base = devfdt_get_addr(bus); + plat->base = dev_read_addr(bus); plat->periph_id = clock_decode_periph_id(bus); if (plat->periph_id == PERIPH_ID_NONE) { @@ -110,10 +108,11 @@ static int tegra210_qspi_ofdata_to_platdata(struct udevice *bus) } /* Use 500KHz as a suitable default */ - plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", - 500000); - plat->deactivate_delay_us = fdtdec_get_int(blob, node, - "spi-deactivate-delay", 0); + plat->frequency = dev_read_u32_default(bus, "spi-max-frequency", + 500000); + plat->deactivate_delay_us = dev_read_u32_default(bus, + "spi-deactivate-delay", + 0); debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n", __func__, plat->base, plat->periph_id, plat->frequency, plat->deactivate_delay_us); -- cgit v1.2.3 From 808e19362f054c8e7cac68e6cd306f7b85d166d3 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Fri, 20 Mar 2020 14:20:09 -0700 Subject: mtd: spi: Add Macronix MX25U3235F device Add Macronix MX25U3235F flash device description. This is a 4MiB part. Signed-off-by: Tom Warren --- drivers/mtd/spi/spi-nor-ids.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 973b6f86c94..abdf560e020 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -147,6 +147,7 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SECT_4K) }, { INFO("mx25u2033e", 0xc22532, 0, 64 * 1024, 4, SECT_4K) }, { INFO("mx25u1635e", 0xc22535, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("mx25u3235f", 0xc22536, 0, 4 * 1024, 1024, SECT_4K) }, { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0) }, { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, -- cgit v1.2.3