xref: /openbmc/linux/arch/arm/plat-orion/time.c (revision 22fd411a)
1 /*
2  * arch/arm/plat-orion/time.c
3  *
4  * Marvell Orion SoC timer handling.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  *
10  * Timer 0 is used as free-running clocksource, while timer 1 is
11  * used as clock_event_device.
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/timer.h>
17 #include <linux/clockchips.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <asm/sched_clock.h>
21 #include <asm/mach/time.h>
22 #include <mach/bridge-regs.h>
23 #include <mach/hardware.h>
24 
25 /*
26  * Number of timer ticks per jiffy.
27  */
28 static u32 ticks_per_jiffy;
29 
30 
31 /*
32  * Timer block registers.
33  */
34 #define TIMER_CTRL		(TIMER_VIRT_BASE + 0x0000)
35 #define  TIMER0_EN		0x0001
36 #define  TIMER0_RELOAD_EN	0x0002
37 #define  TIMER1_EN		0x0004
38 #define  TIMER1_RELOAD_EN	0x0008
39 #define TIMER0_RELOAD		(TIMER_VIRT_BASE + 0x0010)
40 #define TIMER0_VAL		(TIMER_VIRT_BASE + 0x0014)
41 #define TIMER1_RELOAD		(TIMER_VIRT_BASE + 0x0018)
42 #define TIMER1_VAL		(TIMER_VIRT_BASE + 0x001c)
43 
44 
45 /*
46  * Orion's sched_clock implementation. It has a resolution of
47  * at least 7.5ns (133MHz TCLK).
48  */
49 static DEFINE_CLOCK_DATA(cd);
50 
51 unsigned long long notrace sched_clock(void)
52 {
53 	u32 cyc = 0xffffffff - readl(TIMER0_VAL);
54 	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
55 }
56 
57 
58 static void notrace orion_update_sched_clock(void)
59 {
60 	u32 cyc = 0xffffffff - readl(TIMER0_VAL);
61 	update_sched_clock(&cd, cyc, (u32)~0);
62 }
63 
64 static void __init setup_sched_clock(unsigned long tclk)
65 {
66 	init_sched_clock(&cd, orion_update_sched_clock, 32, tclk);
67 }
68 
69 /*
70  * Clocksource handling.
71  */
72 static cycle_t orion_clksrc_read(struct clocksource *cs)
73 {
74 	return 0xffffffff - readl(TIMER0_VAL);
75 }
76 
77 static struct clocksource orion_clksrc = {
78 	.name		= "orion_clocksource",
79 	.rating		= 300,
80 	.read		= orion_clksrc_read,
81 	.mask		= CLOCKSOURCE_MASK(32),
82 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
83 };
84 
85 
86 
87 /*
88  * Clockevent handling.
89  */
90 static int
91 orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
92 {
93 	unsigned long flags;
94 	u32 u;
95 
96 	if (delta == 0)
97 		return -ETIME;
98 
99 	local_irq_save(flags);
100 
101 	/*
102 	 * Clear and enable clockevent timer interrupt.
103 	 */
104 	writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
105 
106 	u = readl(BRIDGE_MASK);
107 	u |= BRIDGE_INT_TIMER1;
108 	writel(u, BRIDGE_MASK);
109 
110 	/*
111 	 * Setup new clockevent timer value.
112 	 */
113 	writel(delta, TIMER1_VAL);
114 
115 	/*
116 	 * Enable the timer.
117 	 */
118 	u = readl(TIMER_CTRL);
119 	u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN;
120 	writel(u, TIMER_CTRL);
121 
122 	local_irq_restore(flags);
123 
124 	return 0;
125 }
126 
127 static void
128 orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
129 {
130 	unsigned long flags;
131 	u32 u;
132 
133 	local_irq_save(flags);
134 	if (mode == CLOCK_EVT_MODE_PERIODIC) {
135 		/*
136 		 * Setup timer to fire at 1/HZ intervals.
137 		 */
138 		writel(ticks_per_jiffy - 1, TIMER1_RELOAD);
139 		writel(ticks_per_jiffy - 1, TIMER1_VAL);
140 
141 		/*
142 		 * Enable timer interrupt.
143 		 */
144 		u = readl(BRIDGE_MASK);
145 		writel(u | BRIDGE_INT_TIMER1, BRIDGE_MASK);
146 
147 		/*
148 		 * Enable timer.
149 		 */
150 		u = readl(TIMER_CTRL);
151 		writel(u | TIMER1_EN | TIMER1_RELOAD_EN, TIMER_CTRL);
152 	} else {
153 		/*
154 		 * Disable timer.
155 		 */
156 		u = readl(TIMER_CTRL);
157 		writel(u & ~TIMER1_EN, TIMER_CTRL);
158 
159 		/*
160 		 * Disable timer interrupt.
161 		 */
162 		u = readl(BRIDGE_MASK);
163 		writel(u & ~BRIDGE_INT_TIMER1, BRIDGE_MASK);
164 
165 		/*
166 		 * ACK pending timer interrupt.
167 		 */
168 		writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
169 
170 	}
171 	local_irq_restore(flags);
172 }
173 
174 static struct clock_event_device orion_clkevt = {
175 	.name		= "orion_tick",
176 	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
177 	.shift		= 32,
178 	.rating		= 300,
179 	.set_next_event	= orion_clkevt_next_event,
180 	.set_mode	= orion_clkevt_mode,
181 };
182 
183 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
184 {
185 	/*
186 	 * ACK timer interrupt and call event handler.
187 	 */
188 	writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
189 	orion_clkevt.event_handler(&orion_clkevt);
190 
191 	return IRQ_HANDLED;
192 }
193 
194 static struct irqaction orion_timer_irq = {
195 	.name		= "orion_tick",
196 	.flags		= IRQF_DISABLED | IRQF_TIMER,
197 	.handler	= orion_timer_interrupt
198 };
199 
200 void __init orion_time_init(unsigned int irq, unsigned int tclk)
201 {
202 	u32 u;
203 
204 	ticks_per_jiffy = (tclk + HZ/2) / HZ;
205 
206 	/*
207 	 * Set scale and timer for sched_clock
208 	 */
209 	setup_sched_clock(tclk);
210 
211 	/*
212 	 * Setup free-running clocksource timer (interrupts
213 	 * disabled.)
214 	 */
215 	writel(0xffffffff, TIMER0_VAL);
216 	writel(0xffffffff, TIMER0_RELOAD);
217 	u = readl(BRIDGE_MASK);
218 	writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK);
219 	u = readl(TIMER_CTRL);
220 	writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL);
221 	clocksource_register_hz(&orion_clksrc, tclk);
222 
223 	/*
224 	 * Setup clockevent timer (interrupt-driven.)
225 	 */
226 	setup_irq(irq, &orion_timer_irq);
227 	orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift);
228 	orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt);
229 	orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt);
230 	orion_clkevt.cpumask = cpumask_of(0);
231 	clockevents_register_device(&orion_clkevt);
232 }
233