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
  51static irq_handler_t timer_interrupt;
  52
  53/***************************************************************************/
  54
  55static void init_timer_irq(void)
  56{
  57#ifdef MCFSIM_ICR_AUTOVEC
  58        /* Timer1 is always used as system timer */
  59        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
  60                MCFSIM_TIMER1ICR);
  61        mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
  62
  63#ifdef CONFIG_HIGHPROFILE
  64        /* Timer2 is to be used as a high speed profile timer  */
  65        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
  66                MCFSIM_TIMER2ICR);
  67        mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
  68#endif
  69#endif /* MCFSIM_ICR_AUTOVEC */
  70}
  71
  72/***************************************************************************/
  73
  74static irqreturn_t mcftmr_tick(int irq, void *dummy)
  75{
  76        /* Reset the ColdFire timer */
  77        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
  78
  79        mcftmr_cnt += mcftmr_cycles_per_jiffy;
  80        return timer_interrupt(irq, dummy);
  81}
  82
  83/***************************************************************************/
  84
  85static struct irqaction mcftmr_timer_irq = {
  86        .name    = "timer",
  87        .flags   = IRQF_TIMER,
  88        .handler = mcftmr_tick,
  89};
  90
  91/***************************************************************************/
  92
  93static u64 mcftmr_read_clk(struct clocksource *cs)
  94{
  95        unsigned long flags;
  96        u32 cycles;
  97        u16 tcn;
  98
  99        local_irq_save(flags);
 100        tcn = __raw_readw(TA(MCFTIMER_TCN));
 101        cycles = mcftmr_cnt;
 102        local_irq_restore(flags);
 103
 104        return cycles + tcn;
 105}
 106
 107/***************************************************************************/
 108
 109static struct clocksource mcftmr_clk = {
 110        .name   = "tmr",
 111        .rating = 250,
 112        .read   = mcftmr_read_clk,
 113        .mask   = CLOCKSOURCE_MASK(32),
 114        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 115};
 116
 117/***************************************************************************/
 118
 119void hw_timer_init(irq_handler_t handler)
 120{
 121        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
 122        mcftmr_cycles_per_jiffy = FREQ / HZ;
 123        /*
 124         *      The coldfire timer runs from 0 to TRR included, then 0
 125         *      again and so on.  It counts thus actually TRR + 1 steps
 126         *      for 1 tick, not TRR.  So if you want n cycles,
 127         *      initialize TRR with n - 1.
 128         */
 129        __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
 130        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
 131                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 132
 133        clocksource_register_hz(&mcftmr_clk, FREQ);
 134
 135        timer_interrupt = handler;
 136        init_timer_irq();
 137        setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
 138
 139#ifdef CONFIG_HIGHPROFILE
 140        coldfire_profile_init();
 141#endif
 142}
 143
 144/***************************************************************************/
 145#ifdef CONFIG_HIGHPROFILE
 146/***************************************************************************/
 147
 148/*
 149 *      By default use timer2 as the profiler clock timer.
 150 */
 151#define PA(a)   (MCFTIMER_BASE2 + (a))
 152
 153/*
 154 *      Choose a reasonably fast profile timer. Make it an odd value to
 155 *      try and get good coverage of kernel operations.
 156 */
 157#define PROFILEHZ       1013
 158
 159/*
 160 *      Use the other timer to provide high accuracy profiling info.
 161 */
 162irqreturn_t coldfire_profile_tick(int irq, void *dummy)
 163{
 164        /* Reset ColdFire timer2 */
 165        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
 166        if (current->pid)
 167                profile_tick(CPU_PROFILING);
 168        return IRQ_HANDLED;
 169}
 170
 171/***************************************************************************/
 172
 173static struct irqaction coldfire_profile_irq = {
 174        .name    = "profile timer",
 175        .flags   = IRQF_TIMER,
 176        .handler = coldfire_profile_tick,
 177};
 178
 179void coldfire_profile_init(void)
 180{
 181        printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
 182               PROFILEHZ);
 183
 184        /* Set up TIMER 2 as high speed profile clock */
 185        __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
 186
 187        __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
 188        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
 189                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
 190
 191        setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
 192}
 193
 194/***************************************************************************/
 195#endif  /* CONFIG_HIGHPROFILE */
 196/***************************************************************************/
 197