19055c7d1SRyan Harkin /* 2*9fb8af33SRoberto 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 ***********************************************************/ 15*9fb8af33SRoberto 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*9fb8af33SRoberto Vargas assert(timer_ops != NULL && 24*9fb8af33SRoberto Vargas (timer_ops->clk_mult != 0) && 25*9fb8af33SRoberto Vargas (timer_ops->clk_div != 0) && 26*9fb8af33SRoberto Vargas (timer_ops->get_timer_value != NULL)); 279055c7d1SRyan Harkin 280bcedb22SAntonio Nino Diaz uint32_t start, delta, total_delta; 299055c7d1SRyan Harkin 30*9fb8af33SRoberto Vargas assert(usec < UINT32_MAX / timer_ops->clk_div); 310bcedb22SAntonio Nino Diaz 32*9fb8af33SRoberto Vargas start = timer_ops->get_timer_value(); 330bcedb22SAntonio Nino Diaz 34e2aec918SJulius Werner /* Add an extra tick to avoid delaying less than requested. */ 35*9fb8af33SRoberto Vargas total_delta = 36*9fb8af33SRoberto Vargas div_round_up(usec * timer_ops->clk_div, timer_ops->clk_mult) + 1; 370bcedb22SAntonio Nino Diaz 389055c7d1SRyan Harkin do { 390bcedb22SAntonio Nino Diaz /* 400bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 410bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 420bcedb22SAntonio Nino Diaz */ 43*9fb8af33SRoberto Vargas delta = start - timer_ops->get_timer_value(); /* Decreasing counter */ 440bcedb22SAntonio Nino Diaz 450bcedb22SAntonio Nino Diaz } while (delta < total_delta); 469055c7d1SRyan Harkin } 479055c7d1SRyan Harkin 489055c7d1SRyan Harkin /*********************************************************** 499055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 509055c7d1SRyan Harkin * be initialized before calling this function. 519055c7d1SRyan Harkin ***********************************************************/ 529055c7d1SRyan Harkin void mdelay(uint32_t msec) 539055c7d1SRyan Harkin { 549055c7d1SRyan Harkin udelay(msec*1000); 559055c7d1SRyan Harkin } 569055c7d1SRyan Harkin 579055c7d1SRyan Harkin /*********************************************************** 589055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 599055c7d1SRyan Harkin * ops pointer must be valid. 609055c7d1SRyan Harkin ***********************************************************/ 619055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr) 629055c7d1SRyan Harkin { 631496b489SEtienne Carriere assert(ops_ptr != NULL && 649055c7d1SRyan Harkin (ops_ptr->clk_mult != 0) && 659055c7d1SRyan Harkin (ops_ptr->clk_div != 0) && 661496b489SEtienne Carriere (ops_ptr->get_timer_value != NULL)); 679055c7d1SRyan Harkin 68*9fb8af33SRoberto Vargas timer_ops = ops_ptr; 699055c7d1SRyan Harkin } 70