diff options
author | Olof Johansson <olof@lixom.net> | 2013-04-17 13:10:01 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-04-17 13:10:01 -0400 |
commit | c3e0c873d0653e6e7628b5a8a9fcb3745444ca9e (patch) | |
tree | dd7448d5515c56604cd8e57f3d6399f5640d57a3 | |
parent | 228e3023eb0430b4b9ed0736f8f87c96a6cd9c7a (diff) | |
parent | 69a517b2471bcd1c5a175aad82647c1e2c24f08b (diff) |
Merge tag 'clksrc-cleanup-for-3.10-part2' of git://sources.calxeda.com/kernel/linux into late/clksrc
This is the 2nd part of ARM timer clean-ups for 3.10. This series has
the following changes:
- Add sched_clock selection logic to select the highest frequency clock
- Use full 64-bit arch timer counter for sched_clock
- Convert arch timer, sp804 and integrator-cp timers to CLKSRC_OF and
adapt all users to use clocksource_of_init
* tag 'clksrc-cleanup-for-3.10-part2' of git://sources.calxeda.com/kernel/linux:
devtree: add binding documentation for sp804
ARM: integrator-cp: convert use CLKSRC_OF for timer init
ARM: versatile: use OF init for sp804 timer
ARM: versatile: add versatile dtbs to dtbs target
ARM: vexpress: remove extra timer-sp control register clearing
ARM: dts: vexpress: disable CA9 core tile sp804 timer
ARM: vexpress: remove sp804 OF init
ARM: highbank: use OF init for sp804 timer
ARM: timer-sp: convert to use CLKSRC_OF init
OF: add empty of_device_is_available for !OF
ARM: convert arm/arm64 arch timer to use CLKSRC_OF init
ARM: make machine_desc->init_time default to clocksource_of_init
ARM: arch_timer: use full 64-bit counter for sched_clock
ARM: make sched_clock just call a function pointer
ARM: sched_clock: allow changing to higher frequency counter
Signed-off-by: Olof Johansson <olof@lixom.net>
This has a nasty set of conflicts with the exynos MCT code, which was
moved in a separate branch, and then fixed up when merged in, but still
conflicts a bit here. It should have been sorted out by this merge though.
34 files changed, 262 insertions, 191 deletions
diff --git a/Documentation/devicetree/bindings/timer/arm,sp804.txt b/Documentation/devicetree/bindings/timer/arm,sp804.txt new file mode 100644 index 000000000000..5cd8eee74af1 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/arm,sp804.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | ARM sp804 Dual Timers | ||
2 | --------------------------------------- | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: Should be "arm,sp804" & "arm,primecell" | ||
6 | - interrupts: Should contain the list of Dual Timer interrupts. This is the | ||
7 | interrupt for timer 1 and timer 2. In the case of a single entry, it is | ||
8 | the combined interrupt or if "arm,sp804-has-irq" is present that | ||
9 | specifies which timer interrupt is connected. | ||
10 | - reg: Should contain location and length for dual timer register. | ||
11 | - clocks: clocks driving the dual timer hardware. This list should be 1 or 3 | ||
12 | clocks. With 3 clocks, the order is timer0 clock, timer1 clock, | ||
13 | apb_pclk. A single clock can also be specified if the same clock is | ||
14 | used for all clock inputs. | ||
15 | |||
16 | Optional properties: | ||
17 | - arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this | ||
18 | specifies if the irq connection is for timer 1 or timer 2. A value of 1 | ||
19 | or 2 should be used. | ||
20 | |||
21 | Example: | ||
22 | |||
23 | timer0: timer@fc800000 { | ||
24 | compatible = "arm,sp804", "arm,primecell"; | ||
25 | reg = <0xfc800000 0x1000>; | ||
26 | interrupts = <0 0 4>, <0 1 4>; | ||
27 | clocks = <&timclk1 &timclk2 &pclk>; | ||
28 | clock-names = "timer1", "timer2", "apb_pclk"; | ||
29 | }; | ||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 03301cb114ac..1571a4150439 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1180,6 +1180,7 @@ config PLAT_VERSATILE | |||
1180 | config ARM_TIMER_SP804 | 1180 | config ARM_TIMER_SP804 |
1181 | bool | 1181 | bool |
1182 | select CLKSRC_MMIO | 1182 | select CLKSRC_MMIO |
1183 | select CLKSRC_OF if OF | ||
1183 | select HAVE_SCHED_CLOCK | 1184 | select HAVE_SCHED_CLOCK |
1184 | 1185 | ||
1185 | source arch/arm/mm/Kconfig | 1186 | source arch/arm/mm/Kconfig |
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 9c6255884cbb..08d298db0090 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile | |||
@@ -165,6 +165,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ | |||
165 | tegra30-cardhu-a04.dtb \ | 165 | tegra30-cardhu-a04.dtb \ |
166 | tegra114-dalmore.dtb \ | 166 | tegra114-dalmore.dtb \ |
167 | tegra114-pluto.dtb | 167 | tegra114-pluto.dtb |
168 | dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \ | ||
169 | versatile-pb.dtb | ||
168 | dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ | 170 | dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ |
169 | vexpress-v2p-ca9.dtb \ | 171 | vexpress-v2p-ca9.dtb \ |
170 | vexpress-v2p-ca15-tc1.dtb \ | 172 | vexpress-v2p-ca15-tc1.dtb \ |
diff --git a/arch/arm/boot/dts/integratorcp.dts b/arch/arm/boot/dts/integratorcp.dts index 8b119399025a..ff1aea0ee043 100644 --- a/arch/arm/boot/dts/integratorcp.dts +++ b/arch/arm/boot/dts/integratorcp.dts | |||
@@ -24,15 +24,15 @@ | |||
24 | }; | 24 | }; |
25 | 25 | ||
26 | timer0: timer@13000000 { | 26 | timer0: timer@13000000 { |
27 | compatible = "arm,sp804", "arm,primecell"; | 27 | compatible = "arm,integrator-cp-timer"; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | timer1: timer@13000100 { | 30 | timer1: timer@13000100 { |
31 | compatible = "arm,sp804", "arm,primecell"; | 31 | compatible = "arm,integrator-cp-timer"; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | timer2: timer@13000200 { | 34 | timer2: timer@13000200 { |
35 | compatible = "arm,sp804", "arm,primecell"; | 35 | compatible = "arm,integrator-cp-timer"; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | pic: pic@14000000 { | 38 | pic: pic@14000000 { |
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts index e2fe3195c0d1..dde75ae8b4b1 100644 --- a/arch/arm/boot/dts/versatile-ab.dts +++ b/arch/arm/boot/dts/versatile-ab.dts | |||
@@ -121,6 +121,18 @@ | |||
121 | interrupts = <0>; | 121 | interrupts = <0>; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | timer@101e2000 { | ||
125 | compatible = "arm,sp804", "arm,primecell"; | ||
126 | reg = <0x101e2000 0x1000>; | ||
127 | interrupts = <4>; | ||
128 | }; | ||
129 | |||
130 | timer@101e3000 { | ||
131 | compatible = "arm,sp804", "arm,primecell"; | ||
132 | reg = <0x101e3000 0x1000>; | ||
133 | interrupts = <5>; | ||
134 | }; | ||
135 | |||
124 | gpio0: gpio@101e4000 { | 136 | gpio0: gpio@101e4000 { |
125 | compatible = "arm,pl061", "arm,primecell"; | 137 | compatible = "arm,pl061", "arm,primecell"; |
126 | reg = <0x101e4000 0x1000>; | 138 | reg = <0x101e4000 0x1000>; |
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts index 1420bb14d95c..62d9b225dcce 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts | |||
@@ -98,6 +98,7 @@ | |||
98 | <0 49 4>; | 98 | <0 49 4>; |
99 | clocks = <&oscclk2>, <&oscclk2>; | 99 | clocks = <&oscclk2>, <&oscclk2>; |
100 | clock-names = "timclk", "apb_pclk"; | 100 | clock-names = "timclk", "apb_pclk"; |
101 | status = "disabled"; | ||
101 | }; | 102 | }; |
102 | 103 | ||
103 | watchdog@100e5000 { | 104 | watchdog@100e5000 { |
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 9d2d3ba339ff..ddc740769601 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c | |||
@@ -25,33 +25,29 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/irq.h> | 26 | #include <linux/irq.h> |
27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/of.h> | ||
29 | #include <linux/of_address.h> | ||
30 | #include <linux/of_irq.h> | ||
28 | 31 | ||
29 | #include <asm/sched_clock.h> | 32 | #include <asm/sched_clock.h> |
30 | #include <asm/hardware/arm_timer.h> | 33 | #include <asm/hardware/arm_timer.h> |
34 | #include <asm/hardware/timer-sp.h> | ||
31 | 35 | ||
32 | static long __init sp804_get_clock_rate(const char *name) | 36 | static long __init sp804_get_clock_rate(struct clk *clk) |
33 | { | 37 | { |
34 | struct clk *clk; | ||
35 | long rate; | 38 | long rate; |
36 | int err; | 39 | int err; |
37 | 40 | ||
38 | clk = clk_get_sys("sp804", name); | ||
39 | if (IS_ERR(clk)) { | ||
40 | pr_err("sp804: %s clock not found: %d\n", name, | ||
41 | (int)PTR_ERR(clk)); | ||
42 | return PTR_ERR(clk); | ||
43 | } | ||
44 | |||
45 | err = clk_prepare(clk); | 41 | err = clk_prepare(clk); |
46 | if (err) { | 42 | if (err) { |
47 | pr_err("sp804: %s clock failed to prepare: %d\n", name, err); | 43 | pr_err("sp804: clock failed to prepare: %d\n", err); |
48 | clk_put(clk); | 44 | clk_put(clk); |
49 | return err; | 45 | return err; |
50 | } | 46 | } |
51 | 47 | ||
52 | err = clk_enable(clk); | 48 | err = clk_enable(clk); |
53 | if (err) { | 49 | if (err) { |
54 | pr_err("sp804: %s clock failed to enable: %d\n", name, err); | 50 | pr_err("sp804: clock failed to enable: %d\n", err); |
55 | clk_unprepare(clk); | 51 | clk_unprepare(clk); |
56 | clk_put(clk); | 52 | clk_put(clk); |
57 | return err; | 53 | return err; |
@@ -59,7 +55,7 @@ static long __init sp804_get_clock_rate(const char *name) | |||
59 | 55 | ||
60 | rate = clk_get_rate(clk); | 56 | rate = clk_get_rate(clk); |
61 | if (rate < 0) { | 57 | if (rate < 0) { |
62 | pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); | 58 | pr_err("sp804: clock failed to get rate: %ld\n", rate); |
63 | clk_disable(clk); | 59 | clk_disable(clk); |
64 | clk_unprepare(clk); | 60 | clk_unprepare(clk); |
65 | clk_put(clk); | 61 | clk_put(clk); |
@@ -77,9 +73,21 @@ static u32 sp804_read(void) | |||
77 | 73 | ||
78 | void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, | 74 | void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, |
79 | const char *name, | 75 | const char *name, |
76 | struct clk *clk, | ||
80 | int use_sched_clock) | 77 | int use_sched_clock) |
81 | { | 78 | { |
82 | long rate = sp804_get_clock_rate(name); | 79 | long rate; |
80 | |||
81 | if (!clk) { | ||
82 | clk = clk_get_sys("sp804", name); | ||
83 | if (IS_ERR(clk)) { | ||
84 | pr_err("sp804: clock not found: %d\n", | ||
85 | (int)PTR_ERR(clk)); | ||
86 | return; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | rate = sp804_get_clock_rate(clk); | ||
83 | 91 | ||
84 | if (rate < 0) | 92 | if (rate < 0) |
85 | return; | 93 | return; |
@@ -171,12 +179,20 @@ static struct irqaction sp804_timer_irq = { | |||
171 | .dev_id = &sp804_clockevent, | 179 | .dev_id = &sp804_clockevent, |
172 | }; | 180 | }; |
173 | 181 | ||
174 | void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, | 182 | void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) |
175 | const char *name) | ||
176 | { | 183 | { |
177 | struct clock_event_device *evt = &sp804_clockevent; | 184 | struct clock_event_device *evt = &sp804_clockevent; |
178 | long rate = sp804_get_clock_rate(name); | 185 | long rate; |
179 | 186 | ||
187 | if (!clk) | ||
188 | clk = clk_get_sys("sp804", name); | ||
189 | if (IS_ERR(clk)) { | ||
190 | pr_err("sp804: %s clock not found: %d\n", name, | ||
191 | (int)PTR_ERR(clk)); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | rate = sp804_get_clock_rate(clk); | ||
180 | if (rate < 0) | 196 | if (rate < 0) |
181 | return; | 197 | return; |
182 | 198 | ||
@@ -186,6 +202,98 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, | |||
186 | evt->irq = irq; | 202 | evt->irq = irq; |
187 | evt->cpumask = cpu_possible_mask; | 203 | evt->cpumask = cpu_possible_mask; |
188 | 204 | ||
205 | writel(0, base + TIMER_CTRL); | ||
206 | |||
189 | setup_irq(irq, &sp804_timer_irq); | 207 | setup_irq(irq, &sp804_timer_irq); |
190 | clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); | 208 | clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); |
191 | } | 209 | } |
210 | |||
211 | static void __init sp804_of_init(struct device_node *np) | ||
212 | { | ||
213 | static bool initialized = false; | ||
214 | void __iomem *base; | ||
215 | int irq; | ||
216 | u32 irq_num = 0; | ||
217 | struct clk *clk1, *clk2; | ||
218 | const char *name = of_get_property(np, "compatible", NULL); | ||
219 | |||
220 | base = of_iomap(np, 0); | ||
221 | if (WARN_ON(!base)) | ||
222 | return; | ||
223 | |||
224 | /* Ensure timers are disabled */ | ||
225 | writel(0, base + TIMER_CTRL); | ||
226 | writel(0, base + TIMER_2_BASE + TIMER_CTRL); | ||
227 | |||
228 | if (initialized || !of_device_is_available(np)) | ||
229 | goto err; | ||
230 | |||
231 | clk1 = of_clk_get(np, 0); | ||
232 | if (IS_ERR(clk1)) | ||
233 | clk1 = NULL; | ||
234 | |||
235 | /* Get the 2nd clock if the timer has 2 timer clocks */ | ||
236 | if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) { | ||
237 | clk2 = of_clk_get(np, 1); | ||
238 | if (IS_ERR(clk2)) { | ||
239 | pr_err("sp804: %s clock not found: %d\n", np->name, | ||
240 | (int)PTR_ERR(clk2)); | ||
241 | goto err; | ||
242 | } | ||
243 | } else | ||
244 | clk2 = clk1; | ||
245 | |||
246 | irq = irq_of_parse_and_map(np, 0); | ||
247 | if (irq <= 0) | ||
248 | goto err; | ||
249 | |||
250 | of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); | ||
251 | if (irq_num == 2) { | ||
252 | __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); | ||
253 | __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); | ||
254 | } else { | ||
255 | __sp804_clockevents_init(base, irq, clk1 , name); | ||
256 | __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, | ||
257 | name, clk2, 1); | ||
258 | } | ||
259 | initialized = true; | ||
260 | |||
261 | return; | ||
262 | err: | ||
263 | iounmap(base); | ||
264 | } | ||
265 | CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); | ||
266 | |||
267 | static void __init integrator_cp_of_init(struct device_node *np) | ||
268 | { | ||
269 | static int init_count = 0; | ||
270 | void __iomem *base; | ||
271 | int irq; | ||
272 | const char *name = of_get_property(np, "compatible", NULL); | ||
273 | |||
274 | base = of_iomap(np, 0); | ||
275 | if (WARN_ON(!base)) | ||
276 | return; | ||
277 | |||
278 | /* Ensure timer is disabled */ | ||
279 | writel(0, base + TIMER_CTRL); | ||
280 | |||
281 | if (init_count == 2 || !of_device_is_available(np)) | ||
282 | goto err; | ||
283 | |||
284 | if (!init_count) | ||
285 | sp804_clocksource_init(base, name); | ||
286 | else { | ||
287 | irq = irq_of_parse_and_map(np, 0); | ||
288 | if (irq <= 0) | ||
289 | goto err; | ||
290 | |||
291 | sp804_clockevents_init(base, irq, name); | ||
292 | } | ||
293 | |||
294 | init_count++; | ||
295 | return; | ||
296 | err: | ||
297 | iounmap(base); | ||
298 | } | ||
299 | CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); | ||
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 7ade91d8cc6f..7c1bfc0aea0c 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h | |||
@@ -10,8 +10,7 @@ | |||
10 | #include <clocksource/arm_arch_timer.h> | 10 | #include <clocksource/arm_arch_timer.h> |
11 | 11 | ||
12 | #ifdef CONFIG_ARM_ARCH_TIMER | 12 | #ifdef CONFIG_ARM_ARCH_TIMER |
13 | int arch_timer_of_register(void); | 13 | int arch_timer_arch_init(void); |
14 | int arch_timer_sched_clock_init(void); | ||
15 | 14 | ||
16 | /* | 15 | /* |
17 | * These register accessors are marked inline so the compiler can | 16 | * These register accessors are marked inline so the compiler can |
@@ -110,16 +109,6 @@ static inline void __cpuinit arch_counter_set_user_access(void) | |||
110 | 109 | ||
111 | asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); | 110 | asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); |
112 | } | 111 | } |
113 | #else | ||
114 | static inline int arch_timer_of_register(void) | ||
115 | { | ||
116 | return -ENXIO; | ||
117 | } | ||
118 | |||
119 | static inline int arch_timer_sched_clock_init(void) | ||
120 | { | ||
121 | return -ENXIO; | ||
122 | } | ||
123 | #endif | 112 | #endif |
124 | 113 | ||
125 | #endif | 114 | #endif |
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h index 2dd9d3f83f29..bb28af7c32de 100644 --- a/arch/arm/include/asm/hardware/timer-sp.h +++ b/arch/arm/include/asm/hardware/timer-sp.h | |||
@@ -1,15 +1,23 @@ | |||
1 | struct clk; | ||
2 | |||
1 | void __sp804_clocksource_and_sched_clock_init(void __iomem *, | 3 | void __sp804_clocksource_and_sched_clock_init(void __iomem *, |
2 | const char *, int); | 4 | const char *, struct clk *, int); |
5 | void __sp804_clockevents_init(void __iomem *, unsigned int, | ||
6 | struct clk *, const char *); | ||
3 | 7 | ||
4 | static inline void sp804_clocksource_init(void __iomem *base, const char *name) | 8 | static inline void sp804_clocksource_init(void __iomem *base, const char *name) |
5 | { | 9 | { |
6 | __sp804_clocksource_and_sched_clock_init(base, name, 0); | 10 | __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0); |
7 | } | 11 | } |
8 | 12 | ||
9 | static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, | 13 | static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, |
10 | const char *name) | 14 | const char *name) |
11 | { | 15 | { |
12 | __sp804_clocksource_and_sched_clock_init(base, name, 1); | 16 | __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1); |
13 | } | 17 | } |
14 | 18 | ||
15 | void sp804_clockevents_init(void __iomem *, unsigned int, const char *); | 19 | static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name) |
20 | { | ||
21 | __sp804_clockevents_init(base, irq, NULL, name); | ||
22 | |||
23 | } | ||
diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h index e3f757263438..3d520ddca61b 100644 --- a/arch/arm/include/asm/sched_clock.h +++ b/arch/arm/include/asm/sched_clock.h | |||
@@ -11,4 +11,6 @@ | |||
11 | extern void sched_clock_postinit(void); | 11 | extern void sched_clock_postinit(void); |
12 | extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); | 12 | extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); |
13 | 13 | ||
14 | extern unsigned long long (*sched_clock_func)(void); | ||
15 | |||
14 | #endif | 16 | #endif |
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index d957a51435d8..59dcdced6e30 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c | |||
@@ -22,9 +22,11 @@ static unsigned long arch_timer_read_counter_long(void) | |||
22 | return arch_timer_read_counter(); | 22 | return arch_timer_read_counter(); |
23 | } | 23 | } |
24 | 24 | ||
25 | static u32 arch_timer_read_counter_u32(void) | 25 | static u32 sched_clock_mult __read_mostly; |
26 | |||
27 | static unsigned long long notrace arch_timer_sched_clock(void) | ||
26 | { | 28 | { |
27 | return arch_timer_read_counter(); | 29 | return arch_timer_read_counter() * sched_clock_mult; |
28 | } | 30 | } |
29 | 31 | ||
30 | static struct delay_timer arch_delay_timer; | 32 | static struct delay_timer arch_delay_timer; |
@@ -37,25 +39,20 @@ static void __init arch_timer_delay_timer_register(void) | |||
37 | register_current_timer_delay(&arch_delay_timer); | 39 | register_current_timer_delay(&arch_delay_timer); |
38 | } | 40 | } |
39 | 41 | ||
40 | int __init arch_timer_of_register(void) | 42 | int __init arch_timer_arch_init(void) |
41 | { | 43 | { |
42 | int ret; | 44 | u32 arch_timer_rate = arch_timer_get_rate(); |
43 | 45 | ||
44 | ret = arch_timer_init(); | 46 | if (arch_timer_rate == 0) |
45 | if (ret) | 47 | return -ENXIO; |
46 | return ret; | ||
47 | 48 | ||
48 | arch_timer_delay_timer_register(); | 49 | arch_timer_delay_timer_register(); |
49 | 50 | ||
50 | return 0; | 51 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ |
51 | } | 52 | sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; |
52 | 53 | sched_clock_func = arch_timer_sched_clock; | |
53 | int __init arch_timer_sched_clock_init(void) | 54 | pr_info("sched_clock: ARM arch timer >56 bits at %ukHz, resolution %uns\n", |
54 | { | 55 | arch_timer_rate / 1000, sched_clock_mult); |
55 | if (arch_timer_get_rate() == 0) | ||
56 | return -ENXIO; | ||
57 | 56 | ||
58 | setup_sched_clock(arch_timer_read_counter_u32, | ||
59 | 32, arch_timer_get_rate()); | ||
60 | return 0; | 57 | return 0; |
61 | } | 58 | } |
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index bd6f56b9ec21..880584852fca 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c | |||
@@ -20,6 +20,7 @@ struct clock_data { | |||
20 | u64 epoch_ns; | 20 | u64 epoch_ns; |
21 | u32 epoch_cyc; | 21 | u32 epoch_cyc; |
22 | u32 epoch_cyc_copy; | 22 | u32 epoch_cyc_copy; |
23 | unsigned long rate; | ||
23 | u32 mult; | 24 | u32 mult; |
24 | u32 shift; | 25 | u32 shift; |
25 | bool suspended; | 26 | bool suspended; |
@@ -113,11 +114,14 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) | |||
113 | u64 res, wrap; | 114 | u64 res, wrap; |
114 | char r_unit; | 115 | char r_unit; |
115 | 116 | ||
117 | if (cd.rate > rate) | ||
118 | return; | ||
119 | |||
116 | BUG_ON(bits > 32); | 120 | BUG_ON(bits > 32); |
117 | WARN_ON(!irqs_disabled()); | 121 | WARN_ON(!irqs_disabled()); |
118 | WARN_ON(read_sched_clock != jiffy_sched_clock_read); | ||
119 | read_sched_clock = read; | 122 | read_sched_clock = read; |
120 | sched_clock_mask = (1 << bits) - 1; | 123 | sched_clock_mask = (1 << bits) - 1; |
124 | cd.rate = rate; | ||
121 | 125 | ||
122 | /* calculate the mult/shift to convert counter ticks to ns. */ | 126 | /* calculate the mult/shift to convert counter ticks to ns. */ |
123 | clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0); | 127 | clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0); |
@@ -161,12 +165,19 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) | |||
161 | pr_debug("Registered %pF as sched_clock source\n", read); | 165 | pr_debug("Registered %pF as sched_clock source\n", read); |
162 | } | 166 | } |
163 | 167 | ||
164 | unsigned long long notrace sched_clock(void) | 168 | static unsigned long long notrace sched_clock_32(void) |
165 | { | 169 | { |
166 | u32 cyc = read_sched_clock(); | 170 | u32 cyc = read_sched_clock(); |
167 | return cyc_to_sched_clock(cyc, sched_clock_mask); | 171 | return cyc_to_sched_clock(cyc, sched_clock_mask); |
168 | } | 172 | } |
169 | 173 | ||
174 | unsigned long long __read_mostly (*sched_clock_func)(void) = sched_clock_32; | ||
175 | |||
176 | unsigned long long notrace sched_clock(void) | ||
177 | { | ||
178 | return sched_clock_func(); | ||
179 | } | ||
180 | |||
170 | void __init sched_clock_postinit(void) | 181 | void __init sched_clock_postinit(void) |
171 | { | 182 | { |
172 | /* | 183 | /* |
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 955d92d265e5..abff4e9aaee0 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/profile.h> | 23 | #include <linux/profile.h> |
24 | #include <linux/timer.h> | 24 | #include <linux/timer.h> |
25 | #include <linux/clocksource.h> | ||
25 | #include <linux/irq.h> | 26 | #include <linux/irq.h> |
26 | 27 | ||
27 | #include <asm/thread_info.h> | 28 | #include <asm/thread_info.h> |
@@ -115,6 +116,10 @@ int __init register_persistent_clock(clock_access_fn read_boot, | |||
115 | 116 | ||
116 | void __init time_init(void) | 117 | void __init time_init(void) |
117 | { | 118 | { |
118 | machine_desc->init_time(); | 119 | if (machine_desc->init_time) |
120 | machine_desc->init_time(); | ||
121 | else | ||
122 | clocksource_of_init(); | ||
123 | |||
119 | sched_clock_postinit(); | 124 | sched_clock_postinit(); |
120 | } | 125 | } |
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 7da4791bfb8b..be7eaac0df01 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c | |||
@@ -217,7 +217,6 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") | |||
217 | .map_io = exynos5_dt_map_io, | 217 | .map_io = exynos5_dt_map_io, |
218 | .init_machine = exynos5_dt_machine_init, | 218 | .init_machine = exynos5_dt_machine_init, |
219 | .init_late = exynos_init_late, | 219 | .init_late = exynos_init_late, |
220 | .init_time = clocksource_of_init, | ||
221 | .dt_compat = exynos5_dt_compat, | 220 | .dt_compat = exynos5_dt_compat, |
222 | .restart = exynos5_restart, | 221 | .restart = exynos5_restart, |
223 | .reserve = exynos5_reserve, | 222 | .reserve = exynos5_reserve, |
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 76c1170b3528..e7df2dd43a40 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c | |||
@@ -15,6 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/clkdev.h> | 17 | #include <linux/clkdev.h> |
18 | #include <linux/clocksource.h> | ||
18 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
19 | #include <linux/io.h> | 20 | #include <linux/io.h> |
20 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
@@ -28,12 +29,9 @@ | |||
28 | #include <linux/amba/bus.h> | 29 | #include <linux/amba/bus.h> |
29 | #include <linux/clk-provider.h> | 30 | #include <linux/clk-provider.h> |
30 | 31 | ||
31 | #include <asm/arch_timer.h> | ||
32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
33 | #include <asm/cputype.h> | 33 | #include <asm/cputype.h> |
34 | #include <asm/smp_plat.h> | 34 | #include <asm/smp_plat.h> |
35 | #include <asm/hardware/arm_timer.h> | ||
36 | #include <asm/hardware/timer-sp.h> | ||
37 | #include <asm/hardware/cache-l2x0.h> | 35 | #include <asm/hardware/cache-l2x0.h> |
38 | #include <asm/mach/arch.h> | 36 | #include <asm/mach/arch.h> |
39 | #include <asm/mach/map.h> | 37 | #include <asm/mach/map.h> |
@@ -90,36 +88,16 @@ static void __init highbank_init_irq(void) | |||
90 | #endif | 88 | #endif |
91 | } | 89 | } |
92 | 90 | ||
93 | static struct clk_lookup lookup = { | ||
94 | .dev_id = "sp804", | ||
95 | .con_id = NULL, | ||
96 | }; | ||
97 | |||
98 | static void __init highbank_timer_init(void) | 91 | static void __init highbank_timer_init(void) |
99 | { | 92 | { |
100 | int irq; | ||
101 | struct device_node *np; | 93 | struct device_node *np; |
102 | void __iomem *timer_base; | ||
103 | 94 | ||
104 | /* Map system registers */ | 95 | /* Map system registers */ |
105 | np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); | 96 | np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); |
106 | sregs_base = of_iomap(np, 0); | 97 | sregs_base = of_iomap(np, 0); |
107 | WARN_ON(!sregs_base); | 98 | WARN_ON(!sregs_base); |
108 | 99 | ||
109 | np = of_find_compatible_node(NULL, NULL, "arm,sp804"); | ||
110 | timer_base = of_iomap(np, 0); | ||
111 | WARN_ON(!timer_base); | ||
112 | irq = irq_of_parse_and_map(np, 0); | ||
113 | |||
114 | of_clk_init(NULL); | 100 | of_clk_init(NULL); |
115 | lookup.clk = of_clk_get(np, 0); | ||
116 | clkdev_add(&lookup); | ||
117 | |||
118 | sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); | ||
119 | sp804_clockevents_init(timer_base, irq, "timer0"); | ||
120 | |||
121 | arch_timer_of_register(); | ||
122 | arch_timer_sched_clock_init(); | ||
123 | 101 | ||
124 | clocksource_of_init(); | 102 | clocksource_of_init(); |
125 | } | 103 | } |
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index da1091be0887..8c60fcb08a98 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
@@ -250,39 +250,6 @@ static void __init intcp_init_early(void) | |||
250 | } | 250 | } |
251 | 251 | ||
252 | #ifdef CONFIG_OF | 252 | #ifdef CONFIG_OF |
253 | |||
254 | static void __init cp_of_timer_init(void) | ||
255 | { | ||
256 | struct device_node *node; | ||
257 | const char *path; | ||
258 | void __iomem *base; | ||
259 | int err; | ||
260 | int irq; | ||
261 | |||
262 | err = of_property_read_string(of_aliases, | ||
263 | "arm,timer-primary", &path); | ||
264 | if (WARN_ON(err)) | ||
265 | return; | ||
266 | node = of_find_node_by_path(path); | ||
267 | base = of_iomap(node, 0); | ||
268 | if (WARN_ON(!base)) | ||
269 | return; | ||
270 | writel(0, base + TIMER_CTRL); | ||
271 | sp804_clocksource_init(base, node->name); | ||
272 | |||
273 | err = of_property_read_string(of_aliases, | ||
274 | "arm,timer-secondary", &path); | ||
275 | if (WARN_ON(err)) | ||
276 | return; | ||
277 | node = of_find_node_by_path(path); | ||
278 | base = of_iomap(node, 0); | ||
279 | if (WARN_ON(!base)) | ||
280 | return; | ||
281 | irq = irq_of_parse_and_map(node, 0); | ||
282 | writel(0, base + TIMER_CTRL); | ||
283 | sp804_clockevents_init(base, irq, node->name); | ||
284 | } | ||
285 | |||
286 | static const struct of_device_id fpga_irq_of_match[] __initconst = { | 253 | static const struct of_device_id fpga_irq_of_match[] __initconst = { |
287 | { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, | 254 | { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, |
288 | { /* Sentinel */ } | 255 | { /* Sentinel */ } |
@@ -383,7 +350,6 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") | |||
383 | .init_early = intcp_init_early, | 350 | .init_early = intcp_init_early, |
384 | .init_irq = intcp_init_irq_of, | 351 | .init_irq = intcp_init_irq_of, |
385 | .handle_irq = fpga_handle_irq, | 352 | .handle_irq = fpga_handle_irq, |
386 | .init_time = cp_of_timer_init, | ||
387 | .init_machine = intcp_init_of, | 353 | .init_machine = intcp_init_of, |
388 | .restart = integrator_restart, | 354 | .restart = integrator_restart, |
389 | .dt_compat = intcp_dt_board_compat, | 355 | .dt_compat = intcp_dt_board_compat, |
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index f12aa6c15da4..d5a13dcb64b8 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <asm/smp_twd.h> | 46 | #include <asm/smp_twd.h> |
47 | #include <asm/sched_clock.h> | 47 | #include <asm/sched_clock.h> |
48 | 48 | ||
49 | #include <asm/arch_timer.h> | ||
50 | #include "omap_hwmod.h" | 49 | #include "omap_hwmod.h" |
51 | #include "omap_device.h" | 50 | #include "omap_device.h" |
52 | #include <plat/counter-32k.h> | 51 | #include <plat/counter-32k.h> |
@@ -627,9 +626,7 @@ void __init omap5_realtime_timer_init(void) | |||
627 | omap4_sync32k_timer_init(); | 626 | omap4_sync32k_timer_init(); |
628 | realtime_counter_init(); | 627 | realtime_counter_init(); |
629 | 628 | ||
630 | err = arch_timer_of_register(); | 629 | clocksource_of_init(); |
631 | if (err) | ||
632 | pr_err("%s: arch_timer_register failed %d\n", __func__, err); | ||
633 | } | 630 | } |
634 | #endif /* CONFIG_SOC_OMAP5 */ | 631 | #endif /* CONFIG_SOC_OMAP5 */ |
635 | 632 | ||
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c index c254782aa727..c016ccd92433 100644 --- a/arch/arm/mach-shmobile/board-kzm9d.c +++ b/arch/arm/mach-shmobile/board-kzm9d.c | |||
@@ -90,6 +90,5 @@ DT_MACHINE_START(KZM9D_DT, "kzm9d") | |||
90 | .init_irq = emev2_init_irq, | 90 | .init_irq = emev2_init_irq, |
91 | .init_machine = kzm9d_add_standard_devices, | 91 | .init_machine = kzm9d_add_standard_devices, |
92 | .init_late = shmobile_init_late, | 92 | .init_late = shmobile_init_late, |
93 | .init_time = shmobile_timer_init, | ||
94 | .dt_compat = kzm9d_boards_compat_dt, | 93 | .dt_compat = kzm9d_boards_compat_dt, |
95 | MACHINE_END | 94 | MACHINE_END |
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index e4545c152722..899a86c31ec9 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c | |||
@@ -456,7 +456,6 @@ DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") | |||
456 | .nr_irqs = NR_IRQS_LEGACY, | 456 | .nr_irqs = NR_IRQS_LEGACY, |
457 | .init_irq = irqchip_init, | 457 | .init_irq = irqchip_init, |
458 | .init_machine = emev2_add_standard_devices_dt, | 458 | .init_machine = emev2_add_standard_devices_dt, |
459 | .init_time = shmobile_timer_init, | ||
460 | .dt_compat = emev2_boards_compat_dt, | 459 | .dt_compat = emev2_boards_compat_dt, |
461 | MACHINE_END | 460 | MACHINE_END |
462 | 461 | ||
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8b85d4d8fab6..104b474a2ccf 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c | |||
@@ -906,7 +906,6 @@ DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)") | |||
906 | .init_irq = r8a7740_init_irq, | 906 | .init_irq = r8a7740_init_irq, |
907 | .handle_irq = shmobile_handle_irq_intc, | 907 | .handle_irq = shmobile_handle_irq_intc, |
908 | .init_machine = r8a7740_add_standard_devices_dt, | 908 | .init_machine = r8a7740_add_standard_devices_dt, |
909 | .init_time = shmobile_timer_init, | ||
910 | .dt_compat = r8a7740_boards_compat_dt, | 909 | .dt_compat = r8a7740_boards_compat_dt, |
911 | MACHINE_END | 910 | MACHINE_END |
912 | 911 | ||
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 59c7146bf66f..5502d624aca6 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c | |||
@@ -1175,7 +1175,6 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") | |||
1175 | .init_irq = sh7372_init_irq, | 1175 | .init_irq = sh7372_init_irq, |
1176 | .handle_irq = shmobile_handle_irq_intc, | 1176 | .handle_irq = shmobile_handle_irq_intc, |
1177 | .init_machine = sh7372_add_standard_devices_dt, | 1177 | .init_machine = sh7372_add_standard_devices_dt, |
1178 | .init_time = shmobile_timer_init, | ||
1179 | .dt_compat = sh7372_boards_compat_dt, | 1178 | .dt_compat = sh7372_boards_compat_dt, |
1180 | MACHINE_END | 1179 | MACHINE_END |
1181 | 1180 | ||
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index e8cd93a5c550..fdf3894b1cc3 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c | |||
@@ -1037,7 +1037,6 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") | |||
1037 | .nr_irqs = NR_IRQS_LEGACY, | 1037 | .nr_irqs = NR_IRQS_LEGACY, |
1038 | .init_irq = irqchip_init, | 1038 | .init_irq = irqchip_init, |
1039 | .init_machine = sh73a0_add_standard_devices_dt, | 1039 | .init_machine = sh73a0_add_standard_devices_dt, |
1040 | .init_time = shmobile_timer_init, | ||
1041 | .dt_compat = sh73a0_boards_compat_dt, | 1040 | .dt_compat = sh73a0_boards_compat_dt, |
1042 | MACHINE_END | 1041 | MACHINE_END |
1043 | #endif /* CONFIG_USE_OF */ | 1042 | #endif /* CONFIG_USE_OF */ |
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 3d16d4dff01b..f321dbeb2379 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c | |||
@@ -19,10 +19,8 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/clocksource.h> | ||
22 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
23 | #include <asm/arch_timer.h> | ||
24 | #include <asm/mach/time.h> | ||
25 | #include <asm/smp_twd.h> | ||
26 | 24 | ||
27 | void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, | 25 | void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, |
28 | unsigned int mult, unsigned int div) | 26 | unsigned int mult, unsigned int div) |
@@ -63,6 +61,5 @@ void __init shmobile_earlytimer_init(void) | |||
63 | 61 | ||
64 | void __init shmobile_timer_init(void) | 62 | void __init shmobile_timer_init(void) |
65 | { | 63 | { |
66 | arch_timer_of_register(); | 64 | clocksource_of_init(); |
67 | arch_timer_sched_clock_init(); | ||
68 | } | 65 | } |
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 25160aeaa3b7..54bb80b012ac 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -749,12 +749,25 @@ void versatile_restart(char mode, const char *cmd) | |||
749 | /* Early initializations */ | 749 | /* Early initializations */ |
750 | void __init versatile_init_early(void) | 750 | void __init versatile_init_early(void) |
751 | { | 751 | { |
752 | u32 val; | ||
752 | void __iomem *sys = __io_address(VERSATILE_SYS_BASE); | 753 | void __iomem *sys = __io_address(VERSATILE_SYS_BASE); |
753 | 754 | ||
754 | osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET; | 755 | osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET; |
755 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | 756 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); |
756 | 757 | ||
757 | versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000); | 758 | versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000); |
759 | |||
760 | /* | ||
761 | * set clock frequency: | ||
762 | * VERSATILE_REFCLK is 32KHz | ||
763 | * VERSATILE_TIMCLK is 1MHz | ||
764 | */ | ||
765 | val = readl(__io_address(VERSATILE_SCTL_BASE)); | ||
766 | writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | | ||
767 | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | | ||
768 | (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | | ||
769 | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, | ||
770 | __io_address(VERSATILE_SCTL_BASE)); | ||
758 | } | 771 | } |
759 | 772 | ||
760 | void __init versatile_init(void) | 773 | void __init versatile_init(void) |
@@ -785,19 +798,6 @@ void __init versatile_init(void) | |||
785 | */ | 798 | */ |
786 | void __init versatile_timer_init(void) | 799 | void __init versatile_timer_init(void) |
787 | { | 800 | { |
788 | u32 val; | ||
789 | |||
790 | /* | ||
791 | * set clock frequency: | ||
792 | * VERSATILE_REFCLK is 32KHz | ||
793 | * VERSATILE_TIMCLK is 1MHz | ||
794 | */ | ||
795 | val = readl(__io_address(VERSATILE_SCTL_BASE)); | ||
796 | writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | | ||
797 | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | | ||
798 | (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | | ||
799 | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, | ||
800 | __io_address(VERSATILE_SCTL_BASE)); | ||
801 | 801 | ||
802 | /* | 802 | /* |
803 | * Initialise to a known state (all timers off) | 803 | * Initialise to a known state (all timers off) |
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c index 2558f2e957c3..3621b000a0f6 100644 --- a/arch/arm/mach-versatile/versatile_dt.c +++ b/arch/arm/mach-versatile/versatile_dt.c | |||
@@ -45,7 +45,6 @@ DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)") | |||
45 | .map_io = versatile_map_io, | 45 | .map_io = versatile_map_io, |
46 | .init_early = versatile_init_early, | 46 | .init_early = versatile_init_early, |
47 | .init_irq = versatile_init_irq, | 47 | .init_irq = versatile_init_irq, |
48 | .init_time = versatile_timer_init, | ||
49 | .init_machine = versatile_dt_init, | 48 | .init_machine = versatile_dt_init, |
50 | .dt_compat = versatile_dt_match, | 49 | .dt_compat = versatile_dt_match, |
51 | .restart = versatile_restart, | 50 | .restart = versatile_restart, |
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index d0ad78998cb6..09e571ddc984 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Versatile Express V2M Motherboard Support | 2 | * Versatile Express V2M Motherboard Support |
3 | */ | 3 | */ |
4 | #include <linux/clocksource.h> | ||
4 | #include <linux/device.h> | 5 | #include <linux/device.h> |
5 | #include <linux/amba/bus.h> | 6 | #include <linux/amba/bus.h> |
6 | #include <linux/amba/mmci.h> | 7 | #include <linux/amba/mmci.h> |
@@ -23,7 +24,6 @@ | |||
23 | #include <linux/regulator/machine.h> | 24 | #include <linux/regulator/machine.h> |
24 | #include <linux/vexpress.h> | 25 | #include <linux/vexpress.h> |
25 | 26 | ||
26 | #include <asm/arch_timer.h> | ||
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | #include <asm/sizes.h> | 28 | #include <asm/sizes.h> |
29 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
@@ -61,9 +61,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq) | |||
61 | if (WARN_ON(!base || irq == NO_IRQ)) | 61 | if (WARN_ON(!base || irq == NO_IRQ)) |
62 | return; | 62 | return; |
63 | 63 | ||
64 | writel(0, base + TIMER_1_BASE + TIMER_CTRL); | ||
65 | writel(0, base + TIMER_2_BASE + TIMER_CTRL); | ||
66 | |||
67 | sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1"); | 64 | sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1"); |
68 | sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0"); | 65 | sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0"); |
69 | } | 66 | } |
@@ -431,25 +428,11 @@ void __init v2m_dt_init_early(void) | |||
431 | 428 | ||
432 | static void __init v2m_dt_timer_init(void) | 429 | static void __init v2m_dt_timer_init(void) |
433 | { | 430 | { |
434 | struct device_node *node = NULL; | ||
435 | |||
436 | vexpress_clk_of_init(); | 431 | vexpress_clk_of_init(); |
437 | 432 | ||
438 | clocksource_of_init(); | 433 | clocksource_of_init(); |
439 | do { | ||
440 | node = of_find_compatible_node(node, NULL, "arm,sp804"); | ||
441 | } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB); | ||
442 | if (node) { | ||
443 | pr_info("Using SP804 '%s' as a clock & events source\n", | ||
444 | node->full_name); | ||
445 | v2m_sp804_init(of_iomap(node, 0), | ||
446 | irq_of_parse_and_map(node, 0)); | ||
447 | } | ||
448 | |||
449 | arch_timer_of_register(); | ||
450 | 434 | ||
451 | if (arch_timer_sched_clock_init() != 0) | 435 | versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), |
452 | versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), | ||
453 | 24000000); | 436 | 24000000); |
454 | } | 437 | } |
455 | 438 | ||
diff --git a/arch/arm/mach-virt/virt.c b/arch/arm/mach-virt/virt.c index 31666f6b4373..adc0945255ae 100644 --- a/arch/arm/mach-virt/virt.c +++ b/arch/arm/mach-virt/virt.c | |||
@@ -23,21 +23,13 @@ | |||
23 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
24 | #include <linux/smp.h> | 24 | #include <linux/smp.h> |
25 | 25 | ||
26 | #include <asm/arch_timer.h> | ||
27 | #include <asm/mach/arch.h> | 26 | #include <asm/mach/arch.h> |
28 | #include <asm/mach/time.h> | ||
29 | 27 | ||
30 | static void __init virt_init(void) | 28 | static void __init virt_init(void) |
31 | { | 29 | { |
32 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 30 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
33 | } | 31 | } |
34 | 32 | ||
35 | static void __init virt_timer_init(void) | ||
36 | { | ||
37 | WARN_ON(arch_timer_of_register() != 0); | ||
38 | WARN_ON(arch_timer_sched_clock_init() != 0); | ||
39 | } | ||
40 | |||
41 | static const char *virt_dt_match[] = { | 33 | static const char *virt_dt_match[] = { |
42 | "linux,dummy-virt", | 34 | "linux,dummy-virt", |
43 | NULL | 35 | NULL |
@@ -47,7 +39,6 @@ extern struct smp_operations virt_smp_ops; | |||
47 | 39 | ||
48 | DT_MACHINE_START(VIRT, "Dummy Virtual Machine") | 40 | DT_MACHINE_START(VIRT, "Dummy Virtual Machine") |
49 | .init_irq = irqchip_init, | 41 | .init_irq = irqchip_init, |
50 | .init_time = virt_timer_init, | ||
51 | .init_machine = virt_init, | 42 | .init_machine = virt_init, |
52 | .smp = smp_ops(virt_smp_ops), | 43 | .smp = smp_ops(virt_smp_ops), |
53 | .dt_compat = virt_dt_match, | 44 | .dt_compat = virt_dt_match, |
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 91e2a6a6fcd4..bf6ab242f047 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h | |||
@@ -130,4 +130,9 @@ static inline u64 arch_counter_get_cntvct(void) | |||
130 | return cval; | 130 | return cval; |
131 | } | 131 | } |
132 | 132 | ||
133 | static inline int arch_timer_arch_init(void) | ||
134 | { | ||
135 | return 0; | ||
136 | } | ||
137 | |||
133 | #endif | 138 | #endif |
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index b0ef18d14c3b..a551f88ae2c1 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/timer.h> | 32 | #include <linux/timer.h> |
33 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/clocksource.h> | ||
35 | 36 | ||
36 | #include <clocksource/arm_arch_timer.h> | 37 | #include <clocksource/arm_arch_timer.h> |
37 | 38 | ||
@@ -77,10 +78,11 @@ void __init time_init(void) | |||
77 | { | 78 | { |
78 | u32 arch_timer_rate; | 79 | u32 arch_timer_rate; |
79 | 80 | ||
80 | if (arch_timer_init()) | 81 | clocksource_of_init(); |
81 | panic("Unable to initialise architected timer.\n"); | ||
82 | 82 | ||
83 | arch_timer_rate = arch_timer_get_rate(); | 83 | arch_timer_rate = arch_timer_get_rate(); |
84 | if (!arch_timer_rate) | ||
85 | panic("Unable to initialise architected timer.\n"); | ||
84 | 86 | ||
85 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ | 87 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ |
86 | sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; | 88 | sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 73fcddb8314d..29ba35e6a143 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -65,6 +65,7 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | |||
65 | 65 | ||
66 | config ARM_ARCH_TIMER | 66 | config ARM_ARCH_TIMER |
67 | bool | 67 | bool |
68 | select CLKSRC_OF if OF | ||
68 | 69 | ||
69 | config CLKSRC_METAG_GENERIC | 70 | config CLKSRC_METAG_GENERIC |
70 | def_bool y if METAG | 71 | def_bool y if METAG |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d7ad425ab9b3..122ff05628b5 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -337,22 +337,14 @@ out: | |||
337 | return err; | 337 | return err; |
338 | } | 338 | } |
339 | 339 | ||
340 | static const struct of_device_id arch_timer_of_match[] __initconst = { | 340 | static void __init arch_timer_init(struct device_node *np) |
341 | { .compatible = "arm,armv7-timer", }, | ||
342 | { .compatible = "arm,armv8-timer", }, | ||
343 | {}, | ||
344 | }; | ||
345 | |||
346 | int __init arch_timer_init(void) | ||
347 | { | 341 | { |
348 | struct device_node *np; | ||
349 | u32 freq; | 342 | u32 freq; |
350 | int i; | 343 | int i; |
351 | 344 | ||
352 | np = of_find_matching_node(NULL, arch_timer_of_match); | 345 | if (arch_timer_get_rate()) { |
353 | if (!np) { | 346 | pr_warn("arch_timer: multiple nodes in dt, skipping\n"); |
354 | pr_err("arch_timer: can't find DT node\n"); | 347 | return; |
355 | return -ENODEV; | ||
356 | } | 348 | } |
357 | 349 | ||
358 | /* Try to determine the frequency from the device tree or CNTFRQ */ | 350 | /* Try to determine the frequency from the device tree or CNTFRQ */ |
@@ -378,7 +370,7 @@ int __init arch_timer_init(void) | |||
378 | if (!arch_timer_ppi[PHYS_SECURE_PPI] || | 370 | if (!arch_timer_ppi[PHYS_SECURE_PPI] || |
379 | !arch_timer_ppi[PHYS_NONSECURE_PPI]) { | 371 | !arch_timer_ppi[PHYS_NONSECURE_PPI]) { |
380 | pr_warn("arch_timer: No interrupt available, giving up\n"); | 372 | pr_warn("arch_timer: No interrupt available, giving up\n"); |
381 | return -EINVAL; | 373 | return; |
382 | } | 374 | } |
383 | } | 375 | } |
384 | 376 | ||
@@ -387,5 +379,8 @@ int __init arch_timer_init(void) | |||
387 | else | 379 | else |
388 | arch_timer_read_counter = arch_counter_get_cntpct; | 380 | arch_timer_read_counter = arch_counter_get_cntpct; |
389 | 381 | ||
390 | return arch_timer_register(); | 382 | arch_timer_register(); |
383 | arch_timer_arch_init(); | ||
391 | } | 384 | } |
385 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); | ||
386 | CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); | ||
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 957af8636c9d..b078d7cbc930 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
25 | #include <linux/clocksource.h> | 25 | #include <linux/clocksource.h> |
26 | 26 | ||
27 | #include <asm/arch_timer.h> | ||
28 | #include <asm/localtimer.h> | 27 | #include <asm/localtimer.h> |
29 | 28 | ||
30 | #include <plat/cpu.h> | 29 | #include <plat/cpu.h> |
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 2603267b1a29..e6c9c4cc9b23 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h | |||
@@ -31,18 +31,12 @@ | |||
31 | 31 | ||
32 | #ifdef CONFIG_ARM_ARCH_TIMER | 32 | #ifdef CONFIG_ARM_ARCH_TIMER |
33 | 33 | ||
34 | extern int arch_timer_init(void); | ||
35 | extern u32 arch_timer_get_rate(void); | 34 | extern u32 arch_timer_get_rate(void); |
36 | extern u64 (*arch_timer_read_counter)(void); | 35 | extern u64 (*arch_timer_read_counter)(void); |
37 | extern struct timecounter *arch_timer_get_timecounter(void); | 36 | extern struct timecounter *arch_timer_get_timecounter(void); |
38 | 37 | ||
39 | #else | 38 | #else |
40 | 39 | ||
41 | static inline int arch_timer_init(void) | ||
42 | { | ||
43 | return -ENXIO; | ||
44 | } | ||
45 | |||
46 | static inline u32 arch_timer_get_rate(void) | 40 | static inline u32 arch_timer_get_rate(void) |
47 | { | 41 | { |
48 | return 0; | 42 | return 0; |
diff --git a/include/linux/of.h b/include/linux/of.h index c0747a44eaff..b0f3bbd0216b 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -382,6 +382,11 @@ static inline int of_device_is_compatible(const struct device_node *device, | |||
382 | return 0; | 382 | return 0; |
383 | } | 383 | } |
384 | 384 | ||
385 | static inline int of_device_is_available(const struct device_node *device) | ||
386 | { | ||
387 | return 0; | ||
388 | } | ||
389 | |||
385 | static inline struct property *of_find_property(const struct device_node *np, | 390 | static inline struct property *of_find_property(const struct device_node *np, |
386 | const char *name, | 391 | const char *name, |
387 | int *lenp) | 392 | int *lenp) |