root/arch/xtensa/kernel/time.c

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

DEFINITIONS

This source file includes following definitions.
  1. ccount_read
  2. ccount_sched_clock_read
  3. ccount_timer_set_next_event
  4. ccount_timer_shutdown
  5. ccount_timer_set_oneshot
  6. timer_interrupt
  7. local_timer_setup
  8. calibrate_ccount
  9. calibrate_ccount
  10. time_init
  11. calibrate_delay

   1 /*
   2  * arch/xtensa/kernel/time.c
   3  *
   4  * Timer and clock support.
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file "COPYING" in the main directory of this archive
   8  * for more details.
   9  *
  10  * Copyright (C) 2005 Tensilica Inc.
  11  *
  12  * Chris Zankel <chris@zankel.net>
  13  */
  14 
  15 #include <linux/clk.h>
  16 #include <linux/clk-provider.h>
  17 #include <linux/errno.h>
  18 #include <linux/sched.h>
  19 #include <linux/time.h>
  20 #include <linux/clocksource.h>
  21 #include <linux/clockchips.h>
  22 #include <linux/interrupt.h>
  23 #include <linux/module.h>
  24 #include <linux/init.h>
  25 #include <linux/irq.h>
  26 #include <linux/profile.h>
  27 #include <linux/delay.h>
  28 #include <linux/irqdomain.h>
  29 #include <linux/sched_clock.h>
  30 
  31 #include <asm/timex.h>
  32 #include <asm/platform.h>
  33 
  34 unsigned long ccount_freq;              /* ccount Hz */
  35 EXPORT_SYMBOL(ccount_freq);
  36 
  37 static u64 ccount_read(struct clocksource *cs)
  38 {
  39         return (u64)get_ccount();
  40 }
  41 
  42 static u64 notrace ccount_sched_clock_read(void)
  43 {
  44         return get_ccount();
  45 }
  46 
  47 static struct clocksource ccount_clocksource = {
  48         .name = "ccount",
  49         .rating = 200,
  50         .read = ccount_read,
  51         .mask = CLOCKSOURCE_MASK(32),
  52         .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  53 };
  54 
  55 struct ccount_timer {
  56         struct clock_event_device evt;
  57         int irq_enabled;
  58         char name[24];
  59 };
  60 
  61 static int ccount_timer_set_next_event(unsigned long delta,
  62                 struct clock_event_device *dev)
  63 {
  64         unsigned long flags, next;
  65         int ret = 0;
  66 
  67         local_irq_save(flags);
  68         next = get_ccount() + delta;
  69         set_linux_timer(next);
  70         if (next - get_ccount() > delta)
  71                 ret = -ETIME;
  72         local_irq_restore(flags);
  73 
  74         return ret;
  75 }
  76 
  77 /*
  78  * There is no way to disable the timer interrupt at the device level,
  79  * only at the intenable register itself. Since enable_irq/disable_irq
  80  * calls are nested, we need to make sure that these calls are
  81  * balanced.
  82  */
  83 static int ccount_timer_shutdown(struct clock_event_device *evt)
  84 {
  85         struct ccount_timer *timer =
  86                 container_of(evt, struct ccount_timer, evt);
  87 
  88         if (timer->irq_enabled) {
  89                 disable_irq_nosync(evt->irq);
  90                 timer->irq_enabled = 0;
  91         }
  92         return 0;
  93 }
  94 
  95 static int ccount_timer_set_oneshot(struct clock_event_device *evt)
  96 {
  97         struct ccount_timer *timer =
  98                 container_of(evt, struct ccount_timer, evt);
  99 
 100         if (!timer->irq_enabled) {
 101                 enable_irq(evt->irq);
 102                 timer->irq_enabled = 1;
 103         }
 104         return 0;
 105 }
 106 
 107 static DEFINE_PER_CPU(struct ccount_timer, ccount_timer) = {
 108         .evt = {
 109                 .features = CLOCK_EVT_FEAT_ONESHOT,
 110                 .rating = 300,
 111                 .set_next_event = ccount_timer_set_next_event,
 112                 .set_state_shutdown = ccount_timer_shutdown,
 113                 .set_state_oneshot = ccount_timer_set_oneshot,
 114                 .tick_resume = ccount_timer_set_oneshot,
 115         },
 116 };
 117 
 118 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 119 {
 120         struct clock_event_device *evt = &this_cpu_ptr(&ccount_timer)->evt;
 121 
 122         set_linux_timer(get_linux_timer());
 123         evt->event_handler(evt);
 124 
 125         /* Allow platform to do something useful (Wdog). */
 126         platform_heartbeat();
 127 
 128         return IRQ_HANDLED;
 129 }
 130 
 131 static struct irqaction timer_irqaction = {
 132         .handler =      timer_interrupt,
 133         .flags =        IRQF_TIMER,
 134         .name =         "timer",
 135 };
 136 
 137 void local_timer_setup(unsigned cpu)
 138 {
 139         struct ccount_timer *timer = &per_cpu(ccount_timer, cpu);
 140         struct clock_event_device *clockevent = &timer->evt;
 141 
 142         timer->irq_enabled = 1;
 143         snprintf(timer->name, sizeof(timer->name), "ccount_clockevent_%u", cpu);
 144         clockevent->name = timer->name;
 145         clockevent->cpumask = cpumask_of(cpu);
 146         clockevent->irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
 147         if (WARN(!clockevent->irq, "error: can't map timer irq"))
 148                 return;
 149         clockevents_config_and_register(clockevent, ccount_freq,
 150                                         0xf, 0xffffffff);
 151 }
 152 
 153 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 154 #ifdef CONFIG_OF
 155 static void __init calibrate_ccount(void)
 156 {
 157         struct device_node *cpu;
 158         struct clk *clk;
 159 
 160         cpu = of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu");
 161         if (cpu) {
 162                 clk = of_clk_get(cpu, 0);
 163                 if (!IS_ERR(clk)) {
 164                         ccount_freq = clk_get_rate(clk);
 165                         return;
 166                 } else {
 167                         pr_warn("%s: CPU input clock not found\n",
 168                                 __func__);
 169                 }
 170         } else {
 171                 pr_warn("%s: CPU node not found in the device tree\n",
 172                         __func__);
 173         }
 174 
 175         platform_calibrate_ccount();
 176 }
 177 #else
 178 static inline void calibrate_ccount(void)
 179 {
 180         platform_calibrate_ccount();
 181 }
 182 #endif
 183 #endif
 184 
 185 void __init time_init(void)
 186 {
 187         of_clk_init(NULL);
 188 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 189         pr_info("Calibrating CPU frequency ");
 190         calibrate_ccount();
 191         pr_cont("%d.%02d MHz\n",
 192                 (int)ccount_freq / 1000000,
 193                 (int)(ccount_freq / 10000) % 100);
 194 #else
 195         ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL;
 196 #endif
 197         WARN(!ccount_freq,
 198              "%s: CPU clock frequency is not set up correctly\n",
 199              __func__);
 200         clocksource_register_hz(&ccount_clocksource, ccount_freq);
 201         local_timer_setup(0);
 202         setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
 203         sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
 204         timer_probe();
 205 }
 206 
 207 #ifndef CONFIG_GENERIC_CALIBRATE_DELAY
 208 void calibrate_delay(void)
 209 {
 210         loops_per_jiffy = ccount_freq / HZ;
 211         pr_info("Calibrating delay loop (skipped)... %lu.%02lu BogoMIPS preset\n",
 212                 loops_per_jiffy / (1000000 / HZ),
 213                 (loops_per_jiffy / (10000 / HZ)) % 100);
 214 }
 215 #endif

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