1 /* $NetBSD: clock.c,v 1.32 2006/10/04 15:14:49 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.32 2006/10/04 15:14:49 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(struct device *, struct cfdata *, void *); 146 static void clock_attach(struct device *, struct device *, void *); 147 148 CFATTACH_DECL(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(struct device *, struct cfdata *, void *); 158 static void oclock_attach(struct device *, struct device *, void *); 159 160 CFATTACH_DECL(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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux) 199 { 200 struct confargs *ca = aux; 201 struct intersil7170_softc *sc = (void *)self; 202 203 /* Get a mapping for it. */ 204 sc->sc_bst = ca->ca_bustag; 205 if (bus_space_map(sc->sc_bst, ca->ca_paddr, sizeof(struct intersil7170), 206 0, &sc->sc_bsh) != 0) { 207 printf(": can't map registers\n"); 208 return; 209 } 210 211 intersil_va = bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 212 213 #ifdef DIAGNOSTIC 214 /* Verify correct probe order... */ 215 if (mostek_clk_va) { 216 mostek_clk_va = NULL; 217 printf("%s: warning - mostek found also!\n", self->dv_xname); 218 } 219 #endif 220 221 /* 222 * Set the clock to the correct interrupt rate, but 223 * do not enable the interrupt until cpu_initclocks. 224 * XXX: Actually, the interrupt_reg should be zero 225 * at this point, so the clock interrupts should not 226 * affect us, but we need to set the rate... 227 */ 228 bus_space_write_1(sc->sc_bst, sc->sc_bsh, INTERSIL_ICMD, 229 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE)); 230 (void)bus_space_read_1(sc->sc_bst, sc->sc_bsh, INTERSIL_IINTR); 231 232 /* Set the clock to 100 Hz, but do not enable it yet. */ 233 bus_space_write_1(sc->sc_bst, sc->sc_bsh, 234 INTERSIL_IINTR, INTERSIL_INTER_CSECONDS); 235 236 sc->sc_year0 = 1968; 237 intersil7170_attach(sc); 238 239 printf("\n"); 240 241 todr_attach(&sc->sc_handle); 242 243 /* 244 * Can not hook up the ISR until cpu_initclocks() 245 * because hardclock is not ready until then. 246 * For now, the handler is _isr_autovec(), which 247 * will complain if it gets clock interrupts. 248 */ 249 } 250 #endif /* SUN3_470 */ 251 252 253 /* 254 * Is there a Mostek clock? Hard to tell... 255 * (See comment at top of this file.) 256 */ 257 static int 258 clock_match(struct device *parent, struct cfdata *cf, void *args) 259 { 260 struct confargs *ca = args; 261 262 /* This driver only supports one unit. */ 263 if (mostek_clk_va) 264 return 0; 265 266 /* If intersil was found, use that. */ 267 if (intersil_va) 268 return 0; 269 /* Else assume a Mostek is there... */ 270 271 /* Default interrupt priority. */ 272 if (ca->ca_intpri == -1) 273 ca->ca_intpri = CLOCK_PRI; 274 275 return 1; 276 } 277 278 /* 279 * Attach the mostek clock. 280 */ 281 static void 282 clock_attach(struct device *parent, struct device *self, void *aux) 283 { 284 struct mk48txx_softc *sc = (void *)self; 285 struct confargs *ca = aux; 286 287 sc->sc_bst = ca->ca_bustag; 288 if (bus_space_map(sc->sc_bst, ca->ca_paddr - MKCLOCK_REG_OFFSET, 289 MK48T02_CLKSZ, 0, &sc->sc_bsh) != 0) { 290 printf("can't map device space\n"); 291 return; 292 } 293 294 mostek_clk_va = (void *)(sc->sc_bsh + MKCLOCK_REG_OFFSET); /* XXX */ 295 296 sc->sc_model = "mk48t02"; 297 sc->sc_year0 = 1968; 298 299 mk48txx_attach(sc); 300 301 printf("\n"); 302 303 todr_attach(&sc->sc_handle); 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 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 #ifdef SUN3_470 426 if (intersil_va) { 427 /* Read the clock interrupt register. */ 428 intersil_clear(); 429 } 430 #endif /* SUN3_470 */ 431 432 /* Pulse the clock intr. enable low. */ 433 single_inst_bclr_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 434 single_inst_bset_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 435 436 #ifdef SUN3_470 437 if (intersil_va) { 438 /* Read the clock intr. reg. AGAIN! */ 439 intersil_clear(); 440 } 441 #endif /* SUN3_470 */ 442 443 intrcnt[CLOCK_PRI]++; 444 uvmexp.intrs++; 445 446 /* Entertainment! */ 447 if (cf.cf_pc == (long)_Idle) 448 leds_intr(); 449 450 /* Call common clock interrupt handler. */ 451 hardclock(&cf); 452 } 453