diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:14:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:14:51 -0400 |
commit | 1b044f1cfc65a7d90b209dfabd57e16d98b58c5b (patch) | |
tree | ad657c911b563f9176b17578c0b88a1ea9916a02 /drivers/clocksource/timer-fttmr010.c | |
parent | e0f3e8f14da868047c524a0cf11e08b95fd1b008 (diff) | |
parent | 2287d8664fe7345ead891017eccd879fc605305e (diff) |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner:
"A rather large update for timers/timekeeping:
- compat syscall consolidation (Al Viro)
- Posix timer consolidation (Christoph Helwig / Thomas Gleixner)
- Cleanup of the device tree based initialization for clockevents and
clocksources (Daniel Lezcano)
- Consolidation of the FTTMR010 clocksource/event driver (Linus
Walleij)
- The usual set of small fixes and updates all over the place"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (93 commits)
timers: Make the cpu base lock raw
clocksource/drivers/mips-gic-timer: Fix an error code in 'gic_clocksource_of_init()'
clocksource/drivers/fsl_ftm_timer: Unmap region obtained by of_iomap
clocksource/drivers/tcb_clksrc: Make IO endian agnostic
clocksource/drivers/sun4i: Switch to the timer-of common init
clocksource/drivers/timer-of: Fix invalid iomap check
Revert "ktime: Simplify ktime_compare implementation"
clocksource/drivers: Fix uninitialized variable use in timer_of_init
kselftests: timers: Add test for frequency step
kselftests: timers: Fix inconsistency-check to not ignore first timestamp
time: Add warning about imminent deprecation of CONFIG_GENERIC_TIME_VSYSCALL_OLD
time: Clean up CLOCK_MONOTONIC_RAW time handling
posix-cpu-timers: Make timespec to nsec conversion safe
itimer: Make timeval to nsec conversion range limited
timers: Fix parameter description of try_to_del_timer_sync()
ktime: Simplify ktime_compare implementation
clocksource/drivers/fttmr010: Factor out clock read code
clocksource/drivers/fttmr010: Implement delay timer
clocksource/drivers: Add timer-of common init routine
clocksource/drivers/tcb_clksrc: Save timer context on suspend/resume
...
Diffstat (limited to 'drivers/clocksource/timer-fttmr010.c')
-rw-r--r-- | drivers/clocksource/timer-fttmr010.c | 476 |
1 files changed, 289 insertions, 187 deletions
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index b4a6f1e4bc54..66dd909960c6 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c | |||
@@ -11,12 +11,13 @@ | |||
11 | #include <linux/of.h> | 11 | #include <linux/of.h> |
12 | #include <linux/of_address.h> | 12 | #include <linux/of_address.h> |
13 | #include <linux/of_irq.h> | 13 | #include <linux/of_irq.h> |
14 | #include <linux/mfd/syscon.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <linux/clockchips.h> | 14 | #include <linux/clockchips.h> |
17 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
18 | #include <linux/sched_clock.h> | 16 | #include <linux/sched_clock.h> |
19 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/slab.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/delay.h> | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * Register definitions for the timers | 23 | * Register definitions for the timers |
@@ -37,267 +38,368 @@ | |||
37 | #define TIMER_INTR_STATE (0x34) | 38 | #define TIMER_INTR_STATE (0x34) |
38 | #define TIMER_INTR_MASK (0x38) | 39 | #define TIMER_INTR_MASK (0x38) |
39 | 40 | ||
40 | #define TIMER_1_CR_ENABLE (1 << 0) | 41 | #define TIMER_1_CR_ENABLE BIT(0) |
41 | #define TIMER_1_CR_CLOCK (1 << 1) | 42 | #define TIMER_1_CR_CLOCK BIT(1) |
42 | #define TIMER_1_CR_INT (1 << 2) | 43 | #define TIMER_1_CR_INT BIT(2) |
43 | #define TIMER_2_CR_ENABLE (1 << 3) | 44 | #define TIMER_2_CR_ENABLE BIT(3) |
44 | #define TIMER_2_CR_CLOCK (1 << 4) | 45 | #define TIMER_2_CR_CLOCK BIT(4) |
45 | #define TIMER_2_CR_INT (1 << 5) | 46 | #define TIMER_2_CR_INT BIT(5) |
46 | #define TIMER_3_CR_ENABLE (1 << 6) | 47 | #define TIMER_3_CR_ENABLE BIT(6) |
47 | #define TIMER_3_CR_CLOCK (1 << 7) | 48 | #define TIMER_3_CR_CLOCK BIT(7) |
48 | #define TIMER_3_CR_INT (1 << 8) | 49 | #define TIMER_3_CR_INT BIT(8) |
49 | #define TIMER_1_CR_UPDOWN (1 << 9) | 50 | #define TIMER_1_CR_UPDOWN BIT(9) |
50 | #define TIMER_2_CR_UPDOWN (1 << 10) | 51 | #define TIMER_2_CR_UPDOWN BIT(10) |
51 | #define TIMER_3_CR_UPDOWN (1 << 11) | 52 | #define TIMER_3_CR_UPDOWN BIT(11) |
52 | #define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \ | 53 | |
53 | TIMER_3_CR_ENABLE | \ | 54 | /* |
54 | TIMER_3_CR_UPDOWN) | 55 | * The Aspeed AST2400 moves bits around in the control register |
55 | 56 | * and lacks bits for setting the timer to count upwards. | |
56 | #define TIMER_1_INT_MATCH1 (1 << 0) | 57 | */ |
57 | #define TIMER_1_INT_MATCH2 (1 << 1) | 58 | #define TIMER_1_CR_ASPEED_ENABLE BIT(0) |
58 | #define TIMER_1_INT_OVERFLOW (1 << 2) | 59 | #define TIMER_1_CR_ASPEED_CLOCK BIT(1) |
59 | #define TIMER_2_INT_MATCH1 (1 << 3) | 60 | #define TIMER_1_CR_ASPEED_INT BIT(2) |
60 | #define TIMER_2_INT_MATCH2 (1 << 4) | 61 | #define TIMER_2_CR_ASPEED_ENABLE BIT(4) |
61 | #define TIMER_2_INT_OVERFLOW (1 << 5) | 62 | #define TIMER_2_CR_ASPEED_CLOCK BIT(5) |
62 | #define TIMER_3_INT_MATCH1 (1 << 6) | 63 | #define TIMER_2_CR_ASPEED_INT BIT(6) |
63 | #define TIMER_3_INT_MATCH2 (1 << 7) | 64 | #define TIMER_3_CR_ASPEED_ENABLE BIT(8) |
64 | #define TIMER_3_INT_OVERFLOW (1 << 8) | 65 | #define TIMER_3_CR_ASPEED_CLOCK BIT(9) |
66 | #define TIMER_3_CR_ASPEED_INT BIT(10) | ||
67 | |||
68 | #define TIMER_1_INT_MATCH1 BIT(0) | ||
69 | #define TIMER_1_INT_MATCH2 BIT(1) | ||
70 | #define TIMER_1_INT_OVERFLOW BIT(2) | ||
71 | #define TIMER_2_INT_MATCH1 BIT(3) | ||
72 | #define TIMER_2_INT_MATCH2 BIT(4) | ||
73 | #define TIMER_2_INT_OVERFLOW BIT(5) | ||
74 | #define TIMER_3_INT_MATCH1 BIT(6) | ||
75 | #define TIMER_3_INT_MATCH2 BIT(7) | ||
76 | #define TIMER_3_INT_OVERFLOW BIT(8) | ||
65 | #define TIMER_INT_ALL_MASK 0x1ff | 77 | #define TIMER_INT_ALL_MASK 0x1ff |
66 | 78 | ||
67 | static unsigned int tick_rate; | 79 | struct fttmr010 { |
68 | static void __iomem *base; | 80 | void __iomem *base; |
81 | unsigned int tick_rate; | ||
82 | bool count_down; | ||
83 | u32 t1_enable_val; | ||
84 | struct clock_event_device clkevt; | ||
85 | #ifdef CONFIG_ARM | ||
86 | struct delay_timer delay_timer; | ||
87 | #endif | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * A local singleton used by sched_clock and delay timer reads, which are | ||
92 | * fast and stateless | ||
93 | */ | ||
94 | static struct fttmr010 *local_fttmr; | ||
95 | |||
96 | static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) | ||
97 | { | ||
98 | return container_of(evt, struct fttmr010, clkevt); | ||
99 | } | ||
100 | |||
101 | static unsigned long fttmr010_read_current_timer_up(void) | ||
102 | { | ||
103 | return readl(local_fttmr->base + TIMER2_COUNT); | ||
104 | } | ||
105 | |||
106 | static unsigned long fttmr010_read_current_timer_down(void) | ||
107 | { | ||
108 | return ~readl(local_fttmr->base + TIMER2_COUNT); | ||
109 | } | ||
110 | |||
111 | static u64 notrace fttmr010_read_sched_clock_up(void) | ||
112 | { | ||
113 | return fttmr010_read_current_timer_up(); | ||
114 | } | ||
69 | 115 | ||
70 | static u64 notrace fttmr010_read_sched_clock(void) | 116 | static u64 notrace fttmr010_read_sched_clock_down(void) |
71 | { | 117 | { |
72 | return readl(base + TIMER3_COUNT); | 118 | return fttmr010_read_current_timer_down(); |
73 | } | 119 | } |
74 | 120 | ||
75 | static int fttmr010_timer_set_next_event(unsigned long cycles, | 121 | static int fttmr010_timer_set_next_event(unsigned long cycles, |
76 | struct clock_event_device *evt) | 122 | struct clock_event_device *evt) |
77 | { | 123 | { |
124 | struct fttmr010 *fttmr010 = to_fttmr010(evt); | ||
78 | u32 cr; | 125 | u32 cr; |
79 | 126 | ||
80 | /* Setup the match register */ | 127 | /* Stop */ |
81 | cr = readl(base + TIMER1_COUNT); | 128 | cr = readl(fttmr010->base + TIMER_CR); |
82 | writel(cr + cycles, base + TIMER1_MATCH1); | 129 | cr &= ~fttmr010->t1_enable_val; |
83 | if (readl(base + TIMER1_COUNT) - cr > cycles) | 130 | writel(cr, fttmr010->base + TIMER_CR); |
84 | return -ETIME; | 131 | |
132 | /* Setup the match register forward/backward in time */ | ||
133 | cr = readl(fttmr010->base + TIMER1_COUNT); | ||
134 | if (fttmr010->count_down) | ||
135 | cr -= cycles; | ||
136 | else | ||
137 | cr += cycles; | ||
138 | writel(cr, fttmr010->base + TIMER1_MATCH1); | ||
139 | |||
140 | /* Start */ | ||
141 | cr = readl(fttmr010->base + TIMER_CR); | ||
142 | cr |= fttmr010->t1_enable_val; | ||
143 | writel(cr, fttmr010->base + TIMER_CR); | ||
85 | 144 | ||
86 | return 0; | 145 | return 0; |
87 | } | 146 | } |
88 | 147 | ||
89 | static int fttmr010_timer_shutdown(struct clock_event_device *evt) | 148 | static int fttmr010_timer_shutdown(struct clock_event_device *evt) |
90 | { | 149 | { |
150 | struct fttmr010 *fttmr010 = to_fttmr010(evt); | ||
91 | u32 cr; | 151 | u32 cr; |
92 | 152 | ||
93 | /* | 153 | /* Stop */ |
94 | * Disable also for oneshot: the set_next() call will arm the timer | 154 | cr = readl(fttmr010->base + TIMER_CR); |
95 | * instead. | 155 | cr &= ~fttmr010->t1_enable_val; |
96 | */ | 156 | writel(cr, fttmr010->base + TIMER_CR); |
97 | /* Stop timer and interrupt. */ | 157 | |
98 | cr = readl(base + TIMER_CR); | 158 | return 0; |
99 | cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); | 159 | } |
100 | writel(cr, base + TIMER_CR); | 160 | |
161 | static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) | ||
162 | { | ||
163 | struct fttmr010 *fttmr010 = to_fttmr010(evt); | ||
164 | u32 cr; | ||
165 | |||
166 | /* Stop */ | ||
167 | cr = readl(fttmr010->base + TIMER_CR); | ||
168 | cr &= ~fttmr010->t1_enable_val; | ||
169 | writel(cr, fttmr010->base + TIMER_CR); | ||
101 | 170 | ||
102 | /* Setup counter start from 0 */ | 171 | /* Setup counter start from 0 or ~0 */ |
103 | writel(0, base + TIMER1_COUNT); | 172 | writel(0, fttmr010->base + TIMER1_COUNT); |
104 | writel(0, base + TIMER1_LOAD); | 173 | if (fttmr010->count_down) |
174 | writel(~0, fttmr010->base + TIMER1_LOAD); | ||
175 | else | ||
176 | writel(0, fttmr010->base + TIMER1_LOAD); | ||
105 | 177 | ||
106 | /* enable interrupt */ | 178 | /* Enable interrupt */ |
107 | cr = readl(base + TIMER_INTR_MASK); | 179 | cr = readl(fttmr010->base + TIMER_INTR_MASK); |
108 | cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); | 180 | cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); |
109 | cr |= TIMER_1_INT_MATCH1; | 181 | cr |= TIMER_1_INT_MATCH1; |
110 | writel(cr, base + TIMER_INTR_MASK); | 182 | writel(cr, fttmr010->base + TIMER_INTR_MASK); |
111 | |||
112 | /* start the timer */ | ||
113 | cr = readl(base + TIMER_CR); | ||
114 | cr |= TIMER_1_CR_ENABLE; | ||
115 | writel(cr, base + TIMER_CR); | ||
116 | 183 | ||
117 | return 0; | 184 | return 0; |
118 | } | 185 | } |
119 | 186 | ||
120 | static int fttmr010_timer_set_periodic(struct clock_event_device *evt) | 187 | static int fttmr010_timer_set_periodic(struct clock_event_device *evt) |
121 | { | 188 | { |
122 | u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); | 189 | struct fttmr010 *fttmr010 = to_fttmr010(evt); |
190 | u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); | ||
123 | u32 cr; | 191 | u32 cr; |
124 | 192 | ||
125 | /* Stop timer and interrupt */ | 193 | /* Stop */ |
126 | cr = readl(base + TIMER_CR); | 194 | cr = readl(fttmr010->base + TIMER_CR); |
127 | cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); | 195 | cr &= ~fttmr010->t1_enable_val; |
128 | writel(cr, base + TIMER_CR); | 196 | writel(cr, fttmr010->base + TIMER_CR); |
129 | 197 | ||
130 | /* Setup timer to fire at 1/HT intervals. */ | 198 | /* Setup timer to fire at 1/HZ intervals. */ |
131 | cr = 0xffffffff - (period - 1); | 199 | if (fttmr010->count_down) { |
132 | writel(cr, base + TIMER1_COUNT); | 200 | writel(period, fttmr010->base + TIMER1_LOAD); |
133 | writel(cr, base + TIMER1_LOAD); | 201 | writel(0, fttmr010->base + TIMER1_MATCH1); |
134 | 202 | } else { | |
135 | /* enable interrupt on overflow */ | 203 | cr = 0xffffffff - (period - 1); |
136 | cr = readl(base + TIMER_INTR_MASK); | 204 | writel(cr, fttmr010->base + TIMER1_COUNT); |
137 | cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); | 205 | writel(cr, fttmr010->base + TIMER1_LOAD); |
138 | cr |= TIMER_1_INT_OVERFLOW; | 206 | |
139 | writel(cr, base + TIMER_INTR_MASK); | 207 | /* Enable interrupt on overflow */ |
208 | cr = readl(fttmr010->base + TIMER_INTR_MASK); | ||
209 | cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); | ||
210 | cr |= TIMER_1_INT_OVERFLOW; | ||
211 | writel(cr, fttmr010->base + TIMER_INTR_MASK); | ||
212 | } | ||
140 | 213 | ||
141 | /* Start the timer */ | 214 | /* Start the timer */ |
142 | cr = readl(base + TIMER_CR); | 215 | cr = readl(fttmr010->base + TIMER_CR); |
143 | cr |= TIMER_1_CR_ENABLE; | 216 | cr |= fttmr010->t1_enable_val; |
144 | cr |= TIMER_1_CR_INT; | 217 | writel(cr, fttmr010->base + TIMER_CR); |
145 | writel(cr, base + TIMER_CR); | ||
146 | 218 | ||
147 | return 0; | 219 | return 0; |
148 | } | 220 | } |
149 | 221 | ||
150 | /* Use TIMER1 as clock event */ | ||
151 | static struct clock_event_device fttmr010_clockevent = { | ||
152 | .name = "TIMER1", | ||
153 | /* Reasonably fast and accurate clock event */ | ||
154 | .rating = 300, | ||
155 | .shift = 32, | ||
156 | .features = CLOCK_EVT_FEAT_PERIODIC | | ||
157 | CLOCK_EVT_FEAT_ONESHOT, | ||
158 | .set_next_event = fttmr010_timer_set_next_event, | ||
159 | .set_state_shutdown = fttmr010_timer_shutdown, | ||
160 | .set_state_periodic = fttmr010_timer_set_periodic, | ||
161 | .set_state_oneshot = fttmr010_timer_shutdown, | ||
162 | .tick_resume = fttmr010_timer_shutdown, | ||
163 | }; | ||
164 | |||
165 | /* | 222 | /* |
166 | * IRQ handler for the timer | 223 | * IRQ handler for the timer |
167 | */ | 224 | */ |
168 | static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) | 225 | static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) |
169 | { | 226 | { |
170 | struct clock_event_device *evt = &fttmr010_clockevent; | 227 | struct clock_event_device *evt = dev_id; |
171 | 228 | ||
172 | evt->event_handler(evt); | 229 | evt->event_handler(evt); |
173 | return IRQ_HANDLED; | 230 | return IRQ_HANDLED; |
174 | } | 231 | } |
175 | 232 | ||
176 | static struct irqaction fttmr010_timer_irq = { | 233 | static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) |
177 | .name = "Faraday FTTMR010 Timer Tick", | ||
178 | .flags = IRQF_TIMER, | ||
179 | .handler = fttmr010_timer_interrupt, | ||
180 | }; | ||
181 | |||
182 | static int __init fttmr010_timer_common_init(struct device_node *np) | ||
183 | { | 234 | { |
235 | struct fttmr010 *fttmr010; | ||
184 | int irq; | 236 | int irq; |
237 | struct clk *clk; | ||
238 | int ret; | ||
239 | u32 val; | ||
240 | |||
241 | /* | ||
242 | * These implementations require a clock reference. | ||
243 | * FIXME: we currently only support clocking using PCLK | ||
244 | * and using EXTCLK is not supported in the driver. | ||
245 | */ | ||
246 | clk = of_clk_get_by_name(np, "PCLK"); | ||
247 | if (IS_ERR(clk)) { | ||
248 | pr_err("could not get PCLK\n"); | ||
249 | return PTR_ERR(clk); | ||
250 | } | ||
251 | ret = clk_prepare_enable(clk); | ||
252 | if (ret) { | ||
253 | pr_err("failed to enable PCLK\n"); | ||
254 | return ret; | ||
255 | } | ||
185 | 256 | ||
186 | base = of_iomap(np, 0); | 257 | fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); |
187 | if (!base) { | 258 | if (!fttmr010) { |
259 | ret = -ENOMEM; | ||
260 | goto out_disable_clock; | ||
261 | } | ||
262 | fttmr010->tick_rate = clk_get_rate(clk); | ||
263 | |||
264 | fttmr010->base = of_iomap(np, 0); | ||
265 | if (!fttmr010->base) { | ||
188 | pr_err("Can't remap registers"); | 266 | pr_err("Can't remap registers"); |
189 | return -ENXIO; | 267 | ret = -ENXIO; |
268 | goto out_free; | ||
190 | } | 269 | } |
191 | /* IRQ for timer 1 */ | 270 | /* IRQ for timer 1 */ |
192 | irq = irq_of_parse_and_map(np, 0); | 271 | irq = irq_of_parse_and_map(np, 0); |
193 | if (irq <= 0) { | 272 | if (irq <= 0) { |
194 | pr_err("Can't parse IRQ"); | 273 | pr_err("Can't parse IRQ"); |
195 | return -EINVAL; | 274 | ret = -EINVAL; |
275 | goto out_unmap; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * The Aspeed AST2400 moves bits around in the control register, | ||
280 | * otherwise it works the same. | ||
281 | */ | ||
282 | if (is_aspeed) { | ||
283 | fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | | ||
284 | TIMER_1_CR_ASPEED_INT; | ||
285 | /* Downward not available */ | ||
286 | fttmr010->count_down = true; | ||
287 | } else { | ||
288 | fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; | ||
196 | } | 289 | } |
197 | 290 | ||
198 | /* | 291 | /* |
199 | * Reset the interrupt mask and status | 292 | * Reset the interrupt mask and status |
200 | */ | 293 | */ |
201 | writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); | 294 | writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); |
202 | writel(0, base + TIMER_INTR_STATE); | 295 | writel(0, fttmr010->base + TIMER_INTR_STATE); |
203 | writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); | 296 | |
297 | /* | ||
298 | * Enable timer 1 count up, timer 2 count up, except on Aspeed, | ||
299 | * where everything just counts down. | ||
300 | */ | ||
301 | if (is_aspeed) | ||
302 | val = TIMER_2_CR_ASPEED_ENABLE; | ||
303 | else { | ||
304 | val = TIMER_2_CR_ENABLE; | ||
305 | if (!fttmr010->count_down) | ||
306 | val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN; | ||
307 | } | ||
308 | writel(val, fttmr010->base + TIMER_CR); | ||
204 | 309 | ||
205 | /* | 310 | /* |
206 | * Setup free-running clocksource timer (interrupts | 311 | * Setup free-running clocksource timer (interrupts |
207 | * disabled.) | 312 | * disabled.) |
208 | */ | 313 | */ |
209 | writel(0, base + TIMER3_COUNT); | 314 | local_fttmr = fttmr010; |
210 | writel(0, base + TIMER3_LOAD); | 315 | writel(0, fttmr010->base + TIMER2_COUNT); |
211 | writel(0, base + TIMER3_MATCH1); | 316 | writel(0, fttmr010->base + TIMER2_MATCH1); |
212 | writel(0, base + TIMER3_MATCH2); | 317 | writel(0, fttmr010->base + TIMER2_MATCH2); |
213 | clocksource_mmio_init(base + TIMER3_COUNT, | 318 | |
214 | "fttmr010_clocksource", tick_rate, | 319 | if (fttmr010->count_down) { |
215 | 300, 32, clocksource_mmio_readl_up); | 320 | writel(~0, fttmr010->base + TIMER2_LOAD); |
216 | sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); | 321 | clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, |
322 | "FTTMR010-TIMER2", | ||
323 | fttmr010->tick_rate, | ||
324 | 300, 32, clocksource_mmio_readl_down); | ||
325 | sched_clock_register(fttmr010_read_sched_clock_down, 32, | ||
326 | fttmr010->tick_rate); | ||
327 | } else { | ||
328 | writel(0, fttmr010->base + TIMER2_LOAD); | ||
329 | clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, | ||
330 | "FTTMR010-TIMER2", | ||
331 | fttmr010->tick_rate, | ||
332 | 300, 32, clocksource_mmio_readl_up); | ||
333 | sched_clock_register(fttmr010_read_sched_clock_up, 32, | ||
334 | fttmr010->tick_rate); | ||
335 | } | ||
217 | 336 | ||
218 | /* | 337 | /* |
219 | * Setup clockevent timer (interrupt-driven.) | 338 | * Setup clockevent timer (interrupt-driven) on timer 1. |
220 | */ | 339 | */ |
221 | writel(0, base + TIMER1_COUNT); | 340 | writel(0, fttmr010->base + TIMER1_COUNT); |
222 | writel(0, base + TIMER1_LOAD); | 341 | writel(0, fttmr010->base + TIMER1_LOAD); |
223 | writel(0, base + TIMER1_MATCH1); | 342 | writel(0, fttmr010->base + TIMER1_MATCH1); |
224 | writel(0, base + TIMER1_MATCH2); | 343 | writel(0, fttmr010->base + TIMER1_MATCH2); |
225 | setup_irq(irq, &fttmr010_timer_irq); | 344 | ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER, |
226 | fttmr010_clockevent.cpumask = cpumask_of(0); | 345 | "FTTMR010-TIMER1", &fttmr010->clkevt); |
227 | clockevents_config_and_register(&fttmr010_clockevent, tick_rate, | 346 | if (ret) { |
347 | pr_err("FTTMR010-TIMER1 no IRQ\n"); | ||
348 | goto out_unmap; | ||
349 | } | ||
350 | |||
351 | fttmr010->clkevt.name = "FTTMR010-TIMER1"; | ||
352 | /* Reasonably fast and accurate clock event */ | ||
353 | fttmr010->clkevt.rating = 300; | ||
354 | fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | | ||
355 | CLOCK_EVT_FEAT_ONESHOT; | ||
356 | fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; | ||
357 | fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown; | ||
358 | fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; | ||
359 | fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; | ||
360 | fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown; | ||
361 | fttmr010->clkevt.cpumask = cpumask_of(0); | ||
362 | fttmr010->clkevt.irq = irq; | ||
363 | clockevents_config_and_register(&fttmr010->clkevt, | ||
364 | fttmr010->tick_rate, | ||
228 | 1, 0xffffffff); | 365 | 1, 0xffffffff); |
229 | 366 | ||
230 | return 0; | 367 | #ifdef CONFIG_ARM |
231 | } | 368 | /* Also use this timer for delays */ |
369 | if (fttmr010->count_down) | ||
370 | fttmr010->delay_timer.read_current_timer = | ||
371 | fttmr010_read_current_timer_down; | ||
372 | else | ||
373 | fttmr010->delay_timer.read_current_timer = | ||
374 | fttmr010_read_current_timer_up; | ||
375 | fttmr010->delay_timer.freq = fttmr010->tick_rate; | ||
376 | register_current_timer_delay(&fttmr010->delay_timer); | ||
377 | #endif | ||
232 | 378 | ||
233 | static int __init fttmr010_timer_of_init(struct device_node *np) | 379 | return 0; |
234 | { | ||
235 | /* | ||
236 | * These implementations require a clock reference. | ||
237 | * FIXME: we currently only support clocking using PCLK | ||
238 | * and using EXTCLK is not supported in the driver. | ||
239 | */ | ||
240 | struct clk *clk; | ||
241 | 380 | ||
242 | clk = of_clk_get_by_name(np, "PCLK"); | 381 | out_unmap: |
243 | if (IS_ERR(clk)) { | 382 | iounmap(fttmr010->base); |
244 | pr_err("could not get PCLK"); | 383 | out_free: |
245 | return PTR_ERR(clk); | 384 | kfree(fttmr010); |
246 | } | 385 | out_disable_clock: |
247 | tick_rate = clk_get_rate(clk); | 386 | clk_disable_unprepare(clk); |
248 | 387 | ||
249 | return fttmr010_timer_common_init(np); | 388 | return ret; |
250 | } | 389 | } |
251 | CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init); | ||
252 | 390 | ||
253 | /* | 391 | static __init int aspeed_timer_init(struct device_node *np) |
254 | * Gemini-specific: relevant registers in the global syscon | ||
255 | */ | ||
256 | #define GLOBAL_STATUS 0x04 | ||
257 | #define CPU_AHB_RATIO_MASK (0x3 << 18) | ||
258 | #define CPU_AHB_1_1 (0x0 << 18) | ||
259 | #define CPU_AHB_3_2 (0x1 << 18) | ||
260 | #define CPU_AHB_24_13 (0x2 << 18) | ||
261 | #define CPU_AHB_2_1 (0x3 << 18) | ||
262 | #define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) | ||
263 | |||
264 | static int __init gemini_timer_of_init(struct device_node *np) | ||
265 | { | 392 | { |
266 | static struct regmap *map; | 393 | return fttmr010_common_init(np, true); |
267 | int ret; | 394 | } |
268 | u32 val; | ||
269 | |||
270 | map = syscon_regmap_lookup_by_phandle(np, "syscon"); | ||
271 | if (IS_ERR(map)) { | ||
272 | pr_err("Can't get regmap for syscon handle\n"); | ||
273 | return -ENODEV; | ||
274 | } | ||
275 | ret = regmap_read(map, GLOBAL_STATUS, &val); | ||
276 | if (ret) { | ||
277 | pr_err("Can't read syscon status register\n"); | ||
278 | return -ENXIO; | ||
279 | } | ||
280 | |||
281 | tick_rate = REG_TO_AHB_SPEED(val) * 1000000; | ||
282 | pr_info("Bus: %dMHz ", tick_rate / 1000000); | ||
283 | |||
284 | tick_rate /= 6; /* APB bus run AHB*(1/6) */ | ||
285 | |||
286 | switch (val & CPU_AHB_RATIO_MASK) { | ||
287 | case CPU_AHB_1_1: | ||
288 | pr_cont("(1/1)\n"); | ||
289 | break; | ||
290 | case CPU_AHB_3_2: | ||
291 | pr_cont("(3/2)\n"); | ||
292 | break; | ||
293 | case CPU_AHB_24_13: | ||
294 | pr_cont("(24/13)\n"); | ||
295 | break; | ||
296 | case CPU_AHB_2_1: | ||
297 | pr_cont("(2/1)\n"); | ||
298 | break; | ||
299 | } | ||
300 | 395 | ||
301 | return fttmr010_timer_common_init(np); | 396 | static __init int fttmr010_timer_init(struct device_node *np) |
397 | { | ||
398 | return fttmr010_common_init(np, false); | ||
302 | } | 399 | } |
303 | CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init); | 400 | |
401 | TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); | ||
402 | TIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); | ||
403 | TIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init); | ||
404 | TIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init); | ||
405 | TIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init); | ||