clock.c revision 1.59.28.1 1 /* $NetBSD: clock.c,v 1.59.28.1 2020/04/13 08:03:39 martin Exp $ */
2
3 /*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1982, 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: Utah $Hdr: clock.c 1.18 91/01/21$
37 *
38 * @(#)clock.c 7.6 (Berkeley) 5/7/91
39 */
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.59.28.1 2020/04/13 08:03:39 martin Exp $");
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/device.h>
48 #include <sys/uio.h>
49 #include <sys/conf.h>
50 #include <sys/proc.h>
51 #include <sys/event.h>
52 #include <sys/timetc.h>
53
54 #include <dev/clock_subr.h>
55
56 #include <machine/psl.h>
57 #include <machine/cpu.h>
58 #include <machine/iomap.h>
59 #include <machine/mfp.h>
60 #include <atari/dev/clockreg.h>
61 #include <atari/dev/clockvar.h>
62 #include <atari/atari/device.h>
63
64 #if defined(GPROF) && defined(PROFTIMER)
65 #include <machine/profile.h>
66 #endif
67
68 #include "ioconf.h"
69
70 static int atari_rtc_get(todr_chip_handle_t, struct clock_ymdhms *);
71 static int atari_rtc_set(todr_chip_handle_t, struct clock_ymdhms *);
72
73 /*
74 * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider
75 * of 200. Therefore the timer runs at an effective rate of:
76 * 2457600/200 = 12288Hz.
77 */
78 #define CLOCK_HZ 12288
79
80 static u_int clk_getcounter(struct timecounter *);
81
82 static struct timecounter clk_timecounter = {
83 clk_getcounter, /* get_timecount */
84 0, /* no poll_pps */
85 ~0u, /* counter_mask */
86 CLOCK_HZ, /* frequency */
87 "clock", /* name, overriden later */
88 100, /* quality */
89 NULL, /* prev */
90 NULL, /* next */
91 };
92
93 /*
94 * Machine-dependent clock routines.
95 *
96 * Inittodr initializes the time of day hardware which provides
97 * date functions.
98 *
99 * Resettodr restores the time of day hardware after a time change.
100 */
101
102 struct clock_softc {
103 device_t sc_dev;
104 int sc_flags;
105 struct todr_chip_handle sc_handle;
106 };
107
108 /*
109 * 'sc_flags' state info. Only used by the rtc-device functions.
110 */
111 #define RTC_OPEN 1
112
113 dev_type_open(rtcopen);
114 dev_type_close(rtcclose);
115 dev_type_read(rtcread);
116 dev_type_write(rtcwrite);
117
118 static void clockattach(device_t, device_t, void *);
119 static int clockmatch(device_t, cfdata_t, void *);
120
121 CFATTACH_DECL_NEW(clock, sizeof(struct clock_softc),
122 clockmatch, clockattach, NULL, NULL);
123
124 const struct cdevsw rtc_cdevsw = {
125 .d_open = rtcopen,
126 .d_close = rtcclose,
127 .d_read = rtcread,
128 .d_write = rtcwrite,
129 .d_ioctl = noioctl,
130 .d_stop = nostop,
131 .d_tty = notty,
132 .d_poll = nopoll,
133 .d_mmap = nommap,
134 .d_kqfilter = nokqfilter,
135 .d_discard = nodiscard,
136 .d_flag = 0
137 };
138
139 void statintr(struct clockframe);
140
141 static int twodigits(char *, int);
142
143 static int divisor; /* Systemclock divisor */
144
145 /*
146 * Statistics and profile clock intervals and variances. Variance must
147 * be a power of 2. Since this gives us an even number, not an odd number,
148 * we discard one case and compensate. That is, a variance of 64 would
149 * give us offsets in [0..63]. Instead, we take offsets in [1..63].
150 * This is symmetric around the point 32, or statvar/2, and thus averages
151 * to that value (assuming uniform random numbers).
152 */
153 #ifdef STATCLOCK
154 static int statvar = 32; /* {stat,prof}clock variance */
155 static int statmin; /* statclock divisor - variance/2 */
156 static int profmin; /* profclock divisor - variance/2 */
157 static int clk2min; /* current, from above choices */
158 #endif
159
160 static int
161 clockmatch(device_t parent, cfdata_t cf, void *aux)
162 {
163
164 if (!strcmp("clock", aux))
165 return 1;
166 return 0;
167 }
168
169 /*
170 * Start the real-time clock.
171 */
172 static void
173 clockattach(device_t parent, device_t self, void *aux)
174 {
175 struct clock_softc *sc = device_private(self);
176 struct todr_chip_handle *tch;
177
178 sc->sc_dev = self;
179 tch = &sc->sc_handle;
180 tch->todr_gettime_ymdhms = atari_rtc_get;
181 tch->todr_settime_ymdhms = atari_rtc_set;
182 tch->todr_setwen = NULL;
183
184 todr_attach(tch);
185
186 sc->sc_flags = 0;
187
188 /*
189 * Initialize Timer-A in the ST-MFP. We use a divisor of 200.
190 * The MFP clock runs at 2457600Hz. Therefore the timer runs
191 * at an effective rate of: 2457600/200 = 12288Hz. The
192 * following expression works for 48, 64 or 96 hz.
193 */
194 divisor = CLOCK_HZ/hz;
195 MFP->mf_tacr = 0; /* Stop timer */
196 MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */
197 MFP->mf_tadr = divisor; /* Set divisor */
198
199 clk_timecounter.tc_frequency = CLOCK_HZ;
200
201 if (hz != 48 && hz != 64 && hz != 96) { /* XXX */
202 printf (": illegal value %d for systemclock, reset to %d\n\t",
203 hz, 64);
204 hz = 64;
205 }
206 printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor);
207 tc_init(&clk_timecounter);
208
209 #ifdef STATCLOCK
210 if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz))
211 stathz = hz;
212 if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz))
213 profhz = hz << 1;
214
215 MFP->mf_tcdcr &= 0x7; /* Stop timer */
216 MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */
217 MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */
218
219 statmin = (CLOCK_HZ/stathz) - (statvar >> 1);
220 profmin = (CLOCK_HZ/profhz) - (statvar >> 1);
221 clk2min = statmin;
222 #endif /* STATCLOCK */
223 }
224
225 void
226 cpu_initclocks(void)
227 {
228
229 MFP->mf_tacr = T_Q200; /* Start timer */
230 MFP->mf_ipra = (u_int8_t)~IA_TIMA;/* Clear pending interrupts */
231 MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */
232 MFP->mf_imra |= IA_TIMA; /* ..... */
233
234 #ifdef STATCLOCK
235 MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */
236 MFP->mf_iprb = (u_int8_t)~IB_TIMC;/* Clear pending interrupts */
237 MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */
238 MFP->mf_imrb |= IB_TIMC; /* ..... */
239 #endif /* STATCLOCK */
240 }
241
242 void
243 setstatclockrate(int newhz)
244 {
245
246 #ifdef STATCLOCK
247 if (newhz == stathz)
248 clk2min = statmin;
249 else clk2min = profmin;
250 #endif /* STATCLOCK */
251 }
252
253 #ifdef STATCLOCK
254 void
255 statintr(struct clockframe frame)
256 {
257 register int var, r;
258
259 var = statvar - 1;
260 do {
261 r = random() & var;
262 } while (r == 0);
263
264 /*
265 * Note that we are always lagging behind as the new divisor
266 * value will not be loaded until the next interrupt. This
267 * shouldn't disturb the median frequency (I think ;-) ) as
268 * only the value used when switching frequencies is used
269 * twice. This shouldn't happen very often.
270 */
271 MFP->mf_tcdr = clk2min + r;
272
273 statclock(&frame);
274 }
275 #endif /* STATCLOCK */
276
277 static u_int
278 clk_getcounter(struct timecounter *tc)
279 {
280 uint32_t delta, count, cur_hardclock;
281 uint8_t ipra, tadr;
282 int s;
283 static uint32_t lastcount;
284
285 s = splhigh();
286 cur_hardclock = hardclock_ticks;
287 ipra = MFP->mf_ipra;
288 tadr = MFP->mf_tadr;
289 delta = divisor - tadr;
290
291 if (ipra & IA_TIMA)
292 delta += divisor;
293 splx(s);
294
295 count = (divisor * cur_hardclock) + delta;
296 if ((int32_t)(count - lastcount) < 0) {
297 /* XXX wrapped; maybe hardclock() is blocked more than 2/HZ */
298 count = lastcount + 1;
299 }
300 lastcount = count;
301
302 return count;
303 }
304
305 #define TIMB_FREQ 614400
306 #define TIMB_LIMIT 256
307
308 void
309 init_delay(void)
310 {
311
312 /*
313 * Initialize Timer-B in the ST-MFP. This timer is used by
314 * the 'delay' function below. This timer is setup to be
315 * continueously counting from 255 back to zero at a
316 * frequency of 614400Hz. We do this *early* in the
317 * initialisation process.
318 */
319 MFP->mf_tbcr = 0; /* Stop timer */
320 MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */
321 MFP->mf_tbdr = 0;
322 MFP->mf_tbcr = T_Q004; /* Start timer */
323 }
324
325 /*
326 * Wait "n" microseconds.
327 * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz.
328 * Note: timer had better have been programmed before this is first used!
329 */
330 void
331 delay(unsigned int n)
332 {
333 int ticks, otick, remaining;
334
335 /*
336 * Read the counter first, so that the rest of the setup overhead is
337 * counted.
338 */
339 otick = MFP->mf_tbdr;
340
341 if (n <= UINT_MAX / TIMB_FREQ) {
342 /*
343 * For unsigned arithmetic, division can be replaced with
344 * multiplication with the inverse and a shift.
345 */
346 remaining = n * TIMB_FREQ / 1000000;
347 } else {
348 /* This is a very long delay.
349 * Being slow here doesn't matter.
350 */
351 remaining = (unsigned long long) n * TIMB_FREQ / 1000000;
352 }
353
354 while (remaining > 0) {
355 ticks = MFP->mf_tbdr;
356 if (ticks > otick)
357 remaining -= TIMB_LIMIT - (ticks - otick);
358 else
359 remaining -= otick - ticks;
360 otick = ticks;
361 }
362 }
363
364 #ifdef GPROF
365 /*
366 * profclock() is expanded in line in lev6intr() unless profiling kernel.
367 * Assumes it is called with clock interrupts blocked.
368 */
369 profclock(void *pc, int ps)
370 {
371
372 /*
373 * Came from user mode.
374 * If this process is being profiled record the tick.
375 */
376 if (USERMODE(ps)) {
377 if (p->p_stats.p_prof.pr_scale)
378 addupc(pc, &curproc->p_stats.p_prof, 1);
379 }
380 /*
381 * Came from kernel (supervisor) mode.
382 * If we are profiling the kernel, record the tick.
383 */
384 else if (profiling < 2) {
385 register int s = pc - s_lowpc;
386
387 if (s < s_textsize)
388 kcount[s / (HISTFRACTION * sizeof(*kcount))]++;
389 }
390 /*
391 * Kernel profiling was on but has been disabled.
392 * Mark as no longer profiling kernel and if all profiling done,
393 * disable the clock.
394 */
395 if (profiling && (profon & PRF_KERNEL)) {
396 profon &= ~PRF_KERNEL;
397 if (profon == PRF_NONE)
398 stopprofclock();
399 }
400 }
401 #endif
402
403 /***********************************************************************
404 * Real Time Clock support *
405 ***********************************************************************/
406
407 u_int mc146818_read(void *cookie, u_int regno)
408 {
409 struct rtc *rtc = cookie;
410
411 rtc->rtc_regno = regno;
412 return rtc->rtc_data & 0xff;
413 }
414
415 void mc146818_write(void *cookie, u_int regno, u_int value)
416 {
417 struct rtc *rtc = cookie;
418
419 rtc->rtc_regno = regno;
420 rtc->rtc_data = value;
421 }
422
423 static int
424 atari_rtc_get(todr_chip_handle_t todr, struct clock_ymdhms *dtp)
425 {
426 int sps;
427 mc_todregs clkregs;
428 u_int regb;
429
430 sps = splhigh();
431 regb = mc146818_read(RTC, MC_REGB);
432 MC146818_GETTOD(RTC, &clkregs);
433 splx(sps);
434
435 regb &= MC_REGB_24HR|MC_REGB_BINARY;
436 if (regb != (MC_REGB_24HR|MC_REGB_BINARY)) {
437 printf("Error: Nonstandard RealTimeClock Configuration -"
438 " value ignored\n"
439 " A write to /dev/rtc will correct this.\n");
440 return 0;
441 }
442 if (clkregs[MC_SEC] > 59)
443 return -1;
444 if (clkregs[MC_MIN] > 59)
445 return -1;
446 if (clkregs[MC_HOUR] > 23)
447 return -1;
448 if (range_test(clkregs[MC_DOM], 1, 31))
449 return -1;
450 if (range_test(clkregs[MC_MONTH], 1, 12))
451 return -1;
452 if (clkregs[MC_YEAR] > 99)
453 return -1;
454
455 dtp->dt_year = clkregs[MC_YEAR] + GEMSTARTOFTIME;
456 dtp->dt_mon = clkregs[MC_MONTH];
457 dtp->dt_day = clkregs[MC_DOM];
458 dtp->dt_hour = clkregs[MC_HOUR];
459 dtp->dt_min = clkregs[MC_MIN];
460 dtp->dt_sec = clkregs[MC_SEC];
461
462 return 0;
463 }
464
465 static int
466 atari_rtc_set(todr_chip_handle_t todr, struct clock_ymdhms *dtp)
467 {
468 int s;
469 mc_todregs clkregs;
470
471 clkregs[MC_YEAR] = dtp->dt_year - GEMSTARTOFTIME;
472 clkregs[MC_MONTH] = dtp->dt_mon;
473 clkregs[MC_DOM] = dtp->dt_day;
474 clkregs[MC_HOUR] = dtp->dt_hour;
475 clkregs[MC_MIN] = dtp->dt_min;
476 clkregs[MC_SEC] = dtp->dt_sec;
477
478 s = splclock();
479 MC146818_PUTTOD(RTC, &clkregs);
480 splx(s);
481
482 return 0;
483 }
484
485 /***********************************************************************
486 * RTC-device support *
487 ***********************************************************************/
488 int
489 rtcopen(dev_t dev, int flag, int mode, struct lwp *l)
490 {
491 int unit = minor(dev);
492 struct clock_softc *sc;
493
494 sc = device_lookup_private(&clock_cd, unit);
495 if (sc == NULL)
496 return ENXIO;
497 if (sc->sc_flags & RTC_OPEN)
498 return EBUSY;
499
500 sc->sc_flags = RTC_OPEN;
501 return 0;
502 }
503
504 int
505 rtcclose(dev_t dev, int flag, int mode, struct lwp *l)
506 {
507 int unit = minor(dev);
508 struct clock_softc *sc = device_lookup_private(&clock_cd, unit);
509
510 sc->sc_flags = 0;
511 return 0;
512 }
513
514 int
515 rtcread(dev_t dev, struct uio *uio, int flags)
516 {
517 mc_todregs clkregs;
518 int s, length;
519 char buffer[16 + 1];
520
521 s = splhigh();
522 MC146818_GETTOD(RTC, &clkregs);
523 splx(s);
524
525 snprintf(buffer, sizeof(buffer), "%4d%02d%02d%02d%02d.%02d\n",
526 clkregs[MC_YEAR] + GEMSTARTOFTIME,
527 clkregs[MC_MONTH], clkregs[MC_DOM],
528 clkregs[MC_HOUR], clkregs[MC_MIN], clkregs[MC_SEC]);
529
530 if (uio->uio_offset > strlen(buffer))
531 return 0;
532
533 length = strlen(buffer) - uio->uio_offset;
534 if (length > uio->uio_resid)
535 length = uio->uio_resid;
536
537 return uiomove((void *)buffer, length, uio);
538 }
539
540 static int
541 twodigits(char *buffer, int pos)
542 {
543 int result = 0;
544
545 if (buffer[pos] >= '0' && buffer[pos] <= '9')
546 result = (buffer[pos] - '0') * 10;
547 if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9')
548 result += (buffer[pos+1] - '0');
549 return result;
550 }
551
552 int
553 rtcwrite(dev_t dev, struct uio *uio, int flags)
554 {
555 mc_todregs clkregs;
556 int s, length, error;
557 char buffer[16];
558
559 /*
560 * We require atomic updates!
561 */
562 length = uio->uio_resid;
563 if (uio->uio_offset || (length != sizeof(buffer)
564 && length != sizeof(buffer) - 1))
565 return EINVAL;
566
567 if ((error = uiomove((void *)buffer, sizeof(buffer), uio)))
568 return error;
569
570 if (length == sizeof(buffer) && buffer[sizeof(buffer) - 1] != '\n')
571 return EINVAL;
572
573 s = splclock();
574 mc146818_write(RTC, MC_REGB,
575 mc146818_read(RTC, MC_REGB) | MC_REGB_24HR | MC_REGB_BINARY);
576 MC146818_GETTOD(RTC, &clkregs);
577 splx(s);
578
579 clkregs[MC_SEC] = twodigits(buffer, 13);
580 clkregs[MC_MIN] = twodigits(buffer, 10);
581 clkregs[MC_HOUR] = twodigits(buffer, 8);
582 clkregs[MC_DOM] = twodigits(buffer, 6);
583 clkregs[MC_MONTH] = twodigits(buffer, 4);
584 s = twodigits(buffer, 0) * 100 + twodigits(buffer, 2);
585 clkregs[MC_YEAR] = s - GEMSTARTOFTIME;
586
587 s = splclock();
588 MC146818_PUTTOD(RTC, &clkregs);
589 splx(s);
590
591 return 0;
592 }
593