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