1 1.2 matt /* $NetBSD: ralink_wdog.c,v 1.2 2011/07/28 15:38:49 matt Exp $ */ 2 1.2 matt /*- 3 1.2 matt * Copyright (c) 2011 CradlePoint Technology, Inc. 4 1.2 matt * All rights reserved. 5 1.2 matt * 6 1.2 matt * 7 1.2 matt * Redistribution and use in source and binary forms, with or without 8 1.2 matt * modification, are permitted provided that the following conditions 9 1.2 matt * are met: 10 1.2 matt * 1. Redistributions of source code must retain the above copyright 11 1.2 matt * notice, this list of conditions and the following disclaimer. 12 1.2 matt * 2. Redistributions in binary form must reproduce the above copyright 13 1.2 matt * notice, this list of conditions and the following disclaimer in the 14 1.2 matt * documentation and/or other materials provided with the distribution. 15 1.2 matt * 16 1.2 matt * THIS SOFTWARE IS PROVIDED BY CRADLEPOINT TECHNOLOGY, INC. AND CONTRIBUTORS 17 1.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 20 1.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.2 matt * POSSIBILITY OF SUCH DAMAGE. 27 1.2 matt */ 28 1.2 matt 29 1.2 matt /* 30 1.2 matt * ra_wdog.c -- Ralink 305x Watchdog Timer driver 31 1.2 matt * 32 1.2 matt * Timer 1 is used as a system reset watchdog timer 33 1.2 matt * Timer 0 is (optionally) used as a periodic watchdog service interrupt 34 1.2 matt * 35 1.2 matt * NetBSD sysmon watchdog is used in mode defined by RA_WDOG_DEFAULT_MODE 36 1.2 matt * (which can be set via kernel config), or by mode passed to 37 1.2 matt * our 'smw_setmode' function. The mode used determines what 38 1.2 matt * mechanism is used to periodically service the watchdog. 39 1.2 matt * 40 1.2 matt * KTICKLE mode is default and supports 2 variants, allowing some control 41 1.2 matt * over the priority of the service routine: 42 1.2 matt * 43 1.2 matt * 1. the specified reset period is a positive integer: 44 1.2 matt * A callout runs the 'smw_tickle' function at IPL_SOFTCLOCK for service. 45 1.2 matt * If your system cannot make "forward progress" without softints running, 46 1.2 matt * you should use this variant. 47 1.2 matt * 48 1.2 matt * 2. the specified reset period is a negative integer: 49 1.2 matt * Timer 0 interrupt runs ra_wdog_timer0() at IPL_VM for service. 50 1.2 matt * If your system can make "forward progress" while spelding long times 51 1.2 matt * at IPL_VM, you should use this variant. 52 1.2 matt * The numbner is rectified 53 1.2 matt * 54 1.2 matt * The reset period is defined by RA_WDOG_DEFAULT_PERIOD 55 1.2 matt * (which can be set via kernel config), or by period passed to 56 1.2 matt * our 'smw_setmode' function. The interrupt service interval 57 1.2 matt * is half the reset interval. 58 1.2 matt * 59 1.2 matt */ 60 1.2 matt 61 1.2 matt #include "rwdog.h" 62 1.2 matt 63 1.2 matt #include <sys/cdefs.h> 64 1.2 matt __KERNEL_RCSID(0, "$NetBSD: ralink_wdog.c,v 1.2 2011/07/28 15:38:49 matt Exp $"); 65 1.2 matt 66 1.2 matt #include <sys/param.h> 67 1.2 matt #include <sys/bus.h> 68 1.2 matt #include <sys/device.h> 69 1.2 matt #include <sys/systm.h> 70 1.2 matt #include <sys/wdog.h> 71 1.2 matt 72 1.2 matt #include <mips/ralink/ralink_var.h> 73 1.2 matt #include <mips/ralink/ralink_reg.h> 74 1.2 matt 75 1.2 matt #include <dev/sysmon/sysmonvar.h> 76 1.2 matt 77 1.2 matt #if 0 78 1.2 matt # define DISABLE_WATCHDOG 79 1.2 matt #endif 80 1.2 matt 81 1.2 matt #ifndef RA_WDOG_DEFAULT_MODE 82 1.2 matt # define RA_WDOG_DEFAULT_MODE WDOG_MODE_KTICKLE 83 1.2 matt #endif 84 1.2 matt 85 1.2 matt /* 86 1.2 matt * PERIODs are in in seconds; 87 1.2 matt * the counter is 16-bits; 88 1.2 matt * maximum period depends on bus freq 89 1.2 matt */ 90 1.2 matt #ifndef RA_WDOG_DEFAULT_PERIOD 91 1.2 matt # define RA_WDOG_DEFAULT_PERIOD 10 92 1.2 matt #endif 93 1.2 matt #define WDOG_COUNT_MASK 0xffff 94 1.2 matt #define WDOG_MAX_COUNT WDOG_COUNT_MASK 95 1.2 matt #define WDOG_MAX_PERIOD \ 96 1.2 matt (WDOG_MAX_COUNT / (RA_BUS_FREQ / WDOG_MAX_COUNT)) 97 1.2 matt 98 1.2 matt static int ra_wdog_match(device_t, cfdata_t, void *); 99 1.2 matt static void ra_wdog_attach(device_t, device_t, void *); 100 1.2 matt static int ra_wdog_tickle(struct sysmon_wdog *); 101 1.2 matt static int ra_wdog_timer0(void *); 102 1.2 matt static int ra_wdog_setmode(struct sysmon_wdog *); 103 1.2 matt 104 1.2 matt extern int sysmon_wdog_setmode(struct sysmon_wdog *, int, u_int); 105 1.2 matt 106 1.2 matt typedef struct ra_wdog_softc { 107 1.2 matt device_t sc_dev; 108 1.2 matt struct sysmon_wdog sc_smw; 109 1.2 matt bus_space_tag_t sc_memt; 110 1.2 matt bus_space_handle_t sc_memh; 111 1.2 matt void *sc_ih; 112 1.2 matt } ra_wdog_softc_t; 113 1.2 matt 114 1.2 matt 115 1.2 matt CFATTACH_DECL_NEW(rwdog, sizeof(struct ra_wdog_softc), 116 1.2 matt ra_wdog_match, ra_wdog_attach, NULL, NULL); 117 1.2 matt 118 1.2 matt static const char *wdog_modestr[WDOG_MODE_MASK+1] = { 119 1.2 matt [ WDOG_MODE_DISARMED ] = "DISARMED", 120 1.2 matt [ WDOG_MODE_KTICKLE ] = "KTICKLE", 121 1.2 matt [ WDOG_MODE_UTICKLE ] = "UTICKLE", 122 1.2 matt [ WDOG_MODE_ETICKLE ] = "ETICKLE" 123 1.2 matt }; 124 1.2 matt 125 1.2 matt static inline void 126 1.2 matt ra_wdog_reset(const ra_wdog_softc_t *sc) 127 1.2 matt { 128 1.2 matt uint32_t r; 129 1.2 matt 130 1.2 matt r = bus_space_read_4(sc->sc_memt, sc->sc_memh, RA_TIMER_STAT); 131 1.2 matt r |= TIMER_1_RESET; 132 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_STAT, r); 133 1.2 matt } 134 1.2 matt 135 1.2 matt static inline u_int32_t 136 1.2 matt ra_wdog_sec_to_count(u_int nsec) 137 1.2 matt { 138 1.2 matt KASSERT(nsec <= WDOG_MAX_PERIOD); 139 1.2 matt const u_int32_t count = (RA_BUS_FREQ / WDOG_MAX_COUNT) * nsec; 140 1.2 matt KASSERT(count <= WDOG_MAX_COUNT); 141 1.2 matt return count; 142 1.2 matt } 143 1.2 matt 144 1.2 matt static int 145 1.2 matt ra_wdog_match(device_t parent, cfdata_t cf, void *aux) 146 1.2 matt { 147 1.2 matt return 1; 148 1.2 matt } 149 1.2 matt 150 1.2 matt static void 151 1.2 matt ra_wdog_attach(device_t parent, device_t self, void *aux) 152 1.2 matt { 153 1.2 matt ra_wdog_softc_t * const sc = device_private(self); 154 1.2 matt const struct mainbus_attach_args *ma = aux; 155 1.2 matt bus_space_handle_t memh; 156 1.2 matt int error; 157 1.2 matt 158 1.2 matt aprint_naive(": Ralink watchdog controller\n"); 159 1.2 matt aprint_normal(": Ralink watchdog controller\n"); 160 1.2 matt aprint_normal_dev(self, "max period %d sec.\n", WDOG_MAX_PERIOD); 161 1.2 matt 162 1.2 matt error = bus_space_map(ma->ma_memt, RA_TIMER_BASE, 0x100, 0, &memh); 163 1.2 matt if (error != 0) { 164 1.2 matt aprint_error_dev(self, "unable to map registers, " 165 1.2 matt "error=%d\n", error); 166 1.2 matt return; 167 1.2 matt } 168 1.2 matt 169 1.2 matt sc->sc_memt = ma->ma_memt; 170 1.2 matt sc->sc_memh = memh; 171 1.2 matt 172 1.2 matt sc->sc_smw.smw_name = device_xname(self); 173 1.2 matt sc->sc_smw.smw_cookie = sc; 174 1.2 matt sc->sc_smw.smw_setmode = ra_wdog_setmode; 175 1.2 matt sc->sc_smw.smw_tickle = ra_wdog_tickle; 176 1.2 matt sc->sc_smw.smw_period = RA_WDOG_DEFAULT_PERIOD; 177 1.2 matt 178 1.2 matt error = sysmon_wdog_register(&sc->sc_smw); 179 1.2 matt if (error != 0) 180 1.2 matt aprint_error_dev(self, "unable to register with sysmon, " 181 1.2 matt "error %d\n", error); 182 1.2 matt 183 1.2 matt sc->sc_ih = ra_intr_establish(RA_IRQ_TIMER0, ra_wdog_timer0, sc, 0); 184 1.2 matt if (sc->sc_ih == NULL) 185 1.2 matt aprint_error_dev(self, "unable to establish interrupt\n"); 186 1.2 matt /* expect watchdog reset shortly */ 187 1.2 matt 188 1.2 matt if (RA_WDOG_DEFAULT_MODE == WDOG_MODE_DISARMED) { 189 1.2 matt /* 190 1.2 matt * disarm the watchdog 191 1.2 matt */ 192 1.2 matt bus_space_write_4(sc->sc_memt, memh, RA_TIMER_0_CNTRL, 0); 193 1.2 matt bus_space_write_4(sc->sc_memt, memh, RA_TIMER_1_CNTRL, 0); 194 1.2 matt aprint_normal_dev(self, "%s mode\n", 195 1.2 matt wdog_modestr[sc->sc_smw.smw_mode]); 196 1.2 matt } else { 197 1.2 matt /* 198 1.2 matt * initialize and arm the watchdog now. 199 1.2 matt * if boot loader already initialized the watchdog 200 1.2 matt * then we are re-initializing; this will buy some time 201 1.2 matt * until interrupts are enabled, and will establish our 202 1.2 matt * (default) mode and smw_period indedpendent of the 203 1.2 matt * boot loader. 204 1.2 matt */ 205 1.2 matt error = sysmon_wdog_setmode(&sc->sc_smw, RA_WDOG_DEFAULT_MODE, 206 1.2 matt RA_WDOG_DEFAULT_PERIOD); 207 1.2 matt if (error != 0) { 208 1.2 matt aprint_error_dev(self, "unable to set sysmon wdog, " 209 1.2 matt "mode %d, error %d\n", 210 1.2 matt RA_WDOG_DEFAULT_MODE, error); 211 1.2 matt } else { 212 1.2 matt aprint_normal_dev(self, "%s mode, period %d sec.\n", 213 1.2 matt wdog_modestr[sc->sc_smw.smw_mode], 214 1.2 matt sc->sc_smw.smw_period); 215 1.2 matt } 216 1.2 matt } 217 1.2 matt } 218 1.2 matt 219 1.2 matt /* 220 1.2 matt * ra_wdog_tickle - smw watchdog service function 221 1.2 matt */ 222 1.2 matt static int 223 1.2 matt ra_wdog_tickle(struct sysmon_wdog *smw) 224 1.2 matt { 225 1.2 matt const ra_wdog_softc_t * const sc = smw->smw_cookie; 226 1.2 matt ra_wdog_reset(sc); 227 1.2 matt return 0; 228 1.2 matt } 229 1.2 matt 230 1.2 matt /* 231 1.2 matt * ra_wdog_timer0 - periodic watchdog service ISR 232 1.2 matt */ 233 1.2 matt static int 234 1.2 matt ra_wdog_timer0(void *arg) 235 1.2 matt { 236 1.2 matt const ra_wdog_softc_t * const sc = arg; 237 1.2 matt ra_wdog_reset(sc); 238 1.2 matt return 0; 239 1.2 matt } 240 1.2 matt 241 1.2 matt static int 242 1.2 matt ra_wdog_setmode(struct sysmon_wdog *smw) 243 1.2 matt { 244 1.2 matt const ra_wdog_softc_t * const sc = smw->smw_cookie; 245 1.2 matt u_int period = smw->smw_period; 246 1.2 matt bool itickle = false; 247 1.2 matt uint32_t r; 248 1.2 matt 249 1.2 matt if (((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_KTICKLE) && 250 1.2 matt ((int)period < 0)) { 251 1.2 matt itickle = true; /* use Timer 0 */ 252 1.2 matt period = -period; 253 1.2 matt } 254 1.2 matt 255 1.2 matt /* all configuration has to be done with the timer disabled */ 256 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_CNTRL, 0); 257 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_CNTRL, 0); 258 1.2 matt 259 1.2 matt if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) 260 1.2 matt return 0; 261 1.2 matt 262 1.2 matt if (period > WDOG_MAX_PERIOD) 263 1.2 matt return EOPNOTSUPP; 264 1.2 matt 265 1.2 matt /* Set the new watchdog reset period in Timer 1 */ 266 1.2 matt r = ra_wdog_sec_to_count(period); 267 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_LOAD, r); 268 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_CNTRL, 269 1.2 matt TIMER_EN | TIMER_MODE(TIMER_MODE_WDOG) | 270 1.2 matt TIMER_PRESCALE(TIMER_PRESCALE_DIV_65536)); 271 1.2 matt 272 1.2 matt if (itickle) { 273 1.2 matt /* Set the new watchdog service period in Timer 0 */ 274 1.2 matt r = ra_wdog_sec_to_count(period) / 2; 275 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_LOAD, r); 276 1.2 matt bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_CNTRL, 277 1.2 matt TIMER_EN | TIMER_MODE(TIMER_MODE_PERIODIC) | 278 1.2 matt TIMER_PRESCALE(TIMER_PRESCALE_DIV_65536)); 279 1.2 matt } 280 1.2 matt 281 1.2 matt return 0; 282 1.2 matt } 283