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