Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / vax / vax / clock.c
blob22a236d4c02c0d72bc6fc2d3935d69ded95229ac
1 /* $NetBSD: clock.c,v 1.51 2009/09/14 02:19:15 mhitch Exp $ */
2 /*
3 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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,
62 #if VAX46 || VAXANY
63 static u_int
64 vax_diag_get_counter(struct timecounter *tc)
66 extern struct vs_cpu *ka46_cpu;
67 int cur_hardclock;
68 u_int counter;
70 do {
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;
79 #endif
81 static u_int
82 vax_mfpr_get_counter(struct timecounter *tc)
84 int cur_hardclock;
85 u_int counter;
86 static int prev_count, prev_hardclock;
88 do {
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)
105 cur_hardclock++;
107 prev_count = counter;
108 prev_hardclock=cur_hardclock;
110 return counter + cur_hardclock * tick;
113 #if VAX46 || VAXANY
114 static struct timecounter vax_diag_tc = {
115 vax_diag_get_counter, /* get_timecount */
116 0, /* no poll_pps */
117 ~0u, /* counter_mask */
118 1000000, /* frequency */
119 "diagtimer", /* name */
120 100, /* quality */
121 NULL, /* prev */
122 NULL, /* next */
124 #endif
126 static struct timecounter vax_mfpr_tc = {
127 vax_mfpr_get_counter, /* get_timecount */
128 0, /* no poll_pps */
129 ~0u, /* counter_mask */
130 1000000, /* frequency */
131 "mfpr", /* name */
132 100, /* quality */
133 NULL, /* prev */
134 NULL, /* next */
138 * A delayloop that delays about the number of milliseconds that is
139 * given as argument.
141 void
142 delay(int i)
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.
152 void
153 cpu_initclocks(void)
155 mtpr(-10000, PR_NICR); /* Load in count register */
156 mtpr(0x800000d1, PR_ICCS); /* Start clock and enable interrupt */
158 todr_attach(&todr_handle);
160 #if VAX46 || VAXANY
161 if (vax_boardtype == VAX_BTYP_46)
162 tc_init(&vax_diag_tc);
163 #endif
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);
179 return 0;
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.
193 yeartonum(int y)
195 int n;
197 for (n = 0, y -= 1; y > 69; y--)
198 n += SECPERYEAR(y);
199 return n;
203 * Converts tick number to a year 70 ->
206 numtoyear(int num)
208 int y = 70, j;
209 while(num >= (j = SECPERYEAR(y))) {
210 y++;
211 num -= j;
213 return 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);
229 * Sanity check.
231 if (klocka < TODRBASE) {
232 if (klocka == 0)
233 printf("TODR stopped");
234 else
235 printf("TODR too small");
236 return EINVAL;
239 tvp->tv_sec = yeartonum(numtoyear(tvp->tv_sec)) + (klocka - TODRBASE) / 100;
240 return 0;
244 * Takes the current system time and writes it to the TODR.
246 void
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);
254 #endif
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;
271 #ifdef DIAGNOSTIC
272 if (clk_page == 0)
273 panic("trying to use unset chip clock page");
274 #endif
276 if ((REGPEEK(CSRD_OFF) & CSRD_VRT) == 0) {
277 printf("WARNING: TOY clock not marked valid");
278 return EINVAL;
280 while (REGPEEK(CSRA_OFF) & CSRA_UIP) {
281 if (--timeout == 0) {
282 printf ("TOY clock timed out");
283 return ETIMEDOUT;
287 s = splhigh();
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);
295 splx(s);
297 tvp->tv_sec = clock_ymdhms_to_secs(&c);
298 tvp->tv_usec = 0;
299 return 0;
302 void
303 chip_settime(struct timeval *tvp)
305 struct clock_ymdhms c;
307 #ifdef DIAGNOSTIC
308 if (clk_page == 0)
309 panic("trying to use unset chip clock page");
310 #endif
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);
326 #endif