aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/time-armada-370-xp.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-16 16:10:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-16 16:10:26 -0400
commita4ae54f90e0a7063799eb90852aa8648ccfbb791 (patch)
tree88fd7f7920c8849fed99c782ab1fc605da69a375 /drivers/clocksource/time-armada-370-xp.c
parent3369d116934b70bd2755cdd8b2af9741d18a4047 (diff)
parent63ce2cc474ce962d936ae6dfaa6ae2354b1db5b2 (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.c131
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
73static struct clock_event_device __percpu *armada_370_xp_evt; 85static struct clock_event_device __percpu *armada_370_xp_evt;
74 86
87static 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
93static 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
75static u32 notrace armada_370_xp_read_sched_clock(void) 99static 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
84armada_370_xp_clkevt_next_event(unsigned long delta, 108armada_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
110armada_370_xp_clkevt_mode(enum clock_event_mode mode, 130armada_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 */
164static int armada_370_xp_timer_setup(struct clock_event_device *evt) 178static 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
220void __init armada_370_xp_timer_init(void) 234static 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
294static 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}
304CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
305 armada_xp_timer_init);
306
307static 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}
317CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
318 armada_370_timer_init);