aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-prima2/timer.c
diff options
context:
space:
mode:
authorBinghua Duan <binghua.duan@csr.com>2011-07-08 05:40:12 -0400
committerBarry Song <21cnbao@gmail.com>2011-07-08 19:19:28 -0400
commit02c981c07bc95ac1e42ec6c817f0c28cf3fe993a (patch)
tree3b0f9a368d7d3b4cef3eab9128a0c3d95e8188d4 /arch/arm/mach-prima2/timer.c
parentf1bb20a8365f6753e0f7b6e94981ca2b662bae13 (diff)
ARM: CSR: Adding CSR SiRFprimaII board support
SiRFprimaII is the latest generation application processor from CSR’s Multifunction SoC product family. Designed around an ARM cortex A9 core, high-speed memory bus, advanced 3D accelerator and full-HD multi-format video decoder, SiRFprimaII is able to meet the needs of complicated applications for modern multifunction devices that require heavy concurrent applications and fluid user experience. Integrated with GPS baseband, analog and PMU, this new platform is designed to provide a cost effective solution for Automotive and Consumer markets. This patch adds the basic support for this SoC and EVB board based on device tree. It is following the ZYNQ of Xilinx in some degree. Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> Signed-off-by: Yuping Luo <Yuping.Luo@csr.com> Signed-off-by: Bin Shi <Bin.Shi@csr.com> Signed-off-by: Huayi Li <Huayi.Li@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm/mach-prima2/timer.c')
-rw-r--r--arch/arm/mach-prima2/timer.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
new file mode 100644
index 000000000000..44027f34a88a
--- /dev/null
+++ b/arch/arm/mach-prima2/timer.c
@@ -0,0 +1,217 @@
1/*
2 * System timer for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/kernel.h>
10#include <linux/interrupt.h>
11#include <linux/clockchips.h>
12#include <linux/clocksource.h>
13#include <linux/bitops.h>
14#include <linux/irq.h>
15#include <linux/clk.h>
16#include <linux/err.h>
17#include <linux/slab.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <mach/map.h>
21#include <asm/mach/time.h>
22
23#define SIRFSOC_TIMER_COUNTER_LO 0x0000
24#define SIRFSOC_TIMER_COUNTER_HI 0x0004
25#define SIRFSOC_TIMER_MATCH_0 0x0008
26#define SIRFSOC_TIMER_MATCH_1 0x000C
27#define SIRFSOC_TIMER_MATCH_2 0x0010
28#define SIRFSOC_TIMER_MATCH_3 0x0014
29#define SIRFSOC_TIMER_MATCH_4 0x0018
30#define SIRFSOC_TIMER_MATCH_5 0x001C
31#define SIRFSOC_TIMER_STATUS 0x0020
32#define SIRFSOC_TIMER_INT_EN 0x0024
33#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028
34#define SIRFSOC_TIMER_DIV 0x002C
35#define SIRFSOC_TIMER_LATCH 0x0030
36#define SIRFSOC_TIMER_LATCHED_LO 0x0034
37#define SIRFSOC_TIMER_LATCHED_HI 0x0038
38
39#define SIRFSOC_TIMER_WDT_INDEX 5
40
41#define SIRFSOC_TIMER_LATCH_BIT BIT(0)
42
43static void __iomem *sirfsoc_timer_base;
44static void __init sirfsoc_of_timer_map(void);
45
46/* timer0 interrupt handler */
47static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
48{
49 struct clock_event_device *ce = dev_id;
50
51 WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
52
53 /* clear timer0 interrupt */
54 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
55
56 ce->event_handler(ce);
57
58 return IRQ_HANDLED;
59}
60
61/* read 64-bit timer counter */
62static cycle_t sirfsoc_timer_read(struct clocksource *cs)
63{
64 u64 cycles;
65
66 /* latch the 64-bit timer counter */
67 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
68 cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
69 cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
70
71 return cycles;
72}
73
74static int sirfsoc_timer_set_next_event(unsigned long delta,
75 struct clock_event_device *ce)
76{
77 unsigned long now, next;
78
79 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
80 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
81 next = now + delta;
82 writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
83 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
84 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
85
86 return next - now > delta ? -ETIME : 0;
87}
88
89static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
90 struct clock_event_device *ce)
91{
92 u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
93 switch (mode) {
94 case CLOCK_EVT_MODE_PERIODIC:
95 WARN_ON(1);
96 break;
97 case CLOCK_EVT_MODE_ONESHOT:
98 writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
99 break;
100 case CLOCK_EVT_MODE_SHUTDOWN:
101 writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
102 break;
103 case CLOCK_EVT_MODE_UNUSED:
104 case CLOCK_EVT_MODE_RESUME:
105 break;
106 }
107}
108
109static struct clock_event_device sirfsoc_clockevent = {
110 .name = "sirfsoc_clockevent",
111 .rating = 200,
112 .features = CLOCK_EVT_FEAT_ONESHOT,
113 .set_mode = sirfsoc_timer_set_mode,
114 .set_next_event = sirfsoc_timer_set_next_event,
115};
116
117static struct clocksource sirfsoc_clocksource = {
118 .name = "sirfsoc_clocksource",
119 .rating = 200,
120 .mask = CLOCKSOURCE_MASK(64),
121 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
122 .read = sirfsoc_timer_read,
123};
124
125static struct irqaction sirfsoc_timer_irq = {
126 .name = "sirfsoc_timer0",
127 .flags = IRQF_TIMER,
128 .irq = 0,
129 .handler = sirfsoc_timer_interrupt,
130 .dev_id = &sirfsoc_clockevent,
131};
132
133/* Overwrite weak default sched_clock with more precise one */
134unsigned long long notrace sched_clock(void)
135{
136 static int is_mapped = 0;
137
138 /*
139 * sched_clock is called earlier than .init of sys_timer
140 * if we map timer memory in .init of sys_timer, system
141 * will panic due to illegal memory access
142 */
143 if(!is_mapped) {
144 sirfsoc_of_timer_map();
145 is_mapped = 1;
146 }
147
148 return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
149}
150
151static void __init sirfsoc_clockevent_init(void)
152{
153 clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
154
155 sirfsoc_clockevent.max_delta_ns =
156 clockevent_delta2ns(-2, &sirfsoc_clockevent);
157 sirfsoc_clockevent.min_delta_ns =
158 clockevent_delta2ns(2, &sirfsoc_clockevent);
159
160 sirfsoc_clockevent.cpumask = cpumask_of(0);
161 clockevents_register_device(&sirfsoc_clockevent);
162}
163
164/* initialize the kernel jiffy timer source */
165static void __init sirfsoc_timer_init(void)
166{
167 unsigned long rate;
168
169 /* timer's input clock is io clock */
170 struct clk *clk = clk_get_sys("io", NULL);
171
172 BUG_ON(IS_ERR(clk));
173
174 rate = clk_get_rate(clk);
175
176 BUG_ON(rate < CLOCK_TICK_RATE);
177 BUG_ON(rate % CLOCK_TICK_RATE);
178
179 writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
180 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
181 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
182 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
183
184 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
185
186 BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
187
188 sirfsoc_clockevent_init();
189}
190
191static struct of_device_id timer_ids[] = {
192 { .compatible = "sirf,prima2-tick" },
193};
194
195static void __init sirfsoc_of_timer_map(void)
196{
197 struct device_node *np;
198 const unsigned int *intspec;
199
200 np = of_find_matching_node(NULL, timer_ids);
201 if (!np)
202 panic("unable to find compatible timer node in dtb\n");
203 sirfsoc_timer_base = of_iomap(np, 0);
204 if (!sirfsoc_timer_base)
205 panic("unable to map timer cpu registers\n");
206
207 /* Get the interrupts property */
208 intspec = of_get_property(np, "interrupts", NULL);
209 BUG_ON(!intspec);
210 sirfsoc_timer_irq.irq = be32_to_cpup(intspec);
211
212 of_node_put(np);
213}
214
215struct sys_timer sirfsoc_timer = {
216 .init = sirfsoc_timer_init,
217};