aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc/kernel
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-01-18 04:42:18 -0500
committerVineet Gupta <vgupta@synopsys.com>2013-02-11 09:30:39 -0500
commitd8005e6b95268cbb50db3773d5f180c32a9434fe (patch)
tree1e27f00970c3612521a4d29146948ef4cec05586 /arch/arc/kernel
parentbf90e1eab682dcb79b7765989fb65835ce9d6165 (diff)
ARC: Timers/counters/delay management
ARC700 includes 2 in-core 32bit timers TIMER0 and TIMER1. Both have exactly same capabilies. * programmable to count from TIMER<n>_CNT to TIMER<n>_LIMIT * for count 0 and LIMIT ~1, provides a free-running counter by auto-wrapping when limit is reached. * optionally interrupt when LIMIT is reached (oneshot event semantics) * rearming the interrupt provides periodic semantics * run at CPU clk ARC Linux uses TIMER0 for clockevent (periodic/oneshot) and TIMER1 for clocksource (free-running clock). Newer cores provide RTSC insn which gives a 64bit cpu clk snapshot hence is more apt for clocksource when available. SMP poses a bit of challenge for global timekeeping clocksource / sched_clock() backend: -TIMER1 based local clocks are out-of-sync hence can't be used (thus we default to jiffies based cs as well as sched_clock() one/both of which platform can override with it's specific hardware assist) -RTSC is only allowed in SMP if it's cross-core-sync (Kconfig glue ensures that) and thus usable for both requirements. Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r--arch/arc/kernel/clk.c11
-rw-r--r--arch/arc/kernel/time.c295
2 files changed, 306 insertions, 0 deletions
diff --git a/arch/arc/kernel/clk.c b/arch/arc/kernel/clk.c
new file mode 100644
index 000000000000..64925db9eb5e
--- /dev/null
+++ b/arch/arc/kernel/clk.c
@@ -0,0 +1,11 @@
1/*
2 * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <asm/clk.h>
10
11unsigned long core_freq = CONFIG_ARC_PLAT_CLK;
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
new file mode 100644
index 000000000000..05dba11fdb2d
--- /dev/null
+++ b/arch/arc/kernel/time.c
@@ -0,0 +1,295 @@
1/*
2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * vineetg: Jan 1011
9 * -sched_clock( ) no longer jiffies based. Uses the same clocksource
10 * as gtod
11 *
12 * Rajeshwarr/Vineetg: Mar 2008
13 * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code)
14 * for arch independent gettimeofday()
15 * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers
16 *
17 * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c
18 */
19
20/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1
21 * Each can programmed to go from @count to @limit and optionally
22 * interrupt when that happens.
23 * A write to Control Register clears the Interrupt
24 *
25 * We've designated TIMER0 for events (clockevents)
26 * while TIMER1 for free running (clocksource)
27 *
28 * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1
29 */
30
31#include <linux/spinlock.h>
32#include <linux/interrupt.h>
33#include <linux/module.h>
34#include <linux/sched.h>
35#include <linux/kernel.h>
36#include <linux/interrupt.h>
37#include <linux/time.h>
38#include <linux/init.h>
39#include <linux/timex.h>
40#include <linux/profile.h>
41#include <linux/clocksource.h>
42#include <linux/clockchips.h>
43#include <asm/irq.h>
44#include <asm/arcregs.h>
45#include <asm/clk.h>
46
47#define ARC_TIMER_MAX 0xFFFFFFFF
48
49/********** Clock Source Device *********/
50
51#ifdef CONFIG_ARC_HAS_RTSC
52
53int __cpuinit arc_counter_setup(void)
54{
55 /* RTSC insn taps into cpu clk, needs no setup */
56
57 /* For SMP, only allowed if cross-core-sync, hence usable as cs */
58 return 1;
59}
60
61static cycle_t arc_counter_read(struct clocksource *cs)
62{
63 unsigned long flags;
64 union {
65#ifdef CONFIG_CPU_BIG_ENDIAN
66 struct { u32 high, low; };
67#else
68 struct { u32 low, high; };
69#endif
70 cycle_t full;
71 } stamp;
72
73 flags = arch_local_irq_save();
74
75 __asm__ __volatile(
76 " .extCoreRegister tsch, 58, r, cannot_shortcut \n"
77 " rtsc %0, 0 \n"
78 " mov %1, tsch \n" /* TSCH is extn core reg 58 */
79 : "=r" (stamp.low), "=r" (stamp.high));
80
81 arch_local_irq_restore(flags);
82
83 return stamp.full;
84}
85
86static struct clocksource arc_counter = {
87 .name = "ARC RTSC",
88 .rating = 300,
89 .read = arc_counter_read,
90 .mask = CLOCKSOURCE_MASK(64),
91 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
92};
93
94#else /* !CONFIG_ARC_HAS_RTSC */
95
96static bool is_usable_as_clocksource(void)
97{
98#ifdef CONFIG_SMP
99 return 0;
100#else
101 return 1;
102#endif
103}
104
105/*
106 * set 32bit TIMER1 to keep counting monotonically and wraparound
107 */
108int __cpuinit arc_counter_setup(void)
109{
110 write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
111 write_aux_reg(ARC_REG_TIMER1_CNT, 0);
112 write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
113
114 return is_usable_as_clocksource();
115}
116
117static cycle_t arc_counter_read(struct clocksource *cs)
118{
119 return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT);
120}
121
122static struct clocksource arc_counter = {
123 .name = "ARC Timer1",
124 .rating = 300,
125 .read = arc_counter_read,
126 .mask = CLOCKSOURCE_MASK(32),
127 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
128};
129
130#endif
131
132/********** Clock Event Device *********/
133
134/*
135 * Arm the timer to interrupt after @limit cycles
136 * The distinction for oneshot/periodic is done in arc_event_timer_ack() below
137 */
138static void arc_timer_event_setup(unsigned int limit)
139{
140 write_aux_reg(ARC_REG_TIMER0_LIMIT, limit);
141 write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */
142
143 write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH);
144}
145
146/*
147 * Acknowledge the interrupt (oneshot) and optionally re-arm it (periodic)
148 * -Any write to CTRL Reg will ack the intr (NH bit: Count when not halted)
149 * -Rearming is done by setting the IE bit
150 *
151 * Small optimisation: Normal code would have been
152 * if (irq_reenable)
153 * CTRL_REG = (IE | NH);
154 * else
155 * CTRL_REG = NH;
156 * However since IE is BIT0 we can fold the branch
157 */
158static void arc_timer_event_ack(unsigned int irq_reenable)
159{
160 write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
161}
162
163static int arc_clkevent_set_next_event(unsigned long delta,
164 struct clock_event_device *dev)
165{
166 arc_timer_event_setup(delta);
167 return 0;
168}
169
170static void arc_clkevent_set_mode(enum clock_event_mode mode,
171 struct clock_event_device *dev)
172{
173 switch (mode) {
174 case CLOCK_EVT_MODE_PERIODIC:
175 arc_timer_event_setup(arc_get_core_freq() / HZ);
176 break;
177 case CLOCK_EVT_MODE_ONESHOT:
178 break;
179 default:
180 break;
181 }
182
183 return;
184}
185
186static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
187 .name = "ARC Timer0",
188 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
189 .mode = CLOCK_EVT_MODE_UNUSED,
190 .rating = 300,
191 .irq = TIMER0_IRQ, /* hardwired, no need for resources */
192 .set_next_event = arc_clkevent_set_next_event,
193 .set_mode = arc_clkevent_set_mode,
194};
195
196static irqreturn_t timer_irq_handler(int irq, void *dev_id)
197{
198 struct clock_event_device *clk = &__get_cpu_var(arc_clockevent_device);
199
200 arc_timer_event_ack(clk->mode == CLOCK_EVT_MODE_PERIODIC);
201 clk->event_handler(clk);
202 return IRQ_HANDLED;
203}
204
205static struct irqaction arc_timer_irq = {
206 .name = "Timer0 (clock-evt-dev)",
207 .flags = IRQF_TIMER | IRQF_PERCPU,
208 .handler = timer_irq_handler,
209};
210
211/*
212 * Setup the local event timer for @cpu
213 * N.B. weak so that some exotic ARC SoCs can completely override it
214 */
215void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu)
216{
217 struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
218
219 clockevents_calc_mult_shift(clk, arc_get_core_freq(), 5);
220
221 clk->max_delta_ns = clockevent_delta2ns(ARC_TIMER_MAX, clk);
222 clk->cpumask = cpumask_of(cpu);
223
224 clockevents_register_device(clk);
225
226 /*
227 * setup the per-cpu timer IRQ handler - for all cpus
228 * For non boot CPU explicitly unmask at intc
229 * setup_irq() -> .. -> irq_startup() already does this on boot-cpu
230 */
231 if (!cpu)
232 setup_irq(TIMER0_IRQ, &arc_timer_irq);
233 else
234 arch_unmask_irq(TIMER0_IRQ);
235}
236
237/*
238 * Called from start_kernel() - boot CPU only
239 *
240 * -Sets up h/w timers as applicable on boot cpu
241 * -Also sets up any global state needed for timer subsystem:
242 * - for "counting" timer, registers a clocksource, usable across CPUs
243 * (provided that underlying counter h/w is synchronized across cores)
244 * - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic)
245 */
246void __init time_init(void)
247{
248 /*
249 * sets up the timekeeping free-flowing counter which also returns
250 * whether the counter is usable as clocksource
251 */
252 if (arc_counter_setup())
253 /*
254 * CLK upto 4.29 GHz can be safely represented in 32 bits
255 * because Max 32 bit number is 4,294,967,295
256 */
257 clocksource_register_hz(&arc_counter, arc_get_core_freq());
258
259 /* sets up the periodic event timer */
260 arc_local_timer_setup(smp_processor_id());
261}
262
263#ifdef CONFIG_ARC_HAS_RTSC
264/*
265 * sched_clock math assist
266 * ns = cycles * (ns_per_sec / cpu_freq_hz)
267 * ns = cycles * (10^6 / cpu_freq_khz)
268 * ns = cycles * (10^6 * 2^SF / cpu_freq_khz) / 2^SF
269 * ns = cycles * cyc2ns_scale >> SF
270 */
271#define CYC2NS_SF 10 /* 2^10, carefully chosen */
272#define CYC2NS_SCALE ((1000000 << CYC2NS_SF) / (arc_get_core_freq() / 1000))
273
274static unsigned long long cycles2ns(unsigned long long cyc)
275{
276 return (cyc * CYC2NS_SCALE ) >> CYC2NS_SF;
277}
278
279/*
280 * Scheduler clock - a monotonically increasing clock in nanosec units.
281 * It's return value must NOT wrap around.
282 *
283 * - Since 32bit TIMER1 will overflow almost immediately (53sec @ 80MHz), it
284 * can't be used directly.
285 * - Using getrawmonotonic (TIMER1 based, but with state for last + current
286 * snapshots), is no-good either because of seqlock deadlock possibilities
287 * - So only with native 64bit timer we do this, otherwise fallback to generic
288 * jiffies based version - which despite not being fine grained gaurantees
289 * the monotonically increasing semantics.
290 */
291unsigned long long sched_clock(void)
292{
293 return cycles2ns(arc_counter_read(NULL));
294}
295#endif