FreeBSD/Linux Kernel Cross Reference
sys/chips/mc_clock.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: mc_clock.c,v $
29 * Revision 2.15 93/05/17 15:11:48 rvb
30 * Type casts, etc to quiet gcc 2.3.3 warnings
31 * [93/05/17 rvb]
32 *
33 * Revision 2.14 93/05/15 19:37:12 mrt
34 * machparam.h -> machspl.h
35 *
36 * Revision 2.13 93/05/10 20:08:19 rvb
37 * Fixed types. Define what is exported and what not.
38 * [93/05/06 09:57:45 af]
39 *
40 * Revision 2.12 93/02/05 08:05:43 danner
41 * Heavy cosmetic changes to make it look like a device after all.
42 * Flamingo uses it too.
43 * [93/02/04 01:30:53 af]
44 *
45 * Proper spl typing.
46 * [92/11/30 af]
47 *
48 * Revision 2.11 92/02/19 16:45:57 elf
49 * Wait for uip before stopping the chip, too.
50 * [92/01/22 af]
51 *
52 * Revision 2.10 91/08/24 11:52:28 af
53 * Fixed spl munging, for 3min.
54 * [91/08/02 01:49:09 af]
55 *
56 * Revision 2.9 91/06/25 20:54:18 rpd
57 * Tweaks to make gcc happy.
58 *
59 * Revision 2.8 91/06/19 11:53:54 rvb
60 * mips->DECSTATION; vax->VAXSTATION
61 * [91/06/12 14:01:54 rvb]
62 *
63 * File moved here from mips/PMAX since it tries to be generic;
64 * it is used on the PMAX and could be used on the Vax3100.
65 * It would need a few ifdef vax & ifdef mips for the latter.
66 * [91/06/04 rvb]
67 *
68 * Revision 2.7 91/05/14 17:24:22 mrt
69 * Correcting copyright
70 *
71 * Revision 2.6 91/02/14 14:34:41 mrt
72 * Factored out delay() function, and made it box-indep.
73 * Added accurate_config_delay() which calls delay()'s
74 * configuration code. Modified ackrtclock() to
75 * invoke it on first call.
76 * Tell the user what the CPU clock speed loks like,
77 * distinguish between DS3100 and DS2100 based on clock speed.
78 * [91/02/12 13:03:16 af]
79 *
80 * Revision 2.5 91/02/05 17:42:35 mrt
81 * Added author notices
82 * [91/02/04 11:15:06 mrt]
83 *
84 * Changed to use new Mach copyright
85 * [91/02/02 12:13:45 mrt]
86 *
87 * Revision 2.4 90/12/05 23:32:39 af
88 *
89 *
90 * Revision 2.3 90/12/05 20:47:31 af
91 * Made file conditional.
92 * [90/12/03 23:28:03 af]
93 *
94 * Revision 2.2 90/08/27 22:06:05 dbg
95 * Initialized cpu_speed to a non-zero value. Apparently,
96 * we need delays much earlier than we can possibly know
97 * what this machine looks like. I know this will bite back.
98 * [90/08/21 af]
99 * Made apparent who is resetting the clock back to 1972.
100 * [90/08/20 10:30:19 af]
101 *
102 * Created, from Motorola's MC146818 specs.
103 * [90/08/17 af]
104 *
105 */
106 /*
107 * File: mc_clock.c
108 * Author: Alessandro Forin
109 * Date: 8/90
110 *
111 * Driver for the MC146818 Clock
112 */
113
114 #include <mc.h>
115 #if NMC > 0
116 #include <platforms.h>
117
118 #include <mach/std_types.h>
119 #include <machine/machspl.h> /* spl definitions */
120 #include <chips/busses.h>
121
122 #include <sys/time.h>
123 #include <kern/time_out.h>
124 #include <chips/mc_clock.h>
125
126 #ifdef DECSTATION
127 #include <mips/mips_cpu.h>
128 #include <mips/clock.h>
129 #endif /*DECSTATION*/
130
131 #ifdef FLAMINGO
132 #include <alpha/clock.h>
133 #endif /*FLAMINGO*/
134
135 #define private static
136 #define public
137
138
139 /* Architecture-specific defines */
140
141 #ifdef DECSTATION
142
143 #define MC_DEFAULT_ADDRESS (mc_clock_ram_t *)PHYS_TO_K1SEG(0x1d000000)
144 #define MC_DOES_DELAYS 1
145
146 /*
147 * Both the Pmax and the 3max implementations of the chip map
148 * bytes of the chip's RAM to 32 bit words (low byte).
149 * For convenience, we redefine here the chip's RAM layout
150 * making padding explicit.
151 */
152
153 typedef struct {
154 volatile unsigned char mc_second;
155 char pad0[3];
156 volatile unsigned char mc_alarm_second;
157 char pad1[3];
158 volatile unsigned char mc_minute;
159 char pad2[3];
160 volatile unsigned char mc_alarm_minute;
161 char pad3[3];
162 volatile unsigned char mc_hour;
163 char pad4[3];
164 volatile unsigned char mc_alarm_hour;
165 char pad5[3];
166 volatile unsigned char mc_day_of_week;
167 char pad6[3];
168 volatile unsigned char mc_day_of_month;
169 char pad7[3];
170 volatile unsigned char mc_month;
171 char pad8[3];
172 volatile unsigned char mc_year;
173 char pad9[3];
174 volatile unsigned char mc_register_A;
175 char pad10[3];
176 volatile unsigned char mc_register_B;
177 char pad11[3];
178 volatile unsigned char mc_register_C;
179 char pad12[3];
180 volatile unsigned char mc_register_D;
181 char pad13[3];
182 unsigned char mc_non_volatile_ram[50 * 4]; /* unused */
183 } mc_clock_ram_t;
184
185 #define MC_CLOCK_PADDED 1
186
187 #endif /*DECSTATION*/
188
189
190 #ifdef FLAMINGO
191 #define MC_DEFAULT_ADDRESS 0L
192
193 /* padded, later */
194
195 #endif /* FLAMINGO */
196
197
198
199 #ifndef MC_CLOCK_PADDED
200 typedef mc_clock_t mc_clock_ram_t; /* No padding needed */
201 #endif
202
203 /*
204 * Functions provided herein
205 */
206 int mc_probe( vm_offset_t addr, struct bus_ctlr * );
207 private void mc_attach();
208
209 int mc_intr();
210
211 void mc_open(), mc_close(), mc_write();
212 private unsigned int mc_read();
213
214 private void mc_wait_for_uip( mc_clock_ram_t *clock );
215
216
217 /*
218 * Status
219 */
220 boolean_t mc_running = FALSE;
221 boolean_t mc_new_century = FALSE; /* "year" info overfloweth */
222
223 private int days_per_month[12] = {
224 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
225 };
226
227 private unsigned int mc_read(); /* forward */
228 private void mc_wait_for_uip();
229
230 /*
231 * Where is the chip's RAM mapped
232 */
233 private mc_clock_ram_t *rt_clock = MC_DEFAULT_ADDRESS;
234
235 /*
236 * (Auto?)Configuration
237 */
238 private vm_offset_t mc_std[NMC] = { 0 };
239 private struct bus_device *mc_info[NMC];
240
241 struct bus_driver mc_driver =
242 { mc_probe, 0, mc_attach, 0, mc_std, "mc", mc_info, };
243
244
245 mc_probe(vm_offset_t addr, struct bus_ctlr *ui)
246 {
247 rt_clock = (mc_clock_ram_t *)addr;
248 return 1;
249 }
250
251 private void
252 mc_attach()
253 {
254 printf(": MC146818 or like Time-Of-Year chip");
255 }
256
257 /*
258 * Interrupt routine
259 */
260 #if MC_DOES_DELAYS
261
262 private int config_step = 3;
263 private volatile int had_intr;
264
265 mc_intr(spllevel)
266 spl_t spllevel;
267 {
268 /*
269 * Interrupt flags are read-to-clear.
270 */
271 if (config_step > 2)
272 return (rt_clock->mc_register_C & MC_REG_C_IRQF);
273 had_intr = (rt_clock->mc_register_C & MC_REG_C_IRQF) ? 1 : 0;
274 if (config_step++ == 0)
275 accurate_config_delay(spllevel);
276 return had_intr;
277 }
278 #else /* MC_DOES_DELAYS */
279
280 mc_intr()
281 {
282 return (rt_clock->mc_register_C); /* clear intr */
283 }
284
285 #endif /* MC_DOES_DELAYS */
286
287 /*
288 * Start real-time clock.
289 */
290 void
291 mc_open()
292 {
293 /*
294 * All we should need to do is to enable interrupts, but
295 * since we do not know what OS last ran on this box
296 * we'll reset it all over again. Just kidding..
297 */
298 unsigned unix_seconds_now;
299
300 /*
301 * Check for battery backup power. If we do not have it,
302 * warn the user. Time will be bogus only after power up.
303 */
304 if ((rt_clock->mc_register_D & MC_REG_D_VRT) == 0)
305 printf("WARNING: clock batteries are low\n");
306
307 /*
308 * Read the current time settings, check if the year info
309 * has been screwed up.
310 */
311 unix_seconds_now = mc_read();
312
313 if (unix_seconds_now < (SECYR * (1990 - YRREF)))
314 printf("The prom has clobbered the clock\n");
315
316 time.tv_sec = (long)unix_seconds_now;
317 mc_write();
318
319 mc_running = TRUE;
320 }
321
322 void
323 mc_close()
324 {
325 /*
326 * Disable interrupts, but keep the chip running.
327 * Note we are called at splhigh and an interrupt
328 * might be pending already.
329 */
330
331 mc_intr(0);
332 rt_clock->mc_register_B &= ~(MC_REG_B_UIE|MC_REG_B_AIE|MC_REG_B_PIE);
333 mc_running = FALSE;
334 #if MC_DOES_DELAYS
335 config_step = 0;
336 #endif
337 }
338
339
340 /*
341 * Set time-of-day. Must be called at splhigh()
342 */
343 void
344 mc_write()
345 {
346 register mc_clock_ram_t *clock = rt_clock;
347 register unsigned years, months, days, hours, minutes, seconds;
348 register unsigned unix_seconds = time.tv_sec;
349 int frequence_selector, temp;
350 int bogus_hz = 0;
351
352 /*
353 * Convert U*x time into absolute time
354 */
355
356 years = YRREF;
357 while (1) {
358 seconds = SECYR;
359 if (LEAPYEAR(years))
360 seconds += SECDAY;
361 if (unix_seconds < seconds)
362 break;
363 unix_seconds -= seconds;
364 years++;
365 }
366
367 months = 0;
368 while (1) {
369 seconds = days_per_month[months++] * SECDAY;
370 if (months == 2 /* February */ && LEAPYEAR(years))
371 seconds += SECDAY;
372 if (unix_seconds < seconds)
373 break;
374 unix_seconds -= seconds;
375 }
376
377 days = unix_seconds / SECDAY;
378 unix_seconds -= SECDAY * days++;
379
380 hours = unix_seconds / SECHOUR;
381 unix_seconds -= SECHOUR * hours;
382
383 minutes = unix_seconds / SECMIN;
384 unix_seconds -= SECMIN * minutes;
385
386 seconds = unix_seconds;
387
388 /*
389 * Trim years into 0-99 range.
390 */
391 if ((years -= 1900) > 99) {
392 years -= 100;
393 mc_new_century = TRUE;
394 }
395
396 /*
397 * Check for "hot dates"
398 */
399 if (days >= 28 && days <= 30 &&
400 hours == 23 && minutes == 59 &&
401 seconds >= 58)
402 seconds = 57;
403
404 /*
405 * Select the interrupt frequency based on system params
406 */
407 switch (hz) {
408 case 1024:
409 frequence_selector = MC_BASE_32_KHz | MC_RATE_1024_Hz;
410 break;
411 case 512:
412 frequence_selector = MC_BASE_32_KHz | MC_RATE_512_Hz;
413 break;
414 case 256:
415 frequence_selector = MC_BASE_32_KHz | MC_RATE_256_Hz;
416 break;
417 case 128:
418 frequence_selector = MC_BASE_32_KHz | MC_RATE_128_Hz;
419 break;
420 case 64:
421 default_frequence:
422 frequence_selector = MC_BASE_32_KHz | MC_RATE_64_Hz;
423 break;
424 default:
425 bogus_hz = hz;
426 hz = 64;
427 tick = 1000000 / 64;
428 goto default_frequence;
429 }
430
431 /*
432 * Stop updates while we fix it
433 */
434 mc_wait_for_uip(clock);
435 clock->mc_register_B = MC_REG_B_STOP;
436 wbflush();
437
438 /*
439 * Ack any pending interrupts
440 */
441 temp = clock->mc_register_C;
442
443 /*
444 * Reset the frequency divider, in case we are changing it.
445 */
446 clock->mc_register_A = MC_BASE_RESET;
447
448 /*
449 * Now update the time
450 */
451 clock->mc_second = seconds;
452 clock->mc_minute = minutes;
453 clock->mc_hour = hours;
454 clock->mc_day_of_month = days;
455 clock->mc_month = months;
456 clock->mc_year = years;
457
458 /*
459 * Spec says the VRT bit can be validated, but does not say how. I
460 * assume it is via reading the register.
461 */
462 temp = clock->mc_register_D;
463
464 /*
465 * Reconfigure the chip and get it started again
466 */
467 clock->mc_register_A = frequence_selector;
468 clock->mc_register_B = MC_REG_B_24HM | MC_REG_B_DM | MC_REG_B_PIE;
469
470 /*
471 * Print warnings, if we have to
472 */
473 if (bogus_hz != 0)
474 printf("Unacceptable value (%d Hz) for hz, reset to %d Hz\n",
475 bogus_hz, hz);
476 }
477
478
479 /*
480 * Internal functions
481 */
482
483 private void
484 mc_wait_for_uip(clock)
485 mc_clock_ram_t *clock;
486 {
487 while (clock->mc_register_A & MC_REG_A_UIP)
488 delay(MC_UPD_MINIMUM >> 2);
489 }
490
491 private unsigned int
492 mc_read()
493 {
494 /*
495 * Note we only do this at boot time
496 */
497 register unsigned years, months, days, hours, minutes, seconds;
498 register mc_clock_ram_t *clock = rt_clock;;
499
500 /*
501 * If the chip is updating, wait
502 */
503 mc_wait_for_uip(clock);
504
505 years = clock->mc_year;
506 months = clock->mc_month;
507 days = clock->mc_day_of_month;
508 hours = clock->mc_hour;
509 minutes = clock->mc_minute;
510 seconds = clock->mc_second;
511
512 /*
513 * Convert to Unix time
514 */
515 seconds += minutes * SECMIN;
516 seconds += hours * SECHOUR;
517 seconds += (days - 1) * SECDAY;
518 if (months > 2 /* February */ && LEAPYEAR(years))
519 seconds += SECDAY;
520 while (months > 1)
521 seconds += days_per_month[--months - 1];
522
523 /*
524 * Note that in ten years from today (Aug,1990) the new century will
525 * cause the trouble that mc_new_century attempts to avoid.
526 */
527 if (mc_new_century)
528 years += 100;
529 years += 1900; /* chip base year in YRREF's century */
530
531 for (--years; years >= YRREF; years--) {
532 seconds += SECYR;
533 if (LEAPYEAR(years))
534 seconds += SECDAY;
535 }
536
537 return seconds;
538 }
539
540 #ifdef MC_DOES_DELAYS
541
542 /*
543 * Timed delays
544 */
545 extern unsigned int cpu_speed;
546
547 void
548 config_delay(speed)
549 {
550 /*
551 * This is just an initial estimate, later on with the clock
552 * running we'll tune it more accurately.
553 */
554 cpu_speed = speed;
555 }
556
557 accurate_config_delay(spllevel)
558 spl_t spllevel;
559 {
560 register unsigned int i;
561 register spl_t s;
562 int inner_loop_count;
563
564 #ifdef mips
565 /* find "spllevel - 1" */
566 s = spllevel | ((spllevel >> 1) & SR_INT_MASK);
567 splx(s);
568 #else
569 #endif
570
571 /* wait till we have an interrupt pending */
572 had_intr = 0;
573 while (!had_intr)
574 continue;
575
576 had_intr = 0;
577 i = delay_timing_function(1, &had_intr, &inner_loop_count);
578
579 splx(spllevel);
580
581 i *= hz;
582 cpu_speed = i / (inner_loop_count * 1000000);
583
584 /* roundup clock speed */
585 i /= 100000;
586 if ((i % 10) >= 5)
587 i += 5;
588 printf("Estimating CPU clock at %d Mhz\n", i / 10);
589 if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) {
590 printf("%s\n", "This machine looks like a DEC 2100");
591 machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000;
592 }
593 }
594 #endif /* MC_DOES_DELAYS */
595
596 #endif NMC > 0
Cache object: c5c4b5cb05030461e747582b79ab13b6
|