1 /* $NetBSD: clock.c,v 1.40 2013/09/06 17:43:19 tsutsui 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) 1994 Gordon W. Ross 41 * Copyright (c) 1993 Adam Glass 42 * Copyright (c) 1988 University of Utah. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah Hdr: clock.c 1.18 91/01/21$ 77 * from: @(#)clock.c 8.2 (Berkeley) 1/12/94 78 */ 79 80 /* 81 * Machine-dependent clock routines. Sun3X machines may have 82 * either the Mostek 48T02 or the Intersil 7170 clock. 83 * 84 * It is tricky to determine which you have, because there is 85 * always something responding at the address where the Mostek 86 * clock might be found: either a Mostek or plain-old EEPROM. 87 * Therefore, we cheat. If we find an Intersil clock, assume 88 * that what responds at the end of the EEPROM space is just 89 * plain-old EEPROM (not a Mostek clock). Worse, there are 90 * H/W problems with probing for an Intersil on the 3/80, so 91 * on that machine we "know" there is a Mostek clock. 92 * 93 * Note that the probing algorithm described above requires 94 * that we probe the intersil before we probe the mostek! 95 */ 96 97 #include <sys/cdefs.h> 98 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.40 2013/09/06 17:43:19 tsutsui Exp $"); 99 100 #include <sys/param.h> 101 #include <sys/systm.h> 102 #include <sys/time.h> 103 #include <sys/kernel.h> 104 #include <sys/device.h> 105 106 #include <uvm/uvm_extern.h> 107 108 #include <m68k/asm_single.h> 109 110 #include <machine/autoconf.h> 111 #include <machine/bus.h> 112 #include <machine/cpu.h> 113 #include <machine/idprom.h> 114 #include <machine/leds.h> 115 116 #include <dev/clock_subr.h> 117 #include <dev/ic/intersil7170reg.h> 118 #include <dev/ic/intersil7170var.h> 119 #include <dev/ic/mk48txxreg.h> 120 #include <dev/ic/mk48txxvar.h> 121 122 #include <sun3/sun3/machdep.h> 123 #include <sun3/sun3/interreg.h> 124 125 extern int intrcnt[]; 126 127 #define SUN3_470 Yes 128 129 #define CLOCK_PRI 5 130 #define IREG_CLK_BITS (IREG_CLOCK_ENAB_7 | IREG_CLOCK_ENAB_5) 131 132 #define MKCLOCK_REG_OFFSET (MK48T02_CLKOFF + MK48TXX_ICSR) 133 134 /* 135 * Only one of these two variables should be non-zero after 136 * autoconfiguration determines which clock we have. 137 */ 138 static volatile void *intersil_va; 139 static volatile void *mostek_clk_va; 140 141 void _isr_clock(void); /* in locore.s */ 142 void clock_intr(struct clockframe); 143 144 145 static int clock_match(device_t, cfdata_t, void *); 146 static void clock_attach(device_t, device_t, void *); 147 148 CFATTACH_DECL_NEW(clock, sizeof(struct mk48txx_softc), 149 clock_match, clock_attach, NULL, NULL); 150 151 #ifdef SUN3_470 152 153 #define intersil_clock ((volatile struct intersil7170 *)intersil_va) 154 155 #define intersil_clear() (void)intersil_clock->clk_intr_reg 156 157 static int oclock_match(device_t, cfdata_t, void *); 158 static void oclock_attach(device_t, device_t, void *); 159 160 CFATTACH_DECL_NEW(oclock, sizeof(struct intersil7170_softc), 161 oclock_match, oclock_attach, NULL, NULL); 162 163 164 /* 165 * Is there an intersil clock? 166 */ 167 static int 168 oclock_match(device_t parent, cfdata_t cf, void *aux) 169 { 170 struct confargs *ca = aux; 171 172 /* This driver only supports one unit. */ 173 if (intersil_va) 174 return 0; 175 176 /* 177 * The 3/80 can not probe the Intersil absent, 178 * but it never has one, so "just say no." 179 */ 180 if (cpu_machine_id == ID_SUN3X_80) 181 return 0; 182 183 /* OK, really probe for the Intersil. */ 184 if (bus_peek(ca->ca_bustype, ca->ca_paddr, 1) == -1) 185 return 0; 186 187 /* Default interrupt priority. */ 188 if (ca->ca_intpri == -1) 189 ca->ca_intpri = CLOCK_PRI; 190 191 return 1; 192 } 193 194 /* 195 * Attach the intersil clock. 196 */ 197 static void 198 oclock_attach(device_t parent, device_t self, void *aux) 199 { 200 struct intersil7170_softc *sc = device_private(self); 201 struct confargs *ca = aux; 202 203 sc->sc_dev = self; 204 205 /* Get a mapping for it. */ 206 sc->sc_bst = ca->ca_bustag; 207 if (bus_space_map(sc->sc_bst, ca->ca_paddr, sizeof(struct intersil7170), 208 0, &sc->sc_bsh) != 0) { 209 aprint_error(": can't map registers\n"); 210 return; 211 } 212 213 intersil_va = bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 214 215 #ifdef DIAGNOSTIC 216 /* Verify correct probe order... */ 217 if (mostek_clk_va) { 218 mostek_clk_va = NULL; 219 aprint_normal("\n"); 220 aprint_error_dev(self, "warning - mostek found also!\n"); 221 } 222 #endif 223 224 /* 225 * Set the clock to the correct interrupt rate, but 226 * do not enable the interrupt until cpu_initclocks. 227 * XXX: Actually, the interrupt_reg should be zero 228 * at this point, so the clock interrupts should not 229 * affect us, but we need to set the rate... 230 */ 231 bus_space_write_1(sc->sc_bst, sc->sc_bsh, INTERSIL_ICMD, 232 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE)); 233 (void)bus_space_read_1(sc->sc_bst, sc->sc_bsh, INTERSIL_IINTR); 234 235 /* Set the clock to 100 Hz, but do not enable it yet. */ 236 bus_space_write_1(sc->sc_bst, sc->sc_bsh, 237 INTERSIL_IINTR, INTERSIL_INTER_CSECONDS); 238 239 sc->sc_year0 = 1968; 240 intersil7170_attach(sc); 241 242 aprint_normal("\n"); 243 244 /* 245 * Can not hook up the ISR until cpu_initclocks() 246 * because hardclock is not ready until then. 247 * For now, the handler is _isr_autovec(), which 248 * will complain if it gets clock interrupts. 249 */ 250 } 251 #endif /* SUN3_470 */ 252 253 254 /* 255 * Is there a Mostek clock? Hard to tell... 256 * (See comment at top of this file.) 257 */ 258 static int 259 clock_match(device_t parent, cfdata_t cf, void *args) 260 { 261 struct confargs *ca = args; 262 263 /* This driver only supports one unit. */ 264 if (mostek_clk_va) 265 return 0; 266 267 /* If intersil was found, use that. */ 268 if (intersil_va) 269 return 0; 270 /* Else assume a Mostek is there... */ 271 272 /* Default interrupt priority. */ 273 if (ca->ca_intpri == -1) 274 ca->ca_intpri = CLOCK_PRI; 275 276 return 1; 277 } 278 279 /* 280 * Attach the mostek clock. 281 */ 282 static void 283 clock_attach(device_t parent, device_t self, void *aux) 284 { 285 struct mk48txx_softc *sc = device_private(self); 286 struct confargs *ca = aux; 287 288 sc->sc_dev = self; 289 sc->sc_bst = ca->ca_bustag; 290 if (bus_space_map(sc->sc_bst, ca->ca_paddr - MKCLOCK_REG_OFFSET, 291 MK48T02_CLKSZ, 0, &sc->sc_bsh) != 0) { 292 aprint_error(": can't map device space\n"); 293 return; 294 } 295 296 mostek_clk_va = bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 297 298 sc->sc_model = "mk48t02"; 299 sc->sc_year0 = 1968; 300 301 mk48txx_attach(sc); 302 303 aprint_normal("\n"); 304 } 305 306 /* 307 * Set and/or clear the desired clock bits in the interrupt 308 * register. We have to be extremely careful that we do it 309 * in such a manner that we don't get ourselves lost. 310 * XXX: Watch out! It's really easy to break this! 311 */ 312 void 313 set_clk_mode(u_char on, u_char off, int enable_clk) 314 { 315 u_char interreg; 316 317 /* 318 * If we have not yet mapped the register, 319 * then we do not want to do any of this... 320 */ 321 if (!interrupt_reg) 322 return; 323 324 #ifdef DIAGNOSTIC 325 /* Assertion: were are at splhigh! */ 326 if ((getsr() & PSL_IPL) < PSL_IPL7) 327 panic("set_clk_mode: bad ipl"); 328 #endif 329 330 /* 331 * make sure that we are only playing w/ 332 * clock interrupt register bits 333 */ 334 on &= IREG_CLK_BITS; 335 off &= IREG_CLK_BITS; 336 337 /* First, turn off the "master" enable bit. */ 338 single_inst_bclr_b(*interrupt_reg, IREG_ALL_ENAB); 339 340 /* 341 * Save the current interrupt register clock bits, 342 * and turn off/on the requested bits in the copy. 343 */ 344 interreg = *interrupt_reg & IREG_CLK_BITS; 345 interreg &= ~off; 346 interreg |= on; 347 348 /* Clear the CLK5 and CLK7 bits to clear the flip-flops. */ 349 single_inst_bclr_b(*interrupt_reg, IREG_CLK_BITS); 350 351 #ifdef SUN3_470 352 if (intersil_va) { 353 /* 354 * Then disable clock interrupts, and read the clock's 355 * interrupt register to clear any pending signals there. 356 */ 357 intersil_clock->clk_cmd_reg = 358 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE); 359 intersil_clear(); 360 } 361 #endif /* SUN3_470 */ 362 363 /* Set the requested bits in the interrupt register. */ 364 single_inst_bset_b(*interrupt_reg, interreg); 365 366 #ifdef SUN3_470 367 /* Turn the clock back on (maybe) */ 368 if (intersil_va && enable_clk) 369 intersil_clock->clk_cmd_reg = 370 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE); 371 #endif /* SUN3_470 */ 372 373 /* Finally, turn the "master" enable back on. */ 374 single_inst_bset_b(*interrupt_reg, IREG_ALL_ENAB); 375 } 376 377 /* 378 * Set up the real-time clock (enable clock interrupts). 379 * Leave stathz 0 since there is no secondary clock available. 380 * Note that clock interrupts MUST STAY DISABLED until here. 381 */ 382 void 383 cpu_initclocks(void) 384 { 385 int s; 386 387 s = splhigh(); 388 389 /* Install isr (in locore.s) that calls clock_intr(). */ 390 isr_add_custom(CLOCK_PRI, (void *)_isr_clock); 391 392 /* Now enable the clock at level 5 in the interrupt reg. */ 393 set_clk_mode(IREG_CLOCK_ENAB_5, 0, 1); 394 395 splx(s); 396 } 397 398 /* 399 * This doesn't need to do anything, as we have only one timer and 400 * profhz==stathz==hz. 401 */ 402 void 403 setstatclockrate(int newhz) 404 { 405 406 /* nothing */ 407 } 408 409 /* 410 * Clock interrupt handler (for both Intersil and Mostek). 411 * XXX - Is it worth the trouble to save a few cycles here 412 * by making two separate interrupt handlers? 413 * 414 * This is called by the "custom" interrupt handler. 415 * Note that we can get ZS interrupts while this runs, 416 * and zshard may touch the interrupt_reg, so we must 417 * be careful to use the single_inst_* macros to modify 418 * the interrupt register atomically. 419 */ 420 void 421 clock_intr(struct clockframe cf) 422 { 423 extern char _Idle[]; /* locore.s */ 424 425 idepth++; 426 427 #ifdef SUN3_470 428 if (intersil_va) { 429 /* Read the clock interrupt register. */ 430 intersil_clear(); 431 } 432 #endif /* SUN3_470 */ 433 434 /* Pulse the clock intr. enable low. */ 435 single_inst_bclr_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 436 single_inst_bset_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 437 438 #ifdef SUN3_470 439 if (intersil_va) { 440 /* Read the clock intr. reg. AGAIN! */ 441 intersil_clear(); 442 } 443 #endif /* SUN3_470 */ 444 445 intrcnt[CLOCK_PRI]++; 446 curcpu()->ci_data.cpu_nintr++; 447 448 /* Entertainment! */ 449 if (cf.cf_pc == (long)_Idle) 450 leds_intr(); 451 452 /* Call common clock interrupt handler. */ 453 hardclock(&cf); 454 455 idepth--; 456 } 457