Home | History | Annotate | Line # | Download | only in hb68k
      1 /*      $NetBSD: clock.c,v 1.2 2026/08/07 23:37:46 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.2 2026/08/07 23:37:46 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 	const char *name;
     88 	struct clock_if *clkif;
     89 	struct evcnt counter;
     90 } m68k_clocks[NCLOCKS] = {
     91 	[CLOCK_HARDCLOCK] = {
     92 		.name = "hardclock",
     93 	},
     94 	[CLOCK_STATCLOCK] = {
     95 		.name = "statclock",
     96 	},
     97 };
     98 
     99 static TAILQ_HEAD(, clock_if) clock_candidates =
    100     TAILQ_HEAD_INITIALIZER(clock_candidates);
    101 
    102 /*
    103  * Statistics clock interval and variance, in usec.  Variance must be a
    104  * power of two.  Since this gives us an even number, not an odd number,
    105  * we discard one case and compensate.  That is, a variance of 1024 would
    106  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
    107  * This is symmetric about the point 512, or statvar/2, and thus averages
    108  * to that value (assuming uniform random numbers).
    109  */
    110 /* XXX fix comment to match value */
    111 int	clock_statvar = 8192;
    112 int	clock_statmin;		/* statclock interval - (1/2 * variance) */
    113 
    114 #include <dev/fdt/fdtvar.h>
    115 #include <dev/ofw/openfirm.h>
    116 #include <libfdt.h>
    117 
    118 /*
    119  * Given a device phandle, see if it is one of the system clock
    120  * sources.
    121  */
    122 static int
    123 clock_from_phandle(int phandle)
    124 {
    125 	static const char * propnames[NCLOCKS] = {
    126 		[CLOCK_HARDCLOCK] = "netbsd,hardclock",
    127 		[CLOCK_STATCLOCK] = "netbsd,statclock",
    128 	};
    129 	const int off = fdt_path_offset(fdtbus_get_data(), "/chosen");
    130 	const char *propval;
    131 
    132 	if (off < 0) {
    133 		return CLOCK_NONE;
    134 	}
    135 
    136 	for (int i = 0; i < NCLOCKS; i++) {
    137 		propval = fdt_getprop(fdtbus_get_data(), off,
    138 		    propnames[i], NULL);
    139 		if (propval == NULL) {
    140 			continue;
    141 		}
    142 		if (*propval != '/') {
    143 			/* Alias */
    144 			propval = fdt_get_alias(fdtbus_get_data(), propval);
    145 			if (propval == NULL) {
    146 				continue;
    147 			}
    148 		}
    149 		if (OF_finddevice(propval) == phandle) {
    150 			return i;
    151 		}
    152 	}
    153 	return CLOCK_NONE;
    154 }
    155 
    156 static int
    157 clock_hardclock_intr(void *v)
    158 {
    159 	struct clock_if * const clk = m68k_clocks[CLOCK_HARDCLOCK].clkif;
    160 
    161 	/* ACK interrupt, re-load timer. */
    162 	(*clk->clk_intr)(clk);
    163 
    164 	m68k_clocks[CLOCK_HARDCLOCK].counter.ev_count++;
    165 	hardclock((struct clockframe *)v);
    166 
    167 	return 1;
    168 }
    169 
    170 static int
    171 clock_statclock_intr(void *v)
    172 {
    173 	struct clock_if * const clk = m68k_clocks[CLOCK_STATCLOCK].clkif;
    174 
    175 	/* ACK interrupt, re-load timer. */
    176 	/* XXX add variance */
    177 	(*clk->clk_intr)(clk);
    178 
    179 	m68k_clocks[CLOCK_STATCLOCK].counter.ev_count++;
    180 	statclock((struct clockframe *)v);
    181 
    182 	return 1;
    183 }
    184 
    185 /*
    186  * Common parts of clock autoconfiguration.
    187  */
    188 void
    189 clock_attach(struct clock_if *clk)
    190 {
    191 	clk->clk_which =
    192 	    clock_from_phandle(devhandle_to_of(device_handle(clk->clk_dev)));
    193 	if (clk->clk_which == CLOCK_NONE) {
    194 		TAILQ_INSERT_TAIL(&clock_candidates, clk, clk_list);
    195 	} else {
    196 		TAILQ_INSERT_HEAD(&clock_candidates, clk, clk_list);
    197 	}
    198 }
    199 
    200 static const char *
    201 clock_name(int which)
    202 {
    203 	KASSERT(which >= 0);
    204 	KASSERT(which < NCLOCKS);
    205 
    206 	return m68k_clocks[which].name;
    207 }
    208 
    209 /*
    210  * Set up the real-time and statistics clocks.  Leave stathz 0 only
    211  * if no alternative timer is available.
    212  *
    213  * The frequencies of these clocks must be an even number of microseconds.
    214  */
    215 void
    216 cpu_initclocks(void)
    217 {
    218 	int i, statint = 0, minint = 0;
    219 	struct clock_if *clk;
    220 
    221 	/*
    222 	 * Assign the clocks.  All the clocks with pre-assigned roles
    223 	 * are at the head of the list, and all of the unassigned clocks
    224 	 * are at the end.
    225 	 */
    226 	TAILQ_FOREACH(clk, &clock_candidates, clk_list) {
    227 		if (clk->clk_which != CLOCK_NONE) {
    228 			KASSERT(m68k_clocks[clk->clk_which].clkif == NULL);
    229 			m68k_clocks[clk->clk_which].clkif = clk;
    230 		} else if (m68k_clocks[CLOCK_HARDCLOCK].clkif == NULL) {
    231 			clk->clk_which = CLOCK_HARDCLOCK;
    232 			m68k_clocks[CLOCK_HARDCLOCK].clkif = clk;
    233 		} else if (m68k_clocks[CLOCK_STATCLOCK].clkif == NULL) {
    234 			clk->clk_which = CLOCK_STATCLOCK;
    235 			m68k_clocks[CLOCK_STATCLOCK].clkif = clk;
    236 		}
    237 	}
    238 
    239 	if (m68k_clocks[CLOCK_HARDCLOCK].clkif == NULL) {
    240 		panic("Clock not configured");
    241 	}
    242 
    243 	if (1000000 % hz) {
    244 		aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz);
    245 		hz = 100;
    246 		tick = 1000000 / hz;
    247 	}
    248 
    249 	if (m68k_clocks[CLOCK_STATCLOCK].clkif == NULL) {
    250 		aprint_normal("No statclock; using hardclock.\n");
    251 		stathz = 0;
    252 		statint = 0;
    253 	} else if (stathz == 0) {
    254 		stathz = hz;
    255 		if (1000000 % stathz) {
    256 			aprint_error("Cannot get %d Hz statclock; "
    257 				     "using 100 Hz\n", stathz);
    258 			stathz = 100;
    259 		}
    260 		profhz = stathz;	/* always */
    261 		statint = 1000000 / stathz;
    262 		minint = statint / 2 + 100;
    263 		while (clock_statvar > minint)
    264 			clock_statvar >>= 1;
    265 		clock_statmin = statint - (clock_statvar >> 1);
    266 	}
    267 
    268 	for (i = 0; i < NCLOCKS; i++) {
    269 		clk = m68k_clocks[i].clkif;
    270 		unsigned int freq, interval;
    271 		int (*func)(void *);
    272 		int error;
    273 
    274 		if (clk == NULL) {
    275 			continue;
    276 		}
    277 		switch (i) {
    278 		case CLOCK_HARDCLOCK:
    279 			freq = hz;
    280 			interval = tick;
    281 			func = clock_hardclock_intr;
    282 			break;
    283 
    284 		case CLOCK_STATCLOCK:
    285 			freq = stathz;
    286 			interval = statint;
    287 			func = clock_statclock_intr;
    288 			break;
    289 
    290 		default:
    291 			KASSERT(0);
    292 		}
    293 
    294 		evcnt_attach_dynamic(&m68k_clocks[i].counter,
    295 		    EVCNT_TYPE_INTR, clk->clk_parent_evcnt,
    296 		    device_xname(clk->clk_dev), m68k_clocks[i].name);
    297 
    298 		aprint_normal_dev(clk->clk_dev,
    299 		    "%s: freq=%u Hz, interval=%u usec\n",
    300 		    clock_name(i), freq, interval);
    301 		error = (*clk->clk_init)(clk, func);
    302 		if (error) {
    303 			panic("Failed to initialize %s for %s (error %d)",
    304 			    device_xname(clk->clk_dev),
    305 			    clock_name(i), error);
    306 		}
    307 		error = (*clk->clk_arm)(clk, interval);
    308 		if (error) {
    309 			panic("Failed to arm %s for %s (error %d)",
    310 			    device_xname(clk->clk_dev),
    311 			    clock_name(i), error);
    312 		}
    313 	}
    314 }
    315 
    316 void
    317 setstatclockrate(int newhz)
    318 {
    319 
    320 	/* XXX should we do something here? XXX */
    321 }
    322