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