1 /* $NetBSD: sa11x0_ost.c,v 1.9 2002/10/02 05:02:32 thorpej 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 CFATTACH_DECL(saost, sizeof(struct saost_softc), 87 saost_match, saost_attach, NULL, NULL); 88 89 static int 90 saost_match(parent, match, aux) 91 struct device *parent; 92 struct cfdata *match; 93 void *aux; 94 { 95 return (1); 96 } 97 98 void 99 saost_attach(parent, self, aux) 100 struct device *parent; 101 struct device *self; 102 void *aux; 103 { 104 struct saost_softc *sc = (struct saost_softc*)self; 105 struct sa11x0_attach_args *sa = aux; 106 107 printf("\n"); 108 109 sc->sc_iot = sa->sa_iot; 110 sc->sc_baseaddr = sa->sa_addr; 111 112 saost_sc = sc; 113 114 if(bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, 115 &sc->sc_ioh)) 116 panic("%s: Cannot map registers", self->dv_xname); 117 118 /* disable all channel and clear interrupt status */ 119 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 0); 120 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf); 121 122 printf("%s: SA-11x0 OS Timer\n", sc->sc_dev.dv_xname); 123 } 124 125 static int 126 clockintr(arg) 127 void *arg; 128 { 129 struct clockframe *frame = arg; 130 u_int32_t oscr, nextmatch, oldmatch; 131 int s; 132 133 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 134 SAOST_SR, 1); 135 136 /* schedule next clock intr */ 137 oldmatch = saost_sc->sc_clock_count; 138 nextmatch = oldmatch + TIMER_FREQUENCY / hz; 139 140 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0, 141 nextmatch); 142 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 143 SAOST_CR); 144 145 if ((nextmatch > oldmatch && 146 (oscr > nextmatch || oscr < oldmatch)) || 147 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 148 /* 149 * we couldn't set the matching register in time. 150 * just set it to some value so that next interrupt happens. 151 * XXX is it possible to compansate lost interrupts? 152 */ 153 154 s = splhigh(); 155 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 156 SAOST_CR); 157 nextmatch = oscr + 10; 158 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 159 SAOST_MR0, nextmatch); 160 splx(s); 161 } 162 163 saost_sc->sc_clock_count = nextmatch; 164 hardclock(frame); 165 166 return(1); 167 } 168 169 static int 170 statintr(arg) 171 void *arg; 172 { 173 struct clockframe *frame = arg; 174 u_int32_t oscr, nextmatch, oldmatch; 175 int s; 176 177 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 178 SAOST_SR, 2); 179 180 /* schedule next clock intr */ 181 oldmatch = saost_sc->sc_statclock_count; 182 nextmatch = oldmatch + saost_sc->sc_statclock_step; 183 184 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1, 185 nextmatch); 186 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 187 SAOST_CR); 188 189 if ((nextmatch > oldmatch && 190 (oscr > nextmatch || oscr < oldmatch)) || 191 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 192 /* 193 * we couldn't set the matching register in time. 194 * just set it to some value so that next interrupt happens. 195 * XXX is it possible to compansate lost interrupts? 196 */ 197 198 s = splhigh(); 199 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 200 SAOST_CR); 201 nextmatch = oscr + 10; 202 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 203 SAOST_MR1, nextmatch); 204 splx(s); 205 } 206 207 saost_sc->sc_statclock_count = nextmatch; 208 statclock(frame); 209 210 return(1); 211 } 212 213 214 void 215 setstatclockrate(hz) 216 int hz; 217 { 218 u_int32_t count; 219 220 saost_sc->sc_statclock_step = TIMER_FREQUENCY / hz; 221 count = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR); 222 count += saost_sc->sc_statclock_step; 223 saost_sc->sc_statclock_count = count; 224 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, 225 SAOST_MR1, count); 226 } 227 228 void 229 cpu_initclocks() 230 { 231 stathz = STATHZ; 232 profhz = stathz; 233 saost_sc->sc_statclock_step = TIMER_FREQUENCY / stathz; 234 235 printf("clock: hz=%d stathz = %d\n", hz, stathz); 236 237 /* Use the channels 0 and 1 for hardclock and statclock, respectively */ 238 saost_sc->sc_clock_count = TIMER_FREQUENCY / hz; 239 saost_sc->sc_statclock_count = TIMER_FREQUENCY / stathz; 240 241 sa11x0_intr_establish(0, 26, 1, IPL_CLOCK, clockintr, 0); 242 sa11x0_intr_establish(0, 27, 1, IPL_CLOCK, statintr, 0); 243 244 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf); 245 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 3); 246 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0, 247 saost_sc->sc_clock_count); 248 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1, 249 saost_sc->sc_statclock_count); 250 251 /* Zero the counter value */ 252 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR, 0); 253 } 254 255 int 256 gettick() 257 { 258 int counter; 259 u_int savedints; 260 savedints = disable_interrupts(I32_bit); 261 262 counter = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 263 SAOST_CR); 264 265 restore_interrupts(savedints); 266 return counter; 267 } 268 269 void 270 microtime(tvp) 271 register struct timeval *tvp; 272 { 273 int s, tm, deltatm; 274 static struct timeval lasttime; 275 276 if(saost_sc == NULL) { 277 tvp->tv_sec = 0; 278 tvp->tv_usec = 0; 279 return; 280 } 281 282 s = splhigh(); 283 tm = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, 284 SAOST_CR); 285 286 deltatm = saost_sc->sc_clock_count - tm; 287 288 #ifdef DEBUG 289 printf("deltatm = %d\n",deltatm); 290 #endif 291 292 *tvp = time; 293 tvp->tv_usec++; /* XXX */ 294 while (tvp->tv_usec >= 1000000) { 295 tvp->tv_sec++; 296 tvp->tv_usec -= 1000000; 297 } 298 299 if (tvp->tv_sec == lasttime.tv_sec && 300 tvp->tv_usec <= lasttime.tv_usec && 301 (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) 302 { 303 tvp->tv_sec++; 304 tvp->tv_usec -= 1000000; 305 } 306 lasttime = *tvp; 307 splx(s); 308 } 309 310 void 311 delay(usecs) 312 u_int usecs; 313 { 314 u_int32_t tick, otick, delta; 315 int j, csec, usec; 316 317 csec = usecs / 10000; 318 usec = usecs % 10000; 319 320 usecs = (TIMER_FREQUENCY / 100) * csec 321 + (TIMER_FREQUENCY / 100) * usec / 10000; 322 323 if (! saost_sc) { 324 /* clock isn't initialized yet */ 325 for(; usecs > 0; usecs--) 326 for(j = 100; j > 0; j--) 327 ; 328 return; 329 } 330 331 otick = gettick(); 332 333 while (1) { 334 for(j = 100; j > 0; j--) 335 ; 336 tick = gettick(); 337 delta = tick - otick; 338 if (delta > usecs) 339 break; 340 usecs -= delta; 341 otick = tick; 342 } 343 } 344 345 void 346 resettodr() 347 { 348 } 349 350 void 351 inittodr(base) 352 time_t base; 353 { 354 time.tv_sec = base; 355 time.tv_usec = 0; 356 } 357