1 //
2 // Copyright (c) 2010-2020 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System.Collections.Generic;
8 using System.Threading;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.Bus;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.I2C
17 {
18     public class MPFS_I2C : SimpleContainer<II2CPeripheral>, IProvidesRegisterCollection<ByteRegisterCollection>, II2CPeripheral, IBytePeripheral, IKnownSize
19     {
MPFS_I2C(IMachine machine)20         public MPFS_I2C(IMachine machine) : base(machine)
21         {
22             transferBuffer = new Queue<byte>();
23             receiveBuffer = new Queue<byte>();
24             IRQ = new GPIO();
25 
26             RegistersCollection = new ByteRegisterCollection(this);
27             DefineRegisters();
28 
29             Reset();
30         }
31 
Reset()32         public override void Reset()
33         {
34             Interlocked.Exchange(ref irqResubmitCounter, 0);
35             pendingMasterTransaction = false;
36             isReadOperation = false;
37             selectedSlave = null;
38             transferBuffer.Clear();
39             receiveBuffer.Clear();
40             RegistersCollection.Reset();
41             // setting current state will update interrupts
42             CurrentState = State.Idle;
43         }
44 
FinishTransmission()45         public void FinishTransmission()
46         {
47         }
48 
ReadByte(long offset)49         public byte ReadByte(long offset)
50         {
51             return RegistersCollection.Read(offset);
52         }
53 
WriteByte(long offset, byte value)54         public void WriteByte(long offset, byte value)
55         {
56             RegistersCollection.Write(offset, value);
57         }
58 
Write(byte[] data)59         public void Write(byte[] data)
60         {
61             foreach(var b in data)
62             {
63                 receiveBuffer.Enqueue(b);
64             }
65             CurrentState = State.PreviouslyAddressedWithOwnAddressDataReceivedAckReturned;
66         }
67 
Read(int count = 1)68         public byte[] Read(int count = 1)
69         {
70             // at the moment we do not take `count` into account because of API changes in the near future
71             return transferBuffer.ToArray();
72         }
73 
74         public long Size => 0x1000;
75         public GPIO IRQ { get; private set; }
76         public ByteRegisterCollection RegistersCollection { get; private set; }
77 
78         // due to a troublesome implementation of the controller's isr
79         // we need to queue the interrupt requests and resubmit them
80         // on a clear of 'si'
SubmitInterrupt()81         private void SubmitInterrupt()
82         {
83             Interlocked.Increment(ref irqResubmitCounter);
84             serialInterruptFlag.Value = true;
85             UpdateInterrupt();
86         }
87 
SendDataToSlave()88         private void SendDataToSlave()
89         {
90             if(selectedSlave == null)
91             {
92                 CurrentState = State.Idle;
93                 return;
94             }
95 
96             if(transferBuffer.Count > 0)
97             {
98                 selectedSlave.Write(transferBuffer.ToArray());
99                 transferBuffer.Clear();
100                 CurrentState = State.DataTransmittedAckReceived;
101             }
102             else
103             {
104                 CurrentState = State.Idle;
105             }
106         }
107 
UpdateInterrupt()108         private void UpdateInterrupt()
109         {
110             IRQ.Set(isCoreEnabled.Value && serialInterruptFlag.Value);
111         }
112 
DefineRegisters()113         private void DefineRegisters()
114         {
115             Registers.Control.Define(this)
116                 .WithTag("CR2", 7, 1)
117                 .WithFlag(6, out isCoreEnabled, name: "ens1")
118                 .WithFlag(5, FieldMode.WriteOneToClear | FieldMode.Read, name: "sta",
119                     writeCallback: (_, val) =>
120                     {
121                         if(!val)
122                         {
123                             return;
124                         }
125 
126                         switch(CurrentState)
127                         {
128                             case State.Idle:
129                             case State.SlaveAddressReadBitTransmittedAckNotReceived:
130                             case State.SlaveAddressWriteBitTransmittedAckNotReceived:
131                                 pendingMasterTransaction = true;
132                                 CurrentState = State.StartConditionTransmitted;
133                                 break;
134                             case State.StartConditionTransmitted:
135                             case State.RepeatedStartConditionTransmitted:
136                                 SendDataToSlave();
137                                 CurrentState = State.RepeatedStartConditionTransmitted;
138                                 break;
139                             case State.DataTransmittedAckReceived:
140                                 if(pendingMasterTransaction)
141                                 {
142                                     isReadOperation = true;
143                                     CurrentState = State.RepeatedStartConditionTransmitted;
144                                 }
145                                 break;
146                             default:
147                                 this.Log(LogLevel.Warning, "Setting START bit in unhandled state: {0}", CurrentState);
148                                 break;
149                         }
150                     })
151                 .WithFlag(4, FieldMode.WriteOneToClear | FieldMode.Read, name: "sto",
152                     writeCallback: (_, val) =>
153                     {
154                         if(val)
155                         {
156                             selectedSlave = null;
157                             isReadOperation = false;
158                             pendingMasterTransaction = false;
159                             CurrentState = State.Idle;
160                         }
161                     })
162                 .WithFlag(3, out serialInterruptFlag, name: "si", writeCallback: (previousValue, currentValue) =>
163                     {
164                         if(!(previousValue && !currentValue))
165                         {
166                             // writing 0 clears the interrupt
167                             return;
168                         }
169                         if(Interlocked.Decrement(ref irqResubmitCounter) > 0)
170                         {
171                             // if there are any queued irqs set the flag again
172                             serialInterruptFlag.Value = true;
173                         }
174                         else
175                         {
176                             Interlocked.Increment(ref irqResubmitCounter);
177                         }
178                         UpdateInterrupt();
179                     })
180                 .WithFlag(2, name: "aa")
181                 .WithTag("CR0/CR1", 0, 2);
182 
183 
184             Registers.Status.Define(this)
185                 .WithEnumField<ByteRegister, State>(0, 8, FieldMode.Read,
186                     valueProviderCallback: _ =>
187                     {
188                         return CurrentState;
189                     }
190                 );
191 
192 
193             Registers.Data.Define(this)
194                 .WithValueField(0, 8, name: "sd",
195                     valueProviderCallback: _ =>
196                     {
197                         if(receiveBuffer.Count == 0)
198                         {
199                             this.Log(LogLevel.Warning, "{0} trying to read from empty data buffer, transaction will halt", pendingMasterTransaction ? "Master" : "Slave");
200                             if(pendingMasterTransaction)
201                             {
202                                 pendingMasterTransaction = false;
203                                 CurrentState = State.DataReceivedAckNotReturned;
204                             }
205                             else
206                             {
207                                 CurrentState = State.Stop;
208                             }
209                             return 0;
210                         }
211                         var result = receiveBuffer.Dequeue();
212                         if(receiveBuffer.Count > 0)
213                         {
214                             // the state machine requires states in which master and slave are reading from the data register
215                             CurrentState = pendingMasterTransaction ? State.DataReceivedAckReturned : State.PreviouslyAddressedWithOwnAddressDataReceivedAckReturned;
216                         }
217                         return result;
218                     },
219                     writeCallback: (_, val) =>
220                     {
221                         switch(CurrentState)
222                         {
223                             case State.StartConditionTransmitted:
224                             case State.RepeatedStartConditionTransmitted:
225                                 var slaveAddress = val >> 1;
226                                 isReadOperation = BitHelper.IsBitSet(val, 0);
227                                 if(!ChildCollection.TryGetValue((int)slaveAddress, out selectedSlave))
228                                 {
229                                     this.Log(LogLevel.Warning, "Addressing unregistered slave: 0x{0:X}", slaveAddress);
230                                     CurrentState = (isReadOperation) ? State.SlaveAddressReadBitTransmittedAckNotReceived : State.SlaveAddressWriteBitTransmittedAckNotReceived;
231                                 }
232                                 else
233                                 {
234                                     if(isReadOperation)
235                                     {
236                                         var bytes = selectedSlave.Read();
237                                         if(bytes.Length > 0)
238                                         {
239                                             foreach(var b in bytes)
240                                             {
241                                                 receiveBuffer.Enqueue(b);
242                                             }
243                                             CurrentState = State.DataReceivedAckReturned;
244                                         }
245                                     }
246                                     else
247                                     {
248                                         CurrentState = State.SlaveAddressWriteBitTransmittedAckReceived;
249                                     }
250                                 }
251                                 break;
252                             case State.SlaveAddressWriteBitTransmittedAckReceived:
253                             case State.DataTransmittedAckReceived:
254                                 transferBuffer.Enqueue((byte)val);
255                                 SendDataToSlave();
256                                 break;
257                             default:
258                                 this.Log(LogLevel.Warning, "Writing to data register in unhandled state: {0}", CurrentState);
259                                 break;
260                         }
261                     });
262 
263             Registers.Slave0Address.Define(this)
264                 .WithValueField(1, 7, name: "adr")
265                 .WithFlag(0, name: "gc");
266 
267             Registers.Slave1Address.Define(this)
268                 .WithValueField(1, 7, name: "adr")
269                 .WithFlag(0, name: "gc");
270         }
271 
272         private State CurrentState
273         {
274             get
275             {
276                 return state;
277             }
278 
279             set
280             {
281                 state = value;
282                 SubmitInterrupt();
283             }
284         }
285 
286         private readonly Queue<byte> receiveBuffer;
287         private readonly Queue<byte> transferBuffer;
288 
289         private State state;
290         private II2CPeripheral selectedSlave;
291         private IFlagRegisterField serialInterruptFlag;
292         private IFlagRegisterField isCoreEnabled;
293         private bool pendingMasterTransaction;
294         private bool isReadOperation;
295         private int irqResubmitCounter;
296 
297         private enum State
298         {
299             // MASTER states
300             StartConditionTransmitted = 0x08,
301             RepeatedStartConditionTransmitted = 0x10,
302             SlaveAddressWriteBitTransmittedAckReceived = 0x18,
303             SlaveAddressWriteBitTransmittedAckNotReceived = 0x20,
304             DataTransmittedAckReceived = 0x28,
305             SlaveAddressReadBitTransmittedAckReceived = 0x40,
306             SlaveAddressReadBitTransmittedAckNotReceived = 0x48,
307             DataReceivedAckReturned = 0x50,
308             DataReceivedAckNotReturned = 0x58,
309             Idle = 0xF8,
310 
311             // SLAVE states
312             OwnSlaveAddressWriteBitReceivedAckReturned = 0x60,
313             PreviouslyAddressedWithOwnAddressDataReceivedAckReturned = 0x80,
314             Stop = 0xA0
315         }
316 
317         private enum Registers
318         {
319             Control = 0x0,
320             Status = 0x4,
321             Data = 0x8,
322             Slave0Address = 0xC,
323             SMBus = 0x10,
324             Frequency = 0x14,
325             GlitchRegLength = 0x18,
326             Slave1Address = 0x1C
327         }
328     }
329 }
330