1 /* $NetBSD: clock.c,v 1.1 2026/07/19 01:48:21 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2023, 2025 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1992, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This software was developed by the Computer Systems Engineering group 37 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 38 * contributed to Berkeley. 39 * 40 * All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Lawrence Berkeley Laboratory. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 * 69 * @(#)clock.c 8.1 (Berkeley) 6/11/93 70 */ 71 72 #include "opt_fdt.h" 73 74 #include <sys/cdefs.h> 75 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.1 2026/07/19 01:48:21 thorpej Exp $"); 76 77 #include <sys/param.h> 78 #include <sys/kernel.h> 79 #include <sys/systm.h> 80 #include <sys/device.h> 81 82 #include <machine/clockvar.h> 83 #include <machine/psl.h> 84 #include <machine/bus.h> 85 86 static struct clock_vars { 87 struct clock_attach_args *args; 88 struct evcnt counter; 89 } m68k_clocks[NCLOCKS]; 90 91 static struct clock_handlers { 92 const char *name; 93 void (*func)(struct clockframe *); 94 } m68k_clock_handlers[] = { 95 [CLOCK_HARDCLOCK] = { .name = "hardclock", 96 .func = hardclock }, 97 [CLOCK_STATCLOCK] = { .name = "statclock", 98 .func = statclock }, 99 }; 100 101 void *clock_devices[NCLOCKS]; 102 103 /* 104 * Statistics clock interval and variance, in usec. Variance must be a 105 * power of two. Since this gives us an even number, not an odd number, 106 * we discard one case and compensate. That is, a variance of 1024 would 107 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 108 * This is symmetric about the point 512, or statvar/2, and thus averages 109 * to that value (assuming uniform random numbers). 110 */ 111 /* XXX fix comment to match value */ 112 int clock_statvar = 8192; 113 int clock_statmin; /* statclock interval - (1/2 * variance) */ 114 115 #ifdef FDT 116 #include <dev/fdt/fdtvar.h> 117 #include <libfdt.h> 118 119 /* 120 * Given a device phandle, see if it is one of the system clock 121 * sources. 122 */ 123 int 124 clock_from_phandle(int phandle) 125 { 126 static const char * propnames[NCLOCKS] = { 127 [CLOCK_HARDCLOCK] = "netbsd,hardclock", 128 [CLOCK_STATCLOCK] = "netbsd,statclock", 129 }; 130 const int off = fdt_path_offset(fdtbus_get_data(), "/chosen"); 131 const char *propval; 132 133 if (off < 0) { 134 return CLOCK_NONE; 135 } 136 137 for (int i = 0; i < NCLOCKS; i++) { 138 propval = fdt_getprop(fdtbus_get_data(), off, 139 propnames[i], NULL); 140 if (propval == NULL) { 141 continue; 142 } 143 if (*propval != '/') { 144 /* Alias */ 145 propval = fdt_get_alias(fdtbus_get_data(), propval); 146 if (propval == NULL) { 147 continue; 148 } 149 } 150 if (OF_finddevice(propval) == phandle) { 151 return i; 152 } 153 } 154 return CLOCK_NONE; 155 } 156 #endif /* FDT */ 157 158 /* 159 * Common parts of clock autoconfiguration. 160 */ 161 void 162 clock_attach(device_t dev, struct clock_attach_args *ca) 163 { 164 /* Hook up that which we need. */ 165 KASSERT(ca->ca_which >= 0 || ca->ca_which == CLOCK_NONE); 166 KASSERT(ca->ca_which < NCLOCKS); 167 168 /* 169 * If this isn't a clock source, then just ignore it. 170 */ 171 if (ca->ca_which == CLOCK_NONE) { 172 return; 173 } 174 175 KASSERT(clock_devices[ca->ca_which] == NULL); 176 KASSERT(m68k_clocks[ca->ca_which].args == NULL); 177 178 clock_devices[ca->ca_which] = ca->ca_arg; 179 m68k_clocks[ca->ca_which].args = ca; 180 181 evcnt_attach_dynamic(&m68k_clocks[ca->ca_which].counter, 182 EVCNT_TYPE_INTR, ca->ca_parent_evcnt, 183 device_xname(dev), m68k_clock_handlers[ca->ca_which].name); 184 } 185 186 const char * 187 clock_name(int which) 188 { 189 KASSERT(which >= 0); 190 KASSERT(which < NCLOCKS); 191 192 return m68k_clock_handlers[which].name; 193 } 194 195 /* 196 * Set up the real-time and statistics clocks. Leave stathz 0 only 197 * if no alternative timer is available. 198 * 199 * The frequencies of these clocks must be an even number of microseconds. 200 */ 201 void 202 cpu_initclocks(void) 203 { 204 int i, statint = 0, minint = 0; 205 206 if (m68k_clocks[CLOCK_HARDCLOCK].args == NULL) { 207 panic("Clock not configured"); 208 } 209 210 if (1000000 % hz) { 211 aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz); 212 hz = 100; 213 tick = 1000000 / hz; 214 } 215 216 if (m68k_clocks[CLOCK_STATCLOCK].args == NULL) { 217 aprint_normal("No statclock; using hardclock.\n"); 218 stathz = 0; 219 statint = 0; 220 } else if (stathz == 0) { 221 stathz = hz; 222 if (1000000 % stathz) { 223 aprint_error("Cannot get %d Hz statclock; " 224 "using 100 Hz\n", stathz); 225 stathz = 100; 226 } 227 profhz = stathz; /* always */ 228 statint = 1000000 / stathz; 229 minint = statint / 2 + 100; 230 while (clock_statvar > minint) 231 clock_statvar >>= 1; 232 clock_statmin = statint - (clock_statvar >> 1); 233 } 234 235 for (i = 0; i < NCLOCKS; i++) { 236 struct clock_attach_args *ca = m68k_clocks[i].args; 237 unsigned int freq, interval; 238 239 if (ca == NULL) { 240 continue; 241 } 242 switch (i) { 243 case CLOCK_HARDCLOCK: 244 freq = hz; 245 interval = tick; 246 break; 247 248 case CLOCK_STATCLOCK: 249 freq = stathz; 250 interval = statint; 251 break; 252 253 default: 254 KASSERT(0); 255 } 256 257 aprint_normal("Initialzing %s: freq=%u Hz, interval=%u usec\n", 258 clock_name(i), freq, interval); 259 ca->ca_initfunc(ca->ca_arg, interval, 260 &m68k_clocks[i].counter, 261 m68k_clock_handlers[i].func); 262 } 263 } 264 265 void 266 setstatclockrate(int newhz) 267 { 268 269 /* XXX should we do something here? XXX */ 270 } 271