AJA NTV2 SDK  17.1.1.1245
NTV2 SDK 17.1.1.1245
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  {
257  return true;
258  }
259  else
260  {
261  return false;
262  }
263 }
264 
265 bool CNTV2AxiSpiFlash::Read(const uint32_t address, std::vector<uint8_t> &data, uint32_t maxBytes)
266 {
267  const uint32_t pageSize = 128;
268  ProgramState ps = programstate_for_address(address, 2);
269 
270  uint32_t pageAddress = address;
271  uint32_t numPages = (uint32_t)ceil((double)maxBytes/(double)pageSize);
272 
273  uint32_t bytesLeftToTransfer = maxBytes;
274  uint32_t bytesTransfered = 0;
275  mDevice.WriteRegister(kVRegFlashState, ps);
276  mDevice.WriteRegister(kVRegFlashSize, bytesLeftToTransfer);
277  mDevice.WriteRegister(kVRegFlashStatus, 0);
278 
279  uint32_t lastPercent = 0;
280  for(uint32_t p=0;p<numPages;p++)
281  {
282  vector<uint8_t> commandSequence;
283  commandSequence.push_back(CYPRESS_FLASH_READFAST_COMMAND);
284  FlashFixAddress(pageAddress, commandSequence);
285 
286  uint32_t bytesToTransfer = pageSize;
287  if (bytesLeftToTransfer < pageSize)
288  bytesToTransfer = bytesLeftToTransfer;
289 
290  vector<uint8_t> dummyInput;
291  SpiTransfer(commandSequence, dummyInput, data, bytesToTransfer);
293 
294  bytesLeftToTransfer -= bytesToTransfer;
295  pageAddress += pageSize;
296 
297  bytesTransfered += bytesToTransfer;
298 
299  if (mVerbose && maxBytes > 0)
300  print_flash_status("Verify", bytesTransfered, maxBytes, lastPercent);
301 
302  mDevice.WriteRegister(kVRegFlashState, ps);
303  mDevice.WriteRegister(kVRegFlashStatus, bytesTransfered);
304  }
305 
306  if (mVerbose)
307  print_flash_status_final("Verify");
308 
309  return true;
310 }
311 
312 bool CNTV2AxiSpiFlash::Write(const uint32_t address, const std::vector<uint8_t> data, uint32_t maxBytes)
313 {
314  const uint32_t pageSize = 128;
315  ProgramState ps = programstate_for_address(address, 1);
316 
317  uint32_t maxWrite = maxBytes;
318  if (maxWrite > data.size())
319  maxWrite = (uint32_t)data.size();
320 
321  std::vector<uint8_t> dummyOutput;
322 
323  uint32_t pageAddress = address;
324  uint32_t numPages = (uint32_t)ceil((double)maxWrite/(double)pageSize);
325 
326  uint32_t bytesTransfered = 0;
327  mDevice.WriteRegister(kVRegFlashState, ps);
328  mDevice.WriteRegister(kVRegFlashSize, maxWrite);
329  mDevice.WriteRegister(kVRegFlashStatus, 0);
330 
331  uint32_t lastPercent = 0;
332  for(uint32_t p=0;p<numPages;p++)
333  {
334  vector<uint8_t> commandSequence;
335  commandSequence.push_back(CYPRESS_FLASH_PAGE_PROGRAM_COMMAND);
336  FlashFixAddress(pageAddress, commandSequence);
337 
338  vector<uint8_t> pageData;
339  for(unsigned i=0;i<pageSize;i++)
340  {
341  uint32_t offset = (p*pageSize)+i;
342  if (offset >= data.size())
343  break;
344 
345  pageData.push_back(data.at(offset));
346  }
347 
348  // enable write
349  SpiEnableWrite(true);
350 
351  SpiTransfer(commandSequence, pageData, dummyOutput, (uint32_t)pageData.size());
353 
354  // disable write
355  SpiEnableWrite(false);
356 
357  pageAddress += pageSize;
358  bytesTransfered += static_cast<uint32_t>(pageData.size());
359 
360  if (mVerbose && maxWrite > 0)
361  print_flash_status("Program", bytesTransfered, maxWrite, lastPercent);
362 
363  mDevice.WriteRegister(kVRegFlashState, ps);
364  mDevice.WriteRegister(kVRegFlashStatus, bytesTransfered);
365  }
366 
367  if (mVerbose)
368  print_flash_status_final("Program");
369 
370  return true;
371 }
372 
373 bool CNTV2AxiSpiFlash::Erase(const uint32_t address, uint32_t bytes)
374 {
375  //testing
376 #if 0
377  // 64k
378  uint32_t test1Addr = 0x20000;
379  uint32_t test1ExpectedSector = 32;
380 
381  // 4k
382  uint32_t test2Addr = 0x1F000;
383  uint32_t test2ExpectedSector = 31;
384 
385  // 64k
386  uint32_t test3Addr = 0x1FF0000;
387  uint32_t test3ExpectedSector = 541;
388 
389  uint32_t test1Res = sector_for_address(mSectorSize, test1Addr);
390  uint32_t test2Res = sector_for_address(mSectorSize, test2Addr);
391  uint32_t test3Res = sector_for_address(mSectorSize, test3Addr);
392 
393  uint32_t test1AddrRes = address_for_sector(mSectorSize, test1ExpectedSector);
394  uint32_t test2AddrRes = address_for_sector(mSectorSize, test2ExpectedSector);
395  uint32_t test3AddrRes = address_for_sector(mSectorSize, test3ExpectedSector);
396 
397  uint32_t test1Cmd = erase_cmd_for_sector(mSectorSize, test1ExpectedSector);
398  uint32_t test2Cmd = erase_cmd_for_sector(mSectorSize, test2ExpectedSector);
399  uint32_t test3Cmd = erase_cmd_for_sector(mSectorSize, test3ExpectedSector);
400  return true;
401 #endif
402 
403  ProgramState ps = programstate_for_address(address, 0);
404 
405  uint32_t startSector = sector_for_address(mSectorSize, address);
406  uint32_t endSector = sector_for_address(mSectorSize, address + bytes);
407 
408  uint32_t cmd = erase_cmd_for_sector(mSectorSize, startSector);
409  uint32_t sectorAddress = address_for_sector(mSectorSize, startSector);
410 
411  vector<uint8_t> commandSequence;
412  commandSequence.push_back(cmd);
413  FlashFixAddress(address, commandSequence);
414 
415  uint32_t lastPercent = 0;
416 
417  if (mVerbose && endSector > startSector)
418  print_flash_status("Erase", startSector, endSector-startSector, lastPercent);
419 
420  // enable write
421  SpiEnableWrite(true);
422 
423  vector<uint8_t> dummyInput;
424  vector<uint8_t> dummyOutput;
425  SpiTransfer(commandSequence, dummyInput, dummyOutput, bytes);
427 
428  // disable write
429  //SpiEnableWrite(false);
430 
431  // Handle the case of erase spanning sectors
432  if (endSector > startSector)
433  {
434  uint32_t numSectors = endSector-startSector;
435  mDevice.WriteRegister(kVRegFlashState, ps);
436  mDevice.WriteRegister(kVRegFlashSize, numSectors);
437  mDevice.WriteRegister(kVRegFlashStatus, 0);
438 
439  uint32_t start = startSector;
440  while (start < endSector)
441  {
442  ++start;
443  cmd = erase_cmd_for_sector(mSectorSize, start);
444  sectorAddress = address_for_sector(mSectorSize, start);
445 
446  vector<uint8_t> commandSequence2;
447  commandSequence2.push_back(cmd);
448  FlashFixAddress(sectorAddress, commandSequence2);
449 
450  // enable write
451  SpiEnableWrite(true);
452 
453  //vector<uint8_t> dummyInput;
454  SpiTransfer(commandSequence2, dummyInput, dummyOutput, bytes);
456 
457  // disable write
458  SpiEnableWrite(false);
459 
460  uint32_t curProgress = start-startSector;
461  if (mVerbose)
462  print_flash_status("Erase", curProgress, endSector-startSector, lastPercent);
463 
464  mDevice.WriteRegister(kVRegFlashState, ps);
465  mDevice.WriteRegister(kVRegFlashStatus, curProgress);
466  }
467 
468  if (mVerbose)
469  print_flash_status_final("Erase");
470 
471  }
472 
473  return true;
474 }
475 
476 bool CNTV2AxiSpiFlash::Verify(const uint32_t address, const std::vector<uint8_t>& dataWritten)
477 {
478  vector<uint8_t> verifyData;
479  bool readGood = Read(address, verifyData, uint32_t(dataWritten.size()));
480 
481  if (readGood == false)
482  return false;
483 
484  return verify_vectors(dataWritten, verifyData, mVerbose);
485 }
486 
488 {
489  uint32_t retVal = 0;
490 
491  switch(sectionID)
492  {
493  case SPI_FLASH_SECTION_UBOOT: retVal = 0x00080000; break;
494  case SPI_FLASH_SECTION_KERNEL: retVal = 0x00C00000; break;
495  case SPI_FLASH_SECTION_LICENSE: retVal = 0x00040000; break;
496  case SPI_FLASH_SECTION_MCSINFO: retVal = 0x00040000; break;
497  case SPI_FLASH_SECTION_MAC: retVal = 0x00040000; break;
498  case SPI_FLASH_SECTION_SERIAL: retVal = 0x00040000; break;
499  case SPI_FLASH_SECTION_TOTAL: retVal = mSize; break;
500 
501  default:
502  break;
503  }
504 
505  return retVal;
506 }
507 
509 {
510  uint32_t retVal = 0xffffffff;
511 
512  switch(sectionID)
513  {
514  case SPI_FLASH_SECTION_UBOOT: retVal = 0x00000000; break;
515  case SPI_FLASH_SECTION_KERNEL: retVal = 0x00100000; break;
516  case SPI_FLASH_SECTION_LICENSE: retVal = 0x01F00000; break;
517  case SPI_FLASH_SECTION_MCSINFO: retVal = 0x01F40000; break;
518  case SPI_FLASH_SECTION_MAC: retVal = 0x01F80000; break;
519  case SPI_FLASH_SECTION_SERIAL: retVal = 0x01FC0000; break;
520  case SPI_FLASH_SECTION_TOTAL: retVal = 0; break;
521 
522  default:
523  break;
524  }
525 
526  return retVal;
527 }
528 
529 bool CNTV2AxiSpiFlash::NTV2DeviceOk()
530 {
531  if (mDevice.IsOpen() == false)
532  return false;
533  if (DeviceSupported(mDevice.GetDeviceID()) == false)
534  return false;
535 
536  return true;
537 }
538 
539 void CNTV2AxiSpiFlash::SpiReset()
540 {
541  if (!NTV2DeviceOk())
542  return;
543 
544  mDevice.WriteRegister(mSpiSlaveReg, 0x0);
545  SpiResetFifos();
546 
547  // make sure in 32bit mode
548  uint8_t bankAddressVal=0;
549  NTV2_UNUSED(bankAddressVal);
550 }
551 
552 bool CNTV2AxiSpiFlash::SpiResetFifos()
553 {
554  if (!NTV2DeviceOk())
555  return false;
556 
557  uint32_t spi_ctrl_val=0x1e6;
558  return mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
559 }
560 
561 void CNTV2AxiSpiFlash::SpiEnableWrite(bool enable)
562 {
563  // see AXI Quad SPI v3.2 guide page 105
564 
565  // 1 disable master transaction and reset fifos
566  make_spi_ready(mDevice);
567  SpiResetFifos();
568 
569  // 2 issue the write enable command
570  if (enable)
571  {
572  make_spi_ready(mDevice);
573  mDevice.WriteRegister(mSpiWriteReg, CYPRESS_FLASH_WRITEENABLE_COMMAND);
574  SpiSendFIFOData();
575  }
576  else
577  {
578  make_spi_ready(mDevice);
579  //mDevice.WriteRegister(mSpiWriteReg, CYPRESS_FLASH_WRITEDISABLE_COMMAND);
580  //SpiSendFIFOData();
581  }
582  // Steps 3,4,5,6
583  //SpiSendFIFOData();
584 }
585 
586 bool CNTV2AxiSpiFlash::FlashDeviceInfo(uint8_t& manufactureID, uint8_t& memInerfaceType,
587  uint8_t& memDensity, uint8_t& sectorArchitecture,
588  uint8_t& familyID)
589 {
590  vector<uint8_t> commandSequence;
591  commandSequence.push_back(CYPRESS_FLASH_READ_JEDEC_ID_COMMAND);
592 
593  vector<uint8_t> dummyInput;
594  vector<uint8_t> resultData;
595  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 6);
596  if (result && resultData.size() >= 6)
597  {
598  manufactureID = resultData.at(0);
599  memInerfaceType = resultData.at(1);
600  memDensity = resultData.at(2);
601  sectorArchitecture = resultData.at(4);
602  familyID = resultData.at(5);
603  }
604 
605  return result;
606 }
607 
608 bool CNTV2AxiSpiFlash::FlashReadConfig(uint8_t& configValue)
609 {
610  vector<uint8_t> commandSequence;
611  commandSequence.push_back(CYPRESS_FLASH_READ_CONFIG_COMMAND);
612 
613  vector<uint8_t> dummyInput;
614  vector<uint8_t> resultData;
615  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
616  if (result && resultData.size() > 0)
617  {
618  configValue = resultData.at(0);
619  }
620  return result;
621 }
622 
623 bool CNTV2AxiSpiFlash::FlashReadStatus(uint8_t& statusValue)
624 {
625  vector<uint8_t> commandSequence;
626  commandSequence.push_back(CYPRESS_FLASH_READ_STATUS_COMMAND);
627 
628  vector<uint8_t> dummyInput;
629  vector<uint8_t> resultData;
630  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
631  if (result && resultData.size() > 0)
632  {
633  statusValue = resultData.at(0);
634  }
635  return result;
636 }
637 
638 bool CNTV2AxiSpiFlash::FlashReadBankAddress(uint8_t& bankAddressVal)
639 {
640  if(mManufactureID != 0x20)
641  {
642  vector<uint8_t> commandSequence;
643  commandSequence.push_back(CYPRESS_FLASH_READBANK_COMMAND);
644 
645  vector<uint8_t> dummyInput;
646  vector<uint8_t> resultData;
647  bool result = SpiTransfer(commandSequence, dummyInput, resultData, 1);
648  if (result && resultData.size() > 0)
649  {
650  bankAddressVal = resultData.at(0);
651  }
652  return result;
653  }
654  return true;
655 }
656 
657 bool CNTV2AxiSpiFlash::FlashWriteBankAddress(const uint8_t bankAddressVal)
658 {
659  if (mManufactureID != 0x20)
660  {
661  vector<uint8_t> commandSequence;
662  commandSequence.push_back(CYPRESS_FLASH_WRITEBANK_COMMAND);
663 
664  vector<uint8_t> input;
665  input.push_back(bankAddressVal);
666  std::vector<uint8_t> dummyOutput;
667  return SpiTransfer(commandSequence, input, dummyOutput, 1);
668  }
669  return true;
670 }
671 
672 void CNTV2AxiSpiFlash::FlashFixAddress(const uint32_t address, std::vector<uint8_t>& commandSequence)
673 {
674  // turn the address into a bytes stream and change ordering to match what
675  // the flash chip wants to see (MSB)
676  commandSequence.push_back((address & (0xff000000)) >> 24);
677  commandSequence.push_back((address & (0x00ff0000)) >> 16);
678  commandSequence.push_back((address & (0x0000ff00)) >> 8);
679  commandSequence.push_back((address & (0x000000ff)) >> 0);
680 }
681 
682 void CNTV2AxiSpiFlash::SpiSendFIFOData()
683 {
684  // The step number is determined by the transaction type
685  // Step 3/4 issue chip select
686  make_spi_ready(mDevice);
687  mDevice.WriteRegister(mSpiSlaveReg, 0x00);
688 
689  // Step 4/5 enable the master transaction by setting 0x100 low in spi control reg
690  uint32_t spi_ctrl_val = 0;
691  make_spi_ready(mDevice);
692  mDevice.ReadRegister(mSpiControlReg, spi_ctrl_val);
693  spi_ctrl_val &= ~0x100;
694  make_spi_ready(mDevice);
695  mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
696 
697  bool txFIFOEmpty = false;
698  uint32_t notEmptyCount = 0;
699  while(!txFIFOEmpty && notEmptyCount < 1000)
700  {
701  uint32_t Tx_Empty = 0;
702  mDevice.ReadRegister(mSpiStatusReg, Tx_Empty, BIT(2), 2);
703  txFIFOEmpty = Tx_Empty ? true : false;
704  notEmptyCount++;
705  }
706 
707  // Step 5/6 deassert chip select
708  make_spi_ready(mDevice);
709  mDevice.WriteRegister(mSpiSlaveReg, 0x01);
710 
711  // Step 6/7 disable the master transaction by setting 0x100 high in spi control reg
712  make_spi_ready(mDevice);
713  mDevice.ReadRegister(mSpiControlReg, spi_ctrl_val);
714  spi_ctrl_val |= 0x100;
715  make_spi_ready(mDevice);
716  mDevice.WriteRegister(mSpiControlReg, spi_ctrl_val);
717 }
718 
719 bool CNTV2AxiSpiFlash::SpiTransfer(std::vector<uint8_t> commandSequence,
720  const std::vector<uint8_t> inputData,
721  std::vector<uint8_t>& outputData, uint32_t maxByteCutoff)
722 {
723  // see AXI Quad SPI v3.2 guide page 106
724 
725  bool retVal = true;
726 
727  if (commandSequence.empty())
728  return false;
729 
730  make_spi_ready(mDevice);
731 
732  // 1 Reset
733  SpiResetFifos();
734 
735  // 2 issue the command & arguments
736  uint32_t numDummyBytes = 0;
737  for(unsigned i=0;i<commandSequence.size();++i)
738  {
739  make_spi_ready(mDevice);
740  mDevice.WriteRegister(mSpiWriteReg, (ULWord)commandSequence.at(i));
741  numDummyBytes++;
742  }
743 
744  if(commandSequence.at(0) == CYPRESS_FLASH_READFAST_COMMAND)
745  numDummyBytes++;
746 
747  // 3 Load data(write) or dummy bytes(read)
748  if (commandSequence.at(0) == CYPRESS_FLASH_SECTOR4K_ERASE_COMMAND ||
749  commandSequence.at(0) == CYPRESS_FLASH_SECTOR_ERASE_COMMAND)
750  {
751  // steps 3,4,5,6
752  SpiSendFIFOData();
753  }
754  else if (inputData.empty() == false)
755  {
756  // a write command
757  // 3 load data into fifo
758  uint32_t maxWrite = maxByteCutoff;
759  if (maxWrite > inputData.size())
760  maxWrite = (uint32_t)inputData.size();
761 
762  for(uint32_t i=0;i<maxWrite;++i)
763  {
764  make_spi_ready(mDevice);
765  mDevice.WriteRegister(mSpiWriteReg, inputData.at(i));
766  }
767 
768  // 4,5,6,7
769  SpiSendFIFOData();
770  }
771  else
772  {
773  // a read command
774  // 3 load fifo with dummy bytes
775  uint32_t val = 0;
776  for(uint32_t i=0;i<=maxByteCutoff;++i)
777  {
778  make_spi_ready(mDevice);
779  mDevice.WriteRegister(mSpiWriteReg, 0x0); //dummy
780  }
781 
782  // 4,5,6,7
783  SpiSendFIFOData();
784  make_spi_ready(mDevice);
785 
786  // 8 read data from fifo
787  bool rxFIFOEmpty = false;
788  uint32_t notEmptyCount = 0;
789  while(!rxFIFOEmpty && notEmptyCount < 1000)
790  {
791  make_spi_ready(mDevice);
792  mDevice.ReadRegister(mSpiReadReg, val);
793 
794  // the first byte back is a dummy when reading flash
795  if (notEmptyCount >= numDummyBytes && notEmptyCount <= (maxByteCutoff + numDummyBytes))
796  {
797  outputData.push_back(val);
798  //printf("Pushed %X\n", val);
799  }
800  else
801  {
802  //printf("Dumped %x\n", val);
803  }
804  uint32_t Rx_Empty = 0;
805  mDevice.ReadRegister(mSpiStatusReg, Rx_Empty, BIT(0), 0);
806  rxFIFOEmpty = Rx_Empty ? true : false;
807  //printf("Not empty Rx_Empty = %d, count = %d\n", Rx_Empty, notEmptyCount);
808  notEmptyCount++;
809  }
810  }
811 
812  return retVal;
813 }
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:508
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:487
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:253
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:373
UWord
uint16_t UWord
Definition: ajatypes.h:251
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:162
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:265
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:381
CNTV2AxiSpiFlash::Verify
virtual bool Verify(const uint32_t address, const std::vector< uint8_t > &dataWritten)
Definition: ntv2spiinterface.cpp:476
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:312
BIT
#define BIT(_x_)
Definition: ajatypes.h:561
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