github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/board/raspberrypi/watchdog.go (about)

     1  // Raspberry Pi watchdog timer support
     2  // https://github.com/f-secure-foundry/tamago
     3  //
     4  // Copyright (c) the pi package authors
     5  //
     6  // Use of this source code is governed by the license
     7  // that can be found in the LICENSE file.
     8  
     9  package pi
    10  
    11  import (
    12  	"time"
    13  
    14  	"github.com/f-secure-foundry/tamago/internal/reg"
    15  	"github.com/f-secure-foundry/tamago/soc/bcm2835"
    16  )
    17  
    18  // Power Management, Reset controller and Watchdog registers
    19  const (
    20  	PM_BASE = 0x100000
    21  
    22  	PM_RSTC = PM_BASE + 0x1c
    23  
    24  	PM_WDOG          = PM_BASE + 0x24
    25  	PM_WDOG_RESET    = 0000000000
    26  	PM_WDOG_TIME_SET = 0x000fffff
    27  
    28  	PM_PASSWORD              = 0x5a000000
    29  	PM_RSTC_WRCFG_CLR        = 0xffffffcf
    30  	PM_RSTC_WRCFG_SET        = 0x00000030
    31  	PM_RSTC_WRCFG_FULL_RESET = 0x00000020
    32  	PM_RSTC_RESET            = 0x00000102
    33  )
    34  
    35  type watchdog struct {
    36  	timeout uint32
    37  }
    38  
    39  // Watchdog can automatically reset the board on lock-up.
    40  //
    41  // A typical example might be to reset the board due to an OOM (Out-Of-Memory)
    42  // condition. In Go out-of-memory is not recoverable, and halts the CPU -
    43  // automatic reset of the board can be an appropriate action to take.
    44  //
    45  // To use, start the watchdog with a timeout. Periodically call Reset from your
    46  // logic (within the timeout). If you fail to call Reset within the timeout,
    47  // the watchdog interrupt will fire, resetting the board.
    48  var Watchdog = &watchdog{}
    49  
    50  // Start the watchdog timer, with a given timeout.
    51  func (w *watchdog) Start(timeout time.Duration) {
    52  	t := uint64(timeout) / bcm2835.WatchdogPeriod
    53  
    54  	// Exceeding the watchdog timeout is indicative of a major logic issue, so
    55  	// panic rather than returning error.
    56  	if (t & ^uint64(PM_WDOG_TIME_SET)) != 0 {
    57  		panic("excess timeout for watchdog")
    58  	}
    59  
    60  	w.timeout = uint32(t)
    61  
    62  	w.Reset()
    63  }
    64  
    65  // Reset the watchdog count-down.
    66  func (w *watchdog) Reset() {
    67  	// Reset could probably be done more efficiently, there should be a way to reset
    68  	// without a full re-initialization.
    69  	pm_rstc := reg.Read(bcm2835.PeripheralAddress(PM_RSTC))
    70  	pm_wdog := PM_PASSWORD | (w.timeout & PM_WDOG_TIME_SET)
    71  
    72  	pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET
    73  
    74  	reg.Write(bcm2835.PeripheralAddress(PM_WDOG), pm_wdog)
    75  	reg.Write(bcm2835.PeripheralAddress(PM_RSTC), pm_rstc)
    76  }
    77  
    78  // Stop the watchdog.
    79  func (w *watchdog) Stop() {
    80  	reg.Write(bcm2835.PeripheralAddress(PM_RSTC), PM_PASSWORD|PM_RSTC_RESET)
    81  }
    82  
    83  // Remaining gets the remaining duration of the watchdog.
    84  func (w *watchdog) Remaining() time.Duration {
    85  	t := reg.Read(bcm2835.PeripheralAddress(PM_WDOG)) & PM_WDOG_TIME_SET
    86  	return time.Duration(uint64(t) * bcm2835.WatchdogPeriod)
    87  }