linux/arch/m68k/coldfire/timers.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/***************************************************************************/
   3
   4/*
   5 *      timers.c -- generic ColdFire hardware timer support.
   6 *
   7 *      Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
   8 */
   9
  10/***************************************************************************/
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/sched.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/profile.h>
  18#include <linux/clocksource.h>
  19#include <asm/io.h>
  20#include <asm/traps.h>
  21#include <asm/machdep.h>
  22#include <asm/coldfire.h>
  23#include <asm/mcftimer.h>
  24#include <asm/mcfsim.h>
  25
  26/***************************************************************************/
  27
  28/*
  29 *      By default use timer1 as the system clock timer.
  30 */
  31#define FREQ    (MCF_BUSCLK / 16)
  32#define TA(a)   (MCFTIMER_BASE1 + (a))
  33
  34/*
  35 *      These provide the underlying interrupt vector support.
  36 *      Unfortunately it is a little different on each ColdFire.
  37 */
  38void coldfire_profile_init(void);
  39
  40#if defined(CONFIG_M53xx) || defined(CONFIG_M5441x)
  41#define __raw_readtrr   __raw_readl
  42#define __raw_writetrr  __raw_writel
  43#else
  44#define __raw_readtrr   __raw_readw
  45#define __raw_writetrr  __raw_writew
  46#endif
  47
  48static u32 mcftmr_cycles_per_jiffy;
  49static u32 mcftmr_cnt;
  50
  51/***************************************************************************/
  52
  53static void init_timer_irq(void)
  54{
  55#ifdef MCFSIM_ICR_AUTOVEC
  56        /* Timer1 is always used as system timer */
  57        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
  58                MCFSIM_TIMER1ICR);
  59        mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
  60
  61#ifdef CONFIG_HIGHPROFILE
  62        /* Timer2 is to be used as a high speed profile timer  */
  63        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
  64                MCFSIM_TIMER2ICR);
  65        mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
  66#endif
  67#endif /* MCFSIM_ICR_AUTOVEC */
  68}
  69
  70/***************************************************************************/
  71
  72static irqreturn_t mcftmr_tick(int irq, void *dummy)
  73{
  74        /* Reset the ColdFire timer */
  75        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
  76
  77        mcftmr_cnt += mcftmr_cycles_per_jiffy;
  78        legacy_timer_tick(1);
  79        return IRQ_HANDLED;
  80}
  81
  82/***************************************************************************/
  83
  84static u64 mcftmr_read_clk(struct clocksource *cs)
  85{
  86        unsigned long flags;
  87        u32 cycles;
  88        u16 tcn;
  89
  90        local_irq_save(flags);
  91        tcn = __raw_readw(TA(MCFTIMER_TCN));
  92        cycles = mcftmr_cnt;
  93        local_irq_restore(flags);
  94
  95        return cycles + tcn;
  96}
  97
  98/***************************************************************************/
  99
 100static struct clocksource mcftmr_clk = {
 101        .name   = "tmr",
 102        .rating = 250,
 103        .read   = mcftmr_read_clk,
 104        .mask   = CLOCKSOURCE_MASK(32),
 105        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 106};
 107
 108/***************************************************************************/
 109
 110void hw_timer_init(void)
 111{
 112        int r;
 113
 114        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
 115        mcftmr_cycles_per_jiffy = FREQ / HZ;
 116        /*
 117         *      The coldfire timer runs from 0 to TRR included, then 0
 118         *      again and so on.  It counts thus actually TRR + 1 steps
 119         *      for 1 tick, not TRR.  So if you want n cycles,
 120         *      initialize TRR with n - 1.
 121         */
 122        __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
 123        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
 124                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 125
 126        clocksource_register_hz(&mcftmr_clk, FREQ);
 127
 128        init_timer_irq();
 129        r = request_irq(MCF_IRQ_TIMER, mcftmr_tick, IRQF_TIMER, "timer", NULL);
 130        if (r) {
 131                pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_TIMER,
 132                       ERR_PTR(r));
 133        }
 134
 135#ifdef CONFIG_HIGHPROFILE
 136        coldfire_profile_init();
 137#endif
 138}
 139
 140/***************************************************************************/
 141#ifdef CONFIG_HIGHPROFILE
 142/***************************************************************************/
 143
 144/*
 145 *      By default use timer2 as the profiler clock timer.
 146 */
 147#define PA(a)   (MCFTIMER_BASE2 + (a))
 148
 149/*
 150 *      Choose a reasonably fast profile timer. Make it an odd value to
 151 *      try and get good coverage of kernel operations.
 152 */
 153#define PROFILEHZ       1013
 154
 155/*
 156 *      Use the other timer to provide high accuracy profiling info.
 157 */
 158irqreturn_t coldfire_profile_tick(int irq, void *dummy)
 159{
 160        /* Reset ColdFire timer2 */
 161        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
 162        if (current->pid)
 163                profile_tick(CPU_PROFILING);
 164        return IRQ_HANDLED;
 165}
 166
 167/***************************************************************************/
 168
 169void coldfire_profile_init(void)
 170{
 171        int ret;
 172
 173        printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
 174               PROFILEHZ);
 175
 176        /* Set up TIMER 2 as high speed profile clock */
 177        __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
 178
 179        __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
 180        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
 181                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
 182
 183        ret = request_irq(MCF_IRQ_PROFILER, coldfire_profile_tick, IRQF_TIMER,
 184                          "profile timer", NULL);
 185        if (ret) {
 186                pr_err("Failed to request irq %d (profile timer): %pe\n",
 187                       MCF_IRQ_PROFILER, ERR_PTR(ret));
 188        }
 189}
 190
 191/***************************************************************************/
 192#endif  /* CONFIG_HIGHPROFILE */
 193/***************************************************************************/
 194