Merge commit 'refs/pipelines/15015' of https://source.denx.de/u-boot/custodians/u-boot-tegra
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5e112e6..bd7fffc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1286,6 +1286,7 @@
 	select GPIO_EXTRA_HEADER
 	imply DISTRO_DEFAULTS
 	imply FAT_WRITE
+	imply SPL_TIMER if SPL
 
 config ARCH_VEXPRESS64
 	bool "Support ARMv8 Arm Ltd. VExpress based boards and models"
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index 6586015..1dd5d07 100644
--- a/arch/arm/include/asm/arch-tegra/clock.h
+++ b/arch/arm/include/asm/arch-tegra/clock.h
@@ -13,12 +13,13 @@
 /* Set of oscillator frequencies supported in the internal API. */
 enum clock_osc_freq {
 	/* All in MHz, so 13_0 is 13.0MHz */
-	CLOCK_OSC_FREQ_13_0,
-	CLOCK_OSC_FREQ_19_2,
-	CLOCK_OSC_FREQ_12_0,
-	CLOCK_OSC_FREQ_26_0,
+	CLOCK_OSC_FREQ_13_0 = 0,
+	CLOCK_OSC_FREQ_16_8,
+	CLOCK_OSC_FREQ_19_2 = 4,
 	CLOCK_OSC_FREQ_38_4,
+	CLOCK_OSC_FREQ_12_0 = 8,
 	CLOCK_OSC_FREQ_48_0,
+	CLOCK_OSC_FREQ_26_0 = 12,
 
 	CLOCK_OSC_FREQ_COUNT,
 };
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 1b575cc..4fc79eb 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -73,6 +73,7 @@
 	select SPL_BOARD_INIT if SPL
 	select SPL_SKIP_LOWLEVEL_INIT_ONLY if SPL
 	select SUPPORT_SPL
+	select TIMER
 	select TEGRA_CLKRST
 	select TEGRA_COMMON
 	select TEGRA_GPIO
@@ -81,6 +82,7 @@
 	select TEGRA_NO_BPMP
 	select TEGRA_PINCTRL
 	select TEGRA_PMC
+	select TEGRA_TIMER
 
 config TEGRA_ARMV8_COMMON
 	bool "Tegra 64-bit common options"
@@ -125,6 +127,7 @@
 config TEGRA210
 	bool "Tegra210 family"
 	select GICV2
+	select TIMER
 	select TEGRA_ARMV8_COMMON
 	select TEGRA_CLKRST
 	select TEGRA_GPIO
@@ -134,6 +137,7 @@
 	select TEGRA_PINCTRL
 	select TEGRA_PMC
 	select TEGRA_PMC_SECURE
+	select TEGRA_TIMER
 
 config TEGRA186
 	bool "Tegra186 family"
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 77c8ad9..11bffc1 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -28,16 +28,23 @@
 static unsigned pll_rate[CLOCK_ID_COUNT];
 
 /*
- * The oscillator frequency is fixed to one of four set values. Based on this
+ * The oscillator frequency is fixed to one of seven set values. Based on this
  * the other clocks are set up appropriately.
  */
 static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = {
 	13000000,
+	16800000,
+	       0,
+	       0,
 	19200000,
-	12000000,
-	26000000,
 	38400000,
+	       0,
+	       0,
+	12000000,
 	48000000,
+	       0,
+	       0,
+	26000000,
 };
 
 /* return 1 if a peripheral ID is in range */
@@ -766,6 +773,7 @@
 	 */
 	switch (clock_get_osc_freq()) {
 	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+	case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
 		clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
 		clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
 		break;
@@ -776,10 +784,13 @@
 		break;
 
 	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+	case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
 		clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
 		break;
+
 	case CLOCK_OSC_FREQ_19_2:
+	case CLOCK_OSC_FREQ_38_4:
 	default:
 		/*
 		 * These are not supported. It is too early to print a
diff --git a/arch/arm/mach-tegra/cpu.c b/arch/arm/mach-tegra/cpu.c
index 65b15b7..59ca8ae 100644
--- a/arch/arm/mach-tegra/cpu.c
+++ b/arch/arm/mach-tegra/cpu.c
@@ -55,11 +55,18 @@
 	 */
 	{
 		{ .n = 1000, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n =  625, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n = 1000, .m = 12, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n = 1000, .m = 26, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
-		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* OSC: 38.4 MHz (N/A) */
-		{ .n =    0, .m =  0, .p = 0, .cpcon =  0 }, /* OSC: 48.0 MHz (N/A) */
 	},
 	/*
 	 * T25: 1.2 GHz
@@ -73,11 +80,18 @@
 	 */
 	{
 		{ .n = 923, .m = 10, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n = 750, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n = 600, .m =  6, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* N/A */
 		{ .n = 600, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
-		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* OSC: 38.4 MHz (N/A) */
-		{ .n =   0, .m =  0, .p = 0, .cpcon =  0 }, /* OSC: 48.0 MHz (N/A) */
 	},
 	/*
 	 * T30: 600 MHz
@@ -91,11 +105,18 @@
 	 */
 	{
 		{ .n = 600, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 13.0 MHz */
+		{ .n = 600, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 16.8 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
 		{ .n = 500, .m = 16, .p = 0, .cpcon = 8 }, /* OSC: 19.2 MHz */
+		{ .n = 500, .m = 16, .p = 0, .cpcon = 8 }, /* OSC: 38.4 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
 		{ .n = 600, .m = 12, .p = 0, .cpcon = 8 }, /* OSC: 12.0 MHz */
+		{ .n = 600, .m = 12, .p = 0, .cpcon = 8 }, /* OSC: 48.0 MHz */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
+		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* N/A */
 		{ .n = 600, .m = 26, .p = 0, .cpcon = 8 }, /* OSC: 26.0 MHz */
-		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* OSC: 38.4 MHz (N/A) */
-		{ .n =   0, .m =  0, .p = 0, .cpcon = 0 }, /* OSC: 48.0 MHz (N/A) */
 	},
 	/*
 	 * T114: 700 MHz
@@ -108,11 +129,18 @@
 	 */
 	{
 		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 16.8 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 38.4 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 48.0 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
-		{ .n =   0, .m = 0, .p = 0 }, /* OSC: 38.4 MHz (N/A) */
-		{ .n =   0, .m = 0, .p = 0 }, /* OSC: 48.0 MHz (N/A) */
 	},
 
 	/*
@@ -126,11 +154,18 @@
 	 */
 	{
 		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 16.8 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 38.4 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 48.0 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
 		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
-		{ .n =   0, .m = 0, .p = 0 }, /* OSC: 38.4 MHz (N/A) */
-		{ .n =   0, .m = 0, .p = 0 }, /* OSC: 48.0 MHz (N/A) */
 	},
 
 	/*
@@ -143,12 +178,19 @@
 	 * PLLX_BASE  m       7: 0    8
 	 */
 	{
-		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz = 702   MHz*/
-		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz = 700.8 MHz*/
-		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz = 696   MHz*/
-		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz = 702   MHz*/
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz = 702   MHz */
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 16.0 MHz = 702   MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz = 700.8 MHz */
 		{ .n =  36, .m = 1, .p = 1 }, /* OSC: 38.4 MHz = 691.2 MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz = 696   MHz */
 		{ .n =  58, .m = 2, .p = 1 }, /* OSC: 48.0 MHz = 696   MHz */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n =   0, .m = 0, .p = 0 }, /* (N/A) */
+		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz = 702   MHz */
 	},
 };
 
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c
index 703a231..143f868 100644
--- a/arch/arm/mach-tegra/tegra114/clock.c
+++ b/arch/arm/mach-tegra/tegra114/clock.c
@@ -459,8 +459,7 @@
 
 /*
  * Get the oscillator frequency, from the corresponding hardware configuration
- * field. Note that T30/T114 support 3 new higher freqs, but we map back
- * to the old T20 freqs. Support for the higher oscillators is TBD.
+ * field. Note that T30+ supports 3 new higher freqs.
  */
 enum clock_osc_freq clock_get_osc_freq(void)
 {
@@ -469,12 +468,7 @@
 	u32 reg;
 
 	reg = readl(&clkrst->crc_osc_ctrl);
-	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
-
-	if (reg & 1)				/* one of the newer freqs */
-		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
-
-	return reg >> 2;	/* Map to most common (T20) freqs */
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
 /* Returns a pointer to the clock source register for a peripheral */
@@ -674,6 +668,7 @@
 	 */
 	switch (clock_get_osc_freq()) {
 	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+	case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
 		break;
@@ -684,10 +679,12 @@
 		break;
 
 	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+	case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
 		break;
 	case CLOCK_OSC_FREQ_19_2:
+	case CLOCK_OSC_FREQ_38_4:
 	default:
 		/*
 		 * These are not supported. It is too early to print a
diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c
index bbfe184..da38b26 100644
--- a/arch/arm/mach-tegra/tegra124/clock.c
+++ b/arch/arm/mach-tegra/tegra124/clock.c
@@ -601,8 +601,7 @@
 
 /*
  * Get the oscillator frequency, from the corresponding hardware configuration
- * field. Note that Tegra30+ support 3 new higher freqs, but we map back
- * to the old T20 freqs. Support for the higher oscillators is TBD.
+ * field. Note that T30+ supports 3 new higher freqs.
  */
 enum clock_osc_freq clock_get_osc_freq(void)
 {
@@ -611,12 +610,7 @@
 	u32 reg;
 
 	reg = readl(&clkrst->crc_osc_ctrl);
-	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
-
-	if (reg & 1)				/* one of the newer freqs */
-		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
-
-	return reg >> 2;	/* Map to most common (T20) freqs */
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
 /* Returns a pointer to the clock source register for a peripheral */
@@ -854,6 +848,7 @@
 	 */
 	switch (clock_get_osc_freq()) {
 	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+	case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
 		break;
@@ -864,10 +859,12 @@
 		break;
 
 	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+	case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
 		break;
 	case CLOCK_OSC_FREQ_19_2:
+	case CLOCK_OSC_FREQ_38_4:
 	default:
 		/*
 		 * These are not supported. It is too early to print a
diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c
index 3b50a81..8c12743 100644
--- a/arch/arm/mach-tegra/tegra20/clock.c
+++ b/arch/arm/mach-tegra/tegra20/clock.c
@@ -399,7 +399,9 @@
 	u32 reg;
 
 	reg = readl(&clkrst->crc_osc_ctrl);
-	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+
+	return reg << 2;
 }
 
 /* Returns a pointer to the clock source register for a peripheral */
diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c
index 10c2478..330753f 100644
--- a/arch/arm/mach-tegra/tegra210/clock.c
+++ b/arch/arm/mach-tegra/tegra210/clock.c
@@ -672,8 +672,7 @@
 
 /*
  * Get the oscillator frequency, from the corresponding hardware configuration
- * field. Note that Tegra30+ support 3 new higher freqs, but we map back
- * to the old T20 freqs. Support for the higher oscillators is TBD.
+ * field. Note that T30+ supports 3 new higher freqs.
  */
 enum clock_osc_freq clock_get_osc_freq(void)
 {
@@ -682,22 +681,7 @@
 	u32 reg;
 
 	reg = readl(&clkrst->crc_osc_ctrl);
-	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
-	/*
-	 * 0 = 13MHz, 1 = 16.8MHz, 4 = 19.2MHz, 5 = 38.4MHz,
-	 * 8 = 12MHz, 9 = 48MHz,  12 = 26MHz
-	 */
-	if (reg == 5) {
-		debug("OSC_FREQ is 38.4MHz (%d) ...\n", reg);
-		/* Map it to the 5th CLOCK_OSC_ enum, i.e. 4 */
-		return 4;
-	}
-
-	/*
-	 * Map to most common (T20) freqs (except 38.4, handled above):
-	 *  13/16.8 = 0, 19.2 = 1, 12/48 = 2, 26 = 3
-	 */
-	return reg >> 2;
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
 /* Returns a pointer to the clock source register for a peripheral */
@@ -986,6 +970,7 @@
 	 */
 	switch (clock_get_osc_freq()) {
 	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+	case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
 		break;
@@ -996,6 +981,7 @@
 		break;
 
 	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+	case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
 		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
 		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
 		break;
diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c
index c835cd0..449b66e 100644
--- a/arch/arm/mach-tegra/tegra30/clock.c
+++ b/arch/arm/mach-tegra/tegra30/clock.c
@@ -439,8 +439,7 @@
 
 /*
  * Get the oscillator frequency, from the corresponding hardware configuration
- * field. Note that T30 supports 3 new higher freqs, but we map back
- * to the old T20 freqs. Support for the higher oscillators is TBD.
+ * field. Note that T30+ supports 3 new higher freqs.
  */
 enum clock_osc_freq clock_get_osc_freq(void)
 {
@@ -449,12 +448,7 @@
 	u32 reg;
 
 	reg = readl(&clkrst->crc_osc_ctrl);
-	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
-
-	if (reg & 1)			/* one of the newer freqs */
-		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
-
-	return reg >> 2;	/* Map to most common (T20) freqs */
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
 /* Returns a pointer to the clock source register for a peripheral */
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 6d66650..f32bd16 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -252,6 +252,14 @@
 	  Select this to enable support for the timer found on
 	  STM32 devices.
 
+config TEGRA_TIMER
+	bool "Tegra timer support"
+	depends on TIMER
+	select TIMER_EARLY
+	help
+	  Select this to enable support for the timer found on
+	  Tegra devices.
+
 config X86_TSC_TIMER
 	bool "x86 Time-Stamp Counter (TSC) timer support"
 	depends on TIMER && X86
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 6470fd5..3c92113 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)	+= arm_global_timer.o
 obj-$(CONFIG_STM32_TIMER)	+= stm32_timer.o
+obj-$(CONFIG_TEGRA_TIMER)	+= tegra-timer.o
 obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
 obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
 obj-$(CONFIG_MCHP_PIT64B_TIMER)	+= mchp-pit64b-timer.o
diff --git a/drivers/timer/tegra-timer.c b/drivers/timer/tegra-timer.c
new file mode 100644
index 0000000..a867c64
--- /dev/null
+++ b/drivers/timer/tegra-timer.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/tegra.h>
+
+#define TEGRA_OSC_CLK_ENB_L_SET		(NV_PA_CLK_RST_BASE + 0x320)
+#define TEGRA_OSC_SET_CLK_ENB_TMR	BIT(5)
+
+#define TEGRA_TIMER_USEC_CNTR		(NV_PA_TMRUS_BASE + 0)
+#define TEGRA_TIMER_USEC_CFG		(NV_PA_TMRUS_BASE + 4)
+
+#define TEGRA_TIMER_RATE		1000000 /* 1 MHz */
+
+/*
+ * On pre-DM stage timer should be left configured by
+ * previous bootloader for correct 1MHz clock.
+ * In the case of reset default value is set to 1/13 of
+ * CLK_M which should be decent enough to safely
+ * get to DM stage.
+ */
+u64 notrace timer_early_get_count(void)
+{
+	/* At this stage raw timer is used */
+	return readl(TEGRA_TIMER_USEC_CNTR);
+}
+
+unsigned long notrace timer_early_get_rate(void)
+{
+	return TEGRA_TIMER_RATE;
+}
+
+ulong timer_get_boot_us(void)
+{
+	return timer_early_get_count();
+}
+
+/*
+ * At moment of calling get_count, timer driver is already
+ * probed and is configured to have precise 1MHz clock.
+ * Tegra timer has a step of 1 microsecond which removes
+ * need of using adjusments involving uc_priv->clock_rate.
+ */
+static notrace u64 tegra_timer_get_count(struct udevice *dev)
+{
+	u32 val = timer_early_get_count();
+	return timer_conv_64(val);
+}
+
+static int tegra_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	u32 usec_config, value;
+
+	/* Timer rate has to be set unconditionally */
+	uc_priv->clock_rate = TEGRA_TIMER_RATE;
+
+	/*
+	 * Configure microsecond timers to have 1MHz clock
+	 * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
+	 * Uses n+1 scheme
+	 */
+	switch (clock_get_rate(CLOCK_ID_CLK_M)) {
+	case 12000000:
+		usec_config = 0x000b; /* (11+1)/(0+1) */
+		break;
+	case 12800000:
+		usec_config = 0x043f; /* (63+1)/(4+1) */
+		break;
+	case 13000000:
+		usec_config = 0x000c; /* (12+1)/(0+1) */
+		break;
+	case 16800000:
+		usec_config = 0x0453; /* (83+1)/(4+1) */
+		break;
+	case 19200000:
+		usec_config = 0x045f; /* (95+1)/(4+1) */
+		break;
+	case 26000000:
+		usec_config = 0x0019; /* (25+1)/(0+1) */
+		break;
+	case 38400000:
+		usec_config = 0x04bf; /* (191+1)/(4+1) */
+		break;
+	case 48000000:
+		usec_config = 0x002f; /* (47+1)/(0+1) */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable clock to timer hardware */
+	value = readl_relaxed(TEGRA_OSC_CLK_ENB_L_SET);
+	writel_relaxed(value | TEGRA_OSC_SET_CLK_ENB_TMR,
+		       TEGRA_OSC_CLK_ENB_L_SET);
+
+	writel_relaxed(usec_config, TEGRA_TIMER_USEC_CFG);
+
+	return 0;
+}
+
+static const struct timer_ops tegra_timer_ops = {
+	.get_count = tegra_timer_get_count,
+};
+
+static const struct udevice_id tegra_timer_ids[] = {
+	{ .compatible = "nvidia,tegra20-timer" },
+	{ .compatible = "nvidia,tegra30-timer" },
+	{ .compatible = "nvidia,tegra114-timer" },
+	{ .compatible = "nvidia,tegra124-timer" },
+	{ .compatible = "nvidia,tegra210-timer" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra_timer) = {
+	.name		= "tegra_timer",
+	.id		= UCLASS_TIMER,
+	.of_match	= tegra_timer_ids,
+	.probe		= tegra_timer_probe,
+	.ops		= &tegra_timer_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 11d7767..76562bd 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -127,42 +127,70 @@
 static const unsigned T20_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
 	{ 0x3C0, 0x0D, 0x00, 0xC,   0,  0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 },
+	{ 0x3C0, 0x0D, 0x00, 0xC,   0,  0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
 	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   0,  0x02, 0x2F, 0x04, 0x76, 0x7530, 5 },
 	{ 0x3C0, 0x0C, 0x00, 0xC,   0,  0x02, 0x2F, 0x04, 0x76, 0x7530, 5 },
-	{ 0x3C0, 0x1A, 0x00, 0xC,   0,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 },
 	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
-	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   0,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
 };
 
 static const unsigned T30_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
 	{ 0x3C0, 0x0D, 0x00, 0xC,   1,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 5 },
+	{ 0x3C0, 0x0D, 0x00, 0xC,   1,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 5 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
 	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 7 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 7 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
 	{ 0x3C0, 0x0C, 0x00, 0xC,   1,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
-	{ 0x3C0, 0x1A, 0x00, 0xC,   1,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   1,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
 	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
-	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+	{ 0x3C0, 0x1A, 0x00, 0xC,   1,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
 };
 
 static const unsigned T114_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
 	{ 0x3C0, 0x0D, 0x00, 0xC,   2,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 6 },
+	{ 0x3C0, 0x0D, 0x00, 0xC,   2,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 6 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   2,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 8 },
 	{ 0x0C8, 0x04, 0x00, 0x3,   2,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 8 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   2,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
 	{ 0x3C0, 0x0C, 0x00, 0xC,   2,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
-	{ 0x3C0, 0x1A, 0x00, 0xC,   2,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 11 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
 	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
-	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+	{ 0x3C0, 0x1A, 0x00, 0xC,   2,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 11 }
 };
 
 /* NOTE: 13/26MHz settings are N/A for T210, so dupe 12MHz settings for now */
 static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	/* DivN, DivM, DivP, KCP,   KVCO,  Delays              Debounce, Bias */
 	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  32500,  5 },
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  32500,  5 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
 	{ 0x019, 0x01, 0x01, 0x0,   0,  0x03, 0x4B, 0x0C, 0xBB,  48000,  8 },
-	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  30000,  5 },
-	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  65000,  5 },
 	{ 0x019, 0x02, 0x01, 0x0,   0,  0x05, 0x96, 0x18, 0x177, 96000, 15 },
-	{ 0x028, 0x04, 0x01, 0x0,   0,  0x04, 0x66, 0x09, 0xFE, 120000, 20 }
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  30000,  5 },
+	{ 0x028, 0x04, 0x01, 0x0,   0,  0x04, 0x66, 0x09, 0xFE, 120000, 20 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00,      0,  0 },
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  65000,  5 }
 };
 
 /* UTMIP Idle Wait Delay */
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index bde7ffc..c558679 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -15,12 +15,6 @@
 
 #include <asm/arch/tegra.h>		/* get chip and board defs */
 
-/* Use the Tegra US timer on ARMv7, but the architected timer on ARMv8. */
-#ifndef CONFIG_ARM64
-#define CFG_SYS_TIMER_RATE		1000000
-#define CFG_SYS_TIMER_COUNTER	NV_PA_TMRUS_BASE
-#endif
-
 /* Environment */
 
 /*