1 /* $NetBSD: clock.c,v 1.51 2009/09/14 02:19:15 mhitch Exp $ */
3 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
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.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of Lule}.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.51 2009/09/14 02:19:15 mhitch Exp $");
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/timetc.h>
39 #include <sys/device.h>
41 #include <machine/mtpr.h>
42 #include <machine/sid.h>
43 #include <machine/clock.h>
44 #include <machine/cpu.h>
45 #include <machine/uvax.h>
47 #include "opt_cputype.h"
49 struct evcnt clock_intrcnt
=
50 EVCNT_INITIALIZER(EVCNT_TYPE_INTR
, NULL
, "clock", "intr");
52 EVCNT_ATTACH_STATIC(clock_intrcnt
);
54 static int vax_gettime(todr_chip_handle_t
, struct timeval
*);
55 static int vax_settime(todr_chip_handle_t
, struct timeval
*);
57 static struct todr_chip_handle todr_handle
= {
58 .todr_gettime
= vax_gettime
,
59 .todr_settime
= vax_settime
,
64 vax_diag_get_counter(struct timecounter
*tc
)
66 extern struct vs_cpu
*ka46_cpu
;
71 cur_hardclock
= hardclock_ticks
;
72 counter
= *(volatile u_int
*)&ka46_cpu
->vc_diagtimu
;
73 } while (cur_hardclock
!= hardclock_ticks
);
75 counter
= (counter
& 0x3ff) + (counter
>> 16) * 1024;
77 return counter
+ hardclock_ticks
* tick
;
82 vax_mfpr_get_counter(struct timecounter
*tc
)
86 static int prev_count
, prev_hardclock
;
89 cur_hardclock
= hardclock_ticks
;
90 counter
= mfpr(PR_ICR
) + tick
;
91 } while (cur_hardclock
!= hardclock_ticks
);
94 * Handle interval counter wrapping with interrupts blocked.
95 * If the current hardclock_ticks is less than what we saw
96 * previously, use the previous value.
97 * If the interval counter is smaller, assume it has wrapped,
98 * and if the [adjusted] current hardclock ticks is the same
99 * as what we saw previously, increment the local copy of
100 * the hardclock ticks.
102 if (cur_hardclock
< prev_hardclock
)
103 cur_hardclock
= prev_hardclock
;
104 if (counter
< prev_count
&& cur_hardclock
== prev_hardclock
)
107 prev_count
= counter
;
108 prev_hardclock
=cur_hardclock
;
110 return counter
+ cur_hardclock
* tick
;
114 static struct timecounter vax_diag_tc
= {
115 vax_diag_get_counter
, /* get_timecount */
117 ~0u, /* counter_mask */
118 1000000, /* frequency */
119 "diagtimer", /* name */
126 static struct timecounter vax_mfpr_tc
= {
127 vax_mfpr_get_counter
, /* get_timecount */
129 ~0u, /* counter_mask */
130 1000000, /* frequency */
138 * A delayloop that delays about the number of milliseconds that is
144 __asm ("1: sobgtr %0, 1b" : : "r" (dep_call
->cpu_vups
* i
));
148 * On all VAXen there are a microsecond clock that should
149 * be used for interval interrupts. Some CPUs don't use the ICR interval
150 * register but it doesn't hurt to load it anyway.
155 mtpr(-10000, PR_NICR
); /* Load in count register */
156 mtpr(0x800000d1, PR_ICCS
); /* Start clock and enable interrupt */
158 todr_attach(&todr_handle
);
161 if (vax_boardtype
== VAX_BTYP_46
)
162 tc_init(&vax_diag_tc
);
164 if (vax_boardtype
!= VAX_BTYP_46
&& vax_boardtype
!= VAX_BTYP_48
)
165 tc_init(&vax_mfpr_tc
);
169 vax_gettime(todr_chip_handle_t handle
, struct timeval
*tvp
)
171 tvp
->tv_sec
= handle
->base_time
;
172 return (*dep_call
->cpu_gettime
)(tvp
);
176 vax_settime(todr_chip_handle_t handle
, struct timeval
*tvp
)
178 (*dep_call
->cpu_settime
)(tvp
);
183 * There are two types of real-time battery-backed up clocks on
184 * VAX computers, one with a register that counts up every 1/100 second,
185 * one with a clock chip that delivers time. For the register clock
186 * we have a generic version, and for the chip clock there are
187 * support routines for time conversion.
190 * Converts a year to corresponding number of ticks.
197 for (n
= 0, y
-= 1; y
> 69; y
--)
203 * Converts tick number to a year 70 ->
209 while(num
>= (j
= SECPERYEAR(y
))) {
216 #if VAX750 || VAX780 || VAX8600 || VAX650 || \
217 VAX660 || VAX670 || VAX680 || VAX53 || VAXANY
219 * Reads the TODR register; returns a (probably) true tick value, and 0 is
220 * success or EINVAL if failed. The year is based on the argument
221 * year; the TODR doesn't hold years.
224 generic_gettime(struct timeval
*tvp
)
226 unsigned klocka
= mfpr(PR_TODR
);
231 if (klocka
< TODRBASE
) {
233 printf("TODR stopped");
235 printf("TODR too small");
239 tvp
->tv_sec
= yeartonum(numtoyear(tvp
->tv_sec
)) + (klocka
- TODRBASE
) / 100;
244 * Takes the current system time and writes it to the TODR.
247 generic_settime(struct timeval
*tvp
)
249 unsigned tid
= tvp
->tv_sec
, bastid
;
251 bastid
= tid
- yeartonum(numtoyear(tid
));
252 mtpr((bastid
* 100) + TODRBASE
, PR_TODR
);
256 #if VAX630 || VAX410 || VAX43 || VAX8200 || VAX46 || VAX48 || VAX49 || VAXANY
258 volatile short *clk_page
; /* where the chip is mapped in virtual memory */
259 int clk_adrshift
; /* how much to multiply the in-page address with */
260 int clk_tweak
; /* Offset of time into word. */
262 #define REGPEEK(off) (clk_page[off << clk_adrshift] >> clk_tweak)
263 #define REGPOKE(off, v) (clk_page[off << clk_adrshift] = ((v) << clk_tweak))
266 chip_gettime(struct timeval
*tvp
)
268 struct clock_ymdhms c
;
269 int timeout
= 1<<15, s
;
273 panic("trying to use unset chip clock page");
276 if ((REGPEEK(CSRD_OFF
) & CSRD_VRT
) == 0) {
277 printf("WARNING: TOY clock not marked valid");
280 while (REGPEEK(CSRA_OFF
) & CSRA_UIP
) {
281 if (--timeout
== 0) {
282 printf ("TOY clock timed out");
288 c
.dt_year
= ((u_char
)REGPEEK(YR_OFF
)) + 1970;
289 c
.dt_mon
= REGPEEK(MON_OFF
);
290 c
.dt_day
= REGPEEK(DAY_OFF
);
291 c
.dt_wday
= REGPEEK(WDAY_OFF
);
292 c
.dt_hour
= REGPEEK(HR_OFF
);
293 c
.dt_min
= REGPEEK(MIN_OFF
);
294 c
.dt_sec
= REGPEEK(SEC_OFF
);
297 tvp
->tv_sec
= clock_ymdhms_to_secs(&c
);
303 chip_settime(struct timeval
*tvp
)
305 struct clock_ymdhms c
;
309 panic("trying to use unset chip clock page");
312 REGPOKE(CSRB_OFF
, CSRB_SET
);
314 clock_secs_to_ymdhms(tvp
->tv_sec
, &c
);
316 REGPOKE(YR_OFF
, ((u_char
)(c
.dt_year
- 1970)));
317 REGPOKE(MON_OFF
, c
.dt_mon
);
318 REGPOKE(DAY_OFF
, c
.dt_day
);
319 REGPOKE(WDAY_OFF
, c
.dt_wday
);
320 REGPOKE(HR_OFF
, c
.dt_hour
);
321 REGPOKE(MIN_OFF
, c
.dt_min
);
322 REGPOKE(SEC_OFF
, c
.dt_sec
);
324 REGPOKE(CSRB_OFF
, CSRB_DM
|CSRB_24
);