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