1/***************************************************************************/ 2 3/* 4 * timers.c -- generic ColdFire hardware timer support. 5 * 6 * Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com) 7 */ 8 9/***************************************************************************/ 10 11#include <linux/kernel.h> 12#include <linux/sched.h> 13#include <linux/param.h> 14#include <linux/interrupt.h> 15#include <linux/init.h> 16#include <asm/io.h> 17#include <asm/irq.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> 23 24/***************************************************************************/ 25 26/* 27 * By default use timer1 as the system clock timer. 28 */ 29#define TA(a) (MCF_MBAR + MCFTIMER_BASE1 + (a)) 30 31/* 32 * Default the timer and vector to use for ColdFire. Some ColdFire 33 * CPU's and some boards may want different. Their sub-architecture 34 * startup code (in config.c) can change these if they want. 35 */ 36unsigned int mcf_timervector = 29; 37unsigned int mcf_profilevector = 31; 38unsigned int mcf_timerlevel = 5; 39 40/* 41 * These provide the underlying interrupt vector support. 42 * Unfortunately it is a little different on each ColdFire. 43 */ 44extern void mcf_settimericr(int timer, int level); 45extern int mcf_timerirqpending(int timer); 46 47#if defined(CONFIG_M532x) 48#define __raw_readtrr __raw_readl 49#define __raw_writetrr __raw_writel 50#else 51#define __raw_readtrr __raw_readw 52#define __raw_writetrr __raw_writew 53#endif 54 55/***************************************************************************/ 56 57void coldfire_tick(void) 58{ 59 /* Reset the ColdFire timer */ 60 __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); 61} 62 63/***************************************************************************/ 64 65static int ticks_per_intr; 66 67void coldfire_timer_init(irq_handler_t handler) 68{ 69 __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); 70 ticks_per_intr = (MCF_BUSCLK / 16) / HZ; 71 __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR)); 72 __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | 73 MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); 74 75 request_irq(mcf_timervector, handler, IRQF_DISABLED, "timer", NULL); 76 mcf_settimericr(1, mcf_timerlevel); 77 78#ifdef CONFIG_HIGHPROFILE 79 coldfire_profile_init(); 80#endif 81} 82 83/***************************************************************************/ 84 85unsigned long coldfire_timer_offset(void) 86{ 87 unsigned long tcn, offset; 88 89 tcn = __raw_readw(TA(MCFTIMER_TCN)); 90 offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr; 91 92 /* Check if we just wrapped the counters and maybe missed a tick */ 93 if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1)) 94 offset += 1000000 / HZ; 95 return offset; 96} 97 98/***************************************************************************/ 99#ifdef CONFIG_HIGHPROFILE 100/***************************************************************************/ 101 102/* 103 * By default use timer2 as the profiler clock timer. 104 */ 105#define PA(a) (MCF_MBAR + MCFTIMER_BASE2 + (a)) 106 107/* 108 * Choose a reasonably fast profile timer. Make it an odd value to 109 * try and get good coverage of kernel operations. 110 */ 111#define PROFILEHZ 1013 112 113/* 114 * Use the other timer to provide high accuracy profiling info. 115 */ 116irqreturn_t coldfire_profile_tick(int irq, void *dummy) 117{ 118 /* Reset ColdFire timer2 */ 119 __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); 120 if (current->pid) 121 profile_tick(CPU_PROFILING, regs); 122 return IRQ_HANDLED; 123} 124 125/***************************************************************************/ 126 127void coldfire_profile_init(void) 128{ 129 printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ); 130 131 /* Set up TIMER 2 as high speed profile clock */ 132 __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); 133 134 __raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); 135 __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | 136 MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); 137 138 request_irq(mcf_profilevector, coldfire_profile_tick, 139 (IRQF_DISABLED | IRQ_FLG_FAST), "profile timer", NULL); 140 mcf_settimericr(2, 7); 141} 142 143/***************************************************************************/ 144#endif /* CONFIG_HIGHPROFILE */ 145/***************************************************************************/ 146