1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using System.Collections.Generic; 15 16 namespace Antmicro.Renode.Peripherals.I2C 17 { 18 public class TegraI2CController : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral 19 { 20 TegraI2CController(IMachine machine)21 public TegraI2CController(IMachine machine) : base(machine) 22 { 23 IRQ = new GPIO(); 24 } 25 ReadDoubleWord(long offset)26 public virtual uint ReadDoubleWord(long offset) 27 { 28 switch((Registers)offset) 29 { 30 case Registers.Config: 31 return config; 32 case Registers.Status: 33 return imInUse ? 1 << 8 : 0u; 34 case Registers.SlaveConfig: 35 return slaveConfig; 36 case Registers.SlaveAddress1: 37 return slaveAddress1; 38 case Registers.SlaveAddress2: 39 return slaveAddress2; 40 case Registers.TxFifo: 41 return 0; //very confusing manual, 0 in other sources 42 case Registers.RxFifo: 43 if(rxQueue.Count == 0) 44 { 45 SetInterrupt(Interrupts.RxFifoUnderflow); 46 return 0; 47 } 48 var value = 0u; 49 for(var i = 0; i < 32 && rxQueue.Count > 0; i += 8) 50 { 51 value |= (uint)(rxQueue.Dequeue() << i); 52 } 53 if(rxQueue.Count == 0) 54 { 55 ClearInterrupt(Interrupts.RxFifoDataReq); 56 } 57 if(payloadDone < payloadSize) 58 { 59 PrepareRead(); 60 } 61 return value; 62 case Registers.PacketTransferStatus: 63 return packetTransferStatus; 64 case Registers.FifoControl: 65 return fifoControl; 66 case Registers.FifoStatus: 67 return (uint)(((rxQueue.Count + 3) / 4) | (8 << 4)); 68 case Registers.InterruptMask: 69 return interruptMask; 70 case Registers.InterruptStatus: 71 return interruptStatus; 72 case Registers.ClockDivisor: 73 return clockDivisor; 74 default: 75 this.LogUnhandledRead(offset); 76 return 0; 77 } 78 } 79 WriteDoubleWord(long offset, uint value)80 public virtual void WriteDoubleWord(long offset, uint value) 81 { 82 switch((Registers)offset) 83 { 84 case Registers.Config: 85 config = value; 86 break; 87 case Registers.SlaveConfig: 88 slaveConfig = value; 89 break; 90 case Registers.SlaveAddress1: 91 slaveAddress1 = value; 92 break; 93 case Registers.SlaveAddress2: 94 slaveAddress2 = value; 95 break; 96 case Registers.TxFifo: 97 TransferData(value); 98 break; 99 case Registers.FifoControl: 100 if((value & (1 << 1)) != 0) 101 { //tx flush 102 mode = Mode.FirstHeader; 103 ClearInterrupt(Interrupts.TxFifoOverflow); 104 } 105 if((value & (1 << 0)) != 0) 106 { //rx flush 107 rxQueue.Clear(); 108 ClearInterrupt(Interrupts.RxFifoUnderflow); 109 } 110 fifoControl = value & 0xFC; //flush rx and tx fifos, both are cleared, but they should generate an interrupt 111 break; 112 case Registers.InterruptMask: 113 interruptMask = (value & 0x6f); 114 Update(); 115 break; 116 case Registers.InterruptStatus: 117 interruptStatus &= (~value | (1u << (int)Interrupts.RxFifoDataReq) | (1u << (int)Interrupts.TxFifoDataReq)); //last two bytes cannot be cleared 118 Update(); 119 break; 120 case Registers.ClockDivisor: 121 clockDivisor = value; 122 break; 123 default: 124 this.LogUnhandledWrite(offset, value); 125 break; 126 } 127 } 128 Reset()129 public override void Reset() 130 { 131 config = 0; 132 interruptMask = 0; 133 interruptStatus = 0; 134 mode = Mode.FirstHeader; 135 payloadDone = 0; 136 payloadSize = 0; 137 } 138 TransferData(uint value)139 private void TransferData(uint value) 140 { 141 this.Log(LogLevel.Debug, "TransferData(0x{0:X}) in mode {1}.", value, mode); 142 switch(mode) 143 { 144 case Mode.FirstHeader: 145 packetTransferStatus = value & (0xFF << 16); //packet ID 146 mode = Mode.SecondHeader; 147 break; 148 case Mode.SecondHeader: 149 payloadSize = (value & 0x7FF) + 1; 150 this.Log(LogLevel.Debug, "Payloald size: {0}.", payloadSize); 151 payloadDone = 0; 152 mode = Mode.HeaderSpecific; 153 break; 154 case Mode.HeaderSpecific: 155 imInUse = true; 156 enableInterruptAfterPacket = (value & (1 << 17)) != 0; 157 slaveAddressForPacket = (byte)((value >> 1) & 0x7F); 158 159 II2CPeripheral device; 160 if(!TryGetByAddress(slaveAddressForPacket, out device)) 161 { 162 this.Log(LogLevel.Debug, "Not found {0}", slaveAddressForPacket); 163 SetInterrupt(Interrupts.NoACK); 164 return; 165 } 166 if((value & (1 << 19)) != 0) //read 167 { 168 this.Log(LogLevel.Debug, "Will read from 0x{0:X}.", slaveAddressForPacket); 169 PrepareRead(); 170 } 171 else //write 172 { 173 this.Log(LogLevel.Debug, "Will write to 0x{0:X}.", slaveAddressForPacket); 174 mode = Mode.Payload; 175 } 176 break; 177 case Mode.Payload: 178 var bytesSent = 0; 179 //payloadSize might be > 4 180 while(payloadDone < payloadSize && bytesSent++ < 4) 181 { 182 this.Log(LogLevel.Noisy, "Writing 0x{0:X}", value); 183 packet.Add((byte)(value & 0xFF)); 184 value >>= 8; 185 payloadDone++; 186 packetTransferStatus = (uint)((packetTransferStatus & ~0xFFF0) | (payloadDone << 4)); 187 } 188 SetInterrupt(Interrupts.TxFifoDataReq); 189 if(payloadDone == payloadSize) 190 { 191 this.Log(LogLevel.Noisy, "Writing done, {0} bytes.", payloadDone); 192 GetByAddress(slaveAddressForPacket).Write(packet.ToArray()); 193 packet.Clear(); 194 FinishTransfer(); 195 } 196 Update(); 197 break; 198 } 199 } 200 FinishTransfer()201 private void FinishTransfer() 202 { 203 imInUse = false; 204 packetTransferStatus |= (1 << 24); 205 mode = Mode.FirstHeader; 206 if(enableInterruptAfterPacket) 207 { 208 SetInterrupt(Interrupts.PacketXferComplete, Interrupts.AllPacketsXferComplete); 209 } 210 } 211 PrepareRead()212 private void PrepareRead() 213 { 214 var packet = GetByAddress(slaveAddressForPacket).Read(); 215 foreach(var item in packet) 216 { 217 rxQueue.Enqueue(item); 218 payloadDone++; 219 } 220 if(packet.Count() > 0) 221 { 222 SetInterrupt(Interrupts.RxFifoDataReq); 223 } 224 if(payloadDone == payloadSize) 225 { 226 FinishTransfer(); 227 } 228 } 229 230 public GPIO IRQ{ get; private set; } 231 Update()232 private void Update() 233 { 234 if((interruptStatus & (interruptMask | (1 << (int)Interrupts.PacketXferComplete))) > 0) 235 { 236 this.NoisyLog("Irq set"); 237 IRQ.Set(); 238 } 239 else 240 { 241 this.NoisyLog("Irq unset"); 242 IRQ.Unset(); 243 } 244 } 245 ClearInterrupt(params Interrupts[] interrupt)246 private void ClearInterrupt(params Interrupts[] interrupt) 247 { 248 foreach(var item in interrupt) 249 { 250 interruptStatus &= (uint)~(1 << (int)item); 251 } 252 Update(); 253 } 254 255 SetInterrupt(params Interrupts[] interrupt)256 private void SetInterrupt(params Interrupts[] interrupt) 257 { 258 foreach(var item in interrupt) 259 { 260 interruptStatus |= (uint)(1 << (int)item); 261 } 262 Update(); 263 } 264 265 private uint config; 266 private uint slaveConfig; 267 private uint slaveAddress1; 268 private uint slaveAddress2; 269 private uint fifoControl; 270 private uint interruptMask; 271 private uint interruptStatus; 272 private uint clockDivisor; 273 private uint packetTransferStatus; 274 private Mode mode; 275 private uint payloadSize; 276 private uint payloadDone; 277 private bool enableInterruptAfterPacket; 278 private byte slaveAddressForPacket; 279 private bool imInUse; 280 281 private List<byte> packet = new List<byte>(); 282 private Queue<byte> rxQueue = new Queue<byte>(); 283 284 private enum Mode 285 { 286 FirstHeader, 287 SecondHeader, 288 HeaderSpecific, 289 Payload 290 } 291 292 private enum Interrupts 293 { 294 RxFifoDataReq = 0x0, 295 TxFifoDataReq = 0x1, 296 ArbitrationLost = 0x2, 297 NoACK = 0x3, 298 RxFifoUnderflow = 0x4, 299 TxFifoOverflow = 0x5, 300 AllPacketsXferComplete = 0x6, 301 PacketXferComplete = 0x7 302 } 303 304 private enum Registers 305 { 306 Config = 0x0, 307 Status = 0x1C, 308 SlaveConfig = 0x20, 309 SlaveAddress1 = 0x2C, 310 SlaveAddress2 = 0x30, 311 TxFifo = 0x50, 312 RxFifo = 0x54, 313 PacketTransferStatus = 0x58, 314 FifoControl = 0x5C, 315 FifoStatus = 0x60, 316 InterruptMask = 0x64, 317 InterruptStatus = 0x68, 318 ClockDivisor = 0x6C, 319 320 321 } 322 } 323 } 324 325