Path: blob/master/arch/m68k/platform/coldfire/sltimers.c
10819 views
/***************************************************************************/12/*3* sltimers.c -- generic ColdFire slice timer support.4*5* Copyright (C) 2009-2010, Philippe De Muyter <[email protected]>6* based on7* timers.c -- generic ColdFire hardware timer support.8* Copyright (C) 1999-2008, Greg Ungerer <[email protected]>9*/1011/***************************************************************************/1213#include <linux/kernel.h>14#include <linux/init.h>15#include <linux/sched.h>16#include <linux/interrupt.h>17#include <linux/irq.h>18#include <linux/profile.h>19#include <linux/clocksource.h>20#include <asm/io.h>21#include <asm/traps.h>22#include <asm/machdep.h>23#include <asm/coldfire.h>24#include <asm/mcfslt.h>25#include <asm/mcfsim.h>2627/***************************************************************************/2829#ifdef CONFIG_HIGHPROFILE3031/*32* By default use Slice Timer 1 as the profiler clock timer.33*/34#define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a))3536/*37* Choose a reasonably fast profile timer. Make it an odd value to38* try and get good coverage of kernel operations.39*/40#define PROFILEHZ 10134142irqreturn_t mcfslt_profile_tick(int irq, void *dummy)43{44/* Reset Slice Timer 1 */45__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));46if (current->pid)47profile_tick(CPU_PROFILING);48return IRQ_HANDLED;49}5051static struct irqaction mcfslt_profile_irq = {52.name = "profile timer",53.flags = IRQF_DISABLED | IRQF_TIMER,54.handler = mcfslt_profile_tick,55};5657void mcfslt_profile_init(void)58{59printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",60PROFILEHZ);6162setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);6364/* Set up TIMER 2 as high speed profile clock */65__raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));66__raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,67PA(MCFSLT_SCR));6869}7071#endif /* CONFIG_HIGHPROFILE */7273/***************************************************************************/7475/*76* By default use Slice Timer 0 as the system clock timer.77*/78#define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a))7980static u32 mcfslt_cycles_per_jiffy;81static u32 mcfslt_cnt;8283static irqreturn_t mcfslt_tick(int irq, void *dummy)84{85/* Reset Slice Timer 0 */86__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));87mcfslt_cnt += mcfslt_cycles_per_jiffy;88return arch_timer_interrupt(irq, dummy);89}9091static struct irqaction mcfslt_timer_irq = {92.name = "timer",93.flags = IRQF_DISABLED | IRQF_TIMER,94.handler = mcfslt_tick,95};9697static cycle_t mcfslt_read_clk(struct clocksource *cs)98{99unsigned long flags;100u32 cycles;101u16 scnt;102103local_irq_save(flags);104scnt = __raw_readl(TA(MCFSLT_SCNT));105cycles = mcfslt_cnt;106local_irq_restore(flags);107108/* subtract because slice timers count down */109return cycles - scnt;110}111112static struct clocksource mcfslt_clk = {113.name = "slt",114.rating = 250,115.read = mcfslt_read_clk,116.shift = 20,117.mask = CLOCKSOURCE_MASK(32),118.flags = CLOCK_SOURCE_IS_CONTINUOUS,119};120121void hw_timer_init(void)122{123mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;124/*125* The coldfire slice timer (SLT) runs from STCNT to 0 included,126* then STCNT again and so on. It counts thus actually127* STCNT + 1 steps for 1 tick, not STCNT. So if you want128* n cycles, initialize STCNT with n - 1.129*/130__raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));131__raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,132TA(MCFSLT_SCR));133/* initialize mcfslt_cnt knowing that slice timers count down */134mcfslt_cnt = mcfslt_cycles_per_jiffy;135136setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);137138mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);139clocksource_register(&mcfslt_clk);140141#ifdef CONFIG_HIGHPROFILE142mcfslt_profile_init();143#endif144}145146147