Skip to content

Commit 16a60bf

Browse files
committed
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. 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>
1 parent 96e6c84 commit 16a60bf

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

drivers/timer/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,14 @@ config STM32_TIMER
252252
Select this to enable support for the timer found on
253253
STM32 devices.
254254

255+
config TEGRA_TIMER
256+
bool "Tegra timer support"
257+
depends on TIMER
258+
select TIMER_EARLY
259+
help
260+
Select this to enable support for the timer found on
261+
Tegra devices.
262+
255263
config X86_TSC_TIMER
256264
bool "x86 Time-Stamp Counter (TSC) timer support"
257265
depends on TIMER && X86

drivers/timer/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ obj-$(CONFIG_SP804_TIMER) += sp804_timer.o
2727
obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint_timer.o
2828
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
2929
obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
30+
obj-$(CONFIG_TEGRA_TIMER) += tegra-timer.o
3031
obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
3132
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
3233
obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o

drivers/timer/tegra-timer.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright (C) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4+
*/
5+
6+
#include <common.h>
7+
#include <dm.h>
8+
#include <errno.h>
9+
#include <timer.h>
10+
11+
#include <asm/io.h>
12+
#include <asm/arch/clock.h>
13+
#include <asm/arch/tegra.h>
14+
15+
#define TEGRA_OSC_CLK_ENB_L_SET (NV_PA_CLK_RST_BASE + 0x320)
16+
#define TEGRA_OSC_SET_CLK_ENB_TMR BIT(5)
17+
18+
#define TEGRA_TIMER_USEC_CNTR (NV_PA_TMRUS_BASE + 0)
19+
#define TEGRA_TIMER_USEC_CFG (NV_PA_TMRUS_BASE + 4)
20+
21+
#define TEGRA_TIMER_RATE 1000000 /* 1 MHz */
22+
23+
u64 notrace timer_early_get_count(void)
24+
{
25+
/* At this stage raw timer is used */
26+
return readl(TEGRA_TIMER_USEC_CNTR);
27+
}
28+
29+
unsigned long notrace timer_early_get_rate(void)
30+
{
31+
return TEGRA_TIMER_RATE;
32+
}
33+
34+
#if CONFIG_IS_ENABLED(BOOTSTAGE)
35+
ulong timer_get_boot_us(void)
36+
{
37+
u64 ticks = 0;
38+
int ret;
39+
40+
ret = dm_timer_init();
41+
if (!ret)
42+
timer_get_count(gd->timer, &ticks);
43+
else
44+
ticks = timer_early_get_count();
45+
46+
return ticks;
47+
}
48+
#endif
49+
50+
static notrace u64 tegra_timer_get_count(struct udevice *dev)
51+
{
52+
u32 val = timer_early_get_count();
53+
return timer_conv_64(val);
54+
}
55+
56+
static int tegra_timer_probe(struct udevice *dev)
57+
{
58+
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
59+
u32 usec_config, value;
60+
61+
/* Timer rate has to be set unconditionally */
62+
uc_priv->clock_rate = TEGRA_TIMER_RATE;
63+
64+
/*
65+
* Configure microsecond timers to have 1MHz clock
66+
* Config register is 0xqqww, where qq is "dividend", ww is "divisor"
67+
* Uses n+1 scheme
68+
*/
69+
switch (clock_get_osc_freq()) {
70+
case CLOCK_OSC_FREQ_13_0:
71+
usec_config = 0x000c; /* (12+1)/(0+1) */
72+
break;
73+
case CLOCK_OSC_FREQ_19_2:
74+
usec_config = 0x045f; /* (95+1)/(4+1) */
75+
break;
76+
case CLOCK_OSC_FREQ_12_0:
77+
usec_config = 0x000b; /* (11+1)/(0+1) */
78+
break;
79+
case CLOCK_OSC_FREQ_26_0:
80+
usec_config = 0x0019; /* (25+1)/(0+1) */
81+
break;
82+
case CLOCK_OSC_FREQ_16_8:
83+
usec_config = 0x0453; /* (83+1)/(4+1) */
84+
break;
85+
case CLOCK_OSC_FREQ_38_4:
86+
usec_config = 0x04bf; /* (191+1)/(4+1) */
87+
break;
88+
case CLOCK_OSC_FREQ_48_0:
89+
usec_config = 0x002f; /* (47+1)/(0+1) */
90+
break;
91+
default:
92+
return -EINVAL;
93+
}
94+
95+
/* Enable clock to timer hardware */
96+
value = readl_relaxed(TEGRA_OSC_CLK_ENB_L_SET);
97+
writel_relaxed(value | TEGRA_OSC_SET_CLK_ENB_TMR,
98+
TEGRA_OSC_CLK_ENB_L_SET);
99+
100+
writel_relaxed(usec_config, TEGRA_TIMER_USEC_CFG);
101+
102+
return 0;
103+
}
104+
105+
static const struct timer_ops tegra_timer_ops = {
106+
.get_count = tegra_timer_get_count,
107+
};
108+
109+
static const struct udevice_id tegra_timer_ids[] = {
110+
{ .compatible = "nvidia,tegra20-timer" },
111+
{ .compatible = "nvidia,tegra30-timer" },
112+
{ .compatible = "nvidia,tegra114-timer" },
113+
{ .compatible = "nvidia,tegra124-timer" },
114+
{ }
115+
};
116+
117+
U_BOOT_DRIVER(tegra_timer) = {
118+
.name = "tegra_timer",
119+
.id = UCLASS_TIMER,
120+
.of_match = tegra_timer_ids,
121+
.probe = tegra_timer_probe,
122+
.ops = &tegra_timer_ops,
123+
.flags = DM_FLAG_PRE_RELOC,
124+
};

0 commit comments

Comments
 (0)