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> 8*09d40e0eSAntonio Nino Diaz 99055c7d1SRyan Harkin #include <platform_def.h> 10*09d40e0eSAntonio Nino Diaz 11*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 12*09d40e0eSAntonio 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 ***********************************************************/ 239055c7d1SRyan Harkin void 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 300bcedb22SAntonio Nino Diaz uint32_t start, delta, total_delta; 319055c7d1SRyan Harkin 32d47509d6SSathees Balya assert(usec < (UINT32_MAX / timer_ops->clk_div)); 330bcedb22SAntonio Nino Diaz 349fb8af33SRoberto Vargas start = timer_ops->get_timer_value(); 350bcedb22SAntonio Nino Diaz 36e2aec918SJulius Werner /* Add an extra tick to avoid delaying less than requested. */ 379fb8af33SRoberto Vargas total_delta = 38d47509d6SSathees Balya div_round_up(usec * timer_ops->clk_div, 39d47509d6SSathees Balya timer_ops->clk_mult) + 1U; 400bcedb22SAntonio Nino Diaz 419055c7d1SRyan Harkin do { 420bcedb22SAntonio Nino Diaz /* 430bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 440bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 450bcedb22SAntonio Nino Diaz */ 469fb8af33SRoberto Vargas delta = start - timer_ops->get_timer_value(); /* Decreasing counter */ 470bcedb22SAntonio Nino Diaz 480bcedb22SAntonio Nino Diaz } while (delta < total_delta); 499055c7d1SRyan Harkin } 509055c7d1SRyan Harkin 519055c7d1SRyan Harkin /*********************************************************** 529055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 539055c7d1SRyan Harkin * be initialized before calling this function. 549055c7d1SRyan Harkin ***********************************************************/ 559055c7d1SRyan Harkin void mdelay(uint32_t msec) 569055c7d1SRyan Harkin { 57d47509d6SSathees Balya udelay(msec * 1000U); 589055c7d1SRyan Harkin } 599055c7d1SRyan Harkin 609055c7d1SRyan Harkin /*********************************************************** 619055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 629055c7d1SRyan Harkin * ops pointer must be valid. 639055c7d1SRyan Harkin ***********************************************************/ 649055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr) 659055c7d1SRyan Harkin { 66d47509d6SSathees Balya assert((ops_ptr != NULL) && 67d47509d6SSathees Balya (ops_ptr->clk_mult != 0U) && 68d47509d6SSathees Balya (ops_ptr->clk_div != 0U) && 691496b489SEtienne Carriere (ops_ptr->get_timer_value != NULL)); 709055c7d1SRyan Harkin 719fb8af33SRoberto Vargas timer_ops = ops_ptr; 729055c7d1SRyan Harkin } 73