1 /* $NetBSD: clock.c,v 1.35 2008/01/26 14:02:54 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.35 2008/01/26 14:02:54 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 /* 242 * Can not hook up the ISR until cpu_initclocks() 243 * because hardclock is not ready until then. 244 * For now, the handler is _isr_autovec(), which 245 * will complain if it gets clock interrupts. 246 */ 247 } 248 #endif /* SUN3_470 */ 249 250 251 /* 252 * Is there a Mostek clock? Hard to tell... 253 * (See comment at top of this file.) 254 */ 255 static int 256 clock_match(struct device *parent, struct cfdata *cf, void *args) 257 { 258 struct confargs *ca = args; 259 260 /* This driver only supports one unit. */ 261 if (mostek_clk_va) 262 return 0; 263 264 /* If intersil was found, use that. */ 265 if (intersil_va) 266 return 0; 267 /* Else assume a Mostek is there... */ 268 269 /* Default interrupt priority. */ 270 if (ca->ca_intpri == -1) 271 ca->ca_intpri = CLOCK_PRI; 272 273 return 1; 274 } 275 276 /* 277 * Attach the mostek clock. 278 */ 279 static void 280 clock_attach(struct device *parent, struct device *self, void *aux) 281 { 282 struct mk48txx_softc *sc = (void *)self; 283 struct confargs *ca = aux; 284 285 sc->sc_bst = ca->ca_bustag; 286 if (bus_space_map(sc->sc_bst, ca->ca_paddr - MKCLOCK_REG_OFFSET, 287 MK48T02_CLKSZ, 0, &sc->sc_bsh) != 0) { 288 printf("can't map device space\n"); 289 return; 290 } 291 292 mostek_clk_va = (void *)(sc->sc_bsh + MKCLOCK_REG_OFFSET); /* XXX */ 293 294 sc->sc_model = "mk48t02"; 295 sc->sc_year0 = 1968; 296 297 mk48txx_attach(sc); 298 299 printf("\n"); 300 } 301 302 /* 303 * Set and/or clear the desired clock bits in the interrupt 304 * register. We have to be extremely careful that we do it 305 * in such a manner that we don't get ourselves lost. 306 * XXX: Watch out! It's really easy to break this! 307 */ 308 void 309 set_clk_mode(u_char on, u_char off, int enable_clk) 310 { 311 u_char interreg; 312 313 /* 314 * If we have not yet mapped the register, 315 * then we do not want to do any of this... 316 */ 317 if (!interrupt_reg) 318 return; 319 320 #ifdef DIAGNOSTIC 321 /* Assertion: were are at splhigh! */ 322 if ((getsr() & PSL_IPL) < PSL_IPL7) 323 panic("set_clk_mode: bad ipl"); 324 #endif 325 326 /* 327 * make sure that we are only playing w/ 328 * clock interrupt register bits 329 */ 330 on &= IREG_CLK_BITS; 331 off &= IREG_CLK_BITS; 332 333 /* First, turn off the "master" enable bit. */ 334 single_inst_bclr_b(*interrupt_reg, IREG_ALL_ENAB); 335 336 /* 337 * Save the current interrupt register clock bits, 338 * and turn off/on the requested bits in the copy. 339 */ 340 interreg = *interrupt_reg & IREG_CLK_BITS; 341 interreg &= ~off; 342 interreg |= on; 343 344 /* Clear the CLK5 and CLK7 bits to clear the flip-flops. */ 345 single_inst_bclr_b(*interrupt_reg, IREG_CLK_BITS); 346 347 #ifdef SUN3_470 348 if (intersil_va) { 349 /* 350 * Then disable clock interrupts, and read the clock's 351 * interrupt register to clear any pending signals there. 352 */ 353 intersil_clock->clk_cmd_reg = 354 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE); 355 intersil_clear(); 356 } 357 #endif /* SUN3_470 */ 358 359 /* Set the requested bits in the interrupt register. */ 360 single_inst_bset_b(*interrupt_reg, interreg); 361 362 #ifdef SUN3_470 363 /* Turn the clock back on (maybe) */ 364 if (intersil_va && enable_clk) 365 intersil_clock->clk_cmd_reg = 366 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE); 367 #endif /* SUN3_470 */ 368 369 /* Finally, turn the "master" enable back on. */ 370 single_inst_bset_b(*interrupt_reg, IREG_ALL_ENAB); 371 } 372 373 /* 374 * Set up the real-time clock (enable clock interrupts). 375 * Leave stathz 0 since there is no secondary clock available. 376 * Note that clock interrupts MUST STAY DISABLED until here. 377 */ 378 void 379 cpu_initclocks(void) 380 { 381 int s; 382 383 s = splhigh(); 384 385 /* Install isr (in locore.s) that calls clock_intr(). */ 386 isr_add_custom(CLOCK_PRI, (void *)_isr_clock); 387 388 /* Now enable the clock at level 5 in the interrupt reg. */ 389 set_clk_mode(IREG_CLOCK_ENAB_5, 0, 1); 390 391 splx(s); 392 } 393 394 /* 395 * This doesn't need to do anything, as we have only one timer and 396 * profhz==stathz==hz. 397 */ 398 void 399 setstatclockrate(int newhz) 400 { 401 402 /* nothing */ 403 } 404 405 /* 406 * Clock interrupt handler (for both Intersil and Mostek). 407 * XXX - Is it worth the trouble to save a few cycles here 408 * by making two separate interrupt handlers? 409 * 410 * This is is called by the "custom" interrupt handler. 411 * Note that we can get ZS interrupts while this runs, 412 * and zshard may touch the interrupt_reg, so we must 413 * be careful to use the single_inst_* macros to modify 414 * the interrupt register atomically. 415 */ 416 void 417 clock_intr(struct clockframe cf) 418 { 419 extern char _Idle[]; /* locore.s */ 420 421 idepth++; 422 423 #ifdef SUN3_470 424 if (intersil_va) { 425 /* Read the clock interrupt register. */ 426 intersil_clear(); 427 } 428 #endif /* SUN3_470 */ 429 430 /* Pulse the clock intr. enable low. */ 431 single_inst_bclr_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 432 single_inst_bset_b(*interrupt_reg, IREG_CLOCK_ENAB_5); 433 434 #ifdef SUN3_470 435 if (intersil_va) { 436 /* Read the clock intr. reg. AGAIN! */ 437 intersil_clear(); 438 } 439 #endif /* SUN3_470 */ 440 441 intrcnt[CLOCK_PRI]++; 442 uvmexp.intrs++; 443 444 /* Entertainment! */ 445 if (cf.cf_pc == (long)_Idle) 446 leds_intr(); 447 448 /* Call common clock interrupt handler. */ 449 hardclock(&cf); 450 451 idepth--; 452 } 453