aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc/kernel/time.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 12:46:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 12:46:18 -0400
commit0efacbbaee1e94e9942da0912f5b46ffd45a74bd (patch)
treea17933437de955f4ce5e74760610bab75f2ae385 /arch/arc/kernel/time.c
parentf4f27d0028aabce57e44c16c2fdefccd6310d2f3 (diff)
parent776d7f1694a7d678291354a05f0243965708306a (diff)
Merge tag 'arc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
Pull ARC updates from Vineet Gupta: "We have a relatively big changeset for ARC for 4.7. The highlight is support for EZChip (now Mellanox) NPS-400 network processor, a 400-Gb throughput C-programmable packet processor based on ARC700 cores from Synopsys. See http://www.mellanox.com/related-docs/prod_npu/PB_NPS-400.pdf Also present are irqchip and clocksource drivers for NPS as agreed with respective maintainers to go via ARC tree due to an soc header dependency. I have the needed ACKs from Jason, Marc, Daniel. You might run into a trivial merge conflict in drivers/irqchip/* This EZChip platform support required some deep changes in ARC architecture code and also opportunity to cleanup past sins (legacy irq domains, missing irq domain lookup, hard coded timer irqs...) Summary: - Support for EZChip (now Mellanox) NPS-400 Network processor based on ARC700 - NPS interrupt controller and clocksource drivers - ARC timers probed off DT - ARC iqrchips switching to linear domain (upgrade from legacy domains)" * tag 'arc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc: (37 commits) arc: axs103_smp: Fix CPU frequency to 100MHz for dual-core arc: axs10x: Add DT bindings for I2S PLL Clock ARC: pae: STRICT_MM_TYPECHECKS was broken ARC: Add eznps platform to Kconfig and Makefile ARC: [plat-eznps] Use dedicated COMMAND_LINE_SIZE ARC: [plat-eznps] Use dedicated cpu_relax() ARC: [plat-eznps] Use dedicated identity auxiliary register. ARC: [plat-eznps] Use dedicated SMP barriers ARC: [plat-eznps] Use dedicated atomic/bitops/cmpxchg ARC: [plat-eznps] Use dedicated user stack top ARC: [plat-eznps] Add eznps platform ARC: [plat-eznps] Add eznps board defconfig and dts ARC: Mark secondary cpu online only after all HW setup is done ARC: rwlock: disable interrupts in !LLSC variant ARC: Make vmalloc size configurable ARC: clean out UAPI byteorder.h clean off Kconfig symbol irqchip: add nps Internal and external irqchips clocksource: Add NPS400 timers driver soc: Support for EZchip SoC Documentation: Add EZchip vendor to binding list ...
Diffstat (limited to 'arch/arc/kernel/time.c')
-rw-r--r--arch/arc/kernel/time.c238
1 files changed, 163 insertions, 75 deletions
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 7d9a736fc7e5..4549ab255dd1 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -29,21 +29,16 @@
29 * which however is currently broken 29 * which however is currently broken
30 */ 30 */
31 31
32#include <linux/spinlock.h>
33#include <linux/interrupt.h> 32#include <linux/interrupt.h>
34#include <linux/module.h> 33#include <linux/clk.h>
35#include <linux/sched.h> 34#include <linux/clk-provider.h>
36#include <linux/kernel.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> 35#include <linux/clocksource.h>
42#include <linux/clockchips.h> 36#include <linux/clockchips.h>
37#include <linux/cpu.h>
38#include <linux/of.h>
39#include <linux/of_irq.h>
43#include <asm/irq.h> 40#include <asm/irq.h>
44#include <asm/arcregs.h> 41#include <asm/arcregs.h>
45#include <asm/clk.h>
46#include <asm/mach_desc.h>
47 42
48#include <asm/mcip.h> 43#include <asm/mcip.h>
49 44
@@ -60,16 +55,35 @@
60 55
61#define ARC_TIMER_MAX 0xFFFFFFFF 56#define ARC_TIMER_MAX 0xFFFFFFFF
62 57
63/********** Clock Source Device *********/ 58static unsigned long arc_timer_freq;
64
65#ifdef CONFIG_ARC_HAS_GFRC
66 59
67static int arc_counter_setup(void) 60static int noinline arc_get_timer_clk(struct device_node *node)
68{ 61{
69 return 1; 62 struct clk *clk;
63 int ret;
64
65 clk = of_clk_get(node, 0);
66 if (IS_ERR(clk)) {
67 pr_err("timer missing clk");
68 return PTR_ERR(clk);
69 }
70
71 ret = clk_prepare_enable(clk);
72 if (ret) {
73 pr_err("Couldn't enable parent clk\n");
74 return ret;
75 }
76
77 arc_timer_freq = clk_get_rate(clk);
78
79 return 0;
70} 80}
71 81
72static cycle_t arc_counter_read(struct clocksource *cs) 82/********** Clock Source Device *********/
83
84#ifdef CONFIG_ARC_HAS_GFRC
85
86static cycle_t arc_read_gfrc(struct clocksource *cs)
73{ 87{
74 unsigned long flags; 88 unsigned long flags;
75 union { 89 union {
@@ -94,15 +108,31 @@ static cycle_t arc_counter_read(struct clocksource *cs)
94 return stamp.full; 108 return stamp.full;
95} 109}
96 110
97static struct clocksource arc_counter = { 111static struct clocksource arc_counter_gfrc = {
98 .name = "ARConnect GFRC", 112 .name = "ARConnect GFRC",
99 .rating = 400, 113 .rating = 400,
100 .read = arc_counter_read, 114 .read = arc_read_gfrc,
101 .mask = CLOCKSOURCE_MASK(64), 115 .mask = CLOCKSOURCE_MASK(64),
102 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 116 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
103}; 117};
104 118
105#else 119static void __init arc_cs_setup_gfrc(struct device_node *node)
120{
121 int exists = cpuinfo_arc700[0].extn.gfrc;
122 int ret;
123
124 if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected"))
125 return;
126
127 ret = arc_get_timer_clk(node);
128 if (ret)
129 return;
130
131 clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
132}
133CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
134
135#endif
106 136
107#ifdef CONFIG_ARC_HAS_RTC 137#ifdef CONFIG_ARC_HAS_RTC
108 138
@@ -110,15 +140,7 @@ static struct clocksource arc_counter = {
110#define AUX_RTC_LOW 0x104 140#define AUX_RTC_LOW 0x104
111#define AUX_RTC_HIGH 0x105 141#define AUX_RTC_HIGH 0x105
112 142
113int arc_counter_setup(void) 143static cycle_t arc_read_rtc(struct clocksource *cs)
114{
115 write_aux_reg(AUX_RTC_CTRL, 1);
116
117 /* Not usable in SMP */
118 return !IS_ENABLED(CONFIG_SMP);
119}
120
121static cycle_t arc_counter_read(struct clocksource *cs)
122{ 144{
123 unsigned long status; 145 unsigned long status;
124 union { 146 union {
@@ -142,47 +164,78 @@ static cycle_t arc_counter_read(struct clocksource *cs)
142 return stamp.full; 164 return stamp.full;
143} 165}
144 166
145static struct clocksource arc_counter = { 167static struct clocksource arc_counter_rtc = {
146 .name = "ARCv2 RTC", 168 .name = "ARCv2 RTC",
147 .rating = 350, 169 .rating = 350,
148 .read = arc_counter_read, 170 .read = arc_read_rtc,
149 .mask = CLOCKSOURCE_MASK(64), 171 .mask = CLOCKSOURCE_MASK(64),
150 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 172 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
151}; 173};
152 174
153#else /* !CONFIG_ARC_HAS_RTC */ 175static void __init arc_cs_setup_rtc(struct device_node *node)
154
155/*
156 * set 32bit TIMER1 to keep counting monotonically and wraparound
157 */
158int arc_counter_setup(void)
159{ 176{
160 write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); 177 int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc;
161 write_aux_reg(ARC_REG_TIMER1_CNT, 0); 178 int ret;
162 write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); 179
180 if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected"))
181 return;
182
183 /* Local to CPU hence not usable in SMP */
184 if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP"))
185 return;
186
187 ret = arc_get_timer_clk(node);
188 if (ret)
189 return;
190
191 write_aux_reg(AUX_RTC_CTRL, 1);
163 192
164 /* Not usable in SMP */ 193 clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
165 return !IS_ENABLED(CONFIG_SMP);
166} 194}
195CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
167 196
168static cycle_t arc_counter_read(struct clocksource *cs) 197#endif
198
199/*
200 * 32bit TIMER1 to keep counting monotonically and wraparound
201 */
202
203static cycle_t arc_read_timer1(struct clocksource *cs)
169{ 204{
170 return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); 205 return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT);
171} 206}
172 207
173static struct clocksource arc_counter = { 208static struct clocksource arc_counter_timer1 = {
174 .name = "ARC Timer1", 209 .name = "ARC Timer1",
175 .rating = 300, 210 .rating = 300,
176 .read = arc_counter_read, 211 .read = arc_read_timer1,
177 .mask = CLOCKSOURCE_MASK(32), 212 .mask = CLOCKSOURCE_MASK(32),
178 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 213 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
179}; 214};
180 215
181#endif 216static void __init arc_cs_setup_timer1(struct device_node *node)
182#endif 217{
218 int ret;
219
220 /* Local to CPU hence not usable in SMP */
221 if (IS_ENABLED(CONFIG_SMP))
222 return;
223
224 ret = arc_get_timer_clk(node);
225 if (ret)
226 return;
227
228 write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
229 write_aux_reg(ARC_REG_TIMER1_CNT, 0);
230 write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
231
232 clocksource_register_hz(&arc_counter_timer1, arc_timer_freq);
233}
183 234
184/********** Clock Event Device *********/ 235/********** Clock Event Device *********/
185 236
237static int arc_timer_irq;
238
186/* 239/*
187 * Arm the timer to interrupt after @cycles 240 * Arm the timer to interrupt after @cycles
188 * The distinction for oneshot/periodic is done in arc_event_timer_ack() below 241 * The distinction for oneshot/periodic is done in arc_event_timer_ack() below
@@ -209,7 +262,7 @@ static int arc_clkevent_set_periodic(struct clock_event_device *dev)
209 * At X Hz, 1 sec = 1000ms -> X cycles; 262 * At X Hz, 1 sec = 1000ms -> X cycles;
210 * 10ms -> X / 100 cycles 263 * 10ms -> X / 100 cycles
211 */ 264 */
212 arc_timer_event_setup(arc_get_core_freq() / HZ); 265 arc_timer_event_setup(arc_timer_freq / HZ);
213 return 0; 266 return 0;
214} 267}
215 268
@@ -218,7 +271,6 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
218 .features = CLOCK_EVT_FEAT_ONESHOT | 271 .features = CLOCK_EVT_FEAT_ONESHOT |
219 CLOCK_EVT_FEAT_PERIODIC, 272 CLOCK_EVT_FEAT_PERIODIC,
220 .rating = 300, 273 .rating = 300,
221 .irq = TIMER0_IRQ, /* hardwired, no need for resources */
222 .set_next_event = arc_clkevent_set_next_event, 274 .set_next_event = arc_clkevent_set_next_event,
223 .set_state_periodic = arc_clkevent_set_periodic, 275 .set_state_periodic = arc_clkevent_set_periodic,
224}; 276};
@@ -244,45 +296,81 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
244 return IRQ_HANDLED; 296 return IRQ_HANDLED;
245} 297}
246 298
299static int arc_timer_cpu_notify(struct notifier_block *self,
300 unsigned long action, void *hcpu)
301{
302 struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
303
304 evt->cpumask = cpumask_of(smp_processor_id());
305
306 switch (action & ~CPU_TASKS_FROZEN) {
307 case CPU_STARTING:
308 clockevents_config_and_register(evt, arc_timer_freq,
309 0, ULONG_MAX);
310 enable_percpu_irq(arc_timer_irq, 0);
311 break;
312 case CPU_DYING:
313 disable_percpu_irq(arc_timer_irq);
314 break;
315 }
316
317 return NOTIFY_OK;
318}
319
320static struct notifier_block arc_timer_cpu_nb = {
321 .notifier_call = arc_timer_cpu_notify,
322};
323
247/* 324/*
248 * Setup the local event timer for @cpu 325 * clockevent setup for boot CPU
249 */ 326 */
250void arc_local_timer_setup() 327static void __init arc_clockevent_setup(struct device_node *node)
251{ 328{
252 struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); 329 struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
253 int cpu = smp_processor_id(); 330 int ret;
331
332 register_cpu_notifier(&arc_timer_cpu_nb);
254 333
255 evt->cpumask = cpumask_of(cpu); 334 arc_timer_irq = irq_of_parse_and_map(node, 0);
256 clockevents_config_and_register(evt, arc_get_core_freq(), 335 if (arc_timer_irq <= 0)
336 panic("clockevent: missing irq");
337
338 ret = arc_get_timer_clk(node);
339 if (ret)
340 panic("clockevent: missing clk");
341
342 evt->irq = arc_timer_irq;
343 evt->cpumask = cpumask_of(smp_processor_id());
344 clockevents_config_and_register(evt, arc_timer_freq,
257 0, ARC_TIMER_MAX); 345 0, ARC_TIMER_MAX);
258 346
259 /* setup the per-cpu timer IRQ handler - for all cpus */ 347 /* Needs apriori irq_set_percpu_devid() done in intc map function */
260 arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, 348 ret = request_percpu_irq(arc_timer_irq, timer_irq_handler,
261 "Timer0 (per-cpu-tick)", evt); 349 "Timer0 (per-cpu-tick)", evt);
350 if (ret)
351 panic("clockevent: unable to request irq\n");
352
353 enable_percpu_irq(arc_timer_irq, 0);
262} 354}
263 355
356static void __init arc_of_timer_init(struct device_node *np)
357{
358 static int init_count = 0;
359
360 if (!init_count) {
361 init_count = 1;
362 arc_clockevent_setup(np);
363 } else {
364 arc_cs_setup_timer1(np);
365 }
366}
367CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init);
368
264/* 369/*
265 * Called from start_kernel() - boot CPU only 370 * Called from start_kernel() - boot CPU only
266 *
267 * -Sets up h/w timers as applicable on boot cpu
268 * -Also sets up any global state needed for timer subsystem:
269 * - for "counting" timer, registers a clocksource, usable across CPUs
270 * (provided that underlying counter h/w is synchronized across cores)
271 * - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic)
272 */ 371 */
273void __init time_init(void) 372void __init time_init(void)
274{ 373{
275 /* 374 of_clk_init(NULL);
276 * sets up the timekeeping free-flowing counter which also returns 375 clocksource_probe();
277 * whether the counter is usable as clocksource
278 */
279 if (arc_counter_setup())
280 /*
281 * CLK upto 4.29 GHz can be safely represented in 32 bits
282 * because Max 32 bit number is 4,294,967,295
283 */
284 clocksource_register_hz(&arc_counter, arc_get_core_freq());
285
286 /* sets up the periodic event timer */
287 arc_local_timer_setup();
288} 376}