2 * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/malloc.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>
43 #include "econa_reg.h"
44 #include "econa_var.h"
46 #define INITIAL_TIMECOUNTER (0xffffffff)
48 static int timers_initialized = 0;
52 extern unsigned int CPU_clock;
53 extern unsigned int AHB_clock;
54 extern unsigned int APB_clock;
56 static unsigned long timer_counter = 0;
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;
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 },
72 static unsigned ec_timer_get_timecount(struct timecounter *);
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 */
79 .tc_counter_mask = ~0u,
83 static struct ec_timer_softc *timer_softc = NULL;
86 void write_4(unsigned int val, unsigned int addr)
88 bus_space_write_4(timer_softc->timer_bst,
89 timer_softc->timer_bsh, addr, val);
94 unsigned int read_4(unsigned int addr)
97 return bus_space_read_4(timer_softc->timer_bst,
98 timer_softc->timer_bsh, addr);
101 #define uSECS_PER_TICK (1000000 / APB_clock)
102 #define TICKS2USECS(x) ((x) * uSECS_PER_TICK)
105 read_timer_counter_noint(void)
109 unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
117 uint32_t val, val_temp;
120 if (!timers_initialized) {
121 for (; usec > 0; usec--)
122 for (val = 100; val > 0; val--)
127 val = read_timer_counter_noint();
128 nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
131 val_temp = read_timer_counter_noint();
133 nticks -= (val - val_temp);
135 nticks -= (val + (timer_counter - val_temp));
146 setup_timer(unsigned int counter_value)
148 unsigned int control_value;
149 unsigned int mask_value;
151 control_value = read_4(TIMER_TM_CR_REG);
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);
159 control_value &= ~(TIMER1_CLOCK_SOURCE);
160 control_value |= TIMER1_UP_DOWN_COUNT;
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);
167 control_value &= ~(TIMER2_CLOCK_SOURCE);
168 control_value &= ~(TIMER2_UP_DOWN_COUNT);
172 write_4(control_value, TIMER_TM_CR_REG);
173 write_4(mask_value, TIMER_TM_INTR_MASK_REG);
182 unsigned int control_value;
184 control_value = read_4(TIMER_TM_CR_REG);
186 control_value |= TIMER1_OVERFLOW_ENABLE;
187 control_value |= TIMER1_ENABLE;
188 control_value |= TIMER2_OVERFLOW_ENABLE;
189 control_value |= TIMER2_ENABLE;
191 write_4(control_value, TIMER_TM_CR_REG);
194 static inline unsigned int
195 read_second_timer_counter(void)
198 return read_4(TIMER_TM2_COUNTER_REG);
202 * Get timer interrupt status
204 static inline unsigned int
205 read_timer_interrupt_status(void)
208 return read_4(TIMER_TM_INTR_STATUS_REG);
212 * Clear timer interrupt status
215 clear_timer_interrupt_status(unsigned int irq)
217 unsigned int interrupt_status;
219 interrupt_status = read_4(TIMER_TM_INTR_STATUS_REG);
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);
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);
237 write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
241 ec_timer_get_timecount(struct timecounter *a)
245 ticks1 = read_second_timer_counter();
257 timer_counter = APB_clock/HZ;
259 * setup timer-related values
261 setup_timer(timer_counter);
268 ec_timecounter.tc_frequency = APB_clock;
269 tc_init(&ec_timecounter);
271 timers_initialized = 1;
275 cpu_startprofclock(void)
281 cpu_stopprofclock(void)
287 ec_timer_probe(device_t dev)
290 device_set_desc(dev, "Econa CPU Timer");
299 clear_timer_interrupt_status(1);
301 return (FILTER_HANDLED);
305 ec_hardclock(void *arg)
307 struct trapframe *frame;
309 /*clear timer interrupt status*/
313 val = read_4(TIMER_INTERRUPT_STATUS_REG);
314 val &= ~(TIMER1_OVERFLOW_INTERRUPT);
315 write_4(val, TIMER_INTERRUPT_STATUS_REG);
317 frame = (struct trapframe *)arg;
318 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
322 return (FILTER_HANDLED);
326 ec_timer_attach(device_t dev)
328 struct ec_timer_softc *sc;
333 if (timer_softc != NULL)
336 sc = (struct ec_timer_softc *)device_get_softc(dev);
340 error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
342 device_printf(dev, "could not allocate resources\n");
346 sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
347 sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
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");
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");
368 static device_method_t ec_timer_methods[] = {
369 DEVMETHOD(device_probe, ec_timer_probe),
370 DEVMETHOD(device_attach, ec_timer_attach),
374 static driver_t ec_timer_driver = {
377 sizeof(struct ec_timer_softc),
380 static devclass_t ec_timer_devclass;
382 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);