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 Antmicro.Renode.Peripherals.Bus;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals.MTD;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure;
13 using System.Collections.Specialized;
14 using System;
15 
16 namespace Antmicro.Renode.Peripherals.SPI
17 {
18     public class XilinxQSPI : NullRegistrationPointPeripheralContainer<ISPIFlash>, IDoubleWordPeripheral
19     {
XilinxQSPI(IMachine machine)20         public XilinxQSPI(IMachine machine) : base(machine)
21         {
22             IRQ = new GPIO();
23             InnerReset();
24         }
25 
Reset()26         public override void Reset()
27         {
28             InnerReset();
29         }
30 
ReadDoubleWord(long offset)31         public uint ReadDoubleWord(long offset)
32         {
33             this.Log(LogLevel.Info, "Reading from offset {0:X}", offset);
34             switch((Offset)offset)
35             {
36             case Offset.Config:
37                 return registers.Config.Get();
38             case Offset.InterruptStatus:
39                 return registers.InterruptStatus;
40                 /*case Offset.InterruptEnable:
41                 return registers.InterruptEnable;
42             case Offset.InterruptDisable:
43                 return registers.InterruptDisable;
44             case Offset.Enable:
45                 return registers.Enable;
46             case Offset.Delay:
47                 return registers.Delay;*/
48             case Offset.ReceiveData:
49                 receiveFIFODataCount = 0;
50                 registers.InterruptStatus &= ~(1u << 4); //clear rx FIFO not empty
51                 return registers.ReceiveData;
52                 /*case Offset.SlaveIdleCount:
53                 return registers.SlaveIdleCount;
54             case Offset.TransmitFifoThreshold:
55                 return registers.TransmitFifoThreshold;
56             case Offset.ReceiveFifoThreshold:
57                 return registers.ReceiveFifoThreshold;
58             case Offset.GPIO:
59                 return registers.GPIO;
60             case Offset.LoopbackMasterClockDelayAdjustment:
61                 return registers.LoopbackMasterClockDelayAdjustment;
62             case Offset.LinearQSPIConfig:
63                 return registers.LinearQSPIConfig;
64             case Offset.LinearQSPIStatus:
65                 return registers.LinearQSPIStatus;
66             case Offset.ModuleID:
67                 return registers.ModuleID;*/
68             default:
69                 this.LogUnhandledRead(offset);
70                 break;
71             }
72             return 0;
73         }
74 
WriteDoubleWord(long offset, uint value)75         public void WriteDoubleWord(long offset, uint value)
76         {
77             this.Log(LogLevel.Info, "Writing to offset {0:X} value {1:X}", offset, value);
78             switch((Offset)offset)
79             {
80             case Offset.Config:
81                 registers.Config.Set(value);
82                 if(registers.Config.ManualStartEnable && registers.Config.ManualStart)
83                 {
84                     /*manual start*/
85                     registers.Config.ManualStart = false;
86                     sendCommand(registers.TransmitData, commandLength);
87                     commandLength = 0;
88                 }
89                 break;
90             case Offset.InterruptStatus:
91                 registers.InterruptStatus &= ~value;
92                 break;
93             case Offset.InterruptEnable:
94                 registers.InterruptEnable |= value;
95                 break;
96             case Offset.InterruptDisable:
97                 registers.InterruptEnable &= ~value;
98                 break;
99             case Offset.Enable:
100                 registers.Enable = value;
101                 break;
102             /*case Offset.Delay:
103                 return registers.Delay;*/
104             case Offset.TransmitData0:
105                 registers.TransmitData = value;
106                 commandLength = 4;
107                 transferFIFODataCount += 4;
108                 break;
109                 /*case Offset.ReceiveData:
110                 return registers.ReceiveData;
111             case Offset.SlaveIdleCount:
112                 return registers.SlaveIdleCount;
113             case Offset.TransmitFifoThreshold:
114                 return registers.TransmitFifoThreshold;*/
115             case Offset.ReceiveFifoThreshold:
116                 registers.ReceiveFifoThreshold = value;
117                 break;
118                 /*case Offset.GPIO:
119                 return registers.GPIO;
120             case Offset.LoopbackMasterClockDelayAdjustment:
121                 return registers.LoopbackMasterClockDelayAdjustment;*/
122             case Offset.TransmitData1:
123                 registers.TransmitData = value;
124                 commandLength = 1;
125                 transferFIFODataCount += 1;
126                 break;
127             case Offset.TransmitData2:
128                 registers.TransmitData = value;
129                 commandLength = 2;
130                 transferFIFODataCount += 2;
131                 break;
132             case Offset.TransmitData3:
133                 registers.TransmitData = value;
134                 commandLength = 3;
135                 transferFIFODataCount += 3;
136                 break;
137                 /*case Offset.LinearQSPIConfig:
138                 return registers.LinearQSPIConfig;
139             case Offset.LinearQSPIStatus:
140                 return registers.LinearQSPIStatus;
141             case Offset.ModuleID:
142                 return registers.ModuleID;*/
143             default:
144                 this.LogUnhandledWrite(offset, value);
145                 break;
146             }
147             checkInterrupt();
148         }
149 
checkInterrupt()150         private void checkInterrupt()
151         {
152             var interrupt = false;
153             if(transferFIFODataCount >= registers.TransmitFifoThreshold)
154             {
155                 registers.InterruptStatus |= 1u << 3;
156                 if((registers.InterruptEnable & (1u << 3)) != 0)
157                 {
158                     interrupt = true;
159                 }
160             }
161             if(receiveFIFODataCount >= registers.ReceiveFifoThreshold)
162             {
163                 registers.InterruptStatus |= 1u << 4;
164                 if((registers.InterruptEnable & (1u<<4))!=0) //RX FIFO not empty
165                 {
166                     interrupt = true;
167                 }
168             }
169 
170             if(((registers.InterruptEnable & (1u << 2)) != 0) && writeOccured) //TX FIFO not full (always in emulation)
171             {
172                 registers.InterruptStatus |= 1u << 2;
173                 interrupt = true;
174                 writeOccured = false;
175             }
176             if(interrupt)
177             {
178                 this.Log(LogLevel.Noisy, "IRQ.SET");
179                 IRQ.Set();
180             }
181             else
182             {
183                 this.Log(LogLevel.Noisy, "IRQ.UNSET");
184                 IRQ.Unset();
185             }
186         }
187 
sendCommand(uint command, uint length)188         private void sendCommand(uint command, uint length)
189         {
190             //TODO: Endianess
191             writeOccured = true;
192             transferFIFODataCount = 0;
193             this.Log(LogLevel.Warning, "Flash command {0:X}", command);
194             switch((SPIFlashCommand)(command & 0xff))
195             {
196             case SPIFlashCommand.ReadID:
197                 //TODO: polarization
198                 var ID = 0xffffffffu; //return 0xffffffff if there is no flash attached
199                 if(RegisteredPeripheral != null)
200                 {
201                     ID = RegisteredPeripheral.ReadID();
202                 }
203                 registers.ReceiveData = ID;
204                 receiveFIFODataCount += 1;
205                 break;
206             default:
207                 receiveFIFODataCount += 1; //XXX: ugly
208                 this.Log(LogLevel.Warning, "Unimplemented SPI Flash command {0:X}", command);
209                 break;
210             }
211         }
212 
InnerReset()213         private void InnerReset()
214         {
215             registers = new regs();
216             writeOccured = false;
217             commandLength = 0;
218             receiveFIFODataCount = 0;
219             transferFIFODataCount = 0;
220         }
221 
222         /* variables */
223         // Analysis disable RedundantDefaultFieldInitializer
224         public GPIO IRQ { get; private set; }
225         private bool writeOccured = false;
226         private uint commandLength = 0;
227         private uint receiveFIFODataCount = 0;
228         private uint transferFIFODataCount = 0;
229         // Analysis restore RedundantDefaultFieldInitializer
230 
231         /* internal registers */
232         private class ConfigRegister
233         {
ConfigRegister()234             public ConfigRegister()
235             {
236                 mode = BitVector32.CreateSection(1);
237                 var clkPol = BitVector32.CreateSection(1, mode);
238                 var clkPh = BitVector32.CreateSection(1, clkPol);
239                 var baud = BitVector32.CreateSection(7, clkPh);
240                 fifoWidth = BitVector32.CreateSection(3, baud);
241                 var refClk = BitVector32.CreateSection(1, fifoWidth);
242                 var reserved0 = BitVector32.CreateSection(1, refClk);
243                 var pcs = BitVector32.CreateSection(1, reserved0);
244                 var reserved1 = BitVector32.CreateSection(7, pcs);
245                 var manualCS = BitVector32.CreateSection(1, reserved1);
246                 manualStartEnable = BitVector32.CreateSection(1, manualCS);
247                 manualStart = BitVector32.CreateSection(1, manualStartEnable);
248                 var reserved2 = BitVector32.CreateSection(3, manualStart);
249                 var holdb = BitVector32.CreateSection(1,reserved2);
250                 var reserved3 = BitVector32.CreateSection(63, holdb);
251                 endian = BitVector32.CreateSection(1, reserved3);
252             }
253 
Set(uint value)254             public void Set(uint value)
255             {
256                 registerValue = value;
257                 var register = new BitVector32((int)value);
258                 Mode = register[mode] != 0;
259                 FifoWidth = (byte)register[fifoWidth];
260                 ManualStartEnable = register[manualStartEnable] != 0;
261                 ManualStart = register[manualStart] != 0;
262                 Endian = register[endian] != 0;
263             }
264 
Get()265             public uint Get()
266             {
267                 return registerValue;
268             }
269 
270             private BitVector32.Section mode;
271             private BitVector32.Section fifoWidth;
272             private BitVector32.Section manualStartEnable;
273             private BitVector32.Section manualStart;
274             private BitVector32.Section endian;
275             private uint registerValue = 0x80020000;
276 
277             // Analysis disable RedundantDefaultFieldInitializer
278             public bool Mode = false;
279             public byte FifoWidth = 0;
280             public bool ManualStartEnable = false;
281             public bool ManualStart = false;
282             public bool Endian = false;
283             // Analysis restore RedundantDefaultFieldInitializer
284         }
285 
286         private regs registers;
287         private class regs
288         {
regs()289             public regs()
290             {
291                 Config = new ConfigRegister();
292             }
293             public ConfigRegister Config;
294             // Analysis disable RedundantDefaultFieldInitializer
295             public uint InterruptStatus = 0x00000000;
296             public uint InterruptEnable = 0x00000000;
297             public uint InterruptMask = 0x00000000;
298             public uint Enable = 0x00000000;
299             public uint Delay = 0x00000000;
300             public uint TransmitData = 0x00000000;
301             public uint ReceiveData = 0x00000000;
302             public uint SlaveIdleCount = 0x000000FF;
303             public uint TransmitFifoThreshold = 0x00000001;
304             public uint ReceiveFifoThreshold = 0x00000001;
305             public uint GPIO = 0x00000001;
306             public uint LoopbackMasterClockDelayAdjustment = 0x00000033;
307             public uint LinearQSPIConfig = 0x07A002EB;
308             public uint LinearQSPIStatus = 0x00000000;
309             public uint ModuleID = 0x01090101;
310             // Analysis restore RedundantDefaultFieldInitializer
311         }
312 
313         private enum Offset
314         {
315             Config = 0x00,
316             InterruptStatus = 0x04,
317             InterruptEnable = 0x08,
318             InterruptDisable = 0x0C,
319             InterruptMask = 0x10,
320             Enable = 0x14,
321             Delay = 0x18,
322             TransmitData0 = 0x1C,
323             ReceiveData = 0x20,
324             SlaveIdleCount = 0x24,
325             TransmitFifoThreshold = 0x28,
326             ReceiveFifoThreshold = 0x2C,
327             GPIO = 0x30,
328             LoopbackMasterClockDelayAdjustment = 0x38,
329             TransmitData1 = 0x80,
330             TransmitData2 = 0x84,
331             TransmitData3 = 0x88,
332             LinearQSPIConfig = 0xA0,
333             LinearQSPIStatus = 0xA4,
334             ModuleID = 0xFC
335         }
336     }
337 }
338 
339