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