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 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 STM32WBA_PWR : BasicDoubleWordPeripheral, IKnownSize 15 { STM32WBA_PWR(IMachine machine)16 public STM32WBA_PWR(IMachine machine) : base(machine) 17 { 18 IRQ = new GPIO(); 19 20 DefineRegisters(); 21 Reset(); 22 } 23 Reset()24 public override void Reset() 25 { 26 base.Reset(); 27 IRQ.Unset(); 28 Voltage = 3.3; 29 prevPvdo = false; 30 } 31 32 public long Size => 0x400; 33 public GPIO IRQ { get; } 34 35 public double? ThresholdVoltage { get => PvdLevelToVoltage(pvdLevel.Value); } 36 37 public double Voltage 38 { 39 get 40 { 41 return voltage; 42 } 43 set 44 { 45 voltage = value; 46 UpdatePvd(); 47 } 48 } 49 50 public PvdLevelSelection PvdLevel 51 { 52 get 53 { 54 return pvdLevel.Value; 55 } 56 set 57 { 58 pvdLevel.Value = value; 59 UpdatePvd(); 60 } 61 } 62 DefineRegisters()63 private void DefineRegisters() 64 { 65 Registers.Control1.Define(this) 66 .WithTag("LPMS", 0, 3) 67 .WithReservedBits(3, 2) 68 .WithTaggedFlag("R2RSB1", 5) 69 .WithReservedBits(6, 1) 70 .WithTaggedFlag("ULPMEN", 7) 71 .WithReservedBits(8, 1) 72 .WithTaggedFlag("RADIORSB", 9) 73 .WithReservedBits(10, 2) 74 .WithTaggedFlag("R1RSB1", 12) 75 .WithReservedBits(13, 19); 76 Registers.Control2.Define(this) 77 .WithTaggedFlag("SRAM1PDS1", 0) 78 .WithReservedBits(1, 3) 79 .WithTaggedFlag("SRAM2PDS1", 4) 80 .WithReservedBits(5, 3) 81 .WithTaggedFlag("ICRAMPDS", 8) 82 .WithReservedBits(9, 5) 83 .WithTaggedFlag("FLASHFWU", 14) 84 .WithReservedBits(15, 17); 85 Registers.Control3.Define(this) 86 .WithReservedBits(0, 2) 87 .WithTaggedFlag("FSTEN", 2) 88 .WithReservedBits(3, 29); 89 Registers.VoltageScaling.Define(this, 0x0000_8000) 90 .WithReservedBits(0, 15) 91 .WithTaggedFlag("VOSRDY", 15) 92 .WithEnumField<DoubleWordRegister, VoltageScalingRangeSelection>(16, 1, out vosValue, name: "VOS") 93 .WithReservedBits(17, 15); 94 Registers.SupplyVoltageMonitoringControl.Define(this) 95 .WithReservedBits(0, 4) 96 .WithFlag(4, out pvdEnableFlag, name: "PVDE") 97 .WithEnumField<DoubleWordRegister, PvdLevelSelection>(5, 3, out pvdLevel, writeCallback: (_, value) => 98 { 99 if(value == PvdLevelSelection.ExternalInput) 100 { 101 this.Log(LogLevel.Warning, "External PVD input selected, this is not supported"); 102 } 103 UpdatePvd(); 104 }, name: "PVDLS") 105 .WithReservedBits(8, 24); 106 Registers.WakeupControl1.Define(this) 107 .WithTaggedFlag("WUPEN1", 0) 108 .WithTaggedFlag("WUPEN2", 1) 109 .WithTaggedFlag("WUPEN3", 2) 110 .WithTaggedFlag("WUPEN4", 3) 111 .WithTaggedFlag("WUPEN5", 4) 112 .WithTaggedFlag("WUPEN6", 5) 113 .WithTaggedFlag("WUPEN7", 6) 114 .WithTaggedFlag("WUPEN8", 7) 115 .WithReservedBits(8, 24); 116 Registers.WakeupControl2.Define(this) 117 .WithTaggedFlag("WUPP1", 0) 118 .WithTaggedFlag("WUPP2", 1) 119 .WithTaggedFlag("WUPP3", 2) 120 .WithTaggedFlag("WUPP4", 3) 121 .WithTaggedFlag("WUPP5", 4) 122 .WithTaggedFlag("WUPP6", 5) 123 .WithTaggedFlag("WUPP7", 6) 124 .WithTaggedFlag("WUPP8", 7) 125 .WithReservedBits(8, 24); 126 Registers.WakeupControl3.Define(this) 127 .WithTag("WUSEL1", 0, 2) 128 .WithTag("WUSEL2", 2, 2) 129 .WithTag("WUSEL3", 4, 2) 130 .WithTag("WUSEL4", 6, 2) 131 .WithTag("WUSEL5", 8, 2) 132 .WithTag("WUSEL6", 10, 2) 133 .WithTag("WUSEL7", 12, 2) 134 .WithTag("WUSEL8", 14, 2) 135 .WithReservedBits(16, 16); 136 Registers.BackupDomain.Define(this) 137 .WithFlag(0, out backupDomainDisabled, name: "DBP") 138 .WithReservedBits(1, 31); 139 Registers.SecurityConfiguration.Define(this) 140 .WithTaggedFlag("WUP1SEC", 0) 141 .WithTaggedFlag("WUP2SEC", 1) 142 .WithTaggedFlag("WUP3SEC", 2) 143 .WithTaggedFlag("WUP4SEC", 3) 144 .WithTaggedFlag("WUP5SEC", 4) 145 .WithTaggedFlag("WUP6SEC", 5) 146 .WithTaggedFlag("WUP7SEC", 6) 147 .WithTaggedFlag("WUP8SEC", 7) 148 .WithReservedBits(8, 4) 149 .WithTaggedFlag("LPMSEC", 12) 150 .WithTaggedFlag("VDMSEC", 13) 151 .WithTaggedFlag("VBSEC", 14) 152 .WithReservedBits(15, 17); 153 Registers.PrivilegeControl.Define(this) 154 .WithTaggedFlag("SPRIV", 0) 155 .WithTaggedFlag("NSPRIV", 1) 156 .WithReservedBits(2, 30); 157 Registers.Status.Define(this) 158 .WithFlag(0, FieldMode.WriteOneToClear, name: "CSSF", 159 writeCallback: (_, __) => 160 { 161 standbyFlag.Value = false; 162 stopFlag.Value = false; 163 }) 164 .WithFlag(1, out stopFlag, FieldMode.Read, name: "STOPF") 165 .WithFlag(2, out standbyFlag, FieldMode.Read, name: "SBF") 166 .WithReservedBits(3, 29); 167 Registers.SupplyVoltageMonitoringStatus.Define(this, 0x0000_8000) 168 .WithReservedBits(0, 4) 169 .WithFlag(4, out pvdoFlag, FieldMode.Read, name: "PVDO") 170 .WithReservedBits(5, 10) 171 .WithTaggedFlag("ACTVOSRDY", 15) 172 .WithTaggedFlag("ACTVOS", 16) 173 .WithReservedBits(17, 15); 174 Registers.WakeupStatus.Define(this) 175 .WithFlags(0, 8, out wakeupFlags, FieldMode.Read, name: "WUF") 176 .WithReservedBits(8, 24); 177 Registers.WakeupStatusClear.Define(this) 178 .WithFlags(0, 8, FieldMode.WriteOneToClear, name: "CWUF", 179 writeCallback: (idx, _, __) => wakeupFlags[idx].Value = false) 180 .WithReservedBits(8, 24); 181 Registers.GpioAStandbyEnable.Define(this) 182 .WithTag("EN[0:3]", 0, 4) 183 .WithReservedBits(4, 1) 184 .WithTag("EN[5:15]", 5, 11) 185 .WithReservedBits(16, 16); 186 Registers.GpioAStandbyStatus.Define(this) 187 .WithTag("RET[0:3]", 0, 4) 188 .WithReservedBits(4, 1) 189 .WithTag("RET[5:15]", 5, 11) 190 .WithReservedBits(16, 16); 191 Registers.GpioBStandbyEnable.Define(this) 192 .WithTag("EN[0:15]", 0, 16) 193 .WithReservedBits(16, 16); 194 Registers.GpioBStandbyStatus.Define(this) 195 .WithTag("RET[0:15]", 0, 16) 196 .WithReservedBits(16, 16); 197 Registers.GpioCStandbyEnable.Define(this) 198 .WithReservedBits(0, 13) 199 .WithTag("EN[13:15]", 13, 3) 200 .WithReservedBits(16, 16); 201 Registers.GpioCStandbyStatus.Define(this) 202 .WithReservedBits(0, 13) 203 .WithTag("RET[13:15]", 13, 3) 204 .WithReservedBits(16, 16); 205 Registers.GpioHStandbyEnable.Define(this) 206 .WithReservedBits(0, 3) 207 .WithTaggedFlag("EN3", 3) 208 .WithReservedBits(4, 28); 209 Registers.GpioHStandbyStatus.Define(this) 210 .WithReservedBits(0, 3) 211 .WithTaggedFlag("RET3", 3) 212 .WithReservedBits(4, 28); 213 Registers.RadioStatusAndControl.Define(this) 214 .WithTag("MODE", 0, 2) 215 .WithTaggedFlag("PHYMODE", 2) 216 .WithTaggedFlag("ENCMODE", 3) 217 .WithReservedBits(4, 4) 218 .WithTag("RFVDDHPA", 8, 5) 219 .WithReservedBits(13, 2) 220 .WithTaggedFlag("REGPARDYVDDRFPA", 15) 221 .WithReservedBits(16, 16); 222 } 223 PvdLevelToVoltage(PvdLevelSelection level)224 private double? PvdLevelToVoltage(PvdLevelSelection level) 225 { 226 switch(level) 227 { 228 case PvdLevelSelection.V2_0: 229 return 2.0; 230 case PvdLevelSelection.V2_2: 231 return 2.2; 232 case PvdLevelSelection.V2_4: 233 return 2.4; 234 case PvdLevelSelection.V2_5: 235 return 2.5; 236 case PvdLevelSelection.V2_6: 237 return 2.6; 238 case PvdLevelSelection.V2_8: 239 return 2.8; 240 case PvdLevelSelection.V2_9: 241 return 2.9; 242 case PvdLevelSelection.ExternalInput: 243 default: 244 return null; 245 } 246 } 247 UpdatePvd()248 private void UpdatePvd() 249 { 250 if(PvdLevel == PvdLevelSelection.ExternalInput) 251 { 252 // External input is not supported yet, skip updating the pvd 253 return; 254 } 255 256 bool pvdo; 257 if(prevPvdo && Voltage > ThresholdVoltage + Hysteresis) 258 { 259 // PVDO should be false if the voltage was below and is above the threshold 260 pvdo = false; 261 } 262 else if(!prevPvdo && Voltage < ThresholdVoltage - Hysteresis) 263 { 264 // PVDO should be true if the voltage was above and is below the threshold 265 pvdo = true; 266 } 267 else 268 { 269 // No change (within hysteresis) 270 pvdo = prevPvdo; 271 } 272 prevPvdo = pvdo; 273 pvdo &= pvdEnableFlag.Value; 274 275 pvdoFlag.Value = pvdo; 276 IRQ.Set(pvdo); 277 } 278 279 private IFlagRegisterField[] wakeupFlags = new IFlagRegisterField[8]; 280 private IFlagRegisterField standbyFlag; 281 private IFlagRegisterField stopFlag; 282 private IFlagRegisterField pvdoFlag; 283 private IFlagRegisterField pvdEnableFlag; 284 private IEnumRegisterField<PvdLevelSelection> pvdLevel; 285 private IEnumRegisterField<VoltageScalingRangeSelection> vosValue; 286 private IFlagRegisterField backupDomainDisabled; 287 private double voltage; 288 private bool prevPvdo; 289 290 private const double Hysteresis = 0.1; 291 292 public enum PvdLevelSelection 293 { 294 V2_0 = 0b000, 295 V2_2 = 0b001, 296 V2_4 = 0b010, 297 V2_5 = 0b011, 298 V2_6 = 0b100, 299 V2_8 = 0b101, 300 V2_9 = 0b110, 301 ExternalInput = 0b111, 302 } 303 304 private enum Registers 305 { 306 Control1 = 0x00, 307 Control2 = 0x04, 308 Control3 = 0x08, 309 VoltageScaling = 0x0C, 310 SupplyVoltageMonitoringControl = 0x10, 311 WakeupControl1 = 0x14, 312 WakeupControl2 = 0x18, 313 WakeupControl3 = 0x1C, 314 // Reserved = 0x20 - 0x24 315 BackupDomain = 0x28, 316 SecurityConfiguration = 0x30, 317 PrivilegeControl = 0x34, 318 Status = 0x38, 319 SupplyVoltageMonitoringStatus = 0x3C, 320 // Reserved = 0x40 321 WakeupStatus = 0x44, 322 WakeupStatusClear = 0x48, 323 // Reserved = 0x4C 324 GpioAStandbyEnable = 0x50, 325 GpioAStandbyStatus = 0x54, 326 GpioBStandbyEnable = 0x58, 327 GpioBStandbyStatus = 0x5C, 328 GpioCStandbyEnable = 0x60, 329 GpioCStandbyStatus = 0x64, 330 // Reserved = 0x68 - 0x84 331 GpioHStandbyEnable = 0x88, 332 GpioHStandbyStatus = 0x8C, 333 // Reserved = 0x90 - 0xFC 334 RadioStatusAndControl = 0x100, 335 } 336 337 private enum VoltageScalingRangeSelection 338 { 339 LowestPower, 340 HighestFrequency, 341 } 342 } 343 } 344