summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-zynq/timer.c
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2015-03-16 16:43:22 +0900
committerMichal Simek <michal.simek@xilinx.com>2015-04-29 11:19:05 +0200
commit0107f2403669f764ab726d0d404e35bb9447bbcc (patch)
treeb35d4ca109c56dc4f0033d73199207b07eee06e7 /arch/arm/mach-zynq/timer.c
parent7472a5dfcbbc3180d3e728bbd4233c21243ea943 (diff)
downloadblackbird-obmc-uboot-0107f2403669f764ab726d0d404e35bb9447bbcc.tar.gz
blackbird-obmc-uboot-0107f2403669f764ab726d0d404e35bb9447bbcc.zip
ARM: zynq: move SoC sources to mach-zynq
Move arch/arm/cpu/armv7/zynq/* -> arch/arm/mach-zynq/* Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Diffstat (limited to 'arch/arm/mach-zynq/timer.c')
-rw-r--r--arch/arm/mach-zynq/timer.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
new file mode 100644
index 0000000000..5ed9642df9
--- /dev/null
+++ b/arch/arm/mach-zynq/timer.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
+ *
+ * (C) Copyright 2008
+ * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
+ *
+ * (C) Copyright 2004
+ * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
+ *
+ * (C) Copyright 2002-2004
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * (C) Copyright 2003
+ * Texas Instruments <www.ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/clk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct scu_timer {
+ u32 load; /* Timer Load Register */
+ u32 counter; /* Timer Counter Register */
+ u32 control; /* Timer Control Register */
+};
+
+static struct scu_timer *timer_base =
+ (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
+
+#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
+#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8
+#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */
+#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */
+
+#define TIMER_LOAD_VAL 0xFFFFFFFF
+#define TIMER_PRESCALE 255
+
+int timer_init(void)
+{
+ const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
+ (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
+ SCUTIMER_CONTROL_ENABLE_MASK;
+
+ gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
+
+ /* Load the timer counter register */
+ writel(0xFFFFFFFF, &timer_base->load);
+
+ /*
+ * Start the A9Timer device
+ * Enable Auto reload mode, Clear prescaler control bits
+ * Set prescaler value, Enable the decrementer
+ */
+ clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
+ emask);
+
+ /* Reset time */
+ gd->arch.lastinc = readl(&timer_base->counter) /
+ (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
+ gd->arch.tbl = 0;
+
+ return 0;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+ulong get_timer_masked(void)
+{
+ ulong now;
+
+ now = readl(&timer_base->counter) /
+ (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
+
+ if (gd->arch.lastinc >= now) {
+ /* Normal mode */
+ gd->arch.tbl += gd->arch.lastinc - now;
+ } else {
+ /* We have an overflow ... */
+ gd->arch.tbl += gd->arch.lastinc + (TIMER_LOAD_VAL /
+ (gd->arch.timer_rate_hz / CONFIG_SYS_HZ)) -
+ now + 1;
+ }
+ gd->arch.lastinc = now;
+
+ return gd->arch.tbl;
+}
+
+void __udelay(unsigned long usec)
+{
+ u32 countticks;
+ u32 timeend;
+ u32 timediff;
+ u32 timenow;
+
+ if (usec == 0)
+ return;
+
+ countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec),
+ 1000000);
+
+ /* decrementing timer */
+ timeend = readl(&timer_base->counter) - countticks;
+
+#if TIMER_LOAD_VAL != 0xFFFFFFFF
+ /* do not manage multiple overflow */
+ if (countticks >= TIMER_LOAD_VAL)
+ countticks = TIMER_LOAD_VAL - 1;
+#endif
+
+ do {
+ timenow = readl(&timer_base->counter);
+
+ if (timenow >= timeend) {
+ /* normal case */
+ timediff = timenow - timeend;
+ } else {
+ if ((TIMER_LOAD_VAL - timeend + timenow) <=
+ countticks) {
+ /* overflow */
+ timediff = TIMER_LOAD_VAL - timeend + timenow;
+ } else {
+ /* missed the exact match */
+ break;
+ }
+ }
+ } while (timediff > 0);
+}
+
+/* Timer without interrupts */
+ulong get_timer(ulong base)
+{
+ return get_timer_masked() - base;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+ return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+ return CONFIG_SYS_HZ;
+}
OpenPOWER on IntegriCloud