root/drivers/clocksource/bcm_kona_timer.c

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

DEFINITIONS

This source file includes following definitions.
  1. kona_timer_disable_and_clear
  2. kona_timer_get_counter
  3. kona_timer_set_next_event
  4. kona_timer_shutdown
  5. kona_timer_clockevents_init
  6. kona_timer_interrupt
  7. kona_timer_init

   1 /*
   2  * Copyright (C) 2012 Broadcom Corporation
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public License as
   6  * published by the Free Software Foundation version 2.
   7  *
   8  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
   9  * kind, whether express or implied; without even the implied warranty
  10  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11  * GNU General Public License for more details.
  12  */
  13 
  14 #include <linux/init.h>
  15 #include <linux/irq.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/jiffies.h>
  18 #include <linux/clockchips.h>
  19 #include <linux/types.h>
  20 #include <linux/clk.h>
  21 
  22 #include <linux/io.h>
  23 
  24 #include <linux/of.h>
  25 #include <linux/of_address.h>
  26 #include <linux/of_irq.h>
  27 
  28 
  29 #define KONA_GPTIMER_STCS_OFFSET                        0x00000000
  30 #define KONA_GPTIMER_STCLO_OFFSET                       0x00000004
  31 #define KONA_GPTIMER_STCHI_OFFSET                       0x00000008
  32 #define KONA_GPTIMER_STCM0_OFFSET                       0x0000000C
  33 
  34 #define KONA_GPTIMER_STCS_TIMER_MATCH_SHIFT             0
  35 #define KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT          4
  36 
  37 struct kona_bcm_timers {
  38         int tmr_irq;
  39         void __iomem *tmr_regs;
  40 };
  41 
  42 static struct kona_bcm_timers timers;
  43 
  44 static u32 arch_timer_rate;
  45 
  46 /*
  47  * We use the peripheral timers for system tick, the cpu global timer for
  48  * profile tick
  49  */
  50 static void kona_timer_disable_and_clear(void __iomem *base)
  51 {
  52         uint32_t reg;
  53 
  54         /*
  55          * clear and disable interrupts
  56          * We are using compare/match register 0 for our system interrupts
  57          */
  58         reg = readl(base + KONA_GPTIMER_STCS_OFFSET);
  59 
  60         /* Clear compare (0) interrupt */
  61         reg |= 1 << KONA_GPTIMER_STCS_TIMER_MATCH_SHIFT;
  62         /* disable compare */
  63         reg &= ~(1 << KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT);
  64 
  65         writel(reg, base + KONA_GPTIMER_STCS_OFFSET);
  66 
  67 }
  68 
  69 static int
  70 kona_timer_get_counter(void __iomem *timer_base, uint32_t *msw, uint32_t *lsw)
  71 {
  72         int loop_limit = 3;
  73 
  74         /*
  75          * Read 64-bit free running counter
  76          * 1. Read hi-word
  77          * 2. Read low-word
  78          * 3. Read hi-word again
  79          * 4.1
  80          *      if new hi-word is not equal to previously read hi-word, then
  81          *      start from #1
  82          * 4.2
  83          *      if new hi-word is equal to previously read hi-word then stop.
  84          */
  85 
  86         do {
  87                 *msw = readl(timer_base + KONA_GPTIMER_STCHI_OFFSET);
  88                 *lsw = readl(timer_base + KONA_GPTIMER_STCLO_OFFSET);
  89                 if (*msw == readl(timer_base + KONA_GPTIMER_STCHI_OFFSET))
  90                         break;
  91         } while (--loop_limit);
  92         if (!loop_limit) {
  93                 pr_err("bcm_kona_timer: getting counter failed.\n");
  94                 pr_err(" Timer will be impacted\n");
  95                 return -ETIMEDOUT;
  96         }
  97 
  98         return 0;
  99 }
 100 
 101 static int kona_timer_set_next_event(unsigned long clc,
 102                                   struct clock_event_device *unused)
 103 {
 104         /*
 105          * timer (0) is disabled by the timer interrupt already
 106          * so, here we reload the next event value and re-enable
 107          * the timer.
 108          *
 109          * This way, we are potentially losing the time between
 110          * timer-interrupt->set_next_event. CPU local timers, when
 111          * they come in should get rid of skew.
 112          */
 113 
 114         uint32_t lsw, msw;
 115         uint32_t reg;
 116         int ret;
 117 
 118         ret = kona_timer_get_counter(timers.tmr_regs, &msw, &lsw);
 119         if (ret)
 120                 return ret;
 121 
 122         /* Load the "next" event tick value */
 123         writel(lsw + clc, timers.tmr_regs + KONA_GPTIMER_STCM0_OFFSET);
 124 
 125         /* Enable compare */
 126         reg = readl(timers.tmr_regs + KONA_GPTIMER_STCS_OFFSET);
 127         reg |= (1 << KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT);
 128         writel(reg, timers.tmr_regs + KONA_GPTIMER_STCS_OFFSET);
 129 
 130         return 0;
 131 }
 132 
 133 static int kona_timer_shutdown(struct clock_event_device *evt)
 134 {
 135         kona_timer_disable_and_clear(timers.tmr_regs);
 136         return 0;
 137 }
 138 
 139 static struct clock_event_device kona_clockevent_timer = {
 140         .name = "timer 1",
 141         .features = CLOCK_EVT_FEAT_ONESHOT,
 142         .set_next_event = kona_timer_set_next_event,
 143         .set_state_shutdown = kona_timer_shutdown,
 144         .tick_resume = kona_timer_shutdown,
 145 };
 146 
 147 static void __init kona_timer_clockevents_init(void)
 148 {
 149         kona_clockevent_timer.cpumask = cpumask_of(0);
 150         clockevents_config_and_register(&kona_clockevent_timer,
 151                 arch_timer_rate, 6, 0xffffffff);
 152 }
 153 
 154 static irqreturn_t kona_timer_interrupt(int irq, void *dev_id)
 155 {
 156         struct clock_event_device *evt = &kona_clockevent_timer;
 157 
 158         kona_timer_disable_and_clear(timers.tmr_regs);
 159         evt->event_handler(evt);
 160         return IRQ_HANDLED;
 161 }
 162 
 163 static struct irqaction kona_timer_irq = {
 164         .name = "Kona Timer Tick",
 165         .flags = IRQF_TIMER,
 166         .handler = kona_timer_interrupt,
 167 };
 168 
 169 static int __init kona_timer_init(struct device_node *node)
 170 {
 171         u32 freq;
 172         struct clk *external_clk;
 173 
 174         external_clk = of_clk_get_by_name(node, NULL);
 175 
 176         if (!IS_ERR(external_clk)) {
 177                 arch_timer_rate = clk_get_rate(external_clk);
 178                 clk_prepare_enable(external_clk);
 179         } else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
 180                 arch_timer_rate = freq;
 181         } else {
 182                 pr_err("Kona Timer v1 unable to determine clock-frequency\n");
 183                 return -EINVAL;
 184         }
 185 
 186         /* Setup IRQ numbers */
 187         timers.tmr_irq = irq_of_parse_and_map(node, 0);
 188 
 189         /* Setup IO addresses */
 190         timers.tmr_regs = of_iomap(node, 0);
 191 
 192         kona_timer_disable_and_clear(timers.tmr_regs);
 193 
 194         kona_timer_clockevents_init();
 195         setup_irq(timers.tmr_irq, &kona_timer_irq);
 196         kona_timer_set_next_event((arch_timer_rate / HZ), NULL);
 197 
 198         return 0;
 199 }
 200 
 201 TIMER_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init);
 202 /*
 203  * bcm,kona-timer is deprecated by brcm,kona-timer
 204  * being kept here for driver compatibility
 205  */
 206 TIMER_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init);

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