xref: /rk3399_ARM-atf/drivers/delay_timer/delay_timer.c (revision c948f77136c42a92d0bb660543a3600c36dcf7f1)
1 /*
2  * Copyright (c) 2015-2018, 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  ***********************************************************/
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, total_delta;
31 
32 	assert(usec < (UINT32_MAX / timer_ops->clk_div));
33 
34 	start = timer_ops->get_timer_value();
35 
36 	/* Add an extra tick to avoid delaying less than requested. */
37 	total_delta =
38 		div_round_up(usec * timer_ops->clk_div,
39 						timer_ops->clk_mult) + 1U;
40 
41 	do {
42 		/*
43 		 * If the timer value wraps around, the subtraction will
44 		 * overflow and it will still give the correct result.
45 		 */
46 		delta = start - timer_ops->get_timer_value(); /* Decreasing counter */
47 
48 	} while (delta < total_delta);
49 }
50 
51 /***********************************************************
52  * Delay for the given number of milliseconds. The driver must
53  * be initialized before calling this function.
54  ***********************************************************/
55 void mdelay(uint32_t msec)
56 {
57 	udelay(msec * 1000U);
58 }
59 
60 /***********************************************************
61  * Initialize the timer. The fields in the provided timer
62  * ops pointer must be valid.
63  ***********************************************************/
64 void timer_init(const timer_ops_t *ops_ptr)
65 {
66 	assert((ops_ptr != NULL)  &&
67 		(ops_ptr->clk_mult != 0U) &&
68 		(ops_ptr->clk_div != 0U) &&
69 		(ops_ptr->get_timer_value != NULL));
70 
71 	timer_ops = ops_ptr;
72 }
73