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