]> bbs.cooldavid.org Git - net-next-2.6.git/blame - arch/m68knommu/platform/5307/timers.c
Linux-2.6.12-rc2
[net-next-2.6.git] / arch / m68knommu / platform / 5307 / timers.c
CommitLineData
1da177e4
LT
1/***************************************************************************/
2
3/*
4 * timers.c -- generic ColdFire hardware timer support.
5 *
6 * Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
7 */
8
9/***************************************************************************/
10
11#include <linux/config.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/param.h>
15#include <linux/interrupt.h>
16#include <linux/init.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 * Default the timer and vector to use for ColdFire. Some ColdFire
28 * CPU's and some boards may want different. Their sub-architecture
29 * startup code (in config.c) can change these if they want.
30 */
31unsigned int mcf_timervector = 29;
32unsigned int mcf_profilevector = 31;
33unsigned int mcf_timerlevel = 5;
34
35static volatile struct mcftimer *mcf_timerp;
36
37/*
38 * These provide the underlying interrupt vector support.
39 * Unfortunately it is a little different on each ColdFire.
40 */
41extern void mcf_settimericr(int timer, int level);
42extern int mcf_timerirqpending(int timer);
43
44/***************************************************************************/
45
46void coldfire_tick(void)
47{
48 /* Reset the ColdFire timer */
49 mcf_timerp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
50}
51
52/***************************************************************************/
53
54void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
55{
56 /* Set up an internal TIMER as poll clock */
57 mcf_timerp = (volatile struct mcftimer *) (MCF_MBAR + MCFTIMER_BASE1);
58 mcf_timerp->tmr = MCFTIMER_TMR_DISABLE;
59
60 mcf_timerp->trr = (unsigned short) ((MCF_BUSCLK / 16) / HZ);
61 mcf_timerp->tmr = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
62 MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE;
63
64 request_irq(mcf_timervector, handler, SA_INTERRUPT, "timer", NULL);
65 mcf_settimericr(1, mcf_timerlevel);
66
67#ifdef CONFIG_HIGHPROFILE
68 coldfire_profile_init();
69#endif
70}
71
72/***************************************************************************/
73
74unsigned long coldfire_timer_offset(void)
75{
76 unsigned long trr, tcn, offset;
77
78 /*
79 * The change to pointer and de-reference is to force the compiler
80 * to read the registers with a single 16bit access. Otherwise it
81 * does some crazy 8bit read combining.
82 */
83 tcn = *(&mcf_timerp->tcn);
84 trr = *(&mcf_timerp->trr);
85 offset = (tcn * (1000000 / HZ)) / trr;
86
87 /* Check if we just wrapped the counters and maybe missed a tick */
88 if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1))
89 offset += 1000000 / HZ;
90 return offset;
91}
92
93/***************************************************************************/
94#ifdef CONFIG_HIGHPROFILE
95/***************************************************************************/
96
97/*
98 * Choose a reasonably fast profile timer. Make it an odd value to
99 * try and get good coverage of kernal operations.
100 */
101#define PROFILEHZ 1013
102
103static volatile struct mcftimer *mcf_proftp;
104
105/*
106 * Use the other timer to provide high accuracy profiling info.
107 */
108
109void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs)
110{
111 /* Reset ColdFire timer2 */
112 mcf_proftp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
113 if (current->pid)
114 profile_tick(CPU_PROFILING, regs);
115}
116
117/***************************************************************************/
118
119void coldfire_profile_init(void)
120{
121 printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ);
122
123 /* Set up TIMER 2 as high speed profile clock */
124 mcf_proftp = (volatile struct mcftimer *) (MCF_MBAR + MCFTIMER_BASE2);
125 mcf_proftp->tmr = MCFTIMER_TMR_DISABLE;
126
127 mcf_proftp->trr = (unsigned short) ((MCF_CLK / 16) / PROFILEHZ);
128 mcf_proftp->tmr = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
129 MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE;
130
131 request_irq(mcf_profilevector, coldfire_profile_tick,
132 (SA_INTERRUPT | IRQ_FLG_FAST), "profile timer", NULL);
133 mcf_settimericr(2, 7);
134}
135
136/***************************************************************************/
137#endif /* CONFIG_HIGHPROFILE */
138/***************************************************************************/