Commit 9affd6becbfb2c3f0d04e554bb87234761b37aba
1 parent
9607a85b67
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
arm: fix mismerge of arch/arm/mach-omap2/timer.c
I badly screwed up the merge in commit 6fa52ed33bea ("Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/.../arm-soc") by incorrectly taking the arch/arm/mach-omap2/* data fully from the merge target because the 'drivers-for-linus' branch seemed to be a proper superset of the duplicate ARM commits. That was bogus: commit ff931c821bab ("ARM: OMAP: clocks: Delay clk inits atleast until slab is initialized") only existed in head, and the changes to arch/arm/mach-omap2/timer.c from that commit got list. Re-doing the merge more carefully, I do think this part was the only thing I screwed up. Knock wood. Reported-by: Tony Lindgren <tony@atomide.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Olof Johansson <olof@lixom.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 4 additions and 0 deletions Inline Diff
arch/arm/mach-omap2/timer.c
1 | /* | 1 | /* |
2 | * linux/arch/arm/mach-omap2/timer.c | 2 | * linux/arch/arm/mach-omap2/timer.c |
3 | * | 3 | * |
4 | * OMAP2 GP timer support. | 4 | * OMAP2 GP timer support. |
5 | * | 5 | * |
6 | * Copyright (C) 2009 Nokia Corporation | 6 | * Copyright (C) 2009 Nokia Corporation |
7 | * | 7 | * |
8 | * Update to use new clocksource/clockevent layers | 8 | * Update to use new clocksource/clockevent layers |
9 | * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> | 9 | * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> |
10 | * Copyright (C) 2007 MontaVista Software, Inc. | 10 | * Copyright (C) 2007 MontaVista Software, Inc. |
11 | * | 11 | * |
12 | * Original driver: | 12 | * Original driver: |
13 | * Copyright (C) 2005 Nokia Corporation | 13 | * Copyright (C) 2005 Nokia Corporation |
14 | * Author: Paul Mundt <paul.mundt@nokia.com> | 14 | * Author: Paul Mundt <paul.mundt@nokia.com> |
15 | * Juha Yrjölä <juha.yrjola@nokia.com> | 15 | * Juha Yrjölä <juha.yrjola@nokia.com> |
16 | * OMAP Dual-mode timer framework support by Timo Teras | 16 | * OMAP Dual-mode timer framework support by Timo Teras |
17 | * | 17 | * |
18 | * Some parts based off of TI's 24xx code: | 18 | * Some parts based off of TI's 24xx code: |
19 | * | 19 | * |
20 | * Copyright (C) 2004-2009 Texas Instruments, Inc. | 20 | * Copyright (C) 2004-2009 Texas Instruments, Inc. |
21 | * | 21 | * |
22 | * Roughly modelled after the OMAP1 MPU timer code. | 22 | * Roughly modelled after the OMAP1 MPU timer code. |
23 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> | 23 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> |
24 | * | 24 | * |
25 | * This file is subject to the terms and conditions of the GNU General Public | 25 | * This file is subject to the terms and conditions of the GNU General Public |
26 | * License. See the file "COPYING" in the main directory of this archive | 26 | * License. See the file "COPYING" in the main directory of this archive |
27 | * for more details. | 27 | * for more details. |
28 | */ | 28 | */ |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/time.h> | 30 | #include <linux/time.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/err.h> | 32 | #include <linux/err.h> |
33 | #include <linux/clk.h> | 33 | #include <linux/clk.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/irq.h> | 35 | #include <linux/irq.h> |
36 | #include <linux/clocksource.h> | 36 | #include <linux/clocksource.h> |
37 | #include <linux/clockchips.h> | 37 | #include <linux/clockchips.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/of.h> | 39 | #include <linux/of.h> |
40 | #include <linux/of_address.h> | 40 | #include <linux/of_address.h> |
41 | #include <linux/of_irq.h> | 41 | #include <linux/of_irq.h> |
42 | #include <linux/platform_device.h> | 42 | #include <linux/platform_device.h> |
43 | #include <linux/platform_data/dmtimer-omap.h> | 43 | #include <linux/platform_data/dmtimer-omap.h> |
44 | 44 | ||
45 | #include <asm/mach/time.h> | 45 | #include <asm/mach/time.h> |
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 "omap_hwmod.h" | 49 | #include "omap_hwmod.h" |
50 | #include "omap_device.h" | 50 | #include "omap_device.h" |
51 | #include <plat/counter-32k.h> | 51 | #include <plat/counter-32k.h> |
52 | #include <plat/dmtimer.h> | 52 | #include <plat/dmtimer.h> |
53 | #include "omap-pm.h" | 53 | #include "omap-pm.h" |
54 | 54 | ||
55 | #include "soc.h" | 55 | #include "soc.h" |
56 | #include "common.h" | 56 | #include "common.h" |
57 | #include "powerdomain.h" | 57 | #include "powerdomain.h" |
58 | 58 | ||
59 | #define REALTIME_COUNTER_BASE 0x48243200 | 59 | #define REALTIME_COUNTER_BASE 0x48243200 |
60 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 | 60 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 |
61 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 | 61 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 |
62 | #define NUMERATOR_DENUMERATOR_MASK 0xfffff000 | 62 | #define NUMERATOR_DENUMERATOR_MASK 0xfffff000 |
63 | 63 | ||
64 | /* Clockevent code */ | 64 | /* Clockevent code */ |
65 | 65 | ||
66 | static struct omap_dm_timer clkev; | 66 | static struct omap_dm_timer clkev; |
67 | static struct clock_event_device clockevent_gpt; | 67 | static struct clock_event_device clockevent_gpt; |
68 | 68 | ||
69 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) | 69 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) |
70 | { | 70 | { |
71 | struct clock_event_device *evt = &clockevent_gpt; | 71 | struct clock_event_device *evt = &clockevent_gpt; |
72 | 72 | ||
73 | __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW); | 73 | __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW); |
74 | 74 | ||
75 | evt->event_handler(evt); | 75 | evt->event_handler(evt); |
76 | return IRQ_HANDLED; | 76 | return IRQ_HANDLED; |
77 | } | 77 | } |
78 | 78 | ||
79 | static struct irqaction omap2_gp_timer_irq = { | 79 | static struct irqaction omap2_gp_timer_irq = { |
80 | .name = "gp_timer", | 80 | .name = "gp_timer", |
81 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 81 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
82 | .handler = omap2_gp_timer_interrupt, | 82 | .handler = omap2_gp_timer_interrupt, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static int omap2_gp_timer_set_next_event(unsigned long cycles, | 85 | static int omap2_gp_timer_set_next_event(unsigned long cycles, |
86 | struct clock_event_device *evt) | 86 | struct clock_event_device *evt) |
87 | { | 87 | { |
88 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, | 88 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, |
89 | 0xffffffff - cycles, OMAP_TIMER_POSTED); | 89 | 0xffffffff - cycles, OMAP_TIMER_POSTED); |
90 | 90 | ||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | 94 | static void omap2_gp_timer_set_mode(enum clock_event_mode mode, |
95 | struct clock_event_device *evt) | 95 | struct clock_event_device *evt) |
96 | { | 96 | { |
97 | u32 period; | 97 | u32 period; |
98 | 98 | ||
99 | __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate); | 99 | __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate); |
100 | 100 | ||
101 | switch (mode) { | 101 | switch (mode) { |
102 | case CLOCK_EVT_MODE_PERIODIC: | 102 | case CLOCK_EVT_MODE_PERIODIC: |
103 | period = clkev.rate / HZ; | 103 | period = clkev.rate / HZ; |
104 | period -= 1; | 104 | period -= 1; |
105 | /* Looks like we need to first set the load value separately */ | 105 | /* Looks like we need to first set the load value separately */ |
106 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, | 106 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, |
107 | 0xffffffff - period, OMAP_TIMER_POSTED); | 107 | 0xffffffff - period, OMAP_TIMER_POSTED); |
108 | __omap_dm_timer_load_start(&clkev, | 108 | __omap_dm_timer_load_start(&clkev, |
109 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, | 109 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, |
110 | 0xffffffff - period, OMAP_TIMER_POSTED); | 110 | 0xffffffff - period, OMAP_TIMER_POSTED); |
111 | break; | 111 | break; |
112 | case CLOCK_EVT_MODE_ONESHOT: | 112 | case CLOCK_EVT_MODE_ONESHOT: |
113 | break; | 113 | break; |
114 | case CLOCK_EVT_MODE_UNUSED: | 114 | case CLOCK_EVT_MODE_UNUSED: |
115 | case CLOCK_EVT_MODE_SHUTDOWN: | 115 | case CLOCK_EVT_MODE_SHUTDOWN: |
116 | case CLOCK_EVT_MODE_RESUME: | 116 | case CLOCK_EVT_MODE_RESUME: |
117 | break; | 117 | break; |
118 | } | 118 | } |
119 | } | 119 | } |
120 | 120 | ||
121 | static struct clock_event_device clockevent_gpt = { | 121 | static struct clock_event_device clockevent_gpt = { |
122 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 122 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
123 | .rating = 300, | 123 | .rating = 300, |
124 | .set_next_event = omap2_gp_timer_set_next_event, | 124 | .set_next_event = omap2_gp_timer_set_next_event, |
125 | .set_mode = omap2_gp_timer_set_mode, | 125 | .set_mode = omap2_gp_timer_set_mode, |
126 | }; | 126 | }; |
127 | 127 | ||
128 | static struct property device_disabled = { | 128 | static struct property device_disabled = { |
129 | .name = "status", | 129 | .name = "status", |
130 | .length = sizeof("disabled"), | 130 | .length = sizeof("disabled"), |
131 | .value = "disabled", | 131 | .value = "disabled", |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct of_device_id omap_timer_match[] __initdata = { | 134 | static struct of_device_id omap_timer_match[] __initdata = { |
135 | { .compatible = "ti,omap2420-timer", }, | 135 | { .compatible = "ti,omap2420-timer", }, |
136 | { .compatible = "ti,omap3430-timer", }, | 136 | { .compatible = "ti,omap3430-timer", }, |
137 | { .compatible = "ti,omap4430-timer", }, | 137 | { .compatible = "ti,omap4430-timer", }, |
138 | { .compatible = "ti,omap5430-timer", }, | 138 | { .compatible = "ti,omap5430-timer", }, |
139 | { .compatible = "ti,am335x-timer", }, | 139 | { .compatible = "ti,am335x-timer", }, |
140 | { .compatible = "ti,am335x-timer-1ms", }, | 140 | { .compatible = "ti,am335x-timer-1ms", }, |
141 | { } | 141 | { } |
142 | }; | 142 | }; |
143 | 143 | ||
144 | /** | 144 | /** |
145 | * omap_get_timer_dt - get a timer using device-tree | 145 | * omap_get_timer_dt - get a timer using device-tree |
146 | * @match - device-tree match structure for matching a device type | 146 | * @match - device-tree match structure for matching a device type |
147 | * @property - optional timer property to match | 147 | * @property - optional timer property to match |
148 | * | 148 | * |
149 | * Helper function to get a timer during early boot using device-tree for use | 149 | * Helper function to get a timer during early boot using device-tree for use |
150 | * as kernel system timer. Optionally, the property argument can be used to | 150 | * as kernel system timer. Optionally, the property argument can be used to |
151 | * select a timer with a specific property. Once a timer is found then mark | 151 | * select a timer with a specific property. Once a timer is found then mark |
152 | * the timer node in device-tree as disabled, to prevent the kernel from | 152 | * the timer node in device-tree as disabled, to prevent the kernel from |
153 | * registering this timer as a platform device and so no one else can use it. | 153 | * registering this timer as a platform device and so no one else can use it. |
154 | */ | 154 | */ |
155 | static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, | 155 | static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, |
156 | const char *property) | 156 | const char *property) |
157 | { | 157 | { |
158 | struct device_node *np; | 158 | struct device_node *np; |
159 | 159 | ||
160 | for_each_matching_node(np, match) { | 160 | for_each_matching_node(np, match) { |
161 | if (!of_device_is_available(np)) | 161 | if (!of_device_is_available(np)) |
162 | continue; | 162 | continue; |
163 | 163 | ||
164 | if (property && !of_get_property(np, property, NULL)) | 164 | if (property && !of_get_property(np, property, NULL)) |
165 | continue; | 165 | continue; |
166 | 166 | ||
167 | if (!property && (of_get_property(np, "ti,timer-alwon", NULL) || | 167 | if (!property && (of_get_property(np, "ti,timer-alwon", NULL) || |
168 | of_get_property(np, "ti,timer-dsp", NULL) || | 168 | of_get_property(np, "ti,timer-dsp", NULL) || |
169 | of_get_property(np, "ti,timer-pwm", NULL) || | 169 | of_get_property(np, "ti,timer-pwm", NULL) || |
170 | of_get_property(np, "ti,timer-secure", NULL))) | 170 | of_get_property(np, "ti,timer-secure", NULL))) |
171 | continue; | 171 | continue; |
172 | 172 | ||
173 | of_add_property(np, &device_disabled); | 173 | of_add_property(np, &device_disabled); |
174 | return np; | 174 | return np; |
175 | } | 175 | } |
176 | 176 | ||
177 | return NULL; | 177 | return NULL; |
178 | } | 178 | } |
179 | 179 | ||
180 | /** | 180 | /** |
181 | * omap_dmtimer_init - initialisation function when device tree is used | 181 | * omap_dmtimer_init - initialisation function when device tree is used |
182 | * | 182 | * |
183 | * For secure OMAP3 devices, timers with device type "timer-secure" cannot | 183 | * For secure OMAP3 devices, timers with device type "timer-secure" cannot |
184 | * be used by the kernel as they are reserved. Therefore, to prevent the | 184 | * be used by the kernel as they are reserved. Therefore, to prevent the |
185 | * kernel registering these devices remove them dynamically from the device | 185 | * kernel registering these devices remove them dynamically from the device |
186 | * tree on boot. | 186 | * tree on boot. |
187 | */ | 187 | */ |
188 | static void __init omap_dmtimer_init(void) | 188 | static void __init omap_dmtimer_init(void) |
189 | { | 189 | { |
190 | struct device_node *np; | 190 | struct device_node *np; |
191 | 191 | ||
192 | if (!cpu_is_omap34xx()) | 192 | if (!cpu_is_omap34xx()) |
193 | return; | 193 | return; |
194 | 194 | ||
195 | /* If we are a secure device, remove any secure timer nodes */ | 195 | /* If we are a secure device, remove any secure timer nodes */ |
196 | if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { | 196 | if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { |
197 | np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure"); | 197 | np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure"); |
198 | if (np) | 198 | if (np) |
199 | of_node_put(np); | 199 | of_node_put(np); |
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | /** | 203 | /** |
204 | * omap_dm_timer_get_errata - get errata flags for a timer | 204 | * omap_dm_timer_get_errata - get errata flags for a timer |
205 | * | 205 | * |
206 | * Get the timer errata flags that are specific to the OMAP device being used. | 206 | * Get the timer errata flags that are specific to the OMAP device being used. |
207 | */ | 207 | */ |
208 | static u32 __init omap_dm_timer_get_errata(void) | 208 | static u32 __init omap_dm_timer_get_errata(void) |
209 | { | 209 | { |
210 | if (cpu_is_omap24xx()) | 210 | if (cpu_is_omap24xx()) |
211 | return 0; | 211 | return 0; |
212 | 212 | ||
213 | return OMAP_TIMER_ERRATA_I103_I767; | 213 | return OMAP_TIMER_ERRATA_I103_I767; |
214 | } | 214 | } |
215 | 215 | ||
216 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | 216 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
217 | const char *fck_source, | 217 | const char *fck_source, |
218 | const char *property, | 218 | const char *property, |
219 | const char **timer_name, | 219 | const char **timer_name, |
220 | int posted) | 220 | int posted) |
221 | { | 221 | { |
222 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ | 222 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ |
223 | const char *oh_name; | 223 | const char *oh_name; |
224 | struct device_node *np; | 224 | struct device_node *np; |
225 | struct omap_hwmod *oh; | 225 | struct omap_hwmod *oh; |
226 | struct resource irq, mem; | 226 | struct resource irq, mem; |
227 | struct clk *src; | 227 | struct clk *src; |
228 | int r = 0; | 228 | int r = 0; |
229 | 229 | ||
230 | if (of_have_populated_dt()) { | 230 | if (of_have_populated_dt()) { |
231 | np = omap_get_timer_dt(omap_timer_match, property); | 231 | np = omap_get_timer_dt(omap_timer_match, property); |
232 | if (!np) | 232 | if (!np) |
233 | return -ENODEV; | 233 | return -ENODEV; |
234 | 234 | ||
235 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 235 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
236 | if (!oh_name) | 236 | if (!oh_name) |
237 | return -ENODEV; | 237 | return -ENODEV; |
238 | 238 | ||
239 | timer->irq = irq_of_parse_and_map(np, 0); | 239 | timer->irq = irq_of_parse_and_map(np, 0); |
240 | if (!timer->irq) | 240 | if (!timer->irq) |
241 | return -ENXIO; | 241 | return -ENXIO; |
242 | 242 | ||
243 | timer->io_base = of_iomap(np, 0); | 243 | timer->io_base = of_iomap(np, 0); |
244 | 244 | ||
245 | of_node_put(np); | 245 | of_node_put(np); |
246 | } else { | 246 | } else { |
247 | if (omap_dm_timer_reserve_systimer(timer->id)) | 247 | if (omap_dm_timer_reserve_systimer(timer->id)) |
248 | return -ENODEV; | 248 | return -ENODEV; |
249 | 249 | ||
250 | sprintf(name, "timer%d", timer->id); | 250 | sprintf(name, "timer%d", timer->id); |
251 | oh_name = name; | 251 | oh_name = name; |
252 | } | 252 | } |
253 | 253 | ||
254 | oh = omap_hwmod_lookup(oh_name); | 254 | oh = omap_hwmod_lookup(oh_name); |
255 | if (!oh) | 255 | if (!oh) |
256 | return -ENODEV; | 256 | return -ENODEV; |
257 | 257 | ||
258 | *timer_name = oh->name; | 258 | *timer_name = oh->name; |
259 | 259 | ||
260 | if (!of_have_populated_dt()) { | 260 | if (!of_have_populated_dt()) { |
261 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, | 261 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, |
262 | &irq); | 262 | &irq); |
263 | if (r) | 263 | if (r) |
264 | return -ENXIO; | 264 | return -ENXIO; |
265 | timer->irq = irq.start; | 265 | timer->irq = irq.start; |
266 | 266 | ||
267 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, | 267 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, |
268 | &mem); | 268 | &mem); |
269 | if (r) | 269 | if (r) |
270 | return -ENXIO; | 270 | return -ENXIO; |
271 | 271 | ||
272 | /* Static mapping, never released */ | 272 | /* Static mapping, never released */ |
273 | timer->io_base = ioremap(mem.start, mem.end - mem.start); | 273 | timer->io_base = ioremap(mem.start, mem.end - mem.start); |
274 | } | 274 | } |
275 | 275 | ||
276 | if (!timer->io_base) | 276 | if (!timer->io_base) |
277 | return -ENXIO; | 277 | return -ENXIO; |
278 | 278 | ||
279 | /* After the dmtimer is using hwmod these clocks won't be needed */ | 279 | /* After the dmtimer is using hwmod these clocks won't be needed */ |
280 | timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); | 280 | timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); |
281 | if (IS_ERR(timer->fclk)) | 281 | if (IS_ERR(timer->fclk)) |
282 | return PTR_ERR(timer->fclk); | 282 | return PTR_ERR(timer->fclk); |
283 | 283 | ||
284 | src = clk_get(NULL, fck_source); | 284 | src = clk_get(NULL, fck_source); |
285 | if (IS_ERR(src)) | 285 | if (IS_ERR(src)) |
286 | return PTR_ERR(src); | 286 | return PTR_ERR(src); |
287 | 287 | ||
288 | if (clk_get_parent(timer->fclk) != src) { | 288 | if (clk_get_parent(timer->fclk) != src) { |
289 | r = clk_set_parent(timer->fclk, src); | 289 | r = clk_set_parent(timer->fclk, src); |
290 | if (r < 0) { | 290 | if (r < 0) { |
291 | pr_warn("%s: %s cannot set source\n", __func__, | 291 | pr_warn("%s: %s cannot set source\n", __func__, |
292 | oh->name); | 292 | oh->name); |
293 | clk_put(src); | 293 | clk_put(src); |
294 | return r; | 294 | return r; |
295 | } | 295 | } |
296 | } | 296 | } |
297 | 297 | ||
298 | clk_put(src); | 298 | clk_put(src); |
299 | 299 | ||
300 | omap_hwmod_setup_one(oh_name); | 300 | omap_hwmod_setup_one(oh_name); |
301 | omap_hwmod_enable(oh); | 301 | omap_hwmod_enable(oh); |
302 | __omap_dm_timer_init_regs(timer); | 302 | __omap_dm_timer_init_regs(timer); |
303 | 303 | ||
304 | if (posted) | 304 | if (posted) |
305 | __omap_dm_timer_enable_posted(timer); | 305 | __omap_dm_timer_enable_posted(timer); |
306 | 306 | ||
307 | /* Check that the intended posted configuration matches the actual */ | 307 | /* Check that the intended posted configuration matches the actual */ |
308 | if (posted != timer->posted) | 308 | if (posted != timer->posted) |
309 | return -EINVAL; | 309 | return -EINVAL; |
310 | 310 | ||
311 | timer->rate = clk_get_rate(timer->fclk); | 311 | timer->rate = clk_get_rate(timer->fclk); |
312 | timer->reserved = 1; | 312 | timer->reserved = 1; |
313 | 313 | ||
314 | return r; | 314 | return r; |
315 | } | 315 | } |
316 | 316 | ||
317 | static void __init omap2_gp_clockevent_init(int gptimer_id, | 317 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
318 | const char *fck_source, | 318 | const char *fck_source, |
319 | const char *property) | 319 | const char *property) |
320 | { | 320 | { |
321 | int res; | 321 | int res; |
322 | 322 | ||
323 | clkev.id = gptimer_id; | 323 | clkev.id = gptimer_id; |
324 | clkev.errata = omap_dm_timer_get_errata(); | 324 | clkev.errata = omap_dm_timer_get_errata(); |
325 | 325 | ||
326 | /* | 326 | /* |
327 | * For clock-event timers we never read the timer counter and | 327 | * For clock-event timers we never read the timer counter and |
328 | * so we are not impacted by errata i103 and i767. Therefore, | 328 | * so we are not impacted by errata i103 and i767. Therefore, |
329 | * we can safely ignore this errata for clock-event timers. | 329 | * we can safely ignore this errata for clock-event timers. |
330 | */ | 330 | */ |
331 | __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767); | 331 | __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767); |
332 | 332 | ||
333 | res = omap_dm_timer_init_one(&clkev, fck_source, property, | 333 | res = omap_dm_timer_init_one(&clkev, fck_source, property, |
334 | &clockevent_gpt.name, OMAP_TIMER_POSTED); | 334 | &clockevent_gpt.name, OMAP_TIMER_POSTED); |
335 | BUG_ON(res); | 335 | BUG_ON(res); |
336 | 336 | ||
337 | omap2_gp_timer_irq.dev_id = &clkev; | 337 | omap2_gp_timer_irq.dev_id = &clkev; |
338 | setup_irq(clkev.irq, &omap2_gp_timer_irq); | 338 | setup_irq(clkev.irq, &omap2_gp_timer_irq); |
339 | 339 | ||
340 | __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); | 340 | __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); |
341 | 341 | ||
342 | clockevent_gpt.cpumask = cpu_possible_mask; | 342 | clockevent_gpt.cpumask = cpu_possible_mask; |
343 | clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev); | 343 | clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev); |
344 | clockevents_config_and_register(&clockevent_gpt, clkev.rate, | 344 | clockevents_config_and_register(&clockevent_gpt, clkev.rate, |
345 | 3, /* Timer internal resynch latency */ | 345 | 3, /* Timer internal resynch latency */ |
346 | 0xffffffff); | 346 | 0xffffffff); |
347 | 347 | ||
348 | pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, | 348 | pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, |
349 | clkev.rate); | 349 | clkev.rate); |
350 | } | 350 | } |
351 | 351 | ||
352 | /* Clocksource code */ | 352 | /* Clocksource code */ |
353 | static struct omap_dm_timer clksrc; | 353 | static struct omap_dm_timer clksrc; |
354 | static bool use_gptimer_clksrc; | 354 | static bool use_gptimer_clksrc; |
355 | 355 | ||
356 | /* | 356 | /* |
357 | * clocksource | 357 | * clocksource |
358 | */ | 358 | */ |
359 | static cycle_t clocksource_read_cycles(struct clocksource *cs) | 359 | static cycle_t clocksource_read_cycles(struct clocksource *cs) |
360 | { | 360 | { |
361 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, | 361 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, |
362 | OMAP_TIMER_NONPOSTED); | 362 | OMAP_TIMER_NONPOSTED); |
363 | } | 363 | } |
364 | 364 | ||
365 | static struct clocksource clocksource_gpt = { | 365 | static struct clocksource clocksource_gpt = { |
366 | .rating = 300, | 366 | .rating = 300, |
367 | .read = clocksource_read_cycles, | 367 | .read = clocksource_read_cycles, |
368 | .mask = CLOCKSOURCE_MASK(32), | 368 | .mask = CLOCKSOURCE_MASK(32), |
369 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 369 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
370 | }; | 370 | }; |
371 | 371 | ||
372 | static u32 notrace dmtimer_read_sched_clock(void) | 372 | static u32 notrace dmtimer_read_sched_clock(void) |
373 | { | 373 | { |
374 | if (clksrc.reserved) | 374 | if (clksrc.reserved) |
375 | return __omap_dm_timer_read_counter(&clksrc, | 375 | return __omap_dm_timer_read_counter(&clksrc, |
376 | OMAP_TIMER_NONPOSTED); | 376 | OMAP_TIMER_NONPOSTED); |
377 | 377 | ||
378 | return 0; | 378 | return 0; |
379 | } | 379 | } |
380 | 380 | ||
381 | static struct of_device_id omap_counter_match[] __initdata = { | 381 | static struct of_device_id omap_counter_match[] __initdata = { |
382 | { .compatible = "ti,omap-counter32k", }, | 382 | { .compatible = "ti,omap-counter32k", }, |
383 | { } | 383 | { } |
384 | }; | 384 | }; |
385 | 385 | ||
386 | /* Setup free-running counter for clocksource */ | 386 | /* Setup free-running counter for clocksource */ |
387 | static int __init __maybe_unused omap2_sync32k_clocksource_init(void) | 387 | static int __init __maybe_unused omap2_sync32k_clocksource_init(void) |
388 | { | 388 | { |
389 | int ret; | 389 | int ret; |
390 | struct device_node *np = NULL; | 390 | struct device_node *np = NULL; |
391 | struct omap_hwmod *oh; | 391 | struct omap_hwmod *oh; |
392 | void __iomem *vbase; | 392 | void __iomem *vbase; |
393 | const char *oh_name = "counter_32k"; | 393 | const char *oh_name = "counter_32k"; |
394 | 394 | ||
395 | /* | 395 | /* |
396 | * If device-tree is present, then search the DT blob | 396 | * If device-tree is present, then search the DT blob |
397 | * to see if the 32kHz counter is supported. | 397 | * to see if the 32kHz counter is supported. |
398 | */ | 398 | */ |
399 | if (of_have_populated_dt()) { | 399 | if (of_have_populated_dt()) { |
400 | np = omap_get_timer_dt(omap_counter_match, NULL); | 400 | np = omap_get_timer_dt(omap_counter_match, NULL); |
401 | if (!np) | 401 | if (!np) |
402 | return -ENODEV; | 402 | return -ENODEV; |
403 | 403 | ||
404 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 404 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
405 | if (!oh_name) | 405 | if (!oh_name) |
406 | return -ENODEV; | 406 | return -ENODEV; |
407 | } | 407 | } |
408 | 408 | ||
409 | /* | 409 | /* |
410 | * First check hwmod data is available for sync32k counter | 410 | * First check hwmod data is available for sync32k counter |
411 | */ | 411 | */ |
412 | oh = omap_hwmod_lookup(oh_name); | 412 | oh = omap_hwmod_lookup(oh_name); |
413 | if (!oh || oh->slaves_cnt == 0) | 413 | if (!oh || oh->slaves_cnt == 0) |
414 | return -ENODEV; | 414 | return -ENODEV; |
415 | 415 | ||
416 | omap_hwmod_setup_one(oh_name); | 416 | omap_hwmod_setup_one(oh_name); |
417 | 417 | ||
418 | if (np) { | 418 | if (np) { |
419 | vbase = of_iomap(np, 0); | 419 | vbase = of_iomap(np, 0); |
420 | of_node_put(np); | 420 | of_node_put(np); |
421 | } else { | 421 | } else { |
422 | vbase = omap_hwmod_get_mpu_rt_va(oh); | 422 | vbase = omap_hwmod_get_mpu_rt_va(oh); |
423 | } | 423 | } |
424 | 424 | ||
425 | if (!vbase) { | 425 | if (!vbase) { |
426 | pr_warn("%s: failed to get counter_32k resource\n", __func__); | 426 | pr_warn("%s: failed to get counter_32k resource\n", __func__); |
427 | return -ENXIO; | 427 | return -ENXIO; |
428 | } | 428 | } |
429 | 429 | ||
430 | ret = omap_hwmod_enable(oh); | 430 | ret = omap_hwmod_enable(oh); |
431 | if (ret) { | 431 | if (ret) { |
432 | pr_warn("%s: failed to enable counter_32k module (%d)\n", | 432 | pr_warn("%s: failed to enable counter_32k module (%d)\n", |
433 | __func__, ret); | 433 | __func__, ret); |
434 | return ret; | 434 | return ret; |
435 | } | 435 | } |
436 | 436 | ||
437 | ret = omap_init_clocksource_32k(vbase); | 437 | ret = omap_init_clocksource_32k(vbase); |
438 | if (ret) { | 438 | if (ret) { |
439 | pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", | 439 | pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", |
440 | __func__, ret); | 440 | __func__, ret); |
441 | omap_hwmod_idle(oh); | 441 | omap_hwmod_idle(oh); |
442 | } | 442 | } |
443 | 443 | ||
444 | return ret; | 444 | return ret; |
445 | } | 445 | } |
446 | 446 | ||
447 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, | 447 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, |
448 | const char *fck_source, | 448 | const char *fck_source, |
449 | const char *property) | 449 | const char *property) |
450 | { | 450 | { |
451 | int res; | 451 | int res; |
452 | 452 | ||
453 | clksrc.id = gptimer_id; | 453 | clksrc.id = gptimer_id; |
454 | clksrc.errata = omap_dm_timer_get_errata(); | 454 | clksrc.errata = omap_dm_timer_get_errata(); |
455 | 455 | ||
456 | res = omap_dm_timer_init_one(&clksrc, fck_source, property, | 456 | res = omap_dm_timer_init_one(&clksrc, fck_source, property, |
457 | &clocksource_gpt.name, | 457 | &clocksource_gpt.name, |
458 | OMAP_TIMER_NONPOSTED); | 458 | OMAP_TIMER_NONPOSTED); |
459 | BUG_ON(res); | 459 | BUG_ON(res); |
460 | 460 | ||
461 | __omap_dm_timer_load_start(&clksrc, | 461 | __omap_dm_timer_load_start(&clksrc, |
462 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, | 462 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, |
463 | OMAP_TIMER_NONPOSTED); | 463 | OMAP_TIMER_NONPOSTED); |
464 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); | 464 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); |
465 | 465 | ||
466 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) | 466 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) |
467 | pr_err("Could not register clocksource %s\n", | 467 | pr_err("Could not register clocksource %s\n", |
468 | clocksource_gpt.name); | 468 | clocksource_gpt.name); |
469 | else | 469 | else |
470 | pr_info("OMAP clocksource: %s at %lu Hz\n", | 470 | pr_info("OMAP clocksource: %s at %lu Hz\n", |
471 | clocksource_gpt.name, clksrc.rate); | 471 | clocksource_gpt.name, clksrc.rate); |
472 | } | 472 | } |
473 | 473 | ||
474 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER | 474 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
475 | /* | 475 | /* |
476 | * The realtime counter also called master counter, is a free-running | 476 | * The realtime counter also called master counter, is a free-running |
477 | * counter, which is related to real time. It produces the count used | 477 | * counter, which is related to real time. It produces the count used |
478 | * by the CPU local timer peripherals in the MPU cluster. The timer counts | 478 | * by the CPU local timer peripherals in the MPU cluster. The timer counts |
479 | * at a rate of 6.144 MHz. Because the device operates on different clocks | 479 | * at a rate of 6.144 MHz. Because the device operates on different clocks |
480 | * in different power modes, the master counter shifts operation between | 480 | * in different power modes, the master counter shifts operation between |
481 | * clocks, adjusting the increment per clock in hardware accordingly to | 481 | * clocks, adjusting the increment per clock in hardware accordingly to |
482 | * maintain a constant count rate. | 482 | * maintain a constant count rate. |
483 | */ | 483 | */ |
484 | static void __init realtime_counter_init(void) | 484 | static void __init realtime_counter_init(void) |
485 | { | 485 | { |
486 | void __iomem *base; | 486 | void __iomem *base; |
487 | static struct clk *sys_clk; | 487 | static struct clk *sys_clk; |
488 | unsigned long rate; | 488 | unsigned long rate; |
489 | unsigned int reg, num, den; | 489 | unsigned int reg, num, den; |
490 | 490 | ||
491 | base = ioremap(REALTIME_COUNTER_BASE, SZ_32); | 491 | base = ioremap(REALTIME_COUNTER_BASE, SZ_32); |
492 | if (!base) { | 492 | if (!base) { |
493 | pr_err("%s: ioremap failed\n", __func__); | 493 | pr_err("%s: ioremap failed\n", __func__); |
494 | return; | 494 | return; |
495 | } | 495 | } |
496 | sys_clk = clk_get(NULL, "sys_clkin"); | 496 | sys_clk = clk_get(NULL, "sys_clkin"); |
497 | if (IS_ERR(sys_clk)) { | 497 | if (IS_ERR(sys_clk)) { |
498 | pr_err("%s: failed to get system clock handle\n", __func__); | 498 | pr_err("%s: failed to get system clock handle\n", __func__); |
499 | iounmap(base); | 499 | iounmap(base); |
500 | return; | 500 | return; |
501 | } | 501 | } |
502 | 502 | ||
503 | rate = clk_get_rate(sys_clk); | 503 | rate = clk_get_rate(sys_clk); |
504 | /* Numerator/denumerator values refer TRM Realtime Counter section */ | 504 | /* Numerator/denumerator values refer TRM Realtime Counter section */ |
505 | switch (rate) { | 505 | switch (rate) { |
506 | case 1200000: | 506 | case 1200000: |
507 | num = 64; | 507 | num = 64; |
508 | den = 125; | 508 | den = 125; |
509 | break; | 509 | break; |
510 | case 1300000: | 510 | case 1300000: |
511 | num = 768; | 511 | num = 768; |
512 | den = 1625; | 512 | den = 1625; |
513 | break; | 513 | break; |
514 | case 19200000: | 514 | case 19200000: |
515 | num = 8; | 515 | num = 8; |
516 | den = 25; | 516 | den = 25; |
517 | break; | 517 | break; |
518 | case 2600000: | 518 | case 2600000: |
519 | num = 384; | 519 | num = 384; |
520 | den = 1625; | 520 | den = 1625; |
521 | break; | 521 | break; |
522 | case 2700000: | 522 | case 2700000: |
523 | num = 256; | 523 | num = 256; |
524 | den = 1125; | 524 | den = 1125; |
525 | break; | 525 | break; |
526 | case 38400000: | 526 | case 38400000: |
527 | default: | 527 | default: |
528 | /* Program it for 38.4 MHz */ | 528 | /* Program it for 38.4 MHz */ |
529 | num = 4; | 529 | num = 4; |
530 | den = 25; | 530 | den = 25; |
531 | break; | 531 | break; |
532 | } | 532 | } |
533 | 533 | ||
534 | /* Program numerator and denumerator registers */ | 534 | /* Program numerator and denumerator registers */ |
535 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & | 535 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & |
536 | NUMERATOR_DENUMERATOR_MASK; | 536 | NUMERATOR_DENUMERATOR_MASK; |
537 | reg |= num; | 537 | reg |= num; |
538 | __raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET); | 538 | __raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET); |
539 | 539 | ||
540 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & | 540 | reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & |
541 | NUMERATOR_DENUMERATOR_MASK; | 541 | NUMERATOR_DENUMERATOR_MASK; |
542 | reg |= den; | 542 | reg |= den; |
543 | __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); | 543 | __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); |
544 | 544 | ||
545 | iounmap(base); | 545 | iounmap(base); |
546 | } | 546 | } |
547 | #else | 547 | #else |
548 | static inline void __init realtime_counter_init(void) | 548 | static inline void __init realtime_counter_init(void) |
549 | {} | 549 | {} |
550 | #endif | 550 | #endif |
551 | 551 | ||
552 | #define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ | 552 | #define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ |
553 | clksrc_nr, clksrc_src, clksrc_prop) \ | 553 | clksrc_nr, clksrc_src, clksrc_prop) \ |
554 | void __init omap##name##_gptimer_timer_init(void) \ | 554 | void __init omap##name##_gptimer_timer_init(void) \ |
555 | { \ | 555 | { \ |
556 | if (omap_clk_init) \ | ||
557 | omap_clk_init(); \ | ||
556 | omap_dmtimer_init(); \ | 558 | omap_dmtimer_init(); \ |
557 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ | 559 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ |
558 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ | 560 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ |
559 | clksrc_prop); \ | 561 | clksrc_prop); \ |
560 | } | 562 | } |
561 | 563 | ||
562 | #define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ | 564 | #define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ |
563 | clksrc_nr, clksrc_src, clksrc_prop) \ | 565 | clksrc_nr, clksrc_src, clksrc_prop) \ |
564 | void __init omap##name##_sync32k_timer_init(void) \ | 566 | void __init omap##name##_sync32k_timer_init(void) \ |
565 | { \ | 567 | { \ |
568 | if (omap_clk_init) \ | ||
569 | omap_clk_init(); \ | ||
566 | omap_dmtimer_init(); \ | 570 | omap_dmtimer_init(); \ |
567 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ | 571 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ |
568 | /* Enable the use of clocksource="gp_timer" kernel parameter */ \ | 572 | /* Enable the use of clocksource="gp_timer" kernel parameter */ \ |
569 | if (use_gptimer_clksrc) \ | 573 | if (use_gptimer_clksrc) \ |
570 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ | 574 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ |
571 | clksrc_prop); \ | 575 | clksrc_prop); \ |
572 | else \ | 576 | else \ |
573 | omap2_sync32k_clocksource_init(); \ | 577 | omap2_sync32k_clocksource_init(); \ |
574 | } | 578 | } |
575 | 579 | ||
576 | #ifdef CONFIG_ARCH_OMAP2 | 580 | #ifdef CONFIG_ARCH_OMAP2 |
577 | OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon", | 581 | OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon", |
578 | 2, "timer_sys_ck", NULL); | 582 | 2, "timer_sys_ck", NULL); |
579 | #endif /* CONFIG_ARCH_OMAP2 */ | 583 | #endif /* CONFIG_ARCH_OMAP2 */ |
580 | 584 | ||
581 | #ifdef CONFIG_ARCH_OMAP3 | 585 | #ifdef CONFIG_ARCH_OMAP3 |
582 | OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon", | 586 | OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon", |
583 | 2, "timer_sys_ck", NULL); | 587 | 2, "timer_sys_ck", NULL); |
584 | OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure", | 588 | OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure", |
585 | 2, "timer_sys_ck", NULL); | 589 | 2, "timer_sys_ck", NULL); |
586 | #endif /* CONFIG_ARCH_OMAP3 */ | 590 | #endif /* CONFIG_ARCH_OMAP3 */ |
587 | 591 | ||
588 | #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) | 592 | #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) |
589 | OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL, | 593 | OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL, |
590 | 1, "timer_sys_ck", "ti,timer-alwon"); | 594 | 1, "timer_sys_ck", "ti,timer-alwon"); |
591 | #endif | 595 | #endif |
592 | 596 | ||
593 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) | 597 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) |
594 | static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", | 598 | static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", |
595 | 2, "sys_clkin_ck", NULL); | 599 | 2, "sys_clkin_ck", NULL); |
596 | #endif | 600 | #endif |
597 | 601 | ||
598 | #ifdef CONFIG_ARCH_OMAP4 | 602 | #ifdef CONFIG_ARCH_OMAP4 |
599 | #ifdef CONFIG_LOCAL_TIMERS | 603 | #ifdef CONFIG_LOCAL_TIMERS |
600 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); | 604 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); |
601 | void __init omap4_local_timer_init(void) | 605 | void __init omap4_local_timer_init(void) |
602 | { | 606 | { |
603 | omap4_sync32k_timer_init(); | 607 | omap4_sync32k_timer_init(); |
604 | /* Local timers are not supprted on OMAP4430 ES1.0 */ | 608 | /* Local timers are not supprted on OMAP4430 ES1.0 */ |
605 | if (omap_rev() != OMAP4430_REV_ES1_0) { | 609 | if (omap_rev() != OMAP4430_REV_ES1_0) { |
606 | int err; | 610 | int err; |
607 | 611 | ||
608 | if (of_have_populated_dt()) { | 612 | if (of_have_populated_dt()) { |
609 | clocksource_of_init(); | 613 | clocksource_of_init(); |
610 | return; | 614 | return; |
611 | } | 615 | } |
612 | 616 | ||
613 | err = twd_local_timer_register(&twd_local_timer); | 617 | err = twd_local_timer_register(&twd_local_timer); |
614 | if (err) | 618 | if (err) |
615 | pr_err("twd_local_timer_register failed %d\n", err); | 619 | pr_err("twd_local_timer_register failed %d\n", err); |
616 | } | 620 | } |
617 | } | 621 | } |
618 | #else /* CONFIG_LOCAL_TIMERS */ | 622 | #else /* CONFIG_LOCAL_TIMERS */ |
619 | void __init omap4_local_timer_init(void) | 623 | void __init omap4_local_timer_init(void) |
620 | { | 624 | { |
621 | omap4_sync32k_timer_init(); | 625 | omap4_sync32k_timer_init(); |
622 | } | 626 | } |
623 | #endif /* CONFIG_LOCAL_TIMERS */ | 627 | #endif /* CONFIG_LOCAL_TIMERS */ |
624 | #endif /* CONFIG_ARCH_OMAP4 */ | 628 | #endif /* CONFIG_ARCH_OMAP4 */ |
625 | 629 | ||
626 | #ifdef CONFIG_SOC_OMAP5 | 630 | #ifdef CONFIG_SOC_OMAP5 |
627 | void __init omap5_realtime_timer_init(void) | 631 | void __init omap5_realtime_timer_init(void) |
628 | { | 632 | { |
629 | omap4_sync32k_timer_init(); | 633 | omap4_sync32k_timer_init(); |
630 | realtime_counter_init(); | 634 | realtime_counter_init(); |
631 | 635 | ||
632 | clocksource_of_init(); | 636 | clocksource_of_init(); |
633 | } | 637 | } |
634 | #endif /* CONFIG_SOC_OMAP5 */ | 638 | #endif /* CONFIG_SOC_OMAP5 */ |
635 | 639 | ||
636 | /** | 640 | /** |
637 | * omap_timer_init - build and register timer device with an | 641 | * omap_timer_init - build and register timer device with an |
638 | * associated timer hwmod | 642 | * associated timer hwmod |
639 | * @oh: timer hwmod pointer to be used to build timer device | 643 | * @oh: timer hwmod pointer to be used to build timer device |
640 | * @user: parameter that can be passed from calling hwmod API | 644 | * @user: parameter that can be passed from calling hwmod API |
641 | * | 645 | * |
642 | * Called by omap_hwmod_for_each_by_class to register each of the timer | 646 | * Called by omap_hwmod_for_each_by_class to register each of the timer |
643 | * devices present in the system. The number of timer devices is known | 647 | * devices present in the system. The number of timer devices is known |
644 | * by parsing through the hwmod database for a given class name. At the | 648 | * by parsing through the hwmod database for a given class name. At the |
645 | * end of function call memory is allocated for timer device and it is | 649 | * end of function call memory is allocated for timer device and it is |
646 | * registered to the framework ready to be proved by the driver. | 650 | * registered to the framework ready to be proved by the driver. |
647 | */ | 651 | */ |
648 | static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) | 652 | static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) |
649 | { | 653 | { |
650 | int id; | 654 | int id; |
651 | int ret = 0; | 655 | int ret = 0; |
652 | char *name = "omap_timer"; | 656 | char *name = "omap_timer"; |
653 | struct dmtimer_platform_data *pdata; | 657 | struct dmtimer_platform_data *pdata; |
654 | struct platform_device *pdev; | 658 | struct platform_device *pdev; |
655 | struct omap_timer_capability_dev_attr *timer_dev_attr; | 659 | struct omap_timer_capability_dev_attr *timer_dev_attr; |
656 | 660 | ||
657 | pr_debug("%s: %s\n", __func__, oh->name); | 661 | pr_debug("%s: %s\n", __func__, oh->name); |
658 | 662 | ||
659 | /* on secure device, do not register secure timer */ | 663 | /* on secure device, do not register secure timer */ |
660 | timer_dev_attr = oh->dev_attr; | 664 | timer_dev_attr = oh->dev_attr; |
661 | if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr) | 665 | if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr) |
662 | if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE) | 666 | if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE) |
663 | return ret; | 667 | return ret; |
664 | 668 | ||
665 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 669 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); |
666 | if (!pdata) { | 670 | if (!pdata) { |
667 | pr_err("%s: No memory for [%s]\n", __func__, oh->name); | 671 | pr_err("%s: No memory for [%s]\n", __func__, oh->name); |
668 | return -ENOMEM; | 672 | return -ENOMEM; |
669 | } | 673 | } |
670 | 674 | ||
671 | /* | 675 | /* |
672 | * Extract the IDs from name field in hwmod database | 676 | * Extract the IDs from name field in hwmod database |
673 | * and use the same for constructing ids' for the | 677 | * and use the same for constructing ids' for the |
674 | * timer devices. In a way, we are avoiding usage of | 678 | * timer devices. In a way, we are avoiding usage of |
675 | * static variable witin the function to do the same. | 679 | * static variable witin the function to do the same. |
676 | * CAUTION: We have to be careful and make sure the | 680 | * CAUTION: We have to be careful and make sure the |
677 | * name in hwmod database does not change in which case | 681 | * name in hwmod database does not change in which case |
678 | * we might either make corresponding change here or | 682 | * we might either make corresponding change here or |
679 | * switch back static variable mechanism. | 683 | * switch back static variable mechanism. |
680 | */ | 684 | */ |
681 | sscanf(oh->name, "timer%2d", &id); | 685 | sscanf(oh->name, "timer%2d", &id); |
682 | 686 | ||
683 | if (timer_dev_attr) | 687 | if (timer_dev_attr) |
684 | pdata->timer_capability = timer_dev_attr->timer_capability; | 688 | pdata->timer_capability = timer_dev_attr->timer_capability; |
685 | 689 | ||
686 | pdata->timer_errata = omap_dm_timer_get_errata(); | 690 | pdata->timer_errata = omap_dm_timer_get_errata(); |
687 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; | 691 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; |
688 | 692 | ||
689 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); | 693 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); |
690 | 694 | ||
691 | if (IS_ERR(pdev)) { | 695 | if (IS_ERR(pdev)) { |
692 | pr_err("%s: Can't build omap_device for %s: %s.\n", | 696 | pr_err("%s: Can't build omap_device for %s: %s.\n", |
693 | __func__, name, oh->name); | 697 | __func__, name, oh->name); |
694 | ret = -EINVAL; | 698 | ret = -EINVAL; |
695 | } | 699 | } |
696 | 700 | ||
697 | kfree(pdata); | 701 | kfree(pdata); |
698 | 702 | ||
699 | return ret; | 703 | return ret; |
700 | } | 704 | } |
701 | 705 | ||
702 | /** | 706 | /** |
703 | * omap2_dm_timer_init - top level regular device initialization | 707 | * omap2_dm_timer_init - top level regular device initialization |
704 | * | 708 | * |
705 | * Uses dedicated hwmod api to parse through hwmod database for | 709 | * Uses dedicated hwmod api to parse through hwmod database for |
706 | * given class name and then build and register the timer device. | 710 | * given class name and then build and register the timer device. |
707 | */ | 711 | */ |
708 | static int __init omap2_dm_timer_init(void) | 712 | static int __init omap2_dm_timer_init(void) |
709 | { | 713 | { |
710 | int ret; | 714 | int ret; |
711 | 715 | ||
712 | /* If dtb is there, the devices will be created dynamically */ | 716 | /* If dtb is there, the devices will be created dynamically */ |
713 | if (of_have_populated_dt()) | 717 | if (of_have_populated_dt()) |
714 | return -ENODEV; | 718 | return -ENODEV; |
715 | 719 | ||
716 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); | 720 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); |
717 | if (unlikely(ret)) { | 721 | if (unlikely(ret)) { |
718 | pr_err("%s: device registration failed.\n", __func__); | 722 | pr_err("%s: device registration failed.\n", __func__); |
719 | return -EINVAL; | 723 | return -EINVAL; |
720 | } | 724 | } |
721 | 725 | ||
722 | return 0; | 726 | return 0; |
723 | } | 727 | } |
724 | omap_arch_initcall(omap2_dm_timer_init); | 728 | omap_arch_initcall(omap2_dm_timer_init); |
725 | 729 | ||
726 | /** | 730 | /** |
727 | * omap2_override_clocksource - clocksource override with user configuration | 731 | * omap2_override_clocksource - clocksource override with user configuration |
728 | * | 732 | * |
729 | * Allows user to override default clocksource, using kernel parameter | 733 | * Allows user to override default clocksource, using kernel parameter |
730 | * clocksource="gp_timer" (For all OMAP2PLUS architectures) | 734 | * clocksource="gp_timer" (For all OMAP2PLUS architectures) |
731 | * | 735 | * |
732 | * Note that, here we are using same standard kernel parameter "clocksource=", | 736 | * Note that, here we are using same standard kernel parameter "clocksource=", |
733 | * and not introducing any OMAP specific interface. | 737 | * and not introducing any OMAP specific interface. |
734 | */ | 738 | */ |
735 | static int __init omap2_override_clocksource(char *str) | 739 | static int __init omap2_override_clocksource(char *str) |
736 | { | 740 | { |
737 | if (!str) | 741 | if (!str) |
738 | return 0; | 742 | return 0; |
739 | /* | 743 | /* |
740 | * For OMAP architecture, we only have two options | 744 | * For OMAP architecture, we only have two options |
741 | * - sync_32k (default) | 745 | * - sync_32k (default) |
742 | * - gp_timer (sys_clk based) | 746 | * - gp_timer (sys_clk based) |
743 | */ | 747 | */ |
744 | if (!strcmp(str, "gp_timer")) | 748 | if (!strcmp(str, "gp_timer")) |
745 | use_gptimer_clksrc = true; | 749 | use_gptimer_clksrc = true; |
746 | 750 | ||
747 | return 0; | 751 | return 0; |
748 | } | 752 | } |
749 | early_param("clocksource", omap2_override_clocksource); | 753 | early_param("clocksource", omap2_override_clocksource); |
750 | 754 |