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