
Add an implementation of the timer functions for tegra, so that timing is more accurate. Tegra has a 1 microsecond timer for this purpose.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/tegra-common/Makefile | 1 + arch/arm/cpu/tegra-common/timer.c | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 arch/arm/cpu/tegra-common/timer.c
diff --git a/arch/arm/cpu/tegra-common/Makefile b/arch/arm/cpu/tegra-common/Makefile index a78869e..3dbe97f 100644 --- a/arch/arm/cpu/tegra-common/Makefile +++ b/arch/arm/cpu/tegra-common/Makefile @@ -14,6 +14,7 @@ obj-y += clock.o obj-y += lowlevel_init.o obj-y += pinmux-common.o obj-y += powergate.o +obj-y += timer.o obj-y += xusb-padctl.o obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o obj-$(CONFIG_TEGRA124) += vpr.o diff --git a/arch/arm/cpu/tegra-common/timer.c b/arch/arm/cpu/tegra-common/timer.c new file mode 100644 index 0000000..c7f80a5 --- /dev/null +++ b/arch/arm/cpu/tegra-common/timer.c @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2015 Googoe, Inc + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * (C) Copyright 2008 + * Texas Instruments + * + * Richard Woodruff r-woodruff2@ti.com + * Syed Moahmmed Khasim khasim@ti.com + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger mgroeger@sysgo.de + * Alex Zuepke azu@sysgo.de + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/timer.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* counter runs at 1MHz */ +#define TIMER_CLK 1000000 +#define TIMER_LOAD_VAL 0xffffffff + +/* timer without interrupts */ +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* delay x useconds */ +void __udelay(unsigned long usec) +{ + long tmo = usec * (TIMER_CLK / 1000) / 1000; + unsigned long now, last = timer_get_us(); + + while (tmo > 0) { + now = timer_get_us(); + if (last > now) /* count up timer overflow */ + tmo -= TIMER_LOAD_VAL - last + now; + else + tmo -= now - last; + last = now; + } +} + +ulong get_timer_masked(void) +{ + ulong now; + + /* current tick value */ + now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ); + + if (now >= gd->arch.lastinc) /* normal mode (non roll) */ + /* move stamp forward with absolute diff ticks */ + gd->arch.tbl += (now - gd->arch.lastinc); + else /* we have rollover of incrementer */ + gd->arch.tbl += ((TIMER_LOAD_VAL / (TIMER_CLK / CONFIG_SYS_HZ)) + - gd->arch.lastinc) + now; + gd->arch.lastinc = now; + return gd->arch.tbl; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +unsigned long timer_get_us(void) +{ + struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE; + + return readl(&timer_base->cntr_1us); +}