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