blob: c9f84d7773e34924906a852da9bf3945ac7de6ff [file] [log] [blame]
Ryan Harkin32539fc2015-03-17 14:50:05 +00001/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Ryan Harkin32539fc2015-03-17 14:50:05 +00005 */
6
7#include <assert.h>
8#include <delay_timer.h>
9#include <platform_def.h>
Julius Wernerb0a432d2018-01-22 14:02:03 -080010#include <utils_def.h>
Ryan Harkin32539fc2015-03-17 14:50:05 +000011
12/***********************************************************
13 * The delay timer implementation
14 ***********************************************************/
15static const timer_ops_t *ops;
16
17/***********************************************************
18 * Delay for the given number of microseconds. The driver must
19 * be initialized before calling this function.
20 ***********************************************************/
21void udelay(uint32_t usec)
22{
Etienne Carrieref4eecb22017-06-07 16:42:26 +020023 assert(ops != NULL &&
Ryan Harkin32539fc2015-03-17 14:50:05 +000024 (ops->clk_mult != 0) &&
25 (ops->clk_div != 0) &&
Etienne Carrieref4eecb22017-06-07 16:42:26 +020026 (ops->get_timer_value != NULL));
Ryan Harkin32539fc2015-03-17 14:50:05 +000027
Antonio Nino Diazbcd79b22016-05-18 10:37:25 +010028 uint32_t start, delta, total_delta;
Ryan Harkin32539fc2015-03-17 14:50:05 +000029
Antonio Nino Diazbcd79b22016-05-18 10:37:25 +010030 assert(usec < UINT32_MAX / ops->clk_div);
31
Ryan Harkin32539fc2015-03-17 14:50:05 +000032 start = ops->get_timer_value();
Antonio Nino Diazbcd79b22016-05-18 10:37:25 +010033
Julius Wernerb0a432d2018-01-22 14:02:03 -080034 /* Add an extra tick to avoid delaying less than requested. */
35 total_delta = div_round_up(usec * ops->clk_div, ops->clk_mult) + 1;
Antonio Nino Diazbcd79b22016-05-18 10:37:25 +010036
Ryan Harkin32539fc2015-03-17 14:50:05 +000037 do {
Antonio Nino Diazbcd79b22016-05-18 10:37:25 +010038 /*
39 * If the timer value wraps around, the subtraction will
40 * overflow and it will still give the correct result.
41 */
42 delta = start - ops->get_timer_value(); /* Decreasing counter */
43
44 } while (delta < total_delta);
Ryan Harkin32539fc2015-03-17 14:50:05 +000045}
46
47/***********************************************************
48 * Delay for the given number of milliseconds. The driver must
49 * be initialized before calling this function.
50 ***********************************************************/
51void mdelay(uint32_t msec)
52{
53 udelay(msec*1000);
54}
55
56/***********************************************************
57 * Initialize the timer. The fields in the provided timer
58 * ops pointer must be valid.
59 ***********************************************************/
60void timer_init(const timer_ops_t *ops_ptr)
61{
Etienne Carrieref4eecb22017-06-07 16:42:26 +020062 assert(ops_ptr != NULL &&
Ryan Harkin32539fc2015-03-17 14:50:05 +000063 (ops_ptr->clk_mult != 0) &&
64 (ops_ptr->clk_div != 0) &&
Etienne Carrieref4eecb22017-06-07 16:42:26 +020065 (ops_ptr->get_timer_value != NULL));
Ryan Harkin32539fc2015-03-17 14:50:05 +000066
67 ops = ops_ptr;
68}