NetBSD-5.0.2/sys/arch/alpha/alpha/mcclock.c

Compare this file to the similar file:
Show the results in this format:

/* $NetBSD: mcclock.c,v 1.14 2008/02/03 07:31:21 tsutsui Exp $ */

/*
 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */

__KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.14 2008/02/03 07:31:21 tsutsui Exp $");

#include "opt_clock_compat_osf1.h"

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <machine/bus.h>
#include <machine/cpu_counter.h>

#include <dev/clock_subr.h>

#include <dev/ic/mc146818reg.h>
#include <dev/ic/mc146818var.h>

#include <alpha/alpha/mcclockvar.h>
#include <alpha/alpha/clockvar.h>

#ifdef CLOCK_COMPAT_OSF1
/*
 * According to OSF/1's /usr/sys/include/arch/alpha/clock.h,
 * the console adjusts the RTC years 13..19 to 93..99 and
 * 20..40 to 00..20. (historical reasons?)
 * DEC Unix uses an offset to the year to stay outside
 * the dangerous area for the next couple of years.
 */
#define UNIX_YEAR_OFFSET 52 /* 41=>1993, 12=>2064 */
#else
#define UNIX_YEAR_OFFSET 0
#endif


static void mcclock_set_pcc_freq(struct mc146818_softc *);
static void mcclock_init(void *);

void
mcclock_attach(struct mc146818_softc *sc)
{

	sc->sc_year0 = 1900 + UNIX_YEAR_OFFSET;
	sc->sc_flag = 0;	/* BINARY, 24HR */

	mc146818_attach(sc);

	aprint_normal("\n");

	/* Turn interrupts off, just in case. */
	(*sc->sc_mcwrite)(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR);

	mcclock_set_pcc_freq(sc);

	clockattach(mcclock_init, (void *)sc);
}

#define NLOOP	4

static void
mcclock_set_pcc_freq(struct mc146818_softc *sc)
{
	struct cpu_info *ci;
	uint64_t freq;
	uint32_t ctrdiff[NLOOP], pcc_start, pcc_end;
	uint8_t reg_a;
	int i;

	/* save REG_A */
	reg_a = (*sc->sc_mcread)(sc, MC_REGA);

	/* set interval 16Hz to measure pcc */
	(*sc->sc_mcwrite)(sc, MC_REGA, MC_BASE_32_KHz | MC_RATE_16_Hz);

	/* Run the loop an extra time to prime the cache. */
	for (i = 0; i < NLOOP; i++) {
		/* clear interrupt flags */
		(void)(*sc->sc_mcread)(sc, MC_REGC);

		/* wait till the periodic interupt flag is set */
		while (((*sc->sc_mcread)(sc, MC_REGC) & MC_REGC_PF) == 0)
			;
		pcc_start = cpu_counter32();

		/* wait till the periodic interupt flag is set again */
		while (((*sc->sc_mcread)(sc, MC_REGC) & MC_REGC_PF) == 0)
			;
		pcc_end = cpu_counter32();

		ctrdiff[i] = pcc_end - pcc_start;
	}

	freq = ((ctrdiff[NLOOP - 2] + ctrdiff[NLOOP - 1]) / 2) * 16 /* Hz */;

	/* restore REG_A */
	(*sc->sc_mcwrite)(sc, MC_REGA, reg_a);

	/* XXX assume all processors have the same clock and frequency */
	for (ci = &cpu_info_primary; ci; ci = ci->ci_next)
		ci->ci_pcc_freq = freq;
}

static void
mcclock_init(void *dev)
{
	struct mc146818_softc *sc = dev;

	/* enable interval clock interrupt */
	(*sc->sc_mcwrite)(sc, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
	(*sc->sc_mcwrite)(sc, MC_REGB,
	    MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR);
}