1169695Skan/* $NetBSD: au_timer.c,v 1.10 2011/02/20 07:48:36 matt Exp $ */
2169695Skan
3169695Skan/*
4169695Skan * Copyright 2002 Wasabi Systems, Inc.
5169695Skan * All rights reserved.
6169695Skan *
7169695Skan * Written by Simon Burge for Wasabi Systems, Inc.
8169695Skan *
9169695Skan * Redistribution and use in source and binary forms, with or without
10169695Skan * modification, are permitted provided that the following conditions
11169695Skan * are met:
12169695Skan * 1. Redistributions of source code must retain the above copyright
13169695Skan *    notice, this list of conditions and the following disclaimer.
14169695Skan * 2. Redistributions in binary form must reproduce the above copyright
15169695Skan *    notice, this list of conditions and the following disclaimer in the
16169695Skan *    documentation and/or other materials provided with the distribution.
17169695Skan * 3. All advertising materials mentioning features or use of this software
18169695Skan *    must display the following acknowledgement:
19169695Skan *      This product includes software developed for the NetBSD Project by
20169695Skan *      Wasabi Systems, Inc.
21169695Skan * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22169695Skan *    or promote products derived from this software without specific prior
23169695Skan *    written permission.
24169695Skan *
25169695Skan * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26169695Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27169695Skan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28169695Skan * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29169695Skan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30169695Skan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31169695Skan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32169695Skan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33169695Skan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34169695Skan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35169695Skan * POSSIBILITY OF SUCH DAMAGE.
36169695Skan */
37169695Skan
38169695Skan#include <sys/cdefs.h>
39169695Skan__KERNEL_RCSID(0, "$NetBSD: au_timer.c,v 1.10 2011/02/20 07:48:36 matt Exp $");
40169695Skan
41169695Skan#include <sys/param.h>
42169695Skan#include <sys/kernel.h>
43169695Skan#include <sys/lwp.h>
44169695Skan#include <sys/systm.h>
45169695Skan
46169695Skan#include <sys/bus.h>
47169695Skan#include <mips/locore.h>
48169695Skan
49169695Skan#include <mips/alchemy/include/aureg.h>
50169695Skan#include <mips/alchemy/include/auvar.h>
51169695Skan
52169695Skan/*
53169695Skan * Set a programmable clock register.
54169695Skan * If "wait" is non-zero, wait for that bit to become 0 in the
55169695Skan * counter control register before and after writing to the
56169695Skan * specified clock register.
57169695Skan */
58169695Skan#define	SET_PC_REG(reg, wait, val)					\
59169695Skando {									\
60169695Skan	if (wait)							\
61169695Skan		while (bus_space_read_4(st, sh, PC_COUNTER_CONTROL)	\
62169695Skan		    & (wait))						\
63169695Skan			/* nothing */;					\
64169695Skan	bus_space_write_4(st, sh, (reg), (val));			\
65169695Skan	if (wait)							\
66169695Skan		while (bus_space_read_4(st, sh, (reg)) & (wait))	\
67169695Skan			/* nothing */;					\
68169695Skan} while (0)
69169695Skan
70169695Skanvoid
71169695Skanau_cal_timers(bus_space_tag_t st, bus_space_handle_t sh)
72169695Skan{
73169695Skan	struct cpu_info * const ci = curcpu();
74169695Skan	uint32_t ctrdiff[4], startctr, endctr;
75169695Skan	uint32_t ctl, ctr, octr;
76169695Skan	int i;
77169695Skan
78169695Skan	/* Enable the programmable counter 1. */
79169695Skan	ctl = bus_space_read_4(st, sh, PC_COUNTER_CONTROL);
80169695Skan	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1))
81169695Skan		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl | CC_EO | CC_EN1);
82169695Skan
83169695Skan	/* Initialize for 16Hz. */
84169695Skan	SET_PC_REG(PC_TRIM1, CC_T1S, PC_RATE / 16 - 1);
85169695Skan
86169695Skan	/* Run the loop an extra time to prime the cache. */
87169695Skan	for (i = 0; i < 4; i++) {
88169695Skan		/* Reset the counter. */
89169695Skan		SET_PC_REG(PC_COUNTER_WRITE1, CC_C1S, 0);
90169695Skan
91169695Skan		/* Wait for 1/16th of a second. */
92169695Skan		//startctr = mips3_cp0_count_read();
93169695Skan
94169695Skan		/* Wait for the PC to tick over. */
95169695Skan		ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
96169695Skan		do {
97169695Skan			octr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
98169695Skan		} while (ctr == octr);
99169695Skan
100169695Skan		startctr = mips3_cp0_count_read();
101169695Skan		do {
102169695Skan			ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
103169695Skan		} while (ctr == octr);	// while (ctr <= octr + 1);
104169695Skan		endctr = mips3_cp0_count_read();
105169695Skan		ctrdiff[i] = endctr - startctr;
106169695Skan	}
107169695Skan
108169695Skan	/* Disable the counter (if it wasn't enabled already). */
109169695Skan	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1))
110169695Skan		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl);
111169695Skan
112169695Skan	/* Compute the number of cycles per second. */
113169695Skan	ci->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
114169695Skan	ci->ci_cctr_freq = ci->ci_cpu_freq;
115169695Skan
116169695Skan	/* Compute the number of ticks for hz. */
117169695Skan	ci->ci_cycles_per_hz = (ci->ci_cpu_freq + hz / 2) / hz;
118169695Skan
119169695Skan	/* Compute the delay divisor. */
120169695Skan	ci->ci_divisor_delay = (ci->ci_cpu_freq + 500000) / 1000000;
121169695Skan
122169695Skan	/*
123169695Skan	 * Get correct cpu frequency if the CPU runs at twice the
124169695Skan	 * external/cp0-count frequency.
125169695Skan	 */
126169695Skan	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
127169695Skan		ci->ci_cpu_freq *= 2;
128169695Skan
129169695Skan#ifdef DEBUG
130169695Skan	printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n",
131169695Skan	    ci->ci_cpu_freq, ctrdiff[2], ctrdiff[3]);
132169695Skan#endif
133169695Skan}
134169695Skan