1 /* $NetBSD: oclock.c,v 1.21 2021/01/24 07:36:54 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * sun4 intersil time-of-day clock driver. This chip also provides 34 * the system timer. 35 * 36 * Only 4/100's and 4/200's have this old clock device. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: oclock.c,v 1.21 2021/01/24 07:36:54 mrg Exp $"); 41 42 #include "opt_sparc_arch.h" 43 44 #include <sys/param.h> 45 #include <sys/kernel.h> 46 #include <sys/device.h> 47 #include <sys/systm.h> 48 #include <sys/bus.h> 49 50 #include <machine/promlib.h> 51 #include <machine/autoconf.h> 52 53 #include <sparc/sparc/timervar.h> 54 55 #include <dev/clock_subr.h> 56 #include <dev/ic/intersil7170reg.h> 57 #include <dev/ic/intersil7170var.h> 58 59 static int oclockmatch(device_t, cfdata_t, void *); 60 static void oclockattach(device_t, device_t, void *); 61 62 CFATTACH_DECL_NEW(oclock, sizeof(struct intersil7170_softc), 63 oclockmatch, oclockattach, NULL, NULL); 64 65 #if defined(SUN4) 66 static bus_space_tag_t i7_bt; 67 static bus_space_handle_t i7_bh; 68 69 #define intersil_disable() \ 70 bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD, \ 71 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE)); 72 73 #define intersil_enable() \ 74 bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD, \ 75 INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE)); 76 77 #define intersil_clear() bus_space_read_1(i7_bt, i7_bh, INTERSIL_IINTR) 78 79 int oclockintr(void *); 80 static struct intrhand level10 = { oclockintr }; 81 void oclock_init(void); 82 #endif /* SUN4 */ 83 84 /* 85 * old clock match routine 86 */ 87 static int 88 oclockmatch(device_t parent, cfdata_t cf, void *aux) 89 { 90 union obio_attach_args *uoba = aux; 91 struct obio4_attach_args *oba; 92 93 if (uoba->uoba_isobio4 == 0) 94 return (0); 95 96 /* Only these sun4s have oclock */ 97 if (!CPU_ISSUN4 || 98 (cpuinfo.cpu_type != CPUTYP_4_100 && 99 cpuinfo.cpu_type != CPUTYP_4_200)) 100 return (0); 101 102 /* Make sure there is something there */ 103 oba = &uoba->uoba_oba4; 104 return (bus_space_probe(oba->oba_bustag, oba->oba_paddr, 105 1, /* probe size */ 106 0, /* offset */ 107 0, /* flags */ 108 NULL, NULL)); 109 } 110 111 /* ARGSUSED */ 112 static void 113 oclockattach(device_t parent, device_t self, void *aux) 114 { 115 #if defined(SUN4) 116 struct intersil7170_softc *sc = device_private(self); 117 union obio_attach_args *uoba = aux; 118 struct obio4_attach_args *oba = &uoba->uoba_oba4; 119 120 oldclk = 1; /* we've got an oldie! */ 121 122 sc->sc_dev = self; 123 sc->sc_bst = oba->oba_bustag; 124 if (bus_space_map(sc->sc_bst, 125 oba->oba_paddr, 126 sizeof(struct intersil7170), 127 BUS_SPACE_MAP_LINEAR, /* flags */ 128 &sc->sc_bsh) != 0) { 129 aprint_error(": can't map register\n"); 130 return; 131 } 132 i7_bt = sc->sc_bst; 133 i7_bh = sc->sc_bsh; 134 135 /* 136 * calibrate delay() 137 */ 138 ienab_bic(IE_L14 | IE_L10); /* disable all clock intrs */ 139 for (timerblurb = 1; ; timerblurb++) { 140 int ival; 141 142 /* Set to 1/100 second interval */ 143 bus_space_write_1(sc->sc_bst, sc->sc_bsh, INTERSIL_IINTR, 144 INTERSIL_INTER_CSECONDS); 145 146 /* enable clock */ 147 intersil_enable(); 148 149 while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0) 150 /* sync with interrupt */; 151 while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0) 152 /* XXX: do it again, seems to need it */; 153 154 /* Probe 1/100 sec delay */ 155 delay(10000); 156 157 /* clear, save value */ 158 ival = intersil_clear(); 159 160 /* disable clock */ 161 intersil_disable(); 162 163 if ((ival & INTERSIL_INTER_PENDING) != 0) { 164 aprint_normal(" delay constant %d%s\n", timerblurb, 165 (timerblurb == 1) ? " [TOO SMALL?]" : ""); 166 break; 167 } 168 if (timerblurb > 10) { 169 aprint_normal("\n"); 170 aprint_error_dev(self, "calibration failing; " 171 "clamped at %d\n", timerblurb); 172 break; 173 } 174 } 175 176 timer_init = oclock_init; 177 178 /* link interrupt handler */ 179 intr_establish(10, 0, &level10, NULL, false); 180 181 /* Our TOD clock year 0 represents 1968 */ 182 sc->sc_year0 = 1968; 183 intersil7170_attach(sc); 184 185 aprint_normal("\n"); 186 #endif /* SUN4 */ 187 } 188 189 #if defined(SUN4) 190 /* 191 * Set up the real-time and statistics clocks. 192 * Leave stathz 0 only if no alternative timer is available. 193 * 194 * The frequencies of these clocks must be an even number of microseconds. 195 */ 196 void 197 oclock_init(void) 198 { 199 200 profhz = hz = 100; 201 tick = 1000000 / hz; 202 203 /* Select 1/100 second interval */ 204 bus_space_write_1(i7_bt, i7_bh, INTERSIL_IINTR, 205 INTERSIL_INTER_CSECONDS); 206 207 ienab_bic(IE_L14 | IE_L10); /* disable all clock intrs */ 208 intersil_disable(); /* disable clock */ 209 (void)intersil_clear(); /* clear interrupts */ 210 ienab_bis(IE_L10); /* enable l10 interrupt */ 211 intersil_enable(); /* enable clock */ 212 } 213 214 /* 215 * Level 10 (clock) interrupts from system counter. 216 * If we are using the FORTH PROM for console input, we need to check 217 * for that here as well, and generate a software interrupt to read it. 218 */ 219 int 220 oclockintr(void *cap) 221 { 222 int s; 223 224 /* 225 * Protect the clearing of the clock interrupt. If we don't 226 * do this, and we're interrupted (by the zs, for example), 227 * the clock stops! 228 * XXX WHY DOES THIS HAPPEN? 229 */ 230 s = splhigh(); 231 232 (void)intersil_clear(); 233 ienab_bic(IE_L10); /* clear interrupt */ 234 ienab_bis(IE_L10); /* enable interrupt */ 235 splx(s); 236 237 hardclock((struct clockframe *)cap); 238 return (1); 239 } 240 #endif /* SUN4 */ 241