19055c7d1SRyan Harkin /* 29055c7d1SRyan Harkin * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 39055c7d1SRyan Harkin * 4*82cb2c1aSdp-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> 109055c7d1SRyan Harkin 119055c7d1SRyan Harkin /*********************************************************** 129055c7d1SRyan Harkin * The delay timer implementation 139055c7d1SRyan Harkin ***********************************************************/ 149055c7d1SRyan Harkin static const timer_ops_t *ops; 159055c7d1SRyan Harkin 169055c7d1SRyan Harkin /*********************************************************** 179055c7d1SRyan Harkin * Delay for the given number of microseconds. The driver must 189055c7d1SRyan Harkin * be initialized before calling this function. 199055c7d1SRyan Harkin ***********************************************************/ 209055c7d1SRyan Harkin void udelay(uint32_t usec) 219055c7d1SRyan Harkin { 229055c7d1SRyan Harkin assert(ops != 0 && 239055c7d1SRyan Harkin (ops->clk_mult != 0) && 249055c7d1SRyan Harkin (ops->clk_div != 0) && 259055c7d1SRyan Harkin (ops->get_timer_value != 0)); 269055c7d1SRyan Harkin 270bcedb22SAntonio Nino Diaz uint32_t start, delta, total_delta; 289055c7d1SRyan Harkin 290bcedb22SAntonio Nino Diaz assert(usec < UINT32_MAX / ops->clk_div); 300bcedb22SAntonio Nino Diaz 319055c7d1SRyan Harkin start = ops->get_timer_value(); 320bcedb22SAntonio Nino Diaz 330bcedb22SAntonio Nino Diaz total_delta = (usec * ops->clk_div) / ops->clk_mult; 340bcedb22SAntonio Nino Diaz 359055c7d1SRyan Harkin do { 360bcedb22SAntonio Nino Diaz /* 370bcedb22SAntonio Nino Diaz * If the timer value wraps around, the subtraction will 380bcedb22SAntonio Nino Diaz * overflow and it will still give the correct result. 390bcedb22SAntonio Nino Diaz */ 400bcedb22SAntonio Nino Diaz delta = start - ops->get_timer_value(); /* Decreasing counter */ 410bcedb22SAntonio Nino Diaz 420bcedb22SAntonio Nino Diaz } while (delta < total_delta); 439055c7d1SRyan Harkin } 449055c7d1SRyan Harkin 459055c7d1SRyan Harkin /*********************************************************** 469055c7d1SRyan Harkin * Delay for the given number of milliseconds. The driver must 479055c7d1SRyan Harkin * be initialized before calling this function. 489055c7d1SRyan Harkin ***********************************************************/ 499055c7d1SRyan Harkin void mdelay(uint32_t msec) 509055c7d1SRyan Harkin { 519055c7d1SRyan Harkin udelay(msec*1000); 529055c7d1SRyan Harkin } 539055c7d1SRyan Harkin 549055c7d1SRyan Harkin /*********************************************************** 559055c7d1SRyan Harkin * Initialize the timer. The fields in the provided timer 569055c7d1SRyan Harkin * ops pointer must be valid. 579055c7d1SRyan Harkin ***********************************************************/ 589055c7d1SRyan Harkin void timer_init(const timer_ops_t *ops_ptr) 599055c7d1SRyan Harkin { 609055c7d1SRyan Harkin assert(ops_ptr != 0 && 619055c7d1SRyan Harkin (ops_ptr->clk_mult != 0) && 629055c7d1SRyan Harkin (ops_ptr->clk_div != 0) && 639055c7d1SRyan Harkin (ops_ptr->get_timer_value != 0)); 649055c7d1SRyan Harkin 659055c7d1SRyan Harkin ops = ops_ptr; 669055c7d1SRyan Harkin } 67