aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-prima2
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2013-03-19 10:27:22 -0400
committerArnd Bergmann <arnd@arndb.de>2013-03-25 07:29:41 -0400
commit275786b71d42bb54c03c15197128d7cb05d4dd8b (patch)
treef617b3c2c278798da79f832f14faa81fa57f2c6c /arch/arm/mach-prima2
parent67bdb28718ae6dbdfbfa541161529acfa0f3c137 (diff)
ARM: sirf: use clocksource_of infrastructure
This moves the two sirf clocksource drivers to drivers/clocksource and integrates them into the framework for locating the clock sources automatically. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Barry Song <Baohua.Song@csr.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/arm/mach-prima2')
-rw-r--r--arch/arm/mach-prima2/Makefile2
-rw-r--r--arch/arm/mach-prima2/common.c14
-rw-r--r--arch/arm/mach-prima2/common.h3
-rw-r--r--arch/arm/mach-prima2/timer-marco.c316
-rw-r--r--arch/arm/mach-prima2/timer-prima2.c239
5 files changed, 11 insertions, 563 deletions
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index 5fdff7e32290..52ac738881c8 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -6,5 +6,3 @@ obj-$(CONFIG_CACHE_L2X0) += l2x0.o
6obj-$(CONFIG_SUSPEND) += pm.o sleep.o 6obj-$(CONFIG_SUSPEND) += pm.o sleep.o
7obj-$(CONFIG_SMP) += platsmp.o headsmp.o 7obj-$(CONFIG_SMP) += platsmp.o headsmp.o
8obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 8obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
9obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
10obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index 31f43eac1420..4f94cd87972a 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -6,6 +6,7 @@
6 * Licensed under GPLv2 or later. 6 * Licensed under GPLv2 or later.
7 */ 7 */
8 8
9#include <linux/clocksource.h>
9#include <linux/init.h> 10#include <linux/init.h>
10#include <linux/kernel.h> 11#include <linux/kernel.h>
11#include <linux/irqchip.h> 12#include <linux/irqchip.h>
@@ -31,6 +32,13 @@ void __init sirfsoc_init_late(void)
31 sirfsoc_pm_init(); 32 sirfsoc_pm_init();
32} 33}
33 34
35static __init void sirfsoc_init_time(void)
36{
37 /* initialize clocking early, we want to set the OS timer */
38 sirfsoc_of_clk_init();
39 clocksource_of_init();
40}
41
34static __init void sirfsoc_map_io(void) 42static __init void sirfsoc_map_io(void)
35{ 43{
36 sirfsoc_map_lluart(); 44 sirfsoc_map_lluart();
@@ -48,7 +56,7 @@ DT_MACHINE_START(ATLAS6_DT, "Generic ATLAS6 (Flattened Device Tree)")
48 .nr_irqs = 128, 56 .nr_irqs = 128,
49 .map_io = sirfsoc_map_io, 57 .map_io = sirfsoc_map_io,
50 .init_irq = irqchip_init, 58 .init_irq = irqchip_init,
51 .init_time = sirfsoc_prima2_timer_init, 59 .init_time = sirfsoc_init_time,
52 .init_machine = sirfsoc_mach_init, 60 .init_machine = sirfsoc_mach_init,
53 .init_late = sirfsoc_init_late, 61 .init_late = sirfsoc_init_late,
54 .dt_compat = atlas6_dt_match, 62 .dt_compat = atlas6_dt_match,
@@ -67,7 +75,7 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
67 .nr_irqs = 128, 75 .nr_irqs = 128,
68 .map_io = sirfsoc_map_io, 76 .map_io = sirfsoc_map_io,
69 .init_irq = irqchip_init, 77 .init_irq = irqchip_init,
70 .init_time = sirfsoc_prima2_timer_init, 78 .init_time = sirfsoc_init_time,
71 .dma_zone_size = SZ_256M, 79 .dma_zone_size = SZ_256M,
72 .init_machine = sirfsoc_mach_init, 80 .init_machine = sirfsoc_mach_init,
73 .init_late = sirfsoc_init_late, 81 .init_late = sirfsoc_init_late,
@@ -87,7 +95,7 @@ DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
87 .smp = smp_ops(sirfsoc_smp_ops), 95 .smp = smp_ops(sirfsoc_smp_ops),
88 .map_io = sirfsoc_map_io, 96 .map_io = sirfsoc_map_io,
89 .init_irq = irqchip_init, 97 .init_irq = irqchip_init,
90 .init_time = sirfsoc_marco_timer_init, 98 .init_time = sirfsoc_init_time,
91 .init_machine = sirfsoc_mach_init, 99 .init_machine = sirfsoc_mach_init,
92 .init_late = sirfsoc_init_late, 100 .init_late = sirfsoc_init_late,
93 .dt_compat = marco_dt_match, 101 .dt_compat = marco_dt_match,
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index b7c26b62e4a7..54262cf063c6 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -13,9 +13,6 @@
13#include <asm/mach/time.h> 13#include <asm/mach/time.h>
14#include <asm/exception.h> 14#include <asm/exception.h>
15 15
16extern void sirfsoc_prima2_timer_init(void);
17extern void sirfsoc_marco_timer_init(void);
18
19extern struct smp_operations sirfsoc_smp_ops; 16extern struct smp_operations sirfsoc_smp_ops;
20extern void sirfsoc_secondary_startup(void); 17extern void sirfsoc_secondary_startup(void);
21extern void sirfsoc_cpu_die(unsigned int cpu); 18extern void sirfsoc_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
deleted file mode 100644
index f4eea2e97eb0..000000000000
--- a/arch/arm/mach-prima2/timer-marco.c
+++ /dev/null
@@ -1,316 +0,0 @@
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/slab.h>
17#include <linux/of.h>
18#include <linux/of_irq.h>
19#include <linux/of_address.h>
20#include <asm/sched_clock.h>
21#include <asm/localtimer.h>
22#include <asm/mach/time.h>
23
24#include "common.h"
25
26#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
27#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
28#define SIRFSOC_TIMER_MATCH_0 0x0018
29#define SIRFSOC_TIMER_MATCH_1 0x001c
30#define SIRFSOC_TIMER_COUNTER_0 0x0048
31#define SIRFSOC_TIMER_COUNTER_1 0x004c
32#define SIRFSOC_TIMER_INTR_STATUS 0x0060
33#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064
34#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068
35#define SIRFSOC_TIMER_64COUNTER_LO 0x006c
36#define SIRFSOC_TIMER_64COUNTER_HI 0x0070
37#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074
38#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078
39#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c
40#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080
41
42#define SIRFSOC_TIMER_REG_CNT 6
43
44static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
45 SIRFSOC_TIMER_WATCHDOG_EN,
46 SIRFSOC_TIMER_32COUNTER_0_CTRL,
47 SIRFSOC_TIMER_32COUNTER_1_CTRL,
48 SIRFSOC_TIMER_64COUNTER_CTRL,
49 SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
50 SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
51};
52
53static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
54
55static void __iomem *sirfsoc_timer_base;
56static void __init sirfsoc_of_timer_map(void);
57
58/* disable count and interrupt */
59static inline void sirfsoc_timer_count_disable(int idx)
60{
61 writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
62 sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
63}
64
65/* enable count and interrupt */
66static inline void sirfsoc_timer_count_enable(int idx)
67{
68 writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7,
69 sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
70}
71
72/* timer interrupt handler */
73static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
74{
75 struct clock_event_device *ce = dev_id;
76 int cpu = smp_processor_id();
77
78 /* clear timer interrupt */
79 writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
80
81 if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
82 sirfsoc_timer_count_disable(cpu);
83
84 ce->event_handler(ce);
85
86 return IRQ_HANDLED;
87}
88
89/* read 64-bit timer counter */
90static cycle_t sirfsoc_timer_read(struct clocksource *cs)
91{
92 u64 cycles;
93
94 writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
95 BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
96
97 cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
98 cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
99
100 return cycles;
101}
102
103static int sirfsoc_timer_set_next_event(unsigned long delta,
104 struct clock_event_device *ce)
105{
106 int cpu = smp_processor_id();
107
108 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
109 4 * cpu);
110 writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
111 4 * cpu);
112
113 /* enable the tick */
114 sirfsoc_timer_count_enable(cpu);
115
116 return 0;
117}
118
119static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
120 struct clock_event_device *ce)
121{
122 switch (mode) {
123 case CLOCK_EVT_MODE_ONESHOT:
124 /* enable in set_next_event */
125 break;
126 default:
127 break;
128 }
129
130 sirfsoc_timer_count_disable(smp_processor_id());
131}
132
133static void sirfsoc_clocksource_suspend(struct clocksource *cs)
134{
135 int i;
136
137 for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
138 sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
139}
140
141static void sirfsoc_clocksource_resume(struct clocksource *cs)
142{
143 int i;
144
145 for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
146 writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
147
148 writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
149 sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
150 writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
151 sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
152
153 writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
154 BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
155}
156
157static struct clock_event_device sirfsoc_clockevent = {
158 .name = "sirfsoc_clockevent",
159 .rating = 200,
160 .features = CLOCK_EVT_FEAT_ONESHOT,
161 .set_mode = sirfsoc_timer_set_mode,
162 .set_next_event = sirfsoc_timer_set_next_event,
163};
164
165static struct clocksource sirfsoc_clocksource = {
166 .name = "sirfsoc_clocksource",
167 .rating = 200,
168 .mask = CLOCKSOURCE_MASK(64),
169 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
170 .read = sirfsoc_timer_read,
171 .suspend = sirfsoc_clocksource_suspend,
172 .resume = sirfsoc_clocksource_resume,
173};
174
175static struct irqaction sirfsoc_timer_irq = {
176 .name = "sirfsoc_timer0",
177 .flags = IRQF_TIMER | IRQF_NOBALANCING,
178 .handler = sirfsoc_timer_interrupt,
179 .dev_id = &sirfsoc_clockevent,
180};
181
182#ifdef CONFIG_LOCAL_TIMERS
183
184static struct irqaction sirfsoc_timer1_irq = {
185 .name = "sirfsoc_timer1",
186 .flags = IRQF_TIMER | IRQF_NOBALANCING,
187 .handler = sirfsoc_timer_interrupt,
188};
189
190static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce)
191{
192 /* Use existing clock_event for cpu 0 */
193 if (!smp_processor_id())
194 return 0;
195
196 ce->irq = sirfsoc_timer1_irq.irq;
197 ce->name = "local_timer";
198 ce->features = sirfsoc_clockevent.features;
199 ce->rating = sirfsoc_clockevent.rating;
200 ce->set_mode = sirfsoc_timer_set_mode;
201 ce->set_next_event = sirfsoc_timer_set_next_event;
202 ce->shift = sirfsoc_clockevent.shift;
203 ce->mult = sirfsoc_clockevent.mult;
204 ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
205 ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
206
207 sirfsoc_timer1_irq.dev_id = ce;
208 BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
209 irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
210
211 clockevents_register_device(ce);
212 return 0;
213}
214
215static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
216{
217 sirfsoc_timer_count_disable(1);
218
219 remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
220}
221
222static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
223 .setup = sirfsoc_local_timer_setup,
224 .stop = sirfsoc_local_timer_stop,
225};
226#endif /* CONFIG_LOCAL_TIMERS */
227
228static void __init sirfsoc_clockevent_init(void)
229{
230 clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
231
232 sirfsoc_clockevent.max_delta_ns =
233 clockevent_delta2ns(-2, &sirfsoc_clockevent);
234 sirfsoc_clockevent.min_delta_ns =
235 clockevent_delta2ns(2, &sirfsoc_clockevent);
236
237 sirfsoc_clockevent.cpumask = cpumask_of(0);
238 clockevents_register_device(&sirfsoc_clockevent);
239#ifdef CONFIG_LOCAL_TIMERS
240 local_timer_register(&sirfsoc_local_timer_ops);
241#endif
242}
243
244/* initialize the kernel jiffy timer source */
245void __init sirfsoc_marco_timer_init(void)
246{
247 unsigned long rate;
248 u32 timer_div;
249 struct clk *clk;
250
251 /* initialize clocking early, we want to set the OS timer */
252 sirfsoc_of_clk_init();
253
254 /* timer's input clock is io clock */
255 clk = clk_get_sys("io", NULL);
256
257 BUG_ON(IS_ERR(clk));
258 rate = clk_get_rate(clk);
259
260 BUG_ON(rate < CLOCK_TICK_RATE);
261 BUG_ON(rate % CLOCK_TICK_RATE);
262
263 sirfsoc_of_timer_map();
264
265 /* Initialize the timer dividers */
266 timer_div = rate / CLOCK_TICK_RATE - 1;
267 writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
268 writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
269 writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
270
271 /* Initialize timer counters to 0 */
272 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
273 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
274 writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
275 BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
276 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
277 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
278
279 /* Clear all interrupts */
280 writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
281
282 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
283
284 BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
285
286 sirfsoc_clockevent_init();
287}
288
289static struct of_device_id timer_ids[] = {
290 { .compatible = "sirf,marco-tick" },
291 {},
292};
293
294static void __init sirfsoc_of_timer_map(void)
295{
296 struct device_node *np;
297
298 np = of_find_matching_node(NULL, timer_ids);
299 if (!np)
300 return;
301 sirfsoc_timer_base = of_iomap(np, 0);
302 if (!sirfsoc_timer_base)
303 panic("unable to map timer cpu registers\n");
304
305 sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
306 if (!sirfsoc_timer_irq.irq)
307 panic("No irq passed for timer0 via DT\n");
308
309#ifdef CONFIG_LOCAL_TIMERS
310 sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
311 if (!sirfsoc_timer1_irq.irq)
312 panic("No irq passed for timer1 via DT\n");
313#endif
314
315 of_node_put(np);
316}
diff --git a/arch/arm/mach-prima2/timer-prima2.c b/arch/arm/mach-prima2/timer-prima2.c
deleted file mode 100644
index 982908350b46..000000000000
--- a/arch/arm/mach-prima2/timer-prima2.c
+++ /dev/null
@@ -1,239 +0,0 @@
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_irq.h>
20#include <linux/of_address.h>
21#include <mach/map.h>
22#include <asm/sched_clock.h>
23#include <asm/mach/time.h>
24
25#include "common.h"
26
27#define SIRFSOC_TIMER_COUNTER_LO 0x0000
28#define SIRFSOC_TIMER_COUNTER_HI 0x0004
29#define SIRFSOC_TIMER_MATCH_0 0x0008
30#define SIRFSOC_TIMER_MATCH_1 0x000C
31#define SIRFSOC_TIMER_MATCH_2 0x0010
32#define SIRFSOC_TIMER_MATCH_3 0x0014
33#define SIRFSOC_TIMER_MATCH_4 0x0018
34#define SIRFSOC_TIMER_MATCH_5 0x001C
35#define SIRFSOC_TIMER_STATUS 0x0020
36#define SIRFSOC_TIMER_INT_EN 0x0024
37#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028
38#define SIRFSOC_TIMER_DIV 0x002C
39#define SIRFSOC_TIMER_LATCH 0x0030
40#define SIRFSOC_TIMER_LATCHED_LO 0x0034
41#define SIRFSOC_TIMER_LATCHED_HI 0x0038
42
43#define SIRFSOC_TIMER_WDT_INDEX 5
44
45#define SIRFSOC_TIMER_LATCH_BIT BIT(0)
46
47#define SIRFSOC_TIMER_REG_CNT 11
48
49static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
50 SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
51 SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
52 SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
53 SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
54};
55
56static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
57
58static void __iomem *sirfsoc_timer_base;
59static void __init sirfsoc_of_timer_map(void);
60
61/* timer0 interrupt handler */
62static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
63{
64 struct clock_event_device *ce = dev_id;
65
66 WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
67
68 /* clear timer0 interrupt */
69 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
70
71 ce->event_handler(ce);
72
73 return IRQ_HANDLED;
74}
75
76/* read 64-bit timer counter */
77static cycle_t sirfsoc_timer_read(struct clocksource *cs)
78{
79 u64 cycles;
80
81 /* latch the 64-bit timer counter */
82 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
83 cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
84 cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
85
86 return cycles;
87}
88
89static int sirfsoc_timer_set_next_event(unsigned long delta,
90 struct clock_event_device *ce)
91{
92 unsigned long now, next;
93
94 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
95 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
96 next = now + delta;
97 writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
98 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
99 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
100
101 return next - now > delta ? -ETIME : 0;
102}
103
104static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
105 struct clock_event_device *ce)
106{
107 u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
108 switch (mode) {
109 case CLOCK_EVT_MODE_PERIODIC:
110 WARN_ON(1);
111 break;
112 case CLOCK_EVT_MODE_ONESHOT:
113 writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
114 break;
115 case CLOCK_EVT_MODE_SHUTDOWN:
116 writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
117 break;
118 case CLOCK_EVT_MODE_UNUSED:
119 case CLOCK_EVT_MODE_RESUME:
120 break;
121 }
122}
123
124static void sirfsoc_clocksource_suspend(struct clocksource *cs)
125{
126 int i;
127
128 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
129
130 for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
131 sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
132}
133
134static void sirfsoc_clocksource_resume(struct clocksource *cs)
135{
136 int i;
137
138 for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
139 writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
140
141 writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
142 writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
143}
144
145static struct clock_event_device sirfsoc_clockevent = {
146 .name = "sirfsoc_clockevent",
147 .rating = 200,
148 .features = CLOCK_EVT_FEAT_ONESHOT,
149 .set_mode = sirfsoc_timer_set_mode,
150 .set_next_event = sirfsoc_timer_set_next_event,
151};
152
153static struct clocksource sirfsoc_clocksource = {
154 .name = "sirfsoc_clocksource",
155 .rating = 200,
156 .mask = CLOCKSOURCE_MASK(64),
157 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
158 .read = sirfsoc_timer_read,
159 .suspend = sirfsoc_clocksource_suspend,
160 .resume = sirfsoc_clocksource_resume,
161};
162
163static struct irqaction sirfsoc_timer_irq = {
164 .name = "sirfsoc_timer0",
165 .flags = IRQF_TIMER,
166 .irq = 0,
167 .handler = sirfsoc_timer_interrupt,
168 .dev_id = &sirfsoc_clockevent,
169};
170
171/* Overwrite weak default sched_clock with more precise one */
172static u32 notrace sirfsoc_read_sched_clock(void)
173{
174 return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff);
175}
176
177static void __init sirfsoc_clockevent_init(void)
178{
179 sirfsoc_clockevent.cpumask = cpumask_of(0);
180 clockevents_config_and_register(&sirfsoc_clockevent, CLOCK_TICK_RATE,
181 2, -2);
182}
183
184/* initialize the kernel jiffy timer source */
185void __init sirfsoc_prima2_timer_init(void)
186{
187 unsigned long rate;
188 struct clk *clk;
189
190 /* initialize clocking early, we want to set the OS timer */
191 sirfsoc_of_clk_init();
192
193 /* timer's input clock is io clock */
194 clk = clk_get_sys("io", NULL);
195
196 BUG_ON(IS_ERR(clk));
197
198 rate = clk_get_rate(clk);
199
200 BUG_ON(rate < CLOCK_TICK_RATE);
201 BUG_ON(rate % CLOCK_TICK_RATE);
202
203 sirfsoc_of_timer_map();
204
205 writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
206 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
207 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
208 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
209
210 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
211
212 setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE);
213
214 BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
215
216 sirfsoc_clockevent_init();
217}
218
219static struct of_device_id timer_ids[] = {
220 { .compatible = "sirf,prima2-tick" },
221 {},
222};
223
224static void __init sirfsoc_of_timer_map(void)
225{
226 struct device_node *np;
227
228 np = of_find_matching_node(NULL, timer_ids);
229 if (!np)
230 return;
231 sirfsoc_timer_base = of_iomap(np, 0);
232 if (!sirfsoc_timer_base)
233 panic("unable to map timer cpu registers\n");
234
235 /* Get the interrupts property */
236 sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
237
238 of_node_put(np);
239}