aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-28 23:09:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-28 23:09:24 -0500
commit1a32c58bb945970e56f27a1cfb61625a3ac0b88e (patch)
treef49ac4bebcb62416494c0e5bade076c7f7f3bc56 /drivers/clocksource
parent7307c00f335a4e986586b12334696098d2fc2bcd (diff)
parent564991205956d869db0e45dfabe23a31b596fa15 (diff)
Merge tag 'late-mvebu-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC mvebu platform changes from Olof Johansson: "This series contains changes for the Marvell EBU platforms (mvebu, orion, kirkwood, dove) that were not part of the first set of pull requests because of dependencies on the MMC tree, and being submitted a little late. Notable changes are: - More devices get moved out of board files into device tree descriptions. The remaining devices listed in there have patches that will get sent for 3.10, after which we can remove a lot of the board files entirely. We are doing the pinctrl and mmc drivers here, ethernet and PCI still remain. - SMP support for mvebu is improved with support for the local interrupt controller. - The Guruplug board file gets replaced with a DT description. Unfortunately, the dependency on the MMC tree turned out to be a much larger problem than expected, when the MMC maintainer rebased the patches in his tree that all of the patches in this branch are based on, which caused merge conflicts between the new and old versions of those patches. To work around the merge conflicts, this branch rebases all patches on top of the respective MMC patches that did get merged into 3.9. The patches are all identical to the versions that were part of linux-next, but have a new commit date." * tag 'late-mvebu-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (90 commits) arm: mvebu: enable the SD card slot on Armada 370 Reference Design board ARM: kirkwood: topkick: init mvsdio via DT ARM: kirkwood: nsa310: convert to pinctrl ARM: Kirkwood: topkick: Enable i2c bus. ARM: kirkwood: topkick: convert to pinctrl ARM: dove: convert serial DT nodes to clocks property arm: mvebu: Add SPI flash on Armada 370 DB board arm: mvebu: Add SPI flash on Armada XP-DB board arm: mvebu: Add SPI flash on Armada XP-GP board arm: mvebu: Add support for SPI controller in Armada 370/XP clocksource: update and move armada-370-xp-timer documentation to timer directory arm: mvebu: update DT to support local timers ARM: Dove: convert usb host controller to DT arm: mvebu: Enable USB controllers on Armada 370/XP boards arm: mvebu: Add support for USB host controllers in Armada 370/XP arm: mvebu: add button for OpenBlocks AX3-4 ARM: Kirkwood: Convert NS2 to gpio-poweroff. ARM: Kirkwood: Convert NSA310 I2C to device tree ARM: Kirkwood: Convert NSA310 to use gpio-poweroff driver ARM: Kirkwood: Convert NSA310 to DT based regulators. ...
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/time-armada-370-xp.c150
1 files changed, 112 insertions, 38 deletions
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index a4605fd7e303..47a673070d70 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -27,8 +27,10 @@
27#include <linux/of_address.h> 27#include <linux/of_address.h>
28#include <linux/irq.h> 28#include <linux/irq.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <asm/sched_clock.h>
31 30
31#include <asm/sched_clock.h>
32#include <asm/localtimer.h>
33#include <linux/percpu.h>
32/* 34/*
33 * Timer block registers. 35 * Timer block registers.
34 */ 36 */
@@ -49,6 +51,7 @@
49#define TIMER1_RELOAD_OFF 0x0018 51#define TIMER1_RELOAD_OFF 0x0018
50#define TIMER1_VAL_OFF 0x001c 52#define TIMER1_VAL_OFF 0x001c
51 53
54#define LCL_TIMER_EVENTS_STATUS 0x0028
52/* Global timers are connected to the coherency fabric clock, and the 55/* Global timers are connected to the coherency fabric clock, and the
53 below divider reduces their incrementing frequency. */ 56 below divider reduces their incrementing frequency. */
54#define TIMER_DIVIDER_SHIFT 5 57#define TIMER_DIVIDER_SHIFT 5
@@ -57,14 +60,17 @@
57/* 60/*
58 * SoC-specific data. 61 * SoC-specific data.
59 */ 62 */
60static void __iomem *timer_base; 63static void __iomem *timer_base, *local_base;
61static int timer_irq; 64static unsigned int timer_clk;
65static bool timer25Mhz = true;
62 66
63/* 67/*
64 * Number of timer ticks per jiffy. 68 * Number of timer ticks per jiffy.
65 */ 69 */
66static u32 ticks_per_jiffy; 70static u32 ticks_per_jiffy;
67 71
72static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
73
68static u32 notrace armada_370_xp_read_sched_clock(void) 74static u32 notrace armada_370_xp_read_sched_clock(void)
69{ 75{
70 return ~readl(timer_base + TIMER0_VAL_OFF); 76 return ~readl(timer_base + TIMER0_VAL_OFF);
@@ -78,24 +84,23 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
78 struct clock_event_device *dev) 84 struct clock_event_device *dev)
79{ 85{
80 u32 u; 86 u32 u;
81
82 /* 87 /*
83 * Clear clockevent timer interrupt. 88 * Clear clockevent timer interrupt.
84 */ 89 */
85 writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); 90 writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
86 91
87 /* 92 /*
88 * Setup new clockevent timer value. 93 * Setup new clockevent timer value.
89 */ 94 */
90 writel(delta, timer_base + TIMER1_VAL_OFF); 95 writel(delta, local_base + TIMER0_VAL_OFF);
91 96
92 /* 97 /*
93 * Enable the timer. 98 * Enable the timer.
94 */ 99 */
95 u = readl(timer_base + TIMER_CTRL_OFF); 100 u = readl(local_base + TIMER_CTRL_OFF);
96 u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN | 101 u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
97 TIMER1_DIV(TIMER_DIVIDER_SHIFT)); 102 TIMER0_DIV(TIMER_DIVIDER_SHIFT));
98 writel(u, timer_base + TIMER_CTRL_OFF); 103 writel(u, local_base + TIMER_CTRL_OFF);
99 104
100 return 0; 105 return 0;
101} 106}
@@ -107,37 +112,38 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
107 u32 u; 112 u32 u;
108 113
109 if (mode == CLOCK_EVT_MODE_PERIODIC) { 114 if (mode == CLOCK_EVT_MODE_PERIODIC) {
115
110 /* 116 /*
111 * Setup timer to fire at 1/HZ intervals. 117 * Setup timer to fire at 1/HZ intervals.
112 */ 118 */
113 writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); 119 writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
114 writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); 120 writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
115 121
116 /* 122 /*
117 * Enable timer. 123 * Enable timer.
118 */ 124 */
119 u = readl(timer_base + TIMER_CTRL_OFF);
120 125
121 writel((u | TIMER1_EN | TIMER1_RELOAD_EN | 126 u = readl(local_base + TIMER_CTRL_OFF);
122 TIMER1_DIV(TIMER_DIVIDER_SHIFT)), 127
123 timer_base + TIMER_CTRL_OFF); 128 writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
129 TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
130 local_base + TIMER_CTRL_OFF);
124 } else { 131 } else {
125 /* 132 /*
126 * Disable timer. 133 * Disable timer.
127 */ 134 */
128 u = readl(timer_base + TIMER_CTRL_OFF); 135 u = readl(local_base + TIMER_CTRL_OFF);
129 writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); 136 writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
130 137
131 /* 138 /*
132 * ACK pending timer interrupt. 139 * ACK pending timer interrupt.
133 */ 140 */
134 writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); 141 writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
135
136 } 142 }
137} 143}
138 144
139static struct clock_event_device armada_370_xp_clkevt = { 145static struct clock_event_device armada_370_xp_clkevt = {
140 .name = "armada_370_xp_tick", 146 .name = "armada_370_xp_per_cpu_tick",
141 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, 147 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
142 .shift = 32, 148 .shift = 32,
143 .rating = 300, 149 .rating = 300,
@@ -150,32 +156,78 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
150 /* 156 /*
151 * ACK timer interrupt and call event handler. 157 * ACK timer interrupt and call event handler.
152 */ 158 */
159 struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
153 160
154 writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); 161 writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
155 armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt); 162 evt->event_handler(evt);
156 163
157 return IRQ_HANDLED; 164 return IRQ_HANDLED;
158} 165}
159 166
160static struct irqaction armada_370_xp_timer_irq = { 167/*
161 .name = "armada_370_xp_tick", 168 * Setup the local clock events for a CPU.
162 .flags = IRQF_DISABLED | IRQF_TIMER, 169 */
163 .handler = armada_370_xp_timer_interrupt 170static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
171{
172 u32 u;
173 int cpu = smp_processor_id();
174
175 /* Use existing clock_event for cpu 0 */
176 if (!smp_processor_id())
177 return 0;
178
179 u = readl(local_base + TIMER_CTRL_OFF);
180 if (timer25Mhz)
181 writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
182 else
183 writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
184
185 evt->name = armada_370_xp_clkevt.name;
186 evt->irq = armada_370_xp_clkevt.irq;
187 evt->features = armada_370_xp_clkevt.features;
188 evt->shift = armada_370_xp_clkevt.shift;
189 evt->rating = armada_370_xp_clkevt.rating,
190 evt->set_next_event = armada_370_xp_clkevt_next_event,
191 evt->set_mode = armada_370_xp_clkevt_mode,
192 evt->cpumask = cpumask_of(cpu);
193
194 *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
195
196 clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
197 enable_percpu_irq(evt->irq, 0);
198
199 return 0;
200}
201
202static void armada_370_xp_timer_stop(struct clock_event_device *evt)
203{
204 evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
205 disable_percpu_irq(evt->irq);
206}
207
208static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
209 .setup = armada_370_xp_timer_setup,
210 .stop = armada_370_xp_timer_stop,
164}; 211};
165 212
166void __init armada_370_xp_timer_init(void) 213void __init armada_370_xp_timer_init(void)
167{ 214{
168 u32 u; 215 u32 u;
169 struct device_node *np; 216 struct device_node *np;
170 unsigned int timer_clk; 217 int res;
218
171 np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); 219 np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
172 timer_base = of_iomap(np, 0); 220 timer_base = of_iomap(np, 0);
173 WARN_ON(!timer_base); 221 WARN_ON(!timer_base);
222 local_base = of_iomap(np, 1);
174 223
175 if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { 224 if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
176 /* The fixed 25MHz timer is available so let's use it */ 225 /* The fixed 25MHz timer is available so let's use it */
226 u = readl(local_base + TIMER_CTRL_OFF);
227 writel(u | TIMER0_25MHZ,
228 local_base + TIMER_CTRL_OFF);
177 u = readl(timer_base + TIMER_CTRL_OFF); 229 u = readl(timer_base + TIMER_CTRL_OFF);
178 writel(u | TIMER0_25MHZ | TIMER1_25MHZ, 230 writel(u | TIMER0_25MHZ,
179 timer_base + TIMER_CTRL_OFF); 231 timer_base + TIMER_CTRL_OFF);
180 timer_clk = 25000000; 232 timer_clk = 25000000;
181 } else { 233 } else {
@@ -183,15 +235,23 @@ void __init armada_370_xp_timer_init(void)
183 struct clk *clk = of_clk_get(np, 0); 235 struct clk *clk = of_clk_get(np, 0);
184 WARN_ON(IS_ERR(clk)); 236 WARN_ON(IS_ERR(clk));
185 rate = clk_get_rate(clk); 237 rate = clk_get_rate(clk);
238 u = readl(local_base + TIMER_CTRL_OFF);
239 writel(u & ~(TIMER0_25MHZ),
240 local_base + TIMER_CTRL_OFF);
241
186 u = readl(timer_base + TIMER_CTRL_OFF); 242 u = readl(timer_base + TIMER_CTRL_OFF);
187 writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ), 243 writel(u & ~(TIMER0_25MHZ),
188 timer_base + TIMER_CTRL_OFF); 244 timer_base + TIMER_CTRL_OFF);
245
189 timer_clk = rate / TIMER_DIVIDER; 246 timer_clk = rate / TIMER_DIVIDER;
247 timer25Mhz = false;
190 } 248 }
191 249
192 /* We use timer 0 as clocksource, and timer 1 for 250 /*
193 clockevents */ 251 * We use timer 0 as clocksource, and private(local) timer 0
194 timer_irq = irq_of_parse_and_map(np, 1); 252 * for clockevents
253 */
254 armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
195 255
196 ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; 256 ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
197 257
@@ -216,12 +276,26 @@ void __init armada_370_xp_timer_init(void)
216 "armada_370_xp_clocksource", 276 "armada_370_xp_clocksource",
217 timer_clk, 300, 32, clocksource_mmio_readl_down); 277 timer_clk, 300, 32, clocksource_mmio_readl_down);
218 278
219 /* 279 /* Register the clockevent on the private timer of CPU 0 */
220 * Setup clockevent timer (interrupt-driven).
221 */
222 setup_irq(timer_irq, &armada_370_xp_timer_irq);
223 armada_370_xp_clkevt.cpumask = cpumask_of(0); 280 armada_370_xp_clkevt.cpumask = cpumask_of(0);
224 clockevents_config_and_register(&armada_370_xp_clkevt, 281 clockevents_config_and_register(&armada_370_xp_clkevt,
225 timer_clk, 1, 0xfffffffe); 282 timer_clk, 1, 0xfffffffe);
226}
227 283
284 percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
285
286
287 /*
288 * Setup clockevent timer (interrupt-driven).
289 */
290 *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
291 res = request_percpu_irq(armada_370_xp_clkevt.irq,
292 armada_370_xp_timer_interrupt,
293 armada_370_xp_clkevt.name,
294 percpu_armada_370_xp_evt);
295 if (!res) {
296 enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
297#ifdef CONFIG_LOCAL_TIMERS
298 local_timer_register(&armada_370_xp_local_timer_ops);
299#endif
300 }
301}