root/arch/arm/mach-omap2/timer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_cntfreq
  2. omap2_gp_timer_interrupt
  3. omap2_gp_timer_set_next_event
  4. omap2_gp_timer_shutdown
  5. omap2_gp_timer_set_periodic
  6. omap_clkevt_idle
  7. omap_clkevt_unidle
  8. omap_timer_add_disabled_property
  9. omap_timer_update_dt
  10. omap_get_timer_dt
  11. omap_dmtimer_init
  12. omap_dm_timer_get_errata
  13. omap_dm_timer_init_one
  14. tick_broadcast
  15. omap2_gp_clockevent_init
  16. clocksource_read_cycles
  17. dmtimer_read_sched_clock
  18. omap2_sync32k_clocksource_init
  19. omap2_gptimer_clksrc_suspend
  20. omap2_gptimer_clksrc_resume
  21. omap2_gptimer_clocksource_init
  22. __omap_sync32k_timer_init
  23. omap_init_time
  24. omap3_secure_sync32k_timer_init
  25. omap3_gptimer_timer_init
  26. omap4_sync32k_timer_init
  27. omap4_local_timer_init
  28. realtime_counter_init
  29. omap5_realtime_timer_init
  30. omap2_override_clocksource

   1 /*
   2  * linux/arch/arm/mach-omap2/timer.c
   3  *
   4  * OMAP2 GP timer support.
   5  *
   6  * Copyright (C) 2009 Nokia Corporation
   7  *
   8  * Update to use new clocksource/clockevent layers
   9  * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
  10  * Copyright (C) 2007 MontaVista Software, Inc.
  11  *
  12  * Original driver:
  13  * Copyright (C) 2005 Nokia Corporation
  14  * Author: Paul Mundt <paul.mundt@nokia.com>
  15  *         Juha Yrjölä <juha.yrjola@nokia.com>
  16  * OMAP Dual-mode timer framework support by Timo Teras
  17  *
  18  * Some parts based off of TI's 24xx code:
  19  *
  20  * Copyright (C) 2004-2009 Texas Instruments, Inc.
  21  *
  22  * Roughly modelled after the OMAP1 MPU timer code.
  23  * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  24  *
  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
  27  * for more details.
  28  */
  29 #include <linux/init.h>
  30 #include <linux/time.h>
  31 #include <linux/interrupt.h>
  32 #include <linux/err.h>
  33 #include <linux/clk.h>
  34 #include <linux/delay.h>
  35 #include <linux/irq.h>
  36 #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 
  48 #include "omap_hwmod.h"
  49 #include "omap_device.h"
  50 #include <plat/counter-32k.h>
  51 #include <clocksource/timer-ti-dm.h>
  52 
  53 #include "soc.h"
  54 #include "common.h"
  55 #include "control.h"
  56 #include "powerdomain.h"
  57 #include "omap-secure.h"
  58 
  59 #define REALTIME_COUNTER_BASE                           0x48243200
  60 #define INCREMENTER_NUMERATOR_OFFSET                    0x10
  61 #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET           0x14
  62 #define NUMERATOR_DENUMERATOR_MASK                      0xfffff000
  63 
  64 /* Clockevent code */
  65 
  66 static struct omap_dm_timer clkev;
  67 static struct clock_event_device clockevent_gpt;
  68 
  69 /* Clockevent hwmod for am335x and am437x suspend */
  70 static struct omap_hwmod *clockevent_gpt_hwmod;
  71 
  72 /* Clockesource hwmod for am437x suspend */
  73 static struct omap_hwmod *clocksource_gpt_hwmod;
  74 
  75 #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
  76 static unsigned long arch_timer_freq;
  77 
  78 void set_cntfreq(void)
  79 {
  80         omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq);
  81 }
  82 #endif
  83 
  84 static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
  85 {
  86         struct clock_event_device *evt = &clockevent_gpt;
  87 
  88         __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
  89 
  90         evt->event_handler(evt);
  91         return IRQ_HANDLED;
  92 }
  93 
  94 static struct irqaction omap2_gp_timer_irq = {
  95         .name           = "gp_timer",
  96         .flags          = IRQF_TIMER | IRQF_IRQPOLL,
  97         .handler        = omap2_gp_timer_interrupt,
  98 };
  99 
 100 static int omap2_gp_timer_set_next_event(unsigned long cycles,
 101                                          struct clock_event_device *evt)
 102 {
 103         __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
 104                                    0xffffffff - cycles, OMAP_TIMER_POSTED);
 105 
 106         return 0;
 107 }
 108 
 109 static int omap2_gp_timer_shutdown(struct clock_event_device *evt)
 110 {
 111         __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
 112         return 0;
 113 }
 114 
 115 static int omap2_gp_timer_set_periodic(struct clock_event_device *evt)
 116 {
 117         u32 period;
 118 
 119         __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
 120 
 121         period = clkev.rate / HZ;
 122         period -= 1;
 123         /* Looks like we need to first set the load value separately */
 124         __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, 0xffffffff - period,
 125                               OMAP_TIMER_POSTED);
 126         __omap_dm_timer_load_start(&clkev,
 127                                    OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
 128                                    0xffffffff - period, OMAP_TIMER_POSTED);
 129         return 0;
 130 }
 131 
 132 static void omap_clkevt_idle(struct clock_event_device *unused)
 133 {
 134         if (!clockevent_gpt_hwmod)
 135                 return;
 136 
 137         omap_hwmod_idle(clockevent_gpt_hwmod);
 138 }
 139 
 140 static void omap_clkevt_unidle(struct clock_event_device *unused)
 141 {
 142         if (!clockevent_gpt_hwmod)
 143                 return;
 144 
 145         omap_hwmod_enable(clockevent_gpt_hwmod);
 146         __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
 147 }
 148 
 149 static struct clock_event_device clockevent_gpt = {
 150         .features               = CLOCK_EVT_FEAT_PERIODIC |
 151                                   CLOCK_EVT_FEAT_ONESHOT,
 152         .rating                 = 300,
 153         .set_next_event         = omap2_gp_timer_set_next_event,
 154         .set_state_shutdown     = omap2_gp_timer_shutdown,
 155         .set_state_periodic     = omap2_gp_timer_set_periodic,
 156         .set_state_oneshot      = omap2_gp_timer_shutdown,
 157         .tick_resume            = omap2_gp_timer_shutdown,
 158 };
 159 
 160 static const struct of_device_id omap_timer_match[] __initconst = {
 161         { .compatible = "ti,omap2420-timer", },
 162         { .compatible = "ti,omap3430-timer", },
 163         { .compatible = "ti,omap4430-timer", },
 164         { .compatible = "ti,omap5430-timer", },
 165         { .compatible = "ti,dm814-timer", },
 166         { .compatible = "ti,dm816-timer", },
 167         { .compatible = "ti,am335x-timer", },
 168         { .compatible = "ti,am335x-timer-1ms", },
 169         { }
 170 };
 171 
 172 static int omap_timer_add_disabled_property(struct device_node *np)
 173 {
 174         struct property *prop;
 175 
 176         prop = kzalloc(sizeof(*prop), GFP_KERNEL);
 177         if (!prop)
 178                 return -ENOMEM;
 179 
 180         prop->name = "status";
 181         prop->value = "disabled";
 182         prop->length = strlen(prop->value);
 183 
 184         return of_add_property(np, prop);
 185 }
 186 
 187 static int omap_timer_update_dt(struct device_node *np)
 188 {
 189         int error = 0;
 190 
 191         if (!of_device_is_compatible(np, "ti,omap-counter32k")) {
 192                 error = omap_timer_add_disabled_property(np);
 193                 if (error)
 194                         return error;
 195         }
 196 
 197         /* No parent interconnect target module configured? */
 198         if (of_get_property(np, "ti,hwmods", NULL))
 199                 return error;
 200 
 201         /* Tag parent interconnect target module disabled */
 202         error = omap_timer_add_disabled_property(np->parent);
 203         if (error)
 204                 return error;
 205 
 206         return 0;
 207 }
 208 
 209 /**
 210  * omap_get_timer_dt - get a timer using device-tree
 211  * @match       - device-tree match structure for matching a device type
 212  * @property    - optional timer property to match
 213  *
 214  * Helper function to get a timer during early boot using device-tree for use
 215  * as kernel system timer. Optionally, the property argument can be used to
 216  * select a timer with a specific property. Once a timer is found then mark
 217  * the timer node in device-tree as disabled, to prevent the kernel from
 218  * registering this timer as a platform device and so no one else can use it.
 219  */
 220 static struct device_node * __init omap_get_timer_dt(const struct of_device_id *match,
 221                                                      const char *property)
 222 {
 223         struct device_node *np;
 224         int error;
 225 
 226         for_each_matching_node(np, match) {
 227                 if (!of_device_is_available(np))
 228                         continue;
 229 
 230                 if (property && !of_get_property(np, property, NULL))
 231                         continue;
 232 
 233                 if (!property && (of_get_property(np, "ti,timer-alwon", NULL) ||
 234                                   of_get_property(np, "ti,timer-dsp", NULL) ||
 235                                   of_get_property(np, "ti,timer-pwm", NULL) ||
 236                                   of_get_property(np, "ti,timer-secure", NULL)))
 237                         continue;
 238 
 239                 error = omap_timer_update_dt(np);
 240                 WARN(error, "%s: Could not update dt: %i\n", __func__, error);
 241 
 242                 return np;
 243         }
 244 
 245         return NULL;
 246 }
 247 
 248 /**
 249  * omap_dmtimer_init - initialisation function when device tree is used
 250  *
 251  * For secure OMAP3/DRA7xx devices, timers with device type "timer-secure"
 252  * cannot be used by the kernel as they are reserved. Therefore, to prevent the
 253  * kernel registering these devices remove them dynamically from the device
 254  * tree on boot.
 255  */
 256 static void __init omap_dmtimer_init(void)
 257 {
 258         struct device_node *np;
 259 
 260         if (!cpu_is_omap34xx() && !soc_is_dra7xx())
 261                 return;
 262 
 263         /* If we are a secure device, remove any secure timer nodes */
 264         if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) {
 265                 np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure");
 266                 of_node_put(np);
 267         }
 268 }
 269 
 270 /**
 271  * omap_dm_timer_get_errata - get errata flags for a timer
 272  *
 273  * Get the timer errata flags that are specific to the OMAP device being used.
 274  */
 275 static u32 __init omap_dm_timer_get_errata(void)
 276 {
 277         if (cpu_is_omap24xx())
 278                 return 0;
 279 
 280         return OMAP_TIMER_ERRATA_I103_I767;
 281 }
 282 
 283 static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 284                                          const char *fck_source,
 285                                          const char *property,
 286                                          const char **timer_name,
 287                                          int posted)
 288 {
 289         const char *oh_name = NULL;
 290         struct device_node *np;
 291         struct omap_hwmod *oh;
 292         struct clk *src;
 293         int r = 0;
 294 
 295         np = omap_get_timer_dt(omap_timer_match, property);
 296         if (!np)
 297                 return -ENODEV;
 298 
 299         of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
 300         if (!oh_name) {
 301                 of_property_read_string_index(np->parent, "ti,hwmods", 0,
 302                                               &oh_name);
 303                 if (!oh_name)
 304                         return -ENODEV;
 305         }
 306 
 307         timer->irq = irq_of_parse_and_map(np, 0);
 308         if (!timer->irq)
 309                 return -ENXIO;
 310 
 311         timer->io_base = of_iomap(np, 0);
 312 
 313         timer->fclk = of_clk_get_by_name(np, "fck");
 314 
 315         of_node_put(np);
 316 
 317         oh = omap_hwmod_lookup(oh_name);
 318         if (!oh)
 319                 return -ENODEV;
 320 
 321         *timer_name = oh->name;
 322 
 323         if (!timer->io_base)
 324                 return -ENXIO;
 325 
 326         omap_hwmod_setup_one(oh_name);
 327 
 328         /* After the dmtimer is using hwmod these clocks won't be needed */
 329         if (IS_ERR_OR_NULL(timer->fclk))
 330                 timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh));
 331         if (IS_ERR(timer->fclk))
 332                 return PTR_ERR(timer->fclk);
 333 
 334         src = clk_get(NULL, fck_source);
 335         if (IS_ERR(src))
 336                 return PTR_ERR(src);
 337 
 338         WARN(clk_set_parent(timer->fclk, src) < 0,
 339              "Cannot set timer parent clock, no PLL clock driver?");
 340 
 341         clk_put(src);
 342 
 343         omap_hwmod_enable(oh);
 344         __omap_dm_timer_init_regs(timer);
 345 
 346         if (posted)
 347                 __omap_dm_timer_enable_posted(timer);
 348 
 349         /* Check that the intended posted configuration matches the actual */
 350         if (posted != timer->posted)
 351                 return -EINVAL;
 352 
 353         timer->rate = clk_get_rate(timer->fclk);
 354         timer->reserved = 1;
 355 
 356         return r;
 357 }
 358 
 359 #if !defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
 360 void tick_broadcast(const struct cpumask *mask)
 361 {
 362 }
 363 #endif
 364 
 365 static void __init omap2_gp_clockevent_init(int gptimer_id,
 366                                                 const char *fck_source,
 367                                                 const char *property)
 368 {
 369         int res;
 370 
 371         clkev.id = gptimer_id;
 372         clkev.errata = omap_dm_timer_get_errata();
 373 
 374         /*
 375          * For clock-event timers we never read the timer counter and
 376          * so we are not impacted by errata i103 and i767. Therefore,
 377          * we can safely ignore this errata for clock-event timers.
 378          */
 379         __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
 380 
 381         res = omap_dm_timer_init_one(&clkev, fck_source, property,
 382                                      &clockevent_gpt.name, OMAP_TIMER_POSTED);
 383         BUG_ON(res);
 384 
 385         omap2_gp_timer_irq.dev_id = &clkev;
 386         setup_irq(clkev.irq, &omap2_gp_timer_irq);
 387 
 388         __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
 389 
 390         clockevent_gpt.cpumask = cpu_possible_mask;
 391         clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
 392         clockevents_config_and_register(&clockevent_gpt, clkev.rate,
 393                                         3, /* Timer internal resynch latency */
 394                                         0xffffffff);
 395 
 396         if (soc_is_am33xx() || soc_is_am43xx()) {
 397                 clockevent_gpt.suspend = omap_clkevt_idle;
 398                 clockevent_gpt.resume = omap_clkevt_unidle;
 399 
 400                 clockevent_gpt_hwmod =
 401                         omap_hwmod_lookup(clockevent_gpt.name);
 402         }
 403 
 404         pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
 405                 clkev.rate);
 406 }
 407 
 408 /* Clocksource code */
 409 static struct omap_dm_timer clksrc;
 410 static bool use_gptimer_clksrc __initdata;
 411 
 412 /*
 413  * clocksource
 414  */
 415 static u64 clocksource_read_cycles(struct clocksource *cs)
 416 {
 417         return (u64)__omap_dm_timer_read_counter(&clksrc,
 418                                                      OMAP_TIMER_NONPOSTED);
 419 }
 420 
 421 static struct clocksource clocksource_gpt = {
 422         .rating         = 300,
 423         .read           = clocksource_read_cycles,
 424         .mask           = CLOCKSOURCE_MASK(32),
 425         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 426 };
 427 
 428 static u64 notrace dmtimer_read_sched_clock(void)
 429 {
 430         if (clksrc.reserved)
 431                 return __omap_dm_timer_read_counter(&clksrc,
 432                                                     OMAP_TIMER_NONPOSTED);
 433 
 434         return 0;
 435 }
 436 
 437 static const struct of_device_id omap_counter_match[] __initconst = {
 438         { .compatible = "ti,omap-counter32k", },
 439         { }
 440 };
 441 
 442 /* Setup free-running counter for clocksource */
 443 static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
 444 {
 445         int ret;
 446         struct device_node *np = NULL;
 447         struct omap_hwmod *oh;
 448         const char *oh_name = "counter_32k";
 449 
 450         /*
 451          * See if the 32kHz counter is supported.
 452          */
 453         np = omap_get_timer_dt(omap_counter_match, NULL);
 454         if (!np)
 455                 return -ENODEV;
 456 
 457         of_property_read_string_index(np->parent, "ti,hwmods", 0, &oh_name);
 458         if (!oh_name) {
 459                 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
 460                 if (!oh_name)
 461                         return -ENODEV;
 462         }
 463 
 464         /*
 465          * First check hwmod data is available for sync32k counter
 466          */
 467         oh = omap_hwmod_lookup(oh_name);
 468         if (!oh || oh->slaves_cnt == 0)
 469                 return -ENODEV;
 470 
 471         omap_hwmod_setup_one(oh_name);
 472 
 473         ret = omap_hwmod_enable(oh);
 474         if (ret) {
 475                 pr_warn("%s: failed to enable counter_32k module (%d)\n",
 476                                                         __func__, ret);
 477                 return ret;
 478         }
 479 
 480         return ret;
 481 }
 482 
 483 static unsigned int omap2_gptimer_clksrc_load;
 484 
 485 static void omap2_gptimer_clksrc_suspend(struct clocksource *unused)
 486 {
 487         omap2_gptimer_clksrc_load =
 488                 __omap_dm_timer_read_counter(&clksrc, OMAP_TIMER_NONPOSTED);
 489 
 490         omap_hwmod_idle(clocksource_gpt_hwmod);
 491 }
 492 
 493 static void omap2_gptimer_clksrc_resume(struct clocksource *unused)
 494 {
 495         omap_hwmod_enable(clocksource_gpt_hwmod);
 496 
 497         __omap_dm_timer_load_start(&clksrc,
 498                                    OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
 499                                    omap2_gptimer_clksrc_load,
 500                                    OMAP_TIMER_NONPOSTED);
 501 }
 502 
 503 static void __init omap2_gptimer_clocksource_init(int gptimer_id,
 504                                                   const char *fck_source,
 505                                                   const char *property)
 506 {
 507         int res;
 508 
 509         clksrc.id = gptimer_id;
 510         clksrc.errata = omap_dm_timer_get_errata();
 511 
 512         res = omap_dm_timer_init_one(&clksrc, fck_source, property,
 513                                      &clocksource_gpt.name,
 514                                      OMAP_TIMER_NONPOSTED);
 515 
 516         if (soc_is_am43xx()) {
 517                 clocksource_gpt.suspend = omap2_gptimer_clksrc_suspend;
 518                 clocksource_gpt.resume = omap2_gptimer_clksrc_resume;
 519 
 520                 clocksource_gpt_hwmod =
 521                         omap_hwmod_lookup(clocksource_gpt.name);
 522         }
 523 
 524         BUG_ON(res);
 525 
 526         __omap_dm_timer_load_start(&clksrc,
 527                                    OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
 528                                    OMAP_TIMER_NONPOSTED);
 529         sched_clock_register(dmtimer_read_sched_clock, 32, clksrc.rate);
 530 
 531         if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
 532                 pr_err("Could not register clocksource %s\n",
 533                         clocksource_gpt.name);
 534         else
 535                 pr_info("OMAP clocksource: %s at %lu Hz\n",
 536                         clocksource_gpt.name, clksrc.rate);
 537 }
 538 
 539 static void __init __omap_sync32k_timer_init(int clkev_nr, const char *clkev_src,
 540                 const char *clkev_prop, int clksrc_nr, const char *clksrc_src,
 541                 const char *clksrc_prop, bool gptimer)
 542 {
 543         omap_clk_init();
 544         omap_dmtimer_init();
 545         omap2_gp_clockevent_init(clkev_nr, clkev_src, clkev_prop);
 546 
 547         /* Enable the use of clocksource="gp_timer" kernel parameter */
 548         if (use_gptimer_clksrc || gptimer)
 549                 omap2_gptimer_clocksource_init(clksrc_nr, clksrc_src,
 550                                                 clksrc_prop);
 551         else
 552                 omap2_sync32k_clocksource_init();
 553 }
 554 
 555 void __init omap_init_time(void)
 556 {
 557         __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
 558                         2, "timer_sys_ck", NULL, false);
 559 
 560         timer_probe();
 561 }
 562 
 563 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
 564 void __init omap3_secure_sync32k_timer_init(void)
 565 {
 566         __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure",
 567                         2, "timer_sys_ck", NULL, false);
 568 
 569         timer_probe();
 570 }
 571 #endif /* CONFIG_ARCH_OMAP3 */
 572 
 573 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \
 574         defined(CONFIG_SOC_AM43XX)
 575 void __init omap3_gptimer_timer_init(void)
 576 {
 577         __omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
 578                         1, "timer_sys_ck", "ti,timer-alwon", true);
 579         if (of_have_populated_dt())
 580                 timer_probe();
 581 }
 582 #endif
 583 
 584 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) ||          \
 585         defined(CONFIG_SOC_DRA7XX)
 586 static void __init omap4_sync32k_timer_init(void)
 587 {
 588         __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
 589                         2, "sys_clkin_ck", NULL, false);
 590 }
 591 
 592 void __init omap4_local_timer_init(void)
 593 {
 594         omap4_sync32k_timer_init();
 595         timer_probe();
 596 }
 597 #endif
 598 
 599 #if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
 600 
 601 /*
 602  * The realtime counter also called master counter, is a free-running
 603  * counter, which is related to real time. It produces the count used
 604  * by the CPU local timer peripherals in the MPU cluster. The timer counts
 605  * at a rate of 6.144 MHz. Because the device operates on different clocks
 606  * in different power modes, the master counter shifts operation between
 607  * clocks, adjusting the increment per clock in hardware accordingly to
 608  * maintain a constant count rate.
 609  */
 610 static void __init realtime_counter_init(void)
 611 {
 612 #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
 613         void __iomem *base;
 614         static struct clk *sys_clk;
 615         unsigned long rate;
 616         unsigned int reg;
 617         unsigned long long num, den;
 618 
 619         base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
 620         if (!base) {
 621                 pr_err("%s: ioremap failed\n", __func__);
 622                 return;
 623         }
 624         sys_clk = clk_get(NULL, "sys_clkin");
 625         if (IS_ERR(sys_clk)) {
 626                 pr_err("%s: failed to get system clock handle\n", __func__);
 627                 iounmap(base);
 628                 return;
 629         }
 630 
 631         rate = clk_get_rate(sys_clk);
 632 
 633         if (soc_is_dra7xx()) {
 634                 /*
 635                  * Errata i856 says the 32.768KHz crystal does not start at
 636                  * power on, so the CPU falls back to an emulated 32KHz clock
 637                  * based on sysclk / 610 instead. This causes the master counter
 638                  * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2
 639                  * (OR sysclk * 75 / 244)
 640                  *
 641                  * This affects at least the DRA7/AM572x 1.0, 1.1 revisions.
 642                  * Of course any board built without a populated 32.768KHz
 643                  * crystal would also need this fix even if the CPU is fixed
 644                  * later.
 645                  *
 646                  * Either case can be detected by using the two speedselect bits
 647                  * If they are not 0, then the 32.768KHz clock driving the
 648                  * coarse counter that corrects the fine counter every time it
 649                  * ticks is actually rate/610 rather than 32.768KHz and we
 650                  * should compensate to avoid the 570ppm (at 20MHz, much worse
 651                  * at other rates) too fast system time.
 652                  */
 653                 reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP);
 654                 if (reg & DRA7_SPEEDSELECT_MASK) {
 655                         num = 75;
 656                         den = 244;
 657                         goto sysclk1_based;
 658                 }
 659         }
 660 
 661         /* Numerator/denumerator values refer TRM Realtime Counter section */
 662         switch (rate) {
 663         case 12000000:
 664                 num = 64;
 665                 den = 125;
 666                 break;
 667         case 13000000:
 668                 num = 768;
 669                 den = 1625;
 670                 break;
 671         case 19200000:
 672                 num = 8;
 673                 den = 25;
 674                 break;
 675         case 20000000:
 676                 num = 192;
 677                 den = 625;
 678                 break;
 679         case 26000000:
 680                 num = 384;
 681                 den = 1625;
 682                 break;
 683         case 27000000:
 684                 num = 256;
 685                 den = 1125;
 686                 break;
 687         case 38400000:
 688         default:
 689                 /* Program it for 38.4 MHz */
 690                 num = 4;
 691                 den = 25;
 692                 break;
 693         }
 694 
 695 sysclk1_based:
 696         /* Program numerator and denumerator registers */
 697         reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) &
 698                         NUMERATOR_DENUMERATOR_MASK;
 699         reg |= num;
 700         writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET);
 701 
 702         reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) &
 703                         NUMERATOR_DENUMERATOR_MASK;
 704         reg |= den;
 705         writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
 706 
 707         arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den);
 708         set_cntfreq();
 709 
 710         iounmap(base);
 711 #endif
 712 }
 713 
 714 void __init omap5_realtime_timer_init(void)
 715 {
 716         omap4_sync32k_timer_init();
 717         realtime_counter_init();
 718 
 719         timer_probe();
 720 }
 721 #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
 722 
 723 /**
 724  * omap2_override_clocksource - clocksource override with user configuration
 725  *
 726  * Allows user to override default clocksource, using kernel parameter
 727  *   clocksource="gp_timer"     (For all OMAP2PLUS architectures)
 728  *
 729  * Note that, here we are using same standard kernel parameter "clocksource=",
 730  * and not introducing any OMAP specific interface.
 731  */
 732 static int __init omap2_override_clocksource(char *str)
 733 {
 734         if (!str)
 735                 return 0;
 736         /*
 737          * For OMAP architecture, we only have two options
 738          *    - sync_32k (default)
 739          *    - gp_timer (sys_clk based)
 740          */
 741         if (!strcmp(str, "gp_timer"))
 742                 use_gptimer_clksrc = true;
 743 
 744         return 0;
 745 }
 746 early_param("clocksource", omap2_override_clocksource);

/* [<][>][^][v][top][bottom][index][help] */