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