xref: /openbsd/sys/arch/sparc64/sparc64/clock.c (revision e1f14dc3)
1*e1f14dc3Smiod /*	$OpenBSD: clock.c,v 1.87 2024/04/08 20:05:51 miod Exp $	*/
2284584b0Sjason /*	$NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
3284584b0Sjason 
4284584b0Sjason /*
5284584b0Sjason  * Copyright (c) 1992, 1993
6284584b0Sjason  *	The Regents of the University of California.  All rights reserved.
7284584b0Sjason  * Copyright (c) 1994 Gordon W. Ross
8284584b0Sjason  * Copyright (c) 1993 Adam Glass
9284584b0Sjason  * Copyright (c) 1996 Paul Kranenburg
10284584b0Sjason  * Copyright (c) 1996
11284584b0Sjason  * 	The President and Fellows of Harvard College. All rights reserved.
12284584b0Sjason  *
13284584b0Sjason  * This software was developed by the Computer Systems Engineering group
14284584b0Sjason  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
15284584b0Sjason  * contributed to Berkeley.
16284584b0Sjason  *
17284584b0Sjason  * All advertising materials mentioning features or use of this software
18284584b0Sjason  * must display the following acknowledgement:
19284584b0Sjason  *	This product includes software developed by Harvard University.
20284584b0Sjason  *	This product includes software developed by the University of
21284584b0Sjason  *	California, Lawrence Berkeley Laboratory.
22284584b0Sjason  *
23284584b0Sjason  * Redistribution and use in source and binary forms, with or without
24284584b0Sjason  * modification, are permitted provided that the following conditions
25284584b0Sjason  * are met:
26284584b0Sjason  *
27284584b0Sjason  * 1. Redistributions of source code must retain the above copyright
28284584b0Sjason  *    notice, this list of conditions and the following disclaimer.
29284584b0Sjason  * 2. Redistributions in binary form must reproduce the above copyright
30284584b0Sjason  *    notice, this list of conditions and the following disclaimer in the
31284584b0Sjason  *    documentation and/or other materials provided with the distribution.
32284584b0Sjason  * 3. All advertising materials mentioning features or use of this software
33284584b0Sjason  *    must display the following acknowledgement:
34284584b0Sjason  *	This product includes software developed by the University of
35284584b0Sjason  *	California, Berkeley and its contributors.
36284584b0Sjason  *	This product includes software developed by Paul Kranenburg.
37284584b0Sjason  *	This product includes software developed by Harvard University.
38284584b0Sjason  * 4. Neither the name of the University nor the names of its contributors
39284584b0Sjason  *    may be used to endorse or promote products derived from this software
40284584b0Sjason  *    without specific prior written permission.
41284584b0Sjason  *
42284584b0Sjason  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43284584b0Sjason  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44284584b0Sjason  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45284584b0Sjason  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46284584b0Sjason  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47284584b0Sjason  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48284584b0Sjason  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49284584b0Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50284584b0Sjason  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51284584b0Sjason  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52284584b0Sjason  * SUCH DAMAGE.
53284584b0Sjason  *
54284584b0Sjason  *	@(#)clock.c	8.1 (Berkeley) 6/11/93
55284584b0Sjason  *
56284584b0Sjason  */
57284584b0Sjason 
58284584b0Sjason /*
59284584b0Sjason  * Clock driver.  This is the id prom and eeprom driver as well
60284584b0Sjason  * and includes the timer register functions too.
61284584b0Sjason  */
62284584b0Sjason 
63284584b0Sjason /* Define this for a 1/4s clock to ease debugging */
64284584b0Sjason /* #define INTR_DEBUG */
65284584b0Sjason 
66284584b0Sjason #include <sys/param.h>
67284584b0Sjason #include <sys/kernel.h>
68284584b0Sjason #include <sys/device.h>
69284584b0Sjason #include <sys/malloc.h>
70284584b0Sjason #include <sys/systm.h>
71573d576bScheloha #include <sys/clockintr.h>
72284584b0Sjason #include <sys/sched.h>
73573d576bScheloha #include <sys/stdint.h>
7405a26ea5Sart #include <sys/timetc.h>
75900b001bStedu #include <sys/atomic.h>
76284584b0Sjason 
77284584b0Sjason #include <machine/bus.h>
78284584b0Sjason #include <machine/autoconf.h>
79284584b0Sjason #include <machine/cpu.h>
80284584b0Sjason #include <machine/idprom.h>
81284584b0Sjason 
82284584b0Sjason #include <dev/clock_subr.h>
83284584b0Sjason #include <dev/ic/mk48txxreg.h>
84284584b0Sjason 
85284584b0Sjason #include <sparc64/dev/iommureg.h>
86284584b0Sjason #include <sparc64/dev/sbusreg.h>
87284584b0Sjason #include <dev/sbus/sbusvar.h>
88284584b0Sjason #include <sparc64/dev/ebusreg.h>
89284584b0Sjason #include <sparc64/dev/ebusvar.h>
901d2e6c84Sjason #include <sparc64/dev/fhcvar.h>
91284584b0Sjason 
92284584b0Sjason extern u_int64_t cpu_clockrate;
93284584b0Sjason 
94eb79e960Shenric struct clock_wenable_info {
95eb79e960Shenric 	bus_space_tag_t		cwi_bt;
96eb79e960Shenric 	bus_space_handle_t	cwi_bh;
97eb79e960Shenric 	bus_size_t		cwi_size;
98eb79e960Shenric };
99eb79e960Shenric 
100284584b0Sjason struct cfdriver clock_cd = {
101284584b0Sjason 	NULL, "clock", DV_DULL
102284584b0Sjason };
103284584b0Sjason 
10405a26ea5Sart u_int tick_get_timecount(struct timecounter *);
10505a26ea5Sart 
10605a26ea5Sart struct timecounter tick_timecounter = {
1078611d3cdScheloha 	.tc_get_timecount = tick_get_timecount,
1088611d3cdScheloha 	.tc_counter_mask = ~0u,
1098611d3cdScheloha 	.tc_frequency = 0,
1108611d3cdScheloha 	.tc_name = "tick",
1118611d3cdScheloha 	.tc_quality = 0,
1128611d3cdScheloha 	.tc_priv = NULL,
1138611d3cdScheloha 	.tc_user = TC_TICK,
11405a26ea5Sart };
11505a26ea5Sart 
1168a2bbcc7Skettenis u_int sys_tick_get_timecount(struct timecounter *);
1178a2bbcc7Skettenis 
1188a2bbcc7Skettenis struct timecounter sys_tick_timecounter = {
1198611d3cdScheloha 	.tc_get_timecount = sys_tick_get_timecount,
1208611d3cdScheloha 	.tc_counter_mask = ~0u,
1218611d3cdScheloha 	.tc_frequency = 0,
1228611d3cdScheloha 	.tc_name = "sys_tick",
1238611d3cdScheloha 	.tc_quality = 1000,
1248611d3cdScheloha 	.tc_priv = NULL,
1258611d3cdScheloha 	.tc_user = TC_SYS_TICK,
1268a2bbcc7Skettenis };
1278a2bbcc7Skettenis 
128386fc5f4Skettenis void	tick_start(void);
129386fc5f4Skettenis void	sys_tick_start(void);
130386fc5f4Skettenis void	stick_start(void);
131386fc5f4Skettenis 
132386fc5f4Skettenis int	tickintr(void *);
133386fc5f4Skettenis int	sys_tickintr(void *);
134386fc5f4Skettenis int	stickintr(void *);
135284584b0Sjason 
136573d576bScheloha /* %TICK is at most a 63-bit counter. */
137573d576bScheloha #define TICK_COUNT_MASK 0x7fffffffffffffff
138573d576bScheloha 
139573d576bScheloha uint64_t tick_nsec_cycle_ratio;
140573d576bScheloha uint64_t tick_nsec_max;
141573d576bScheloha 
142573d576bScheloha void tick_rearm(void *, uint64_t);
143573d576bScheloha void tick_trigger(void *);
144573d576bScheloha 
145573d576bScheloha const struct intrclock tick_intrclock = {
146573d576bScheloha 	.ic_rearm = tick_rearm,
147573d576bScheloha 	.ic_trigger = tick_trigger
148573d576bScheloha };
149573d576bScheloha 
150573d576bScheloha /* %STICK is at most a 63-bit counter. */
151573d576bScheloha #define STICK_COUNT_MASK 0x7fffffffffffffff
152573d576bScheloha 
153573d576bScheloha uint64_t sys_tick_nsec_cycle_ratio;
154573d576bScheloha uint64_t sys_tick_nsec_max;
155573d576bScheloha 
156573d576bScheloha void sys_tick_rearm(void *, uint64_t);
157573d576bScheloha void sys_tick_trigger(void *);
158573d576bScheloha 
159573d576bScheloha const struct intrclock sys_tick_intrclock = {
160573d576bScheloha 	.ic_rearm = sys_tick_rearm,
161573d576bScheloha 	.ic_trigger = sys_tick_trigger
162573d576bScheloha };
163573d576bScheloha 
164573d576bScheloha void stick_rearm(void *, uint64_t);
165573d576bScheloha void stick_trigger(void *);
166573d576bScheloha 
167573d576bScheloha const struct intrclock stick_intrclock = {
168573d576bScheloha 	.ic_rearm = stick_rearm,
169573d576bScheloha 	.ic_trigger = stick_trigger
170573d576bScheloha };
171573d576bScheloha 
172573d576bScheloha void sparc64_raise_clockintr(void);
173573d576bScheloha 
1748a1e8ccaSmiod static struct intrhand level10 = {
1758a1e8ccaSmiod 	.ih_fun = tickintr,
1768a1e8ccaSmiod 	.ih_number = 1,
1778a1e8ccaSmiod 	.ih_pil = 10,
1788a1e8ccaSmiod 	.ih_name = "clock"
1798a1e8ccaSmiod };
180284584b0Sjason 
181284584b0Sjason /*
182284584b0Sjason  * clock (eeprom) attaches at the sbus or the ebus (PCI)
183284584b0Sjason  */
184c4071fd1Smillert static int	clockmatch_sbus(struct device *, void *, void *);
185c4071fd1Smillert static void	clockattach_sbus(struct device *, struct device *, void *);
186c4071fd1Smillert static int	clockmatch_ebus(struct device *, void *, void *);
187c4071fd1Smillert static void	clockattach_ebus(struct device *, struct device *, void *);
1881d2e6c84Sjason static int	clockmatch_fhc(struct device *, void *, void *);
1891d2e6c84Sjason static void	clockattach_fhc(struct device *, struct device *, void *);
190c4071fd1Smillert static void	clockattach(int, bus_space_tag_t, bus_space_handle_t);
191284584b0Sjason 
192eb7eaf8dSmpi const struct cfattach clock_sbus_ca = {
193284584b0Sjason 	sizeof(struct device), clockmatch_sbus, clockattach_sbus
194284584b0Sjason };
195284584b0Sjason 
196eb7eaf8dSmpi const struct cfattach clock_ebus_ca = {
197284584b0Sjason 	sizeof(struct device), clockmatch_ebus, clockattach_ebus
198284584b0Sjason };
199284584b0Sjason 
200eb7eaf8dSmpi const struct cfattach clock_fhc_ca = {
2011d2e6c84Sjason 	sizeof(struct device), clockmatch_fhc, clockattach_fhc
2021d2e6c84Sjason };
2031d2e6c84Sjason 
204284584b0Sjason /* Global TOD clock handle & idprom pointer */
205780e31aaSvisa extern todr_chip_handle_t todr_handle;
206284584b0Sjason static struct idprom *idprom;
207284584b0Sjason 
208eb79e960Shenric int clock_bus_wenable(struct todr_chip_handle *, int);
209c4071fd1Smillert void myetheraddr(u_char *);
210eba3994dSjason struct idprom *getidprom(void);
211284584b0Sjason 
212284584b0Sjason /*
213284584b0Sjason  * The OPENPROM calls the clock the "eeprom", so we have to have our
214284584b0Sjason  * own special match function to call it the "clock".
215284584b0Sjason  */
216284584b0Sjason static int
clockmatch_sbus(struct device * parent,void * cf,void * aux)2179ac6db98Scheloha clockmatch_sbus(struct device *parent, void *cf, void *aux)
218284584b0Sjason {
219284584b0Sjason 	struct sbus_attach_args *sa = aux;
220284584b0Sjason 
221284584b0Sjason 	return (strcmp("eeprom", sa->sa_name) == 0);
222284584b0Sjason }
223284584b0Sjason 
224284584b0Sjason static int
clockmatch_ebus(struct device * parent,void * cf,void * aux)2259ac6db98Scheloha clockmatch_ebus(struct device *parent, void *cf, void *aux)
226284584b0Sjason {
227284584b0Sjason 	struct ebus_attach_args *ea = aux;
228284584b0Sjason 
229284584b0Sjason 	return (strcmp("eeprom", ea->ea_name) == 0);
230284584b0Sjason }
231284584b0Sjason 
232284584b0Sjason static int
clockmatch_fhc(struct device * parent,void * cf,void * aux)2339ac6db98Scheloha clockmatch_fhc(struct device *parent, void *cf, void *aux)
2341d2e6c84Sjason {
2351d2e6c84Sjason 	struct fhc_attach_args *fa = aux;
2361d2e6c84Sjason 
2371d2e6c84Sjason 	return (strcmp("eeprom", fa->fa_name) == 0);
2381d2e6c84Sjason }
2391d2e6c84Sjason 
240284584b0Sjason /*
241284584b0Sjason  * Attach a clock (really `eeprom') to the sbus or ebus.
242284584b0Sjason  *
243284584b0Sjason  * We ignore any existing virtual address as we need to map
244284584b0Sjason  * this read-only and make it read-write only temporarily,
245284584b0Sjason  * whenever we read or write the clock chip.  The clock also
246284584b0Sjason  * contains the ID ``PROM'', and I have already had the pleasure
247284584b0Sjason  * of reloading the cpu type, Ethernet address, etc, by hand from
248284584b0Sjason  * the console FORTH interpreter.  I intend not to enjoy it again.
249284584b0Sjason  *
250284584b0Sjason  * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
251284584b0Sjason  * supposed to be identical to it.
252284584b0Sjason  *
253284584b0Sjason  * This is *UGLY*!  We probably have multiple mappings.  But I do
254284584b0Sjason  * know that this all fits inside an 8K page, so I'll just map in
255284584b0Sjason  * once.
256284584b0Sjason  *
257284584b0Sjason  * What we really need is some way to record the bus attach args
258284584b0Sjason  * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
259284584b0Sjason  * or not to write enable/disable the device registers.  This is
260284584b0Sjason  * a non-trivial operation.
261284584b0Sjason  */
262284584b0Sjason 
263284584b0Sjason static void
clockattach_sbus(struct device * parent,struct device * self,void * aux)2649ac6db98Scheloha clockattach_sbus(struct device *parent, struct device *self, void *aux)
265284584b0Sjason {
266284584b0Sjason 	struct sbus_attach_args *sa = aux;
267284584b0Sjason 	bus_space_tag_t bt = sa->sa_bustag;
268284584b0Sjason 	int sz;
269eb79e960Shenric 	static struct clock_wenable_info cwi;
270284584b0Sjason 
271284584b0Sjason 	/* use sa->sa_regs[0].size? */
272284584b0Sjason 	sz = 8192;
273284584b0Sjason 
274284584b0Sjason 	if (sbus_bus_map(bt,
275284584b0Sjason 			 sa->sa_slot,
276284584b0Sjason 			 (sa->sa_offset & ~NBPG),
277284584b0Sjason 			 sz,
278284584b0Sjason 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
279eb79e960Shenric 			 0, &cwi.cwi_bh) != 0) {
280284584b0Sjason 		printf("%s: can't map register\n", self->dv_xname);
281284584b0Sjason 		return;
282284584b0Sjason 	}
283eb79e960Shenric 	clockattach(sa->sa_node, bt, cwi.cwi_bh);
284284584b0Sjason 
285284584b0Sjason 	/* Save info for the clock wenable call. */
286eb79e960Shenric 	cwi.cwi_bt = bt;
287eb79e960Shenric 	cwi.cwi_size = sz;
288eb79e960Shenric 	todr_handle->bus_cookie = &cwi;
289eb79e960Shenric 	todr_handle->todr_setwen = clock_bus_wenable;
290284584b0Sjason }
291284584b0Sjason 
292284584b0Sjason /*
293284584b0Sjason  * Write en/dis-able clock registers.  We coordinate so that several
294284584b0Sjason  * writers can run simultaneously.
295eb79e960Shenric  * XXX There is still a race here.  The page change and the "writers"
296eb79e960Shenric  * change are not atomic.
297284584b0Sjason  */
298284584b0Sjason int
clock_bus_wenable(struct todr_chip_handle * handle,int onoff)2999ac6db98Scheloha clock_bus_wenable(struct todr_chip_handle *handle, int onoff)
300284584b0Sjason {
301eb79e960Shenric 	int s, err = 0;
302eb79e960Shenric 	int prot; /* nonzero => change prot */
303eb79e960Shenric 	volatile static int writers;
304eb79e960Shenric 	struct clock_wenable_info *cwi = handle->bus_cookie;
305284584b0Sjason 
306284584b0Sjason 	s = splhigh();
307284584b0Sjason 	if (onoff)
308900b001bStedu 		prot = writers++ == 0 ? 1 : 0;
309284584b0Sjason 	else
310900b001bStedu 		prot = --writers == 0 ? 1 : 0;
311284584b0Sjason 	splx(s);
312284584b0Sjason 
313eb79e960Shenric 	if (prot) {
314eb79e960Shenric 		err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size,
315eb79e960Shenric 		    onoff ? 0 : BUS_SPACE_MAP_READONLY);
316eb79e960Shenric 		if (err)
317eb79e960Shenric 			printf("clock_wenable_info: WARNING -- cannot %s "
318eb79e960Shenric 			    "page protection\n", onoff ? "disable" : "enable");
319284584b0Sjason 	}
320284584b0Sjason 	return (err);
321284584b0Sjason }
322284584b0Sjason 
323284584b0Sjason static void
clockattach_ebus(struct device * parent,struct device * self,void * aux)3249ac6db98Scheloha clockattach_ebus(struct device *parent, struct device *self, void *aux)
325284584b0Sjason {
326284584b0Sjason 	struct ebus_attach_args *ea = aux;
327eb79e960Shenric 	bus_space_tag_t bt;
328284584b0Sjason 	int sz;
329eb79e960Shenric 	static struct clock_wenable_info cwi;
330284584b0Sjason 
331284584b0Sjason 	/* hard code to 8K? */
332284584b0Sjason 	sz = ea->ea_regs[0].size;
333284584b0Sjason 
3343342c5b5Smiod 	if (ebus_bus_map(ea->ea_iotag, 0,
335eb79e960Shenric 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) {
336eb79e960Shenric 		bt = ea->ea_iotag;
337eb79e960Shenric 	} else if (ebus_bus_map(ea->ea_memtag, 0,
338eb79e960Shenric 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz,
339eb79e960Shenric 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
340eb79e960Shenric 	    0, &cwi.cwi_bh) == 0) {
341eb79e960Shenric 		bt = ea->ea_memtag;
342eb79e960Shenric 	} else {
343284584b0Sjason 		printf("%s: can't map register\n", self->dv_xname);
344284584b0Sjason 		return;
345284584b0Sjason 	}
346eb79e960Shenric 
347eb79e960Shenric 	clockattach(ea->ea_node, bt, cwi.cwi_bh);
348284584b0Sjason 
349284584b0Sjason 	/* Save info for the clock wenable call. */
350eb79e960Shenric 	cwi.cwi_bt = bt;
351eb79e960Shenric 	cwi.cwi_size = sz;
352eb79e960Shenric 	todr_handle->bus_cookie = &cwi;
353eb79e960Shenric 	todr_handle->todr_setwen = (ea->ea_memtag == bt) ?
354eb79e960Shenric 	    clock_bus_wenable : NULL;
355284584b0Sjason }
356284584b0Sjason 
357284584b0Sjason static void
clockattach_fhc(struct device * parent,struct device * self,void * aux)3589ac6db98Scheloha clockattach_fhc(struct device *parent, struct device *self, void *aux)
3591d2e6c84Sjason {
3601d2e6c84Sjason 	struct fhc_attach_args *fa = aux;
3611d2e6c84Sjason 	bus_space_tag_t bt = fa->fa_bustag;
3621d2e6c84Sjason 	int sz;
3631d2e6c84Sjason 	static struct clock_wenable_info cwi;
3641d2e6c84Sjason 
3651d2e6c84Sjason 	/* use sa->sa_regs[0].size? */
3661d2e6c84Sjason 	sz = 8192;
3671d2e6c84Sjason 
3681d2e6c84Sjason 	if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot,
3691d2e6c84Sjason 	    (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size,
3701d2e6c84Sjason 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) {
3711d2e6c84Sjason 		printf("%s: can't map register\n", self->dv_xname);
3721d2e6c84Sjason 		return;
3731d2e6c84Sjason 	}
3741d2e6c84Sjason 
3751d2e6c84Sjason 	clockattach(fa->fa_node, bt, cwi.cwi_bh);
3761d2e6c84Sjason 
3771d2e6c84Sjason 	/* Save info for the clock wenable call. */
3781d2e6c84Sjason 	cwi.cwi_bt = bt;
3791d2e6c84Sjason 	cwi.cwi_size = sz;
3801d2e6c84Sjason 	todr_handle->bus_cookie = &cwi;
3811d2e6c84Sjason 	todr_handle->todr_setwen = clock_bus_wenable;
3821d2e6c84Sjason }
3831d2e6c84Sjason 
3841d2e6c84Sjason static void
clockattach(int node,bus_space_tag_t bt,bus_space_handle_t bh)3859ac6db98Scheloha clockattach(int node, bus_space_tag_t bt, bus_space_handle_t bh)
386284584b0Sjason {
387284584b0Sjason 	char *model;
388284584b0Sjason 	struct idprom *idp;
389284584b0Sjason 	int h;
390284584b0Sjason 
391284584b0Sjason 	model = getpropstring(node, "model");
392284584b0Sjason 
393284584b0Sjason #ifdef DIAGNOSTIC
394284584b0Sjason 	if (model == NULL)
395284584b0Sjason 		panic("clockattach: no model property");
396284584b0Sjason #endif
397284584b0Sjason 
398284584b0Sjason 	/* Our TOD clock year 0 is 1968 */
399284584b0Sjason 	if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL)
400284584b0Sjason 		panic("Can't attach %s tod clock", model);
401284584b0Sjason 
402284584b0Sjason #define IDPROM_OFFSET (8*1024 - 40)	/* XXX - get nvram sz from driver */
403eba3994dSjason 	if (idprom == NULL) {
404eba3994dSjason 		idp = getidprom();
405eba3994dSjason 		if (idp == NULL)
406eb79e960Shenric 			idp = (struct idprom *)(bus_space_vaddr(bt, bh) +
407eb79e960Shenric 			    IDPROM_OFFSET);
408eba3994dSjason 		idprom = idp;
409eba3994dSjason 	} else
410eba3994dSjason 		idp = idprom;
411284584b0Sjason 	h = idp->id_machine << 24;
412284584b0Sjason 	h |= idp->id_hostid[0] << 16;
413284584b0Sjason 	h |= idp->id_hostid[1] << 8;
414284584b0Sjason 	h |= idp->id_hostid[2];
415284584b0Sjason 	hostid = h;
416b4117920Smiod 	printf("\n");
417eba3994dSjason }
418eba3994dSjason 
419eba3994dSjason struct idprom *
getidprom(void)4200aac5001Snaddy getidprom(void)
421b4117920Smiod {
422eba3994dSjason 	struct idprom *idp = NULL;
423eba3994dSjason 	int node, n;
424eba3994dSjason 
425eba3994dSjason 	node = findroot();
426eba3994dSjason 	if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0)
427eba3994dSjason 		return (NULL);
428eba3994dSjason 	if (n != 1) {
429f8e6c425Stedu 		free(idp, M_DEVBUF, 0);
430eba3994dSjason 		return (NULL);
431eba3994dSjason 	}
432eba3994dSjason 	return (idp);
433284584b0Sjason }
434284584b0Sjason 
435284584b0Sjason /*
436284584b0Sjason  * XXX this belongs elsewhere
437284584b0Sjason  */
438284584b0Sjason void
myetheraddr(u_char * cp)4399ac6db98Scheloha myetheraddr(u_char *cp)
440284584b0Sjason {
441284584b0Sjason 	struct idprom *idp;
442284584b0Sjason 
443284584b0Sjason 	if ((idp = idprom) == NULL) {
444284584b0Sjason 		int node, n;
445284584b0Sjason 
446284584b0Sjason 		node = findroot();
447284584b0Sjason 		if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) ||
448284584b0Sjason 		    n != 1) {
449284584b0Sjason 			printf("\nmyetheraddr: clock not setup yet, "
450284584b0Sjason 			       "and no idprom property in /\n");
451284584b0Sjason 			return;
452284584b0Sjason 		}
453284584b0Sjason 	}
454284584b0Sjason 
455284584b0Sjason 	cp[0] = idp->id_ether[0];
456284584b0Sjason 	cp[1] = idp->id_ether[1];
457284584b0Sjason 	cp[2] = idp->id_ether[2];
458284584b0Sjason 	cp[3] = idp->id_ether[3];
459284584b0Sjason 	cp[4] = idp->id_ether[4];
460284584b0Sjason 	cp[5] = idp->id_ether[5];
461284584b0Sjason 	if (idprom == NULL)
462f8e6c425Stedu 		free(idp, M_DEVBUF, 0);
463284584b0Sjason }
464284584b0Sjason 
465284584b0Sjason /*
466573d576bScheloha  * Set up the real-time and statistics clocks.
467284584b0Sjason  *
468284584b0Sjason  * The frequencies of these clocks must be an even number of microseconds.
469284584b0Sjason  */
470284584b0Sjason void
cpu_initclocks(void)4718a2bbcc7Skettenis cpu_initclocks(void)
472284584b0Sjason {
4738a2bbcc7Skettenis 	u_int sys_tick_rate;
4748a2bbcc7Skettenis 	int impl = 0;
475284584b0Sjason 
476284584b0Sjason 	if (1000000 % hz) {
477284584b0Sjason 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
478284584b0Sjason 		hz = 100;
479284584b0Sjason 		tick = 1000000 / hz;
480ee48eda3Scheloha 		tick_nsec = 1000000000 / hz;
481284584b0Sjason 	}
482284584b0Sjason 
483573d576bScheloha 	stathz = hz;
484573d576bScheloha 	profhz = stathz * 10;
485b3ef18bdScheloha 	statclock_is_randomized = 1;
486573d576bScheloha 
487284584b0Sjason 	/* Make sure we have a sane cpu_clockrate -- we'll need it */
488284584b0Sjason 	if (!cpu_clockrate)
489284584b0Sjason 		/* Default to 200MHz clock XXXXX */
490284584b0Sjason 		cpu_clockrate = 200000000;
491284584b0Sjason 
49205a26ea5Sart 	tick_timecounter.tc_frequency = cpu_clockrate;
49305a26ea5Sart 	tc_init(&tick_timecounter);
494284584b0Sjason 
495284584b0Sjason 	/*
4968a2bbcc7Skettenis 	 * UltraSPARC IIe processors do have a STICK register, but it
49736fd90dcSjsg 	 * lives on the PCI host bridge and isn't accessible through
4988a2bbcc7Skettenis 	 * ASR24.
4998a2bbcc7Skettenis 	 */
5008a2bbcc7Skettenis 	if (CPU_ISSUN4U || CPU_ISSUN4US)
5018a2bbcc7Skettenis 		impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT;
5028a2bbcc7Skettenis 
5038a2bbcc7Skettenis 	sys_tick_rate = getpropint(findroot(), "stick-frequency", 0);
5048a2bbcc7Skettenis 	if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) {
5058a2bbcc7Skettenis 		sys_tick_timecounter.tc_frequency = sys_tick_rate;
5068a2bbcc7Skettenis 		tc_init(&sys_tick_timecounter);
5078a2bbcc7Skettenis 	}
5088a2bbcc7Skettenis 
50940cab56cSkettenis 	struct cpu_info *ci;
51040cab56cSkettenis 
511284584b0Sjason 	/*
512284584b0Sjason 	 * Establish a level 10 interrupt handler
513284584b0Sjason 	 *
514284584b0Sjason 	 * We will have a conflict with the softint handler,
515284584b0Sjason 	 * so we set the ih_number to 1.
516284584b0Sjason 	 */
5178a1e8ccaSmiod 	intr_establish(&level10);
5188a1e8ccaSmiod 	evcount_percpu(&level10.ih_count);
51940cab56cSkettenis 
520386fc5f4Skettenis 	if (sys_tick_rate > 0) {
521573d576bScheloha 		sys_tick_nsec_cycle_ratio =
522573d576bScheloha 		    sys_tick_rate * (1ULL << 32) / 1000000000;
523573d576bScheloha 		sys_tick_nsec_max = UINT64_MAX / sys_tick_nsec_cycle_ratio;
524386fc5f4Skettenis 		if (impl == IMPL_HUMMINGBIRD) {
5258a1e8ccaSmiod 			level10.ih_fun = stickintr;
526386fc5f4Skettenis 			cpu_start_clock = stick_start;
527386fc5f4Skettenis 		} else {
5288a1e8ccaSmiod 			level10.ih_fun = sys_tickintr;
529ebe39446Skettenis 			cpu_start_clock = sys_tick_start;
530386fc5f4Skettenis 		}
531ebe39446Skettenis 	} else {
532573d576bScheloha 		tick_nsec_cycle_ratio =
533573d576bScheloha 		    cpu_clockrate * (1ULL << 32) / 1000000000;
534573d576bScheloha 		tick_nsec_max = UINT64_MAX / tick_nsec_cycle_ratio;
5358a1e8ccaSmiod 		level10.ih_fun = tickintr;
536ebe39446Skettenis 		cpu_start_clock = tick_start;
537ebe39446Skettenis 	}
538ebe39446Skettenis 
539ebe39446Skettenis 	for (ci = cpus; ci != NULL; ci = ci->ci_next)
5408a1e8ccaSmiod 		memcpy(&ci->ci_tickintr, &level10, sizeof(level10));
54111d1f9b2Scheloha }
542ebe39446Skettenis 
54311d1f9b2Scheloha void
cpu_startclock(void)54411d1f9b2Scheloha cpu_startclock(void)
54511d1f9b2Scheloha {
546ebe39446Skettenis 	cpu_start_clock();
547284584b0Sjason }
548284584b0Sjason 
549284584b0Sjason void
setstatclockrate(int newhz)5509ac6db98Scheloha setstatclockrate(int newhz)
551284584b0Sjason {
552284584b0Sjason }
553284584b0Sjason 
554284584b0Sjason /*
555284584b0Sjason  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
556284584b0Sjason  * console input, we need to check for that here as well, and generate
557284584b0Sjason  * a software interrupt to read it.
558284584b0Sjason  *
559284584b0Sjason  * %tick is really a level-14 interrupt.  We need to remap this in
560284584b0Sjason  * locore.s to a level 10.
561284584b0Sjason  */
562284584b0Sjason int
tickintr(void * cap)5639ac6db98Scheloha tickintr(void *cap)
564284584b0Sjason {
565573d576bScheloha 	clockintr_dispatch(cap);
5668a1e8ccaSmiod 	evcount_inc(&level10.ih_count);
567284584b0Sjason 	return (1);
568284584b0Sjason }
569284584b0Sjason 
570ebe39446Skettenis int
sys_tickintr(void * cap)5719ac6db98Scheloha sys_tickintr(void *cap)
572ebe39446Skettenis {
573573d576bScheloha 	clockintr_dispatch(cap);
5748a1e8ccaSmiod 	evcount_inc(&level10.ih_count);
575ebe39446Skettenis 	return (1);
576ebe39446Skettenis }
577ebe39446Skettenis 
578386fc5f4Skettenis int
stickintr(void * cap)5799ac6db98Scheloha stickintr(void *cap)
580386fc5f4Skettenis {
581573d576bScheloha 	clockintr_dispatch(cap);
5828a1e8ccaSmiod 	evcount_inc(&level10.ih_count);
583284584b0Sjason 	return (1);
584284584b0Sjason }
585284584b0Sjason 
58658c73160Skettenis void
tick_start(void)58758c73160Skettenis tick_start(void)
58858c73160Skettenis {
58942bbbbfdSkettenis 	tick_enable();
59042bbbbfdSkettenis 
591573d576bScheloha 	clockintr_cpu_init(&tick_intrclock);
592573d576bScheloha 	clockintr_trigger();
593573d576bScheloha }
594573d576bScheloha 
595573d576bScheloha void
tick_rearm(void * unused,uint64_t nsecs)596573d576bScheloha tick_rearm(void *unused, uint64_t nsecs)
597573d576bScheloha {
598573d576bScheloha 	uint64_t s, t0;
599573d576bScheloha 	uint32_t cycles;
600573d576bScheloha 
601573d576bScheloha 	if (nsecs > tick_nsec_max)
602573d576bScheloha 		nsecs = tick_nsec_max;
603573d576bScheloha 	cycles = (nsecs * tick_nsec_cycle_ratio) >> 32;
604573d576bScheloha 
60558c73160Skettenis 	s = intr_disable();
606573d576bScheloha 	t0 = tick();
607573d576bScheloha 	tickcmpr_set((t0 + cycles) & TICK_COUNT_MASK);
608573d576bScheloha 	if (cycles <= ((tick() - t0) & TICK_COUNT_MASK))
609573d576bScheloha 		sparc64_raise_clockintr();
61058c73160Skettenis 	intr_restore(s);
61158c73160Skettenis }
61258c73160Skettenis 
613ebe39446Skettenis void
tick_trigger(void * unused)614573d576bScheloha tick_trigger(void *unused)
6154b28d16fScheloha {
616573d576bScheloha 	sparc64_raise_clockintr();
6174b28d16fScheloha }
6184b28d16fScheloha 
6194b28d16fScheloha void
sys_tick_start(void)620ebe39446Skettenis sys_tick_start(void)
621ebe39446Skettenis {
62242bbbbfdSkettenis 	if (CPU_ISSUN4U || CPU_ISSUN4US) {
62342bbbbfdSkettenis 		tick_enable();
62442bbbbfdSkettenis 		sys_tick_enable();
62542bbbbfdSkettenis 	}
62642bbbbfdSkettenis 
627573d576bScheloha 	clockintr_cpu_init(&sys_tick_intrclock);
628573d576bScheloha 	clockintr_trigger();
629573d576bScheloha }
630573d576bScheloha 
631573d576bScheloha void
sys_tick_rearm(void * unused,uint64_t nsecs)632573d576bScheloha sys_tick_rearm(void *unused, uint64_t nsecs)
633573d576bScheloha {
634573d576bScheloha 	uint64_t s, t0;
635573d576bScheloha 	uint32_t cycles;
636573d576bScheloha 
637573d576bScheloha 	if (nsecs > sys_tick_nsec_max)
638573d576bScheloha 		nsecs = sys_tick_nsec_max;
639573d576bScheloha 	cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32;
640573d576bScheloha 
641ebe39446Skettenis 	s = intr_disable();
642573d576bScheloha 	t0 = sys_tick();
643573d576bScheloha 	sys_tickcmpr_set((t0 + cycles) & STICK_COUNT_MASK);
644573d576bScheloha 	if (cycles <= ((sys_tick() - t0) & STICK_COUNT_MASK))
645573d576bScheloha 		sparc64_raise_clockintr();
646ebe39446Skettenis 	intr_restore(s);
647ebe39446Skettenis }
648ebe39446Skettenis 
649386fc5f4Skettenis void
sys_tick_trigger(void * unused)650573d576bScheloha sys_tick_trigger(void *unused)
6514b28d16fScheloha {
652573d576bScheloha 	sparc64_raise_clockintr();
6534b28d16fScheloha }
6544b28d16fScheloha 
6554b28d16fScheloha void
stick_start(void)656386fc5f4Skettenis stick_start(void)
657386fc5f4Skettenis {
65842bbbbfdSkettenis 	tick_enable();
65942bbbbfdSkettenis 
660573d576bScheloha 	clockintr_cpu_init(&stick_intrclock);
661573d576bScheloha 	clockintr_trigger();
662573d576bScheloha }
663573d576bScheloha 
664573d576bScheloha void
stick_rearm(void * unused,uint64_t nsecs)665573d576bScheloha stick_rearm(void *unused, uint64_t nsecs)
666573d576bScheloha {
667573d576bScheloha 	uint64_t s, t0;
668573d576bScheloha 	uint32_t cycles;
669573d576bScheloha 
670573d576bScheloha 	if (nsecs > sys_tick_nsec_max)
671573d576bScheloha 		nsecs = sys_tick_nsec_max;
672573d576bScheloha 	cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32;
673573d576bScheloha 
674386fc5f4Skettenis 	s = intr_disable();
675573d576bScheloha 	t0 = stick();
676573d576bScheloha 	stickcmpr_set((t0 + cycles) & STICK_COUNT_MASK);
677573d576bScheloha 	if (cycles <= ((stick() - t0) & STICK_COUNT_MASK))
678573d576bScheloha 		sparc64_raise_clockintr();
679386fc5f4Skettenis 	intr_restore(s);
680386fc5f4Skettenis }
681386fc5f4Skettenis 
6822f31c0f7Scheloha void
stick_trigger(void * unused)683573d576bScheloha stick_trigger(void *unused)
6842f31c0f7Scheloha {
685573d576bScheloha 	sparc64_raise_clockintr();
6862f31c0f7Scheloha }
6872f31c0f7Scheloha 
68805a26ea5Sart u_int
tick_get_timecount(struct timecounter * tc)68905a26ea5Sart tick_get_timecount(struct timecounter *tc)
690bec6c41fSjason {
691bec6c41fSjason 	u_int64_t tick;
692bec6c41fSjason 
693de43b1a9Skettenis 	__asm volatile("rd %%tick, %0" : "=r" (tick));
694bec6c41fSjason 
69505a26ea5Sart 	return (tick & ~0u);
696bec6c41fSjason }
6978a2bbcc7Skettenis 
6988a2bbcc7Skettenis u_int
sys_tick_get_timecount(struct timecounter * tc)6998a2bbcc7Skettenis sys_tick_get_timecount(struct timecounter *tc)
7008a2bbcc7Skettenis {
7018a2bbcc7Skettenis 	u_int64_t tick;
7028a2bbcc7Skettenis 
703de43b1a9Skettenis 	__asm volatile("rd %%sys_tick, %0" : "=r" (tick));
7048a2bbcc7Skettenis 
7058a2bbcc7Skettenis 	return (tick & ~0u);
7068a2bbcc7Skettenis }
707573d576bScheloha 
708573d576bScheloha void
sparc64_raise_clockintr(void)709573d576bScheloha sparc64_raise_clockintr(void)
710573d576bScheloha {
711bdd1b079Smiod 	send_softint(PIL_CLOCK, &curcpu()->ci_tickintr);
712573d576bScheloha }
713