19055c7d1SRyan Harkin /* 29055c7d1SRyan Harkin * Copyright (c) 2015, 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> 10*e2aec918SJulius Werner #include <utils_def.h> 119055c7d1SRyan Harkin 129055c7d1SRyan Harkin /*********************************************************** 139055c7d1SRyan Harkin * The delay timer implementation 149055c7d1SRyan Harkin ***********************************************************/ 159055c7d1SRyan Harkin static const timer_ops_t *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 { 231496b489SEtienne Carriere assert(ops != NULL && 249055c7d1SRyan Harkin (ops->clk_mult != 0) && 259055c7d1SRyan Harkin (ops->clk_div != 0) && 261496b489SEtienne Carriere (ops->get_timer_value != NULL)); 279055c7d1SRyan Harkin 280bcedb22SAntonio Nino Diaz uint32_t start, delta, total_delta; 299055c7d1SRyan Harkin 300bcedb22SAntonio Nino Diaz assert(usec < UINT32_MAX / ops->clk_div); 310bcedb22SAntonio Nino Diaz 329055c7d1SRyan Harkin start = ops->get_timer_value(); 330bcedb22SAntonio Nino Diaz 34*e2aec918SJulius Werner /* Add an extra tick to avoid delaying less than requested. */ 35*e2aec918SJulius Werner total_delta = div_round_up(usec * ops->clk_div, ops->clk_mult) + 1; 360bcedb22SAntonio Nino Diaz 379055c7d1SRyan Harkin do { 380bcedb22SAntonio Nino Diaz /* 390bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 400bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 410bcedb22SAntonio Nino Diaz */ 420bcedb22SAntonio Nino Diaz delta = start - ops->get_timer_value(); /* Decreasing counter */ 430bcedb22SAntonio Nino Diaz 440bcedb22SAntonio Nino Diaz } while (delta < total_delta); 459055c7d1SRyan Harkin } 469055c7d1SRyan Harkin 479055c7d1SRyan Harkin /*********************************************************** 489055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 499055c7d1SRyan Harkin * be initialized before calling this function. 509055c7d1SRyan Harkin ***********************************************************/ 519055c7d1SRyan Harkin void mdelay(uint32_t msec) 529055c7d1SRyan Harkin { 539055c7d1SRyan Harkin udelay(msec*1000); 549055c7d1SRyan Harkin } 559055c7d1SRyan Harkin 569055c7d1SRyan Harkin /*********************************************************** 579055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 589055c7d1SRyan Harkin * ops pointer must be valid. 599055c7d1SRyan Harkin ***********************************************************/ 609055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr) 619055c7d1SRyan Harkin { 621496b489SEtienne Carriere assert(ops_ptr != NULL && 639055c7d1SRyan Harkin (ops_ptr->clk_mult != 0) && 649055c7d1SRyan Harkin (ops_ptr->clk_div != 0) && 651496b489SEtienne Carriere (ops_ptr->get_timer_value != NULL)); 669055c7d1SRyan Harkin 679055c7d1SRyan Harkin ops = ops_ptr; 689055c7d1SRyan Harkin } 69