]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/arm/cavium/cns11xx/timer.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / arm / cavium / cns11xx / 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/intr.h>
41
42 #include "econa_reg.h"
43 #include "econa_var.h"
44
45 #define INITIAL_TIMECOUNTER     (0xffffffff)
46
47 static int timers_initialized = 0;
48
49 #define HZ      100
50
51 extern unsigned int CPU_clock;
52 extern unsigned int AHB_clock;
53 extern unsigned int APB_clock;
54
55 static unsigned long timer_counter = 0;
56
57 struct ec_timer_softc {
58         struct resource *       timer_res[3];
59         bus_space_tag_t         timer_bst;
60         bus_space_handle_t      timer_bsh;
61         struct mtx              timer_mtx;
62 };
63
64 static struct resource_spec ec_timer_spec[] = {
65         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
66         { SYS_RES_IRQ,          0,      RF_ACTIVE },
67         { SYS_RES_IRQ,          1,      RF_ACTIVE },
68         { -1, 0 }
69 };
70
71 static unsigned ec_timer_get_timecount(struct timecounter *);
72
73 static struct timecounter ec_timecounter = {
74         .tc_get_timecount = ec_timer_get_timecount,
75         .tc_name = "CPU Timer",
76         /* This is assigned on the fly in the init sequence */
77         .tc_frequency = 0,
78         .tc_counter_mask = ~0u,
79         .tc_quality = 1000,
80 };
81
82 static struct ec_timer_softc *timer_softc = NULL;
83
84 static inline
85 void write_4(unsigned int val, unsigned int addr)
86 {
87         bus_space_write_4(timer_softc->timer_bst,
88                           timer_softc->timer_bsh, addr, val);
89
90 }
91
92 static inline
93 unsigned int read_4(unsigned int addr)
94 {
95
96         return bus_space_read_4(timer_softc->timer_bst,
97             timer_softc->timer_bsh, addr);
98 }
99
100 #define uSECS_PER_TICK  (1000000 / APB_clock)
101 #define TICKS2USECS(x)  ((x) * uSECS_PER_TICK)
102
103 static unsigned
104 read_timer_counter_noint(void)
105 {
106
107         arm_mask_irq(0);
108         unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
109         arm_unmask_irq(0);
110         return v;
111 }
112
113 void
114 DELAY(int usec)
115 {
116         uint32_t val, val_temp;
117         int nticks;
118
119         if (!timers_initialized) {
120                 for (; usec > 0; usec--)
121                         for (val = 100; val > 0; val--)
122                                 ;
123                 return;
124         }
125
126         val = read_timer_counter_noint();
127         nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
128
129         while (nticks > 0) {
130                 val_temp = read_timer_counter_noint();
131                 if (val > val_temp)
132                         nticks -= (val - val_temp);
133                 else
134                         nticks -= (val + (timer_counter - val_temp));
135
136                 val = val_temp;
137         }
138
139 }
140
141 /*
142  * Setup timer
143  */
144 static inline void
145 setup_timer(unsigned int counter_value)
146 {
147         unsigned int control_value;
148         unsigned int mask_value;
149
150         control_value = read_4(TIMER_TM_CR_REG);
151
152         mask_value = read_4(TIMER_TM_INTR_MASK_REG);
153         write_4(counter_value, TIMER_TM1_COUNTER_REG);
154         write_4(counter_value, TIMER_TM1_LOAD_REG);
155         write_4(0, TIMER_TM1_MATCH1_REG);
156         write_4(0,TIMER_TM1_MATCH2_REG);
157
158         control_value &= ~(TIMER1_CLOCK_SOURCE);
159         control_value |= TIMER1_UP_DOWN_COUNT;
160
161         write_4(0, TIMER_TM2_COUNTER_REG);
162         write_4(0, TIMER_TM2_LOAD_REG);
163         write_4(~0u, TIMER_TM2_MATCH1_REG);
164         write_4(~0u,TIMER_TM2_MATCH2_REG);
165
166         control_value &= ~(TIMER2_CLOCK_SOURCE);
167         control_value &= ~(TIMER2_UP_DOWN_COUNT);
168
169         mask_value &= ~(63);
170
171         write_4(control_value, TIMER_TM_CR_REG);
172         write_4(mask_value, TIMER_TM_INTR_MASK_REG);
173 }
174
175 /*
176  * Enable timer
177  */
178 static inline void
179 timer_enable(void)
180 {
181         unsigned int control_value;
182
183         control_value = read_4(TIMER_TM_CR_REG);
184
185         control_value |= TIMER1_OVERFLOW_ENABLE;
186         control_value |= TIMER1_ENABLE;
187         control_value |= TIMER2_OVERFLOW_ENABLE;
188         control_value |= TIMER2_ENABLE;
189
190         write_4(control_value, TIMER_TM_CR_REG);
191 }
192
193 static inline unsigned int
194 read_second_timer_counter(void)
195 {
196
197         return read_4(TIMER_TM2_COUNTER_REG);
198 }
199
200 /*
201  * Get timer interrupt status
202  */
203 static inline unsigned int
204 read_timer_interrupt_status(void)
205 {
206
207         return read_4(TIMER_TM_INTR_STATUS_REG);
208 }
209
210 /*
211  * Clear timer interrupt status
212  */
213 static inline void
214 clear_timer_interrupt_status(unsigned int irq)
215 {
216         unsigned int interrupt_status;
217
218         interrupt_status =   read_4(TIMER_TM_INTR_STATUS_REG);
219         if (irq == 0) {
220                 if (interrupt_status & (TIMER1_MATCH1_INTR))
221                         interrupt_status &= ~(TIMER1_MATCH1_INTR);
222                 if (interrupt_status & (TIMER1_MATCH2_INTR))
223                         interrupt_status &= ~(TIMER1_MATCH2_INTR);
224                 if (interrupt_status & (TIMER1_OVERFLOW_INTR))
225                         interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
226         }
227         if (irq == 1) {
228                 if (interrupt_status & (TIMER2_MATCH1_INTR))
229                         interrupt_status &= ~(TIMER2_MATCH1_INTR);
230                 if (interrupt_status & (TIMER2_MATCH2_INTR))
231                         interrupt_status &= ~(TIMER2_MATCH2_INTR);
232                 if (interrupt_status & (TIMER2_OVERFLOW_INTR))
233                         interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
234         }
235
236         write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
237 }
238
239 static unsigned
240 ec_timer_get_timecount(struct timecounter *a)
241 {
242         unsigned int ticks1;
243         arm_mask_irq(1);
244         ticks1 = read_second_timer_counter();
245         arm_unmask_irq(1);
246         return ticks1;
247 }
248
249 /*
250  * Setup timer
251  */
252 static inline void
253 do_setup_timer(void)
254 {
255
256         timer_counter = APB_clock/HZ;
257         /*
258          * setup timer-related values
259          */
260         setup_timer(timer_counter);
261 }
262
263 void
264 cpu_initclocks(void)
265 {
266
267         ec_timecounter.tc_frequency = APB_clock;
268         tc_init(&ec_timecounter);
269         timer_enable();
270         timers_initialized = 1;
271 }
272
273 void
274 cpu_startprofclock(void)
275 {
276
277 }
278
279 void
280 cpu_stopprofclock(void)
281 {
282
283 }
284
285 static int
286 ec_timer_probe(device_t dev)
287 {
288
289         device_set_desc(dev, "Econa CPU Timer");
290         return (0);
291 }
292
293 static int
294 ec_reset(void *arg)
295 {
296
297         arm_mask_irq(1);
298         clear_timer_interrupt_status(1);
299         arm_unmask_irq(1);
300         return (FILTER_HANDLED);
301 }
302
303 static int
304 ec_hardclock(void *arg)
305 {
306         struct  trapframe *frame;
307         unsigned int val;
308         /*clear timer interrupt status*/
309
310         arm_mask_irq(0);
311
312         val = read_4(TIMER_INTERRUPT_STATUS_REG);
313         val &= ~(TIMER1_OVERFLOW_INTERRUPT);
314         write_4(val, TIMER_INTERRUPT_STATUS_REG);
315
316         frame = (struct trapframe *)arg;
317         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
318
319         arm_unmask_irq(0);
320
321         return (FILTER_HANDLED);
322 }
323
324 static int
325 ec_timer_attach(device_t dev)
326 {
327         struct  ec_timer_softc *sc;
328         int     error;
329         void    *ihl;
330
331
332         if (timer_softc != NULL)
333                 return (ENXIO);
334
335         sc = (struct ec_timer_softc *)device_get_softc(dev);
336
337         timer_softc = sc;
338
339         error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
340         if (error) {
341                 device_printf(dev, "could not allocate resources\n");
342                 return (ENXIO);
343         }
344
345         sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
346         sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
347
348         do_setup_timer();
349
350         if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
351             ec_hardclock, NULL, NULL, &ihl) != 0) {
352                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
353                 device_printf(dev, "could not setup hardclock interrupt\n");
354                 return (ENXIO);
355         }
356
357         if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
358             ec_reset, NULL, NULL, &ihl) != 0) {
359                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
360                 device_printf(dev, "could not setup timer interrupt\n");
361                 return (ENXIO);
362         }
363
364         return (0);
365 }
366
367 static device_method_t ec_timer_methods[] = {
368         DEVMETHOD(device_probe, ec_timer_probe),
369         DEVMETHOD(device_attach, ec_timer_attach),
370         { 0, 0 }
371 };
372
373 static driver_t ec_timer_driver = {
374         "timer",
375         ec_timer_methods,
376         sizeof(struct ec_timer_softc),
377 };
378
379 static devclass_t ec_timer_devclass;
380
381 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);