1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Peripherals.Miscellaneous; 13 14 namespace Antmicro.Renode.Peripherals.Timers 15 { 16 public class OpenTitan_AonTimer: BasicDoubleWordPeripheral, IKnownSize 17 { OpenTitan_AonTimer(IMachine machine, OpenTitan_PowerManager powerManager, OpenTitan_ResetManager resetManager, long frequency = 200000)18 public OpenTitan_AonTimer(IMachine machine, OpenTitan_PowerManager powerManager, OpenTitan_ResetManager resetManager, long frequency = 200000): base(machine) 19 { 20 this.powerManager = powerManager; 21 this.resetManager = resetManager; 22 23 powerManager.LowPowerStateChanged += HandleLowPowerTransition; 24 25 WakeupTimerExpired = new GPIO(); 26 WatchdogTimerBark = new GPIO(); 27 FatalAlert = new GPIO(); 28 29 wkupTimer = new ComparingTimer(machine.ClockSource, frequency, this, "wkup_timer", workMode: Time.WorkMode.Periodic, eventEnabled: true); 30 wkupTimer.CompareReached += UpdateWakeupInterrupts; 31 32 wdogBarkInnerTimer = new ComparingTimer(machine.ClockSource, frequency, this, "wdog_bark_inner_timer", workMode: Time.WorkMode.Periodic, eventEnabled: true); 33 wdogBarkInnerTimer.CompareReached += UpdateWdogBarkInterrupts; 34 wdogBiteInnerTimer = new ComparingTimer(machine.ClockSource, frequency, this, "wdog_bite_inner_timer", workMode: Time.WorkMode.Periodic, eventEnabled: true); 35 wdogBiteInnerTimer.CompareReached += UpdateWdogBiteInterrupts; 36 37 DefineRegisters(); 38 } 39 Reset()40 public override void Reset() 41 { 42 base.Reset(); 43 FatalAlert.Unset(); 44 45 wkupTimer.Reset(); 46 wdogBarkInnerTimer.Reset(); 47 wdogBiteInnerTimer.Reset(); 48 UpdateWakeupInterrupts(); 49 UpdateWdogBarkInterrupts(); 50 UpdateWdogBiteInterrupts(); 51 52 lowPowerState = false; 53 } 54 55 public long Size => 0x30; 56 57 public GPIO WakeupTimerExpired { get; } 58 public GPIO WatchdogTimerBark { get; } 59 public GPIO FatalAlert { get; } 60 HandleLowPowerTransition(bool lowPower)61 private void HandleLowPowerTransition(bool lowPower) 62 { 63 if(lowPowerState == lowPower) 64 { 65 return; 66 } 67 68 if(pauseInSleep.Value) 69 { 70 wdogBarkInnerTimer.Enabled = !lowPower; 71 wdogBiteInnerTimer.Enabled = !lowPower; 72 } 73 74 lowPowerState = lowPower; 75 this.Log(LogLevel.Debug, "Low power state set to {0}", lowPower); 76 } 77 DefineRegisters()78 private void DefineRegisters() 79 { 80 Registers.AlertTest.Define(this) 81 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 82 .WithReservedBits(1, 31); 83 84 Registers.WakeupTimerControl.Define(this) 85 .WithFlag(0, name: "enable", writeCallback: (_, val) => 86 { 87 wkupTimer.Enabled = val; 88 UpdateWakeupInterrupts(); 89 }) 90 .WithValueField(1, 12, name: "prescaler", 91 valueProviderCallback: _ => wkupTimer.Divider - 1, 92 writeCallback: (_, val) => wkupTimer.Divider = (uint)(val + 1u)) 93 .WithReservedBits(13, 19); 94 95 Registers.WakeupTimerThreshold.Define(this) 96 .WithValueField(0, 32, name: "threshold", 97 valueProviderCallback: _ => (uint)wkupTimer.Compare, 98 writeCallback: (_, val) => 99 { 100 wkupTimer.Compare = val; 101 UpdateWakeupInterrupts(); 102 }); 103 104 Registers.WakeupTimerCount.Define(this) 105 .WithValueField(0, 32, name: "count", 106 valueProviderCallback: _ => (uint)wkupTimer.Value, 107 writeCallback: (_, val) => 108 { 109 wkupTimer.Value = val; 110 UpdateWakeupInterrupts(); 111 }); 112 113 Registers.WatchdogTimerWriteEnable.Define(this, 0x1) 114 .WithFlag(0, out wdogConfigNotLocked, FieldMode.Read | FieldMode.WriteZeroToClear, name: "regwen") 115 .WithReservedBits(1, 31); 116 117 Registers.WatchdogTimerControl.Define(this) 118 .WithFlag(0, name: "enable", writeCallback: (_, val) => 119 { 120 if(!wdogConfigNotLocked.Value) 121 { 122 this.Log(LogLevel.Warning, "Watchdog timer configuration is locked"); 123 return; 124 } 125 126 wdogBiteInnerTimer.Enabled = val; 127 UpdateWdogBiteInterrupts(); 128 wdogBarkInnerTimer.Enabled = val; 129 UpdateWdogBarkInterrupts(); 130 }) 131 .WithFlag(1, out pauseInSleep, name: "pause_in_sleep") 132 .WithReservedBits(2, 30); 133 134 Registers.WatchdogTimerBarkThreshold.Define(this) 135 .WithValueField(0, 32, name: "threshold", 136 valueProviderCallback: _ => (uint)wdogBarkInnerTimer.Compare, 137 writeCallback: (_, val) => 138 { 139 if(!wdogConfigNotLocked.Value) 140 { 141 this.Log(LogLevel.Warning, "Watchdog timer configuration is locked"); 142 return; 143 } 144 145 wdogBarkInnerTimer.Compare = val; 146 UpdateWdogBarkInterrupts(); 147 }); 148 149 Registers.WatchdogTimerBiteThreshold.Define(this) 150 .WithValueField(0, 32, name: "threshold", 151 valueProviderCallback: _ => (uint)wdogBiteInnerTimer.Compare, 152 writeCallback: (_, val) => 153 { 154 if(!wdogConfigNotLocked.Value) 155 { 156 this.Log(LogLevel.Warning, "Watchdog timer configuration is locked"); 157 return; 158 } 159 160 wdogBiteInnerTimer.Compare = val; 161 UpdateWdogBiteInterrupts(); 162 }); 163 164 Registers.WatchdogTimerCount.Define(this) 165 .WithValueField(0, 32, name: "count", 166 valueProviderCallback: _ => (uint)wdogBiteInnerTimer.Value, 167 writeCallback: (_, val) => 168 { 169 if(!wdogConfigNotLocked.Value) 170 { 171 this.Log(LogLevel.Warning, "Watchdog timer configuration is locked"); 172 return; 173 } 174 175 wdogBiteInnerTimer.Value = val; 176 UpdateWdogBiteInterrupts(); 177 wdogBarkInnerTimer.Value = val; 178 UpdateWdogBarkInterrupts(); 179 }); 180 181 Registers.InterruptState.Define(this) 182 .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, name: "wkup_timer_expired", 183 valueProviderCallback: _ => WakeupTimerExpired.IsSet, 184 writeCallback: (_, val) => { if(val) WakeupTimerExpired.Set(false); }) 185 .WithFlag(1, FieldMode.Read | FieldMode.WriteOneToClear, name: "wdog_timer_bark", 186 valueProviderCallback: _ => WatchdogTimerBark.IsSet, 187 writeCallback: (_, val) => { if(val) WatchdogTimerBark.Set(false); }) 188 .WithReservedBits(2, 30); 189 190 Registers.InterruptTest.Define(this) 191 .WithFlag(0, FieldMode.Write, name: "wkup_timer_expired", 192 writeCallback: (_, newValue) => 193 { 194 if(newValue) 195 { 196 WakeupTimerExpired.Set(true); 197 } 198 }) 199 .WithFlag(1, FieldMode.Write, name: "wdog_timer_bark", 200 writeCallback: (_, newValue) => 201 { 202 if(newValue) 203 { 204 WatchdogTimerBark.Set(true); 205 } 206 }) 207 .WithReservedBits(2, 30); 208 209 Registers.WakeupRequestStatus.Define(this) 210 .WithFlag(0, out wakeupLevelSignal, FieldMode.Read | FieldMode.WriteZeroToClear, name: "cause") 211 .WithReservedBits(1, 31); 212 } 213 UpdateWakeupInterrupts()214 private void UpdateWakeupInterrupts() 215 { 216 var isActive = wkupTimer.Enabled && wkupTimer.Value >= wkupTimer.Compare; 217 wakeupLevelSignal.Value = isActive; 218 if(isActive && lowPowerState) 219 { 220 // Set wakeup level signal 221 powerManager.RequestWakeup(); 222 } 223 WakeupTimerExpired.Set(isActive); 224 } 225 UpdateWdogBarkInterrupts()226 private void UpdateWdogBarkInterrupts() 227 { 228 var isActive = wdogBarkInnerTimer.Enabled && wdogBarkInnerTimer.Value >= wdogBarkInnerTimer.Compare; 229 WatchdogTimerBark.Set(isActive); 230 this.Log(LogLevel.Debug, "Watchdog bark interrupt is {0}", isActive ? "active" : "inactive"); 231 } 232 UpdateWdogBiteInterrupts()233 private void UpdateWdogBiteInterrupts() 234 { 235 var isActive = wdogBiteInnerTimer.Enabled && wdogBiteInnerTimer.Value >= wdogBiteInnerTimer.Compare; 236 if(isActive) 237 { 238 // Set bite level signal 239 this.Log(LogLevel.Info, "Watchdog timer bite"); 240 resetManager.PeripheralRequestedReset(OpenTitan_ResetManager.HardwareResetReason.Watchdog, lowPowerState); 241 } 242 } 243 244 private readonly ComparingTimer wkupTimer, wdogBarkInnerTimer, wdogBiteInnerTimer; 245 246 private IFlagRegisterField pauseInSleep; 247 private IFlagRegisterField wakeupLevelSignal; 248 private IFlagRegisterField wdogConfigNotLocked; 249 250 private readonly OpenTitan_PowerManager powerManager; 251 private readonly OpenTitan_ResetManager resetManager; 252 private bool lowPowerState; 253 254 public enum Registers 255 { 256 AlertTest = 0x0, 257 WakeupTimerControl = 0x4, 258 WakeupTimerThreshold = 0x8, 259 WakeupTimerCount = 0xc, 260 WatchdogTimerWriteEnable = 0x10, 261 WatchdogTimerControl = 0x14, 262 WatchdogTimerBarkThreshold = 0x18, 263 WatchdogTimerBiteThreshold = 0x1c, 264 WatchdogTimerCount = 0x20, 265 InterruptState = 0x24, 266 InterruptTest = 0x28, 267 WakeupRequestStatus = 0x2c, 268 } 269 } 270 } 271