diff options
author | Tom Rini | 2020-04-03 16:05:46 -0400 |
---|---|---|
committer | Tom Rini | 2020-04-03 16:05:46 -0400 |
commit | 60f1cc529ccc364e8374945a06ff2f7a2c54fb1e (patch) | |
tree | fa4cc23755d3cb6f346e388274c7173c9c819c60 /drivers | |
parent | e14ba8a57703457e31248eccd4959cead92e2063 (diff) | |
parent | 7c02bc9649f6d3afd272ac4a94b280495473834c (diff) |
Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-tegra
- Add support for Jetson Nano, plus miscellaneous other fixes found
during Nano bringup.
- Add Igor's update_uboot wrapper patches.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/tegra_mmc.c | 103 | ||||
-rw-r--r-- | drivers/mtd/spi/spi-nor-ids.c | 1 | ||||
-rw-r--r-- | drivers/spi/tegra210_qspi.c | 39 |
3 files changed, 119 insertions, 24 deletions
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index f022e935525..2b041562a63 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@samsung.com> * Jaehoon Chung <jh80.chung@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, @@ -372,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); @@ -446,16 +469,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 +490,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 +594,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) 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) }, diff --git a/drivers/spi/tegra210_qspi.c b/drivers/spi/tegra210_qspi.c index d82ecaa61fa..6e540e97df4 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 <www.nvidia.com> + * (C) Copyright 2015-2020 NVIDIA Corporation <www.nvidia.com> + * */ #include <common.h> @@ -41,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) @@ -96,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) { @@ -109,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); @@ -126,25 +126,32 @@ 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; } -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; - /* 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 */ |