1 /* $NetBSD: clock.c,v 1.18 2024/01/19 18:18:55 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah Hdr: clock.c 1.18 91/01/21$ 36 * from: @(#)clock.c 8.2 (Berkeley) 1/12/94 37 */ 38 39 /* 40 * Copyright (c) 2001 Matthew Fredette 41 * Copyright (c) 1994 Gordon W. Ross 42 * Copyright (c) 1993 Adam Glass 43 * Copyright (c) 1988 University of Utah. 44 * 45 * This code is derived from software contributed to Berkeley by 46 * the Systems Programming Group of the University of Utah Computer 47 * Science Department. 48 * 49 * Redistribution and use in source and binary forms, with or without 50 * modification, are permitted provided that the following conditions 51 * are met: 52 * 1. Redistributions of source code must retain the above copyright 53 * notice, this list of conditions and the following disclaimer. 54 * 2. Redistributions in binary form must reproduce the above copyright 55 * notice, this list of conditions and the following disclaimer in the 56 * documentation and/or other materials provided with the distribution. 57 * 3. All advertising materials mentioning features or use of this software 58 * must display the following acknowledgement: 59 * This product includes software developed by the University of 60 * California, Berkeley and its contributors. 61 * 4. Neither the name of the University nor the names of its contributors 62 * may be used to endorse or promote products derived from this software 63 * without specific prior written permission. 64 * 65 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 68 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 75 * SUCH DAMAGE. 76 * 77 * from: Utah Hdr: clock.c 1.18 91/01/21$ 78 * from: @(#)clock.c 8.2 (Berkeley) 1/12/94 79 */ 80 81 /* 82 * Machine-dependent clock routines for the Am9513 83 * Written by Matthew Fredette, based on the sun3 clock.c by 84 * Adam Glass and Gordon Ross. 85 */ 86 87 #include <sys/cdefs.h> 88 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.18 2024/01/19 18:18:55 thorpej Exp $"); 89 90 #include <sys/param.h> 91 #include <sys/systm.h> 92 #include <sys/time.h> 93 #include <sys/kernel.h> 94 #include <sys/device.h> 95 96 #include <machine/autoconf.h> 97 #include <machine/cpu.h> 98 #include <machine/frame.h> 99 #include <machine/leds.h> 100 #include <machine/vectors.h> 101 102 #include <sun2/sun2/control.h> 103 #include <sun2/sun2/enable.h> 104 #include <sun2/sun2/machdep.h> 105 106 #include <dev/clock_subr.h> 107 #include <dev/ic/am9513reg.h> 108 109 /* 110 * Carefully define the basic CPU clock rate so 111 * that time-of-day calculations don't float 112 * 113 * Note that the CLK_BASIC is divided by 4 before we can count with it, 114 * e.g. F1 ticks CLK_BASIC/4 times a second. 115 */ 116 #define SUN2_CLK_BASIC (19660800) 117 #define SUN2_CLK_TICKS(func, hz) \ 118 (((SUN2_CLK_BASIC / 4) / AM9513_CM_SOURCE_Fn_DIV(func)) / (hz)) 119 120 /* These define which counters are used for what. */ 121 #define SUN2_CLK_NMI AM9513_TIMER1 /* Non Maskable Interrupts */ 122 #define SUN2_CLK_TIMER AM9513_TIMER2 /* Timer 2 */ 123 #define SUN2_CLK_UNUSED AM9513_TIMER3 /* Unused timer */ 124 #define SUN2_CLK_FAST_LO AM9513_TIMER4 /* Timer 4 for realtime, low order */ 125 #define SUN2_CLK_FAST_HI AM9513_TIMER5 /* Timer 5 for realtime, high order */ 126 127 #define CLOCK_PRI 5 128 #define IREG_CLK_BITS (IREG_CLOCK_ENAB_7 | IREG_CLOCK_ENAB_5) 129 130 void _isr_clock(void); /* in locore.s */ 131 void clock_intr(struct clockframe); 132 133 static bus_space_tag_t am9513_bt; 134 static bus_space_handle_t am9513_bh; 135 #define am9513_write_clk_cmd(val) \ 136 bus_space_write_2(am9513_bt, am9513_bh, AM9513_CLK_CMD, val) 137 #define am9513_write_clk_data(val) \ 138 bus_space_write_2(am9513_bt, am9513_bh, AM9513_CLK_DATA, val) 139 140 static int clock_match(device_t, cfdata_t, void *args); 141 static void clock_attach(device_t, device_t, void *); 142 143 CFATTACH_DECL_NEW(clock, 0, 144 clock_match, clock_attach, NULL, NULL); 145 146 static int clock_attached; 147 148 static int 149 clock_match(device_t parent, cfdata_t cf, void *args) 150 { 151 struct obio_attach_args *oba = args; 152 bus_space_handle_t bh; 153 bool matched; 154 155 /* This driver only supports one unit. */ 156 if (clock_attached) 157 return 0; 158 159 /* Make sure there is something there... */ 160 if (bus_space_map(oba->oba_bustag, oba->oba_paddr, 161 sizeof(struct am9513), 0, &bh)) 162 return 0; 163 matched = (bus_space_peek_2(oba->oba_bustag, bh, 0, NULL) == 0); 164 bus_space_unmap(oba->oba_bustag, bh, sizeof(struct am9513)); 165 if (!matched) 166 return 0; 167 168 /* Default interrupt priority. */ 169 if (oba->oba_pri == -1) 170 oba->oba_pri = CLOCK_PRI; 171 172 return 1; 173 } 174 175 static void 176 clock_attach(device_t parent, device_t self, void *args) 177 { 178 struct obio_attach_args *oba = args; 179 bus_space_handle_t bh; 180 181 clock_attached = 1; 182 183 aprint_normal("\n"); 184 185 /* Get a mapping for it. */ 186 if (bus_space_map(oba->oba_bustag, oba->oba_paddr, 187 sizeof(struct am9513), 0, &bh)) 188 panic("%s: can't map clock", __func__); 189 am9513_bt = oba->oba_bustag; 190 am9513_bh = bh; 191 192 /* 193 * Set the clock to the correct interrupt rate, but 194 * do not enable the interrupt until cpu_initclocks. 195 */ 196 197 /* Disarm the timer and NMI. */ 198 am9513_write_clk_cmd(AM9513_CMD_DISARM(SUN2_CLK_TIMER | SUN2_CLK_NMI)); 199 am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER)); 200 am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_NMI)); 201 202 /* Set the clock to 100 Hz, but do not enable it yet. */ 203 am9513_write_clk_cmd(AM9513_CMD_LOAD_MODE(SUN2_CLK_TIMER)); 204 am9513_write_clk_data((AM9513_CM_MODE_D | AM9513_CM_SOURCE_F2 | 205 AM9513_CM_OUTPUT_TC_TOGGLED)); 206 am9513_write_clk_cmd(AM9513_CMD_LOAD_LOAD(SUN2_CLK_TIMER)); 207 am9513_write_clk_data(SUN2_CLK_TICKS(AM9513_CM_SOURCE_F2, 100)); 208 209 /* 210 * Can not hook up the ISR until cpu_initclocks() 211 * because hardclock is not ready until then. 212 * For now, the handler is _isr_autovec(), which 213 * will complain if it gets clock interrupts. 214 */ 215 } 216 217 /* 218 * Set or clear the desired clock bits in the interrupt 219 * register. We have to be extremely careful that we do it 220 * in such a manner that we don't get ourselves lost. 221 * XXX: Watch out! It's really easy to break this! 222 */ 223 void 224 set_clk_mode(int prom_clock, int on) 225 { 226 int timer; 227 228 #ifdef DIAGNOSTIC 229 /* Assertion: were are at splhigh! */ 230 if ((getsr() & PSL_IPL) < PSL_IPL7) 231 panic("%s: bad ipl", __func__); 232 #endif 233 234 /* Get the timer we're talking about. */ 235 timer = (prom_clock ? SUN2_CLK_NMI : SUN2_CLK_TIMER); 236 237 /* First, turn off the "master" enable bit. */ 238 enable_reg_and(~ENA_INTS); 239 240 /* 241 * Arm the timer we're supposed to turn on. 242 */ 243 if (on) { 244 am9513_write_clk_cmd(AM9513_CMD_ARM(timer)); 245 } 246 247 /* 248 * Disarm and clear the timers we're supposed to turn off. 249 */ 250 else { 251 am9513_write_clk_cmd(AM9513_CMD_DISARM(timer)); 252 am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(timer)); 253 } 254 255 /* Finally, turn the "master" enable back on. */ 256 enable_reg_or(ENA_INTS); 257 } 258 259 /* 260 * Set up the real-time clock (enable clock interrupts). 261 * Leave stathz 0 since there is no secondary clock available. 262 * Note that clock interrupts MUST STAY DISABLED until here. 263 */ 264 void 265 cpu_initclocks(void) 266 { 267 int s; 268 269 s = splhigh(); 270 271 /* Install isr (in locore.s) that calls clock_intr(). */ 272 vec_set_entry(VECI_INTRAV0 + 5, _isr_clock); 273 274 /* Now enable the clock at level 5 in the interrupt reg. */ 275 set_clk_mode(0, 1); 276 277 splx(s); 278 } 279 280 /* 281 * This doesn't need to do anything, as we have only one timer and 282 * profhz==stathz==hz. 283 */ 284 void 285 setstatclockrate(int newhz) 286 { 287 288 /* nothing */ 289 } 290 291 /* 292 * This is called by the "custom" interrupt handler. 293 * Note that we can get ZS interrupts while this runs, 294 * and zshard may touch the interrupt_reg, so we must 295 * be careful to use the single_inst_* macros to modify 296 * the interrupt register atomically. 297 */ 298 void 299 clock_intr(struct clockframe cf) 300 { 301 302 intr_depth++; 303 304 /* Read the clock interrupt register. */ 305 am9513_write_clk_cmd(AM9513_CMD_CLEAR_OUTPUT(SUN2_CLK_TIMER)); 306 307 { /* Entertainment! */ 308 #ifdef LED_IDLE_CHECK 309 /* With this option, LEDs move only when CPU is idle. */ 310 extern char _Idle[]; /* locore.s */ 311 if (cf.cf_pc == (long)_Idle) 312 #endif 313 leds_intr(); 314 } 315 316 /* Call common clock interrupt handler. */ 317 hardclock(&cf); 318 319 intr_depth--; 320 321 ATOMIC_CAS_CHECK(&cf); 322 } 323