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