Wed Mar 4 23:18:21 2015 UTC ()
print "A5" instead of "A9" at attach time if running on a Cortex-A5


(jmcneill)
diff -r1.11 -r1.12 src/sys/arch/arm/cortex/a9tmr.c
diff -r1.3 -r1.4 src/sys/arch/arm/cortex/a9wdt.c

cvs diff -r1.11 -r1.12 src/sys/arch/arm/cortex/a9tmr.c (switch to unified diff)

--- src/sys/arch/arm/cortex/a9tmr.c 2015/02/27 18:26:49 1.11
+++ src/sys/arch/arm/cortex/a9tmr.c 2015/03/04 23:18:21 1.12
@@ -1,363 +1,369 @@ @@ -1,363 +1,369 @@
1/* $NetBSD: a9tmr.c,v 1.11 2015/02/27 18:26:49 jmcneill Exp $ */ 1/* $NetBSD: a9tmr.c,v 1.12 2015/03/04 23:18:21 jmcneill Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas 8 * by Matt Thomas
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: a9tmr.c,v 1.11 2015/02/27 18:26:49 jmcneill Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: a9tmr.c,v 1.12 2015/03/04 23:18:21 jmcneill Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/bus.h> 36#include <sys/bus.h>
37#include <sys/device.h> 37#include <sys/device.h>
38#include <sys/intr.h> 38#include <sys/intr.h>
39#include <sys/kernel.h> 39#include <sys/kernel.h>
40#include <sys/proc.h> 40#include <sys/proc.h>
41#include <sys/systm.h> 41#include <sys/systm.h>
42#include <sys/timetc.h> 42#include <sys/timetc.h>
43#include <sys/xcall.h> 43#include <sys/xcall.h>
44 44
45#include <prop/proplib.h> 45#include <prop/proplib.h>
46 46
47#include <arm/cortex/a9tmr_reg.h> 47#include <arm/cortex/a9tmr_reg.h>
48#include <arm/cortex/a9tmr_var.h> 48#include <arm/cortex/a9tmr_var.h>
49 49
50#include <arm/cortex/mpcore_var.h> 50#include <arm/cortex/mpcore_var.h>
51 51
52static int a9tmr_match(device_t, cfdata_t, void *); 52static int a9tmr_match(device_t, cfdata_t, void *);
53static void a9tmr_attach(device_t, device_t, void *); 53static void a9tmr_attach(device_t, device_t, void *);
54 54
55static int clockhandler(void *); 55static int clockhandler(void *);
56 56
57static u_int a9tmr_get_timecount(struct timecounter *); 57static u_int a9tmr_get_timecount(struct timecounter *);
58 58
59static struct a9tmr_softc a9tmr_sc; 59static struct a9tmr_softc a9tmr_sc;
60 60
61static struct timecounter a9tmr_timecounter = { 61static struct timecounter a9tmr_timecounter = {
62 .tc_get_timecount = a9tmr_get_timecount, 62 .tc_get_timecount = a9tmr_get_timecount,
63 .tc_poll_pps = 0, 63 .tc_poll_pps = 0,
64 .tc_counter_mask = ~0u, 64 .tc_counter_mask = ~0u,
65 .tc_frequency = 0, /* set by cpu_initclocks() */ 65 .tc_frequency = 0, /* set by cpu_initclocks() */
66 .tc_name = NULL, /* set by attach */ 66 .tc_name = NULL, /* set by attach */
67 .tc_quality = 500, 67 .tc_quality = 500,
68 .tc_priv = &a9tmr_sc, 68 .tc_priv = &a9tmr_sc,
69 .tc_next = NULL, 69 .tc_next = NULL,
70}; 70};
71 71
72CFATTACH_DECL_NEW(a9tmr, 0, a9tmr_match, a9tmr_attach, NULL, NULL); 72CFATTACH_DECL_NEW(a9tmr, 0, a9tmr_match, a9tmr_attach, NULL, NULL);
73 73
74static inline uint32_t 74static inline uint32_t
75a9tmr_global_read(struct a9tmr_softc *sc, bus_size_t o) 75a9tmr_global_read(struct a9tmr_softc *sc, bus_size_t o)
76{ 76{
77 return bus_space_read_4(sc->sc_memt, sc->sc_global_memh, o); 77 return bus_space_read_4(sc->sc_memt, sc->sc_global_memh, o);
78} 78}
79 79
80static inline void 80static inline void
81a9tmr_global_write(struct a9tmr_softc *sc, bus_size_t o, uint32_t v) 81a9tmr_global_write(struct a9tmr_softc *sc, bus_size_t o, uint32_t v)
82{ 82{
83 bus_space_write_4(sc->sc_memt, sc->sc_global_memh, o, v); 83 bus_space_write_4(sc->sc_memt, sc->sc_global_memh, o, v);
84} 84}
85 85
86 86
87/* ARGSUSED */ 87/* ARGSUSED */
88static int 88static int
89a9tmr_match(device_t parent, cfdata_t cf, void *aux) 89a9tmr_match(device_t parent, cfdata_t cf, void *aux)
90{ 90{
91 struct mpcore_attach_args * const mpcaa = aux; 91 struct mpcore_attach_args * const mpcaa = aux;
92 92
93 if (a9tmr_sc.sc_dev != NULL) 93 if (a9tmr_sc.sc_dev != NULL)
94 return 0; 94 return 0;
95 95
96 if ((armreg_pfr1_read() & ARM_PFR1_GTIMER_MASK) != 0) 96 if ((armreg_pfr1_read() & ARM_PFR1_GTIMER_MASK) != 0)
97 return 0; 97 return 0;
98 98
99 if (!CPU_ID_CORTEX_A9_P(curcpu()->ci_arm_cpuid) && 99 if (!CPU_ID_CORTEX_A9_P(curcpu()->ci_arm_cpuid) &&
100 !CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid)) 100 !CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid))
101 return 0; 101 return 0;
102 102
103 if (strcmp(mpcaa->mpcaa_name, cf->cf_name) != 0) 103 if (strcmp(mpcaa->mpcaa_name, cf->cf_name) != 0)
104 return 0; 104 return 0;
105 105
106 /* 106 /*
107 * This isn't present on UP A9s (since CBAR isn't present). 107 * This isn't present on UP A9s (since CBAR isn't present).
108 */ 108 */
109 uint32_t mpidr = armreg_mpidr_read(); 109 uint32_t mpidr = armreg_mpidr_read();
110 if (mpidr == 0 || (mpidr & MPIDR_U)) 110 if (mpidr == 0 || (mpidr & MPIDR_U))
111 return 0; 111 return 0;
112 112
113 return 1; 113 return 1;
114} 114}
115 115
116static void 116static void
117a9tmr_attach(device_t parent, device_t self, void *aux) 117a9tmr_attach(device_t parent, device_t self, void *aux)
118{ 118{
119 struct a9tmr_softc *sc = &a9tmr_sc; 119 struct a9tmr_softc *sc = &a9tmr_sc;
120 struct mpcore_attach_args * const mpcaa = aux; 120 struct mpcore_attach_args * const mpcaa = aux;
121 prop_dictionary_t dict = device_properties(self); 121 prop_dictionary_t dict = device_properties(self);
122 char freqbuf[sizeof("XXX SHz")]; 122 char freqbuf[sizeof("XXX SHz")];
 123 const char *cpu_type;
123 124
124 /* 125 /*
125 * This runs at the ARM PERIPHCLOCK which should be 1/2 of the CPU clock. 126 * This runs at the ARM PERIPHCLOCK which should be 1/2 of the CPU clock.
126 * The MD code should have setup our frequency for us. 127 * The MD code should have setup our frequency for us.
127 */ 128 */
128 prop_dictionary_get_uint32(dict, "frequency", &sc->sc_freq); 129 prop_dictionary_get_uint32(dict, "frequency", &sc->sc_freq);
129 130
130 humanize_number(freqbuf, sizeof(freqbuf), sc->sc_freq, "Hz", 1000); 131 humanize_number(freqbuf, sizeof(freqbuf), sc->sc_freq, "Hz", 1000);
131 132
132 aprint_naive("\n"); 133 aprint_naive("\n");
133 aprint_normal(": A9 Global 64-bit Timer (%s)\n", freqbuf); 134 if (CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid)) {
 135 cpu_type = "A5";
 136 } else {
 137 cpu_type = "A9";
 138 }
 139 aprint_normal(": %s Global 64-bit Timer (%s)\n", cpu_type, freqbuf);
134 140
135 self->dv_private = sc; 141 self->dv_private = sc;
136 sc->sc_dev = self; 142 sc->sc_dev = self;
137 sc->sc_memt = mpcaa->mpcaa_memt; 143 sc->sc_memt = mpcaa->mpcaa_memt;
138 sc->sc_memh = mpcaa->mpcaa_memh; 144 sc->sc_memh = mpcaa->mpcaa_memh;
139 145
140 evcnt_attach_dynamic(&sc->sc_ev_missing_ticks, EVCNT_TYPE_MISC, NULL, 146 evcnt_attach_dynamic(&sc->sc_ev_missing_ticks, EVCNT_TYPE_MISC, NULL,
141 device_xname(self), "missing interrupts"); 147 device_xname(self), "missing interrupts");
142 148
143 bus_space_subregion(sc->sc_memt, sc->sc_memh,  149 bus_space_subregion(sc->sc_memt, sc->sc_memh,
144 TMR_GLOBAL_BASE, TMR_GLOBAL_SIZE, &sc->sc_global_memh); 150 TMR_GLOBAL_BASE, TMR_GLOBAL_SIZE, &sc->sc_global_memh);
145 bus_space_subregion(sc->sc_memt, sc->sc_memh,  151 bus_space_subregion(sc->sc_memt, sc->sc_memh,
146 TMR_PRIVATE_BASE, TMR_PRIVATE_SIZE, &sc->sc_private_memh); 152 TMR_PRIVATE_BASE, TMR_PRIVATE_SIZE, &sc->sc_private_memh);
147 bus_space_subregion(sc->sc_memt, sc->sc_memh,  153 bus_space_subregion(sc->sc_memt, sc->sc_memh,
148 TMR_WDOG_BASE, TMR_WDOG_SIZE, &sc->sc_wdog_memh); 154 TMR_WDOG_BASE, TMR_WDOG_SIZE, &sc->sc_wdog_memh);
149 155
150 sc->sc_global_ih = intr_establish(IRQ_A9TMR_PPI_GTIMER, IPL_CLOCK, 156 sc->sc_global_ih = intr_establish(IRQ_A9TMR_PPI_GTIMER, IPL_CLOCK,
151 IST_EDGE | IST_MPSAFE, clockhandler, NULL); 157 IST_EDGE | IST_MPSAFE, clockhandler, NULL);
152 if (sc->sc_global_ih == NULL) 158 if (sc->sc_global_ih == NULL)
153 panic("%s: unable to register timer interrupt", __func__); 159 panic("%s: unable to register timer interrupt", __func__);
154 aprint_normal_dev(sc->sc_dev, "interrupting on irq %d\n", 160 aprint_normal_dev(sc->sc_dev, "interrupting on irq %d\n",
155 IRQ_A9TMR_PPI_GTIMER); 161 IRQ_A9TMR_PPI_GTIMER);
156} 162}
157 163
158static inline uint64_t 164static inline uint64_t
159a9tmr_gettime(struct a9tmr_softc *sc) 165a9tmr_gettime(struct a9tmr_softc *sc)
160{ 166{
161 uint32_t lo, hi; 167 uint32_t lo, hi;
162 168
163 do { 169 do {
164 hi = a9tmr_global_read(sc, TMR_GBL_CTR_U); 170 hi = a9tmr_global_read(sc, TMR_GBL_CTR_U);
165 lo = a9tmr_global_read(sc, TMR_GBL_CTR_L); 171 lo = a9tmr_global_read(sc, TMR_GBL_CTR_L);
166 } while (hi != a9tmr_global_read(sc, TMR_GBL_CTR_U)); 172 } while (hi != a9tmr_global_read(sc, TMR_GBL_CTR_U));
167 173
168 return ((uint64_t)hi << 32) | lo; 174 return ((uint64_t)hi << 32) | lo;
169} 175}
170 176
171void 177void
172a9tmr_init_cpu_clock(struct cpu_info *ci) 178a9tmr_init_cpu_clock(struct cpu_info *ci)
173{ 179{
174 struct a9tmr_softc * const sc = &a9tmr_sc; 180 struct a9tmr_softc * const sc = &a9tmr_sc;
175 uint64_t now = a9tmr_gettime(sc); 181 uint64_t now = a9tmr_gettime(sc);
176 182
177 KASSERT(ci == curcpu()); 183 KASSERT(ci == curcpu());
178 184
179 ci->ci_lastintr = now; 185 ci->ci_lastintr = now;
180 186
181 a9tmr_global_write(sc, TMR_GBL_AUTOINC, sc->sc_autoinc); 187 a9tmr_global_write(sc, TMR_GBL_AUTOINC, sc->sc_autoinc);
182 188
183 /* 189 /*
184 * To update the compare register we have to disable comparisions first. 190 * To update the compare register we have to disable comparisions first.
185 */ 191 */
186 uint32_t ctl = a9tmr_global_read(sc, TMR_GBL_CTL); 192 uint32_t ctl = a9tmr_global_read(sc, TMR_GBL_CTL);
187 if (ctl & TMR_GBL_CTL_CMP_ENABLE) { 193 if (ctl & TMR_GBL_CTL_CMP_ENABLE) {
188 a9tmr_global_write(sc, TMR_GBL_CTL, ctl & ~TMR_GBL_CTL_CMP_ENABLE); 194 a9tmr_global_write(sc, TMR_GBL_CTL, ctl & ~TMR_GBL_CTL_CMP_ENABLE);
189 } 195 }
190 196
191 /* 197 /*
192 * Schedule the next interrupt. 198 * Schedule the next interrupt.
193 */ 199 */
194 now += sc->sc_autoinc; 200 now += sc->sc_autoinc;
195 a9tmr_global_write(sc, TMR_GBL_CMP_L, (uint32_t) now); 201 a9tmr_global_write(sc, TMR_GBL_CMP_L, (uint32_t) now);
196 a9tmr_global_write(sc, TMR_GBL_CMP_H, (uint32_t) (now >> 32)); 202 a9tmr_global_write(sc, TMR_GBL_CMP_H, (uint32_t) (now >> 32));
197 203
198 /* 204 /*
199 * Re-enable the comparator and now enable interrupts. 205 * Re-enable the comparator and now enable interrupts.
200 */ 206 */
201 a9tmr_global_write(sc, TMR_GBL_INT, 1); /* clear interrupt pending */ 207 a9tmr_global_write(sc, TMR_GBL_INT, 1); /* clear interrupt pending */
202 ctl |= TMR_GBL_CTL_CMP_ENABLE | TMR_GBL_CTL_INT_ENABLE | TMR_GBL_CTL_AUTO_INC | TMR_CTL_ENABLE; 208 ctl |= TMR_GBL_CTL_CMP_ENABLE | TMR_GBL_CTL_INT_ENABLE | TMR_GBL_CTL_AUTO_INC | TMR_CTL_ENABLE;
203 a9tmr_global_write(sc, TMR_GBL_CTL, ctl); 209 a9tmr_global_write(sc, TMR_GBL_CTL, ctl);
204#if 0 210#if 0
205 printf("%s: %s: ctl %#x autoinc %u cmp %#x%08x now %#"PRIx64"\n", 211 printf("%s: %s: ctl %#x autoinc %u cmp %#x%08x now %#"PRIx64"\n",
206 __func__, ci->ci_data.cpu_name, 212 __func__, ci->ci_data.cpu_name,
207 a9tmr_global_read(sc, TMR_GBL_CTL), 213 a9tmr_global_read(sc, TMR_GBL_CTL),
208 a9tmr_global_read(sc, TMR_GBL_AUTOINC), 214 a9tmr_global_read(sc, TMR_GBL_AUTOINC),
209 a9tmr_global_read(sc, TMR_GBL_CMP_H), 215 a9tmr_global_read(sc, TMR_GBL_CMP_H),
210 a9tmr_global_read(sc, TMR_GBL_CMP_L), 216 a9tmr_global_read(sc, TMR_GBL_CMP_L),
211 a9tmr_gettime(sc)); 217 a9tmr_gettime(sc));
212 218
213 int s = splsched(); 219 int s = splsched();
214 uint64_t when = now; 220 uint64_t when = now;
215 u_int n = 0; 221 u_int n = 0;
216 while ((now = a9tmr_gettime(sc)) < when) { 222 while ((now = a9tmr_gettime(sc)) < when) {
217 /* spin */ 223 /* spin */
218 n++; 224 n++;
219 KASSERTMSG(n <= sc->sc_autoinc, 225 KASSERTMSG(n <= sc->sc_autoinc,
220 "spun %u times but only %"PRIu64" has passed", 226 "spun %u times but only %"PRIu64" has passed",
221 n, when - now); 227 n, when - now);
222 } 228 }
223 printf("%s: %s: status %#x cmp %#x%08x now %#"PRIx64"\n", 229 printf("%s: %s: status %#x cmp %#x%08x now %#"PRIx64"\n",
224 __func__, ci->ci_data.cpu_name, 230 __func__, ci->ci_data.cpu_name,
225 a9tmr_global_read(sc, TMR_GBL_INT), 231 a9tmr_global_read(sc, TMR_GBL_INT),
226 a9tmr_global_read(sc, TMR_GBL_CMP_H), 232 a9tmr_global_read(sc, TMR_GBL_CMP_H),
227 a9tmr_global_read(sc, TMR_GBL_CMP_L), 233 a9tmr_global_read(sc, TMR_GBL_CMP_L),
228 a9tmr_gettime(sc)); 234 a9tmr_gettime(sc));
229 splx(s); 235 splx(s);
230#elif 0 236#elif 0
231 delay(1000000 / hz + 1000);  237 delay(1000000 / hz + 1000);
232#endif 238#endif
233} 239}
234 240
235void 241void
236cpu_initclocks(void) 242cpu_initclocks(void)
237{ 243{
238 struct a9tmr_softc * const sc = &a9tmr_sc; 244 struct a9tmr_softc * const sc = &a9tmr_sc;
239  245
240 KASSERT(sc->sc_dev != NULL); 246 KASSERT(sc->sc_dev != NULL);
241 KASSERT(sc->sc_freq != 0); 247 KASSERT(sc->sc_freq != 0);
242 248
243 sc->sc_autoinc = sc->sc_freq / hz; 249 sc->sc_autoinc = sc->sc_freq / hz;
244 250
245 a9tmr_init_cpu_clock(curcpu()); 251 a9tmr_init_cpu_clock(curcpu());
246 252
247 a9tmr_timecounter.tc_name = device_xname(sc->sc_dev); 253 a9tmr_timecounter.tc_name = device_xname(sc->sc_dev);
248 a9tmr_timecounter.tc_frequency = sc->sc_freq; 254 a9tmr_timecounter.tc_frequency = sc->sc_freq;
249 255
250 tc_init(&a9tmr_timecounter); 256 tc_init(&a9tmr_timecounter);
251} 257}
252 258
253static void 259static void
254a9tmr_update_freq_cb(void *arg1, void *arg2) 260a9tmr_update_freq_cb(void *arg1, void *arg2)
255{ 261{
256 a9tmr_init_cpu_clock(curcpu()); 262 a9tmr_init_cpu_clock(curcpu());
257} 263}
258 264
259void 265void
260a9tmr_update_freq(uint32_t freq) 266a9tmr_update_freq(uint32_t freq)
261{ 267{
262 struct a9tmr_softc * const sc = &a9tmr_sc; 268 struct a9tmr_softc * const sc = &a9tmr_sc;
263 uint64_t xc; 269 uint64_t xc;
264 270
265 KASSERT(sc->sc_dev != NULL); 271 KASSERT(sc->sc_dev != NULL);
266 KASSERT(freq != 0); 272 KASSERT(freq != 0);
267 273
268 tc_detach(&a9tmr_timecounter); 274 tc_detach(&a9tmr_timecounter);
269 275
270 sc->sc_freq = freq; 276 sc->sc_freq = freq;
271 sc->sc_autoinc = sc->sc_freq / hz; 277 sc->sc_autoinc = sc->sc_freq / hz;
272 278
273 xc = xc_broadcast(0, a9tmr_update_freq_cb, NULL, NULL); 279 xc = xc_broadcast(0, a9tmr_update_freq_cb, NULL, NULL);
274 xc_wait(xc); 280 xc_wait(xc);
275 281
276 a9tmr_timecounter.tc_frequency = sc->sc_freq; 282 a9tmr_timecounter.tc_frequency = sc->sc_freq;
277 tc_init(&a9tmr_timecounter); 283 tc_init(&a9tmr_timecounter);
278} 284}
279 285
280void 286void
281a9tmr_delay(unsigned int n) 287a9tmr_delay(unsigned int n)
282{ 288{
283 struct a9tmr_softc * const sc = &a9tmr_sc; 289 struct a9tmr_softc * const sc = &a9tmr_sc;
284 290
285 KASSERT(sc != NULL); 291 KASSERT(sc != NULL);
286 292
287 uint32_t freq = sc->sc_freq ? sc->sc_freq : curcpu()->ci_data.cpu_cc_freq / 2; 293 uint32_t freq = sc->sc_freq ? sc->sc_freq : curcpu()->ci_data.cpu_cc_freq / 2;
288 KASSERT(freq != 0); 294 KASSERT(freq != 0);
289 295
290 /* 296 /*
291 * not quite divide by 1000000 but close enough 297 * not quite divide by 1000000 but close enough
292 * (higher by 1.3% which means we wait 1.3% longer). 298 * (higher by 1.3% which means we wait 1.3% longer).
293 */ 299 */
294 const uint64_t incr_per_us = (freq >> 20) + (freq >> 24); 300 const uint64_t incr_per_us = (freq >> 20) + (freq >> 24);
295 301
296 const uint64_t delta = n * incr_per_us; 302 const uint64_t delta = n * incr_per_us;
297 const uint64_t base = a9tmr_gettime(sc); 303 const uint64_t base = a9tmr_gettime(sc);
298 const uint64_t finish = base + delta; 304 const uint64_t finish = base + delta;
299 305
300 while (a9tmr_gettime(sc) < finish) { 306 while (a9tmr_gettime(sc) < finish) {
301 /* spin */ 307 /* spin */
302 } 308 }
303} 309}
304 310
305/* 311/*
306 * clockhandler: 312 * clockhandler:
307 * 313 *
308 * Handle the hardclock interrupt. 314 * Handle the hardclock interrupt.
309 */ 315 */
310static int 316static int
311clockhandler(void *arg) 317clockhandler(void *arg)
312{ 318{
313 struct clockframe * const cf = arg; 319 struct clockframe * const cf = arg;
314 struct a9tmr_softc * const sc = &a9tmr_sc; 320 struct a9tmr_softc * const sc = &a9tmr_sc;
315 struct cpu_info * const ci = curcpu(); 321 struct cpu_info * const ci = curcpu();
316  322
317 const uint64_t now = a9tmr_gettime(sc); 323 const uint64_t now = a9tmr_gettime(sc);
318 uint64_t delta = now - ci->ci_lastintr; 324 uint64_t delta = now - ci->ci_lastintr;
319 325
320 a9tmr_global_write(sc, TMR_GBL_INT, 1); // Ack the interrupt 326 a9tmr_global_write(sc, TMR_GBL_INT, 1); // Ack the interrupt
321 327
322#if 0 328#if 0
323 printf("%s(%p): %s: now %#"PRIx64" delta %"PRIu64"\n",  329 printf("%s(%p): %s: now %#"PRIx64" delta %"PRIu64"\n",
324 __func__, cf, ci->ci_data.cpu_name, now, delta); 330 __func__, cf, ci->ci_data.cpu_name, now, delta);
325#endif 331#endif
326 KASSERTMSG(delta > sc->sc_autoinc / 100, 332 KASSERTMSG(delta > sc->sc_autoinc / 100,
327 "%s: interrupting too quickly (delta=%"PRIu64")", 333 "%s: interrupting too quickly (delta=%"PRIu64")",
328 ci->ci_data.cpu_name, delta); 334 ci->ci_data.cpu_name, delta);
329 335
330 ci->ci_lastintr = now; 336 ci->ci_lastintr = now;
331 337
332 hardclock(cf); 338 hardclock(cf);
333 339
334#if 0 340#if 0
335 /* 341 /*
336 * Try to make up up to a seconds amount of missed clock interrupts 342 * Try to make up up to a seconds amount of missed clock interrupts
337 */ 343 */
338 u_int ticks = hz; 344 u_int ticks = hz;
339 for (delta -= sc->sc_autoinc; 345 for (delta -= sc->sc_autoinc;
340 ticks > 0 && delta >= sc->sc_autoinc; 346 ticks > 0 && delta >= sc->sc_autoinc;
341 delta -= sc->sc_autoinc, ticks--) { 347 delta -= sc->sc_autoinc, ticks--) {
342 hardclock(cf); 348 hardclock(cf);
343 } 349 }
344#else 350#else
345 if (delta > sc->sc_autoinc) 351 if (delta > sc->sc_autoinc)
346 sc->sc_ev_missing_ticks.ev_count += delta / sc->sc_autoinc; 352 sc->sc_ev_missing_ticks.ev_count += delta / sc->sc_autoinc;
347#endif 353#endif
348 354
349 return 1; 355 return 1;
350} 356}
351 357
352void 358void
353setstatclockrate(int newhz) 359setstatclockrate(int newhz)
354{ 360{
355} 361}
356 362
357static u_int 363static u_int
358a9tmr_get_timecount(struct timecounter *tc) 364a9tmr_get_timecount(struct timecounter *tc)
359{ 365{
360 struct a9tmr_softc * const sc = tc->tc_priv; 366 struct a9tmr_softc * const sc = tc->tc_priv;
361 367
362 return (u_int) (a9tmr_gettime(sc)); 368 return (u_int) (a9tmr_gettime(sc));
363} 369}

cvs diff -r1.3 -r1.4 src/sys/arch/arm/cortex/a9wdt.c (switch to unified diff)

--- src/sys/arch/arm/cortex/a9wdt.c 2015/02/27 18:43:28 1.3
+++ src/sys/arch/arm/cortex/a9wdt.c 2015/03/04 23:18:21 1.4
@@ -1,250 +1,256 @@ @@ -1,250 +1,256 @@
1/* $NetBSD: a9wdt.c,v 1.3 2015/02/27 18:43:28 jmcneill Exp $ */ 1/* $NetBSD: a9wdt.c,v 1.4 2015/03/04 23:18:21 jmcneill Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas 8 * by Matt Thomas
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: a9wdt.c,v 1.3 2015/02/27 18:43:28 jmcneill Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: a9wdt.c,v 1.4 2015/03/04 23:18:21 jmcneill Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/bus.h> 36#include <sys/bus.h>
37#include <sys/cpu.h> 37#include <sys/cpu.h>
38#include <sys/device.h> 38#include <sys/device.h>
39#include <sys/wdog.h> 39#include <sys/wdog.h>
40 40
41#include <prop/proplib.h> 41#include <prop/proplib.h>
42 42
43#include <dev/sysmon/sysmonvar.h> 43#include <dev/sysmon/sysmonvar.h>
44 44
45#include <arm/cortex/a9tmr_reg.h> 45#include <arm/cortex/a9tmr_reg.h>
46 46
47#include <arm/cortex/mpcore_var.h> 47#include <arm/cortex/mpcore_var.h>
48 48
49static int a9wdt_match(device_t, cfdata_t, void *); 49static int a9wdt_match(device_t, cfdata_t, void *);
50static void a9wdt_attach(device_t, device_t, void *); 50static void a9wdt_attach(device_t, device_t, void *);
51 51
52struct a9wdt_softc { 52struct a9wdt_softc {
53 struct sysmon_wdog sc_smw; 53 struct sysmon_wdog sc_smw;
54 device_t sc_dev; 54 device_t sc_dev;
55 bus_space_tag_t sc_memt; 55 bus_space_tag_t sc_memt;
56 bus_space_handle_t sc_wdog_memh; 56 bus_space_handle_t sc_wdog_memh;
57 u_int sc_wdog_max_period; 57 u_int sc_wdog_max_period;
58 u_int sc_wdog_period; 58 u_int sc_wdog_period;
59 u_int sc_wdog_prescaler; 59 u_int sc_wdog_prescaler;
60 uint32_t sc_freq; 60 uint32_t sc_freq;
61 uint32_t sc_wdog_load; 61 uint32_t sc_wdog_load;
62 uint32_t sc_wdog_ctl; 62 uint32_t sc_wdog_ctl;
63 bool sc_wdog_armed; 63 bool sc_wdog_armed;
64}; 64};
65 65
66#ifndef A9WDT_PERIOD_DEFAULT 66#ifndef A9WDT_PERIOD_DEFAULT
67#define A9WDT_PERIOD_DEFAULT 12 67#define A9WDT_PERIOD_DEFAULT 12
68#endif 68#endif
69 69
70CFATTACH_DECL_NEW(a9wdt, sizeof(struct a9wdt_softc), 70CFATTACH_DECL_NEW(a9wdt, sizeof(struct a9wdt_softc),
71 a9wdt_match, a9wdt_attach, NULL, NULL); 71 a9wdt_match, a9wdt_attach, NULL, NULL);
72 72
73static bool attached; 73static bool attached;
74 74
75static inline uint32_t 75static inline uint32_t
76a9wdt_wdog_read(struct a9wdt_softc *sc, bus_size_t o) 76a9wdt_wdog_read(struct a9wdt_softc *sc, bus_size_t o)
77{ 77{
78 return bus_space_read_4(sc->sc_memt, sc->sc_wdog_memh, o); 78 return bus_space_read_4(sc->sc_memt, sc->sc_wdog_memh, o);
79} 79}
80 80
81static inline void 81static inline void
82a9wdt_wdog_write(struct a9wdt_softc *sc, bus_size_t o, uint32_t v) 82a9wdt_wdog_write(struct a9wdt_softc *sc, bus_size_t o, uint32_t v)
83{ 83{
84 bus_space_write_4(sc->sc_memt, sc->sc_wdog_memh, o, v); 84 bus_space_write_4(sc->sc_memt, sc->sc_wdog_memh, o, v);
85} 85}
86 86
87 87
88/* ARGSUSED */ 88/* ARGSUSED */
89static int 89static int
90a9wdt_match(device_t parent, cfdata_t cf, void *aux) 90a9wdt_match(device_t parent, cfdata_t cf, void *aux)
91{ 91{
92 struct mpcore_attach_args * const mpcaa = aux; 92 struct mpcore_attach_args * const mpcaa = aux;
93 93
94 if (attached) 94 if (attached)
95 return 0; 95 return 0;
96 96
97 if (!CPU_ID_CORTEX_A9_P(curcpu()->ci_arm_cpuid) && 97 if (!CPU_ID_CORTEX_A9_P(curcpu()->ci_arm_cpuid) &&
98 !CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid)) 98 !CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid))
99 return 0; 99 return 0;
100 100
101 if (strcmp(mpcaa->mpcaa_name, cf->cf_name) != 0) 101 if (strcmp(mpcaa->mpcaa_name, cf->cf_name) != 0)
102 return 0; 102 return 0;
103 103
104 /* 104 /*
105 * This isn't present on UP A9s (since CBAR isn't present). 105 * This isn't present on UP A9s (since CBAR isn't present).
106 */ 106 */
107 uint32_t mpidr = armreg_mpidr_read(); 107 uint32_t mpidr = armreg_mpidr_read();
108 if (mpidr == 0 || (mpidr & MPIDR_U)) 108 if (mpidr == 0 || (mpidr & MPIDR_U))
109 return 0; 109 return 0;
110 110
111 return 1; 111 return 1;
112} 112}
113 113
114static int 114static int
115a9wdt_tickle(struct sysmon_wdog *smw) 115a9wdt_tickle(struct sysmon_wdog *smw)
116{ 116{
117 struct a9wdt_softc * const sc = smw->smw_cookie; 117 struct a9wdt_softc * const sc = smw->smw_cookie;
118 118
119 /* 119 /*
120 * Cause the WDOG to restart counting. 120 * Cause the WDOG to restart counting.
121 */ 121 */
122 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load); 122 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load);
123 aprint_debug_dev(sc->sc_dev, "tickle\n"); 123 aprint_debug_dev(sc->sc_dev, "tickle\n");
124 return 0; 124 return 0;
125} 125}
126 126
127static int 127static int
128a9wdt_setmode(struct sysmon_wdog *smw) 128a9wdt_setmode(struct sysmon_wdog *smw)
129{ 129{
130 struct a9wdt_softc * const sc = smw->smw_cookie; 130 struct a9wdt_softc * const sc = smw->smw_cookie;
131 131
132 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 132 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
133 /* 133 /*
134 * Emit magic sequence to turn off WDOG 134 * Emit magic sequence to turn off WDOG
135 */ 135 */
136 a9wdt_wdog_write(sc, TMR_WDOGDIS, TMR_WDOG_DISABLE_MAGIC1); 136 a9wdt_wdog_write(sc, TMR_WDOGDIS, TMR_WDOG_DISABLE_MAGIC1);
137 a9wdt_wdog_write(sc, TMR_WDOGDIS, TMR_WDOG_DISABLE_MAGIC2); 137 a9wdt_wdog_write(sc, TMR_WDOGDIS, TMR_WDOG_DISABLE_MAGIC2);
138 delay(1); 138 delay(1);
139 sc->sc_wdog_ctl = a9wdt_wdog_read(sc, TMR_CTL); 139 sc->sc_wdog_ctl = a9wdt_wdog_read(sc, TMR_CTL);
140 KASSERT((sc->sc_wdog_ctl & TMR_CTL_WDOG_MODE) == 0); 140 KASSERT((sc->sc_wdog_ctl & TMR_CTL_WDOG_MODE) == 0);
141 aprint_debug_dev(sc->sc_dev, "setmode disable\n"); 141 aprint_debug_dev(sc->sc_dev, "setmode disable\n");
142 return 0; 142 return 0;
143 } 143 }
144 144
145 /* 145 /*
146 * If no changes, just tickle it and return. 146 * If no changes, just tickle it and return.
147 */ 147 */
148 if (sc->sc_wdog_armed && smw->smw_period == sc->sc_wdog_period) { 148 if (sc->sc_wdog_armed && smw->smw_period == sc->sc_wdog_period) {
149 sc->sc_wdog_load = sc->sc_freq * sc->sc_wdog_period - 1; 149 sc->sc_wdog_load = sc->sc_freq * sc->sc_wdog_period - 1;
150 sc->sc_wdog_ctl = TMR_CTL_ENABLE | TMR_CTL_WDOG_MODE 150 sc->sc_wdog_ctl = TMR_CTL_ENABLE | TMR_CTL_WDOG_MODE
151 | __SHIFTIN(sc->sc_wdog_prescaler - 1, TMR_CTL_PRESCALER); 151 | __SHIFTIN(sc->sc_wdog_prescaler - 1, TMR_CTL_PRESCALER);
152 152
153 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load); 153 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load);
154 a9wdt_wdog_write(sc, TMR_CTL, sc->sc_wdog_ctl); 154 a9wdt_wdog_write(sc, TMR_CTL, sc->sc_wdog_ctl);
155 aprint_debug_dev(sc->sc_dev, "setmode refresh\n"); 155 aprint_debug_dev(sc->sc_dev, "setmode refresh\n");
156 return 0; 156 return 0;
157 } 157 }
158 158
159 if (smw->smw_period == WDOG_PERIOD_DEFAULT) { 159 if (smw->smw_period == WDOG_PERIOD_DEFAULT) {
160 sc->sc_wdog_period = A9WDT_PERIOD_DEFAULT; 160 sc->sc_wdog_period = A9WDT_PERIOD_DEFAULT;
161 smw->smw_period = A9WDT_PERIOD_DEFAULT; 161 smw->smw_period = A9WDT_PERIOD_DEFAULT;
162 } 162 }
163 163
164 /* 164 /*
165 * Make sure we don't overflow the counter. 165 * Make sure we don't overflow the counter.
166 */ 166 */
167 if (smw->smw_period >= sc->sc_wdog_max_period) { 167 if (smw->smw_period >= sc->sc_wdog_max_period) {
168 return EINVAL; 168 return EINVAL;
169 } 169 }
170 170
171 sc->sc_wdog_load = sc->sc_freq * sc->sc_wdog_period - 1; 171 sc->sc_wdog_load = sc->sc_freq * sc->sc_wdog_period - 1;
172 sc->sc_wdog_ctl = TMR_CTL_ENABLE | TMR_CTL_WDOG_MODE 172 sc->sc_wdog_ctl = TMR_CTL_ENABLE | TMR_CTL_WDOG_MODE
173 | __SHIFTIN(sc->sc_wdog_prescaler - 1, TMR_CTL_PRESCALER); 173 | __SHIFTIN(sc->sc_wdog_prescaler - 1, TMR_CTL_PRESCALER);
174 174
175 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load); 175 a9wdt_wdog_write(sc, TMR_LOAD, sc->sc_wdog_load);
176 a9wdt_wdog_write(sc, TMR_CTL, sc->sc_wdog_ctl); 176 a9wdt_wdog_write(sc, TMR_CTL, sc->sc_wdog_ctl);
177 177
178 aprint_debug_dev(sc->sc_dev, "setmode enable\n"); 178 aprint_debug_dev(sc->sc_dev, "setmode enable\n");
179 return 0; 179 return 0;
180} 180}
181 181
182 182
183static void 183static void
184a9wdt_attach(device_t parent, device_t self, void *aux) 184a9wdt_attach(device_t parent, device_t self, void *aux)
185{ 185{
186 struct a9wdt_softc * const sc = device_private(self); 186 struct a9wdt_softc * const sc = device_private(self);
187 struct mpcore_attach_args * const mpcaa = aux; 187 struct mpcore_attach_args * const mpcaa = aux;
188 prop_dictionary_t dict = device_properties(self); 188 prop_dictionary_t dict = device_properties(self);
 189 const char *cpu_type;
189 190
190 sc->sc_dev = self; 191 sc->sc_dev = self;
191 sc->sc_memt = mpcaa->mpcaa_memt; 192 sc->sc_memt = mpcaa->mpcaa_memt;
192 193
193 bus_space_subregion(sc->sc_memt, mpcaa->mpcaa_memh,  194 bus_space_subregion(sc->sc_memt, mpcaa->mpcaa_memh,
194 TMR_WDOG_BASE, TMR_WDOG_SIZE, &sc->sc_wdog_memh); 195 TMR_WDOG_BASE, TMR_WDOG_SIZE, &sc->sc_wdog_memh);
195 196
196 /* 197 /*
197 * This runs at the ARM PERIPHCLOCK which should be 1/2 of the 198 * This runs at the ARM PERIPHCLOCK which should be 1/2 of the
198 * CPU clock. The MD code should have setup our frequency for us. 199 * CPU clock. The MD code should have setup our frequency for us.
199 */ 200 */
200 prop_dictionary_get_uint32(dict, "frequency", &sc->sc_freq); 201 prop_dictionary_get_uint32(dict, "frequency", &sc->sc_freq);
201 202
202 sc->sc_wdog_ctl = a9wdt_wdog_read(sc, TMR_CTL); 203 sc->sc_wdog_ctl = a9wdt_wdog_read(sc, TMR_CTL);
203 sc->sc_wdog_armed = (sc->sc_wdog_ctl & TMR_CTL_WDOG_MODE) != 0; 204 sc->sc_wdog_armed = (sc->sc_wdog_ctl & TMR_CTL_WDOG_MODE) != 0;
204 if (sc->sc_wdog_armed) { 205 if (sc->sc_wdog_armed) {
205 sc->sc_wdog_prescaler =  206 sc->sc_wdog_prescaler =
206 __SHIFTOUT(sc->sc_wdog_ctl, TMR_CTL_PRESCALER) + 1; 207 __SHIFTOUT(sc->sc_wdog_ctl, TMR_CTL_PRESCALER) + 1;
207 sc->sc_freq /= sc->sc_wdog_prescaler; 208 sc->sc_freq /= sc->sc_wdog_prescaler;
208 sc->sc_wdog_load = a9wdt_wdog_read(sc, TMR_LOAD); 209 sc->sc_wdog_load = a9wdt_wdog_read(sc, TMR_LOAD);
209 sc->sc_wdog_period = (sc->sc_wdog_load + 1) / sc->sc_freq; 210 sc->sc_wdog_period = (sc->sc_wdog_load + 1) / sc->sc_freq;
210 } else { 211 } else {
211 sc->sc_wdog_period = A9WDT_PERIOD_DEFAULT; 212 sc->sc_wdog_period = A9WDT_PERIOD_DEFAULT;
212 sc->sc_wdog_prescaler = 1; 213 sc->sc_wdog_prescaler = 1;
213 /* 214 /*
214 * Let's hope the timer frequency isn't prime. 215 * Let's hope the timer frequency isn't prime.
215 */ 216 */
216 for (size_t div = 256; div >= 2; div++) { 217 for (size_t div = 256; div >= 2; div++) {
217 if (sc->sc_freq % div == 0) { 218 if (sc->sc_freq % div == 0) {
218 sc->sc_wdog_prescaler = div; 219 sc->sc_wdog_prescaler = div;
219 break; 220 break;
220 } 221 }
221 } 222 }
222 sc->sc_freq /= sc->sc_wdog_prescaler; 223 sc->sc_freq /= sc->sc_wdog_prescaler;
223 } 224 }
224 sc->sc_wdog_max_period = UINT32_MAX / sc->sc_freq; 225 sc->sc_wdog_max_period = UINT32_MAX / sc->sc_freq;
225 226
226 /* 227 /*
227 * Does the config file tell us to turn on the watchdog? 228 * Does the config file tell us to turn on the watchdog?
228 */ 229 */
229 if (device_cfdata(self)->cf_flags & 1) 230 if (device_cfdata(self)->cf_flags & 1)
230 sc->sc_wdog_armed = true; 231 sc->sc_wdog_armed = true;
231 232
232 aprint_naive("\n"); 233 aprint_naive("\n");
233 aprint_normal(": A9 Watchdog Timer, default period is %u seconds%s\n", 234 if (CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid)) {
234 sc->sc_wdog_period, 235 cpu_type = "A5";
 236 } else {
 237 cpu_type = "A9";
 238 }
 239 aprint_normal(": %s Watchdog Timer, default period is %u seconds%s\n",
 240 cpu_type, sc->sc_wdog_period,
235 sc->sc_wdog_armed ? " (armed)" : ""); 241 sc->sc_wdog_armed ? " (armed)" : "");
236 242
237 sc->sc_smw.smw_name = device_xname(self); 243 sc->sc_smw.smw_name = device_xname(self);
238 sc->sc_smw.smw_cookie = sc; 244 sc->sc_smw.smw_cookie = sc;
239 sc->sc_smw.smw_setmode = a9wdt_setmode; 245 sc->sc_smw.smw_setmode = a9wdt_setmode;
240 sc->sc_smw.smw_tickle = a9wdt_tickle; 246 sc->sc_smw.smw_tickle = a9wdt_tickle;
241 sc->sc_smw.smw_period = sc->sc_wdog_period; 247 sc->sc_smw.smw_period = sc->sc_wdog_period;
242 248
243 if (sc->sc_wdog_armed) { 249 if (sc->sc_wdog_armed) {
244 int error = sysmon_wdog_setmode(&sc->sc_smw, WDOG_MODE_KTICKLE, 250 int error = sysmon_wdog_setmode(&sc->sc_smw, WDOG_MODE_KTICKLE,
245 sc->sc_wdog_period); 251 sc->sc_wdog_period);
246 if (error) 252 if (error)
247 aprint_error_dev(self, 253 aprint_error_dev(self,
248 "failed to start kernel tickler: %d\n", error); 254 "failed to start kernel tickler: %d\n", error);
249 } 255 }
250} 256}