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