Path: blob/master/arch/m68k/platform/coldfire/timers.c
10819 views
/***************************************************************************/12/*3* timers.c -- generic ColdFire hardware timer support.4*5* Copyright (C) 1999-2008, Greg Ungerer <[email protected]>6*/78/***************************************************************************/910#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/sched.h>13#include <linux/interrupt.h>14#include <linux/irq.h>15#include <linux/profile.h>16#include <linux/clocksource.h>17#include <asm/io.h>18#include <asm/traps.h>19#include <asm/machdep.h>20#include <asm/coldfire.h>21#include <asm/mcftimer.h>22#include <asm/mcfsim.h>2324/***************************************************************************/2526/*27* By default use timer1 as the system clock timer.28*/29#define FREQ (MCF_BUSCLK / 16)30#define TA(a) (MCFTIMER_BASE1 + (a))3132/*33* These provide the underlying interrupt vector support.34* Unfortunately it is a little different on each ColdFire.35*/36void coldfire_profile_init(void);3738#if defined(CONFIG_M532x)39#define __raw_readtrr __raw_readl40#define __raw_writetrr __raw_writel41#else42#define __raw_readtrr __raw_readw43#define __raw_writetrr __raw_writew44#endif4546static u32 mcftmr_cycles_per_jiffy;47static u32 mcftmr_cnt;4849/***************************************************************************/5051static irqreturn_t mcftmr_tick(int irq, void *dummy)52{53/* Reset the ColdFire timer */54__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));5556mcftmr_cnt += mcftmr_cycles_per_jiffy;57return arch_timer_interrupt(irq, dummy);58}5960/***************************************************************************/6162static struct irqaction mcftmr_timer_irq = {63.name = "timer",64.flags = IRQF_DISABLED | IRQF_TIMER,65.handler = mcftmr_tick,66};6768/***************************************************************************/6970static cycle_t mcftmr_read_clk(struct clocksource *cs)71{72unsigned long flags;73u32 cycles;74u16 tcn;7576local_irq_save(flags);77tcn = __raw_readw(TA(MCFTIMER_TCN));78cycles = mcftmr_cnt;79local_irq_restore(flags);8081return cycles + tcn;82}8384/***************************************************************************/8586static struct clocksource mcftmr_clk = {87.name = "tmr",88.rating = 250,89.read = mcftmr_read_clk,90.shift = 20,91.mask = CLOCKSOURCE_MASK(32),92.flags = CLOCK_SOURCE_IS_CONTINUOUS,93};9495/***************************************************************************/9697void hw_timer_init(void)98{99__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));100mcftmr_cycles_per_jiffy = FREQ / HZ;101/*102* The coldfire timer runs from 0 to TRR included, then 0103* again and so on. It counts thus actually TRR + 1 steps104* for 1 tick, not TRR. So if you want n cycles,105* initialize TRR with n - 1.106*/107__raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));108__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |109MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));110111mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);112clocksource_register(&mcftmr_clk);113114setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);115116#ifdef CONFIG_HIGHPROFILE117coldfire_profile_init();118#endif119}120121/***************************************************************************/122#ifdef CONFIG_HIGHPROFILE123/***************************************************************************/124125/*126* By default use timer2 as the profiler clock timer.127*/128#define PA(a) (MCFTIMER_BASE2 + (a))129130/*131* Choose a reasonably fast profile timer. Make it an odd value to132* try and get good coverage of kernel operations.133*/134#define PROFILEHZ 1013135136/*137* Use the other timer to provide high accuracy profiling info.138*/139irqreturn_t coldfire_profile_tick(int irq, void *dummy)140{141/* Reset ColdFire timer2 */142__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));143if (current->pid)144profile_tick(CPU_PROFILING);145return IRQ_HANDLED;146}147148/***************************************************************************/149150static struct irqaction coldfire_profile_irq = {151.name = "profile timer",152.flags = IRQF_DISABLED | IRQF_TIMER,153.handler = coldfire_profile_tick,154};155156void coldfire_profile_init(void)157{158printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",159PROFILEHZ);160161/* Set up TIMER 2 as high speed profile clock */162__raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));163164__raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));165__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |166MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));167168setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);169}170171/***************************************************************************/172#endif /* CONFIG_HIGHPROFILE */173/***************************************************************************/174175176