1/* $NetBSD: mcclock.c,v 1.17 2011/07/01 19:22:35 dyoung Exp $ */
2
3/*
4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22 *  School of Computer Science
23 *  Carnegie Mellon University
24 *  Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
31
32__KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.17 2011/07/01 19:22:35 dyoung Exp $");
33
34#include "opt_clock_compat_osf1.h"
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/device.h>
40
41#include <sys/bus.h>
42#include <machine/cpu_counter.h>
43
44#include <dev/clock_subr.h>
45
46#include <dev/ic/mc146818reg.h>
47#include <dev/ic/mc146818var.h>
48
49#include <alpha/alpha/mcclockvar.h>
50#include <alpha/alpha/clockvar.h>
51
52#ifdef CLOCK_COMPAT_OSF1
53/*
54 * According to OSF/1's /usr/sys/include/arch/alpha/clock.h,
55 * the console adjusts the RTC years 13..19 to 93..99 and
56 * 20..40 to 00..20. (historical reasons?)
57 * DEC Unix uses an offset to the year to stay outside
58 * the dangerous area for the next couple of years.
59 */
60#define UNIX_YEAR_OFFSET 52 /* 41=>1993, 12=>2064 */
61#else
62#define UNIX_YEAR_OFFSET 0
63#endif
64
65
66static void mcclock_set_pcc_freq(struct mc146818_softc *);
67static void mcclock_init(void *);
68
69void
70mcclock_attach(struct mc146818_softc *sc)
71{
72
73	sc->sc_year0 = 1900 + UNIX_YEAR_OFFSET;
74	sc->sc_flag = 0;	/* BINARY, 24HR */
75
76	mc146818_attach(sc);
77
78	aprint_normal("\n");
79
80	/* Turn interrupts off, just in case. */
81	(*sc->sc_mcwrite)(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR);
82
83	mcclock_set_pcc_freq(sc);
84
85	clockattach(mcclock_init, (void *)sc);
86}
87
88#define NLOOP	4
89
90static void
91mcclock_set_pcc_freq(struct mc146818_softc *sc)
92{
93	struct cpu_info *ci;
94	uint64_t freq;
95	uint32_t ctrdiff[NLOOP], pcc_start, pcc_end;
96	uint8_t reg_a;
97	int i;
98
99	/* save REG_A */
100	reg_a = (*sc->sc_mcread)(sc, MC_REGA);
101
102	/* set interval 16Hz to measure pcc */
103	(*sc->sc_mcwrite)(sc, MC_REGA, MC_BASE_32_KHz | MC_RATE_16_Hz);
104
105	/* clear interrupt flags */
106	(void)(*sc->sc_mcread)(sc, MC_REGC);
107
108	/* Run the loop an extra time to prime the cache. */
109	for (i = 0; i < NLOOP; i++) {
110
111		/* wait till the periodic interrupt flag is set */
112		while (((*sc->sc_mcread)(sc, MC_REGC) & MC_REGC_PF) == 0)
113			;
114		pcc_start = cpu_counter32();
115
116		/* wait till the periodic interrupt flag is set again */
117		while (((*sc->sc_mcread)(sc, MC_REGC) & MC_REGC_PF) == 0)
118			;
119		pcc_end = cpu_counter32();
120
121		ctrdiff[i] = pcc_end - pcc_start;
122	}
123
124	freq = ((ctrdiff[NLOOP - 2] + ctrdiff[NLOOP - 1]) * 16 /* Hz */) / 2;
125
126	/* restore REG_A */
127	(*sc->sc_mcwrite)(sc, MC_REGA, reg_a);
128
129	/* XXX assume all processors have the same clock and frequency */
130	for (ci = &cpu_info_primary; ci; ci = ci->ci_next)
131		ci->ci_pcc_freq = freq;
132}
133
134static void
135mcclock_init(void *dev)
136{
137	struct mc146818_softc *sc = dev;
138
139	/* enable interval clock interrupt */
140	(*sc->sc_mcwrite)(sc, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
141	(*sc->sc_mcwrite)(sc, MC_REGB,
142	    MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR);
143}
144