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