github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/board/raspberrypi/watchdog.go (about) 1 // Raspberry Pi watchdog timer support 2 // https://github.com/usbarmory/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/usbarmory/tamago/internal/reg" 15 "github.com/usbarmory/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 }