19055c7d1SRyan Harkin /* 2*a6485b2bSAbhi.Singh * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. 39055c7d1SRyan Harkin * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 59055c7d1SRyan Harkin */ 69055c7d1SRyan Harkin 79055c7d1SRyan Harkin #include <assert.h> 809d40e0eSAntonio Nino Diaz 99055c7d1SRyan Harkin #include <platform_def.h> 1009d40e0eSAntonio Nino Diaz 1109d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 1209d40e0eSAntonio Nino Diaz #include <lib/utils_def.h> 139055c7d1SRyan Harkin 149055c7d1SRyan Harkin /*********************************************************** 159055c7d1SRyan Harkin * The delay timer implementation 169055c7d1SRyan Harkin ***********************************************************/ 179fb8af33SRoberto Vargas static const timer_ops_t *timer_ops; 189055c7d1SRyan Harkin 199055c7d1SRyan Harkin /*********************************************************** 209055c7d1SRyan Harkin * Delay for the given number of microseconds. The driver must 219055c7d1SRyan Harkin * be initialized before calling this function. 229055c7d1SRyan Harkin ***********************************************************/ udelay(uint32_t usec)239055c7d1SRyan Harkinvoid udelay(uint32_t usec) 249055c7d1SRyan Harkin { 25d47509d6SSathees Balya assert((timer_ops != NULL) && 26d47509d6SSathees Balya (timer_ops->clk_mult != 0U) && 27d47509d6SSathees Balya (timer_ops->clk_div != 0U) && 289fb8af33SRoberto Vargas (timer_ops->get_timer_value != NULL)); 299055c7d1SRyan Harkin 30f2976bddSMax Shvetsov uint32_t start, delta; 31f2976bddSMax Shvetsov uint64_t total_delta; 329055c7d1SRyan Harkin 33f2976bddSMax Shvetsov assert(usec < (UINT64_MAX / timer_ops->clk_div)); 340bcedb22SAntonio Nino Diaz 359fb8af33SRoberto Vargas start = timer_ops->get_timer_value(); 360bcedb22SAntonio Nino Diaz 37e2aec918SJulius Werner /* Add an extra tick to avoid delaying less than requested. */ 389fb8af33SRoberto Vargas total_delta = 39f2976bddSMax Shvetsov div_round_up((uint64_t)usec * timer_ops->clk_div, 40d47509d6SSathees Balya timer_ops->clk_mult) + 1U; 41f2976bddSMax Shvetsov /* 42f2976bddSMax Shvetsov * Precaution for the total_delta ~ UINT32_MAX and the fact that we 43f2976bddSMax Shvetsov * cannot catch every tick of the timer. 44f2976bddSMax Shvetsov * For example 100MHz timer over 25MHz APB will miss at least 4 ticks. 45f2976bddSMax Shvetsov * 1000U is an arbitrary big number which is believed to be sufficient. 46f2976bddSMax Shvetsov */ 47f2976bddSMax Shvetsov assert(total_delta < (UINT32_MAX - 1000U)); 480bcedb22SAntonio Nino Diaz 499055c7d1SRyan Harkin do { 500bcedb22SAntonio Nino Diaz /* 510bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 520bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 53f2976bddSMax Shvetsov * delta is decreasing counter 540bcedb22SAntonio Nino Diaz */ 55f2976bddSMax Shvetsov delta = start - timer_ops->get_timer_value(); 560bcedb22SAntonio Nino Diaz 570bcedb22SAntonio Nino Diaz } while (delta < total_delta); 589055c7d1SRyan Harkin } 599055c7d1SRyan Harkin 609055c7d1SRyan Harkin /*********************************************************** 619055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 629055c7d1SRyan Harkin * be initialized before calling this function. 639055c7d1SRyan Harkin ***********************************************************/ mdelay(uint32_t msec)649055c7d1SRyan Harkinvoid mdelay(uint32_t msec) 659055c7d1SRyan Harkin { 66f2976bddSMax Shvetsov assert((msec * 1000UL) < UINT32_MAX); 67d47509d6SSathees Balya udelay(msec * 1000U); 689055c7d1SRyan Harkin } 699055c7d1SRyan Harkin 709055c7d1SRyan Harkin /*********************************************************** 719055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 729055c7d1SRyan Harkin * ops pointer must be valid. 739055c7d1SRyan Harkin ***********************************************************/ timer_init(const timer_ops_t * ops_ptr)749055c7d1SRyan Harkinvoid timer_init(const timer_ops_t *ops_ptr) 759055c7d1SRyan Harkin { 76d47509d6SSathees Balya assert((ops_ptr != NULL) && 77d47509d6SSathees Balya (ops_ptr->clk_mult != 0U) && 78d47509d6SSathees Balya (ops_ptr->clk_div != 0U) && 791496b489SEtienne Carriere (ops_ptr->get_timer_value != NULL)); 809055c7d1SRyan Harkin 819fb8af33SRoberto Vargas timer_ops = ops_ptr; 829055c7d1SRyan Harkin } 83*a6485b2bSAbhi.Singh 84*a6485b2bSAbhi.Singh /*********************************************************** 85*a6485b2bSAbhi.Singh * Initialize the timer in us 86*a6485b2bSAbhi.Singh ***********************************************************/ timeout_init_us(uint32_t usec)87*a6485b2bSAbhi.Singhuint64_t timeout_init_us(uint32_t usec) 88*a6485b2bSAbhi.Singh { 89*a6485b2bSAbhi.Singh assert(timer_ops != NULL); 90*a6485b2bSAbhi.Singh assert(timer_ops->timeout_init_us != NULL); 91*a6485b2bSAbhi.Singh 92*a6485b2bSAbhi.Singh return timer_ops->timeout_init_us(usec); 93*a6485b2bSAbhi.Singh } 94*a6485b2bSAbhi.Singh 95*a6485b2bSAbhi.Singh /*********************************************************** 96*a6485b2bSAbhi.Singh * check the given timeout elapsed or not. 97*a6485b2bSAbhi.Singh ***********************************************************/ timeout_elapsed(uint64_t cnt)98*a6485b2bSAbhi.Singhbool timeout_elapsed(uint64_t cnt) 99*a6485b2bSAbhi.Singh { 100*a6485b2bSAbhi.Singh assert(timer_ops != NULL); 101*a6485b2bSAbhi.Singh assert(timer_ops->timeout_elapsed != NULL); 102*a6485b2bSAbhi.Singh 103*a6485b2bSAbhi.Singh return timer_ops->timeout_elapsed(cnt); 104*a6485b2bSAbhi.Singh } 105