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 
12 namespace Antmicro.Renode.Peripherals.Miscellaneous
13 {
14     public class OpenTitan_PowerManager : BasicDoubleWordPeripheral, IKnownSize
15     {
OpenTitan_PowerManager(IMachine machine, OpenTitan_ResetManager resetManager)16         public OpenTitan_PowerManager(IMachine machine, OpenTitan_ResetManager resetManager) : base(machine)
17         {
18             this.resetManager = resetManager;
19             IRQ = new GPIO();
20             FatalAlert = new GPIO();
21             DefineRegisters();
22         }
23 
Reset()24         public override void Reset()
25         {
26             base.Reset();
27             FatalAlert.Unset();
28         }
29 
RequestWakeup()30         public void RequestWakeup()
31         {
32             if(lowPowerHint.Value)
33             {
34                 // Wakeup level signal from peripheral is active
35                 OnLowPowerStateChange(false);
36                 lowPowerHint.Value = false;
37                 resetManager.LowPowerExitReset();
38             }
39         }
40 
41         public long Size => 0x100;
42 
43         public GPIO IRQ { get; }
44         public GPIO FatalAlert { get; }
45 
46         public event Action<bool> LowPowerStateChanged;
47 
OnLowPowerStateChange(bool lowPowered)48         private void OnLowPowerStateChange(bool lowPowered)
49         {
50             LowPowerStateChanged?.Invoke(lowPowered);
51         }
52 
DefineRegisters()53         private void DefineRegisters()
54         {
55             Registers.InterruptState.Define(this)
56                 .WithFlag(0, out wakeupState, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.wakeup")
57                 .WithIgnoredBits(1, 31)
58                 .WithWriteCallback((_, __) => UpdateInterrupts());
59 
60             Registers.InterruptEnable.Define(this)
61                 .WithFlag(0, out wakeupEnable, name: "INTR_ENABLE.wakeup")
62                 .WithIgnoredBits(1, 31)
63                 .WithWriteCallback((_, __) => UpdateInterrupts());
64 
65             Registers.InterruptTest.Define(this)
66                 .WithFlag(0, FieldMode.Write, name: "INTR_TEST.wakeup", writeCallback: (_, val) =>
67                 {
68                     wakeupState.Value |= val;
69                     UpdateInterrupts();
70                 })
71                 .WithIgnoredBits(1, 31);
72 
73             Registers.AlertTest.Define(this)
74                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
75                 .WithIgnoredBits(1, 31);
76 
77             Registers.ControlConfigRegWriteEnable.Define(this, 0x1)
78                 .WithFlag(0, out controlConfigRegWriteEnable, FieldMode.Read, name: "CTRL_CFG_REGWEN.EN")
79                 .WithIgnoredBits(1, 31);
80 
81             Registers.Control.Define(this, 0x180)
82                 .WithFlag(0, out lowPowerHint)
83                 .WithReservedBits(1, 3)
84                 .WithFlag(4, out coreClockEnable)
85                 .WithFlag(5, out ioClockEnable)
86                 .WithFlag(6, out usbClockEnableLowPower)
87                 .WithFlag(7, out usbClockEnableActive)
88                 .WithFlag(8, out mainPowerDown)
89                 .WithReservedBits(9, 23)
90                 .WithWriteCallback((_, __) => LogPowerState());
91 
92             Registers.ConfigClockDomainSync.Define(this)
93                 .WithFlag(0, name: "SYNC",
94                     valueProviderCallback: _ => false,
95                     writeCallback: (_, val) =>
96                     {
97                         if(val)
98                         {
99                             if(lowPowerHint.Value)
100                             {
101                                 OnLowPowerStateChange(true);
102                             }
103                             else
104                             {
105                                 OnLowPowerStateChange(false);
106                             }
107                         }
108                     })
109                 .WithReservedBits(1, 31);
110 
111             Registers.WakeupEnableRegWriteEnable.Define(this, 0x1)
112                 .WithTaggedFlag("WAKEUP_EN_REGWEN.EN", 0)
113                 .WithReservedBits(1, 31);
114 
115             Registers.WakeupEnable.Define(this)
116                 .WithFlags(0, NumberOfWakeupSources, out wakeupEnableFlags, name: "WAKEUP_EN");
117 
118             Registers.WakeStatus.Define(this)
119                 .WithFlags(0, NumberOfWakeupSources, out wakeStatusFlags, FieldMode.Read, name: "WAKE_STATUS");
120 
121             Registers.ResetEnableRegWriteEnable.Define(this, 0x1)
122                 .WithTaggedFlag("RESET_EN_REGWEN.EN", 0)
123                 .WithReservedBits(1, 31);
124 
125             Registers.ResetEnable.Define(this)
126                 .WithTaggedFlag("RESET_EN.EN0", 0)
127                 .WithTaggedFlag("RESET_EN.EN1", 1)
128                 .WithReservedBits(2, 30);
129 
130             Registers.ResetStatus.Define(this)
131                 .WithTaggedFlag("RESET_STATUS.VAL0", 0)
132                 .WithTaggedFlag("RESET_STATUS.VAL1", 1)
133                 .WithReservedBits(2, 30);
134 
135             Registers.EscalateResetStatue.Define(this)
136                 .WithReservedBits(0, 32);
137 
138             Registers.WakeInfoCaptureDis.Define(this)
139                 .WithReservedBits(0, 32);
140 
141             Registers.WakeInfo.Define(this)
142                 .WithReservedBits(0, 32);
143         }
144 
UpdateInterrupts()145         private void UpdateInterrupts()
146         {
147             IRQ.Set(wakeupState.Value && wakeupEnable.Value);
148         }
149 
LogPowerState()150         private void LogPowerState()
151         {
152             this.Log(LogLevel.Debug, "LowPowerHint:{0}, CoreClockEnable:{1}, " +
153                                      "IoClockEnable:{2}, UsbClockEnableLowPower:{3}, " +
154                                      "UsbClockEnableActive: {4}, MainPowerDown: {5}",
155                                      lowPowerHint.Value, coreClockEnable.Value,
156                                      ioClockEnable.Value, usbClockEnableLowPower.Value,
157                                      usbClockEnableActive.Value, mainPowerDown.Value);
158         }
159 
160         private IFlagRegisterField wakeupState;
161         private IFlagRegisterField wakeupEnable;
162 
163         private IFlagRegisterField controlConfigRegWriteEnable;
164 
165         private IFlagRegisterField lowPowerHint;
166         private IFlagRegisterField coreClockEnable;
167         private IFlagRegisterField ioClockEnable;
168         private IFlagRegisterField usbClockEnableLowPower;
169         private IFlagRegisterField usbClockEnableActive;
170         private IFlagRegisterField mainPowerDown;
171 
172         private IFlagRegisterField[] wakeupEnableFlags;
173         private IFlagRegisterField[] wakeStatusFlags;
174 
175         private readonly OpenTitan_ResetManager resetManager;
176         private const int NumberOfWakeupSources = 6;
177 
178         private enum Registers
179         {
180             InterruptState = 0x0,
181             InterruptEnable = 0x4,
182             InterruptTest = 0x8,
183             AlertTest = 0xC,
184             ControlConfigRegWriteEnable = 0x10,
185             Control = 0x14,
186             ConfigClockDomainSync = 0x18,
187             WakeupEnableRegWriteEnable = 0x1C,
188             WakeupEnable = 0x20,
189             WakeStatus = 0x24,
190             ResetEnableRegWriteEnable = 0x28,
191             ResetEnable = 0x2c,
192             ResetStatus = 0x30,
193             EscalateResetStatue = 0x34,
194             WakeInfoCaptureDis = 0x38,
195             WakeInfo = 0x3C
196         }
197     }
198 }
199 
200