[PATCH v4 0/3] Timer support for ARM Tegra

- ARM: tegra: remap clock_osc_freq for all Tegra family Enum clock_osc_freq was designed to use only with T20. This patch remaps it to use additional frequencies, added in T30+ SoC while maintaining backwards compatibility with T20.
- drivers: timer: add timer driver for ARMv7 based Tegra devices Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
- ARM: tegra: include timer as default option Enable TIMER as default option for add Tegra devices and enable TEGRA_TIMER for TEGRA_ARMV7_COMMON. Additionally enable SPL_TIMER if build as SPL part and drop deprecated configs from common header.
P. S. I have no arm64 Tegra and according to comment in tegra-common.h Use the Tegra US timer on ARMv7, but the architected timer on ARMv8.
Svyatoslav Ryhel (3): ARM: tegra: remap clock_osc_freq for all Tegra family drivers: timer: add timer driver for ARMv7 based Tegra devices ARM: tegra: include timer as default option
arch/arm/Kconfig | 1 + arch/arm/include/asm/arch-tegra/clock.h | 9 +- arch/arm/mach-tegra/Kconfig | 2 + arch/arm/mach-tegra/clock.c | 17 +++- arch/arm/mach-tegra/cpu.c | 70 ++++++++++++--- arch/arm/mach-tegra/tegra114/clock.c | 13 ++- arch/arm/mach-tegra/tegra124/clock.c | 13 ++- arch/arm/mach-tegra/tegra20/clock.c | 4 +- arch/arm/mach-tegra/tegra210/clock.c | 22 +---- arch/arm/mach-tegra/tegra30/clock.c | 10 +-- drivers/timer/Kconfig | 8 ++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++ drivers/usb/host/ehci-tegra.c | 46 ++++++++-- include/configs/tegra-common.h | 6 -- 15 files changed, 256 insertions(+), 79 deletions(-) create mode 100644 drivers/timer/tegra-timer.c

Enum clock_osc_freq was designed to use only with T20. This patch remaps it to use additional frequencies, added in T30+ SoC while maintaining backwards compatibility with T20.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com Reviewed-by: Simon Glass sjg@chromium.org --- arch/arm/include/asm/arch-tegra/clock.h | 9 ++-- arch/arm/mach-tegra/clock.c | 17 ++++-- arch/arm/mach-tegra/cpu.c | 70 ++++++++++++++++++++----- arch/arm/mach-tegra/tegra114/clock.c | 13 ++--- arch/arm/mach-tegra/tegra124/clock.c | 13 ++--- arch/arm/mach-tegra/tegra20/clock.c | 4 +- arch/arm/mach-tegra/tegra210/clock.c | 22 ++------ arch/arm/mach-tegra/tegra30/clock.c | 10 +--- drivers/usb/host/ehci-tegra.c | 46 ++++++++++++---- 9 files changed, 131 insertions(+), 73 deletions(-)
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h index 6586015fd2..1dd5d0742c 100644 --- a/arch/arm/include/asm/arch-tegra/clock.h +++ b/arch/arm/include/asm/arch-tegra/clock.h @@ -13,12 +13,13 @@ struct udevice; /* 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/clock.c b/arch/arm/mach-tegra/clock.c index 77c8ad978e..11bffc1701 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 @@ void tegra30_set_up_pllp(void) */ 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 @@ void tegra30_set_up_pllp(void) 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 65b15b79fe..59ca8aeaba 100644 --- a/arch/arm/mach-tegra/cpu.c +++ b/arch/arm/mach-tegra/cpu.c @@ -55,11 +55,18 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { */ { { .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 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { */ { { .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 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { */ { { .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 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { */ { { .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 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { */ { { .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 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { * 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 703a2314e7..143f86863f 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -459,8 +459,7 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/* * 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 @@ enum clock_osc_freq clock_get_osc_freq(void) 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 @@ void clock_early_init(void) */ 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 @@ void clock_early_init(void) 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 bbfe184652..da38b26c27 100644 --- a/arch/arm/mach-tegra/tegra124/clock.c +++ b/arch/arm/mach-tegra/tegra124/clock.c @@ -601,8 +601,7 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/* * 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 @@ enum clock_osc_freq clock_get_osc_freq(void) 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 @@ void clock_early_init(void) */ 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 @@ void clock_early_init(void) 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 3b50a81194..8c127430aa 100644 --- a/arch/arm/mach-tegra/tegra20/clock.c +++ b/arch/arm/mach-tegra/tegra20/clock.c @@ -399,7 +399,9 @@ enum clock_osc_freq clock_get_osc_freq(void) 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 10c2478df7..330753f2ad 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -672,8 +672,7 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/* * 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 @@ enum clock_osc_freq clock_get_osc_freq(void) 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 @@ void clock_early_init(void) */ 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 @@ void clock_early_init(void) 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 c835cd0d47..449b66e3b2 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -439,8 +439,7 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/* * 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 @@ enum clock_osc_freq clock_get_osc_freq(void) 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/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b02ee89c3e..6fe8594d48 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -127,42 +127,70 @@ struct fdt_usb { 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 */

Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Co-developed-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
---
Changed in v4: - removed BOOTSTAGE ifdefs - use early timer on boot stage unconditionally --- drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/timer/tegra-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6d6665005c..f32bd16227 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -252,6 +252,14 @@ config STM32_TIMER 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 6470fd5426..3c92113fc6 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o 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 0000000000..f0d8ba727d --- /dev/null +++ b/drivers/timer/tegra-timer.c @@ -0,0 +1,113 @@ +// 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 */ + +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(); +} + +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_osc_freq()) { + case CLOCK_OSC_FREQ_13_0: + usec_config = 0x000c; /* (12+1)/(0+1) */ + break; + case CLOCK_OSC_FREQ_19_2: + usec_config = 0x045f; /* (95+1)/(4+1) */ + break; + case CLOCK_OSC_FREQ_12_0: + usec_config = 0x000b; /* (11+1)/(0+1) */ + break; + case CLOCK_OSC_FREQ_26_0: + usec_config = 0x0019; /* (25+1)/(0+1) */ + break; + case CLOCK_OSC_FREQ_16_8: + usec_config = 0x0453; /* (83+1)/(4+1) */ + break; + case CLOCK_OSC_FREQ_38_4: + usec_config = 0x04bf; /* (191+1)/(4+1) */ + break; + case CLOCK_OSC_FREQ_48_0: + 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" }, + { } +}; + +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, +};

Hi Svyatoslav,
On Wed, 18 Jan 2023 at 01:44, Svyatoslav Ryhel clamor95@gmail.com wrote:
Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Co-developed-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
Changed in v4:
- removed BOOTSTAGE ifdefs
- use early timer on boot stage unconditionally
drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/timer/tegra-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6d6665005c..f32bd16227 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -252,6 +252,14 @@ config STM32_TIMER 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 6470fd5426..3c92113fc6 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o 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 0000000000..f0d8ba727d --- /dev/null +++ b/drivers/timer/tegra-timer.c @@ -0,0 +1,113 @@ +// 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 */
+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;
Is that the rate at reset, before the timer is inited? Remember this is called before your probe() function.
If not, you will need to init it first here.
+}
+ulong timer_get_boot_us(void) +{
return timer_early_get_count();
+}
+static notrace u64 tegra_timer_get_count(struct udevice *dev) +{
u32 val = timer_early_get_count();
return timer_conv_64(val);
Here you are ignoring the probed timing, if available. You should really use uc_priv->clock_rate
+}
Regards, Simon

ср, 18 січ. 2023 р. о 21:42 Simon Glass sjg@chromium.org пише:
Hi Svyatoslav,
On Wed, 18 Jan 2023 at 01:44, Svyatoslav Ryhel clamor95@gmail.com wrote:
Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Co-developed-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
Changed in v4:
- removed BOOTSTAGE ifdefs
- use early timer on boot stage unconditionally
drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/timer/tegra-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6d6665005c..f32bd16227 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -252,6 +252,14 @@ config STM32_TIMER 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 6470fd5426..3c92113fc6 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o 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 0000000000..f0d8ba727d --- /dev/null +++ b/drivers/timer/tegra-timer.c @@ -0,0 +1,113 @@ +// 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 */
+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;
Is that the rate at reset, before the timer is inited? Remember this is called before your probe() function.
If not, you will need to init it first here.
It has to be 1 MHz left by the primary bootloader (bootrom). In the case of reset default value set is 1/13 of osc clock. Unfortunately at this stage we can not determine the exact osc clock since it is in the clock and reset device (which itself can not be ready). Pre-dm timer might not be explicitly precise but it works fine on early stages with providing delays.
+}
+ulong timer_get_boot_us(void) +{
return timer_early_get_count();
+}
+static notrace u64 tegra_timer_get_count(struct udevice *dev) +{
u32 val = timer_early_get_count();
return timer_conv_64(val);
Here you are ignoring the probed timing, if available. You should really use uc_priv->clock_rate
At this point the timer is already probed and configured to have a precise 1MHz clock. Tegra timer has a step of 1 microsecond.
U-Boot documentation of timer suggested to refer to sandbox timer and sandbox timer get_count uses microsecond cont.
https://github.com/u-boot/u-boot/blob/a94ab561e2f49a80d8579930e840b810ab1a13...
os_get_nsec() / 1000 which is nanosec / 1000 = microsecond
+}
Regards, Simon

Hi Svyatoslav,
On Thu, 19 Jan 2023 at 00:12, Svyatoslav Ryhel clamor95@gmail.com wrote:
ср, 18 січ. 2023 р. о 21:42 Simon Glass sjg@chromium.org пише:
Hi Svyatoslav,
On Wed, 18 Jan 2023 at 01:44, Svyatoslav Ryhel clamor95@gmail.com wrote:
Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Co-developed-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
Changed in v4:
- removed BOOTSTAGE ifdefs
- use early timer on boot stage unconditionally
drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/timer/tegra-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6d6665005c..f32bd16227 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -252,6 +252,14 @@ config STM32_TIMER 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 6470fd5426..3c92113fc6 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o 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 0000000000..f0d8ba727d --- /dev/null +++ b/drivers/timer/tegra-timer.c @@ -0,0 +1,113 @@ +// 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 */
+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;
Is that the rate at reset, before the timer is inited? Remember this is called before your probe() function.
If not, you will need to init it first here.
It has to be 1 MHz left by the primary bootloader (bootrom). In the case of reset default value set is 1/13 of osc clock. Unfortunately at this stage we can not determine the exact osc clock since it is in the clock and reset device (which itself can not be ready). Pre-dm timer might not be explicitly precise but it works fine on early stages with providing delays.
+}
+ulong timer_get_boot_us(void) +{
return timer_early_get_count();
+}
+static notrace u64 tegra_timer_get_count(struct udevice *dev) +{
u32 val = timer_early_get_count();
return timer_conv_64(val);
Here you are ignoring the probed timing, if available. You should really use uc_priv->clock_rate
At this point the timer is already probed and configured to have a precise 1MHz clock. Tegra timer has a step of 1 microsecond.
U-Boot documentation of timer suggested to refer to sandbox timer and sandbox timer get_count uses microsecond cont.
https://github.com/u-boot/u-boot/blob/a94ab561e2f49a80d8579930e840b810ab1a13...
os_get_nsec() / 1000 which is nanosec / 1000 = microsecond
That sounds OK. Then can you please add a few comments as to why you are ignoring the clock_rate? It will confuse other people who copy your driver? Mentioning the boot ROM, etc. helps too.
With that, please add:
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

чт, 19 січ. 2023 р. о 18:19 Simon Glass sjg@chromium.org пише:
Hi Svyatoslav,
On Thu, 19 Jan 2023 at 00:12, Svyatoslav Ryhel clamor95@gmail.com wrote:
ср, 18 січ. 2023 р. о 21:42 Simon Glass sjg@chromium.org пише:
Hi Svyatoslav,
On Wed, 18 Jan 2023 at 01:44, Svyatoslav Ryhel clamor95@gmail.com wrote:
Add timer support for T20/T30/T114 and T124 based devices. Driver is based on DM, has device tree support and can be used on SPL and early boot stage.
Tested-by: Andreas Westman Dorcsak hedmoo@yahoo.com # ASUS TF600T T30 Tested-by: Jonas Schwöbel jonasschwoebel@yahoo.de # Surface RT T30 Tested-by: Robert Eckelmann longnoserob@gmail.com # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel clamor95@gmail.com # LG P895 T30 Co-developed-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Jonas Schwöbel jonasschwoebel@yahoo.de Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
Changed in v4:
- removed BOOTSTAGE ifdefs
- use early timer on boot stage unconditionally
drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/tegra-timer.c | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/timer/tegra-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6d6665005c..f32bd16227 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -252,6 +252,14 @@ config STM32_TIMER 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 6470fd5426..3c92113fc6 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o 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 0000000000..f0d8ba727d --- /dev/null +++ b/drivers/timer/tegra-timer.c @@ -0,0 +1,113 @@ +// 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 */
+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;
Is that the rate at reset, before the timer is inited? Remember this is called before your probe() function.
If not, you will need to init it first here.
It has to be 1 MHz left by the primary bootloader (bootrom). In the case of reset default value set is 1/13 of osc clock. Unfortunately at this stage we can not determine the exact osc clock since it is in the clock and reset device (which itself can not be ready). Pre-dm timer might not be explicitly precise but it works fine on early stages with providing delays.
+}
+ulong timer_get_boot_us(void) +{
return timer_early_get_count();
+}
+static notrace u64 tegra_timer_get_count(struct udevice *dev) +{
u32 val = timer_early_get_count();
return timer_conv_64(val);
Here you are ignoring the probed timing, if available. You should really use uc_priv->clock_rate
At this point the timer is already probed and configured to have a precise 1MHz clock. Tegra timer has a step of 1 microsecond.
U-Boot documentation of timer suggested to refer to sandbox timer and sandbox timer get_count uses microsecond cont.
https://github.com/u-boot/u-boot/blob/a94ab561e2f49a80d8579930e840b810ab1a13...
os_get_nsec() / 1000 which is nanosec / 1000 = microsecond
That sounds OK. Then can you please add a few comments as to why you are ignoring the clock_rate? It will confuse other people who copy your driver? Mentioning the boot ROM, etc. helps too.
With that, please add:
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon
Thank you! Will do it as soon as possible. Best regards, Svyatoslav R.

Enable TIMER as default option for add Tegra devices and enable TEGRA_TIMER for TEGRA_ARMV7_COMMON. Additionally enable SPL_TIMER if build as SPL part and drop deprecated configs from common header.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com Reviewed-by: Simon Glass sjg@chromium.org --- arch/arm/Kconfig | 1 + arch/arm/mach-tegra/Kconfig | 2 ++ include/configs/tegra-common.h | 6 ------ 3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bbf1d5227b..9abd923149 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1285,6 +1285,7 @@ config ARCH_TEGRA 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/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 1b575cc0f4..cc3f00e501 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -56,6 +56,7 @@ config TEGRA_COMMON select MISC select OF_CONTROL select SPI + select TIMER imply CMD_DM imply CRC32_VERIFY
@@ -81,6 +82,7 @@ config TEGRA_ARMV7_COMMON select TEGRA_NO_BPMP select TEGRA_PINCTRL select TEGRA_PMC + select TEGRA_TIMER
config TEGRA_ARMV8_COMMON bool "Tegra 64-bit common options" diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index bde7ffce00..c558679d04 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 */
/*
participants (2)
-
Simon Glass
-
Svyatoslav Ryhel