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 System; 9 using System.Linq; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Core.USB; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Utilities; 17 using Antmicro.Renode.Utilities.Packets; 18 using System.Threading; 19 using Antmicro.Renode.Peripherals.Bus.Wrappers; 20 21 namespace Antmicro.Renode.Peripherals.SPI 22 { 23 public class MAX3421E : SimpleContainer<IUSBDevice>, IProvidesRegisterCollection<ByteRegisterCollection>, ISPIPeripheral, IDisposable 24 { MAX3421E(IMachine machine)25 public MAX3421E(IMachine machine) : base(machine) 26 { 27 IRQ = new GPIO(); 28 setupQueue = new Queue<byte>(); 29 receiveQueue = new Queue<byte>(); 30 sendQueue = new Queue<byte>(); 31 bumper = machine.ObtainManagedThread(GenerateFrameInterrupt, BumpsPerSecond); 32 33 RegistersCollection = new ByteRegisterCollection(this); 34 35 DefineRegisters(); 36 } 37 Register(IUSBDevice peripheral, NumberRegistrationPoint<int> registrationPoint)38 public override void Register(IUSBDevice peripheral, NumberRegistrationPoint<int> registrationPoint) 39 { 40 base.Register(peripheral, registrationPoint); 41 42 // indicate the K state - full-speed device attached 43 kStatus.Value = true; 44 jStatus.Value = false; 45 46 connectDisconnectInterruptRequest.Value = true; 47 48 this.Log(LogLevel.Debug, "USB device connected to port {0}", registrationPoint.Address); 49 UpdateInterrupts(); 50 51 HandleBumper(); 52 } 53 Unregister(IUSBDevice peripheral)54 public override void Unregister(IUSBDevice peripheral) 55 { 56 base.Unregister(peripheral); 57 58 connectDisconnectInterruptRequest.Value = true; 59 UpdateInterrupts(); 60 61 HandleBumper(); 62 } 63 FinishTransmission()64 public void FinishTransmission() 65 { 66 this.Log(LogLevel.Noisy, "Transmission finished"); 67 state = State.Idle; 68 } 69 Dispose()70 public override void Dispose() 71 { 72 base.Dispose(); 73 bumper.Dispose(); 74 } 75 Reset()76 public override void Reset() 77 { 78 RegistersCollection.Reset(); 79 UpdateInterrupts(); 80 81 lastRegister = 0; 82 state = State.Idle; 83 84 setupQueue.Clear(); 85 receiveQueue.Clear(); 86 sendQueue.Clear(); 87 88 HandleBumper(); 89 } 90 Transmit(byte data)91 public byte Transmit(byte data) 92 { 93 this.Log(LogLevel.Noisy, "Received byte: 0x{0:X} in state {1}", data, state); 94 byte result = 0; 95 96 switch(state) 97 { 98 case State.Idle: 99 HandleCommandByte(data); 100 result = RegistersCollection.Read((long)RegisterType.HostIrqPending); 101 break; 102 103 case State.Writing: 104 this.Log(LogLevel.Noisy, "Writing value 0x{0:X} to register {1} (0x{1:X})", data, lastRegister); 105 RegistersCollection.Write((long)lastRegister, data); 106 break; 107 108 case State.Reading: 109 this.Log(LogLevel.Noisy, "Reading value from register {0} (0x{0:X})", lastRegister); 110 result = RegistersCollection.Read((long)lastRegister); 111 break; 112 113 default: 114 this.Log(LogLevel.Error, "Received byte 0x{0:X} in an unexpected state: {1}. Ignoring it...", data, state); 115 break; 116 } 117 118 this.Log(LogLevel.Noisy, "Returning byte: 0x{0:X}", result); 119 return result; 120 } 121 122 public GPIO IRQ { get; } 123 124 public ByteRegisterCollection RegistersCollection { get; } 125 HandleBumper()126 private void HandleBumper() 127 { 128 if((hostMode.Value || startOfFramePacketsGenerationEnable.Value) && ChildCollection.Any()) 129 { 130 bumper.Start(); 131 } 132 else 133 { 134 bumper.Stop(); 135 } 136 } 137 UpdateInterrupts()138 private void UpdateInterrupts() 139 { 140 var state = false; 141 142 state |= (connectDisconnectInterruptRequest.Value && connectDisconnectInterruptEnable.Value); 143 state |= (busEventInterruptRequest.Value && busEventInterruptEnable.Value); 144 state |= (frameGeneratorInterruptRequest.Value && frameGeneratorInterruptEnable.Value); 145 state |= (hostTransferDoneInterruptRequest.Value && hostTransferDoneInterruptEnable.Value); 146 state |= (receiveDataAvailableInterruptRequest.Value && receiveDataAvailableInterruptEnable.Value); 147 state |= (sendDataBufferAvailableInterruptRequest.Value && sendDataBufferAvailableInterruptEnable.Value); 148 149 state |= (oscillatorOKInterruptRequest.Value && oscillatorOKInterruptEnable.Value); 150 151 state &= interruptEnable.Value; 152 153 this.Log(LogLevel.Noisy, "Setting IRQ to {0}", state); 154 IRQ.Set(state); 155 } 156 DefineRegisters()157 private void DefineRegisters() 158 { 159 RegisterType.ReceiveFifo.Define(this) 160 .WithValueField(0, 8, FieldMode.Read, name: "data", valueProviderCallback: _ => 161 { 162 if(receiveQueue.Count == 0) 163 { 164 this.Log(LogLevel.Warning, "Trying to read from an empty receive queue"); 165 return 0; 166 } 167 return receiveQueue.Dequeue(); 168 }) 169 ; 170 171 RegisterType.SendFifo.Define(this) 172 .WithValueField(0, 8, name: "data", 173 valueProviderCallback: _ => 174 { 175 if(sendQueue.Count == 0) 176 { 177 this.Log(LogLevel.Warning, "Trying to read from an empty send queue"); 178 return 0; 179 } 180 return sendQueue.Dequeue(); 181 182 }, 183 writeCallback: (_, val) => 184 { 185 sendQueue.Enqueue((byte)val); 186 if(sendQueue.Count > FifoSize) 187 { 188 this.Log(LogLevel.Warning, "Too much data put in the send queue. Initial bytes will be dropped"); 189 sendQueue.Dequeue(); 190 } 191 }) 192 ; 193 194 RegisterType.SetupFifo.Define(this) 195 .WithValueField(0, 8, name: "setup data", valueProviderCallback: _ => 196 { 197 if(setupQueue.Count == 0) 198 { 199 this.Log(LogLevel.Warning, "Trying to read from an empty setup queue"); 200 return 0; 201 } 202 return setupQueue.Dequeue(); 203 204 }, 205 writeCallback: (_, val) => 206 { 207 setupQueue.Enqueue((byte)val); 208 if(setupQueue.Count > 8) 209 { 210 this.Log(LogLevel.Warning, "Too much data put in the setup queue. Initial bytes will be dropped"); 211 setupQueue.Dequeue(); 212 } 213 }) 214 ; 215 216 RegisterType.ReceiveQueueLength.Define(this) 217 .WithValueField(0, 7, FieldMode.Read, name: "count", valueProviderCallback: _ => (uint)receiveQueue.Count) 218 .WithReservedBits(7, 1) 219 ; 220 221 RegisterType.SendQueueLength.Define(this) 222 .WithValueField(0, 7, out sendByteCount, name: "count") 223 .WithReservedBits(7, 1) 224 .WithWriteCallback((_, __) => 225 { 226 sendDataBufferAvailableInterruptRequest.Value = false; 227 UpdateInterrupts(); 228 }) 229 ; 230 231 RegisterType.USBIrqPending.Define(this) 232 .WithFlag(0, out oscillatorOKInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "OSCOKIRQ") 233 .WithReservedBits(1, 4) 234 .WithTag("NOVBUSIRQ", 5, 1) 235 .WithTag("VBUSIRQ", 6, 1) 236 .WithReservedBits(7, 1) 237 .WithWriteCallback((_, __) => UpdateInterrupts()) 238 ; 239 240 RegisterType.USBIrqEnabled.Define(this) 241 .WithFlag(0, out oscillatorOKInterruptEnable, name: "OSCOKIE") 242 .WithReservedBits(1, 4) 243 .WithTag("NOVBUSIE", 5, 1) 244 .WithTag("VBUSIE", 6, 1) 245 .WithReservedBits(7, 1) 246 .WithWriteCallback((_, __) => UpdateInterrupts()) 247 ; 248 249 RegisterType.USBControl.Define(this) 250 .WithReservedBits(0, 4) 251 .WithTag("PWRDOWN", 4, 1) 252 .WithFlag(5, name: "Chip Reset", changeCallback: (_, v) => 253 { 254 if(!v) 255 { 256 // software should wait for the oscillator and PLLS 257 // to stabilize after setting CHIPRES = 0 which 258 // is indicated by setting oscillator OK IRQ 259 oscillatorOKInterruptRequest.Value = true; 260 UpdateInterrupts(); 261 } 262 }) 263 .WithReservedBits(6, 2) 264 ; 265 266 RegisterType.CPUControl.Define(this) 267 .WithFlag(0, out interruptEnable, name: "IE") 268 .WithReservedBits(1, 5) 269 .WithTag("PULSEWID", 6, 2) 270 .WithWriteCallback((_, __) => UpdateInterrupts()) 271 ; 272 273 RegisterType.PinControl.Define(this) 274 .WithTag("GPXA", 0, 1) 275 .WithTag("GPXB", 1, 1) 276 .WithTag("POSINT", 2, 1) 277 .WithTag("INTLEVEL", 3, 1) 278 .WithTag("FDUPSPI", 4, 1) 279 .WithReservedBits(5, 3) 280 ; 281 282 RegisterType.Revision.Define(this) 283 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => ChipRevision) 284 ; 285 286 RegisterType.HostIrqPending.Define(this, 0x8) //sndbavirq is set by default 287 .WithFlag(0, out busEventInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "BUSEVENTIRQ") 288 .WithTag("RWUIRQ - Remote Wakeup Interrupt Request", 1, 1) 289 .WithFlag(2, out receiveDataAvailableInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "RCVDAVIRQ") // this should not go automatically from 1 to 0 when the fifo is empty, but should be explicitly cleared by the cpu 290 .WithFlag(3, out sendDataBufferAvailableInterruptRequest, FieldMode.Read, name: "SNDAVIRQ") // this bit is cleared by writing to SNDBC register 291 .WithTag("SUSDNIRQ - Suspend operation Done Interrupt Request", 4, 1) 292 .WithFlag(5, out connectDisconnectInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "CONDETIRQ") 293 .WithFlag(6, out frameGeneratorInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "FRAMEIRQ") 294 .WithFlag(7, out hostTransferDoneInterruptRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "HXFRDNIRQ") 295 .WithWriteCallback((_, __) => UpdateInterrupts()) 296 ; 297 298 RegisterType.HostIrqEnabled.Define(this) 299 .WithFlag(0, out busEventInterruptEnable, name: "BUSEVENTIE") 300 .WithTag("RWUIE - Remote Wakeup Interrupt Enable", 1, 1) 301 .WithFlag(2, out receiveDataAvailableInterruptEnable, name: "RCVDAVIE") 302 .WithFlag(3, out sendDataBufferAvailableInterruptEnable, name: "SNDAVIE") 303 .WithTag("SUSDNIE - Suspend operation Done Interrupt Enable", 4, 1) 304 .WithFlag(5, out connectDisconnectInterruptEnable, name: "CONDETIE") 305 .WithFlag(6, out frameGeneratorInterruptEnable, name: "FRAMEIE") 306 .WithFlag(7, out hostTransferDoneInterruptEnable, name: "HXFRDNIE") 307 .WithWriteCallback((_, __) => UpdateInterrupts()) 308 ; 309 310 RegisterType.Mode.Define(this) 311 .WithFlag(0, out hostMode, name: "host mode") 312 .WithTag("LOWSPEED", 1, 1) 313 .WithTag("HUBPRE - Send the PRE PID to a LS device operating through a USB hub", 2, 1) 314 .WithFlag(3, out startOfFramePacketsGenerationEnable, name: "SOFKAENAB") 315 .WithTag("SEPIRQ - Provides the GPIN IRQS on a separate pin (GPX)", 4, 1) 316 .WithTag("DELAYISO - Delay data transfer to an ISOCHRONOUS endpoint until the next frame", 5, 1) 317 .WithTag("DMPULLDN - Connect internal 15k resistor from D- to ground", 6, 1) 318 .WithTag("DPPULLDN - Connect internal 15k resistor from D+ to ground", 7, 1) 319 .WithWriteCallback((_, __) => HandleBumper()) 320 ; 321 322 RegisterType.PeripheralAddress.Define(this) 323 .WithValueField(0, 7, out deviceAddress, name: "address") 324 .WithReservedBits(7, 1) 325 ; 326 327 RegisterType.HostControl.Define(this) 328 .WithFlag(0, name: "bus reset", 329 valueProviderCallback: _ => false, 330 writeCallback: (_, val) => 331 { 332 if(val) 333 { 334 busEventInterruptRequest.Value = true; 335 UpdateInterrupts(); 336 } 337 }) 338 .WithTag("FRMRST - Reset the SOF frame counter", 1, 1) 339 .WithTag("SAMPLEBUS - Sample the state of the USB bus", 2, 1) 340 .WithTag("SIGRSM - Signal a bus resume event", 3, 1) 341 .WithTag("RCVTOG - Set or clear the data toggle value for a data transfer", 4, 2) 342 .WithTag("SNDTOG - Set or clear the data toggle value for a data transfer", 6, 2) 343 ; 344 345 RegisterType.HostTransfer.Define(this) 346 .WithValueField(0, 4, out var ep, name: "ep") 347 .WithFlag(4, out var setup, name: "setup") 348 .WithFlag(5, out var outnin, name: "outnin") 349 .WithTag("ISO", 6, 1) 350 .WithFlag(7, out var hs, name: "hs") 351 .WithWriteCallback((_, v) => { HandleHostTransfer((uint)ep.Value, setup.Value, outnin.Value, hs.Value); }) 352 ; 353 354 RegisterType.HostResult.Define(this) 355 .WithTag("HRSLT - Host result", 0, 4) 356 .WithTag("RCVTOGRD - Resulting data toggle value for IN transfers", 4, 1) 357 .WithTag("SNDTOGRD - Resulting data toggle value for OUT transfers", 5, 1) 358 .WithFlag(6, out kStatus, name: "KSTATUS - Sample the state of the USB bus") 359 .WithFlag(7, out jStatus, name: "JSTATUS - Sample the state of the USB bus") 360 ; 361 } 362 HandleCommandByte(byte data)363 private void HandleCommandByte(byte data) 364 { 365 var dir = (CommandDirection)((data >> 1) & 0x1); 366 lastRegister = (RegisterType)(data >> 3); 367 368 this.Log(LogLevel.Noisy, "Command byte detected: operation: {0}, register: {1} (0x{1:X})", dir, lastRegister); 369 370 switch(dir) 371 { 372 case CommandDirection.Write: 373 state = State.Writing; 374 break; 375 376 case CommandDirection.Read: 377 state = State.Reading; 378 break; 379 380 default: 381 throw new ArgumentException("Unsupported command direction"); 382 } 383 } 384 HandleHostTransfer(uint ep, bool setup, bool outnin, bool hs)385 private void HandleHostTransfer(uint ep, bool setup, bool outnin, bool hs) 386 { 387 if(setup && hs) 388 { 389 this.Log(LogLevel.Error, "Both SETUP and HS bits set for a host transfer - ignoring it!"); 390 return; 391 } 392 393 var device = this.ChildCollection.Values.FirstOrDefault(x => x.USBCore.Address == deviceAddress.Value); 394 if(device == null) 395 { 396 this.Log(LogLevel.Warning, "Tried to send setup packet to a device with address 0x{0:X}, but it's not connected", deviceAddress.Value); 397 398 // setting the IRQ is necessary to allow communication right after the usb device address has changed 399 hostTransferDoneInterruptRequest.Value = true; 400 UpdateInterrupts(); 401 402 return; 403 } 404 405 if(setup) 406 { 407 this.Log(LogLevel.Noisy, "Setup TX"); 408 if(ep != 0) 409 { 410 this.Log(LogLevel.Error, "This model does not support SETUP packets on EP different than 0"); 411 return; 412 } 413 414 HandleSetup(device); 415 } 416 else if(hs) 417 { 418 this.Log(LogLevel.Noisy, "Handshake {0}", outnin ? "out" : "in"); 419 420 hostTransferDoneInterruptRequest.Value = true; 421 UpdateInterrupts(); 422 } 423 else 424 { 425 USBEndpoint endpoint = null; 426 if(ep != 0) 427 { 428 endpoint = device.USBCore.GetEndpoint((int)ep, outnin ? Direction.HostToDevice : Direction.DeviceToHost); 429 if(endpoint == null) 430 { 431 this.Log(LogLevel.Error, "Tried to access a non-existing EP #{0}", ep); 432 433 hostTransferDoneInterruptRequest.Value = true; 434 UpdateInterrupts(); 435 return; 436 } 437 } 438 439 if(outnin) 440 { 441 this.Log(LogLevel.Noisy, "Bulk out"); 442 HandleBulkOut(endpoint); 443 } 444 else 445 { 446 this.Log(LogLevel.Noisy, "Bulk in"); 447 HandleBulkIn(endpoint); 448 } 449 } 450 } 451 GenerateFrameInterrupt()452 private void GenerateFrameInterrupt() 453 { 454 this.Log(LogLevel.Noisy, "Generating frame interrupt"); 455 456 frameGeneratorInterruptRequest.Value = true; 457 UpdateInterrupts(); 458 } 459 HandleBulkOut(USBEndpoint endpoint)460 private void HandleBulkOut(USBEndpoint endpoint) 461 { 462 if(endpoint != null) 463 { 464 if((int)sendByteCount.Value != sendQueue.Count) 465 { 466 this.Log(LogLevel.Warning, "Requested to send BULK out {0} bytes of data, but there are {1} bytes in the queue.", sendByteCount.Value, sendQueue.Count); 467 } 468 469 var bytesToSend = sendQueue.DequeueRange((int)sendByteCount.Value); 470 this.Log(LogLevel.Noisy, "Writing {0} bytes to the device", bytesToSend.Length); 471 endpoint.WriteData(bytesToSend); 472 473 sendDataBufferAvailableInterruptRequest.Value = true; 474 } 475 476 hostTransferDoneInterruptRequest.Value = true; 477 UpdateInterrupts(); 478 } 479 HandleBulkIn(USBEndpoint endpoint)480 private void HandleBulkIn(USBEndpoint endpoint) 481 { 482 if(endpoint != null) 483 { 484 this.Log(LogLevel.Noisy, "Initiated read from the device"); 485 endpoint.SetDataReadCallbackOneShot((_, data) => 486 { 487 this.Log(LogLevel.Noisy, "Received data from the device"); 488 #if DEBUG_PACKETS 489 this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(data)); 490 #endif 491 EnqueueReceiveData(data); 492 493 hostTransferDoneInterruptRequest.Value = true; 494 UpdateInterrupts(); 495 }); 496 } 497 else 498 { 499 hostTransferDoneInterruptRequest.Value = true; 500 UpdateInterrupts(); 501 } 502 } 503 HandleSetup(IUSBDevice device)504 private void HandleSetup(IUSBDevice device) 505 { 506 var data = setupQueue.DequeueAll(); 507 if(!Packet.TryDecode<SetupPacket>(data, out var setupPacket)) 508 { 509 this.Log(LogLevel.Error, "Could not decode SETUP packet - some data might be lost! Bytes were: {0}", Misc.PrettyPrintCollectionHex(data)); 510 return; 511 } 512 513 device.USBCore.HandleSetupPacket(setupPacket, response => 514 { 515 EnqueueReceiveData(response); 516 517 hostTransferDoneInterruptRequest.Value = true; 518 UpdateInterrupts(); 519 }); 520 } 521 EnqueueReceiveData(IEnumerable<byte> data)522 private void EnqueueReceiveData(IEnumerable<byte> data) 523 { 524 if(receiveQueue.EnqueueRange(data) > 0) 525 { 526 receiveDataAvailableInterruptRequest.Value = true; 527 } 528 } 529 530 private RegisterType lastRegister; 531 private State state; 532 533 private IFlagRegisterField connectDisconnectInterruptRequest; 534 private IFlagRegisterField connectDisconnectInterruptEnable; 535 private IFlagRegisterField interruptEnable; 536 private IFlagRegisterField kStatus; 537 private IFlagRegisterField jStatus; 538 private IFlagRegisterField busEventInterruptRequest; 539 private IFlagRegisterField busEventInterruptEnable; 540 private IFlagRegisterField frameGeneratorInterruptRequest; 541 private IFlagRegisterField frameGeneratorInterruptEnable; 542 private IFlagRegisterField hostTransferDoneInterruptRequest; 543 private IFlagRegisterField hostTransferDoneInterruptEnable; 544 private IFlagRegisterField receiveDataAvailableInterruptRequest; 545 private IFlagRegisterField receiveDataAvailableInterruptEnable; 546 private IValueRegisterField deviceAddress; 547 private IValueRegisterField sendByteCount; 548 private IFlagRegisterField sendDataBufferAvailableInterruptRequest; 549 private IFlagRegisterField sendDataBufferAvailableInterruptEnable; 550 private IFlagRegisterField startOfFramePacketsGenerationEnable; 551 private IFlagRegisterField hostMode; 552 private IFlagRegisterField oscillatorOKInterruptEnable; 553 private IFlagRegisterField oscillatorOKInterruptRequest; 554 private readonly Queue<byte> setupQueue; 555 private readonly Queue<byte> receiveQueue; 556 private readonly Queue<byte> sendQueue; 557 private readonly IManagedThread bumper; 558 559 private const byte ChipRevision = 0x13; 560 private const int BumpsPerSecond = 100; 561 private const int FifoSize = 64; 562 563 private enum State 564 { 565 Idle, 566 Writing, 567 Reading 568 } 569 570 private enum CommandDirection 571 { 572 Read = 0, 573 Write = 1 574 } 575 576 [RegisterMapper.RegistersDescription] 577 private enum RegisterType 578 { 579 // R0 is not available in HOST mode 580 ReceiveFifo = 1, 581 SendFifo = 2, 582 // R3 is not available in HOST mode 583 SetupFifo = 4, 584 // R5 is not available in HOST mode 585 ReceiveQueueLength = 6, 586 SendQueueLength = 7, 587 // R8-R12 are not available in HOST mode 588 USBIrqPending = 13, 589 USBIrqEnabled = 14, 590 USBControl = 15, 591 CPUControl = 16, 592 PinControl = 17, 593 Revision = 18, 594 // R19 is not available in HOST mode 595 IOPins1 = 20, 596 IOPins2 = 21, 597 GeneralPurposeInIrqPending = 22, 598 GeneralPurposeInIrqEnabled = 23, 599 GeneralPurposeInIrqPolarity = 24, 600 HostIrqPending = 25, 601 HostIrqEnabled = 26, 602 Mode = 27, 603 PeripheralAddress = 28, 604 HostControl = 29, 605 HostTransfer = 30, 606 HostResult = 31 607 } 608 } 609 } 610