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.Collections.Generic;
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Exceptions;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.CPU;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     // OpenTitan ResetManager as per https://docs.opentitan.org/hw/ip/rstmgr/doc/ (sha: f4e3845)
18     public class OpenTitan_ResetManager : BasicDoubleWordPeripheral, IGPIOReceiver, IKnownSize
19     {
OpenTitan_ResetManager(IMachine machine, ulong resetPC)20         public OpenTitan_ResetManager(IMachine machine, ulong resetPC) : base(machine)
21         {
22             DefineRegisters();
23             this.resetPC = resetPC;
24             skippedOnLifeCycleReset = new HashSet<IPeripheral>();
25             skippedOnSystemReset = new HashSet<IPeripheral>();
26             skippedOnLowPowerExitReset = new HashSet<IPeripheral>();
27             modules = new IPeripheral[numberOfModules];
28 
29             // Outputs
30             LifeCycleState = new GPIO();    // Current state of rst_lc_n tree.
31             SystemState = new GPIO();       // Current state of rst_sys_n tree.
32             Resets = new GPIO();            // Resets used by the rest of the core domain.
33 
34             // Alerts
35             FatalAlert = new GPIO();            // Triggered when a fatal structural fault is detected
36             FatalConsistencyAlert = new GPIO(); // Triggered when a reset consistency fault is detected
37         }
38 
Reset()39         public override void Reset()
40         {
41             base.Reset();
42             FatalAlert.Unset();
43             FatalConsistencyAlert.Unset();
44         }
45 
MarkAsSkippedOnLifeCycleReset(IPeripheral peripheral)46         public void MarkAsSkippedOnLifeCycleReset(IPeripheral peripheral)
47         {
48             if(!skippedOnLifeCycleReset.Contains(peripheral))
49             {
50                 skippedOnLifeCycleReset.Add(peripheral);
51             }
52         }
53 
MarkAsSkippedOnSystemReset(IPeripheral peripheral)54         public void MarkAsSkippedOnSystemReset(IPeripheral peripheral)
55         {
56             if(!skippedOnSystemReset.Contains(peripheral))
57             {
58                 skippedOnSystemReset.Add(peripheral);
59             }
60         }
61 
MarkAsSkippedOnLowPowerExitReset(IPeripheral peripheral)62         public void MarkAsSkippedOnLowPowerExitReset(IPeripheral peripheral)
63         {
64             if(!skippedOnLowPowerExitReset.Contains(peripheral))
65             {
66                 skippedOnLowPowerExitReset.Add(peripheral);
67             }
68         }
69 
LifeCycleReset()70         public void LifeCycleReset()
71         {
72             ExecuteResetWithSkipped(skippedOnLifeCycleReset);
73         }
74 
PeripheralRequestedReset(HardwareResetReason resetReason, bool lowPower)75         public void PeripheralRequestedReset(HardwareResetReason resetReason, bool lowPower)
76         {
77             // Reset initiated by peripheral
78             ExecutePeripheralInitiatedResetWithSkipped(skippedOnSystemReset);
79 
80             hardwareResetRequest.Value = resetReason;
81             lowPowerExitFlag.Value = lowPower;
82             powerOnResetFlag.Value = false;
83             softwareResetFlag.Value = false;
84         }
85 
LowPowerExitReset()86         public void LowPowerExitReset()
87         {
88             ExecutePeripheralInitiatedResetWithSkipped(skippedOnLowPowerExitReset);
89 
90             hardwareResetRequest.Value = 0;
91             lowPowerExitFlag.Value = true;
92             powerOnResetFlag.Value = false;
93             softwareResetFlag.Value = false;
94         }
95 
RegisterModuleSpecificReset(IPeripheral peripheral, uint id)96         public void RegisterModuleSpecificReset(IPeripheral peripheral, uint id)
97         {
98             if(id >= modules.Length)
99             {
100                 throw new RecoverableException($"Id has to be less than {modules.Length}.");
101             }
102             if(modules[id] != null)
103             {
104                 throw new RecoverableException($"Module with id {id} already registered.");
105             }
106             modules[id] = peripheral;
107         }
108 
OnGPIO(int number, bool value)109         public void OnGPIO(int number, bool value)
110         {
111             var signal = (GPIOInput)number;
112             var ignored = false;
113             switch(signal)
114             {
115                 case GPIOInput.PowerOnReset:
116                     if(value)
117                     {
118                         ExecuteResetWithSkipped(null);
119                     }
120                     break;
121                 case GPIOInput.CPUReset:
122                 case GPIOInput.NonDebugModeReset:
123                     if(value)
124                     {
125                         SystemReset();
126                     }
127                     break;
128                 case GPIOInput.CPUDump:
129                     ignored = true;
130                     break;
131                 case GPIOInput.LifeCycleReset:
132                     if(value)
133                     {
134                         LifeCycleReset();
135                     }
136                     break;
137                 case GPIOInput.SystemReset:
138                     if(value)
139                     {
140                         SystemReset();
141                     }
142                     break;
143                 case GPIOInput.ResetCause:
144                 case GPIOInput.PeripheralReset:
145                     ignored = true;
146                     break;
147                 default:
148                     this.Log(LogLevel.Error, "Received GPIO signal on an unsupported port #{0}.", number);
149                     break;
150             }
151             if(ignored)
152             {
153                 this.Log(LogLevel.Warning, "{0} signal ignored. Function not supported.", signal);
154             }
155         }
156 
157         public long Size => 0x1000;
158 
159         public GPIO LifeCycleState { get; }
160         public GPIO SystemState { get; }
161         public GPIO Resets { get; }
162 
163         public GPIO FatalAlert { get; }
164         public GPIO FatalConsistencyAlert { get; }
165 
ExecuteResetWithSkipped(ICollection<IPeripheral> toSkip)166         private void ExecuteResetWithSkipped(ICollection<IPeripheral> toSkip)
167         {
168             // This method is intended to run only as a result of memory access from translated code.
169             if(!machine.TryRestartTranslationBlockOnCurrentCpu())
170             {
171                 this.Log(LogLevel.Error, "Software reset failed.");
172                 return;
173             }
174 
175             // If the translation block restart succeeded, we know GetCurrentCPU is safe
176             var cpu = machine.SystemBus.GetCurrentCPU();
177 
178             machine.RequestResetInSafeState(() =>
179             {
180                 cpu.PC = resetPC;
181                 this.Log(LogLevel.Info, "Software reset complete.");
182             }, unresetable: toSkip);
183         }
184 
ExecutePeripheralInitiatedResetWithSkipped(ICollection<IPeripheral> toSkip)185         private void ExecutePeripheralInitiatedResetWithSkipped(ICollection<IPeripheral> toSkip)
186         {
187             if(!machine.SystemBus.TryGetCurrentCPU(out var cpu))
188             {
189                 this.Log(LogLevel.Error, "Couldn't find the cpu to reset.");
190                 return;
191             }
192 
193             machine.RequestResetInSafeState(() =>
194             {
195                 cpu.PC = resetPC;
196                 this.Log(LogLevel.Info, "Hardware reset complete.");
197             }, unresetable: toSkip);
198         }
199 
SystemReset()200         private void SystemReset()
201         {
202             ExecuteResetWithSkipped(skippedOnSystemReset);
203         }
204 
SoftwareRequestedReset()205         private void SoftwareRequestedReset()
206         {
207             LifeCycleReset();
208             softwareResetFlag.Value = true;
209         }
210 
SetResetHolds(uint value)211         private void SetResetHolds(uint value)
212         {
213             for(byte i = 0; i < softwareControllableResetsWriteEnableMask.Width; ++i)
214             {
215                 if(!BitHelper.IsBitSet(value, i))
216                 {
217                     continue;
218                 }
219                 if(BitHelper.IsBitSet(softwareControllableResetsWriteEnableMask.Value, i))
220                 {
221                     modules[i].Reset();
222                 }
223                 else
224                 {
225                     this.Log(LogLevel.Warning, "Trying to use disabled software controllable reset VAL_{0}.", i);
226                 }
227             }
228         }
229 
DefineRegisters()230         private void DefineRegisters()
231         {
232             Registers.AlertTest.Define(this, 0x0)
233                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
234                 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalConsistencyAlert.Blink(); }, name: "fatal_cnsty_fault")
235                 .WithReservedBits(2, 30);
236             Registers.ResetRequested.Define(this, 0x5)
237                 .WithValueField(0, 4, out resetRequest, name: "VAL")
238                 .WithReservedBits(4, 28)
239                 .WithChangeCallback((_, __) =>
240                     {
241                         if(resetRequest.Value == (uint)MultiBitBool4.True)
242                         {
243                             resetRequest.Value = 0;
244                             SoftwareRequestedReset();
245                         }
246                     });
247             Registers.DeviceResetReason.Define(this, 0x1)
248                 .WithFlag(0, out powerOnResetFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "POR")
249                 .WithFlag(1, out lowPowerExitFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "LOW_POWER_EXIT")
250                 .WithFlag(2, out softwareResetFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "SW_RESET")
251                 .WithEnumField(3, 5, out hardwareResetRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "HW_REQ")
252                 .WithReservedBits(8, 24);
253             Registers.AlertWriteEnable.Define(this, 0x1)
254                 .WithTaggedFlag("EN", 0);
255             Registers.AlertInfoControls.Define(this, 0x0)
256                 .WithTaggedFlag("EN", 0)
257                 .WithReservedBits(1, 3)
258                 .WithTag("INDEX", 4, 4)
259                 .WithReservedBits(8, 24);
260             Registers.AlertInfoAttributes.Define(this, 0x0)
261                 .WithTag("CNT_AVAIL", 0, 4)
262                 .WithReservedBits(4, 24);
263             Registers.AlertDumpInfo.Define(this, 0x0)
264                 .WithTag("VALUE", 0, 32);
265             Registers.CpuWriteEnable.Define(this, 0x0)
266                 .WithTaggedFlag("EN", 0)
267                 .WithReservedBits(1, 31);
268             Registers.CpuInfoControls.Define(this, 0x0)
269                 .WithTaggedFlag("EN", 0)
270                 .WithReservedBits(1, 3)
271                 .WithTag("INDEX", 4, 4)
272                 .WithReservedBits(8, 24);
273             Registers.CpuInfoAttributes.Define(this, 0x0)
274                 .WithTag("CNT_AVAIL", 0, 4)
275                 .WithReservedBits(4, 28);
276             Registers.CpuDumpInformation.Define(this, 0x0)
277                 .WithTag("VALUE", 0, 32);
278             Registers.SoftwareControllableResetsWriteEnable.Define(this, 0xff)
279                 .WithValueField(0, 8, out softwareControllableResetsWriteEnableMask, FieldMode.Read | FieldMode.WriteZeroToClear, name: "EN")
280                 .WithReservedBits(8, 24);
281             Registers.SoftwareControllableResets.Define(this, 0xff)
282                 .WithValueField(0, 8, writeCallback: (_, val) => { SetResetHolds((uint)val); }, name: "VAL")
283                 .WithReservedBits(8, 24);
284             Registers.ErrorCode.Define(this)
285                 .WithTaggedFlag("REG_INTG_ERR", 0)
286                 .WithTaggedFlag("RESET_CONSISTENCY_ERR", 1)
287                 .WithReservedBits(2, 30);
288         }
289 
290         private IValueRegisterField resetRequest;
291         private IFlagRegisterField powerOnResetFlag;
292         private IFlagRegisterField lowPowerExitFlag;
293         private IFlagRegisterField softwareResetFlag;
294         private IEnumRegisterField<HardwareResetReason> hardwareResetRequest;
295         private IValueRegisterField softwareControllableResetsWriteEnableMask;
296         private readonly ulong resetPC;
297         private readonly HashSet<IPeripheral> skippedOnLifeCycleReset;
298         private readonly HashSet<IPeripheral> skippedOnSystemReset;
299         private readonly HashSet<IPeripheral> skippedOnLowPowerExitReset;
300         private readonly IPeripheral[] modules;
301 
302         private const int numberOfModules = 8;
303 
304         public enum GPIOInput
305         {
306             PowerOnReset,       // Input from ast. This signal is the root reset of the design and is used to generate rst_por_n.
307             CPUReset,           // CPU reset indication. This informs the reset manager that the processor has reset.
308             NonDebugModeReset,  // Non-debug-module reset request from rv_dm.
309             CPUDump,            // CPU crash dump state from rv_core_ibex.
310             LifeCycleReset,     // Power manager request to assert the rst_lc_n tree.
311             SystemReset,        // Power manager request to assert the rst_sys_n tree.
312             ResetCause,         // Power manager indication for why it requested reset, the cause can be low power entry or peripheral issued request.
313             PeripheralReset,    // Peripheral reset requests.
314         }
315 
316         public enum HardwareResetReason
317         {
318             SystemResetControl = 0b00001,
319             Watchdog = 0b00010,
320             PowerUnstable = 0b00100,
321             Escalation = 0b01000,
322             NonDebugModule = 0b10000,
323         }
324 
325         private enum Registers
326         {
327             AlertTest = 0x0,                              // Alert Test Register
328             ResetRequested = 0x4,                         // Software requested system reset.
329             DeviceResetReason = 0x8,                      // Device reset reason.
330             AlertWriteEnable = 0xc,                       // Alert write enable
331             AlertInfoControls = 0x10,                     // Alert info dump controls.
332             AlertInfoAttributes = 0x14,                   // Alert info dump attributes.
333             AlertDumpInfo = 0x18,                         // Alert dump information prior to last reset. Which value read is controlled by the ALERT_INFO_CTRL register.
334             CpuWriteEnable = 0x1c,                        // Cpu write enable
335             CpuInfoControls = 0x20,                       // Cpu info dump controls.
336             CpuInfoAttributes = 0x24,                     // Cpu info dump attributes.
337             CpuDumpInformation = 0x28,                    // Cpu dump information prior to last reset. Which value read is controlled by the CPU_INFO_CTRL register.
338             SoftwareControllableResetsWriteEnable = 0x2c, // Register write enable for software controllable resets. When a particular bit value is 0, the corresponding value in SW_RST_CTRL_N can no longer be changed. When a particular bit value is 1, the corresponding value in SW_RST_CTRL_N can be changed.
339             SoftwareControllableResets = 0x30,            // Software controllable resets. When a particular bit value is 0, the corresponding module is held in reset. When a particular bit value is 1, the corresponding module is not held in reset.
340             ErrorCode = 0x34,                             // A bit vector of all the errors that have occurred in reset manager
341         }
342     }
343 }
344