summaryrefslogtreecommitdiff
path: root/cpu/arm_cortexa9/db8500/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/arm_cortexa9/db8500/timer.c')
-rw-r--r--cpu/arm_cortexa9/db8500/timer.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/cpu/arm_cortexa9/db8500/timer.c b/cpu/arm_cortexa9/db8500/timer.c
new file mode 100644
index 000000000..bc27755b1
--- /dev/null
+++ b/cpu/arm_cortexa9/db8500/timer.c
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2009 Alessandro Rubini
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <boottime.h>
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
+#define MTU_RIS 0x04 /* Raw interrupt status */
+#define MTU_MIS 0x08 /* Masked interrupt status */
+#define MTU_ICR 0x0C /* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
+#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
+#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
+#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA 0x80
+#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK 0x0c
+#define MTU_CRn_PRESCALE_1 0x00
+#define MTU_CRn_PRESCALE_16 0x04
+#define MTU_CRn_PRESCALE_256 0x08
+#define MTU_CRn_32BITS 0x02
+#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR 0xff0
+#define MTU_ITOP 0xff4
+
+#define MTU_PERIPH_ID0 0xfe0
+#define MTU_PERIPH_ID1 0xfe4
+#define MTU_PERIPH_ID2 0xfe8
+#define MTU_PERIPH_ID3 0xfeC
+
+#define MTU_PCELL0 0xff0
+#define MTU_PCELL1 0xff4
+#define MTU_PCELL2 0xff8
+#define MTU_PCELL3 0xffC
+
+/*
+ * The MTU is clocked at 133 MHz by default. (V1 and later)
+ */
+#define TIMER_CLOCK (133 * 1000 * 1000 / 16)
+#define COUNT_TO_USEC(x) ((x) * 16 / 133)
+#define USEC_TO_COUNT(x) ((x) * 133 / 16)
+#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ)
+#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ)
+
+/*
+ * MTU timer to use (from 0 to 3).
+ * Linux ux500 timer0 on MTU0 and timer0 on MTU1
+ */
+#define MTU_TIMER 2
+
+static unsigned int timerbase;
+
+/* macro to read the 32 bit timer: since it decrements, we invert read value */
+#define READ_TIMER() (~readl(timerbase + MTU_VAL(MTU_TIMER)))
+
+/* Configure a free-running, auto-wrap counter with /16 prescaler */
+int timer_init(void)
+{
+ timerbase = u8500_is_earlydrop() ? U8500_MTU0_BASE_ED
+ : U8500_MTU0_BASE_V1;
+
+ writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_16 | MTU_CRn_32BITS,
+ timerbase + MTU_CR(MTU_TIMER));
+ reset_timer();
+ return 0;
+}
+
+/* Restart counting from 0 */
+void reset_timer(void)
+{
+ writel(0, timerbase + MTU_LR(MTU_TIMER)); /* Immediate effect */
+}
+
+/* Return how many HZ passed since "base" */
+ulong get_timer(ulong base)
+{
+ return TICKS_TO_HZ(READ_TIMER()) - base;
+}
+
+u64 get_timer_us(void)
+{
+ return COUNT_TO_USEC(READ_TIMER());
+}
+
+/* Delay x useconds */
+void udelay(unsigned long usec)
+{
+ ulong ini, end;
+
+ ini = READ_TIMER();
+ end = ini + USEC_TO_COUNT(usec);
+ while ((signed)(end - READ_TIMER()) > 0)
+ ;
+ boottime_idle_add(usec);
+}