aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2010-10-27 12:28:57 -0400
committerDavid Howells <dhowells@redhat.com>2010-10-27 12:28:57 -0400
commit730c1fad0ee22a170d2ee76a904709ee304931c0 (patch)
tree365289c84b02c5c54d43238f2bc9b14b143cafbc
parent2502c64eeb125c5d57e3e7dc38320b500d69e088 (diff)
MN10300: Generic time support
Implement generic time support for MN10300. Signed-off-by: Mark Salter <msalter@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--arch/mn10300/Kconfig22
-rw-r--r--arch/mn10300/include/asm/timex.h17
-rw-r--r--arch/mn10300/kernel/Makefile2
-rw-r--r--arch/mn10300/kernel/cevt-mn10300.c131
-rw-r--r--arch/mn10300/kernel/csrc-mn10300.c35
-rw-r--r--arch/mn10300/kernel/internal.h13
-rw-r--r--arch/mn10300/kernel/irq.c32
-rw-r--r--arch/mn10300/kernel/smp.c15
-rw-r--r--arch/mn10300/kernel/time.c79
-rw-r--r--arch/mn10300/unit-asb2303/include/unit/timex.h48
-rw-r--r--arch/mn10300/unit-asb2305/include/unit/timex.h48
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/timex.h74
12 files changed, 401 insertions, 115 deletions
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 81e27816aaf8..42ca55a47377 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -56,6 +56,27 @@ config GENERIC_FIND_NEXT_BIT
56config GENERIC_HWEIGHT 56config GENERIC_HWEIGHT
57 def_bool y 57 def_bool y
58 58
59config GENERIC_TIME
60 def_bool y
61
62config GENERIC_CLOCKEVENTS
63 def_bool y
64
65config GENERIC_CLOCKEVENTS_BUILD
66 def_bool y
67 depends on GENERIC_CLOCKEVENTS
68
69config GENERIC_CLOCKEVENTS_BROADCAST
70 bool
71
72config CEVT_MN10300
73 def_bool y
74 depends on GENERIC_CLOCKEVENTS
75
76config CSRC_MN10300
77 def_bool y
78 depends on GENERIC_TIME
79
59config GENERIC_BUG 80config GENERIC_BUG
60 def_bool y 81 def_bool y
61 82
@@ -245,6 +266,7 @@ config MN10300_USING_JTAG
245 single-stepping, which are taken over completely by the JTAG unit. 266 single-stepping, which are taken over completely by the JTAG unit.
246 267
247source "kernel/Kconfig.hz" 268source "kernel/Kconfig.hz"
269source "kernel/time/Kconfig"
248 270
249config MN10300_RTC 271config MN10300_RTC
250 bool "Using MN10300 RTC" 272 bool "Using MN10300 RTC"
diff --git a/arch/mn10300/include/asm/timex.h b/arch/mn10300/include/asm/timex.h
index ce5719a2ce7c..bd4e90dfe6c2 100644
--- a/arch/mn10300/include/asm/timex.h
+++ b/arch/mn10300/include/asm/timex.h
@@ -18,15 +18,28 @@
18 18
19#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */ 19#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */
20 20
21extern cycles_t cacheflush_time;
22
23#ifdef __KERNEL__ 21#ifdef __KERNEL__
24 22
23extern cycles_t cacheflush_time;
24
25static inline cycles_t get_cycles(void) 25static inline cycles_t get_cycles(void)
26{ 26{
27 return read_timestamp_counter(); 27 return read_timestamp_counter();
28} 28}
29 29
30extern int init_clockevents(void);
31extern int init_clocksource(void);
32
33static inline void setup_jiffies_interrupt(int irq,
34 struct irqaction *action)
35{
36 u16 tmp;
37 setup_irq(irq, action);
38 set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
39 GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
40 tmp = GxICR(irq);
41}
42
30#endif /* __KERNEL__ */ 43#endif /* __KERNEL__ */
31 44
32#endif /* _ASM_TIMEX_H */ 45#endif /* _ASM_TIMEX_H */
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
index 5b41192f496b..8f5f1e81baf5 100644
--- a/arch/mn10300/kernel/Makefile
+++ b/arch/mn10300/kernel/Makefile
@@ -28,3 +28,5 @@ obj-$(CONFIG_MN10300_RTC) += rtc.o
28obj-$(CONFIG_PROFILE) += profile.o profile-low.o 28obj-$(CONFIG_PROFILE) += profile.o profile-low.o
29obj-$(CONFIG_MODULES) += module.o 29obj-$(CONFIG_MODULES) += module.o
30obj-$(CONFIG_KPROBES) += kprobes.o 30obj-$(CONFIG_KPROBES) += kprobes.o
31obj-$(CONFIG_CSRC_MN10300) += csrc-mn10300.o
32obj-$(CONFIG_CEVT_MN10300) += cevt-mn10300.o
diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c
new file mode 100644
index 000000000000..d4cb535bf786
--- /dev/null
+++ b/arch/mn10300/kernel/cevt-mn10300.c
@@ -0,0 +1,131 @@
1/* MN10300 clockevents
2 *
3 * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/clockchips.h>
12#include <linux/interrupt.h>
13#include <linux/percpu.h>
14#include <linux/smp.h>
15#include <asm/timex.h>
16#include "internal.h"
17
18#ifdef CONFIG_SMP
19#if (CONFIG_NR_CPUS > 2) && !defined(CONFIG_GEENERIC_CLOCKEVENTS_BROADCAST)
20#error "This doesn't scale well! Need per-core local timers."
21#endif
22#else /* CONFIG_SMP */
23#define stop_jiffies_counter1()
24#define reload_jiffies_counter1(x)
25#define TMJC1IRQ TMJCIRQ
26#endif
27
28
29static int next_event(unsigned long delta,
30 struct clock_event_device *evt)
31{
32 unsigned int cpu = smp_processor_id();
33
34 if (cpu == 0) {
35 stop_jiffies_counter();
36 reload_jiffies_counter(delta - 1);
37 } else {
38 stop_jiffies_counter1();
39 reload_jiffies_counter1(delta - 1);
40 }
41 return 0;
42}
43
44static void set_clock_mode(enum clock_event_mode mode,
45 struct clock_event_device *evt)
46{
47 /* Nothing to do ... */
48}
49
50static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device);
51static DEFINE_PER_CPU(struct irqaction, timer_irq);
52
53static irqreturn_t timer_interrupt(int irq, void *dev_id)
54{
55 struct clock_event_device *cd;
56 unsigned int cpu = smp_processor_id();
57
58 if (cpu == 0)
59 stop_jiffies_counter();
60 else
61 stop_jiffies_counter1();
62
63 cd = &per_cpu(mn10300_clockevent_device, cpu);
64 cd->event_handler(cd);
65
66 return IRQ_HANDLED;
67}
68
69static void event_handler(struct clock_event_device *dev)
70{
71}
72
73int __init init_clockevents(void)
74{
75 struct clock_event_device *cd;
76 struct irqaction *iact;
77 unsigned int cpu = smp_processor_id();
78
79 cd = &per_cpu(mn10300_clockevent_device, cpu);
80
81 if (cpu == 0) {
82 stop_jiffies_counter();
83 cd->irq = TMJCIRQ;
84 } else {
85 stop_jiffies_counter1();
86 cd->irq = TMJC1IRQ;
87 }
88
89 cd->name = "Timestamp";
90 cd->features = CLOCK_EVT_FEAT_ONESHOT;
91
92 /* Calculate the min / max delta */
93 clockevent_set_clock(cd, MN10300_JCCLK);
94
95 cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd);
96 cd->min_delta_ns = clockevent_delta2ns(100, cd);
97
98 cd->rating = 200;
99 cd->cpumask = cpumask_of(smp_processor_id());
100 cd->set_mode = set_clock_mode;
101 cd->event_handler = event_handler;
102 cd->set_next_event = next_event;
103
104 iact = &per_cpu(timer_irq, cpu);
105 iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
106 iact->handler = timer_interrupt;
107
108 clockevents_register_device(cd);
109
110#if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
111 /* setup timer irq affinity so it only runs on this cpu */
112 {
113 struct irq_desc *desc;
114 desc = irq_to_desc(cd->irq);
115 cpumask_copy(desc->affinity, cpumask_of(cpu));
116 iact->flags |= IRQF_NOBALANCING;
117 }
118#endif
119
120 if (cpu == 0) {
121 reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
122 iact->name = "CPU0 Timer";
123 } else {
124 reload_jiffies_counter1(MN10300_JC_PER_HZ - 1);
125 iact->name = "CPU1 Timer";
126 }
127
128 setup_jiffies_interrupt(cd->irq, iact);
129
130 return 0;
131}
diff --git a/arch/mn10300/kernel/csrc-mn10300.c b/arch/mn10300/kernel/csrc-mn10300.c
new file mode 100644
index 000000000000..ba2f0c4d6e01
--- /dev/null
+++ b/arch/mn10300/kernel/csrc-mn10300.c
@@ -0,0 +1,35 @@
1/* MN10300 clocksource
2 *
3 * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/clocksource.h>
12#include <linux/init.h>
13#include <asm/timex.h>
14#include "internal.h"
15
16static cycle_t mn10300_read(struct clocksource *cs)
17{
18 return read_timestamp_counter();
19}
20
21static struct clocksource clocksource_mn10300 = {
22 .name = "TSC",
23 .rating = 200,
24 .read = mn10300_read,
25 .mask = CLOCKSOURCE_MASK(32),
26 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
27};
28
29int __init init_clocksource(void)
30{
31 startup_timestamp_counter();
32 clocksource_set_clock(&clocksource_mn10300, MN10300_TSCCLK);
33 clocksource_register(&clocksource_mn10300);
34 return 0;
35}
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
index 3b1f48b7e7f4..6a064ab5af07 100644
--- a/arch/mn10300/kernel/internal.h
+++ b/arch/mn10300/kernel/internal.h
@@ -9,6 +9,9 @@
9 * 2 of the Licence, or (at your option) any later version. 9 * 2 of the Licence, or (at your option) any later version.
10 */ 10 */
11 11
12struct clocksource;
13struct clock_event_device;
14
12/* 15/*
13 * kthread.S 16 * kthread.S
14 */ 17 */
@@ -30,3 +33,13 @@ extern void mn10300_low_ipi_handler(void);
30 * time.c 33 * time.c
31 */ 34 */
32extern irqreturn_t local_timer_interrupt(void); 35extern irqreturn_t local_timer_interrupt(void);
36
37/*
38 * time.c
39 */
40#ifdef CONFIG_CEVT_MN10300
41extern void clockevent_set_clock(struct clock_event_device *, unsigned int);
42#endif
43#ifdef CONFIG_CSRC_MN10300
44extern void clocksource_set_clock(struct clocksource *, unsigned int);
45#endif
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 80f15725ecad..2f66a45dcd18 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -16,14 +16,6 @@
16#include <asm/setup.h> 16#include <asm/setup.h>
17#include <asm/serial-regs.h> 17#include <asm/serial-regs.h>
18 18
19#ifdef CONFIG_SMP
20#undef GxICR
21#define GxICR(X) CROSS_GxICR(X, irq_affinity_online[X])
22
23#undef GxICR_u8
24#define GxICR_u8(X) CROSS_GxICR_u8(X, irq_affinity_online[X])
25#endif /* CONFIG_SMP */
26
27unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = { 19unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = {
28 [0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7 20 [0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7
29}; 21};
@@ -92,9 +84,11 @@ static void mn10300_cpupic_mask_ack(unsigned int irq)
92 GxICR(irq) = (tmp & GxICR_LEVEL); 84 GxICR(irq) = (tmp & GxICR_LEVEL);
93 tmp2 = GxICR(irq); 85 tmp2 = GxICR(irq);
94 86
95 irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); 87 irq_affinity_online[irq] =
96 GxICR(irq) = (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT; 88 any_online_cpu(*irq_desc[irq].affinity);
97 tmp = GxICR(irq); 89 CROSS_GxICR(irq, irq_affinity_online[irq]) =
90 (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
91 tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
98 } 92 }
99 93
100 arch_local_irq_restore(flags); 94 arch_local_irq_restore(flags);
@@ -128,8 +122,8 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq)
128 tmp = GxICR(irq); 122 tmp = GxICR(irq);
129 123
130 irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); 124 irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity);
131 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; 125 CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
132 tmp = GxICR(irq); 126 tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
133 } 127 }
134 128
135 arch_local_irq_restore(flags); 129 arch_local_irq_restore(flags);
@@ -217,7 +211,7 @@ static struct irq_chip mn10300_cpu_pic_level = {
217 .unmask = mn10300_cpupic_unmask_clear, 211 .unmask = mn10300_cpupic_unmask_clear,
218#ifdef CONFIG_SMP 212#ifdef CONFIG_SMP
219 .set_affinity = mn10300_cpupic_setaffinity, 213 .set_affinity = mn10300_cpupic_setaffinity,
220#endif /* CONFIG_SMP */ 214#endif
221}; 215};
222 216
223/* 217/*
@@ -235,7 +229,7 @@ static struct irq_chip mn10300_cpu_pic_edge = {
235 .unmask = mn10300_cpupic_unmask, 229 .unmask = mn10300_cpupic_unmask,
236#ifdef CONFIG_SMP 230#ifdef CONFIG_SMP
237 .set_affinity = mn10300_cpupic_setaffinity, 231 .set_affinity = mn10300_cpupic_setaffinity,
238#endif /* CONFIG_SMP */ 232#endif
239}; 233};
240 234
241/* 235/*
@@ -446,9 +440,9 @@ void migrate_irqs(void)
446 if (irq_affinity_online[irq] == self) { 440 if (irq_affinity_online[irq] == self) {
447 u16 x, tmp; 441 u16 x, tmp;
448 442
449 x = CROSS_GxICR(irq, self); 443 x = GxICR(irq);
450 CROSS_GxICR(irq, self) = x & GxICR_LEVEL; 444 GxICR(irq) = x & GxICR_LEVEL;
451 tmp = CROSS_GxICR(irq, self); 445 tmp = GxICR(irq);
452 446
453 new = any_online_cpu(irq_desc[irq].affinity); 447 new = any_online_cpu(irq_desc[irq].affinity);
454 irq_affinity_online[irq] = new; 448 irq_affinity_online[irq] = new;
@@ -458,7 +452,7 @@ void migrate_irqs(void)
458 tmp = CROSS_GxICR(irq, new); 452 tmp = CROSS_GxICR(irq, new);
459 453
460 x &= GxICR_LEVEL | GxICR_ENABLE; 454 x &= GxICR_LEVEL | GxICR_ENABLE;
461 if (CROSS_GxICR(irq, self) & GxICR_REQUEST) 455 if (GxICR(irq) & GxICR_REQUEST) {
462 x |= GxICR_REQUEST | GxICR_DETECT; 456 x |= GxICR_REQUEST | GxICR_DETECT;
463 CROSS_GxICR(irq, new) = x; 457 CROSS_GxICR(irq, new) = x;
464 tmp = CROSS_GxICR(irq, new); 458 tmp = CROSS_GxICR(irq, new);
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index b80234c28e0d..0dcd1c686ba8 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -126,7 +126,6 @@ static struct irq_chip mn10300_ipi_type = {
126 126
127static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id); 127static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id);
128static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id); 128static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id);
129static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
130 129
131static struct irqaction reschedule_ipi = { 130static struct irqaction reschedule_ipi = {
132 .handler = smp_reschedule_interrupt, 131 .handler = smp_reschedule_interrupt,
@@ -136,11 +135,15 @@ static struct irqaction call_function_ipi = {
136 .handler = smp_call_function_interrupt, 135 .handler = smp_call_function_interrupt,
137 .name = "smp call function IPI" 136 .name = "smp call function IPI"
138}; 137};
138
139#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
140static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
139static struct irqaction local_timer_ipi = { 141static struct irqaction local_timer_ipi = {
140 .handler = smp_ipi_timer_interrupt, 142 .handler = smp_ipi_timer_interrupt,
141 .flags = IRQF_DISABLED, 143 .flags = IRQF_DISABLED,
142 .name = "smp local timer IPI" 144 .name = "smp local timer IPI"
143}; 145};
146#endif
144 147
145/** 148/**
146 * init_ipi - Initialise the IPI mechanism 149 * init_ipi - Initialise the IPI mechanism
@@ -165,11 +168,14 @@ static void init_ipi(void)
165 mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI); 168 mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI);
166 169
167 /* set up the local timer IPI */ 170 /* set up the local timer IPI */
171#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
172 defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
168 set_irq_chip_and_handler(LOCAL_TIMER_IPI, 173 set_irq_chip_and_handler(LOCAL_TIMER_IPI,
169 &mn10300_ipi_type, handle_percpu_irq); 174 &mn10300_ipi_type, handle_percpu_irq);
170 setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi); 175 setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi);
171 set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV); 176 set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV);
172 mn10300_ipi_enable(LOCAL_TIMER_IPI); 177 mn10300_ipi_enable(LOCAL_TIMER_IPI);
178#endif
173 179
174#ifdef CONFIG_MN10300_CACHE_ENABLED 180#ifdef CONFIG_MN10300_CACHE_ENABLED
175 /* set up the cache flush IPI */ 181 /* set up the cache flush IPI */
@@ -505,6 +511,8 @@ void smp_nmi_call_function_interrupt(void)
505 } 511 }
506} 512}
507 513
514#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
515 defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
508/** 516/**
509 * smp_ipi_timer_interrupt - Local timer IPI handler 517 * smp_ipi_timer_interrupt - Local timer IPI handler
510 * @irq: The interrupt number. 518 * @irq: The interrupt number.
@@ -516,6 +524,7 @@ static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id)
516{ 524{
517 return local_timer_interrupt(); 525 return local_timer_interrupt();
518} 526}
527#endif
519 528
520void __init smp_init_cpus(void) 529void __init smp_init_cpus(void)
521{ 530{
@@ -620,7 +629,6 @@ void smp_prepare_cpu_init(void)
620int __init start_secondary(void *unused) 629int __init start_secondary(void *unused)
621{ 630{
622 smp_cpu_init(); 631 smp_cpu_init();
623
624 smp_callin(); 632 smp_callin();
625 while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) 633 while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
626 cpu_relax(); 634 cpu_relax();
@@ -629,6 +637,9 @@ int __init start_secondary(void *unused)
629 preempt_disable(); 637 preempt_disable();
630 smp_online(); 638 smp_online();
631 639
640#ifdef CONFIG_GENERIC_CLOCKEVENTS
641 init_clockevents();
642#endif
632 cpu_idle(); 643 cpu_idle();
633 return 0; 644 return 0;
634} 645}
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
index 0cb9bdb3b6bd..f860a340acc9 100644
--- a/arch/mn10300/kernel/time.c
+++ b/arch/mn10300/kernel/time.c
@@ -17,6 +17,8 @@
17#include <linux/smp.h> 17#include <linux/smp.h>
18#include <linux/profile.h> 18#include <linux/profile.h>
19#include <linux/cnt32_to_63.h> 19#include <linux/cnt32_to_63.h>
20#include <linux/clocksource.h>
21#include <linux/clockchips.h>
20#include <asm/irq.h> 22#include <asm/irq.h>
21#include <asm/div64.h> 23#include <asm/div64.h>
22#include <asm/processor.h> 24#include <asm/processor.h>
@@ -27,14 +29,6 @@
27static unsigned long mn10300_last_tsc; /* time-stamp counter at last time 29static unsigned long mn10300_last_tsc; /* time-stamp counter at last time
28 * interrupt occurred */ 30 * interrupt occurred */
29 31
30static irqreturn_t timer_interrupt(int irq, void *dev_id);
31
32static struct irqaction timer_irq = {
33 .handler = timer_interrupt,
34 .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
35 .name = "timer",
36};
37
38static unsigned long sched_clock_multiplier; 32static unsigned long sched_clock_multiplier;
39 33
40/* 34/*
@@ -54,7 +48,7 @@ unsigned long long sched_clock(void)
54 48
55 /* read the TSC value 49 /* read the TSC value
56 */ 50 */
57 tsc = 0 - get_cycles(); /* get_cycles() counts down */ 51 tsc = get_cycles();
58 52
59 /* expand to 64-bits. 53 /* expand to 64-bits.
60 * - sched_clock() must be called once a minute or better or the 54 * - sched_clock() must be called once a minute or better or the
@@ -103,6 +97,7 @@ irqreturn_t local_timer_interrupt(void)
103 return IRQ_HANDLED; 97 return IRQ_HANDLED;
104} 98}
105 99
100#ifndef CONFIG_GENERIC_TIME
106/* 101/*
107 * advance the kernel's time keeping clocks (xtime and jiffies) 102 * advance the kernel's time keeping clocks (xtime and jiffies)
108 * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time 103 * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time
@@ -116,11 +111,11 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
116 write_seqlock(&xtime_lock); 111 write_seqlock(&xtime_lock);
117 112
118 while (tsc = get_cycles(), 113 while (tsc = get_cycles(),
119 elapse = mn10300_last_tsc - tsc, /* time elapsed since last 114 elapse = tsc - mn10300_last_tsc, /* time elapsed since last
120 * tick */ 115 * tick */
121 elapse > MN10300_TSC_PER_HZ 116 elapse > MN10300_TSC_PER_HZ
122 ) { 117 ) {
123 mn10300_last_tsc -= MN10300_TSC_PER_HZ; 118 mn10300_last_tsc += MN10300_TSC_PER_HZ;
124 119
125 /* advance the kernel's time tracking system */ 120 /* advance the kernel's time tracking system */
126 do_timer(1); 121 do_timer(1);
@@ -135,6 +130,50 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
135 return ret; 130 return ret;
136} 131}
137 132
133static struct irqaction timer_irq = {
134 .handler = timer_interrupt,
135 .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
136 .name = "timer",
137};
138#endif /* CONFIG_GENERIC_TIME */
139
140#ifdef CONFIG_CSRC_MN10300
141void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
142{
143 u64 temp;
144 u32 shift;
145
146 /* Find a shift value */
147 for (shift = 32; shift > 0; shift--) {
148 temp = (u64) NSEC_PER_SEC << shift;
149 do_div(temp, clock);
150 if ((temp >> 32) == 0)
151 break;
152 }
153 cs->shift = shift;
154 cs->mult = (u32) temp;
155}
156#endif
157
158#if CONFIG_CEVT_MN10300
159void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
160 unsigned int clock)
161{
162 u64 temp;
163 u32 shift;
164
165 /* Find a shift value */
166 for (shift = 32; shift > 0; shift--) {
167 temp = (u64) clock << shift;
168 do_div(temp, NSEC_PER_SEC);
169 if ((temp >> 32) == 0)
170 break;
171 }
172 cd->shift = shift;
173 cd->mult = (u32) temp;
174}
175#endif
176
138/* 177/*
139 * initialise the various timers used by the main part of the kernel 178 * initialise the various timers used by the main part of the kernel
140 */ 179 */
@@ -146,21 +185,25 @@ void __init time_init(void)
146 */ 185 */
147 TMPSCNT |= TMPSCNT_ENABLE; 186 TMPSCNT |= TMPSCNT_ENABLE;
148 187
188#ifdef CONFIG_GENERIC_TIME
189 init_clocksource();
190#else
149 startup_timestamp_counter(); 191 startup_timestamp_counter();
192#endif
150 193
151 printk(KERN_INFO 194 printk(KERN_INFO
152 "timestamp counter I/O clock running at %lu.%02lu" 195 "timestamp counter I/O clock running at %lu.%02lu"
153 " (calibrated against RTC)\n", 196 " (calibrated against RTC)\n",
154 MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100); 197 MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100);
155 198
156 mn10300_last_tsc = TMTSCBC; 199 mn10300_last_tsc = read_timestamp_counter();
157 200
158 /* use timer 0 & 1 cascaded to tick at as close to HZ as possible */ 201#ifdef CONFIG_GENERIC_CLOCKEVENTS
159 setup_irq(TMJCIRQ, &timer_irq); 202 init_clockevents();
160 203#else
161 set_intr_level(TMJCIRQ, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL)); 204 reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
162 205 setup_jiffies_interrupt(TMJCIRQ, &timer_irq, CONFIG_TIMER_IRQ_LEVEL);
163 startup_jiffies_counter(); 206#endif
164 207
165#ifdef CONFIG_MN10300_WD_TIMER 208#ifdef CONFIG_MN10300_WD_TIMER
166 /* start the watchdog timer */ 209 /* start the watchdog timer */
diff --git a/arch/mn10300/unit-asb2303/include/unit/timex.h b/arch/mn10300/unit-asb2303/include/unit/timex.h
index d1b8dafe7d7d..cc18fe7d8b90 100644
--- a/arch/mn10300/unit-asb2303/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2303/include/unit/timex.h
@@ -1,6 +1,6 @@
1/* ASB2303-specific timer specifications 1/* ASB2303-specific timer specifications
2 * 2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -24,10 +24,6 @@
24 */ 24 */
25 25
26#define TMJCBR_MAX 0xffff 26#define TMJCBR_MAX 0xffff
27#define TMJCBC TM01BC
28
29#define TMJCMD TM01MD
30#define TMJCBR TM01BR
31#define TMJCIRQ TM1IRQ 27#define TMJCIRQ TM1IRQ
32#define TMJCICR TM1ICR 28#define TMJCICR TM1ICR
33 29
@@ -61,34 +57,32 @@
61#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ) 57#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ)
62#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ) 58#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ)
63 59
64static inline void startup_jiffies_counter(void) 60static inline void stop_jiffies_counter(void)
65{ 61{
66 u16 md, t16; 62 u16 tmp;
63 TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
64 tmp = TM01MD;
65}
67 66
68 md = JC_TIMER_CLKSRC; 67static inline void reload_jiffies_counter(u32 cnt)
69 TMJCBR = MN10300_JC_PER_HZ - 1; 68{
70 t16 = TMJCBR; 69 u32 tmp;
71 70
72 TMJCMD = 71 TM01BR = cnt;
73 md | 72 tmp = TM01BR;
74 TM1MD_SRC_TM0CASCADE << 8 |
75 TM0MD_INIT_COUNTER |
76 TM1MD_INIT_COUNTER << 8;
77 73
78 TMJCMD = 74 TM01MD = JC_TIMER_CLKSRC | \
79 md | 75 TM1MD_SRC_TM0CASCADE << 8 | \
80 TM1MD_SRC_TM0CASCADE << 8 | 76 TM0MD_INIT_COUNTER | \
81 TM0MD_COUNT_ENABLE | 77 TM1MD_INIT_COUNTER << 8;
82 TM1MD_COUNT_ENABLE << 8;
83 78
84 t16 = TMJCMD;
85 79
86 TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; 80 TM01MD = JC_TIMER_CLKSRC | \
87 t16 = TMJCICR; 81 TM1MD_SRC_TM0CASCADE << 8 | \
88} 82 TM0MD_COUNT_ENABLE | \
83 TM1MD_COUNT_ENABLE << 8;
89 84
90static inline void shutdown_jiffies_counter(void) 85 tmp = TM01MD;
91{
92} 86}
93 87
94#endif /* !__ASSEMBLY__ */ 88#endif /* !__ASSEMBLY__ */
@@ -148,7 +142,7 @@ typedef unsigned long cycles_t;
148 142
149static inline cycles_t read_timestamp_counter(void) 143static inline cycles_t read_timestamp_counter(void)
150{ 144{
151 return (cycles_t)TMTSCBC; 145 return (cycles_t)~TMTSCBC;
152} 146}
153 147
154#endif /* !__ASSEMBLY__ */ 148#endif /* !__ASSEMBLY__ */
diff --git a/arch/mn10300/unit-asb2305/include/unit/timex.h b/arch/mn10300/unit-asb2305/include/unit/timex.h
index cd8bc14e3ca3..758af30d1a16 100644
--- a/arch/mn10300/unit-asb2305/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2305/include/unit/timex.h
@@ -1,6 +1,6 @@
1/* ASB2305-specific timer specifications 1/* ASB2305-specific timer specifications
2 * 2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -24,10 +24,6 @@
24 */ 24 */
25 25
26#define TMJCBR_MAX 0xffff 26#define TMJCBR_MAX 0xffff
27#define TMJCBC TM01BC
28
29#define TMJCMD TM01MD
30#define TMJCBR TM01BR
31#define TMJCIRQ TM1IRQ 27#define TMJCIRQ TM1IRQ
32#define TMJCICR TM1ICR 28#define TMJCICR TM1ICR
33 29
@@ -61,34 +57,32 @@
61#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ) 57#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ)
62#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ) 58#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ)
63 59
64static inline void startup_jiffies_counter(void) 60static inline void stop_jiffies_counter(void)
65{ 61{
66 u16 md, t16; 62 u16 tmp;
63 TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
64 tmp = TM01MD;
65}
67 66
68 md = JC_TIMER_CLKSRC; 67static inline void reload_jiffies_counter(u32 cnt)
69 TMJCBR = MN10300_JC_PER_HZ - 1; 68{
70 t16 = TMJCBR; 69 u32 tmp;
71 70
72 TMJCMD = 71 TM01BR = cnt;
73 md | 72 tmp = TM01BR;
74 TM1MD_SRC_TM0CASCADE << 8 |
75 TM0MD_INIT_COUNTER |
76 TM1MD_INIT_COUNTER << 8;
77 73
78 TMJCMD = 74 TM01MD = JC_TIMER_CLKSRC | \
79 md | 75 TM1MD_SRC_TM0CASCADE << 8 | \
80 TM1MD_SRC_TM0CASCADE << 8 | 76 TM0MD_INIT_COUNTER | \
81 TM0MD_COUNT_ENABLE | 77 TM1MD_INIT_COUNTER << 8;
82 TM1MD_COUNT_ENABLE << 8;
83 78
84 t16 = TMJCMD;
85 79
86 TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; 80 TM01MD = JC_TIMER_CLKSRC | \
87 t16 = TMJCICR; 81 TM1MD_SRC_TM0CASCADE << 8 | \
88} 82 TM0MD_COUNT_ENABLE | \
83 TM1MD_COUNT_ENABLE << 8;
89 84
90static inline void shutdown_jiffies_counter(void) 85 tmp = TM01MD;
91{
92} 86}
93 87
94#endif /* !__ASSEMBLY__ */ 88#endif /* !__ASSEMBLY__ */
@@ -148,7 +142,7 @@ typedef unsigned long cycles_t;
148 142
149static inline cycles_t read_timestamp_counter(void) 143static inline cycles_t read_timestamp_counter(void)
150{ 144{
151 return (cycles_t)TMTSCBC; 145 return (cycles_t)~TMTSCBC;
152} 146}
153 147
154#endif /* !__ASSEMBLY__ */ 148#endif /* !__ASSEMBLY__ */
diff --git a/arch/mn10300/unit-asb2364/include/unit/timex.h b/arch/mn10300/unit-asb2364/include/unit/timex.h
index b5223f705ef8..ddb7ed010706 100644
--- a/arch/mn10300/unit-asb2364/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2364/include/unit/timex.h
@@ -1,6 +1,6 @@
1/* timex.h: MN2WS0038 architecture timer specifications 1/* timex.h: MN2WS0038 architecture timer specifications
2 * 2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2002, 2010 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -24,12 +24,7 @@
24 */ 24 */
25 25
26#define TMJCBR_MAX 0xffffff /* 24bit */ 26#define TMJCBR_MAX 0xffffff /* 24bit */
27#define TMJCBC TMTBC
28
29#define TMJCMD TMTMD
30#define TMJCBR TMTBR
31#define TMJCIRQ TMTIRQ 27#define TMJCIRQ TMTIRQ
32#define TMJCICR TMTICR
33 28
34#ifndef __ASSEMBLY__ 29#ifndef __ASSEMBLY__
35 30
@@ -50,25 +45,63 @@
50# error MTM tick timer interval value is overflow. 45# error MTM tick timer interval value is overflow.
51#endif 46#endif
52 47
48static inline void stop_jiffies_counter(void)
49{
50 u16 tmp;
51 TMTMD = 0;
52 tmp = TMTMD;
53}
53 54
54static inline void startup_jiffies_counter(void) 55static inline void reload_jiffies_counter(u32 cnt)
55{ 56{
56 u32 sync; 57 u32 tmp;
58
59 TMTBR = cnt;
60 tmp = TMTBR;
57 61
58 TMJCBR = MN10300_JC_PER_HZ - 1; 62 TMTMD = TMTMD_TMTLDE;
59 sync = TMJCBR; 63 TMTMD = TMTMD_TMTCNE;
64 tmp = TMTMD;
65}
60 66
61 TMJCMD = TMTMD_TMTLDE; 67#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS) && \
62 TMJCMD = TMTMD_TMTCNE; 68 !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
63 sync = TMJCMD; 69/*
70 * If we aren't using broadcasting, each core needs its own event timer.
71 * Since CPU0 uses the tick timer which is 24-bits, we use timer 4 & 5
72 * cascaded to 32-bits for CPU1 (but only really use 24-bits to match
73 * CPU0).
74 */
64 75
65 TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; 76#define TMJC1IRQ TM5IRQ
66 sync = TMJCICR; 77
78static inline void stop_jiffies_counter1(void)
79{
80 u8 tmp;
81 TM4MD = 0;
82 TM5MD = 0;
83 tmp = TM4MD;
84 tmp = TM5MD;
67} 85}
68 86
69static inline void shutdown_jiffies_counter(void) 87static inline void reload_jiffies_counter1(u32 cnt)
70{ 88{
89 u32 tmp;
90
91 TM45BR = cnt;
92 tmp = TM45BR;
93
94 TM4MD = TM4MD_INIT_COUNTER;
95 tmp = TM4MD;
96
97 TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_INIT_COUNTER;
98 TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_COUNT_ENABLE;
99 tmp = TM5MD;
100
101 TM4MD = TM4MD_COUNT_ENABLE;
102 tmp = TM4MD;
71} 103}
104#endif /* CONFIG_SMP&GENERIC_CLOCKEVENTS&!GENERIC_CLOCKEVENTS_BROADCAST */
72 105
73#endif /* !__ASSEMBLY__ */ 106#endif /* !__ASSEMBLY__ */
74 107
@@ -76,15 +109,16 @@ static inline void shutdown_jiffies_counter(void)
76/* 109/*
77 * timestamp counter specifications 110 * timestamp counter specifications
78 */ 111 */
79
80#define TMTSCBR_MAX 0xffffffff 112#define TMTSCBR_MAX 0xffffffff
113
114#ifndef __ASSEMBLY__
115
116/* Use 32-bit timestamp counter */
81#define TMTSCMD TMSMD 117#define TMTSCMD TMSMD
82#define TMTSCBR TMSBR 118#define TMTSCBR TMSBR
83#define TMTSCBC TMSBC 119#define TMTSCBC TMSBC
84#define TMTSCICR TMSICR 120#define TMTSCICR TMSICR
85 121
86#ifndef __ASSEMBLY__
87
88static inline void startup_timestamp_counter(void) 122static inline void startup_timestamp_counter(void)
89{ 123{
90 u32 sync; 124 u32 sync;
@@ -117,7 +151,7 @@ typedef unsigned long cycles_t;
117 151
118static inline cycles_t read_timestamp_counter(void) 152static inline cycles_t read_timestamp_counter(void)
119{ 153{
120 return (cycles_t)TMTSCBC; 154 return (cycles_t)~TMTSCBC;
121} 155}
122 156
123#endif /* !__ASSEMBLY__ */ 157#endif /* !__ASSEMBLY__ */