1 /* 2 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. 3 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <arch.h> 9 10 #include <drivers/delay_timer.h> 11 #include <lib/mmio.h> 12 #include <lib/utils_def.h> 13 #include <plat/common/platform.h> 14 15 #include <tegra_def.h> 16 #include <tegra_private.h> 17 18 static uint32_t tegra_timer_get_value(void) 19 { 20 /* enable cntps_tval_el1 timer, mask interrupt */ 21 write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); 22 23 /* 24 * Generic delay timer implementation expects the timer to be a down 25 * counter. We apply bitwise NOT operator to the tick values returned 26 * by read_cntps_tval_el1() to simulate the down counter. The value is 27 * clipped from 64 to 32 bits. 28 */ 29 return (uint32_t)(~read_cntps_tval_el1()); 30 } 31 32 /* 33 * Initialise the architecture provided counter as the delay timer. 34 */ 35 void tegra_delay_timer_init(void) 36 { 37 static timer_ops_t tegra_timer_ops; 38 39 /* Value in ticks */ 40 uint32_t multiplier = MHZ_TICKS_PER_SEC; 41 42 /* Value in ticks per second (Hz) */ 43 uint32_t divider = plat_get_syscnt_freq2(); 44 45 /* Reduce multiplier and divider by dividing them repeatedly by 10 */ 46 while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) { 47 multiplier /= 10U; 48 divider /= 10U; 49 } 50 51 /* enable cntps_tval_el1 timer, mask interrupt */ 52 write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); 53 54 /* register the timer */ 55 tegra_timer_ops.get_timer_value = tegra_timer_get_value; 56 tegra_timer_ops.clk_mult = multiplier; 57 tegra_timer_ops.clk_div = divider; 58 timer_init(&tegra_timer_ops); 59 } 60