diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /drivers/delay_timer | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-upstream.tar.xz arm-trusted-firmware-upstream.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | drivers/delay_timer/delay_timer.c | 82 | ||||
-rw-r--r-- | drivers/delay_timer/generic_delay_timer.c | 62 |
2 files changed, 144 insertions, 0 deletions
diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c new file mode 100644 index 0000000..a3fd7bf --- /dev/null +++ b/drivers/delay_timer/delay_timer.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <platform_def.h> + +#include <drivers/delay_timer.h> +#include <lib/utils_def.h> + +/*********************************************************** + * The delay timer implementation + ***********************************************************/ +static const timer_ops_t *timer_ops; + +/*********************************************************** + * Delay for the given number of microseconds. The driver must + * be initialized before calling this function. + ***********************************************************/ +void udelay(uint32_t usec) +{ + assert((timer_ops != NULL) && + (timer_ops->clk_mult != 0U) && + (timer_ops->clk_div != 0U) && + (timer_ops->get_timer_value != NULL)); + + uint32_t start, delta; + uint64_t total_delta; + + assert(usec < (UINT64_MAX / timer_ops->clk_div)); + + start = timer_ops->get_timer_value(); + + /* Add an extra tick to avoid delaying less than requested. */ + total_delta = + div_round_up((uint64_t)usec * timer_ops->clk_div, + timer_ops->clk_mult) + 1U; + /* + * Precaution for the total_delta ~ UINT32_MAX and the fact that we + * cannot catch every tick of the timer. + * For example 100MHz timer over 25MHz APB will miss at least 4 ticks. + * 1000U is an arbitrary big number which is believed to be sufficient. + */ + assert(total_delta < (UINT32_MAX - 1000U)); + + do { + /* + * If the timer value wraps around, the subtraction will + * overflow and it will still give the correct result. + * delta is decreasing counter + */ + delta = start - timer_ops->get_timer_value(); + + } while (delta < total_delta); +} + +/*********************************************************** + * Delay for the given number of milliseconds. The driver must + * be initialized before calling this function. + ***********************************************************/ +void mdelay(uint32_t msec) +{ + assert((msec * 1000UL) < UINT32_MAX); + udelay(msec * 1000U); +} + +/*********************************************************** + * Initialize the timer. The fields in the provided timer + * ops pointer must be valid. + ***********************************************************/ +void timer_init(const timer_ops_t *ops_ptr) +{ + assert((ops_ptr != NULL) && + (ops_ptr->clk_mult != 0U) && + (ops_ptr->clk_div != 0U) && + (ops_ptr->get_timer_value != NULL)); + + timer_ops = ops_ptr; +} diff --git a/drivers/delay_timer/generic_delay_timer.c b/drivers/delay_timer/generic_delay_timer.c new file mode 100644 index 0000000..ca522e0 --- /dev/null +++ b/drivers/delay_timer/generic_delay_timer.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_features.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <drivers/generic_delay_timer.h> +#include <lib/utils_def.h> +#include <plat/common/platform.h> + +static timer_ops_t ops; + +static uint32_t get_timer_value(void) +{ + /* + * Generic delay timer implementation expects the timer to be a down + * counter. We apply bitwise NOT operator to the tick values returned + * by read_cntpct_el0() to simulate the down counter. The value is + * clipped from 64 to 32 bits. + */ + return (uint32_t)(~read_cntpct_el0()); +} + +void generic_delay_timer_init_args(uint32_t mult, uint32_t div) +{ + ops.get_timer_value = get_timer_value; + ops.clk_mult = mult; + ops.clk_div = div; + + timer_init(&ops); + + VERBOSE("Generic delay timer configured with mult=%u and div=%u\n", + mult, div); +} + +void generic_delay_timer_init(void) +{ + assert(is_armv7_gentimer_present()); + + /* Value in ticks */ + unsigned int mult = MHZ_TICKS_PER_SEC; + + /* Value in ticks per second (Hz) */ + unsigned int div = plat_get_syscnt_freq2(); + + /* Reduce multiplier and divider by dividing them repeatedly by 10 */ + while (((mult % 10U) == 0U) && ((div % 10U) == 0U)) { + mult /= 10U; + div /= 10U; + } + + generic_delay_timer_init_args(mult, div); +} + |