| .. | .. |
|---|
| 26 | 26 | * License. See the file "COPYING" in the main directory of this archive |
|---|
| 27 | 27 | * for more details. |
|---|
| 28 | 28 | */ |
|---|
| 29 | | -#include <linux/init.h> |
|---|
| 30 | | -#include <linux/time.h> |
|---|
| 31 | | -#include <linux/interrupt.h> |
|---|
| 32 | | -#include <linux/err.h> |
|---|
| 33 | 29 | #include <linux/clk.h> |
|---|
| 34 | | -#include <linux/delay.h> |
|---|
| 35 | | -#include <linux/irq.h> |
|---|
| 36 | 30 | #include <linux/clocksource.h> |
|---|
| 37 | | -#include <linux/clockchips.h> |
|---|
| 38 | | -#include <linux/slab.h> |
|---|
| 39 | | -#include <linux/of.h> |
|---|
| 40 | | -#include <linux/of_address.h> |
|---|
| 41 | | -#include <linux/of_irq.h> |
|---|
| 42 | | -#include <linux/platform_device.h> |
|---|
| 43 | | -#include <linux/platform_data/dmtimer-omap.h> |
|---|
| 44 | | -#include <linux/sched_clock.h> |
|---|
| 45 | | - |
|---|
| 46 | | -#include <asm/mach/time.h> |
|---|
| 47 | | -#include <asm/smp_twd.h> |
|---|
| 48 | | - |
|---|
| 49 | | -#include "omap_hwmod.h" |
|---|
| 50 | | -#include "omap_device.h" |
|---|
| 51 | | -#include <plat/counter-32k.h> |
|---|
| 52 | | -#include <clocksource/timer-ti-dm.h> |
|---|
| 53 | 31 | |
|---|
| 54 | 32 | #include "soc.h" |
|---|
| 55 | 33 | #include "common.h" |
|---|
| 56 | 34 | #include "control.h" |
|---|
| 57 | | -#include "powerdomain.h" |
|---|
| 58 | 35 | #include "omap-secure.h" |
|---|
| 59 | 36 | |
|---|
| 60 | 37 | #define REALTIME_COUNTER_BASE 0x48243200 |
|---|
| .. | .. |
|---|
| 62 | 39 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 |
|---|
| 63 | 40 | #define NUMERATOR_DENUMERATOR_MASK 0xfffff000 |
|---|
| 64 | 41 | |
|---|
| 65 | | -/* Clockevent code */ |
|---|
| 66 | | - |
|---|
| 67 | | -/* Clockevent hwmod for am335x and am437x suspend */ |
|---|
| 68 | | -static struct omap_hwmod *clockevent_gpt_hwmod; |
|---|
| 69 | | - |
|---|
| 70 | | -/* Clockesource hwmod for am437x suspend */ |
|---|
| 71 | | -static struct omap_hwmod *clocksource_gpt_hwmod; |
|---|
| 72 | | - |
|---|
| 73 | | -struct dmtimer_clockevent { |
|---|
| 74 | | - struct clock_event_device dev; |
|---|
| 75 | | - struct omap_dm_timer timer; |
|---|
| 76 | | -}; |
|---|
| 77 | | - |
|---|
| 78 | | -static struct dmtimer_clockevent clockevent; |
|---|
| 79 | | - |
|---|
| 80 | | -static struct omap_dm_timer *to_dmtimer(struct clock_event_device *clockevent) |
|---|
| 81 | | -{ |
|---|
| 82 | | - struct dmtimer_clockevent *clkevt = |
|---|
| 83 | | - container_of(clockevent, struct dmtimer_clockevent, dev); |
|---|
| 84 | | - struct omap_dm_timer *timer = &clkevt->timer; |
|---|
| 85 | | - |
|---|
| 86 | | - return timer; |
|---|
| 87 | | -} |
|---|
| 88 | | - |
|---|
| 89 | | -#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
|---|
| 90 | 42 | static unsigned long arch_timer_freq; |
|---|
| 91 | 43 | |
|---|
| 92 | 44 | void set_cntfreq(void) |
|---|
| 93 | 45 | { |
|---|
| 94 | 46 | omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq); |
|---|
| 95 | 47 | } |
|---|
| 96 | | -#endif |
|---|
| 97 | | - |
|---|
| 98 | | -static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) |
|---|
| 99 | | -{ |
|---|
| 100 | | - struct dmtimer_clockevent *clkevt = dev_id; |
|---|
| 101 | | - struct clock_event_device *evt = &clkevt->dev; |
|---|
| 102 | | - struct omap_dm_timer *timer = &clkevt->timer; |
|---|
| 103 | | - |
|---|
| 104 | | - __omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW); |
|---|
| 105 | | - evt->event_handler(evt); |
|---|
| 106 | | - return IRQ_HANDLED; |
|---|
| 107 | | -} |
|---|
| 108 | | - |
|---|
| 109 | | -static int omap2_gp_timer_set_next_event(unsigned long cycles, |
|---|
| 110 | | - struct clock_event_device *evt) |
|---|
| 111 | | -{ |
|---|
| 112 | | - struct omap_dm_timer *timer = to_dmtimer(evt); |
|---|
| 113 | | - |
|---|
| 114 | | - __omap_dm_timer_load_start(timer, OMAP_TIMER_CTRL_ST, |
|---|
| 115 | | - 0xffffffff - cycles, OMAP_TIMER_POSTED); |
|---|
| 116 | | - |
|---|
| 117 | | - return 0; |
|---|
| 118 | | -} |
|---|
| 119 | | - |
|---|
| 120 | | -static int omap2_gp_timer_shutdown(struct clock_event_device *evt) |
|---|
| 121 | | -{ |
|---|
| 122 | | - struct omap_dm_timer *timer = to_dmtimer(evt); |
|---|
| 123 | | - |
|---|
| 124 | | - __omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate); |
|---|
| 125 | | - |
|---|
| 126 | | - return 0; |
|---|
| 127 | | -} |
|---|
| 128 | | - |
|---|
| 129 | | -static int omap2_gp_timer_set_periodic(struct clock_event_device *evt) |
|---|
| 130 | | -{ |
|---|
| 131 | | - struct omap_dm_timer *timer = to_dmtimer(evt); |
|---|
| 132 | | - u32 period; |
|---|
| 133 | | - |
|---|
| 134 | | - __omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate); |
|---|
| 135 | | - |
|---|
| 136 | | - period = timer->rate / HZ; |
|---|
| 137 | | - period -= 1; |
|---|
| 138 | | - /* Looks like we need to first set the load value separately */ |
|---|
| 139 | | - __omap_dm_timer_write(timer, OMAP_TIMER_LOAD_REG, 0xffffffff - period, |
|---|
| 140 | | - OMAP_TIMER_POSTED); |
|---|
| 141 | | - __omap_dm_timer_load_start(timer, |
|---|
| 142 | | - OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, |
|---|
| 143 | | - 0xffffffff - period, OMAP_TIMER_POSTED); |
|---|
| 144 | | - return 0; |
|---|
| 145 | | -} |
|---|
| 146 | | - |
|---|
| 147 | | -static void omap_clkevt_idle(struct clock_event_device *unused) |
|---|
| 148 | | -{ |
|---|
| 149 | | - if (!clockevent_gpt_hwmod) |
|---|
| 150 | | - return; |
|---|
| 151 | | - |
|---|
| 152 | | - omap_hwmod_idle(clockevent_gpt_hwmod); |
|---|
| 153 | | -} |
|---|
| 154 | | - |
|---|
| 155 | | -static void omap_clkevt_unidle(struct clock_event_device *evt) |
|---|
| 156 | | -{ |
|---|
| 157 | | - struct omap_dm_timer *timer = to_dmtimer(evt); |
|---|
| 158 | | - |
|---|
| 159 | | - if (!clockevent_gpt_hwmod) |
|---|
| 160 | | - return; |
|---|
| 161 | | - |
|---|
| 162 | | - omap_hwmod_enable(clockevent_gpt_hwmod); |
|---|
| 163 | | - __omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW); |
|---|
| 164 | | -} |
|---|
| 165 | | - |
|---|
| 166 | | -static const struct of_device_id omap_timer_match[] __initconst = { |
|---|
| 167 | | - { .compatible = "ti,omap2420-timer", }, |
|---|
| 168 | | - { .compatible = "ti,omap3430-timer", }, |
|---|
| 169 | | - { .compatible = "ti,omap4430-timer", }, |
|---|
| 170 | | - { .compatible = "ti,omap5430-timer", }, |
|---|
| 171 | | - { .compatible = "ti,dm814-timer", }, |
|---|
| 172 | | - { .compatible = "ti,dm816-timer", }, |
|---|
| 173 | | - { .compatible = "ti,am335x-timer", }, |
|---|
| 174 | | - { .compatible = "ti,am335x-timer-1ms", }, |
|---|
| 175 | | - { } |
|---|
| 176 | | -}; |
|---|
| 177 | | - |
|---|
| 178 | | -static int omap_timer_add_disabled_property(struct device_node *np) |
|---|
| 179 | | -{ |
|---|
| 180 | | - struct property *prop; |
|---|
| 181 | | - |
|---|
| 182 | | - prop = kzalloc(sizeof(*prop), GFP_KERNEL); |
|---|
| 183 | | - if (!prop) |
|---|
| 184 | | - return -ENOMEM; |
|---|
| 185 | | - |
|---|
| 186 | | - prop->name = "status"; |
|---|
| 187 | | - prop->value = "disabled"; |
|---|
| 188 | | - prop->length = strlen(prop->value); |
|---|
| 189 | | - |
|---|
| 190 | | - return of_add_property(np, prop); |
|---|
| 191 | | -} |
|---|
| 192 | | - |
|---|
| 193 | | -static int omap_timer_update_dt(struct device_node *np) |
|---|
| 194 | | -{ |
|---|
| 195 | | - int error = 0; |
|---|
| 196 | | - |
|---|
| 197 | | - if (!of_device_is_compatible(np, "ti,omap-counter32k")) { |
|---|
| 198 | | - error = omap_timer_add_disabled_property(np); |
|---|
| 199 | | - if (error) |
|---|
| 200 | | - return error; |
|---|
| 201 | | - } |
|---|
| 202 | | - |
|---|
| 203 | | - /* No parent interconnect target module configured? */ |
|---|
| 204 | | - if (of_get_property(np, "ti,hwmods", NULL)) |
|---|
| 205 | | - return error; |
|---|
| 206 | | - |
|---|
| 207 | | - /* Tag parent interconnect target module disabled */ |
|---|
| 208 | | - error = omap_timer_add_disabled_property(np->parent); |
|---|
| 209 | | - if (error) |
|---|
| 210 | | - return error; |
|---|
| 211 | | - |
|---|
| 212 | | - return 0; |
|---|
| 213 | | -} |
|---|
| 214 | | - |
|---|
| 215 | | -/** |
|---|
| 216 | | - * omap_get_timer_dt - get a timer using device-tree |
|---|
| 217 | | - * @match - device-tree match structure for matching a device type |
|---|
| 218 | | - * @property - optional timer property to match |
|---|
| 219 | | - * |
|---|
| 220 | | - * Helper function to get a timer during early boot using device-tree for use |
|---|
| 221 | | - * as kernel system timer. Optionally, the property argument can be used to |
|---|
| 222 | | - * select a timer with a specific property. Once a timer is found then mark |
|---|
| 223 | | - * the timer node in device-tree as disabled, to prevent the kernel from |
|---|
| 224 | | - * registering this timer as a platform device and so no one else can use it. |
|---|
| 225 | | - */ |
|---|
| 226 | | -static struct device_node * __init omap_get_timer_dt(const struct of_device_id *match, |
|---|
| 227 | | - const char *property) |
|---|
| 228 | | -{ |
|---|
| 229 | | - struct device_node *np; |
|---|
| 230 | | - int error; |
|---|
| 231 | | - |
|---|
| 232 | | - for_each_matching_node(np, match) { |
|---|
| 233 | | - if (!of_device_is_available(np)) |
|---|
| 234 | | - continue; |
|---|
| 235 | | - |
|---|
| 236 | | - if (property && !of_get_property(np, property, NULL)) |
|---|
| 237 | | - continue; |
|---|
| 238 | | - |
|---|
| 239 | | - if (!property && (of_get_property(np, "ti,timer-alwon", NULL) || |
|---|
| 240 | | - of_get_property(np, "ti,timer-dsp", NULL) || |
|---|
| 241 | | - of_get_property(np, "ti,timer-pwm", NULL) || |
|---|
| 242 | | - of_get_property(np, "ti,timer-secure", NULL))) |
|---|
| 243 | | - continue; |
|---|
| 244 | | - |
|---|
| 245 | | - error = omap_timer_update_dt(np); |
|---|
| 246 | | - WARN(error, "%s: Could not update dt: %i\n", __func__, error); |
|---|
| 247 | | - |
|---|
| 248 | | - return np; |
|---|
| 249 | | - } |
|---|
| 250 | | - |
|---|
| 251 | | - return NULL; |
|---|
| 252 | | -} |
|---|
| 253 | | - |
|---|
| 254 | | -/** |
|---|
| 255 | | - * omap_dmtimer_init - initialisation function when device tree is used |
|---|
| 256 | | - * |
|---|
| 257 | | - * For secure OMAP3/DRA7xx devices, timers with device type "timer-secure" |
|---|
| 258 | | - * cannot be used by the kernel as they are reserved. Therefore, to prevent the |
|---|
| 259 | | - * kernel registering these devices remove them dynamically from the device |
|---|
| 260 | | - * tree on boot. |
|---|
| 261 | | - */ |
|---|
| 262 | | -static void __init omap_dmtimer_init(void) |
|---|
| 263 | | -{ |
|---|
| 264 | | - struct device_node *np; |
|---|
| 265 | | - |
|---|
| 266 | | - if (!cpu_is_omap34xx() && !soc_is_dra7xx()) |
|---|
| 267 | | - return; |
|---|
| 268 | | - |
|---|
| 269 | | - /* If we are a secure device, remove any secure timer nodes */ |
|---|
| 270 | | - if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { |
|---|
| 271 | | - np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure"); |
|---|
| 272 | | - of_node_put(np); |
|---|
| 273 | | - } |
|---|
| 274 | | -} |
|---|
| 275 | | - |
|---|
| 276 | | -/** |
|---|
| 277 | | - * omap_dm_timer_get_errata - get errata flags for a timer |
|---|
| 278 | | - * |
|---|
| 279 | | - * Get the timer errata flags that are specific to the OMAP device being used. |
|---|
| 280 | | - */ |
|---|
| 281 | | -static u32 __init omap_dm_timer_get_errata(void) |
|---|
| 282 | | -{ |
|---|
| 283 | | - if (cpu_is_omap24xx()) |
|---|
| 284 | | - return 0; |
|---|
| 285 | | - |
|---|
| 286 | | - return OMAP_TIMER_ERRATA_I103_I767; |
|---|
| 287 | | -} |
|---|
| 288 | | - |
|---|
| 289 | | -static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
|---|
| 290 | | - const char *fck_source, |
|---|
| 291 | | - const char *property, |
|---|
| 292 | | - const char **timer_name, |
|---|
| 293 | | - int posted) |
|---|
| 294 | | -{ |
|---|
| 295 | | - const char *oh_name = NULL; |
|---|
| 296 | | - struct device_node *np; |
|---|
| 297 | | - struct omap_hwmod *oh; |
|---|
| 298 | | - struct clk *src; |
|---|
| 299 | | - int r = 0; |
|---|
| 300 | | - |
|---|
| 301 | | - np = omap_get_timer_dt(omap_timer_match, property); |
|---|
| 302 | | - if (!np) |
|---|
| 303 | | - return -ENODEV; |
|---|
| 304 | | - |
|---|
| 305 | | - of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
|---|
| 306 | | - if (!oh_name) { |
|---|
| 307 | | - of_property_read_string_index(np->parent, "ti,hwmods", 0, |
|---|
| 308 | | - &oh_name); |
|---|
| 309 | | - if (!oh_name) |
|---|
| 310 | | - return -ENODEV; |
|---|
| 311 | | - } |
|---|
| 312 | | - |
|---|
| 313 | | - timer->irq = irq_of_parse_and_map(np, 0); |
|---|
| 314 | | - if (!timer->irq) |
|---|
| 315 | | - return -ENXIO; |
|---|
| 316 | | - |
|---|
| 317 | | - timer->io_base = of_iomap(np, 0); |
|---|
| 318 | | - |
|---|
| 319 | | - timer->fclk = of_clk_get_by_name(np, "fck"); |
|---|
| 320 | | - |
|---|
| 321 | | - of_node_put(np); |
|---|
| 322 | | - |
|---|
| 323 | | - oh = omap_hwmod_lookup(oh_name); |
|---|
| 324 | | - if (!oh) |
|---|
| 325 | | - return -ENODEV; |
|---|
| 326 | | - |
|---|
| 327 | | - *timer_name = oh->name; |
|---|
| 328 | | - |
|---|
| 329 | | - if (!timer->io_base) |
|---|
| 330 | | - return -ENXIO; |
|---|
| 331 | | - |
|---|
| 332 | | - omap_hwmod_setup_one(oh_name); |
|---|
| 333 | | - |
|---|
| 334 | | - /* After the dmtimer is using hwmod these clocks won't be needed */ |
|---|
| 335 | | - if (IS_ERR_OR_NULL(timer->fclk)) |
|---|
| 336 | | - timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); |
|---|
| 337 | | - if (IS_ERR(timer->fclk)) |
|---|
| 338 | | - return PTR_ERR(timer->fclk); |
|---|
| 339 | | - |
|---|
| 340 | | - src = clk_get(NULL, fck_source); |
|---|
| 341 | | - if (IS_ERR(src)) |
|---|
| 342 | | - return PTR_ERR(src); |
|---|
| 343 | | - |
|---|
| 344 | | - WARN(clk_set_parent(timer->fclk, src) < 0, |
|---|
| 345 | | - "Cannot set timer parent clock, no PLL clock driver?"); |
|---|
| 346 | | - |
|---|
| 347 | | - clk_put(src); |
|---|
| 348 | | - |
|---|
| 349 | | - omap_hwmod_enable(oh); |
|---|
| 350 | | - __omap_dm_timer_init_regs(timer); |
|---|
| 351 | | - |
|---|
| 352 | | - if (posted) |
|---|
| 353 | | - __omap_dm_timer_enable_posted(timer); |
|---|
| 354 | | - |
|---|
| 355 | | - /* Check that the intended posted configuration matches the actual */ |
|---|
| 356 | | - if (posted != timer->posted) |
|---|
| 357 | | - return -EINVAL; |
|---|
| 358 | | - |
|---|
| 359 | | - timer->rate = clk_get_rate(timer->fclk); |
|---|
| 360 | | - timer->reserved = 1; |
|---|
| 361 | | - |
|---|
| 362 | | - return r; |
|---|
| 363 | | -} |
|---|
| 364 | | - |
|---|
| 365 | | -#if !defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) |
|---|
| 366 | | -void tick_broadcast(const struct cpumask *mask) |
|---|
| 367 | | -{ |
|---|
| 368 | | -} |
|---|
| 369 | | -#endif |
|---|
| 370 | | - |
|---|
| 371 | | -static void __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, |
|---|
| 372 | | - int gptimer_id, |
|---|
| 373 | | - const char *fck_source, |
|---|
| 374 | | - unsigned int features, |
|---|
| 375 | | - const struct cpumask *cpumask, |
|---|
| 376 | | - const char *property, |
|---|
| 377 | | - int rating, const char *name) |
|---|
| 378 | | -{ |
|---|
| 379 | | - struct omap_dm_timer *timer = &clkevt->timer; |
|---|
| 380 | | - int res; |
|---|
| 381 | | - |
|---|
| 382 | | - timer->id = gptimer_id; |
|---|
| 383 | | - timer->errata = omap_dm_timer_get_errata(); |
|---|
| 384 | | - clkevt->dev.features = features; |
|---|
| 385 | | - clkevt->dev.rating = rating; |
|---|
| 386 | | - clkevt->dev.set_next_event = omap2_gp_timer_set_next_event; |
|---|
| 387 | | - clkevt->dev.set_state_shutdown = omap2_gp_timer_shutdown; |
|---|
| 388 | | - clkevt->dev.set_state_periodic = omap2_gp_timer_set_periodic; |
|---|
| 389 | | - clkevt->dev.set_state_oneshot = omap2_gp_timer_shutdown; |
|---|
| 390 | | - clkevt->dev.tick_resume = omap2_gp_timer_shutdown; |
|---|
| 391 | | - |
|---|
| 392 | | - /* |
|---|
| 393 | | - * For clock-event timers we never read the timer counter and |
|---|
| 394 | | - * so we are not impacted by errata i103 and i767. Therefore, |
|---|
| 395 | | - * we can safely ignore this errata for clock-event timers. |
|---|
| 396 | | - */ |
|---|
| 397 | | - __omap_dm_timer_override_errata(timer, OMAP_TIMER_ERRATA_I103_I767); |
|---|
| 398 | | - |
|---|
| 399 | | - res = omap_dm_timer_init_one(timer, fck_source, property, |
|---|
| 400 | | - &clkevt->dev.name, OMAP_TIMER_POSTED); |
|---|
| 401 | | - BUG_ON(res); |
|---|
| 402 | | - |
|---|
| 403 | | - clkevt->dev.cpumask = cpumask; |
|---|
| 404 | | - clkevt->dev.irq = omap_dm_timer_get_irq(timer); |
|---|
| 405 | | - |
|---|
| 406 | | - if (request_irq(clkevt->dev.irq, omap2_gp_timer_interrupt, |
|---|
| 407 | | - IRQF_TIMER | IRQF_IRQPOLL, name, clkevt)) |
|---|
| 408 | | - pr_err("Failed to request irq %d (gp_timer)\n", clkevt->dev.irq); |
|---|
| 409 | | - |
|---|
| 410 | | - __omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW); |
|---|
| 411 | | - |
|---|
| 412 | | - if (soc_is_am33xx() || soc_is_am43xx()) { |
|---|
| 413 | | - clkevt->dev.suspend = omap_clkevt_idle; |
|---|
| 414 | | - clkevt->dev.resume = omap_clkevt_unidle; |
|---|
| 415 | | - |
|---|
| 416 | | - clockevent_gpt_hwmod = |
|---|
| 417 | | - omap_hwmod_lookup(clkevt->dev.name); |
|---|
| 418 | | - } |
|---|
| 419 | | - |
|---|
| 420 | | - pr_info("OMAP clockevent source: %s at %lu Hz\n", clkevt->dev.name, |
|---|
| 421 | | - timer->rate); |
|---|
| 422 | | -} |
|---|
| 423 | | - |
|---|
| 424 | | -/* Clocksource code */ |
|---|
| 425 | | -static struct omap_dm_timer clksrc; |
|---|
| 426 | | -static bool use_gptimer_clksrc __initdata; |
|---|
| 427 | | - |
|---|
| 428 | | -/* |
|---|
| 429 | | - * clocksource |
|---|
| 430 | | - */ |
|---|
| 431 | | -static u64 clocksource_read_cycles(struct clocksource *cs) |
|---|
| 432 | | -{ |
|---|
| 433 | | - return (u64)__omap_dm_timer_read_counter(&clksrc, |
|---|
| 434 | | - OMAP_TIMER_NONPOSTED); |
|---|
| 435 | | -} |
|---|
| 436 | | - |
|---|
| 437 | | -static struct clocksource clocksource_gpt = { |
|---|
| 438 | | - .rating = 300, |
|---|
| 439 | | - .read = clocksource_read_cycles, |
|---|
| 440 | | - .mask = CLOCKSOURCE_MASK(32), |
|---|
| 441 | | - .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
|---|
| 442 | | -}; |
|---|
| 443 | | - |
|---|
| 444 | | -static u64 notrace dmtimer_read_sched_clock(void) |
|---|
| 445 | | -{ |
|---|
| 446 | | - if (clksrc.reserved) |
|---|
| 447 | | - return __omap_dm_timer_read_counter(&clksrc, |
|---|
| 448 | | - OMAP_TIMER_NONPOSTED); |
|---|
| 449 | | - |
|---|
| 450 | | - return 0; |
|---|
| 451 | | -} |
|---|
| 452 | | - |
|---|
| 453 | | -static const struct of_device_id omap_counter_match[] __initconst = { |
|---|
| 454 | | - { .compatible = "ti,omap-counter32k", }, |
|---|
| 455 | | - { } |
|---|
| 456 | | -}; |
|---|
| 457 | | - |
|---|
| 458 | | -/* Setup free-running counter for clocksource */ |
|---|
| 459 | | -static int __init __maybe_unused omap2_sync32k_clocksource_init(void) |
|---|
| 460 | | -{ |
|---|
| 461 | | - int ret; |
|---|
| 462 | | - struct device_node *np = NULL; |
|---|
| 463 | | - struct omap_hwmod *oh; |
|---|
| 464 | | - const char *oh_name = "counter_32k"; |
|---|
| 465 | | - |
|---|
| 466 | | - /* |
|---|
| 467 | | - * See if the 32kHz counter is supported. |
|---|
| 468 | | - */ |
|---|
| 469 | | - np = omap_get_timer_dt(omap_counter_match, NULL); |
|---|
| 470 | | - if (!np) |
|---|
| 471 | | - return -ENODEV; |
|---|
| 472 | | - |
|---|
| 473 | | - of_property_read_string_index(np->parent, "ti,hwmods", 0, &oh_name); |
|---|
| 474 | | - if (!oh_name) { |
|---|
| 475 | | - of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
|---|
| 476 | | - if (!oh_name) |
|---|
| 477 | | - return -ENODEV; |
|---|
| 478 | | - } |
|---|
| 479 | | - |
|---|
| 480 | | - /* |
|---|
| 481 | | - * First check hwmod data is available for sync32k counter |
|---|
| 482 | | - */ |
|---|
| 483 | | - oh = omap_hwmod_lookup(oh_name); |
|---|
| 484 | | - if (!oh || oh->slaves_cnt == 0) |
|---|
| 485 | | - return -ENODEV; |
|---|
| 486 | | - |
|---|
| 487 | | - omap_hwmod_setup_one(oh_name); |
|---|
| 488 | | - |
|---|
| 489 | | - ret = omap_hwmod_enable(oh); |
|---|
| 490 | | - if (ret) { |
|---|
| 491 | | - pr_warn("%s: failed to enable counter_32k module (%d)\n", |
|---|
| 492 | | - __func__, ret); |
|---|
| 493 | | - return ret; |
|---|
| 494 | | - } |
|---|
| 495 | | - |
|---|
| 496 | | - return ret; |
|---|
| 497 | | -} |
|---|
| 498 | | - |
|---|
| 499 | | -static unsigned int omap2_gptimer_clksrc_load; |
|---|
| 500 | | - |
|---|
| 501 | | -static void omap2_gptimer_clksrc_suspend(struct clocksource *unused) |
|---|
| 502 | | -{ |
|---|
| 503 | | - omap2_gptimer_clksrc_load = |
|---|
| 504 | | - __omap_dm_timer_read_counter(&clksrc, OMAP_TIMER_NONPOSTED); |
|---|
| 505 | | - |
|---|
| 506 | | - omap_hwmod_idle(clocksource_gpt_hwmod); |
|---|
| 507 | | -} |
|---|
| 508 | | - |
|---|
| 509 | | -static void omap2_gptimer_clksrc_resume(struct clocksource *unused) |
|---|
| 510 | | -{ |
|---|
| 511 | | - omap_hwmod_enable(clocksource_gpt_hwmod); |
|---|
| 512 | | - |
|---|
| 513 | | - __omap_dm_timer_load_start(&clksrc, |
|---|
| 514 | | - OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, |
|---|
| 515 | | - omap2_gptimer_clksrc_load, |
|---|
| 516 | | - OMAP_TIMER_NONPOSTED); |
|---|
| 517 | | -} |
|---|
| 518 | | - |
|---|
| 519 | | -static void __init omap2_gptimer_clocksource_init(int gptimer_id, |
|---|
| 520 | | - const char *fck_source, |
|---|
| 521 | | - const char *property) |
|---|
| 522 | | -{ |
|---|
| 523 | | - int res; |
|---|
| 524 | | - |
|---|
| 525 | | - clksrc.id = gptimer_id; |
|---|
| 526 | | - clksrc.errata = omap_dm_timer_get_errata(); |
|---|
| 527 | | - |
|---|
| 528 | | - res = omap_dm_timer_init_one(&clksrc, fck_source, property, |
|---|
| 529 | | - &clocksource_gpt.name, |
|---|
| 530 | | - OMAP_TIMER_NONPOSTED); |
|---|
| 531 | | - |
|---|
| 532 | | - if (soc_is_am43xx()) { |
|---|
| 533 | | - clocksource_gpt.suspend = omap2_gptimer_clksrc_suspend; |
|---|
| 534 | | - clocksource_gpt.resume = omap2_gptimer_clksrc_resume; |
|---|
| 535 | | - |
|---|
| 536 | | - clocksource_gpt_hwmod = |
|---|
| 537 | | - omap_hwmod_lookup(clocksource_gpt.name); |
|---|
| 538 | | - } |
|---|
| 539 | | - |
|---|
| 540 | | - BUG_ON(res); |
|---|
| 541 | | - |
|---|
| 542 | | - __omap_dm_timer_load_start(&clksrc, |
|---|
| 543 | | - OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, |
|---|
| 544 | | - OMAP_TIMER_NONPOSTED); |
|---|
| 545 | | - sched_clock_register(dmtimer_read_sched_clock, 32, clksrc.rate); |
|---|
| 546 | | - |
|---|
| 547 | | - if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) |
|---|
| 548 | | - pr_err("Could not register clocksource %s\n", |
|---|
| 549 | | - clocksource_gpt.name); |
|---|
| 550 | | - else |
|---|
| 551 | | - pr_info("OMAP clocksource: %s at %lu Hz\n", |
|---|
| 552 | | - clocksource_gpt.name, clksrc.rate); |
|---|
| 553 | | -} |
|---|
| 554 | | - |
|---|
| 555 | | -static void __init __omap_sync32k_timer_init(int clkev_nr, const char *clkev_src, |
|---|
| 556 | | - const char *clkev_prop, int clksrc_nr, const char *clksrc_src, |
|---|
| 557 | | - const char *clksrc_prop, bool gptimer) |
|---|
| 558 | | -{ |
|---|
| 559 | | - omap_clk_init(); |
|---|
| 560 | | - omap_dmtimer_init(); |
|---|
| 561 | | - dmtimer_clkevt_init_common(&clockevent, clkev_nr, clkev_src, |
|---|
| 562 | | - CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
|---|
| 563 | | - cpu_possible_mask, clkev_prop, 300, "clockevent"); |
|---|
| 564 | | - clockevents_config_and_register(&clockevent.dev, clockevent.timer.rate, |
|---|
| 565 | | - 3, /* Timer internal resynch latency */ |
|---|
| 566 | | - 0xffffffff); |
|---|
| 567 | | - |
|---|
| 568 | | - /* Enable the use of clocksource="gp_timer" kernel parameter */ |
|---|
| 569 | | - if (use_gptimer_clksrc || gptimer) |
|---|
| 570 | | - omap2_gptimer_clocksource_init(clksrc_nr, clksrc_src, |
|---|
| 571 | | - clksrc_prop); |
|---|
| 572 | | - else |
|---|
| 573 | | - omap2_sync32k_clocksource_init(); |
|---|
| 574 | | -} |
|---|
| 575 | | - |
|---|
| 576 | | -void __init omap_init_time(void) |
|---|
| 577 | | -{ |
|---|
| 578 | | - __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", |
|---|
| 579 | | - 2, "timer_sys_ck", NULL, false); |
|---|
| 580 | | - |
|---|
| 581 | | - timer_probe(); |
|---|
| 582 | | -} |
|---|
| 583 | | - |
|---|
| 584 | | -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) |
|---|
| 585 | | -void __init omap3_secure_sync32k_timer_init(void) |
|---|
| 586 | | -{ |
|---|
| 587 | | - __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure", |
|---|
| 588 | | - 2, "timer_sys_ck", NULL, false); |
|---|
| 589 | | - |
|---|
| 590 | | - timer_probe(); |
|---|
| 591 | | -} |
|---|
| 592 | | -#endif /* CONFIG_ARCH_OMAP3 */ |
|---|
| 593 | | - |
|---|
| 594 | | -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \ |
|---|
| 595 | | - defined(CONFIG_SOC_AM43XX) |
|---|
| 596 | | -void __init omap3_gptimer_timer_init(void) |
|---|
| 597 | | -{ |
|---|
| 598 | | - __omap_sync32k_timer_init(2, "timer_sys_ck", NULL, |
|---|
| 599 | | - 1, "timer_sys_ck", "ti,timer-alwon", true); |
|---|
| 600 | | - if (of_have_populated_dt()) |
|---|
| 601 | | - timer_probe(); |
|---|
| 602 | | -} |
|---|
| 603 | | -#endif |
|---|
| 604 | | - |
|---|
| 605 | | -#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ |
|---|
| 606 | | - defined(CONFIG_SOC_DRA7XX) |
|---|
| 607 | | -static void __init omap4_sync32k_timer_init(void) |
|---|
| 608 | | -{ |
|---|
| 609 | | - __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", |
|---|
| 610 | | - 2, "sys_clkin_ck", NULL, false); |
|---|
| 611 | | -} |
|---|
| 612 | | - |
|---|
| 613 | | -void __init omap4_local_timer_init(void) |
|---|
| 614 | | -{ |
|---|
| 615 | | - omap4_sync32k_timer_init(); |
|---|
| 616 | | - timer_probe(); |
|---|
| 617 | | -} |
|---|
| 618 | | -#endif |
|---|
| 619 | | - |
|---|
| 620 | | -#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX) |
|---|
| 621 | 48 | |
|---|
| 622 | 49 | /* |
|---|
| 623 | 50 | * The realtime counter also called master counter, is a free-running |
|---|
| .. | .. |
|---|
| 630 | 57 | */ |
|---|
| 631 | 58 | static void __init realtime_counter_init(void) |
|---|
| 632 | 59 | { |
|---|
| 633 | | -#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
|---|
| 634 | 60 | void __iomem *base; |
|---|
| 635 | 61 | static struct clk *sys_clk; |
|---|
| 636 | 62 | unsigned long rate; |
|---|
| .. | .. |
|---|
| 650 | 76 | } |
|---|
| 651 | 77 | |
|---|
| 652 | 78 | rate = clk_get_rate(sys_clk); |
|---|
| 79 | + clk_put(sys_clk); |
|---|
| 653 | 80 | |
|---|
| 654 | 81 | if (soc_is_dra7xx()) { |
|---|
| 655 | 82 | /* |
|---|
| .. | .. |
|---|
| 729 | 156 | set_cntfreq(); |
|---|
| 730 | 157 | |
|---|
| 731 | 158 | iounmap(base); |
|---|
| 732 | | -#endif |
|---|
| 733 | 159 | } |
|---|
| 734 | 160 | |
|---|
| 735 | 161 | void __init omap5_realtime_timer_init(void) |
|---|
| 736 | 162 | { |
|---|
| 737 | | - omap4_sync32k_timer_init(); |
|---|
| 163 | + omap_clk_init(); |
|---|
| 738 | 164 | realtime_counter_init(); |
|---|
| 739 | 165 | |
|---|
| 740 | 166 | timer_probe(); |
|---|
| 741 | 167 | } |
|---|
| 742 | | -#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ |
|---|
| 743 | | - |
|---|
| 744 | | -/** |
|---|
| 745 | | - * omap2_override_clocksource - clocksource override with user configuration |
|---|
| 746 | | - * |
|---|
| 747 | | - * Allows user to override default clocksource, using kernel parameter |
|---|
| 748 | | - * clocksource="gp_timer" (For all OMAP2PLUS architectures) |
|---|
| 749 | | - * |
|---|
| 750 | | - * Note that, here we are using same standard kernel parameter "clocksource=", |
|---|
| 751 | | - * and not introducing any OMAP specific interface. |
|---|
| 752 | | - */ |
|---|
| 753 | | -static int __init omap2_override_clocksource(char *str) |
|---|
| 754 | | -{ |
|---|
| 755 | | - if (!str) |
|---|
| 756 | | - return 0; |
|---|
| 757 | | - /* |
|---|
| 758 | | - * For OMAP architecture, we only have two options |
|---|
| 759 | | - * - sync_32k (default) |
|---|
| 760 | | - * - gp_timer (sys_clk based) |
|---|
| 761 | | - */ |
|---|
| 762 | | - if (!strcmp(str, "gp_timer")) |
|---|
| 763 | | - use_gptimer_clksrc = true; |
|---|
| 764 | | - |
|---|
| 765 | | - return 0; |
|---|
| 766 | | -} |
|---|
| 767 | | -early_param("clocksource", omap2_override_clocksource); |
|---|