diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index 1fcd0f9ba..1faddbedc 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -597,6 +598,10 @@ #define CNTP_CTL_IMASK_MASK U(1) #define CNTP_CTL_ISTATUS_MASK U(1) +/* Physical timer control macros */ +#define CNTP_CTL_ENABLE_BIT (U(1) << CNTP_CTL_ENABLE_SHIFT) +#define CNTP_CTL_IMASK_BIT (U(1) << CNTP_CTL_IMASK_SHIFT) + /* Exception Syndrome register bits and bobs */ #define ESR_EC_SHIFT U(26) #define ESR_EC_MASK U(0x3f) diff --git a/plat/nvidia/tegra/common/tegra_delay_timer.c b/plat/nvidia/tegra/common/tegra_delay_timer.c index 63dcf410c..cfd9a15e3 100644 --- a/plat/nvidia/tegra/common/tegra_delay_timer.c +++ b/plat/nvidia/tegra/common/tegra_delay_timer.c @@ -1,31 +1,59 @@ /* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include + #include #include +#include +#include #include #include -static uint32_t tegra_timerus_get_value(void) +static uint32_t tegra_timer_get_value(void) { - return mmio_read_32(TEGRA_TMRUS_BASE); + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + + /* + * Generic delay timer implementation expects the timer to be a down + * counter. We apply bitwise NOT operator to the tick values returned + * by read_cntps_tval_el1() to simulate the down counter. The value is + * clipped from 64 to 32 bits. + */ + return (uint32_t)(~read_cntps_tval_el1()); } /* - * Initialise the on-chip free rolling us counter as the delay - * timer. + * Initialise the architecture provided counter as the delay timer. */ void tegra_delay_timer_init(void) { - static const timer_ops_t tegra_timer_ops = { - .get_timer_value = tegra_timerus_get_value, - .clk_mult = 1, - .clk_div = 1, - }; + static timer_ops_t tegra_timer_ops; + /* Value in ticks */ + uint32_t multiplier = MHZ_TICKS_PER_SEC; + + /* Value in ticks per second (Hz) */ + uint32_t divider = plat_get_syscnt_freq2(); + + /* Reduce multiplier and divider by dividing them repeatedly by 10 */ + while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) { + multiplier /= 10U; + divider /= 10U; + } + + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + + /* register the timer */ + tegra_timer_ops.get_timer_value = tegra_timer_get_value; + tegra_timer_ops.clk_mult = multiplier; + tegra_timer_ops.clk_div = divider; timer_init(&tegra_timer_ops); }