Branch data Line data Source code
1 : : /*
2 : : * linux/arch/arm/common/timer-sp.c
3 : : *
4 : : * Copyright (C) 1999 - 2003 ARM Limited
5 : : * Copyright (C) 2000 Deep Blue Solutions Ltd
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, write to the Free Software
19 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 : : */
21 : : #include <linux/clk.h>
22 : : #include <linux/clocksource.h>
23 : : #include <linux/clockchips.h>
24 : : #include <linux/err.h>
25 : : #include <linux/interrupt.h>
26 : : #include <linux/irq.h>
27 : : #include <linux/io.h>
28 : : #include <linux/of.h>
29 : : #include <linux/of_address.h>
30 : : #include <linux/of_irq.h>
31 : : #include <linux/sched_clock.h>
32 : :
33 : : #include <asm/hardware/arm_timer.h>
34 : : #include <asm/hardware/timer-sp.h>
35 : :
36 : 0 : static long __init sp804_get_clock_rate(struct clk *clk)
37 : : {
38 : : long rate;
39 : : int err;
40 : :
41 : 0 : err = clk_prepare(clk);
42 [ # # ]: 0 : if (err) {
43 : 0 : pr_err("sp804: clock failed to prepare: %d\n", err);
44 : 0 : clk_put(clk);
45 : 0 : return err;
46 : : }
47 : :
48 : 0 : err = clk_enable(clk);
49 [ # # ]: 0 : if (err) {
50 : 0 : pr_err("sp804: clock failed to enable: %d\n", err);
51 : 0 : clk_unprepare(clk);
52 : 0 : clk_put(clk);
53 : 0 : return err;
54 : : }
55 : :
56 : 0 : rate = clk_get_rate(clk);
57 [ # # ]: 0 : if (rate < 0) {
58 : 0 : pr_err("sp804: clock failed to get rate: %ld\n", rate);
59 : 0 : clk_disable(clk);
60 : 0 : clk_unprepare(clk);
61 : 0 : clk_put(clk);
62 : : }
63 : :
64 : 0 : return rate;
65 : : }
66 : :
67 : : static void __iomem *sched_clock_base;
68 : :
69 : 0 : static u32 sp804_read(void)
70 : : {
71 : 0 : return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
72 : : }
73 : :
74 : 0 : void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
75 : : const char *name,
76 : : struct clk *clk,
77 : : int use_sched_clock)
78 : : {
79 : : long rate;
80 : :
81 [ # # ]: 0 : if (!clk) {
82 : 0 : clk = clk_get_sys("sp804", name);
83 [ # # ]: 0 : if (IS_ERR(clk)) {
84 : 0 : pr_err("sp804: clock not found: %d\n",
85 : : (int)PTR_ERR(clk));
86 : 0 : return;
87 : : }
88 : : }
89 : :
90 : 0 : rate = sp804_get_clock_rate(clk);
91 : :
92 [ # # ]: 0 : if (rate < 0)
93 : : return;
94 : :
95 : : /* setup timer 0 as free-running clocksource */
96 : 0 : writel(0, base + TIMER_CTRL);
97 : 0 : writel(0xffffffff, base + TIMER_LOAD);
98 : 0 : writel(0xffffffff, base + TIMER_VALUE);
99 : 0 : writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
100 : : base + TIMER_CTRL);
101 : :
102 : 0 : clocksource_mmio_init(base + TIMER_VALUE, name,
103 : : rate, 200, 32, clocksource_mmio_readl_down);
104 : :
105 [ # # ]: 0 : if (use_sched_clock) {
106 : 0 : sched_clock_base = base;
107 : 0 : setup_sched_clock(sp804_read, 32, rate);
108 : : }
109 : : }
110 : :
111 : :
112 : : static void __iomem *clkevt_base;
113 : : static unsigned long clkevt_reload;
114 : :
115 : : /*
116 : : * IRQ handler for the timer
117 : : */
118 : 0 : static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
119 : : {
120 : : struct clock_event_device *evt = dev_id;
121 : :
122 : : /* clear the interrupt */
123 : 640582 : writel(1, clkevt_base + TIMER_INTCLR);
124 : :
125 : 640582 : evt->event_handler(evt);
126 : :
127 : 640582 : return IRQ_HANDLED;
128 : : }
129 : :
130 : 0 : static void sp804_set_mode(enum clock_event_mode mode,
131 : : struct clock_event_device *evt)
132 : : {
133 : : unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE;
134 : :
135 : 0 : writel(ctrl, clkevt_base + TIMER_CTRL);
136 : :
137 [ # # # ]: 0 : switch (mode) {
138 : : case CLOCK_EVT_MODE_PERIODIC:
139 : 0 : writel(clkevt_reload, clkevt_base + TIMER_LOAD);
140 : : ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
141 : 0 : break;
142 : :
143 : : case CLOCK_EVT_MODE_ONESHOT:
144 : : /* period set, and timer enabled in 'next_event' hook */
145 : : ctrl |= TIMER_CTRL_ONESHOT;
146 : 0 : break;
147 : :
148 : : case CLOCK_EVT_MODE_UNUSED:
149 : : case CLOCK_EVT_MODE_SHUTDOWN:
150 : : default:
151 : : break;
152 : : }
153 : :
154 : 0 : writel(ctrl, clkevt_base + TIMER_CTRL);
155 : 0 : }
156 : :
157 : 0 : static int sp804_set_next_event(unsigned long next,
158 : : struct clock_event_device *evt)
159 : : {
160 : 878247 : unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
161 : :
162 : 878247 : writel(next, clkevt_base + TIMER_LOAD);
163 : 878247 : writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
164 : :
165 : 878247 : return 0;
166 : : }
167 : :
168 : : static struct clock_event_device sp804_clockevent = {
169 : : .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
170 : : CLOCK_EVT_FEAT_DYNIRQ,
171 : : .set_mode = sp804_set_mode,
172 : : .set_next_event = sp804_set_next_event,
173 : : .rating = 300,
174 : : };
175 : :
176 : : static struct irqaction sp804_timer_irq = {
177 : : .name = "timer",
178 : : .flags = IRQF_TIMER | IRQF_IRQPOLL,
179 : : .handler = sp804_timer_interrupt,
180 : : .dev_id = &sp804_clockevent,
181 : : };
182 : :
183 : 0 : void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
184 : : {
185 : : struct clock_event_device *evt = &sp804_clockevent;
186 : : long rate;
187 : :
188 [ # # ]: 0 : if (!clk)
189 : 0 : clk = clk_get_sys("sp804", name);
190 [ # # ]: 0 : if (IS_ERR(clk)) {
191 : 0 : pr_err("sp804: %s clock not found: %d\n", name,
192 : : (int)PTR_ERR(clk));
193 : 0 : return;
194 : : }
195 : :
196 : 0 : rate = sp804_get_clock_rate(clk);
197 [ # # ]: 0 : if (rate < 0)
198 : : return;
199 : :
200 : 0 : clkevt_base = base;
201 [ # # ]: 0 : clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
202 : 0 : evt->name = name;
203 : 0 : evt->irq = irq;
204 : 0 : evt->cpumask = cpu_possible_mask;
205 : :
206 : 0 : writel(0, base + TIMER_CTRL);
207 : :
208 : 0 : setup_irq(irq, &sp804_timer_irq);
209 : 0 : clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
210 : : }
211 : :
212 : 0 : static void __init sp804_of_init(struct device_node *np)
213 : : {
214 : : static bool initialized = false;
215 : : void __iomem *base;
216 : : int irq;
217 : 0 : u32 irq_num = 0;
218 : : struct clk *clk1, *clk2;
219 : 0 : const char *name = of_get_property(np, "compatible", NULL);
220 : :
221 : 0 : base = of_iomap(np, 0);
222 [ # # ][ # # ]: 0 : if (WARN_ON(!base))
223 : 0 : return;
224 : :
225 : : /* Ensure timers are disabled */
226 : 0 : writel(0, base + TIMER_CTRL);
227 : 0 : writel(0, base + TIMER_2_BASE + TIMER_CTRL);
228 : :
229 [ # # ][ # # ]: 0 : if (initialized || !of_device_is_available(np))
230 : : goto err;
231 : :
232 : 0 : clk1 = of_clk_get(np, 0);
233 [ # # ]: 0 : if (IS_ERR(clk1))
234 : : clk1 = NULL;
235 : :
236 : : /* Get the 2nd clock if the timer has 2 timer clocks */
237 [ # # ]: 0 : if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
238 : 0 : clk2 = of_clk_get(np, 1);
239 [ # # ]: 0 : if (IS_ERR(clk2)) {
240 : 0 : pr_err("sp804: %s clock not found: %d\n", np->name,
241 : : (int)PTR_ERR(clk2));
242 : 0 : goto err;
243 : : }
244 : : } else
245 : : clk2 = clk1;
246 : :
247 : 0 : irq = irq_of_parse_and_map(np, 0);
248 [ # # ]: 0 : if (irq <= 0)
249 : : goto err;
250 : :
251 : : of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
252 [ # # ]: 0 : if (irq_num == 2) {
253 : 0 : __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
254 : 0 : __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
255 : : } else {
256 : 0 : __sp804_clockevents_init(base, irq, clk1 , name);
257 : 0 : __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
258 : : name, clk2, 1);
259 : : }
260 : 0 : initialized = true;
261 : :
262 : 0 : return;
263 : : err:
264 : 0 : iounmap(base);
265 : : }
266 : : CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
267 : :
268 : 0 : static void __init integrator_cp_of_init(struct device_node *np)
269 : : {
270 : : static int init_count = 0;
271 : : void __iomem *base;
272 : : int irq;
273 : 0 : const char *name = of_get_property(np, "compatible", NULL);
274 : :
275 : 0 : base = of_iomap(np, 0);
276 [ # # ][ # # ]: 0 : if (WARN_ON(!base))
277 : : return;
278 : :
279 : : /* Ensure timer is disabled */
280 : 0 : writel(0, base + TIMER_CTRL);
281 : :
282 [ # # ][ # # ]: 0 : if (init_count == 2 || !of_device_is_available(np))
283 : : goto err;
284 : :
285 [ # # ]: 0 : if (!init_count)
286 : : sp804_clocksource_init(base, name);
287 : : else {
288 : 0 : irq = irq_of_parse_and_map(np, 0);
289 [ # # ]: 0 : if (irq <= 0)
290 : : goto err;
291 : :
292 : : sp804_clockevents_init(base, irq, name);
293 : : }
294 : :
295 : 0 : init_count++;
296 : 0 : return;
297 : : err:
298 : 0 : iounmap(base);
299 : : }
300 : : CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
|