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