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