1 // 2 // Copyright (c) 2010-2024 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.Peripherals.Bus; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using System.Collections.Generic; 13 using Antmicro.Renode.Utilities; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Exceptions; 16 17 namespace Antmicro.Renode.Peripherals.SPI 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 20 public class MPFS_QSPI: NullRegistrationPointPeripheralContainer<Micron_MT25Q>, IDoubleWordPeripheral, IKnownSize 21 { MPFS_QSPI(IMachine machine, uint size)22 public MPFS_QSPI(IMachine machine, uint size) : base(machine) 23 { 24 locker = new object(); 25 IRQ = new GPIO(); 26 27 if(size < MinimumSize) 28 { 29 throw new ConstructionException($"The {nameof(size)} argument can't be lower than {MinimumSize}."); 30 } 31 Size = size; 32 33 var registerMap = new Dictionary<long, DoubleWordRegister> 34 { 35 {(long)Registers.Control, new DoubleWordRegister(this, 0x402) //the docs report 0x502, but this lights up a reserved bit. 36 .WithFlag(0, out enabled, name: "ENABLE") 37 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "MASTER") 38 .WithFlag(2, out xipMode, name: "XIP") 39 .WithEnumField<DoubleWordRegister, XIPAddressBytes>(3, 1, name: "XIPADDR") 40 .WithReservedBits(4, 6) 41 .WithTag("CLKIDLE", 10, 1) 42 .WithTag("SAMPLE", 11, 2) 43 .WithTag("QSPIMODE[0]", 13, 1) 44 .WithTag("QSPIMODE[1]", 14, 2) 45 .WithFlag(16, out x4Enabled, name: "FLAGS4X") 46 .WithTag("CLKRATE", 24, 4) 47 }, 48 49 {(long)Registers.Frames, new DoubleWordRegister(this) 50 .WithValueField(0, 16, writeCallback: (_, value) => 51 { 52 BitHelper.UpdateWith(ref totalBytes, (uint)value, 0, 16); 53 bytesSent = 0; 54 }, valueProviderCallback: _ => totalBytes, name: "TOTALBYTES") 55 .WithValueField(16, 9, out commandBytes, name: "CMDBYTES") 56 .WithTag("QSPI", 25, 1) 57 .WithValueField(26, 4, writeCallback: (_, value) => 58 { 59 idleCycles = (uint)value; 60 bytesToSkip = value >= 8 ? 1u : 0; 61 if(value != 0 && value != 8) 62 { 63 this.Log(LogLevel.Warning, "Requested {0} idle cycles, but values other than 0 or 8 might not be properly handled.", value); 64 } 65 totalBytes += bytesToSkip; 66 }, valueProviderCallback: _ => idleCycles, name: "IDLE") 67 .WithFlag(30, valueProviderCallback: _ => false, 68 // If set then the FIFO flags are set to byte mode 69 changeCallback: (_, value) => x4Enabled.Value = false, name: "FLAGBYTE") 70 .WithFlag(31, valueProviderCallback: _ => false, 71 // If set then the FIFO flags are set to word mode 72 changeCallback: (_, value) => x4Enabled.Value = true, name: "FLAGWORD") 73 .WithWriteCallback((_, __) => 74 { 75 txDone.Value = false; 76 rxDone.Value = false; 77 RefreshInterrupt(); 78 }) 79 }, 80 81 {(long)Registers.InterruptEnable, new DoubleWordRegister(this) 82 .WithFlag(0, out txDoneInterruptEnabled, name: "TXDONE") 83 .WithFlag(1, out rxDoneInterruptEnabled, name: "RXDONE") 84 .WithFlag(2, out rxAvailableInterruptEnabled, name: "RXAVAILABLE") 85 .WithFlag(3, out txAvailableInterruptEnabled, name: "TXAVAILABLE") 86 .WithFlag(4, out rxFifoEmptyInterruptEnabled, name: "RXFIFOEMPTY") 87 .WithFlag(5, name: "TXFIFOFULL") //we keep the value, but not do anything with it, as this never happens 88 .WithChangeCallback((_, __) => RefreshInterrupt()) 89 }, 90 91 {(long)Registers.Status, new DoubleWordRegister(this) 92 .WithFlag(0, out txDone, FieldMode.WriteOneToClear | FieldMode.Read, name: "TXDONE") 93 .WithFlag(1, out rxDone, FieldMode.WriteOneToClear | FieldMode.Read, name: "RXDONE") 94 .WithFlag(2, valueProviderCallback: _ => IsRxAvailable(), name: "RXAVAILABLE") 95 .WithFlag(3, valueProviderCallback: _ => true, name: "TXAVAILABLE") 96 .WithFlag(4, valueProviderCallback: _ => !IsRxAvailable(), name: "RXFIFOEMPTY") 97 .WithFlag(5, valueProviderCallback: _ => false, name: "TXFIFOFULL") 98 .WithReservedBits(6, 1) 99 .WithFlag(7, valueProviderCallback: _ => true, name: "READY") 100 .WithFlag(8, valueProviderCallback: _ => x4Enabled.Value, name: "FLAGSX4") 101 .WithWriteCallback((_, __) => RefreshInterrupt()) 102 }, 103 104 {(long)Registers.UpperAddress, new DoubleWordRegister(this) 105 .WithValueField(0, 8, out upperAddress, name: "ADDRUP") 106 }, 107 108 {(long)Registers.RxData1, new DoubleWordRegister(this) 109 .WithValueField(0, 8, FieldMode.Read, 110 valueProviderCallback: _ => 111 { 112 lock(locker) 113 { 114 return (receiveFifo.Count > 0 ? receiveFifo.Dequeue() : 0u); 115 } 116 }, 117 name: "RXDATA") 118 .WithWriteCallback((_, __) => RefreshInterrupt()) 119 }, 120 121 {(long)Registers.TxData1, new DoubleWordRegister(this) 122 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) => HandleByte((uint)val), name: "TXDATA") 123 }, 124 125 {(long)Registers.RxData4, new DoubleWordRegister(this) 126 // The documentation is ambiguous on this register. 127 // It says 4 bytes must be read from the FIFO, but does not state precisely what happens 128 // when there is not enough data. This model ignores the read until there are at least 4 bytes to be read. 129 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => 130 { 131 lock(locker) 132 { 133 if(receiveFifo.Count >= 4) 134 { 135 var value = 0u; 136 for(var i = 0; i < 4; ++i) 137 { 138 value |= (uint)receiveFifo.Dequeue() << (8 * i); 139 } 140 return value; 141 } 142 } 143 this.Log(LogLevel.Warning, "Trying to read 4 bytes from the receive FIFO, but there are only {0} bytes available.", receiveFifo.Count); 144 return 0; 145 }, 146 name: "RXDATA4") 147 .WithWriteCallback((_, __) => RefreshInterrupt()) 148 }, 149 150 {(long)Registers.TxData4, new DoubleWordRegister(this) 151 .WithValueField(0, 32, FieldMode.Write, 152 writeCallback: (_, val) => 153 { 154 for(var i = 0; i < 4; i++) 155 { 156 HandleByte(BitHelper.GetValue((uint)val, i * 8, 8)); 157 } 158 }, 159 name: "TXDATA4") 160 }, 161 // this register intentionally exposes the whole register for reading and the upper bytes for writing 162 {(long)Registers.FramesUpper, new DoubleWordRegister(this) 163 .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => totalBytes, name: "BYTESLOWER") 164 .WithValueField(16, 16, writeCallback: (_, value) => BitHelper.UpdateWithShifted(ref totalBytes, (uint)value, 16, 16), 165 valueProviderCallback: _ => totalBytes >> 16, name: "BYTESUPPER") 166 } 167 }; 168 registers = new DoubleWordRegisterCollection(this, registerMap); 169 } 170 ReadDoubleWord(long offset)171 public uint ReadDoubleWord(long offset) 172 { 173 return xipMode.Value 174 ? RegisteredPeripheral.UnderlyingMemory.ReadDoubleWord(BitHelper.SetMaskedValue((uint)offset, (uint)upperAddress.Value, 24, 8)) 175 : registers.Read(offset); 176 } 177 WriteDoubleWord(long offset, uint value)178 public void WriteDoubleWord(long offset, uint value) 179 { 180 offset %= RegisterAliasSize; 181 registers.Write(offset, value); 182 } 183 Reset()184 public override void Reset() 185 { 186 registers.Reset(); 187 bytesSent = 0; 188 idleCycles = 0; 189 bytesToSkip = 0; 190 RefreshInterrupt(); 191 lock(locker) 192 { 193 receiveFifo.Clear(); 194 } 195 } 196 197 public GPIO IRQ { get; } 198 public long Size { get; } 199 TryReceive(byte data)200 private void TryReceive(byte data) 201 { 202 lock(locker) 203 { 204 receiveFifo.Enqueue(data); 205 } 206 } 207 208 /* 209 * Method for handling commands sent to flash 210 * 211 * Every operation will consist of at least 1 byte - the command code. 212 * 213 * However, we can distinguish 4 types of flash operations based on the relation between 214 * number of command address bytes and data bytes (a generalization): 215 * 1) 0 address bytes and 0 data bytes 216 * 2) 0 address bytes and at least 1 data byte 217 * 3) 3 or 4 address bytes and 0 data bytes 218 * 4) 3 or 4 address bytes and at least 1 data byte 219 * 220 * Description of significant variables: 221 * a) `commandBytes` = command byte + address bytes 222 * b) `totalBytes` = `commandBytes` + data bytes 223 * c) `bytesSent` = internal counter of bytes sent 224 * 225 * We have a data reception command when `commandBytes` and `totalBytes` are not equal, 226 * and data transmission when they are equal. 227 * 228 * If we have a transmission command, we send all `totalBytes` to the flash and store 229 * the received data in the receiveFifo. 230 * 231 * If we have a reception command, we first check how many address bytes we have to send, 232 * and then send the command and address bytes; if there are any data bytes in the command, 233 * we can send dummy data to the flash and just store the received data in the receiveFifo. 234 * 235 * If the internal counter `bytesSent` is equal to `totalBytes`, we call the 236 * `FinishTransmission()` method on the registered peripheral. 237 * We can assume that commands will not be interrupted. 238 * 239 */ HandleByte(uint val)240 private void HandleByte(uint val) 241 { 242 if(enabled.Value) 243 { 244 // reception 245 if(commandBytes.Value != totalBytes) 246 { 247 // 1 command byte 248 if(commandBytes.Value == 1) 249 { 250 HandleByteTransmission(val); 251 for(var i = bytesSent; i < totalBytes; i++) 252 { 253 HandleByteReception(); 254 } 255 } 256 // 1 command byte + 3 or 4 address bytes 257 else 258 { 259 if(bytesSent < (int)commandBytes.Value) 260 { 261 HandleByteTransmission(val); 262 } 263 if(bytesSent == (int)commandBytes.Value) 264 { 265 for(var i = bytesSent; i < totalBytes; i++) 266 { 267 HandleByteReception(); 268 } 269 } 270 } 271 TryHandleInterrupt(rxDone); 272 } 273 // transmission 274 else 275 { 276 if(bytesSent < totalBytes) 277 { 278 HandleByteTransmission(val); 279 } 280 TryHandleInterrupt(txDone); 281 } 282 } 283 } 284 HandleByteTransmission(uint val)285 private void HandleByteTransmission(uint val) 286 { 287 RegisteredPeripheral.Transmit((byte)val); 288 TryFinishTransmission(); 289 } 290 HandleByteReception()291 private void HandleByteReception() 292 { 293 var receivedByte = RegisteredPeripheral.Transmit(0); 294 if(bytesToSkip > 0) 295 { 296 bytesToSkip--; 297 } 298 else 299 { 300 TryReceive(receivedByte); 301 } 302 TryFinishTransmission(); 303 } 304 TryFinishTransmission()305 private void TryFinishTransmission() 306 { 307 bytesSent++; 308 if(bytesSent == totalBytes) 309 { 310 RegisteredPeripheral.FinishTransmission(); 311 } 312 } 313 TryHandleInterrupt(IFlagRegisterField field)314 private void TryHandleInterrupt(IFlagRegisterField field) 315 { 316 if(bytesSent == totalBytes) 317 { 318 field.Value = true; 319 RefreshInterrupt(); 320 } 321 } 322 RefreshInterrupt()323 private void RefreshInterrupt() 324 { 325 var value = false; 326 value |= txDone.Value && txDoneInterruptEnabled.Value; 327 value |= rxDone.Value && rxDoneInterruptEnabled.Value; 328 value |= IsRxAvailable() && rxAvailableInterruptEnabled.Value; 329 value |= txAvailableInterruptEnabled.Value; 330 value |= !IsRxAvailable() && rxFifoEmptyInterruptEnabled.Value; 331 332 IRQ.Set(value); 333 } 334 IsRxAvailable()335 private bool IsRxAvailable() 336 { 337 lock(locker) 338 { 339 return receiveFifo.Count >= (x4Enabled.Value ? 4 : 1); 340 } 341 } 342 343 344 private readonly Queue<byte> receiveFifo = new Queue<byte>(); 345 private readonly DoubleWordRegisterCollection registers; 346 private readonly IFlagRegisterField enabled; 347 private readonly IFlagRegisterField xipMode; 348 private readonly IValueRegisterField commandBytes; 349 private readonly IFlagRegisterField x4Enabled; 350 private readonly IValueRegisterField upperAddress; 351 private readonly IFlagRegisterField txDone; 352 private readonly IFlagRegisterField rxDone; 353 private readonly IFlagRegisterField txDoneInterruptEnabled; 354 private readonly IFlagRegisterField rxDoneInterruptEnabled; 355 private readonly IFlagRegisterField rxAvailableInterruptEnabled; 356 private readonly IFlagRegisterField txAvailableInterruptEnabled; 357 private readonly IFlagRegisterField rxFifoEmptyInterruptEnabled; 358 359 private uint totalBytes; 360 private uint bytesToSkip; 361 private uint idleCycles; 362 private int bytesSent; 363 364 //Registers are aliased every 256 bytes 365 private const int RegisterAliasSize = 256; 366 private const uint MinimumSize = (uint)Registers.FramesUpper + 4; 367 private object locker; 368 369 private enum XIPAddressBytes 370 { 371 Bytes3 = 0, 372 Bytes4 = 1 373 } 374 375 private enum Registers 376 { 377 Control = 0x0, 378 Frames = 0x4, 379 //0x8 reserved 380 InterruptEnable = 0xc, 381 Status = 0x10, 382 DirectAccess = 0x14, 383 UpperAddress = 0x18, 384 RxData1 = 0x40, 385 TxData1 = 0x44, 386 RxData4 = 0x48, 387 TxData4 = 0x4c, 388 FramesUpper = 0x50, 389 } 390 } 391 } 392