1 /* $NetBSD: sa11x0_ost.c,v 1.6 2002/01/08 11:40:56 rjs Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Mark Brinicombe. 5 * Copyright (c) 1997 Causality Limited. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/time.h> 45 #include <sys/device.h> 46 47 #include <machine/bus.h> 48 #include <machine/intr.h> 49 50 #include <arm/cpufunc.h> 51 52 #include <arm/arm32/katelib.h> 53 54 #include <arm/sa11x0/sa11x0_reg.h> 55 #include <arm/sa11x0/sa11x0_var.h> 56 #include <arm/sa11x0/sa11x0_ostreg.h> 57 58 static int saost_match(struct device *, struct cfdata *, void *); 59 static void saost_attach(struct device *, struct device *, void *); 60 61 int gettick(void); 62 static int clockintr(void *); 63 static int statintr(void *); 64 void rtcinit(void); 65 66 struct saost_softc { 67 struct device sc_dev; 68 bus_addr_t sc_baseaddr; 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_ioh; 71 72 u_int32_t sc_clock_count; 73 u_int32_t sc_statclock_count; 74 u_int32_t sc_statclock_step; 75 }; 76 77 static struct saost_softc *saost_sc = NULL; 78 79 #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */ 80 #define TICKS_PER_MICROSECOND (TIMER_FREQUENCY/1000000) 81 82 #ifndef STATHZ 83 #define STATHZ 64 84 #endif 85 86 struct cfattach saost_ca = { 87 sizeof(struct saost_softc), saost_match, saost_attach 88 }; 89 90 static int 91 saost_match(parent, match, aux) 92 struct device *parent; 93 struct cfdata *match; 94 void *aux; 95 { 96 return (1); 97 } 98 99 void 100 saost_attach(parent, self, aux) 101 struct device *parent; 102 struct device *self; 103 void *aux; 104 { 105 struct saost_softc *sc = (struct saost_softc*)self; 106 struct sa11x0_attach_args *sa = aux; 107 108 printf("\n"); 109 110 sc->sc_iot = sa->sa_iot; 111 sc->sc_baseaddr = sa->sa_addr; 112 113 saost_sc = sc; 114 115 if(bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, 116 &sc->sc_ioh)) 117 panic("%s: Cannot map registers\n", self->dv_xname); 118 119 /* disable all channel and clear interrupt status */ 120 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 0); 121 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf); 122 123 printf("%s: SA-11x0 OS Timer\n", sc->sc_dev.dv_xname); 124 } 125 126 static int 127 clockintr(arg) 128 void *arg; 129 { 130 struct clockframe *frame = arg; 131 u_int32_t oscr, nextmatch, oldmatch; 132 int s; 133 134 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 135 SAOST_SR, 1); 136 137 /* schedule next clock intr */ 138 oldmatch = saost_sc->sc_clock_count; 139 nextmatch = oldmatch + TIMER_FREQUENCY / hz; 140 141 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0, 142 nextmatch); 143 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 144 SAOST_CR); 145 146 if ((nextmatch > oldmatch && 147 (oscr > nextmatch || oscr < oldmatch)) || 148 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 149 /* 150 * we couldn't set the matching register in time. 151 * just set it to some value so that next interrupt happens. 152 * XXX is it possible to compansate lost interrupts? 153 */ 154 155 s = splhigh(); 156 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 157 SAOST_CR); 158 nextmatch = oscr + 10; 159 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 160 SAOST_MR0, nextmatch); 161 splx(s); 162 } 163 164 saost_sc->sc_clock_count = nextmatch; 165 hardclock(frame); 166 167 return(1); 168 } 169 170 static int 171 statintr(arg) 172 void *arg; 173 { 174 struct clockframe *frame = arg; 175 u_int32_t oscr, nextmatch, oldmatch; 176 int s; 177 178 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 179 SAOST_SR, 2); 180 181 /* schedule next clock intr */ 182 oldmatch = saost_sc->sc_statclock_count; 183 nextmatch = oldmatch + saost_sc->sc_statclock_step; 184 185 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1, 186 nextmatch); 187 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 188 SAOST_CR); 189 190 if ((nextmatch > oldmatch && 191 (oscr > nextmatch || oscr < oldmatch)) || 192 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 193 /* 194 * we couldn't set the matching register in time. 195 * just set it to some value so that next interrupt happens. 196 * XXX is it possible to compansate lost interrupts? 197 */ 198 199 s = splhigh(); 200 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 201 SAOST_CR); 202 nextmatch = oscr + 10; 203 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 204 SAOST_MR1, nextmatch); 205 splx(s); 206 } 207 208 saost_sc->sc_statclock_count = nextmatch; 209 statclock(frame); 210 211 return(1); 212 } 213 214 215 void 216 setstatclockrate(hz) 217 int hz; 218 { 219 u_int32_t count; 220 221 saost_sc->sc_statclock_step = TIMER_FREQUENCY / hz; 222 count = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR); 223 count += saost_sc->sc_statclock_step; 224 saost_sc->sc_statclock_count = count; 225 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 226 SAOST_MR1, count); 227 } 228 229 void 230 cpu_initclocks() 231 { 232 stathz = STATHZ; 233 profhz = stathz; 234 saost_sc->sc_statclock_step = TIMER_FREQUENCY / stathz; 235 236 printf("clock: hz=%d stathz = %d\n", hz, stathz); 237 238 /* Use the channels 0 and 1 for hardclock and statclock, respectively */ 239 saost_sc->sc_clock_count = TIMER_FREQUENCY / hz; 240 saost_sc->sc_statclock_count = TIMER_FREQUENCY / stathz; 241 242 sa11x0_intr_establish(0, 26, 1, IPL_CLOCK, clockintr, 0); 243 sa11x0_intr_establish(0, 27, 1, IPL_CLOCK, statintr, 0); 244 245 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf); 246 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 3); 247 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0, 248 saost_sc->sc_clock_count); 249 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1, 250 saost_sc->sc_statclock_count); 251 252 /* Zero the counter value */ 253 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR, 0); 254 } 255 256 int 257 gettick() 258 { 259 int counter; 260 u_int savedints; 261 savedints = disable_interrupts(I32_bit); 262 263 counter = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 264 SAOST_CR); 265 266 restore_interrupts(savedints); 267 return counter; 268 } 269 270 void 271 microtime(tvp) 272 register struct timeval *tvp; 273 { 274 int s, tm, deltatm; 275 static struct timeval lasttime; 276 277 if(saost_sc == NULL) { 278 tvp->tv_sec = 0; 279 tvp->tv_usec = 0; 280 return; 281 } 282 283 s = splhigh(); 284 tm = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 285 SAOST_CR); 286 287 deltatm = saost_sc->sc_clock_count - tm; 288 289 #ifdef DEBUG 290 printf("deltatm = %d\n",deltatm); 291 #endif 292 293 *tvp = time; 294 tvp->tv_usec++; /* XXX */ 295 while (tvp->tv_usec >= 1000000) { 296 tvp->tv_sec++; 297 tvp->tv_usec -= 1000000; 298 } 299 300 if (tvp->tv_sec == lasttime.tv_sec && 301 tvp->tv_usec <= lasttime.tv_usec && 302 (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) 303 { 304 tvp->tv_sec++; 305 tvp->tv_usec -= 1000000; 306 } 307 lasttime = *tvp; 308 splx(s); 309 } 310 311 void 312 delay(usecs) 313 u_int usecs; 314 { 315 u_int32_t tick, otick, delta; 316 int j, csec, usec; 317 318 csec = usecs / 10000; 319 usec = usecs % 10000; 320 321 usecs = (TIMER_FREQUENCY / 100) * csec 322 + (TIMER_FREQUENCY / 100) * usec / 10000; 323 324 if (! saost_sc) { 325 /* clock isn't initialized yet */ 326 for(; usecs > 0; usecs--) 327 for(j = 100; j > 0; j--) 328 ; 329 return; 330 } 331 332 otick = gettick(); 333 334 while (1) { 335 for(j = 100; j > 0; j--) 336 ; 337 tick = gettick(); 338 delta = tick - otick; 339 if (delta > usecs) 340 break; 341 usecs -= delta; 342 otick = tick; 343 } 344 } 345 346 void 347 resettodr() 348 { 349 } 350 351 void 352 inittodr(base) 353 time_t base; 354 { 355 time.tv_sec = base; 356 time.tv_usec = 0; 357 } 358