1 /* $NetBSD: gemini_wdt.c,v 1.5 2025/12/19 13:03:51 nia Exp $ */ 2 3 /* 4 * OMAP watchdog timers, common code 5 * 6 * Copyright (c) 2007 Microsoft 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 33 #include <sys/param.h> 34 #include <sys/callout.h> 35 #include <sys/cdefs.h> 36 #include <sys/device.h> 37 #include <sys/kernel.h> 38 #include <sys/systm.h> 39 #include <sys/wdog.h> 40 41 #include <sys/bus.h> 42 #include <dev/sysmon/sysmonvar.h> 43 44 #include <arm/gemini/gemini_wdtvar.h> 45 #include <arm/gemini/gemini_reg.h> 46 47 geminiwdt_softc_t *geminiwdt_sc; 48 49 #define WATCHDOG_COUNT(nsec) \ 50 (GEMINI_WDT_CLOCK_FREQ * (nsec)) 51 52 53 static void 54 geminiwdt_start(void) 55 { 56 geminiwdt_softc_t *sc = geminiwdt_sc; 57 uint32_t r; 58 59 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR); 60 r |= (WDT_WDCR_RESET_ENB 61 |WDT_WDCR_ENB); 62 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r); 63 } 64 65 static void 66 geminiwdt_stop(void) 67 { 68 geminiwdt_softc_t *sc = geminiwdt_sc; 69 uint32_t r; 70 71 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR); 72 r &= ~(WDT_WDCR_EXTSIG_ENB 73 |WDT_WDCR_RESET_ENB 74 |WDT_WDCR_INTR_ENB 75 |WDT_WDCR_ENB); 76 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r); 77 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 78 GEMINI_WDT_WDCLEAR, WDT_WDCLEAR_CLEAR); 79 } 80 81 static void 82 geminiwdt_do_set_timeout(void) 83 { 84 geminiwdt_softc_t *sc = geminiwdt_sc; 85 uint32_t r; 86 87 /* 88 * Disable the watchdog timer 89 */ 90 if (sc->sc_armed) 91 geminiwdt_stop(); 92 93 /* 94 * Set WdLoad register 95 */ 96 r = (sc->sc_smw.smw_period != 0) ? 97 WATCHDOG_COUNT(sc->sc_smw.smw_period) : WDT_WDLOAD_DFLT; 98 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDLOAD, r); 99 100 /* 101 * feed MAGIC treat to dog 102 */ 103 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 104 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC); 105 106 /* 107 * Select PCLK clock source 108 */ 109 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR); 110 r &= ~WDCR_CLKSRC_5MHZ; 111 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r); 112 113 /* 114 * Enable the timer 115 */ 116 if (sc->sc_armed) 117 geminiwdt_start(); 118 } 119 120 void 121 geminiwdt_set_timeout(unsigned int period) 122 { 123 geminiwdt_softc_t *sc = geminiwdt_sc; 124 int s = splhigh(); 125 126 if (period != sc->sc_smw.smw_period) { 127 sc->sc_smw.smw_period = period; 128 geminiwdt_do_set_timeout(); 129 } 130 131 splx(s); 132 } 133 134 int 135 geminiwdt_enable(int enable) 136 { 137 geminiwdt_softc_t *sc = geminiwdt_sc; 138 int s; 139 int prev_state = geminiwdt_sc->sc_armed; 140 141 /* Normalize the int to a boolean so we can compare values directly. 142 */ 143 enable = !!enable; 144 145 s = splhigh(); 146 147 if (enable != sc->sc_armed) { 148 if (enable) { 149 /* Make sure that the watchdog timeout is up to date. 150 */ 151 geminiwdt_do_set_timeout(); 152 geminiwdt_start(); 153 } else { 154 geminiwdt_stop(); 155 } 156 sc->sc_armed = enable; 157 } 158 159 splx(s); 160 return prev_state; 161 } 162 163 int 164 geminiwdt_setmode(struct sysmon_wdog *smw) 165 { 166 geminiwdt_softc_t *sc = smw->smw_cookie; 167 int error = 0; 168 169 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 170 geminiwdt_enable(0); 171 } else { 172 if (smw->smw_period == WDOG_PERIOD_DEFAULT) 173 sc->sc_smw.smw_period = WDT_WDLOAD_DFLT; 174 else 175 sc->sc_smw.smw_period = smw->smw_period; 176 geminiwdt_set_timeout(sc->sc_smw.smw_period); 177 geminiwdt_enable(1); 178 } 179 return error; 180 } 181 182 int 183 geminiwdt_tickle(struct sysmon_wdog *smw) 184 { 185 geminiwdt_softc_t *sc = geminiwdt_sc; 186 int s = splhigh(); 187 188 /* 189 * feed the dog a MAGIC treat 190 */ 191 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 192 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC); 193 194 splx(s); 195 return 0; 196 } 197