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