diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-16 16:10:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-16 16:10:26 -0400 |
commit | a4ae54f90e0a7063799eb90852aa8648ccfbb791 (patch) | |
tree | 88fd7f7920c8849fed99c782ab1fc605da69a375 /drivers/clocksource/time-armada-370-xp.c | |
parent | 3369d116934b70bd2755cdd8b2af9741d18a4047 (diff) | |
parent | 63ce2cc474ce962d936ae6dfaa6ae2354b1db5b2 (diff) |
Merge branch 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer code update from Thomas Gleixner:
- armada SoC clocksource overhaul with a trivial merge conflict
- Minor improvements to various SoC clocksource drivers
* 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
clocksource: armada-370-xp: Add detailed clock requirements in devicetree binding
clocksource: armada-370-xp: Get reference fixed-clock by name
clocksource: armada-370-xp: Replace WARN_ON with BUG_ON
clocksource: armada-370-xp: Fix device-tree binding
clocksource: armada-370-xp: Introduce new compatibles
clocksource: armada-370-xp: Use CLOCKSOURCE_OF_DECLARE
clocksource: armada-370-xp: Simplify TIMER_CTRL register access
clocksource: armada-370-xp: Use BIT()
ARM: timer-sp: Set dynamic irq affinity
ARM: nomadik: add dynamic irq flag to the timer
clocksource: sh_cmt: 32-bit control register support
clocksource: em_sti: Convert to devm_* managed helpers
Diffstat (limited to 'drivers/clocksource/time-armada-370-xp.c')
-rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 131 |
1 files changed, 77 insertions, 54 deletions
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 847cab6f6e31..0198504ef6b0 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
@@ -13,6 +13,19 @@ | |||
13 | * | 13 | * |
14 | * Timer 0 is used as free-running clocksource, while timer 1 is | 14 | * Timer 0 is used as free-running clocksource, while timer 1 is |
15 | * used as clock_event_device. | 15 | * used as clock_event_device. |
16 | * | ||
17 | * --- | ||
18 | * Clocksource driver for Armada 370 and Armada XP SoC. | ||
19 | * This driver implements one compatible string for each SoC, given | ||
20 | * each has its own characteristics: | ||
21 | * | ||
22 | * * Armada 370 has no 25 MHz fixed timer. | ||
23 | * | ||
24 | * * Armada XP cannot work properly without such 25 MHz fixed timer as | ||
25 | * doing otherwise leads to using a clocksource whose frequency varies | ||
26 | * when doing cpufreq frequency changes. | ||
27 | * | ||
28 | * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | ||
16 | */ | 29 | */ |
17 | 30 | ||
18 | #include <linux/init.h> | 31 | #include <linux/init.h> |
@@ -30,19 +43,18 @@ | |||
30 | #include <linux/module.h> | 43 | #include <linux/module.h> |
31 | #include <linux/sched_clock.h> | 44 | #include <linux/sched_clock.h> |
32 | #include <linux/percpu.h> | 45 | #include <linux/percpu.h> |
33 | #include <linux/time-armada-370-xp.h> | ||
34 | 46 | ||
35 | /* | 47 | /* |
36 | * Timer block registers. | 48 | * Timer block registers. |
37 | */ | 49 | */ |
38 | #define TIMER_CTRL_OFF 0x0000 | 50 | #define TIMER_CTRL_OFF 0x0000 |
39 | #define TIMER0_EN 0x0001 | 51 | #define TIMER0_EN BIT(0) |
40 | #define TIMER0_RELOAD_EN 0x0002 | 52 | #define TIMER0_RELOAD_EN BIT(1) |
41 | #define TIMER0_25MHZ 0x0800 | 53 | #define TIMER0_25MHZ BIT(11) |
42 | #define TIMER0_DIV(div) ((div) << 19) | 54 | #define TIMER0_DIV(div) ((div) << 19) |
43 | #define TIMER1_EN 0x0004 | 55 | #define TIMER1_EN BIT(2) |
44 | #define TIMER1_RELOAD_EN 0x0008 | 56 | #define TIMER1_RELOAD_EN BIT(3) |
45 | #define TIMER1_25MHZ 0x1000 | 57 | #define TIMER1_25MHZ BIT(12) |
46 | #define TIMER1_DIV(div) ((div) << 22) | 58 | #define TIMER1_DIV(div) ((div) << 22) |
47 | #define TIMER_EVENTS_STATUS 0x0004 | 59 | #define TIMER_EVENTS_STATUS 0x0004 |
48 | #define TIMER0_CLR_MASK (~0x1) | 60 | #define TIMER0_CLR_MASK (~0x1) |
@@ -72,6 +84,18 @@ static u32 ticks_per_jiffy; | |||
72 | 84 | ||
73 | static struct clock_event_device __percpu *armada_370_xp_evt; | 85 | static struct clock_event_device __percpu *armada_370_xp_evt; |
74 | 86 | ||
87 | static void timer_ctrl_clrset(u32 clr, u32 set) | ||
88 | { | ||
89 | writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
90 | timer_base + TIMER_CTRL_OFF); | ||
91 | } | ||
92 | |||
93 | static void local_timer_ctrl_clrset(u32 clr, u32 set) | ||
94 | { | ||
95 | writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
96 | local_base + TIMER_CTRL_OFF); | ||
97 | } | ||
98 | |||
75 | static u32 notrace armada_370_xp_read_sched_clock(void) | 99 | static u32 notrace armada_370_xp_read_sched_clock(void) |
76 | { | 100 | { |
77 | return ~readl(timer_base + TIMER0_VAL_OFF); | 101 | return ~readl(timer_base + TIMER0_VAL_OFF); |
@@ -84,7 +108,6 @@ static int | |||
84 | armada_370_xp_clkevt_next_event(unsigned long delta, | 108 | armada_370_xp_clkevt_next_event(unsigned long delta, |
85 | struct clock_event_device *dev) | 109 | struct clock_event_device *dev) |
86 | { | 110 | { |
87 | u32 u; | ||
88 | /* | 111 | /* |
89 | * Clear clockevent timer interrupt. | 112 | * Clear clockevent timer interrupt. |
90 | */ | 113 | */ |
@@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, | |||
98 | /* | 121 | /* |
99 | * Enable the timer. | 122 | * Enable the timer. |
100 | */ | 123 | */ |
101 | u = readl(local_base + TIMER_CTRL_OFF); | 124 | local_timer_ctrl_clrset(TIMER0_RELOAD_EN, |
102 | u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | | 125 | TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); |
103 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | ||
104 | writel(u, local_base + TIMER_CTRL_OFF); | ||
105 | |||
106 | return 0; | 126 | return 0; |
107 | } | 127 | } |
108 | 128 | ||
@@ -110,8 +130,6 @@ static void | |||
110 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, | 130 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, |
111 | struct clock_event_device *dev) | 131 | struct clock_event_device *dev) |
112 | { | 132 | { |
113 | u32 u; | ||
114 | |||
115 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 133 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
116 | 134 | ||
117 | /* | 135 | /* |
@@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
123 | /* | 141 | /* |
124 | * Enable timer. | 142 | * Enable timer. |
125 | */ | 143 | */ |
126 | 144 | local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | | |
127 | u = readl(local_base + TIMER_CTRL_OFF); | 145 | TIMER0_EN | |
128 | 146 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
129 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
130 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), | ||
131 | local_base + TIMER_CTRL_OFF); | ||
132 | } else { | 147 | } else { |
133 | /* | 148 | /* |
134 | * Disable timer. | 149 | * Disable timer. |
135 | */ | 150 | */ |
136 | u = readl(local_base + TIMER_CTRL_OFF); | 151 | local_timer_ctrl_clrset(TIMER0_EN, 0); |
137 | writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); | ||
138 | 152 | ||
139 | /* | 153 | /* |
140 | * ACK pending timer interrupt. | 154 | * ACK pending timer interrupt. |
@@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | |||
163 | */ | 177 | */ |
164 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) | 178 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) |
165 | { | 179 | { |
166 | u32 u; | 180 | u32 clr = 0, set = 0; |
167 | int cpu = smp_processor_id(); | 181 | int cpu = smp_processor_id(); |
168 | 182 | ||
169 | u = readl(local_base + TIMER_CTRL_OFF); | ||
170 | if (timer25Mhz) | 183 | if (timer25Mhz) |
171 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 184 | set = TIMER0_25MHZ; |
172 | else | 185 | else |
173 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 186 | clr = TIMER0_25MHZ; |
187 | local_timer_ctrl_clrset(clr, set); | ||
174 | 188 | ||
175 | evt->name = "armada_370_xp_per_cpu_tick", | 189 | evt->name = "armada_370_xp_per_cpu_tick", |
176 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | 190 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
@@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { | |||
217 | .notifier_call = armada_370_xp_timer_cpu_notify, | 231 | .notifier_call = armada_370_xp_timer_cpu_notify, |
218 | }; | 232 | }; |
219 | 233 | ||
220 | void __init armada_370_xp_timer_init(void) | 234 | static void __init armada_370_xp_timer_common_init(struct device_node *np) |
221 | { | 235 | { |
222 | u32 u; | 236 | u32 clr = 0, set = 0; |
223 | struct device_node *np; | ||
224 | int res; | 237 | int res; |
225 | 238 | ||
226 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); | ||
227 | timer_base = of_iomap(np, 0); | 239 | timer_base = of_iomap(np, 0); |
228 | WARN_ON(!timer_base); | 240 | WARN_ON(!timer_base); |
229 | local_base = of_iomap(np, 1); | 241 | local_base = of_iomap(np, 1); |
230 | 242 | ||
231 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 243 | if (timer25Mhz) |
232 | /* The fixed 25MHz timer is available so let's use it */ | 244 | set = TIMER0_25MHZ; |
233 | u = readl(timer_base + TIMER_CTRL_OFF); | 245 | else |
234 | writel(u | TIMER0_25MHZ, | 246 | clr = TIMER0_25MHZ; |
235 | timer_base + TIMER_CTRL_OFF); | 247 | timer_ctrl_clrset(clr, set); |
236 | timer_clk = 25000000; | 248 | local_timer_ctrl_clrset(clr, set); |
237 | } else { | ||
238 | unsigned long rate = 0; | ||
239 | struct clk *clk = of_clk_get(np, 0); | ||
240 | WARN_ON(IS_ERR(clk)); | ||
241 | rate = clk_get_rate(clk); | ||
242 | |||
243 | u = readl(timer_base + TIMER_CTRL_OFF); | ||
244 | writel(u & ~(TIMER0_25MHZ), | ||
245 | timer_base + TIMER_CTRL_OFF); | ||
246 | |||
247 | timer_clk = rate / TIMER_DIVIDER; | ||
248 | timer25Mhz = false; | ||
249 | } | ||
250 | 249 | ||
251 | /* | 250 | /* |
252 | * We use timer 0 as clocksource, and private(local) timer 0 | 251 | * We use timer 0 as clocksource, and private(local) timer 0 |
@@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void) | |||
268 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); | 267 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); |
269 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); | 268 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); |
270 | 269 | ||
271 | u = readl(timer_base + TIMER_CTRL_OFF); | 270 | timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN | |
272 | 271 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
273 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
274 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF); | ||
275 | 272 | ||
276 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, | 273 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, |
277 | "armada_370_xp_clocksource", | 274 | "armada_370_xp_clocksource", |
@@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void) | |||
293 | if (!res) | 290 | if (!res) |
294 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); | 291 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); |
295 | } | 292 | } |
293 | |||
294 | static void __init armada_xp_timer_init(struct device_node *np) | ||
295 | { | ||
296 | struct clk *clk = of_clk_get_by_name(np, "fixed"); | ||
297 | |||
298 | /* The 25Mhz fixed clock is mandatory, and must always be available */ | ||
299 | BUG_ON(IS_ERR(clk)); | ||
300 | timer_clk = clk_get_rate(clk); | ||
301 | |||
302 | armada_370_xp_timer_common_init(np); | ||
303 | } | ||
304 | CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", | ||
305 | armada_xp_timer_init); | ||
306 | |||
307 | static void __init armada_370_timer_init(struct device_node *np) | ||
308 | { | ||
309 | struct clk *clk = of_clk_get(np, 0); | ||
310 | |||
311 | BUG_ON(IS_ERR(clk)); | ||
312 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; | ||
313 | timer25Mhz = false; | ||
314 | |||
315 | armada_370_xp_timer_common_init(np); | ||
316 | } | ||
317 | CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", | ||
318 | armada_370_timer_init); | ||