1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <platform_def.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <drivers/delay_timer.h> 12*91f16700Schasinglulu #include <lib/utils_def.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu /*********************************************************** 15*91f16700Schasinglulu * The delay timer implementation 16*91f16700Schasinglulu ***********************************************************/ 17*91f16700Schasinglulu static const timer_ops_t *timer_ops; 18*91f16700Schasinglulu 19*91f16700Schasinglulu /*********************************************************** 20*91f16700Schasinglulu * Delay for the given number of microseconds. The driver must 21*91f16700Schasinglulu * be initialized before calling this function. 22*91f16700Schasinglulu ***********************************************************/ 23*91f16700Schasinglulu void udelay(uint32_t usec) 24*91f16700Schasinglulu { 25*91f16700Schasinglulu assert((timer_ops != NULL) && 26*91f16700Schasinglulu (timer_ops->clk_mult != 0U) && 27*91f16700Schasinglulu (timer_ops->clk_div != 0U) && 28*91f16700Schasinglulu (timer_ops->get_timer_value != NULL)); 29*91f16700Schasinglulu 30*91f16700Schasinglulu uint32_t start, delta; 31*91f16700Schasinglulu uint64_t total_delta; 32*91f16700Schasinglulu 33*91f16700Schasinglulu assert(usec < (UINT64_MAX / timer_ops->clk_div)); 34*91f16700Schasinglulu 35*91f16700Schasinglulu start = timer_ops->get_timer_value(); 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* Add an extra tick to avoid delaying less than requested. */ 38*91f16700Schasinglulu total_delta = 39*91f16700Schasinglulu div_round_up((uint64_t)usec * timer_ops->clk_div, 40*91f16700Schasinglulu timer_ops->clk_mult) + 1U; 41*91f16700Schasinglulu /* 42*91f16700Schasinglulu * Precaution for the total_delta ~ UINT32_MAX and the fact that we 43*91f16700Schasinglulu * cannot catch every tick of the timer. 44*91f16700Schasinglulu * For example 100MHz timer over 25MHz APB will miss at least 4 ticks. 45*91f16700Schasinglulu * 1000U is an arbitrary big number which is believed to be sufficient. 46*91f16700Schasinglulu */ 47*91f16700Schasinglulu assert(total_delta < (UINT32_MAX - 1000U)); 48*91f16700Schasinglulu 49*91f16700Schasinglulu do { 50*91f16700Schasinglulu /* 51*91f16700Schasinglulu * If the timer value wraps around, the subtraction will 52*91f16700Schasinglulu * overflow and it will still give the correct result. 53*91f16700Schasinglulu * delta is decreasing counter 54*91f16700Schasinglulu */ 55*91f16700Schasinglulu delta = start - timer_ops->get_timer_value(); 56*91f16700Schasinglulu 57*91f16700Schasinglulu } while (delta < total_delta); 58*91f16700Schasinglulu } 59*91f16700Schasinglulu 60*91f16700Schasinglulu /*********************************************************** 61*91f16700Schasinglulu * Delay for the given number of milliseconds. The driver must 62*91f16700Schasinglulu * be initialized before calling this function. 63*91f16700Schasinglulu ***********************************************************/ 64*91f16700Schasinglulu void mdelay(uint32_t msec) 65*91f16700Schasinglulu { 66*91f16700Schasinglulu assert((msec * 1000UL) < UINT32_MAX); 67*91f16700Schasinglulu udelay(msec * 1000U); 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu /*********************************************************** 71*91f16700Schasinglulu * Initialize the timer. The fields in the provided timer 72*91f16700Schasinglulu * ops pointer must be valid. 73*91f16700Schasinglulu ***********************************************************/ 74*91f16700Schasinglulu void timer_init(const timer_ops_t *ops_ptr) 75*91f16700Schasinglulu { 76*91f16700Schasinglulu assert((ops_ptr != NULL) && 77*91f16700Schasinglulu (ops_ptr->clk_mult != 0U) && 78*91f16700Schasinglulu (ops_ptr->clk_div != 0U) && 79*91f16700Schasinglulu (ops_ptr->get_timer_value != NULL)); 80*91f16700Schasinglulu 81*91f16700Schasinglulu timer_ops = ops_ptr; 82*91f16700Schasinglulu } 83