root/arch/m68k/coldfire/sltimers.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcfslt_profile_tick
  2. mcfslt_profile_init
  3. mcfslt_tick
  4. mcfslt_read_clk
  5. hw_timer_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /***************************************************************************/
   3 
   4 /*
   5  *      sltimers.c -- generic ColdFire slice timer support.
   6  *
   7  *      Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
   8  *      based on
   9  *      timers.c -- generic ColdFire hardware timer support.
  10  *      Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
  11  */
  12 
  13 /***************************************************************************/
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/init.h>
  17 #include <linux/sched.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/irq.h>
  20 #include <linux/profile.h>
  21 #include <linux/clocksource.h>
  22 #include <asm/io.h>
  23 #include <asm/traps.h>
  24 #include <asm/machdep.h>
  25 #include <asm/coldfire.h>
  26 #include <asm/mcfslt.h>
  27 #include <asm/mcfsim.h>
  28 
  29 /***************************************************************************/
  30 
  31 #ifdef CONFIG_HIGHPROFILE
  32 
  33 /*
  34  *      By default use Slice Timer 1 as the profiler clock timer.
  35  */
  36 #define PA(a)   (MCFSLT_TIMER1 + (a))
  37 
  38 /*
  39  *      Choose a reasonably fast profile timer. Make it an odd value to
  40  *      try and get good coverage of kernel operations.
  41  */
  42 #define PROFILEHZ       1013
  43 
  44 irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
  45 {
  46         /* Reset Slice Timer 1 */
  47         __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
  48         if (current->pid)
  49                 profile_tick(CPU_PROFILING);
  50         return IRQ_HANDLED;
  51 }
  52 
  53 static struct irqaction mcfslt_profile_irq = {
  54         .name    = "profile timer",
  55         .flags   = IRQF_TIMER,
  56         .handler = mcfslt_profile_tick,
  57 };
  58 
  59 void mcfslt_profile_init(void)
  60 {
  61         printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
  62                PROFILEHZ);
  63 
  64         setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
  65 
  66         /* Set up TIMER 2 as high speed profile clock */
  67         __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
  68         __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
  69                                                                 PA(MCFSLT_SCR));
  70 
  71 }
  72 
  73 #endif  /* CONFIG_HIGHPROFILE */
  74 
  75 /***************************************************************************/
  76 
  77 /*
  78  *      By default use Slice Timer 0 as the system clock timer.
  79  */
  80 #define TA(a)   (MCFSLT_TIMER0 + (a))
  81 
  82 static u32 mcfslt_cycles_per_jiffy;
  83 static u32 mcfslt_cnt;
  84 
  85 static irq_handler_t timer_interrupt;
  86 
  87 static irqreturn_t mcfslt_tick(int irq, void *dummy)
  88 {
  89         /* Reset Slice Timer 0 */
  90         __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
  91         mcfslt_cnt += mcfslt_cycles_per_jiffy;
  92         return timer_interrupt(irq, dummy);
  93 }
  94 
  95 static struct irqaction mcfslt_timer_irq = {
  96         .name    = "timer",
  97         .flags   = IRQF_TIMER,
  98         .handler = mcfslt_tick,
  99 };
 100 
 101 static u64 mcfslt_read_clk(struct clocksource *cs)
 102 {
 103         unsigned long flags;
 104         u32 cycles, scnt;
 105 
 106         local_irq_save(flags);
 107         scnt = __raw_readl(TA(MCFSLT_SCNT));
 108         cycles = mcfslt_cnt;
 109         if (__raw_readl(TA(MCFSLT_SSR)) & MCFSLT_SSR_TE) {
 110                 cycles += mcfslt_cycles_per_jiffy;
 111                 scnt = __raw_readl(TA(MCFSLT_SCNT));
 112         }
 113         local_irq_restore(flags);
 114 
 115         /* subtract because slice timers count down */
 116         return cycles + ((mcfslt_cycles_per_jiffy - 1) - scnt);
 117 }
 118 
 119 static struct clocksource mcfslt_clk = {
 120         .name   = "slt",
 121         .rating = 250,
 122         .read   = mcfslt_read_clk,
 123         .mask   = CLOCKSOURCE_MASK(32),
 124         .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 125 };
 126 
 127 void hw_timer_init(irq_handler_t handler)
 128 {
 129         mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
 130         /*
 131          *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
 132          *      then STCNT again and so on.  It counts thus actually
 133          *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
 134          *      n cycles, initialize STCNT with n - 1.
 135          */
 136         __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
 137         __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
 138                                                                 TA(MCFSLT_SCR));
 139         /* initialize mcfslt_cnt knowing that slice timers count down */
 140         mcfslt_cnt = mcfslt_cycles_per_jiffy;
 141 
 142         timer_interrupt = handler;
 143         setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
 144 
 145         clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
 146 
 147 #ifdef CONFIG_HIGHPROFILE
 148         mcfslt_profile_init();
 149 #endif
 150 }

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