2 * Copyright (c) 2006-2007 Bruce M. Simpson.
3 * Copyright (c) 2003-2004 Juli Mallett.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Simple driver for the 32-bit interval counter built in to all
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/sysctl.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
43 #include <sys/power.h>
46 #include <sys/timetc.h>
48 #include <machine/clock.h>
49 #include <machine/locore.h>
50 #include <machine/md_var.h>
52 uint64_t counter_freq;
53 uint64_t cycles_per_tick;
54 uint64_t cycles_per_usec;
55 uint64_t cycles_per_sec;
56 uint64_t cycles_per_hz;
58 u_int32_t counter_upper = 0;
59 u_int32_t counter_lower_last = 0;
68 * pad for cache line alignment of pcpu info
69 * cache-line-size - number of used bytes
71 char pad[32-(3*sizeof (u_long))];
72 } static pcpu_ticks[MAXCPU];
77 static int clock_probe(device_t);
78 static void clock_identify(driver_t *, device_t);
79 static int clock_attach(device_t);
80 static unsigned counter_get_timecount(struct timecounter *tc);
82 static struct timecounter counter_timecounter = {
83 counter_get_timecount, /* get_timecount */
85 0xffffffffu, /* counter_mask */
88 800, /* quality (adjusted in code) */
92 mips_timer_early_init(uint64_t clock_hz)
94 /* Initialize clock early so that we can use DELAY sooner */
95 counter_freq = clock_hz;
96 cycles_per_usec = (clock_hz / (1000 * 1000));
104 tc_init(&counter_timecounter);
116 * XXX: MIPS64 platforms can read 64-bits of counter directly.
117 * Also: the tc code is supposed to cope with things wrapping
118 * from the time counter, so I'm not sure why all these hoops
119 * are even necessary.
121 ticktock = mips_rd_count();
123 if (ticktock < counter_lower_last)
125 counter_lower_last = ticktock;
128 ret = ((uint64_t) counter_upper << 32) | counter_lower_last;
133 mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
137 * XXX: Do not use printf here: uart code 8250 may use DELAY so this
138 * function should be called before cninit.
140 counter_freq = platform_counter_freq;
141 cycles_per_tick = counter_freq / 1000;
143 cycles_per_tick *= 2;
144 cycles_per_hz = counter_freq / hz;
145 cycles_per_usec = counter_freq / (1 * 1000 * 1000);
146 cycles_per_sec = counter_freq ;
148 counter_timecounter.tc_frequency = counter_freq;
150 * XXX: Some MIPS32 cores update the Count register only every two
152 * XXX2: We can read this from the hardware register on some
153 * systems. Need to investigate.
155 if (double_count != 0) {
157 cycles_per_usec /= 2;
160 printf("hz=%d cyl_per_hz:%jd cyl_per_usec:%jd freq:%jd cyl_per_hz:%jd cyl_per_sec:%jd\n",
168 set_cputicker(tick_ticker, counter_freq, 1);
172 sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
177 if (counter_timecounter.tc_frequency == 0)
180 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
181 if (error == 0 && req->newptr != NULL) {
183 counter_timecounter.tc_frequency = counter_freq;
188 SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_QUAD | CTLFLAG_RW,
189 0, sizeof(u_int), sysctl_machdep_counter_freq, "IU",
190 "Timecounter frequency in Hz");
193 counter_get_timecount(struct timecounter *tc)
196 return (mips_rd_count());
201 cpu_startprofclock(void)
207 cpu_stopprofclock(void)
213 * Wait for about n microseconds (at least!).
218 uint32_t cur, last, delta, usecs;
221 * This works by polling the timer and counting the number of
222 * microseconds that go by.
224 last = mips_rd_count();
228 cur = mips_rd_count();
230 /* Check to see if the timer has wrapped around. */
232 delta += (cur + (cycles_per_hz - last));
234 delta += (cur - last);
238 if (delta >= cycles_per_usec) {
239 usecs += delta / cycles_per_usec;
240 delta %= cycles_per_usec;
246 int64_t wheel_run = 0;
248 void octeon_led_run_wheel(void);
252 * Device section of file below
255 clock_intr(void *arg)
257 struct clk_ticks *cpu_ticks;
258 struct trapframe *tf;
261 * Set next clock edge.
263 ltick = mips_rd_count();
264 mips_wr_compare(ltick + cycles_per_tick);
265 cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
267 if (ltick < counter_lower_last) {
269 counter_lower_last = ltick;
272 * Magic. Setting up with an arg of NULL means we get passed tf.
274 tf = (struct trapframe *)arg;
276 /* Fire hardclock at hz. */
277 cpu_ticks->hard_ticks += cycles_per_tick;
278 if (cpu_ticks->hard_ticks >= cycles_per_hz) {
279 cpu_ticks->hard_ticks -= cycles_per_hz;
280 if (PCPU_GET(cpuid) == 0)
281 hardclock(USERMODE(tf->sr), tf->pc);
283 hardclock_cpu(USERMODE(tf->sr));
285 /* Fire statclock at stathz. */
286 cpu_ticks->stat_ticks += stathz;
287 if (cpu_ticks->stat_ticks >= cycles_per_hz) {
288 cpu_ticks->stat_ticks -= cycles_per_hz;
289 statclock(USERMODE(tf->sr));
292 /* Fire profclock at profhz, but only when needed. */
293 cpu_ticks->prof_ticks += profhz;
294 if (cpu_ticks->prof_ticks >= cycles_per_hz) {
295 cpu_ticks->prof_ticks -= cycles_per_hz;
297 profclock(USERMODE(tf->sr), tf->pc);
301 /* Run the FreeBSD display once every hz ticks */
302 wheel_run += cycles_per_tick;
303 if (wheel_run >= cycles_per_sec) {
305 octeon_led_run_wheel();
308 return (FILTER_HANDLED);
312 clock_probe(device_t dev)
315 if (device_get_unit(dev) != 0)
316 panic("can't attach more clocks");
318 device_set_desc(dev, "Generic MIPS32 ticker");
323 clock_identify(driver_t * drv, device_t parent)
326 BUS_ADD_CHILD(parent, 0, "clock", 0);
330 clock_attach(device_t dev)
332 struct resource *irq;
337 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 5, 5, 1, RF_ACTIVE);
339 device_printf(dev, "failed to allocate irq\n");
342 error = bus_setup_intr(dev, irq, INTR_TYPE_CLK, clock_intr, NULL,
346 device_printf(dev, "bus_setup_intr returned %d\n", error);
349 mips_wr_compare(mips_rd_count() + counter_freq / hz);
353 static device_method_t clock_methods[] = {
354 /* Device interface */
355 DEVMETHOD(device_probe, clock_probe),
356 DEVMETHOD(device_identify, clock_identify),
357 DEVMETHOD(device_attach, clock_attach),
358 DEVMETHOD(device_detach, bus_generic_detach),
359 DEVMETHOD(device_shutdown, bus_generic_shutdown),
364 static driver_t clock_driver = {
365 "clock", clock_methods, 32
368 static devclass_t clock_devclass;
370 DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0);