19055c7d1SRyan Harkin /* 29fb8af33SRoberto Vargas * Copyright (c) 2015-2018, 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> 89055c7d1SRyan Harkin #include <delay_timer.h> 99055c7d1SRyan Harkin #include <platform_def.h> 10e2aec918SJulius Werner #include <utils_def.h> 119055c7d1SRyan Harkin 129055c7d1SRyan Harkin /*********************************************************** 139055c7d1SRyan Harkin * The delay timer implementation 149055c7d1SRyan Harkin ***********************************************************/ 159fb8af33SRoberto Vargas static const timer_ops_t *timer_ops; 169055c7d1SRyan Harkin 179055c7d1SRyan Harkin /*********************************************************** 189055c7d1SRyan Harkin * Delay for the given number of microseconds. The driver must 199055c7d1SRyan Harkin * be initialized before calling this function. 209055c7d1SRyan Harkin ***********************************************************/ 219055c7d1SRyan Harkin void udelay(uint32_t usec) 229055c7d1SRyan Harkin { 23*d47509d6SSathees Balya assert((timer_ops != NULL) && 24*d47509d6SSathees Balya (timer_ops->clk_mult != 0U) && 25*d47509d6SSathees Balya (timer_ops->clk_div != 0U) && 269fb8af33SRoberto Vargas (timer_ops->get_timer_value != NULL)); 279055c7d1SRyan Harkin 280bcedb22SAntonio Nino Diaz uint32_t start, delta, total_delta; 299055c7d1SRyan Harkin 30*d47509d6SSathees Balya assert(usec < (UINT32_MAX / timer_ops->clk_div)); 310bcedb22SAntonio Nino Diaz 329fb8af33SRoberto Vargas start = timer_ops->get_timer_value(); 330bcedb22SAntonio Nino Diaz 34e2aec918SJulius Werner /* Add an extra tick to avoid delaying less than requested. */ 359fb8af33SRoberto Vargas total_delta = 36*d47509d6SSathees Balya div_round_up(usec * timer_ops->clk_div, 37*d47509d6SSathees Balya timer_ops->clk_mult) + 1U; 380bcedb22SAntonio Nino Diaz 399055c7d1SRyan Harkin do { 400bcedb22SAntonio Nino Diaz /* 410bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 420bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 430bcedb22SAntonio Nino Diaz */ 449fb8af33SRoberto Vargas delta = start - timer_ops->get_timer_value(); /* Decreasing counter */ 450bcedb22SAntonio Nino Diaz 460bcedb22SAntonio Nino Diaz } while (delta < total_delta); 479055c7d1SRyan Harkin } 489055c7d1SRyan Harkin 499055c7d1SRyan Harkin /*********************************************************** 509055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 519055c7d1SRyan Harkin * be initialized before calling this function. 529055c7d1SRyan Harkin ***********************************************************/ 539055c7d1SRyan Harkin void mdelay(uint32_t msec) 549055c7d1SRyan Harkin { 55*d47509d6SSathees Balya udelay(msec * 1000U); 569055c7d1SRyan Harkin } 579055c7d1SRyan Harkin 589055c7d1SRyan Harkin /*********************************************************** 599055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 609055c7d1SRyan Harkin * ops pointer must be valid. 619055c7d1SRyan Harkin ***********************************************************/ 629055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr) 639055c7d1SRyan Harkin { 64*d47509d6SSathees Balya assert((ops_ptr != NULL) && 65*d47509d6SSathees Balya (ops_ptr->clk_mult != 0U) && 66*d47509d6SSathees Balya (ops_ptr->clk_div != 0U) && 671496b489SEtienne Carriere (ops_ptr->get_timer_value != NULL)); 689055c7d1SRyan Harkin 699fb8af33SRoberto Vargas timer_ops = ops_ptr; 709055c7d1SRyan Harkin } 71