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 System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Utilities;
16 
17 namespace Antmicro.Renode.Peripherals.I2C
18 {
19     public class NRF52840_I2C : SimpleContainer<II2CPeripheral>, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize
20     {
NRF52840_I2C(IMachine machine)21         public NRF52840_I2C(IMachine machine) : base(machine)
22         {
23             IRQ = new GPIO();
24 
25             slaveToMasterBuffer = new Queue<byte>();
26             masterToSlaveBuffer = new Queue<byte>();
27 
28             RegistersCollection = new DoubleWordRegisterCollection(this);
29             DefineRegisters();
30         }
31 
Reset()32         public override void Reset()
33         {
34             slaveToMasterBuffer.Clear();
35             masterToSlaveBuffer.Clear();
36 
37             selectedSlave = null;
38             enabled = false;
39             transmissionInProgress = false;
40 
41             RegistersCollection.Reset();
42             UpdateInterrupts();
43         }
44 
ReadDoubleWord(long offset)45         public uint ReadDoubleWord(long offset)
46         {
47             return RegistersCollection.Read(offset);
48         }
49 
WriteDoubleWord(long offset, uint value)50         public void WriteDoubleWord(long offset, uint value)
51         {
52             RegistersCollection.Write(offset, value);
53         }
54 
55         public GPIO IRQ { get; }
56 
57         public long Size => 0x1000;
58 
59         public DoubleWordRegisterCollection RegistersCollection { get; }
60 
DefineRegisters()61         private void DefineRegisters()
62         {
63             Registers.StartReceiving.Define(this)
64                 .WithFlag(0, FieldMode.Write, name: "TASKS_STARTRX", writeCallback: (_, val) =>
65                 {
66                     if(!val)
67                     {
68                         return;
69                     }
70 
71                     transmissionInProgress = true;
72                     // send what is buffered as this might be a repeated start condition
73                     TrySendDataToSlave();
74                     // prepare to receive data from slave
75                     slaveToMasterBuffer.Clear();
76                     // try read the response
77                     TryFillReceivedBuffer(true);
78                 })
79                 .WithReservedBits(1, 31)
80             ;
81 
82             Registers.StartTransmitting.Define(this)
83                 .WithFlag(0, FieldMode.Write, name: "TASKS_STARTTX", writeCallback: (_, val) =>
84                 {
85                     if(!val)
86                     {
87                         return;
88                     }
89 
90                     transmissionInProgress = true;
91                     // send what is buffered as this might be a repeated start condition
92                     TrySendDataToSlave();
93                     // prepare to receive data from slave
94                     slaveToMasterBuffer.Clear();
95                     // wait for writing bytes to TransferBuffer...
96                 })
97                 .WithReservedBits(1, 31)
98             ;
99 
100             Registers.StopTransmitting.Define(this)
101                 .WithFlag(0, FieldMode.Write, name: "TASKS_STOP", writeCallback: (_, val) =>
102                 {
103                     if(!val)
104                     {
105                         return;
106                     }
107 
108                     StopTransmission();
109                 })
110                 .WithReservedBits(1, 31)
111             ;
112 
113             Registers.ResumeReceiving.Define(this)
114                 .WithFlag(0, FieldMode.Write, name: "TASKS_RESUME", writeCallback: (_, val) =>
115                 {
116                     if(!val)
117                     {
118                         return;
119                     }
120 
121                     if(!transmissionInProgress)
122                     {
123                         return;
124                     }
125 
126                     TryFillReceivedBuffer(true);
127                 })
128                 .WithReservedBits(1, 31)
129             ;
130 
131             Registers.StoppedInterruptPending.Define(this)
132                 .WithFlag(0, out stoppedInterruptPending, name: "EVENTS_STOPPED")
133                 .WithReservedBits(1, 31)
134                 .WithWriteCallback((_, __) => UpdateInterrupts())
135             ;
136 
137             Registers.RxInterruptPending.Define(this)
138                 .WithFlag(0, out rxInterruptPending, name: "EVENTS_RXREADY")
139                 .WithReservedBits(1, 31)
140                 .WithWriteCallback((_, __) => UpdateInterrupts())
141             ;
142 
143             Registers.TxInterruptPending.Define(this)
144                 .WithFlag(0, out txInterruptPending, name: "EVENTS_TXDSENT")
145                 .WithReservedBits(1, 31)
146                 .WithWriteCallback((_, __) => UpdateInterrupts())
147             ;
148 
149             Registers.ErrorInterruptPending.Define(this)
150                 .WithFlag(0, out errorInterruptPending, name: "EVENTS_ERROR")
151                 .WithReservedBits(1, 31)
152                 .WithWriteCallback((_, __) => UpdateInterrupts())
153             ;
154 
155             Registers.ErrorSource.Define(this)
156                 .WithTaggedFlag("OVERRUN", 0)
157                 .WithFlag(1, out addressNackError, name: "ANACK")
158                 .WithTaggedFlag("DNACK", 2)
159                 .WithReservedBits(3, 29)
160             ;
161 
162             Registers.Shortcuts.Define(this)
163                 .WithTag("BB_SUSPEND", 0, 1)
164                 .WithFlag(1, out byteBoundaryStopShortcut, name: "BB_STOP")
165                 .WithReservedBits(2, 30)
166             ;
167 
168             Registers.SetEnableInterrupts.Define(this)
169                 .WithReservedBits(0, 1)
170                 .WithFlag(1, out stoppedInterruptEnabled, FieldMode.Read | FieldMode.Set, name: "STOPPED")
171                 .WithFlag(2, out rxInterruptEnabled, FieldMode.Read | FieldMode.Set, name: "RXREADY")
172                 .WithReservedBits(3, 4)
173                 .WithFlag(7, out txInterruptEnabled, FieldMode.Read | FieldMode.Set, name: "TXDSENT")
174                 .WithReservedBits(8, 1)
175                 .WithFlag(9, out errorInterruptEnabled, FieldMode.Read | FieldMode.Set, name: "ERROR")
176                 .WithReservedBits(10, 4)
177                 .WithFlag(14, name: "BB") // this is a flag to limit warnings, we don't support the byte-boundary interrupt
178                 .WithReservedBits(15, 3)
179                 .WithFlag(18, name: "SUSPENDED") // this is a flag to limit warnings, we don't support the suspended interrupt
180                 .WithReservedBits(19, 13)
181                 .WithWriteCallback((_, __) => UpdateInterrupts())
182             ;
183 
184             Registers.ClearEnableInterrupts.Define(this)
185                 .WithReservedBits(0, 1)
186                 .WithFlag(1, name: "STOPPED",
187                     writeCallback: (_, val) => { if(val) stoppedInterruptEnabled.Value = false; },
188                     valueProviderCallback: _ => stoppedInterruptEnabled.Value)
189                 .WithFlag(2, name: "RXREADY",
190                     writeCallback: (_, val) => { if(val) rxInterruptEnabled.Value = false; },
191                     valueProviderCallback: _ => rxInterruptEnabled.Value)
192                 .WithReservedBits(3, 4)
193                 .WithFlag(7, name: "TXDSENT",
194                     writeCallback: (_, val) => { if(val) txInterruptEnabled.Value = false; },
195                     valueProviderCallback: _ => txInterruptEnabled.Value)
196                 .WithReservedBits(8, 1)
197                 .WithFlag(9, name: "ERROR",
198                     writeCallback: (_, val) => { if(val) errorInterruptEnabled.Value = false; },
199                     valueProviderCallback: _ => errorInterruptEnabled.Value)
200                 .WithReservedBits(10, 4)
201                 .WithFlag(14, name: "BB") // this is a flag to limit warnings, we don't support the byte-boundary interrupt
202                 .WithReservedBits(15, 3)
203                 .WithFlag(18, name: "SUSPENDED") // this is a flag to limit warnings, we don't support the suspended interrupt
204                 .WithReservedBits(19, 13)
205                 .WithWriteCallback((_, __) => UpdateInterrupts())
206             ;
207 
208             Registers.Enable.Define(this)
209                 .WithValueField(0, 4, writeCallback: (_, val) =>
210                 {
211                     switch(val)
212                     {
213                         case 0:
214                             enabled = false;
215                             break;
216 
217                         case 5:
218                             enabled = true;
219                             break;
220 
221                         default:
222                             this.Log(LogLevel.Warning, "Wrong enabled value");
223                             break;
224                     }
225                 })
226                 .WithReservedBits(4, 28)
227             ;
228 
229             Registers.ReceiveBuffer.Define(this)
230                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ =>
231                 {
232                     if(!TryReadFromSlave(out var result))
233                     {
234                         this.Log(LogLevel.Warning, "Trying to read from an empty fifo");
235                         result = 0;
236                     }
237 
238                     if(byteBoundaryStopShortcut.Value)
239                     {
240                         StopTransmission();
241                     }
242 
243                     return result;
244                 })
245                 .WithReservedBits(8, 24)
246             ;
247 
248             Registers.TransferBuffer.Define(this)
249                 .WithValueField(0, 8, writeCallback: (_, val) =>
250                 {
251                     if(selectedSlave == null)
252                     {
253                         this.Log(LogLevel.Warning, "No slave is currently attached at selected address 0x{0:X}", address.Value);
254                         addressNackError.Value = true;
255                         errorInterruptPending.Value = true;
256                         UpdateInterrupts();
257                         return;
258                     }
259 
260                     this.Log(LogLevel.Noisy, "Enqueuing byte 0x{0:X}", val);
261                     masterToSlaveBuffer.Enqueue((byte)val);
262 
263                     txInterruptPending.Value = true;
264                     UpdateInterrupts();
265                 })
266                 .WithReservedBits(8, 24)
267             ;
268 
269             Registers.Address.Define(this)
270                 .WithValueField(0, 7, out address, writeCallback: (_, val) =>
271                 {
272                     if(!TryGetByAddress((int)val, out selectedSlave))
273                     {
274                         this.Log(LogLevel.Warning, "Tried to select a not-connected slave at address 0x{0:X}", val);
275                     }
276                 })
277                 .WithReservedBits(8, 24)
278             ;
279         }
280 
TryFillReceivedBuffer(bool generateInterrupt)281         private bool TryFillReceivedBuffer(bool generateInterrupt)
282         {
283             if(selectedSlave == null)
284             {
285                 return false;
286             }
287 
288             if(!slaveToMasterBuffer.Any())
289             {
290                 var data = selectedSlave.Read();
291                 slaveToMasterBuffer.EnqueueRange(data);
292             }
293 
294             if(slaveToMasterBuffer.Any())
295             {
296                 if(generateInterrupt)
297                 {
298                     rxInterruptPending.Value = true;
299                     UpdateInterrupts();
300                 }
301                 return true;
302             }
303 
304             return false;
305         }
306 
TryReadFromSlave(out byte b)307         private bool TryReadFromSlave(out byte b)
308         {
309             if(!enabled)
310             {
311                 this.Log(LogLevel.Warning, "Tried to read data on a disabled controller");
312                 b = 0;
313                 return false;
314             }
315 
316             if(!slaveToMasterBuffer.TryDequeue(out b))
317             {
318                 TryFillReceivedBuffer(false);
319                 if(!slaveToMasterBuffer.TryDequeue(out b))
320                 {
321                     return false;
322                 }
323             }
324 
325             return true;
326         }
327 
TrySendDataToSlave()328         private bool TrySendDataToSlave()
329         {
330             if(!enabled)
331             {
332                 this.Log(LogLevel.Warning, "Tried to send data on a disabled controller");
333                 return false;
334             }
335 
336             if(!masterToSlaveBuffer.Any())
337             {
338                 return false;
339             }
340 
341             if(selectedSlave == null)
342             {
343                 this.Log(LogLevel.Warning, "No slave is currently attached at selected address 0x{0:X}", address.Value);
344                 return false;
345             }
346 
347             var data = masterToSlaveBuffer.DequeueAll();
348             this.Log(LogLevel.Noisy, "Sending {0} bytes to the device {1}", data.Length, address.Value);
349             selectedSlave.Write(data);
350 
351             return true;
352         }
353 
StopTransmission()354         private void StopTransmission()
355         {
356             transmissionInProgress = false;
357 
358             // send out buffered data to slave;
359             // in reality there is no fifo - each
360             // byte is sent right away, but our
361             // I2C interface in Renode works a bit
362             // different
363             TrySendDataToSlave();
364 
365             selectedSlave?.FinishTransmission();
366 
367             stoppedInterruptPending.Value = true;
368             UpdateInterrupts();
369         }
370 
UpdateInterrupts()371         private void UpdateInterrupts()
372         {
373             var flag = false;
374 
375             flag |= txInterruptEnabled.Value && txInterruptPending.Value;
376             flag |= rxInterruptEnabled.Value && rxInterruptPending.Value;
377             flag |= stoppedInterruptEnabled.Value && stoppedInterruptPending.Value;
378             flag |= errorInterruptEnabled.Value && errorInterruptPending.Value;
379 
380             this.Log(LogLevel.Noisy, "Setting IRQ to {0}", flag);
381             IRQ.Set(flag);
382         }
383 
384         private readonly Queue<byte> slaveToMasterBuffer;
385         private readonly Queue<byte> masterToSlaveBuffer;
386 
387         private II2CPeripheral selectedSlave;
388         private bool enabled;
389         private bool transmissionInProgress;
390 
391         private IValueRegisterField address;
392         private IFlagRegisterField txInterruptPending;
393         private IFlagRegisterField txInterruptEnabled;
394 
395         private IFlagRegisterField rxInterruptPending;
396         private IFlagRegisterField rxInterruptEnabled;
397 
398         private IFlagRegisterField errorInterruptPending;
399         private IFlagRegisterField errorInterruptEnabled;
400 
401         private IFlagRegisterField stoppedInterruptPending;
402         private IFlagRegisterField stoppedInterruptEnabled;
403 
404         private IFlagRegisterField byteBoundaryStopShortcut;
405 
406         private IFlagRegisterField addressNackError;
407 
408         private enum Registers
409         {
410             StartReceiving = 0x000,
411             StartTransmitting = 0x008,
412             StopTransmitting = 0x014,
413             SuspendTransmitting = 0x01C,
414             ResumeReceiving = 0x020,
415             StoppedInterruptPending = 0x104,
416             RxInterruptPending = 0x108,
417             TxInterruptPending = 0x11C,
418             ErrorInterruptPending = 0x124,
419             ByteBoundaryEventPending = 0x138,
420             SuspendedInterruptPending = 0x148,
421             Shortcuts = 0x200,
422             SetEnableInterrupts = 0x304,
423             ClearEnableInterrupts = 0x308,
424             ErrorSource = 0x4C4,
425             Enable = 0x500,
426             PinSelectSCL = 0x508,
427             PinSelectSDA = 0x50C,
428             ReceiveBuffer = 0x518,
429             TransferBuffer = 0x51C,
430             Frequency = 0x524,
431             Address = 0x588
432         }
433     }
434 }
435 
436