AJA NTV2 SDK  18.1.0.2262
NTV2 SDK 18.1.0.2262
ntv2spiinterface.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
7 #include "ntv2spiinterface.h"
8 
9 #include <cmath>
10 #include <algorithm>
11 #include <fstream>
12 #include <sstream>
13 #include <string>
14 #include <vector>
15 
16 using namespace std;
17 
18 static bool verify_vectors(const std::vector<uint8_t> &dataWritten, const std::vector<uint8_t> &dataRead, bool verbose = false)
19 {
20  bool result = false;
21 
22  if (equal(dataWritten.begin(), dataWritten.end(), dataRead.begin()))
23  {
24  result = true;
25  }
26  else
27  {
28  result = false;
29  if (verbose)
30  {
31  pair<vector<uint8_t>::const_iterator, vector<uint8_t>::const_iterator> p;
32  p = mismatch(dataWritten.begin(), dataWritten.end(), dataRead.begin());
33  int64_t byteMismatchOffset = distance(dataWritten.begin(), p.first);
34  ostringstream ossWrite;
35  ossWrite << "0x" << std::setw(2) << std::setfill('0') << hex << (int)*p.first;
36  ostringstream ossRead;
37  ossRead << "0x" << std::setw(2) << std::setfill('0') << hex << (int)*p.second;
38 
39  ++p.first; ++p.second;
40  p = mismatch(p.first, dataWritten.end(), p.second);
41 
42  int errorCount = 0;
43  while(p.first != dataWritten.end() && p.second != dataRead.end())
44  {
45  errorCount++;
46  ++p.first; ++p.second;
47  p = mismatch(p.first, dataWritten.end(), p.second);
48  }
49 
50  cout << "Verifying write of: " << dataWritten.size() << " bytes, failed at byte index: " << byteMismatchOffset <<
51  ", byte written to device should be: " << ossWrite.str() << ", byte read back from device is: " << ossRead.str() << ".\n" <<
52  "There are " << errorCount << " other mismatches after this." << endl;
53  }
54  }
55 
56  return result;
57 }
58 
59 inline void print_flash_status(const string& label, uint32_t curValue, uint32_t maxValue, uint32_t& lastPercentage)
60 {
61  if (maxValue == 0)
62  return;
63 
64  uint32_t percentage = (uint32_t)(((double)curValue/(double)maxValue)*100.0);
65  if (percentage != lastPercentage)
66  {
67  lastPercentage = percentage;
68  cout << label << " status: " << dec << lastPercentage << "% \r" << flush;
69  }
70 }
71 
72 inline void print_flash_status_final(const string& label)
73 {
74  cout << label << " status: 100% " << endl;
75 }
76 
77 // Cypress/Spansion commands
78 
79 //const uint32_t CYPRESS_FLASH_WRITE_STATUS_COMMAND = 0x01;
80 //const uint32_t CYPRESS_FLASH_WRITEDISABLE_COMMAND = 0x04;
81 const uint32_t CYPRESS_FLASH_READ_STATUS_COMMAND = 0x05;
82 const uint32_t CYPRESS_FLASH_WRITEENABLE_COMMAND = 0x06;
83 const uint32_t CYPRESS_FLASH_READFAST_COMMAND = 0x0C; //4 byte address
84 const uint32_t CYPRESS_FLASH_PAGE_PROGRAM_COMMAND = 0x12; //4 byte address
85 //const uint32_t CYPRESS_FLASH_READ_COMMAND = 0x13; //4 byte address
86 const uint32_t CYPRESS_FLASH_READBANK_COMMAND = 0x16;
87 const uint32_t CYPRESS_FLASH_WRITEBANK_COMMAND = 0x17;
88 const uint32_t CYPRESS_FLASH_SECTOR4K_ERASE_COMMAND= 0x21; //4 byte address
89 const uint32_t CYPRESS_FLASH_READ_CONFIG_COMMAND = 0x35;
91 const uint32_t CYPRESS_FLASH_SECTOR_ERASE_COMMAND = 0xDC; //4 byte address
92 
93 inline bool has_4k_start_sectors(const uint32_t reportedSectorSize)
94 {
95  NTV2_UNUSED(reportedSectorSize);
96 
97  return false;
98 // if (reportedSectorSize <= 0x20000)
99 // return true;
100 // else
101 // return false;
102 }
103 
104 static uint32_t size_for_sector_number(const uint32_t reportedSectorSize, const uint32_t sector)
105 {
106  if (has_4k_start_sectors(reportedSectorSize) && sector < 32)
107  return 4 * 1024;
108  else
109  return reportedSectorSize;
110 }
111 
112 static uint32_t erase_cmd_for_sector(const uint32_t reportedSectorSize, const uint32_t sector)
113 {
114  if (has_4k_start_sectors(reportedSectorSize) && sector < 32)
115  return CYPRESS_FLASH_SECTOR4K_ERASE_COMMAND; // 4P4E command, 4byte
116  else
117  return CYPRESS_FLASH_SECTOR_ERASE_COMMAND; // 4SE command, 4byte
118 }
119 
120 static uint32_t sector_for_address(uint32_t sectorSizeBytes, uint32_t address)
121 {
122  if (sectorSizeBytes == 0)
123  return 0;
124 
125  uint32_t sector = 0;
126  if (has_4k_start_sectors(sectorSizeBytes))
127  {
128  if (address < 0x20000)
129  {
130  uint32_t sector4kSizeBytes = size_for_sector_number(sectorSizeBytes, 0);
131  sector = address / sector4kSizeBytes;
132  }
133  else
134  {
135  sector += 32;
136  sector += (address-0x20000) / sectorSizeBytes;
137  }
138  }
139  else
140  {
141  sector = address / sectorSizeBytes;
142  }
143 
144  return sector;
145 }
146 
147 static uint32_t address_for_sector(uint32_t sectorSizeBytes, uint32_t sector)
148 {
149  uint32_t address=0;
150  if (has_4k_start_sectors(sectorSizeBytes))
151  {
152  if (sector < 32)
153  address = sector * size_for_sector_number(sectorSizeBytes, 0);
154  else
155  {
156  address = 32 * size_for_sector_number(sectorSizeBytes, 0);
157  address += (sector - 32) * sectorSizeBytes;
158  }
159  }
160  else
161  {
162  address = sector * sectorSizeBytes;
163  }
164 
165  return address;
166 }
167 
168 inline ProgramState programstate_for_address(uint32_t address, int mode)
169 {
170  ProgramState ps;
171  switch(mode)
172  {
173  case 0: ps = (address < 0x100000) ? kProgramStateEraseBank3 : kProgramStateEraseBank4; break;
174  case 1: ps = (address < 0x100000) ? kProgramStateProgramBank3 : kProgramStateProgramBank4; break;
175  case 2: ps = (address < 0x100000) ? kProgramStateVerifyBank3 : kProgramStateVerifyBank4; break;
176  default: ps = kProgramStateFinished; break;
177  }
178 
179  return ps;
180 }
181 
182 inline uint32_t make_spi_ready(CNTV2Card& device)
183 {
184  uint32_t deviceId=0;
185  device.ReadRegister(kRegBoardID, deviceId);
186  return deviceId;
187 }
188 
189 #define wait_for_flash_status_ready() { uint8_t fs=0x00; do { FlashReadStatus(fs); } while(fs & 0x1); }
190 
192  : CNTV2SpiFlash(card, verbose),
193  mDevice(card), mBaseByteAddress(0x300000), mSize(0), mSectorSize(0)
194 {
195  mSpiResetReg = (mBaseByteAddress + 0x40) / 4;
196  mSpiControlReg = (mBaseByteAddress + 0x60) / 4;
197  mSpiStatusReg = (mBaseByteAddress + 0x64) / 4;
198  mSpiWriteReg = (mBaseByteAddress + 0x68) / 4;
199  mSpiReadReg = (mBaseByteAddress + 0x6c) / 4;
200  mSpiSlaveReg = (mBaseByteAddress + 0x70) / 4;
201  mSpiGlobalIntReg = (mBaseByteAddress + 0x1c) / 4;
202 
203  SpiReset();
204 
205  uint8_t manufactureID;
206  uint8_t memInerfaceType;
207  uint8_t memDensity;
208  uint8_t sectorArchitecture;
209  uint8_t familyID;
210  bool good = FlashDeviceInfo(manufactureID, memInerfaceType, memDensity, sectorArchitecture, familyID);
211  if (good)
212  {
213  switch(memDensity)
214  {
215  case 0x18: mSize = 16 * 1024 * 1024; break;
216  case 0x19: mSize = 32 * 1024 * 1024; break;
217  case 0x20: mSize = 64 * 1024 * 1024; break;
218  default: mSize = 0; break;
219  }
220 
221  sectorArchitecture &= 0x03;
222  switch(sectorArchitecture)
223  {
224  case 0x00:
225  {
226  mSectorSize = (manufactureID == 0x20) ? 64 * 1024 : 256 * 1024;
227  break;
228  }
229  case 0x01: mSectorSize = 64 * 1024; break;
230  default: mSectorSize = 0; break;
231  }
232 
233  mManufactureID = manufactureID;
234  }
235 
236  //uint8_t configValue;
237  //good = FlashReadConfig(configValue);
238  //uint8_t statusValue;
239  //good = FlashReadStatus(statusValue);
240 }
241 
243 {
244 }
245 
247 {
248  if ((deviceId == DEVICE_ID_IOIP_2022) ||
249  (deviceId == DEVICE_ID_IOIP_2110) ||
250  (deviceId == DEVICE_ID_IOIP_2110_RGB12) ||
251  (deviceId == DEVICE_ID_KONAX) ||
252  (deviceId == DEVICE_ID_KONAXM) ||
253  (deviceId == DEVICE_ID_KONAX_4CH) ||
254  (deviceId == DEVICE_ID_KONAIP_25G))
255  {
256  return true;
257  }
258  else
259  {
260  return false;
261  }
262 }
263 
264 bool CNTV2AxiSpiFlash::Read(const uint32_t address, std::vector<uint8_t> &data, uint32_t maxBytes)
265 {
266  const uint32_t pageSize = 128;
267  ProgramState ps = programstate_for_address(address, 2);
268 
269  uint32_t pageAddress = address;
270  uint32_t numPages = (uint32_t)ceil((double)maxBytes/(double)pageSize);
271 
272  uint32_t bytesLeftToTransfer = maxBytes;
273  uint32_t bytesTransfered = 0;
274  mDevice.WriteRegister(kVRegFlashState, ps);
275  mDevice.WriteRegister(kVRegFlashSize, bytesLeftToTransfer);
276  mDevice.WriteRegister(kVRegFlashStatus, 0);
277 
278  uint32_t lastPercent = 0;
279  for(uint32_t p=0;p<numPages;p++)
280  {
281  vector<uint8_t> commandSequence;
282  commandSequence.push_back(CYPRESS_FLASH_READFAST_COMMAND);
283  FlashFixAddress(pageAddress, commandSequence);
284 
285  uint32_t bytesToTransfer = pageSize;
286  if (bytesLeftToTransfer < pageSize)
287  bytesToTransfer = bytesLeftToTransfer;
288 
289  vector<uint8_t> dummyInput;
290  SpiTransfer(commandSequence, dummyInput, data, bytesToTransfer);
292 
293  bytesLeftToTransfer -= bytesToTransfer;
294  pageAddress += pageSize;
295 
296  bytesTransfered += bytesToTransfer;
297 
298  if (mVerbose && maxBytes > 0)
299  print_flash_status("Verify", bytesTransfered, maxBytes, lastPercent);
300 
301  mDevice.WriteRegister(kVRegFlashState, ps);
302  mDevice.WriteRegister(kVRegFlashStatus, bytesTransfered);
303  }
304 
305  if (mVerbose)
306  print_flash_status_final("Verify");
307 
308  return true;
309 }
310 
311 bool CNTV2AxiSpiFlash::Write(const uint32_t address, const std::vector<uint8_t> data, uint32_t maxBytes)
312 {
313  const uint32_t pageSize = 128;
314  ProgramState ps = programstate_for_address(address, 1);
315 
316  uint32_t maxWrite = maxBytes;
317  if (maxWrite > data.size())
318  maxWrite = (uint32_t)data.size();
319 
320  std::vector<uint8_t> dummyOutput;
321 
322  uint32_t pageAddress = address;
323  uint32_t numPages = (uint32_t)ceil((double)maxWrite/(double)pageSize);
324 
325  uint32_t bytesTransfered = 0;
326  mDevice.WriteRegister(kVRegFlashState, ps);
327  mDevice.WriteRegister(kVRegFlashSize, maxWrite);
328  mDevice.WriteRegister(kVRegFlashStatus, 0);
329 
330  uint32_t lastPercent = 0;
331  for(uint32_t p=0;p<numPages;p++)
332  {
333  vector<uint8_t> commandSequence;
334  commandSequence.push_back(CYPRESS_FLASH_PAGE_PROGRAM_COMMAND);
335  FlashFixAddress(pageAddress, commandSequence);
336 
337  vector<uint8_t> pageData;
338  for(unsigned i=0;i<pageSize;i++)
339  {
340  uint32_t offset = (p*pageSize)+i;
341  if (offset >= data.size())
342  break;
343 
344  pageData.push_back(data.at(offset));
345  }
346 
347  // enable write
348  SpiEnableWrite(true);
349 
350  SpiTransfer(commandSequence, pageData, dummyOutput, (uint32_t)pageData.size());
352 
353  // disable write
354  SpiEnableWrite(false);
355 
356  pageAddress += pageSize;
357  bytesTransfered += static_cast<uint32_t>(pageData.size());
358 
359  if (mVerbose && maxWrite > 0)
360  print_flash_status("Program", bytesTransfered, maxWrite, lastPercent);
361 
362  mDevice.WriteRegister(kVRegFlashState, ps);
363  mDevice.WriteRegister(kVRegFlashStatus, bytesTransfered);
364  }
365 
366  if (mVerbose)
367  print_flash_status_final("Program");
368 
369  return true;
370 }
371 
372 bool CNTV2AxiSpiFlash::Erase(const uint32_t address, uint32_t bytes)
373 {
374  //testing
375 #if 0
376  // 64k
377  uint32_t test1Addr = 0x20000;
378  uint32_t test1ExpectedSector = 32;
379 
380  // 4k
381  uint32_t test2Addr = 0x1F000;
382  uint32_t test2ExpectedSector = 31;
383 
384  // 64k
385  uint32_t test3Addr = 0x1FF0000;
386  uint32_t test3ExpectedSector = 541;
387 
388  uint32_t test1Res = sector_for_address(mSectorSize, test1Addr);
389  uint32_t test2Res = sector_for_address(mSectorSize, test2Addr);
390  uint32_t test3Res = sector_for_address(mSectorSize, test3Addr);
391 
392  uint32_t test1AddrRes = address_for_sector(mSectorSize, test1ExpectedSector);
393  uint32_t test2AddrRes = address_for_sector(mSectorSize, test2ExpectedSector);
394  uint32_t test3AddrRes = address_for_sector(mSectorSize, test3ExpectedSector);
395 
396  uint32_t test1Cmd = erase_cmd_for_sector(mSectorSize, test1ExpectedSector);
397  uint32_t test2Cmd = erase_cmd_for_sector(mSectorSize, test2ExpectedSector);
398  uint32_t test3Cmd = erase_cmd_for_sector(mSectorSize, test3ExpectedSector);
399  return true;
400 #endif
401 
402  ProgramState ps = programstate_for_address(address, 0);
403 
404  uint32_t startSector = sector_for_address(mSectorSize, address);
405  uint32_t endSector = sector_for_address(mSectorSize, address + bytes);
406 
407  uint32_t cmd = erase_cmd_for_sector(mSectorSize, startSector);
408  uint32_t sectorAddress = address_for_sector(mSectorSize, startSector);
409 
410  vector<uint8_t> commandSequence;
411  commandSequence.push_back(cmd);
412  FlashFixAddress(address, commandSequence);
413 
414  uint32_t lastPercent = 0;
415 
416  if (mVerbose && endSector > startSector)
417  print_flash_status("Erase", startSector, endSector-startSector, lastPercent);
418 
419  // enable write
420  SpiEnableWrite(true);
421 
422  vector<uint8_t> dummyInput;
423  vector<uint8_t> dummyOutput;
424  SpiTransfer(commandSequence, dummyInput, dummyOutput, bytes);
426 
427  // disable write
428  //SpiEnableWrite(false);
429 
430  // Handle the case of erase spanning sectors
431  if (endSector > startSector)
432  {
433  uint32_t numSectors = endSector-startSector;
434  mDevice.WriteRegister(kVRegFlashState, ps);
435  mDevice.WriteRegister(kVRegFlashSize, numSectors);
436  mDevice.WriteRegister(kVRegFlashStatus, 0);
437 
438  uint32_t start = startSector;
439  while (start < endSector)
440  {
441  ++start;
442  cmd = erase_cmd_for_sector(mSectorSize, start);
443  sectorAddress = address_for_sector(mSectorSize, start);
444 
445  vector<uint8_t> commandSequence2;
446  commandSequence2.push_back(cmd);
447  FlashFixAddress(sectorAddress, commandSequence2);
448 
449  // enable write
450  SpiEnableWrite(true);
451 
452  //vector<uint8_t> dummyInput;
453  SpiTransfer(commandSequence2, dummyInput, dummyOutput, bytes);
455 
456  // disable write
457  SpiEnableWrite(false);
458 
459  uint32_t curProgress = start-startSector;
460  if (mVerbose)
461  print_flash_status("Erase", curProgress, endSector-startSector, lastPercent);
462 
463  mDevice.WriteRegister(kVRegFlashState, ps);
464  mDevice.WriteRegister(kVRegFlashStatus, curProgress);
465  }
466 
467  if (mVerbose)
468  print_flash_status_final("Erase");
469 
470  }
471 
472  return true;
473 }
474 
475 bool CNTV2AxiSpiFlash::Verify(const uint32_t address, const std::vector<uint8_t>& dataWritten)
476 {
477  vector<uint8_t> verifyData;
478  bool readGood = Read(address, verifyData, uint32_t(dataWritten.size()));
479 
480  if (readGood == false)
481  return false;
482 
483  return verify_vectors(dataWritten, verifyData, mVerbose);
484 }
485 
487 {
488  uint32_t retVal = 0;
489 
490  switch(sectionID)
491  {
492  case SPI_FLASH_SECTION_UBOOT: retVal = 0x00080000; break;
493  case SPI_FLASH_SECTION_KERNEL: retVal = 0x00C00000; break;
494  case SPI_FLASH_SECTION_LICENSE: retVal = 0x00040000; break;
495  case SPI_FLASH_SECTION_MCSINFO: retVal = 0x00040000; break;
496  case SPI_FLASH_SECTION_MAC: retVal = 0x00040000; break;
497  case SPI_FLASH_SECTION_SERIAL: retVal = 0x00040000; break;
498  case SPI_FLASH_SECTION_TOTAL: retVal = mSize; break;
499 
500  default:
501  break;
502  }
503 
504  return retVal;
505 }
506 
508 {
509  uint32_t retVal = 0xffffffff;
510 
511  switch(sectionID)
512  {
513  case SPI_FLASH_SECTION_UBOOT: retVal = 0x00000000; break;
514  case SPI_FLASH_SECTION_KERNEL: retVal = 0x00100000; break;
515  case SPI_FLASH_SECTION_LICENSE: retVal = 0x01F00000; break;
516  case SPI_FLASH_SECTION_MCSINFO: retVal = 0x01F40000; break;
517  case SPI_FLASH_SECTION_MAC: retVal = 0x01F80000; break;
518  case SPI_FLASH_SECTION_SERIAL: retVal = 0x01FC0000; break;
519  case SPI_FLASH_SECTION_TOTAL: retVal = 0; break;
520 
521  default:
522  break;
523  }
524 
525  return retVal;
526 }
527 
528 bool CNTV2AxiSpiFlash::NTV2DeviceOk()
529 {
530  if (mDevice.IsOpen() == false)
531  return false;
532  if (DeviceSupported(mDevice.GetDeviceID()) == false)
533  return false;
534 
535  return true;
536 }
537 
538 void CNTV2AxiSpiFlash::SpiReset()
539 {
540  if (!NTV2DeviceOk())
541  return;
542 
543  mDevice.WriteRegister(mSpiSlaveReg, 0x0);
544  SpiResetFifos();
545 
546  // make sure in 32bit mode
547  uint8_t bankAddressVal=0;
548  NTV2_UNUSED(bankAddressVal);
549 }
550 
551 bool CNTV2AxiSpiFlash::SpiResetFifos()
552 {
553  if (!NTV2DeviceOk())
554  return false;
555 
556  uint32_t spi_ctrl_val=0x1e6;
557  return mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
558 }
559 
560 void CNTV2AxiSpiFlash::SpiEnableWrite(bool enable)
561 {
562  // see AXI Quad SPI v3.2 guide page 105
563 
564  // 1 disable master transaction and reset fifos
565  make_spi_ready(mDevice);
566  SpiResetFifos();
567 
568  // 2 issue the write enable command
569  if (enable)
570  {
571  make_spi_ready(mDevice);
572  mDevice.WriteRegister(mSpiWriteReg, CYPRESS_FLASH_WRITEENABLE_COMMAND);
573  SpiSendFIFOData();
574  }
575  else
576  {
577  make_spi_ready(mDevice);
578  //mDevice.WriteRegister(mSpiWriteReg, CYPRESS_FLASH_WRITEDISABLE_COMMAND);
579  //SpiSendFIFOData();
580  }
581  // Steps 3,4,5,6
582  //SpiSendFIFOData();
583 }
584 
585 bool CNTV2AxiSpiFlash::FlashDeviceInfo(uint8_t& manufactureID, uint8_t& memInerfaceType,
586  uint8_t& memDensity, uint8_t& sectorArchitecture,
587  uint8_t& familyID)
588 {
589  vector<uint8_t> commandSequence;
590  commandSequence.push_back(CYPRESS_FLASH_READ_JEDEC_ID_COMMAND);
591 
592  vector<uint8_t> dummyInput;
593  vector<uint8_t> resultData;
594  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 6);
595  if (result && resultData.size() >= 6)
596  {
597  manufactureID = resultData.at(0);
598  memInerfaceType = resultData.at(1);
599  memDensity = resultData.at(2);
600  sectorArchitecture = resultData.at(4);
601  familyID = resultData.at(5);
602  }
603 
604  return result;
605 }
606 
607 bool CNTV2AxiSpiFlash::FlashReadConfig(uint8_t& configValue)
608 {
609  vector<uint8_t> commandSequence;
610  commandSequence.push_back(CYPRESS_FLASH_READ_CONFIG_COMMAND);
611 
612  vector<uint8_t> dummyInput;
613  vector<uint8_t> resultData;
614  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
615  if (result && resultData.size() > 0)
616  {
617  configValue = resultData.at(0);
618  }
619  return result;
620 }
621 
622 bool CNTV2AxiSpiFlash::FlashReadStatus(uint8_t& statusValue)
623 {
624  vector<uint8_t> commandSequence;
625  commandSequence.push_back(CYPRESS_FLASH_READ_STATUS_COMMAND);
626 
627  vector<uint8_t> dummyInput;
628  vector<uint8_t> resultData;
629  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
630  if (result && resultData.size() > 0)
631  {
632  statusValue = resultData.at(0);
633  }
634  return result;
635 }
636 
637 bool CNTV2AxiSpiFlash::FlashReadBankAddress(uint8_t& bankAddressVal)
638 {
639  if(mManufactureID != 0x20)
640  {
641  vector<uint8_t> commandSequence;
642  commandSequence.push_back(CYPRESS_FLASH_READBANK_COMMAND);
643 
644  vector<uint8_t> dummyInput;
645  vector<uint8_t> resultData;
646  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
647  if (result && resultData.size() > 0)
648  {
649  bankAddressVal = resultData.at(0);
650  }
651  return result;
652  }
653  return true;
654 }
655 
656 bool CNTV2AxiSpiFlash::FlashWriteBankAddress(const uint8_t bankAddressVal)
657 {
658  if (mManufactureID != 0x20)
659  {
660  vector<uint8_t> commandSequence;
661  commandSequence.push_back(CYPRESS_FLASH_WRITEBANK_COMMAND);
662 
663  vector<uint8_t> input;
664  input.push_back(bankAddressVal);
665  std::vector<uint8_t> dummyOutput;
666  return SpiTransfer(commandSequence, input, dummyOutput, 1);
667  }
668  return true;
669 }
670 
671 void CNTV2AxiSpiFlash::FlashFixAddress(const uint32_t address, std::vector<uint8_t>& commandSequence)
672 {
673  // turn the address into a bytes stream and change ordering to match what
674  // the flash chip wants to see (MSB)
675  commandSequence.push_back((address & (0xff000000)) >> 24);
676  commandSequence.push_back((address & (0x00ff0000)) >> 16);
677  commandSequence.push_back((address & (0x0000ff00)) >> 8);
678  commandSequence.push_back((address & (0x000000ff)) >> 0);
679 }
680 
681 void CNTV2AxiSpiFlash::SpiSendFIFOData()
682 {
683  // The step number is determined by the transaction type
684  // Step 3/4 issue chip select
685  make_spi_ready(mDevice);
686  mDevice.WriteRegister(mSpiSlaveReg, 0x00);
687 
688  // Step 4/5 enable the master transaction by setting 0x100 low in spi control reg
689  uint32_t spi_ctrl_val = 0;
690  make_spi_ready(mDevice);
691  mDevice.ReadRegister(mSpiControlReg, spi_ctrl_val);
692  spi_ctrl_val &= ~0x100;
693  make_spi_ready(mDevice);
694  mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
695 
696  bool txFIFOEmpty = false;
697  uint32_t notEmptyCount = 0;
698  while(!txFIFOEmpty && notEmptyCount < 1000)
699  {
700  uint32_t Tx_Empty = 0;
701  mDevice.ReadRegister(mSpiStatusReg, Tx_Empty, BIT(2), 2);
702  txFIFOEmpty = Tx_Empty ? true : false;
703  notEmptyCount++;
704  }
705 
706  // Step 5/6 deassert chip select
707  make_spi_ready(mDevice);
708  mDevice.WriteRegister(mSpiSlaveReg, 0x01);
709 
710  // Step 6/7 disable the master transaction by setting 0x100 high in spi control reg
711  make_spi_ready(mDevice);
712  mDevice.ReadRegister(mSpiControlReg, spi_ctrl_val);
713  spi_ctrl_val |= 0x100;
714  make_spi_ready(mDevice);
715  mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
716 }
717 
718 bool CNTV2AxiSpiFlash::SpiTransfer(std::vector<uint8_t> commandSequence,
719  const std::vector<uint8_t> inputData,
720  std::vector<uint8_t>& outputData, uint32_t maxByteCutoff)
721 {
722  // see AXI Quad SPI v3.2 guide page 106
723 
724  bool retVal = true;
725 
726  if (commandSequence.empty())
727  return false;
728 
729  make_spi_ready(mDevice);
730 
731  // 1 Reset
732  SpiResetFifos();
733 
734  // 2 issue the command & arguments
735  uint32_t numDummyBytes = 0;
736  for(unsigned i=0;i<commandSequence.size();++i)
737  {
738  make_spi_ready(mDevice);
739  mDevice.WriteRegister(mSpiWriteReg, (ULWord)commandSequence.at(i));
740  numDummyBytes++;
741  }
742 
743  if(commandSequence.at(0) == CYPRESS_FLASH_READFAST_COMMAND)
744  numDummyBytes++;
745 
746  // 3 Load data(write) or dummy bytes(read)
747  if (commandSequence.at(0) == CYPRESS_FLASH_SECTOR4K_ERASE_COMMAND ||
748  commandSequence.at(0) == CYPRESS_FLASH_SECTOR_ERASE_COMMAND)
749  {
750  // steps 3,4,5,6
751  SpiSendFIFOData();
752  }
753  else if (inputData.empty() == false)
754  {
755  // a write command
756  // 3 load data into fifo
757  uint32_t maxWrite = maxByteCutoff;
758  if (maxWrite > inputData.size())
759  maxWrite = (uint32_t)inputData.size();
760 
761  for(uint32_t i=0;i<maxWrite;++i)
762  {
763  make_spi_ready(mDevice);
764  mDevice.WriteRegister(mSpiWriteReg, inputData.at(i));
765  }
766 
767  // 4,5,6,7
768  SpiSendFIFOData();
769  }
770  else
771  {
772  // a read command
773  // 3 load fifo with dummy bytes
774  uint32_t val = 0;
775  for(uint32_t i=0;i<=maxByteCutoff;++i)
776  {
777  make_spi_ready(mDevice);
778  mDevice.WriteRegister(mSpiWriteReg, 0x0); //dummy
779  }
780 
781  // 4,5,6,7
782  SpiSendFIFOData();
783  make_spi_ready(mDevice);
784 
785  // 8 read data from fifo
786  bool rxFIFOEmpty = false;
787  uint32_t notEmptyCount = 0;
788  while(!rxFIFOEmpty && notEmptyCount < 1000)
789  {
790  make_spi_ready(mDevice);
791  mDevice.ReadRegister(mSpiReadReg, val);
792 
793  // the first byte back is a dummy when reading flash
794  if (notEmptyCount >= numDummyBytes && notEmptyCount <= (maxByteCutoff + numDummyBytes))
795  {
796  outputData.push_back(val);
797  //printf("Pushed %X\n", val);
798  }
799  else
800  {
801  //printf("Dumped %x\n", val);
802  }
803  uint32_t Rx_Empty = 0;
804  mDevice.ReadRegister(mSpiStatusReg, Rx_Empty, BIT(0), 0);
805  rxFIFOEmpty = Rx_Empty ? true : false;
806  //printf("Not empty Rx_Empty = %d, count = %d\n", Rx_Empty, notEmptyCount);
807  notEmptyCount++;
808  }
809  }
810 
811  return retVal;
812 }
bool has_4k_start_sectors(const uint32_t reportedSectorSize)
const uint32_t CYPRESS_FLASH_WRITEBANK_COMMAND
static bool DeviceSupported(NTV2DeviceID deviceId)
See Io IP.
Definition: ntv2enums.h:41
I interrogate and control an AJA video/audio capture/playout device.
Definition: ntv2card.h:28
CNTV2AxiSpiFlash(CNTV2Card &card, bool verbose=(0))
#define BIT(_x_)
Definition: ajatypes.h:596
const uint32_t CYPRESS_FLASH_READ_CONFIG_COMMAND
Declares the CNTV2SpiFlash and CNTV2AxiSpiFlash classes.
static uint32_t address_for_sector(uint32_t sectorSizeBytes, uint32_t sector)
Definition: json.hpp:5362
virtual uint32_t Offset(SpiFlashSection sectionID=SPI_FLASH_SECTION_TOTAL)
const uint32_t CYPRESS_FLASH_READFAST_COMMAND
uint32_t ULWord
Definition: ajatypes.h:236
const uint32_t CYPRESS_FLASH_READBANK_COMMAND
#define true
virtual uint32_t Size(SpiFlashSection sectionID=SPI_FLASH_SECTION_TOTAL)
NTV2DeviceID
Identifies a specific AJA NTV2 device model number. The NTV2DeviceID is actually the PROM part number...
Definition: ntv2enums.h:20
virtual bool IsOpen(void) const
const uint32_t CYPRESS_FLASH_READ_STATUS_COMMAND
void print_flash_status_final(const string &label)
else retVal
Definition: ntv2vcam.cpp:1100
virtual bool Erase(const uint32_t address, uint32_t bytes)
static uint32_t sector_for_address(uint32_t sectorSizeBytes, uint32_t address)
uint32_t make_spi_ready(CNTV2Card &device)
#define wait_for_flash_status_ready()
virtual NTV2DeviceID GetDeviceID(void)
static uint32_t erase_cmd_for_sector(const uint32_t reportedSectorSize, const uint32_t sector)
const uint32_t CYPRESS_FLASH_READ_JEDEC_ID_COMMAND
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device...
ProgramState programstate_for_address(uint32_t address, int mode)
virtual bool Read(const uint32_t address, std::vector< uint8_t > &data, uint32_t maxBytes=1)
#define NTV2_UNUSED(__p__)
Definition: ajatypes.h:145
virtual bool WriteRegister(const ULWord inRegNum, const ULWord inValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Updates or replaces all or part of the 32-bit contents of a specific register (real or virtual) on th...
void print_flash_status(const string &label, uint32_t curValue, uint32_t maxValue, uint32_t &lastPercentage)
See Io IP.
Definition: ntv2enums.h:40
static bool verify_vectors(const std::vector< uint8_t > &dataWritten, const std::vector< uint8_t > &dataRead, bool verbose=(0))
const uint32_t CYPRESS_FLASH_SECTOR_ERASE_COMMAND
SpiFlashSection
See KONA X™.
Definition: ntv2enums.h:82
const uint32_t CYPRESS_FLASH_SECTOR4K_ERASE_COMMAND
See KONA X™.
Definition: ntv2enums.h:80
static uint32_t size_for_sector_number(const uint32_t reportedSectorSize, const uint32_t sector)
const uint32_t CYPRESS_FLASH_WRITEENABLE_COMMAND
const uint32_t CYPRESS_FLASH_PAGE_PROGRAM_COMMAND
virtual bool Write(const uint32_t address, const std::vector< uint8_t > data, uint32_t maxBytes=1)
virtual bool Verify(const uint32_t address, const std::vector< uint8_t > &dataWritten)
See KONA IP25.
Definition: ntv2enums.h:74
See KONA XM™.
Definition: ntv2enums.h:81