Home | History | Annotate | Line # | Download | only in gemini
      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