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