summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/delay_timer/delay_timer.c23
-rw-r--r--drivers/delay_timer/generic_delay_timer.c82
2 files changed, 95 insertions, 10 deletions
diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c
index 0bee876f..ed7ed52e 100644
--- a/drivers/delay_timer/delay_timer.c
+++ b/drivers/delay_timer/delay_timer.c
@@ -48,19 +48,22 @@ void udelay(uint32_t usec)
(ops->clk_div != 0) &&
(ops->get_timer_value != 0));
- uint32_t start, cnt, delta, delta_us;
+ uint32_t start, delta, total_delta;
+
+ assert(usec < UINT32_MAX / ops->clk_div);
- /* counter is decreasing */
start = ops->get_timer_value();
+
+ total_delta = (usec * ops->clk_div) / ops->clk_mult;
+
do {
- cnt = ops->get_timer_value();
- if (cnt > start) {
- delta = UINT32_MAX - cnt;
- delta += start;
- } else
- delta = start - cnt;
- delta_us = (delta * ops->clk_mult) / ops->clk_div;
- } while (delta_us < usec);
+ /*
+ * If the timer value wraps around, the subtraction will
+ * overflow and it will still give the correct result.
+ */
+ delta = start - ops->get_timer_value(); /* Decreasing counter */
+
+ } while (delta < total_delta);
}
/***********************************************************
diff --git a/drivers/delay_timer/generic_delay_timer.c b/drivers/delay_timer/generic_delay_timer.c
new file mode 100644
index 00000000..4c364a30
--- /dev/null
+++ b/drivers/delay_timer/generic_delay_timer.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <platform.h>
+
+/* Ticks elapsed in one second by a signal of 1 MHz */
+#define MHZ_TICKS_PER_SEC 1000000
+
+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)
+{
+ /* 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 % 10 == 0) && (div % 10 == 0)) {
+ mult /= 10;
+ div /= 10;
+ }
+
+ generic_delay_timer_init_args(mult, div);
+}
+