1 /* $NetBSD: clock.c,v 1.50 2009/09/11 19:43:08 phx Exp $ */
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * from: Utah $Hdr: clock.c 1.18 91/01/21$
37 * @(#)clock.c 7.6 (Berkeley) 5/7/91
40 * Copyright (c) 1988 University of Utah.
42 * This code is derived from software contributed to Berkeley by
43 * the Systems Programming Group of the University of Utah Computer
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by the University of
57 * California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * from: Utah $Hdr: clock.c 1.18 91/01/21$
76 * @(#)clock.c 7.6 (Berkeley) 5/7/91
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.50 2009/09/11 19:43:08 phx Exp $");
82 #include <sys/param.h>
83 #include <sys/kernel.h>
84 #include <sys/device.h>
85 #include <sys/systm.h>
86 #include <sys/timetc.h>
87 #include <machine/psl.h>
88 #include <machine/cpu.h>
89 #include <amiga/amiga/device.h>
90 #include <amiga/amiga/custom.h>
91 #include <amiga/amiga/cia.h>
93 #include <amiga/amiga/drcustom.h>
94 #include <m68k/include/asm_single.h>
96 #include <amiga/dev/rtc.h>
97 #include <amiga/dev/zbusvar.h>
99 #if defined(PROF) && defined(PROFTIMER)
100 #include <sys/PROF.h>
104 * Machine-dependent clock routines.
106 * Startrtclock restarts the real-time clock, which provides
107 * hardclock interrupts to kern_clock.c.
109 * Inittodr initializes the time of day hardware which provides
112 * Resettodr restores the time of day hardware after a time change.
114 * A note on the real-time clock:
115 * We actually load the clock with amiga_clk_interval-1 instead of amiga_clk_interval.
116 * This is because the counter decrements to zero after N+1 enabled clock
117 * periods where N is the value loaded into the counter.
120 int clockmatch(struct device
*, struct cfdata
*, void *);
121 void clockattach(struct device
*, struct device
*, void *);
122 void cpu_initclocks(void);
123 static void calibrate_delay(struct device
*);
125 /* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz.
126 We're using a 100 Hz clock. */
127 int amiga_clk_interval
;
129 struct CIA
*clockcia
;
131 static u_int
clk_getcounter(struct timecounter
*);
133 static struct timecounter clk_timecounter
= {
134 clk_getcounter
, /* get_timecount */
136 ~0u, /* counter_mask */
138 "clock", /* name, overriden later */
144 CFATTACH_DECL(clock
, sizeof(struct device
),
145 clockmatch
, clockattach
, NULL
, NULL
);
148 clockmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
150 if (matchname("clock", auxp
))
156 * Start the real-time clock.
159 clockattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
161 const char *clockchip
;
162 unsigned short interval
;
169 eclockfreq
= 715909; /* guess NTSC */
171 chipfreq
= eclockfreq
;
174 dracorev
= is_draco();
176 chipfreq
= eclockfreq
/ 7;
177 clockchip
= "QuickLogic";
178 } else if (dracorev
) {
179 clockcia
= (struct CIA
*)CIAAbase
;
184 clockcia
= (struct CIA
*)CIABbase
;
188 amiga_clk_interval
= chipfreq
/ hz
;
190 if (dp
!= NULL
) { /* real autoconfig? */
191 printf(": %s system hz %d hardware hz %d\n", clockchip
, hz
,
194 clk_timecounter
.tc_name
= clockchip
;
195 clk_timecounter
.tc_frequency
= chipfreq
;
196 tc_init(&clk_timecounter
);
202 * can't preload anything beforehand, timer is free_running;
203 * but need this for delay calibration.
206 draco_ioct
->io_timerlo
= amiga_clk_interval
& 0xff;
207 draco_ioct
->io_timerhi
= amiga_clk_interval
>> 8;
217 clockcia
->cra
= clockcia
->cra
& 0xc0;
218 clockcia
->icr
= 1 << 0; /* disable timer A interrupt */
219 interval
= clockcia
->icr
; /* and make sure it's clear */
222 * load interval into registers.
223 * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz
225 interval
= amiga_clk_interval
- 1;
228 * order of setting is important !
230 clockcia
->talo
= interval
& 0xff;
231 clockcia
->tahi
= interval
>> 8;
233 * start timer A in continuous mode
235 clockcia
->cra
= (clockcia
->cra
& 0xc0) | 1;
244 unsigned char dracorev
;
245 dracorev
= is_draco();
247 draco_ioct
->io_timerlo
= amiga_clk_interval
& 0xFF;
248 draco_ioct
->io_timerhi
= amiga_clk_interval
>> 8;
249 draco_ioct
->io_timerrst
= 0; /* any value resets */
250 single_inst_bset_b(draco_ioct
->io_status2
, DRSTAT2_TMRINTENA
);
256 * enable interrupts for timer A
258 clockcia
->icr
= (1<<7) | (1<<0);
261 * start timer A in continuous shot mode
263 clockcia
->cra
= (clockcia
->cra
& 0xc0) | 1;
266 * and globally enable interrupts for ciab
269 if (dracorev
) /* we use cia a on DraCo */
270 single_inst_bset_b(*draco_intena
, DRIRQ_INT2
);
273 custom
.intena
= INTF_SETCLR
| INTF_EXTER
;
278 setstatclockrate(int hertz
)
283 * Returns ticks since last recorded clock "tick"
284 * (i.e. clock interrupt).
293 if (is_draco() >= 4) {
294 hi2
= draco_ioct
->io_chiprev
; /* latch timer */
295 hi
= draco_ioct
->io_timerhi
;
296 lo
= draco_ioct
->io_timerlo
;
297 interval
= ((hi
<<8) | lo
);
298 if (interval
> amiga_clk_interval
) /* timer underflow */
299 interval
= 65536 + amiga_clk_interval
- interval
;
301 interval
= amiga_clk_interval
- interval
;
308 hi2
= clockcia
->tahi
;
314 interval
= (amiga_clk_interval
- 1) - ((hi
<<8) | lo
);
317 * should read ICR and if there's an int pending, adjust
318 * interval. However, since reading ICR clears the interrupt,
319 * we'd lose a hardclock int, and this is not tolerable.
327 clk_getcounter(struct timecounter
*tc
)
329 static int prev_hardclock
;
330 static u_int prev_counter
;
335 cur_hardclock
= hardclock_ticks
;
336 counter
= clk_gettick();
337 } while (cur_hardclock
!= hardclock_ticks
);
340 * Handle the situation of a wrapped interval counter, while
341 * the hardclock() interrupt was not yet executed to update
344 if (cur_hardclock
< prev_hardclock
)
345 cur_hardclock
= prev_hardclock
;
346 if (counter
< prev_counter
&& cur_hardclock
== prev_hardclock
)
349 prev_hardclock
= cur_hardclock
;
350 prev_counter
= counter
;
352 return cur_hardclock
* amiga_clk_interval
+ counter
;
356 * Calibrate delay loop.
357 * We use two iterations because we don't have enough bits to do a factor of
358 * 8 with better than 1%.
360 * XXX Note that we MUST stay below 1 tick if using clk_gettick(), even for
361 * underestimated values of delaydivisor.
363 * XXX the "ns" below is only correct for a shift of 10 bits, and even then
367 calibrate_delay(struct device
*dp
)
369 unsigned long t1
, t2
;
370 extern u_int32_t delaydivisor
;
371 /* XXX this should be defined elsewhere */
374 printf("Calibrating delay loop... ");
381 t2
= ((t2
- t1
) * 1000000) / (amiga_clk_interval
* hz
);
382 delaydivisor
= (delaydivisor
* t2
+ 1023) >> 10;
385 printf("\ndiff %ld us, new divisor %u/1024 us\n", t2
,
392 t2
= ((t2
- t1
) * 1000000) / (amiga_clk_interval
* hz
);
393 delaydivisor
= (delaydivisor
* t2
+ 1023) >> 10;
395 printf("diff %ld us, new divisor %u/1024 us\n", t2
,
403 t2
= ((t2
- t1
) * 1000000) / (amiga_clk_interval
* hz
);
404 delaydivisor
= (delaydivisor
* t2
+ 1023) >> 10;
407 printf("diff %ld us, new divisor ", t2
);
410 printf("%u/1024 us\n", delaydivisor
);
415 /* implement this later. I'd suggest using both timers in CIA-A, they're
421 * /dev/clock: mappable high resolution timer.
423 * This code implements a 32-bit recycling counter (with a 4 usec period)
424 * using timers 2 & 3 on the 6840 clock chip. The counter can be mapped
425 * RO into a user's address space to achieve low overhead (no system calls),
426 * high-precision timing.
428 * Note that timer 3 is also used for the high precision profiling timer
429 * (PROFTIMER code above). Care should be taken when both uses are
430 * configured as only a token effort is made to avoid conflicting use.
432 #include <sys/proc.h>
433 #include <sys/resourcevar.h>
434 #include <sys/ioctl.h>
435 #include <sys/malloc.h>
436 #include <uvm/uvm_extern.h>
437 #include <amiga/amiga/clockioctl.h>
438 #include <sys/specdev.h>
439 #include <sys/vnode.h>
440 #include <sys/mman.h>
442 int clockon
= 0; /* non-zero if high-res timer enabled */
444 int profprocs
= 0; /* # of procs using profiling timer */
452 clockopen(dev_t dev
, int flags
)
457 * Kernel profiling enabled, give up.
463 * If any user processes are profiling, give up.
477 clockclose(dev_t dev
, int flags
)
479 (void) clockunmmap(dev
, (void *)0, curproc
); /* XXX */
487 clockioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct proc
*p
)
494 error
= clockmmap(dev
, (void **)data
, p
);
498 error
= clockunmmap(dev
, *(void **)data
, p
);
502 *(int *)data
= CLK_RESOLUTION
;
514 clockmap(dev_t dev
, int off
, int prot
)
516 return((off
+ (INTIOBASE
+CLKBASE
+CLKSR
-1)) >> PGSHIFT
);
520 clockmmap(dev_t dev
, void **addrp
, struct proc
*p
)
527 flags
= MAP_FILE
|MAP_SHARED
;
531 *addrp
= (void *)0x1000000; /* XXX */
532 vn
.v_type
= VCHR
; /* XXX */
533 vn
.v_specinfo
= &si
; /* XXX */
534 vn
.v_rdev
= dev
; /* XXX */
535 error
= vm_mmap(&p
->p_vmspace
->vm_map
, (vm_offset_t
*)addrp
,
536 PAGE_SIZE
, VM_PROT_ALL
, flags
, (void *)&vn
, 0);
541 clockunmmap(dev_t dev
, void *addr
, struct proc
*p
)
546 return(EINVAL
); /* XXX: how do we deal with this? */
547 uvm_deallocate(p
->p_vmspace
->vm_map
, (vm_offset_t
)addr
, PAGE_SIZE
);
554 register struct clkreg
*clk
= (struct clkreg
*)clkstd
[0];
556 clk
->clk_msb2
= -1; clk
->clk_lsb2
= -1;
557 clk
->clk_msb3
= -1; clk
->clk_lsb3
= -1;
559 clk
->clk_cr2
= CLK_CR3
;
560 clk
->clk_cr3
= CLK_OENAB
|CLK_8BIT
;
561 clk
->clk_cr2
= CLK_CR1
;
562 clk
->clk_cr1
= CLK_IENAB
;
568 register struct clkreg
*clk
= (struct clkreg
*)clkstd
[0];
570 clk
->clk_cr2
= CLK_CR3
;
572 clk
->clk_cr2
= CLK_CR1
;
573 clk
->clk_cr1
= CLK_IENAB
;
582 * This code allows the amiga kernel to use one of the extra timers on
583 * the clock chip for profiling, instead of the regular system timer.
584 * The advantage of this is that the profiling timer can be turned up to
585 * a higher interrupt rate, giving finer resolution timing. The profclock
586 * routine is called from the lev6intr in locore, and is a specialized
587 * routine that calls addupc. The overhead then is far less than if
588 * hardclock/softclock was called. Further, the context switch code in
589 * locore has been changed to turn the profile clock on/off when switching
590 * into/out of a process that is profiling (startprofclock/stopprofclock).
591 * This reduces the impact of the profiling clock on other users, and might
592 * possibly increase the accuracy of the profiling.
594 int profint
= PRF_INTERVAL
; /* Clock ticks between interrupts */
595 int profscale
= 0; /* Scale factor from sys clock to prof clock */
596 char profon
= 0; /* Is profiling clock on? */
598 /* profon values - do not change, locore.s assumes these values */
599 #define PRF_NONE 0x00
600 #define PRF_USER 0x01
601 #define PRF_KERNEL 0x80
607 struct proc
*p
= curproc
; /* XXX */
610 * If the high-res timer is running, force profiling off.
611 * Unfortunately, this gets reflected back to the user not as
612 * an error but as a lack of results.
615 p
->p_stats
->p_prof
.pr_scale
= 0;
619 * Keep track of the number of user processes that are profiling
620 * by checking the scale value.
622 * XXX: this all assumes that the profiling code is well behaved;
623 * i.e. profil() is called once per process with pcscale non-zero
624 * to turn it on, and once with pcscale zero to turn it off.
625 * Also assumes you don't do any forks or execs. Oh well, there
628 if (p
->p_stats
->p_prof
.pr_scale
)
634 * The profile interrupt interval must be an even divisor
635 * of the amiga_clk_interval so that scaling from a system clock
636 * tick to a profile clock tick is possible using integer math.
638 if (profint
> amiga_clk_interval
|| (amiga_clk_interval
% profint
) != 0)
639 profint
= amiga_clk_interval
;
640 profscale
= amiga_clk_interval
/ profint
;
646 unsigned short interval
;
649 clockcia
->crb
= clockcia
->crb
& 0xc0;
651 /* load interval into registers.
652 the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */
654 interval
= profint
- 1;
656 /* order of setting is important ! */
657 clockcia
->tblo
= interval
& 0xff;
658 clockcia
->tbhi
= interval
>> 8;
660 /* enable interrupts for timer B */
661 clockcia
->icr
= (1<<7) | (1<<1);
663 /* start timer B in continuous shot mode */
664 clockcia
->crb
= (clockcia
->crb
& 0xc0) | 1;
671 clockcia
->crb
= clockcia
->crb
& 0xc0;
676 * profclock() is expanded in line in lev6intr() unless profiling kernel.
677 * Assumes it is called with clock interrupts blocked.
680 profclock(void *pc
, int ps
)
683 * Came from user mode.
684 * If this process is being profiled record the tick.
687 if (p
->p_stats
.p_prof
.pr_scale
)
688 addupc(pc
, &curproc
->p_stats
.p_prof
, 1);
691 * Came from kernel (supervisor) mode.
692 * If we are profiling the kernel, record the tick.
694 else if (profiling
< 2) {
695 register int s
= pc
- s_lowpc
;
698 kcount
[s
/ (HISTFRACTION
* sizeof (*kcount
))]++;
701 * Kernel profiling was on but has been disabled.
702 * Mark as no longer profiling kernel and if all profiling done,
705 if (profiling
&& (profon
& PRF_KERNEL
)) {
706 profon
&= ~PRF_KERNEL
;
707 if (profon
== PRF_NONE
)