1 1.33 tsutsui /* $NetBSD: sa11x0_ost.c,v 1.33 2019/11/13 17:52:12 tsutsui Exp $ */ 2 1.1 rjs 3 1.1 rjs /* 4 1.1 rjs * Copyright (c) 1997 Mark Brinicombe. 5 1.1 rjs * Copyright (c) 1997 Causality Limited. 6 1.1 rjs * All rights reserved. 7 1.1 rjs * 8 1.1 rjs * This code is derived from software contributed to The NetBSD Foundation 9 1.1 rjs * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 10 1.1 rjs * 11 1.1 rjs * Redistribution and use in source and binary forms, with or without 12 1.1 rjs * modification, are permitted provided that the following conditions 13 1.1 rjs * are met: 14 1.1 rjs * 1. Redistributions of source code must retain the above copyright 15 1.1 rjs * notice, this list of conditions and the following disclaimer. 16 1.1 rjs * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 rjs * notice, this list of conditions and the following disclaimer in the 18 1.1 rjs * documentation and/or other materials provided with the distribution. 19 1.25 martin * 3. All advertising materials mentioning features or use of this software 20 1.25 martin * must display the following acknowledgement: 21 1.25 martin * This product includes software developed by the NetBSD 22 1.25 martin * Foundation, Inc. and its contributors. 23 1.25 martin * 4. Neither the name of The NetBSD Foundation nor the names of its 24 1.25 martin * contributors may be used to endorse or promote products derived 25 1.25 martin * from this software without specific prior written permission. 26 1.1 rjs * 27 1.1 rjs * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 1.1 rjs * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 1.1 rjs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 1.1 rjs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 1.1 rjs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 1.1 rjs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 1.1 rjs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 1.1 rjs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 1.1 rjs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 1.1 rjs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 1.1 rjs * POSSIBILITY OF SUCH DAMAGE. 38 1.1 rjs */ 39 1.11 lukem 40 1.11 lukem #include <sys/cdefs.h> 41 1.33 tsutsui __KERNEL_RCSID(0, "$NetBSD: sa11x0_ost.c,v 1.33 2019/11/13 17:52:12 tsutsui Exp $"); 42 1.1 rjs 43 1.1 rjs #include <sys/types.h> 44 1.1 rjs #include <sys/param.h> 45 1.1 rjs #include <sys/systm.h> 46 1.1 rjs #include <sys/kernel.h> 47 1.1 rjs #include <sys/time.h> 48 1.19 peter #include <sys/timetc.h> 49 1.1 rjs #include <sys/device.h> 50 1.1 rjs 51 1.29 dyoung #include <sys/bus.h> 52 1.2 matt #include <machine/intr.h> 53 1.4 thorpej 54 1.4 thorpej #include <arm/cpufunc.h> 55 1.4 thorpej 56 1.1 rjs #include <arm/sa11x0/sa11x0_reg.h> 57 1.1 rjs #include <arm/sa11x0/sa11x0_var.h> 58 1.1 rjs #include <arm/sa11x0/sa11x0_ostreg.h> 59 1.30 nonaka #include <arm/sa11x0/sa11x0_ostvar.h> 60 1.1 rjs 61 1.26 rjs static int saost_match(device_t, cfdata_t, void *); 62 1.26 rjs static void saost_attach(device_t, device_t, void *); 63 1.1 rjs 64 1.19 peter static void saost_tc_init(void); 65 1.19 peter 66 1.19 peter static uint32_t gettick(void); 67 1.1 rjs static int clockintr(void *); 68 1.1 rjs static int statintr(void *); 69 1.1 rjs 70 1.1 rjs struct saost_softc { 71 1.26 rjs device_t sc_dev; 72 1.20 peter 73 1.1 rjs bus_space_tag_t sc_iot; 74 1.1 rjs bus_space_handle_t sc_ioh; 75 1.1 rjs 76 1.20 peter uint32_t sc_clock_count; 77 1.20 peter uint32_t sc_statclock_count; 78 1.20 peter uint32_t sc_statclock_step; 79 1.1 rjs }; 80 1.1 rjs 81 1.1 rjs static struct saost_softc *saost_sc = NULL; 82 1.1 rjs 83 1.33 tsutsui #define PXA270_OST_FREQ 3250000 /* PXA270 uses 3.25MHz */ 84 1.33 tsutsui #define SAOST_FREQ 3686400 /* Others use 3.6864MHz */ 85 1.33 tsutsui #define SAOST_MAXFREQ SAOST_FREQ 86 1.33 tsutsui 87 1.23 chris #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250) 88 1.33 tsutsui /* 89 1.33 tsutsui * On dynamic configuration, assume fastest frequency for early delay(9) 90 1.33 tsutsui * before tc_init(9), because longer delay(9) is almost harmless during 91 1.33 tsutsui * device probe and initialization. 92 1.33 tsutsui */ 93 1.27 kiyohara #include <arm/xscale/pxa2x0cpu.h> 94 1.33 tsutsui static uint32_t saost_freq = SAOST_MAXFREQ; 95 1.33 tsutsui #define TIMER_FREQUENCY saost_freq 96 1.23 chris #elif defined(CPU_XSCALE_PXA270) 97 1.33 tsutsui #define TIMER_FREQUENCY PXA270_OST_FREQ 98 1.23 chris #else 99 1.33 tsutsui #define TIMER_FREQUENCY SAOST_FREQ 100 1.23 chris #endif 101 1.1 rjs 102 1.1 rjs #ifndef STATHZ 103 1.1 rjs #define STATHZ 64 104 1.1 rjs #endif 105 1.1 rjs 106 1.26 rjs CFATTACH_DECL_NEW(saost, sizeof(struct saost_softc), 107 1.9 thorpej saost_match, saost_attach, NULL, NULL); 108 1.1 rjs 109 1.1 rjs static int 110 1.26 rjs saost_match(device_t parent, cfdata_t match, void *aux) 111 1.1 rjs { 112 1.28 kiyohara struct sa11x0_attach_args *sa = aux; 113 1.18 peter 114 1.28 kiyohara if (strcmp(sa->sa_name, match->cf_name) != 0) 115 1.28 kiyohara return 0; 116 1.18 peter return 1; 117 1.1 rjs } 118 1.1 rjs 119 1.20 peter static void 120 1.26 rjs saost_attach(device_t parent, device_t self, void *aux) 121 1.1 rjs { 122 1.26 rjs struct saost_softc *sc = device_private(self); 123 1.1 rjs struct sa11x0_attach_args *sa = aux; 124 1.1 rjs 125 1.26 rjs aprint_normal("\n"); 126 1.1 rjs 127 1.26 rjs sc->sc_dev = self; 128 1.1 rjs sc->sc_iot = sa->sa_iot; 129 1.1 rjs 130 1.1 rjs saost_sc = sc; 131 1.1 rjs 132 1.18 peter if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, 133 1.18 peter &sc->sc_ioh)) 134 1.26 rjs panic("%s: Cannot map registers", device_xname(self)); 135 1.1 rjs 136 1.1 rjs /* disable all channel and clear interrupt status */ 137 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_IR, 0); 138 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 0xf); 139 1.1 rjs 140 1.26 rjs aprint_normal_dev(self, "SA-11x0 OS Timer\n"); 141 1.1 rjs } 142 1.1 rjs 143 1.1 rjs static int 144 1.15 peter clockintr(void *arg) 145 1.1 rjs { 146 1.20 peter struct saost_softc *sc = saost_sc; 147 1.1 rjs struct clockframe *frame = arg; 148 1.16 peter uint32_t oscr, nextmatch, oldmatch; 149 1.1 rjs int s; 150 1.1 rjs 151 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 1); 152 1.1 rjs 153 1.1 rjs /* schedule next clock intr */ 154 1.20 peter oldmatch = sc->sc_clock_count; 155 1.1 rjs nextmatch = oldmatch + TIMER_FREQUENCY / hz; 156 1.1 rjs 157 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0, nextmatch); 158 1.20 peter oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 159 1.1 rjs 160 1.1 rjs if ((nextmatch > oldmatch && 161 1.1 rjs (oscr > nextmatch || oscr < oldmatch)) || 162 1.1 rjs (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 163 1.1 rjs /* 164 1.1 rjs * we couldn't set the matching register in time. 165 1.1 rjs * just set it to some value so that next interrupt happens. 166 1.18 peter * XXX is it possible to compensate lost interrupts? 167 1.1 rjs */ 168 1.1 rjs 169 1.1 rjs s = splhigh(); 170 1.20 peter oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 171 1.1 rjs nextmatch = oscr + 10; 172 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0, nextmatch); 173 1.1 rjs splx(s); 174 1.1 rjs } 175 1.1 rjs 176 1.20 peter sc->sc_clock_count = nextmatch; 177 1.1 rjs hardclock(frame); 178 1.1 rjs 179 1.18 peter return 1; 180 1.1 rjs } 181 1.1 rjs 182 1.1 rjs static int 183 1.15 peter statintr(void *arg) 184 1.1 rjs { 185 1.20 peter struct saost_softc *sc = saost_sc; 186 1.1 rjs struct clockframe *frame = arg; 187 1.16 peter uint32_t oscr, nextmatch, oldmatch; 188 1.1 rjs int s; 189 1.1 rjs 190 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 2); 191 1.1 rjs 192 1.1 rjs /* schedule next clock intr */ 193 1.20 peter oldmatch = sc->sc_statclock_count; 194 1.20 peter nextmatch = oldmatch + sc->sc_statclock_step; 195 1.1 rjs 196 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, nextmatch); 197 1.20 peter oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 198 1.1 rjs 199 1.1 rjs if ((nextmatch > oldmatch && 200 1.1 rjs (oscr > nextmatch || oscr < oldmatch)) || 201 1.1 rjs (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) { 202 1.1 rjs /* 203 1.1 rjs * we couldn't set the matching register in time. 204 1.1 rjs * just set it to some value so that next interrupt happens. 205 1.18 peter * XXX is it possible to compensate lost interrupts? 206 1.1 rjs */ 207 1.1 rjs 208 1.1 rjs s = splhigh(); 209 1.20 peter oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 210 1.1 rjs nextmatch = oscr + 10; 211 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, nextmatch); 212 1.1 rjs splx(s); 213 1.1 rjs } 214 1.1 rjs 215 1.20 peter sc->sc_statclock_count = nextmatch; 216 1.1 rjs statclock(frame); 217 1.1 rjs 218 1.18 peter return 1; 219 1.1 rjs } 220 1.1 rjs 221 1.1 rjs void 222 1.15 peter setstatclockrate(int schz) 223 1.1 rjs { 224 1.20 peter struct saost_softc *sc = saost_sc; 225 1.16 peter uint32_t count; 226 1.1 rjs 227 1.20 peter sc->sc_statclock_step = TIMER_FREQUENCY / schz; 228 1.20 peter count = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 229 1.20 peter count += sc->sc_statclock_step; 230 1.20 peter sc->sc_statclock_count = count; 231 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, count); 232 1.1 rjs } 233 1.1 rjs 234 1.1 rjs void 235 1.15 peter cpu_initclocks(void) 236 1.1 rjs { 237 1.20 peter struct saost_softc *sc = saost_sc; 238 1.20 peter 239 1.1 rjs stathz = STATHZ; 240 1.1 rjs profhz = stathz; 241 1.27 kiyohara #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250) 242 1.33 tsutsui TIMER_FREQUENCY = (CPU_IS_PXA270) ? PXA270_OST_FREQ : SAOST_FREQ; 243 1.27 kiyohara #endif 244 1.20 peter sc->sc_statclock_step = TIMER_FREQUENCY / stathz; 245 1.1 rjs 246 1.26 rjs aprint_normal("clock: hz=%d stathz=%d\n", hz, stathz); 247 1.1 rjs 248 1.1 rjs /* Use the channels 0 and 1 for hardclock and statclock, respectively */ 249 1.20 peter sc->sc_clock_count = TIMER_FREQUENCY / hz; 250 1.20 peter sc->sc_statclock_count = TIMER_FREQUENCY / stathz; 251 1.1 rjs 252 1.6 rjs sa11x0_intr_establish(0, 26, 1, IPL_CLOCK, clockintr, 0); 253 1.6 rjs sa11x0_intr_establish(0, 27, 1, IPL_CLOCK, statintr, 0); 254 1.6 rjs 255 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 0xf); 256 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_IR, 3); 257 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0, 258 1.20 peter sc->sc_clock_count); 259 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, 260 1.20 peter sc->sc_statclock_count); 261 1.1 rjs 262 1.6 rjs /* Zero the counter value */ 263 1.20 peter bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_CR, 0); 264 1.19 peter 265 1.19 peter saost_tc_init(); 266 1.19 peter } 267 1.19 peter 268 1.19 peter static u_int 269 1.19 peter saost_tc_get_timecount(struct timecounter *tc) 270 1.19 peter { 271 1.19 peter return (u_int)gettick(); 272 1.19 peter } 273 1.19 peter 274 1.19 peter static void 275 1.19 peter saost_tc_init(void) 276 1.19 peter { 277 1.19 peter static struct timecounter saost_tc = { 278 1.19 peter .tc_get_timecount = saost_tc_get_timecount, 279 1.19 peter .tc_counter_mask = ~0, 280 1.19 peter .tc_name = "saost_count", 281 1.27 kiyohara #if !(defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)) 282 1.27 kiyohara .tc_frequency = TIMER_FREQUENCY, 283 1.27 kiyohara #endif 284 1.19 peter .tc_quality = 100, 285 1.19 peter }; 286 1.19 peter 287 1.27 kiyohara #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250) 288 1.32 christos saost_tc.tc_frequency = TIMER_FREQUENCY; 289 1.27 kiyohara #endif 290 1.19 peter tc_init(&saost_tc); 291 1.1 rjs } 292 1.1 rjs 293 1.19 peter static uint32_t 294 1.15 peter gettick(void) 295 1.1 rjs { 296 1.20 peter struct saost_softc *sc = saost_sc; 297 1.20 peter uint32_t counter; 298 1.20 peter u_int saved_ints; 299 1.20 peter 300 1.20 peter saved_ints = disable_interrupts(I32_bit); 301 1.20 peter counter = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 302 1.20 peter restore_interrupts(saved_ints); 303 1.1 rjs 304 1.1 rjs return counter; 305 1.1 rjs } 306 1.1 rjs 307 1.1 rjs void 308 1.15 peter delay(u_int usecs) 309 1.1 rjs { 310 1.16 peter uint32_t xtick, otick, delta; 311 1.23 chris int csec, usec; 312 1.1 rjs 313 1.1 rjs csec = usecs / 10000; 314 1.1 rjs usec = usecs % 10000; 315 1.1 rjs 316 1.1 rjs usecs = (TIMER_FREQUENCY / 100) * csec 317 1.1 rjs + (TIMER_FREQUENCY / 100) * usec / 10000; 318 1.1 rjs 319 1.20 peter if (saost_sc == NULL) { 320 1.31 joerg volatile int k = 0; 321 1.23 chris int j; 322 1.1 rjs /* clock isn't initialized yet */ 323 1.18 peter for (; usecs > 0; usecs--) 324 1.23 chris for (j = 100; j > 0; j--, k--) 325 1.18 peter continue; 326 1.1 rjs return; 327 1.1 rjs } 328 1.1 rjs 329 1.1 rjs otick = gettick(); 330 1.1 rjs 331 1.1 rjs while (1) { 332 1.12 uwe xtick = gettick(); 333 1.12 uwe delta = xtick - otick; 334 1.1 rjs if (delta > usecs) 335 1.1 rjs break; 336 1.1 rjs usecs -= delta; 337 1.12 uwe otick = xtick; 338 1.1 rjs } 339 1.1 rjs } 340 1.30 nonaka 341 1.30 nonaka void 342 1.30 nonaka saost_reset(void) 343 1.30 nonaka { 344 1.30 nonaka struct saost_softc *sc = saost_sc; 345 1.30 nonaka uint32_t counter; 346 1.30 nonaka uint32_t saved_ints; 347 1.30 nonaka 348 1.30 nonaka saved_ints = disable_interrupts(I32_bit|F32_bit); 349 1.30 nonaka 350 1.30 nonaka counter = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR); 351 1.30 nonaka counter += TIMER_FREQUENCY; 352 1.30 nonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR3, counter); 353 1.30 nonaka 354 1.30 nonaka /* Enable watchdog */ 355 1.30 nonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_WR, 1); 356 1.30 nonaka 357 1.30 nonaka delay(1 * 1000 * 1000); 358 1.30 nonaka 359 1.30 nonaka restore_interrupts(saved_ints); 360 1.30 nonaka } 361