1 // 2 // Copyright (c) 2010-2025 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 System; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Peripherals.Timers; 15 16 namespace Antmicro.Renode.Peripherals.Miscellaneous 17 { 18 public sealed class NRF_CLOCK : BasicDoubleWordPeripheral, IKnownSize 19 { NRF_CLOCK(IMachine machine)20 public NRF_CLOCK(IMachine machine) : base(machine) 21 { 22 // Renode, in general, does not include clock control peripherals. 23 // While this is doable, it seldom benefits real software development 24 // and is very cumbersome to maintain. 25 // 26 // To properly support the CLOCK peripheral, we need to add this stub class. 27 // It is common in Renode that whenever a register is implemented, it 28 // either contains actual logic or tags, indicating not implemented fields. 29 // 30 // Here, however, we want to fake most of the registers as r/w values. 31 // Usually we implemented this logic with Python peripherals. 32 // 33 // Keep in mind that most of these registers do not affect other 34 // peripherals or their clocks. 35 36 // nRF52840 documentation doesn't acknowledge hfclk192, but for USB pullup to happen 37 // under Zephyr, those flags and IRQ have to be handled. 38 IRQ = new GPIO(); 39 DefineRegisters(); 40 } 41 Reset()42 public override void Reset() 43 { 44 base.Reset(); 45 lfclkStarted = false; 46 hfclkStarted = false; 47 Update(); 48 } 49 50 public long Size => 0x1000; 51 52 public GPIO IRQ { get; } 53 Update()54 private void Update() 55 { 56 bool irq = (lfclkEventGenerated.Value && lfclkStartedEventEnabled.Value) 57 || (lfclkCalibrationEventGenerated.Value && lfclkCalibrationEventEnabled.Value) 58 || (hfclkEventGenerated.Value && hfclkStartedEventEnabled.Value) 59 || (hfclk192mStartedEventEnabled.Value && hfclk192mStarted); 60 this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irq); 61 IRQ.Set(irq); 62 } 63 DefineRegisters()64 private void DefineRegisters() 65 { 66 Registers.HFXOCrystalOscillatorStarted.Define(this) 67 .WithFlag(0, out hfclkEventGenerated, name: "EVENTS_HFCLKSTARTED") 68 .WithReservedBits(1, 31) 69 .WithWriteCallback((_, __) => Update()); 70 71 Registers.LFCLKStarted.Define(this) 72 .WithFlag(0, out lfclkEventGenerated, name: "EVENTS_LFCLKSTARTED") 73 .WithReservedBits(1, 31) 74 .WithWriteCallback((_, __) => Update()); 75 76 Registers.StartHFXO.Define(this) 77 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 78 { 79 hfclkStarted = true; 80 hfclkEventGenerated.Value = true; 81 Update(); 82 }, name: "TASK_HFCLKSTART") 83 .WithReservedBits(1, 31); 84 85 Registers.StopHFXO.Define(this) 86 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 87 { 88 hfclkStarted = false; 89 hfclkEventGenerated.Value = false; 90 Update(); 91 }, name: "TASK_HFCLKSTOP") 92 .WithReservedBits(1, 31); 93 94 Registers.StartLFCLK.Define(this) 95 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 96 { 97 lfclkStarted = true; 98 lfclkEventGenerated.Value = true; 99 Update(); 100 }, name: "TASK_LFCLKSTART") 101 .WithReservedBits(1, 31); 102 103 Registers.StartHfClock192M.Define(this) 104 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 105 { 106 hfclk192mStarted = true; 107 Update(); 108 }, name: "TASKS_HFCLK192MSTART") 109 .WithReservedBits(1, 31); 110 111 Registers.CalibrationOfLFRCCompleted.Define(this) 112 .WithFlag(0, out lfclkCalibrationEventGenerated, name: "EVENTS_HFCLKSTARTED") 113 .WithReservedBits(1, 31) 114 .WithWriteCallback((_, __) => Update()); 115 116 Registers.StartLFRCCallibration.Define(this) 117 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 118 { 119 lfclkCalibrationEventGenerated.Value = true; 120 Update(); 121 }).WithReservedBits(1, 31); 122 123 Registers.StopCallibrationTimer.Define(this) 124 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 125 { 126 lfclkCalibrationEventGenerated.Value = false; 127 Update(); 128 }).WithReservedBits(1, 31); 129 130 Registers.PowerUsbRegisterStatus.Define(this) 131 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "VBUSDETECT") 132 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "OUTPUTRDY") 133 .WithReservedBits(2, 30); 134 135 Registers.PowerUSBUsbRemovedEvent.Define(this) 136 .WithFlag(0, valueProviderCallback: _ => false, name: "EVENTS_USBDETECTED") 137 .WithReservedBits(1, 31); 138 139 Registers.PowerUSBDetectedEvent.Define(this) 140 .WithFlag(0, 141 valueProviderCallback: _ => true, name: "EVENTS_USBREMOVED") 142 .WithReservedBits(1, 31); 143 144 Registers.PowerUSBPowerReadyEvent.Define(this) 145 .WithFlag(0, valueProviderCallback: _ => true, name: "EVENTS_USBPWRRDY") 146 .WithReservedBits(1, 31); 147 148 Registers.StopLFCLK.Define(this) 149 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => 150 { 151 lfclkStarted = false; 152 lfclkEventGenerated.Value = false; 153 Update(); 154 }, name: "TASK_LFCLKSTOP") 155 .WithReservedBits(1, 31); 156 Registers.EnableInterrupt.Define(this) 157 .WithFlag(0, out hfclkStartedEventEnabled, FieldMode.Read | FieldMode.Set, name: "HFCLKSTARTED") 158 .WithFlag(1, out lfclkStartedEventEnabled, FieldMode.Read | FieldMode.Set, name: "LFCLKSTARTED") 159 .WithReservedBits(2, 1) 160 .WithFlag(3, out lfclkCalibrationEventEnabled, FieldMode.Read | FieldMode.Set, name: "DONE") 161 .WithTaggedFlag("CTTO", 4) 162 .WithReservedBits(5, 2) 163 .WithTaggedFlag("DONE (nRF5340)", 7) // nRF5340, but also nRF52840 USB 164 .WithFlag(8, out hfclk192mAudioStartedEventEnabled, FieldMode.Read | FieldMode.Set, name: "HFCLKAUDIOSTARTED") // nRF5340, but also nRF52840 with USB 165 .WithFlag(9, out hfclk192mStartedEventEnabled, FieldMode.Read | FieldMode.Set, name: "HFCLK192MSTARTED") // nRF5340, but also nRF52840 with USB 166 .WithTaggedFlag("CTSTARTED", 10) 167 .WithTaggedFlag("CTSTOPPED", 11) 168 .WithReservedBits(12, 20) 169 .WithWriteCallback((_, __) => Update()); 170 171 Registers.DisableInterrupt.Define(this) 172 .WithFlag(0, 173 writeCallback: (_, value) => hfclkStartedEventEnabled.Value &= !value, 174 valueProviderCallback: _ => hfclkStartedEventEnabled.Value, name: "HFCLKSTARTED") 175 .WithFlag(1, 176 writeCallback: (_, value) => lfclkStartedEventEnabled.Value &= !value, 177 valueProviderCallback: _ => lfclkStartedEventEnabled.Value, name: "LFCLKSTARTED") 178 .WithReservedBits(2, 1) 179 .WithFlag(3, 180 writeCallback: (_, value) => lfclkCalibrationEventEnabled.Value &= !value, 181 valueProviderCallback: _ => lfclkCalibrationEventEnabled.Value, name: "DONE") 182 .WithTaggedFlag("CTTO", 4) 183 .WithReservedBits(5, 2) 184 .WithTaggedFlag("DONE (nRF540)", 7) // nRF5340, but also nRF52840 USB 185 .WithFlag(8, 186 writeCallback: (_, value) => hfclk192mAudioStartedEventEnabled.Value &= !value, 187 valueProviderCallback: _ => hfclk192mAudioStartedEventEnabled.Value, name: "HFCLKAUDIOSTARTED") // nRF5340, but also nRF52840 with USB 188 .WithFlag(9, 189 writeCallback: (_, value) => hfclk192mStartedEventEnabled.Value &= !value, 190 valueProviderCallback: _ => hfclk192mStartedEventEnabled.Value, name: "HFCLK192MSTARTED") // nRF5340, but also nRF52840 with USB 191 .WithTaggedFlag("CTSTARTED", 10) 192 .WithTaggedFlag("CTSTOPPED", 11) 193 .WithReservedBits(12, 20) 194 .WithWriteCallback((_, __) => Update()); 195 196 Registers.LFCLKClockSource.Define(this) 197 .WithValueField(0, 2, out var lfclkSource, name: "SRC") 198 .WithReservedBits(2, 14) 199 .WithFlag(16, name: "BYPASS") 200 .WithFlag(17, name: "EXTERNAL") 201 .WithReservedBits(18, 14); 202 203 Registers.HFCLKStatus.Define(this) 204 // true in the first bit indicates that hfclk is started. Not sure if it's possible to return true in STATE and false in SRC 205 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => hfclkStarted, name: "SRC") 206 .WithReservedBits(1, 15) 207 .WithFlag(16, FieldMode.Read, valueProviderCallback: _ => hfclkStarted, name: "STATE") 208 .WithReservedBits(17, 15); 209 210 Registers.LFCLKStatus.Define(this) 211 .WithValueField(0, 2, FieldMode.Read, valueProviderCallback: _ => lfclkSource.Value, name: "SRC") 212 .WithReservedBits(2, 14) 213 .WithFlag(16, FieldMode.Read, valueProviderCallback: _ => lfclkStarted, name: "STATE") 214 .WithReservedBits(17, 15); 215 216 Registers.PowerUSBMainRegisterStatus.Define(this) 217 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "MAINREGSTATUS") 218 .WithReservedBits(1, 31); 219 } 220 221 private bool lfclkStarted; 222 private bool hfclkStarted; 223 private bool hfclk192mStarted; 224 private IFlagRegisterField lfclkStartedEventEnabled; 225 private IFlagRegisterField lfclkEventGenerated; 226 private IFlagRegisterField hfclkStartedEventEnabled; 227 private IFlagRegisterField hfclkEventGenerated; 228 private IFlagRegisterField hfclk192mStartedEventEnabled; 229 private IFlagRegisterField hfclk192mAudioStartedEventEnabled; 230 private IFlagRegisterField lfclkCalibrationEventEnabled; 231 private IFlagRegisterField lfclkCalibrationEventGenerated; 232 233 private enum Registers 234 { 235 StartHFXO = 0x0, 236 StopHFXO = 0x4, 237 StartLFCLK = 0x8, 238 StopLFCLK = 0xC, 239 StartLFRCCallibration = 0x10, 240 StartCallibrationTimer = 0x14, 241 StopCallibrationTimer = 0x18, 242 StartHfClock192M = 0x20, // nRF5340 243 HFXOCrystalOscillatorStarted = 0x100, 244 LFCLKStarted = 0x104, 245 CalibrationOfLFRCCompleted = 0x10C, 246 CalibrationTimerTimeout = 0x110, 247 PowerUSBDetectedEvent = 0x11C, // POWER peripheral 248 PowerUSBUsbRemovedEvent = 0x120, // POWER peripheral 249 PowerUSBPowerReadyEvent = 0x124, // POWER peripheral 250 CalibrationTimerStarted = 0x128, 251 CalibrationTimerStopped = 0x12C, 252 EnableInterrupt = 0x304, 253 DisableInterrupt = 0x308, 254 HFCLKStartTriggered = 0x408, 255 HFCLKStatus = 0x40C, 256 LFCLKStartTriggered = 0x414, 257 LFCLKStatus = 0x418, 258 LFCLKClockSourceCopy = 0x41C, 259 PowerUsbRegisterStatus = 0x438, 260 LFCLKClockSource = 0x518, 261 HFXODebounceTime = 0x528, 262 CallibrationTimerInterval = 0x538, 263 TraceConfig = 0x55C, 264 LFRCModeConfiguration = 0x5B4, 265 PowerUSBMainRegisterStatus = 0x640 266 } 267 } 268 } 269