add watchdog support

development
Andrea Barisani 2 months ago
parent 4ae20b6461
commit 008b51f09b

@ -52,6 +52,11 @@ type CPU struct {
TimerOffset int64
// timer function
TimerFn func() int64
// GIC Distributor base address
gicd uint32
// GIC CPU interface base address
gicc uint32
}
// defined in arm.s

@ -29,6 +29,7 @@ const (
GICD_TYPER_ITLINES = 0
GICD_IGROUPR = 0x080
GICD_ISENABLER = 0x100
GICD_ICENABLER = 0x180
GICD_ICPENDR = 0x280
@ -44,36 +45,76 @@ const (
)
// InitGIC initializes the ARM Generic Interrupt Controller (GIC).
func InitGIC(base uint32) {
gicd := base + GICD_OFF
gicc := base + GICC_OFF
func (cpu *CPU) InitGIC(base uint32, secure bool) {
cpu.gicd = base + GICD_OFF
cpu.gicc = base + GICC_OFF
// Get the maximum number of external interrupt lines
itLinesNum := reg.Get(gicd+GICD_TYPER, GICD_TYPER_ITLINES, 0x1f)
itLinesNum := reg.Get(cpu.gicd+GICD_TYPER, GICD_TYPER_ITLINES, 0x1f)
// Add a line for the 32 internal interrupts
itLinesNum += 1
for i := uint32(0); i < itLinesNum; i++ {
for n := uint32(0); n < itLinesNum; n++ {
// Disable interrupts
addr := gicd + GICD_ICENABLER + 4*i
addr := cpu.gicd + GICD_ICENABLER + 4*n
reg.Write(addr, 0xffffffff)
// Clear pending interrupts
addr = gicd + GICD_ICPENDR + 4*i
addr = cpu.gicd + GICD_ICPENDR + 4*n
reg.Write(addr, 0xffffffff)
// Assign all interrupts to Non-Secure
addr = gicd + GICD_IGROUPR + 4*i
reg.Write(addr, 0xffffffff)
if !secure {
addr = cpu.gicd + GICD_IGROUPR + 4*n
reg.Write(addr, 0xffffffff)
}
}
// Set priority mask to allow Non-Secure world to use the lower half
// of the priority range.
reg.Write(gicc+GICC_PMR, 0x80)
reg.Write(cpu.gicc+GICC_PMR, 0x80)
// Enable GIC
reg.Write(gicc+GICC_CTLR, GICC_CTLR_ENABLEGRP1|GICC_CTLR_ENABLEGRP0|GICC_CTLR_FIQEN)
reg.Set(gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP1)
reg.Set(gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP0)
reg.Write(cpu.gicc+GICC_CTLR, GICC_CTLR_ENABLEGRP1|GICC_CTLR_ENABLEGRP0|GICC_CTLR_FIQEN)
reg.Set(cpu.gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP1)
reg.Set(cpu.gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP0)
}
func irq(gicd uint32, m int, secure bool, enable bool) {
if gicd == 0 {
return
}
var addr uint32
n := uint32(m / 32)
i := m % 32
if enable {
addr = gicd + GICD_IGROUPR + 4*n
if !secure {
reg.Set(addr, i)
} else {
reg.Clear(addr, i)
}
addr = gicd + GICD_ISENABLER + 4*n
} else {
addr = gicd + GICD_ICENABLER + 4*n
}
reg.SetTo(addr, i, true)
}
// EnableInterrupt enables forwarding of the corresponding interrupt to the CPU
// and configures its group status (Secure: Group 0, Non-Secure: Group 1).
func (cpu *CPU) EnableInterrupt(m int, secure bool) {
irq(cpu.gicd, m, secure, true)
}
// DisableInterrupt disables forwarding of the corresponding interrupt to the
// CPU.
func (cpu *CPU) DisableInterrupt(m int) {
irq(cpu.gicd, m, false, false)
}

@ -32,6 +32,14 @@ func Clear16(addr uint32, pos int) {
*reg &= ^(1 << pos)
}
func SetTo16(addr uint32, pos int, val bool) {
if val {
Set16(addr, pos)
} else {
Clear16(addr, pos)
}
}
func SetN16(addr uint32, pos int, mask int, val uint16) {
reg := (*uint16)(unsafe.Pointer(uintptr(addr)))
*reg = (*reg & (^(uint16(mask) << pos))) | (val << pos)

@ -72,8 +72,8 @@ func Init() {
}
func init() {
// clear power-down watchdog
clearWDOG()
// clear watchdogs power-down counters
disablePowerDownCounters()
// use internal OCRAM (iRAM) as default DMA region
dma.Init(OCRAM_START, OCRAM_SIZE)

@ -17,27 +17,49 @@ import (
// are 16-bit.
const (
WDOG1_WCR = 0x020bc000
WDOG1_WSR = 0x020bc002
WDOG1_WICR = 0x020bc006
WDOG1_WMCR = 0x020bc008
WDOG2_WCR = 0x020c0000
WDOG2_WSR = 0x020c0002
WDOG2_WICR = 0x020c0006
WDOG2_WMCR = 0x020c0008
WDOG3_WCR = 0x021e4000
WDOG3_WSR = 0x021e0002
WDOG3_WICR = 0x021e4006
WDOG3_WMCR = 0x021e4008
WCR_SRE = 6
WCR_WDA = 5
WCR_SRS = 4
WCR_WT = 8
WCR_SRE = 6
WCR_WDA = 5
WCR_SRS = 4
WCR_WDE = 2
WICR_WIE = 16
WICR_WTIS = 14
WMCR_PDE = 0
)
// Watchdog interrupts
const (
WDOG1_IRQ = 32 + 80
WDOG2_IRQ = 32 + 81
WDOG3_IRQ = 32 + 11
TZ_WDOG = 2
TZ_WDOG_IRQ = WDOG2_IRQ
)
// System Reset Controller registers
const (
SRC_SCR = 0x020d8000
SCR_WARM_RESET_ENABLE = 0
)
func clearWDOG() {
func disablePowerDownCounters() {
// Clear the 16 seconds power-down counter event for all watchdogs
// (p4085, 59.5.3 Power-down counter event, IMX6ULLRM).
reg.Clear16(WDOG1_WMCR, WMCR_PDE)
@ -45,6 +67,41 @@ func clearWDOG() {
reg.Clear16(WDOG3_WMCR, WMCR_PDE)
}
// EnableWatchdog activates a Watchdog to trigger a reset after the argument
// timeout. The timeout must be specified in milliseconds with 128000 as
// maximum value, the timeout resolution is 500ms.
//
// The interrupt enabling is write once, therefore disabling it on subsequent
// calls has no effect.
//
// Calling the function on a previously enabled watchdog performs its service
// sequence to reset its timeout to a new value.
func EnableWatchdog(index int, timeout int, irq bool) {
var base uint32
switch index {
case 1:
base = WDOG1_WCR
case 2:
base = WDOG2_WCR
case 3:
base = WDOG3_WCR
default:
return
}
reg.SetN16(base, WCR_WT, 0xff, uint16(timeout / 500 - 1))
if reg.Get16(base, WCR_WDE, 1) == 1 {
reg.Write16(base+2, 0x5555)
reg.Write16(base+2, 0xaaaa)
reg.Set16(base+6, WICR_WTIS)
} else {
reg.SetTo16(base+6, WICR_WIE, irq)
reg.Set16(base, WCR_WDE)
}
}
// Reset asserts the global watchdog reset causing the SoC to restart (warm
// reset).
//

Loading…
Cancel
Save