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