]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/arm/econa/timer.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / arm / econa / timer.c
1 /*-
2  * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/malloc.h>
35 #include <sys/rman.h>
36 #include <sys/timetc.h>
37 #include <sys/watchdog.h>
38 #include <machine/bus.h>
39 #include <machine/cpu.h>
40 #include <machine/frame.h>
41 #include <machine/intr.h>
42
43 #include "econa_reg.h"
44 #include "econa_var.h"
45
46 #define INITIAL_TIMECOUNTER     (0xffffffff)
47
48 static int timers_initialized = 0;
49
50 #define HZ      100
51
52 extern unsigned int CPU_clock;
53 extern unsigned int AHB_clock;
54 extern unsigned int APB_clock;
55
56 static unsigned long timer_counter = 0;
57
58 struct ec_timer_softc {
59         struct resource *       timer_res[3];
60         bus_space_tag_t         timer_bst;
61         bus_space_handle_t      timer_bsh;
62         struct mtx              timer_mtx;
63 };
64
65 static struct resource_spec ec_timer_spec[] = {
66         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
67         { SYS_RES_IRQ,          0,      RF_ACTIVE },
68         { SYS_RES_IRQ,          1,      RF_ACTIVE },
69         { -1, 0 }
70 };
71
72 static unsigned ec_timer_get_timecount(struct timecounter *);
73
74 static struct timecounter ec_timecounter = {
75         .tc_get_timecount = ec_timer_get_timecount,
76         .tc_name = "CPU Timer",
77         /* This is assigned on the fly in the init sequence */
78         .tc_frequency = 0,
79         .tc_counter_mask = ~0u,
80         .tc_quality = 1000,
81 };
82
83 static struct ec_timer_softc *timer_softc = NULL;
84
85 static inline
86 void write_4(unsigned int val, unsigned int addr)
87 {
88         bus_space_write_4(timer_softc->timer_bst,
89                           timer_softc->timer_bsh, addr, val);
90
91 }
92
93 static inline
94 unsigned int read_4(unsigned int addr)
95 {
96
97         return bus_space_read_4(timer_softc->timer_bst,
98             timer_softc->timer_bsh, addr);
99 }
100
101 #define uSECS_PER_TICK  (1000000 / APB_clock)
102 #define TICKS2USECS(x)  ((x) * uSECS_PER_TICK)
103
104 static unsigned
105 read_timer_counter_noint(void)
106 {
107
108         arm_mask_irq(0);
109         unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
110         arm_unmask_irq(0);
111         return v;
112 }
113
114 void
115 DELAY(int usec)
116 {
117         uint32_t val, val_temp;
118         int nticks;
119
120         if (!timers_initialized) {
121                 for (; usec > 0; usec--)
122                         for (val = 100; val > 0; val--)
123                                 ;
124                 return;
125         }
126
127         val = read_timer_counter_noint();
128         nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
129
130         while (nticks > 0) {
131                 val_temp = read_timer_counter_noint();
132                 if (val > val_temp)
133                         nticks -= (val - val_temp);
134                 else
135                         nticks -= (val + (timer_counter - val_temp));
136
137                 val = val_temp;
138         }
139
140 }
141
142 /*
143  * Setup timer
144  */
145 static inline void
146 setup_timer(unsigned int counter_value)
147 {
148         unsigned int control_value;
149         unsigned int mask_value;
150
151         control_value = read_4(TIMER_TM_CR_REG);
152
153         mask_value = read_4(TIMER_TM_INTR_MASK_REG);
154         write_4(counter_value, TIMER_TM1_COUNTER_REG);
155         write_4(counter_value, TIMER_TM1_LOAD_REG);
156         write_4(0, TIMER_TM1_MATCH1_REG);
157         write_4(0,TIMER_TM1_MATCH2_REG);
158
159         control_value &= ~(TIMER1_CLOCK_SOURCE);
160         control_value |= TIMER1_UP_DOWN_COUNT;
161
162         write_4(0, TIMER_TM2_COUNTER_REG);
163         write_4(0, TIMER_TM2_LOAD_REG);
164         write_4(~0u, TIMER_TM2_MATCH1_REG);
165         write_4(~0u,TIMER_TM2_MATCH2_REG);
166
167         control_value &= ~(TIMER2_CLOCK_SOURCE);
168         control_value &= ~(TIMER2_UP_DOWN_COUNT);
169
170         mask_value &= ~(63);
171
172         write_4(control_value, TIMER_TM_CR_REG);
173         write_4(mask_value, TIMER_TM_INTR_MASK_REG);
174 }
175
176 /*
177  * Enable timer
178  */
179 static inline void
180 timer_enable(void)
181 {
182         unsigned int control_value;
183
184         control_value = read_4(TIMER_TM_CR_REG);
185
186         control_value |= TIMER1_OVERFLOW_ENABLE;
187         control_value |= TIMER1_ENABLE;
188         control_value |= TIMER2_OVERFLOW_ENABLE;
189         control_value |= TIMER2_ENABLE;
190
191         write_4(control_value, TIMER_TM_CR_REG);
192 }
193
194 static inline unsigned int
195 read_second_timer_counter(void)
196 {
197
198         return read_4(TIMER_TM2_COUNTER_REG);
199 }
200
201 /*
202  * Get timer interrupt status
203  */
204 static inline unsigned int
205 read_timer_interrupt_status(void)
206 {
207
208         return read_4(TIMER_TM_INTR_STATUS_REG);
209 }
210
211 /*
212  * Clear timer interrupt status
213  */
214 static inline void
215 clear_timer_interrupt_status(unsigned int irq)
216 {
217         unsigned int interrupt_status;
218
219         interrupt_status =   read_4(TIMER_TM_INTR_STATUS_REG);
220         if (irq == 0) {
221                 if (interrupt_status & (TIMER1_MATCH1_INTR))
222                         interrupt_status &= ~(TIMER1_MATCH1_INTR);
223                 if (interrupt_status & (TIMER1_MATCH2_INTR))
224                         interrupt_status &= ~(TIMER1_MATCH2_INTR);
225                 if (interrupt_status & (TIMER1_OVERFLOW_INTR))
226                         interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
227         }
228         if (irq == 1) {
229                 if (interrupt_status & (TIMER2_MATCH1_INTR))
230                         interrupt_status &= ~(TIMER2_MATCH1_INTR);
231                 if (interrupt_status & (TIMER2_MATCH2_INTR))
232                         interrupt_status &= ~(TIMER2_MATCH2_INTR);
233                 if (interrupt_status & (TIMER2_OVERFLOW_INTR))
234                         interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
235         }
236
237         write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
238 }
239
240 static unsigned
241 ec_timer_get_timecount(struct timecounter *a)
242 {
243         unsigned int ticks1;
244         arm_mask_irq(1);
245         ticks1 = read_second_timer_counter();
246         arm_unmask_irq(1);
247         return ticks1;
248 }
249
250 /*
251  * Setup timer
252  */
253 static inline void
254 do_setup_timer(void)
255 {
256
257         timer_counter = APB_clock/HZ;
258         /*
259          * setup timer-related values
260          */
261         setup_timer(timer_counter);
262 }
263
264 void
265 cpu_initclocks(void)
266 {
267
268         ec_timecounter.tc_frequency = APB_clock;
269         tc_init(&ec_timecounter);
270         timer_enable();
271         timers_initialized = 1;
272 }
273
274 void
275 cpu_startprofclock(void)
276 {
277
278 }
279
280 void
281 cpu_stopprofclock(void)
282 {
283
284 }
285
286 static int
287 ec_timer_probe(device_t dev)
288 {
289
290         device_set_desc(dev, "Econa CPU Timer");
291         return (0);
292 }
293
294 static int
295 ec_reset(void *arg)
296 {
297
298         arm_mask_irq(1);
299         clear_timer_interrupt_status(1);
300         arm_unmask_irq(1);
301         return (FILTER_HANDLED);
302 }
303
304 static int
305 ec_hardclock(void *arg)
306 {
307         struct  trapframe *frame;
308         unsigned int val;
309         /*clear timer interrupt status*/
310
311         arm_mask_irq(0);
312
313         val = read_4(TIMER_INTERRUPT_STATUS_REG);
314         val &= ~(TIMER1_OVERFLOW_INTERRUPT);
315         write_4(val, TIMER_INTERRUPT_STATUS_REG);
316
317         frame = (struct trapframe *)arg;
318         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
319
320         arm_unmask_irq(0);
321
322         return (FILTER_HANDLED);
323 }
324
325 static int
326 ec_timer_attach(device_t dev)
327 {
328         struct  ec_timer_softc *sc;
329         int     error;
330         void    *ihl;
331
332
333         if (timer_softc != NULL)
334                 return (ENXIO);
335
336         sc = (struct ec_timer_softc *)device_get_softc(dev);
337
338         timer_softc = sc;
339
340         error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
341         if (error) {
342                 device_printf(dev, "could not allocate resources\n");
343                 return (ENXIO);
344         }
345
346         sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
347         sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
348
349         do_setup_timer();
350
351         if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
352             ec_hardclock, NULL, NULL, &ihl) != 0) {
353                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
354                 device_printf(dev, "could not setup hardclock interrupt\n");
355                 return (ENXIO);
356         }
357
358         if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
359             ec_reset, NULL, NULL, &ihl) != 0) {
360                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
361                 device_printf(dev, "could not setup timer interrupt\n");
362                 return (ENXIO);
363         }
364
365         return (0);
366 }
367
368 static device_method_t ec_timer_methods[] = {
369         DEVMETHOD(device_probe, ec_timer_probe),
370         DEVMETHOD(device_attach, ec_timer_attach),
371         { 0, 0 }
372 };
373
374 static driver_t ec_timer_driver = {
375         "timer",
376         ec_timer_methods,
377         sizeof(struct ec_timer_softc),
378 };
379
380 static devclass_t ec_timer_devclass;
381
382 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);