1 /*
2 * linux/include/asm-arm/arch-omaha/time.h
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <asm/system.h>
19 #include <asm/leds.h>
20
21 #define TIMER_INTERVAL mSEC_10
22
23 extern unsigned long (*gettimeoffset)(void);
24
25 /*
26 * Returns number of ms since last clock interrupt. Note that interrupts
27 * will have been disabled by do_gettimeoffset()
28 */
omaha_gettimeoffset(void)29 static unsigned long omaha_gettimeoffset(void)
30 {
31 volatile unsigned int *p;
32 unsigned long ticks1, ticks2;
33
34 /*
35 * Get the current number of ticks. Note that there is a race
36 * condition between us reading the timer and checking for
37 * an interrupt. We get around this by ensuring that the
38 * counter has not reloaded between our two reads.
39 */
40 p = (unsigned int *)(IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TCNTB0));
41
42 // Its only 16-bits
43 ticks2 = __raw_readl(p);
44
45 do {
46 ticks1 = ticks2;
47 ticks2 = __raw_readl(p);
48 } while (ticks2 > ticks1);
49
50 /*
51 * Number of ticks since last interrupt.
52 */
53 ticks1 = TIMER_INTERVAL - ticks2;
54
55 // Return number of usecs since last interrupt
56 return ticks1;
57 }
58
59 /*
60 * IRQ handler for the timer
61 */
omaha_timer_interrupt(int irq,void * dev_id,struct pt_regs * regs)62 static void omaha_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
63 {
64 volatile unsigned int *p;
65 int tmp;
66
67 // Clear the interrupt pending register
68 p = (unsigned int *)(IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_SRCPND));
69
70 tmp = __raw_readl(p);
71 tmp = tmp & ~OMAHA_INT_TIMER0;
72 __raw_writel(tmp, p);
73
74 do_leds();
75 do_timer(regs);
76 do_profile(regs);
77 }
78
79 /*
80 * Set up timer interrupt, and return the current time in seconds.
81 *
82 * The bootloader ensures that the timer always counts at 1MHz.
83 */
setup_timer(void)84 static inline void setup_timer(void)
85 {
86 volatile unsigned int *p;
87 int tmp;
88
89 timer_irq.handler = omaha_timer_interrupt;
90
91 /*
92 * Program reload count.
93 */
94 p = (unsigned int *)(IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TCNTB0));
95
96 __raw_writel(TIMER_INTERVAL, p);
97
98 // Set manual update bit, clear start bit
99 p = (unsigned int *)(IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TCON));
100 tmp = __raw_readl(p);
101 tmp = tmp | 0x2;
102 tmp = tmp & ~0x1;
103 __raw_writel(tmp, p);
104
105 // Clear manual update bit and set start bit
106 p = (unsigned int *)(IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TCON));
107 tmp = __raw_readl(p);
108 tmp = tmp & ~0x2;
109 tmp = tmp | 0x1;
110 __raw_writel(tmp, p);
111
112 /*
113 * Make irqs happen for the system timer
114 */
115 setup_arm_irq(OMAHA_INT_TIMER0, &timer_irq);
116 gettimeoffset = omaha_gettimeoffset;
117 }
118