2 * Copyright (c) 2011 Aeroflex Gaisler
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include <sys/types.h>
28 #include <sys/errno.h>
29 #include <asm-leon/elfmacro.h>
30 #include <asm-leon/leon.h>
31 #include <asm-leon/irq.h>
32 #include <asm-leon/jiffies.h>
33 #include <asm-leon/param.h>
34 #include <asm-leon/leoncompat.h>
36 static __inline__ unsigned long do_gettimeoffset ();
41 unsigned long wall_jiffies = INITIAL_JIFFIES;
42 unsigned long tick_nsec = TICK_NSEC;
43 unsigned long tick_usec = TICK_NSEC / 1000;
44 unsigned long seperateirq = 1;
45 unsigned long noalarm = 1;
46 unsigned long force_noalarm = 0;
47 unsigned long nodotimer = 0;
53 do_timer (struct leonbare_pt_regs *regs)
57 ticks = jiffies - wall_jiffies;
60 wall_jiffies += ticks;
64 xtime.tv_nsec += tick_nsec;
65 if (xtime.tv_nsec >= 1000000000)
67 xtime.tv_nsec -= 1000000000;
77 leonbare_alarm (int irq, void *arg, struct leonbare_pt_regs *regs)
82 extern clock_t (*clock_custom) (void);
84 leonbare_clock_custom ()
86 int hz = leonbare_hz ? leonbare_hz : HZ;
87 return (clock_t) ((jiffies * (CLOCK_TICK_RATE / hz)) + do_gettimeoffset ());
91 tickerhandler ticker_callback = 0;
93 leonbare_tick (int irq, void *arg, struct leonbare_pt_regs *regs)
98 /* only leon3 comes here */
101 ctrl = LEON3_GpTimer_Regs->e[1].ctrl;
102 if (ctrl & LEON3_GPTIMER_IP)
104 leonbare_alarm (irq, arg, regs);
105 LEON3_GpTimer_Regs->e[1].ctrl = ctrl & ~LEON3_GPTIMER_IP;
108 ctrl = LEON3_GpTimer_Regs->e[0].ctrl;
109 if (!(ctrl & LEON3_GPTIMER_IP))
113 LEON3_GpTimer_Regs->e[0].ctrl = ctrl & ~LEON3_GPTIMER_IP;
122 ticker_callback (regs);
127 static struct irqaction irqact1 = { (irqhandler) leonbare_tick, 0, 0, 0 };
128 static struct irqaction irqact2 = { (irqhandler) leonbare_alarm, 0, 0, 0 };
131 leonbare_init_ticks ()
133 int i, irq1 = 0, irq2 = 0;
134 int hz = leonbare_hz ? leonbare_hz : HZ;
135 amba_apb_device dev[1];
137 //---------------------
138 switch (LEONCOMPAT_VERSION)
143 if (LEON3_GpTimer_Regs && LEON3_IrqCtrl_Regs)
145 if ((LEON3_GpTimer_Regs->config & LEON3_GPTIMER_CONFIG_TIMERMASK) >=
146 2 && force_noalarm == 0)
148 if (!(LEON3_GpTimer_Regs->config & LEON3_GPTIMER_CONFIG_SEPERATE))
150 LEON3_GpTimer_Regs->e[0].val = 0;
151 LEON3_GpTimer_Regs->e[0].rld = (((CLOCK_TICK_RATE / hz) - 1));
152 LEON3_GpTimer_Regs->e[0].ctrl = 0;
153 LEON3_GpTimer_Regs->e[0].ctrl =
155 LEON3_GPTIMER_RL | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN;
156 irq1 = LEON3_GpTimer_Irq;
157 irq2 = LEON3_GpTimer_Irq + 1;
161 //---------------------
165 clock_custom = leonbare_clock_custom;
166 chained_catch_interrupt (irq1, &irqact1);
167 leonbare_enable_irq (irq1);
169 if (irq2 && (!noalarm) && seperateirq)
171 chained_catch_interrupt (irq2, &irqact2);
172 leonbare_enable_irq (irq2);
177 //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
179 static __inline__ unsigned long
182 unsigned long usec = 0;
183 //---------------------
184 switch (LEONCOMPAT_VERSION)
188 usec = ((LEON3_GpTimer_Regs->e[0].rld & 0x7fffff) -
189 (LEON3_GpTimer_Regs->e[0].val & 0x7fffff));
192 //---------------------
196 /* get usec (timeval) resolution,
197 * could use nsec (timespec) because pthread use it (todo) */
199 do_gettimeofday (struct timeval *tv)
204 unsigned long usec, sec;
211 usec = do_gettimeoffset ();
212 lost = jiffies - wall_jiffies;
216 usec += lost * tick_usec;
220 usec += (xtime.tv_nsec / 1000);
222 while (seq != jiffies);
224 while (usec >= 1000000)
235 gettimeofday (struct timeval *__p, void *__tz)
237 do_gettimeofday (__p);
241 //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
244 do_settimeofday (struct timespec *tv)
246 time_t sec = tv->tv_sec;
247 long nsec = tv->tv_nsec;
249 if ((unsigned long) nsec >= NSEC_PER_SEC)
253 * This is revolting. We need to set "xtime" correctly. However, the
254 * value in this location is the value at the most recent update of
255 * wall time. Discover what correction gettimeofday() would have
256 * made, and then undo it!
258 nsec -= 1000 * (do_gettimeoffset () +
259 (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
261 set_normalized_timespec (&xtime, sec, nsec);
266 settimeofday (const struct timeval *tv, const struct timezone *tz)
269 ts.tv_sec = tv->tv_sec;
270 ts.tv_nsec = tv->tv_usec * NSEC_PER_USEC;
271 return do_settimeofday (&ts);