source: rtems/bsps/shared/dev/spi/xqspipsu-flash-helper.c @ 09fd5dd3

Last change on this file since 09fd5dd3 was 09fd5dd3, checked in by Kinsey Moore <kinsey.moore@…>, on 05/24/23 at 19:53:58

bsps/xqspipsu: Use device information from the FCT

Instead of statically defining the device parameters, use the device
information available via the NOR device layer's Flash Configuration
Table.

  • Property mode set to 100644
File size: 63.1 KB
Line 
1/******************************************************************************
2* Copyright (C) 2018 - 2022 Xilinx, Inc.  All rights reserved.
3* SPDX-License-Identifier: MIT
4******************************************************************************/
5
6/**
7 * @file xqspipsu_flash_helper.c
8 *
9 * This file contains flash helper functions for the QSPIPSU driver. It
10 * consists of modified functions from Xilinx's flash example in
11 * examples/xqspipsu_generic_flash_interrupt_example.c of the qspipsu driver.
12 *
13 */
14
15#include "xqspipsu_flash_config.h"
16#include "xqspipsu-flash-helper.h"
17
18#include <rtems.h>
19
20/*
21 * Number of flash pages to be written.
22 */
23#define PAGE_COUNT              32
24
25/*
26 * Max page size to initialize write and read buffer
27 */
28#define MAX_PAGE_SIZE 1024
29
30#define TEST_ADDRESS            0x000000
31
32#define ENTER_4B        1
33#define EXIT_4B         0
34
35u8 ReadCmd;
36u8 WriteCmd;
37u8 StatusCmd;
38u8 SectorEraseCmd;
39u8 FSRFlag;
40
41static int FlashReadID(XQspiPsu *QspiPsuPtr);
42
43static int MultiDieRead(
44  XQspiPsu *QspiPsuPtr,
45  u32 Address,
46  u32 ByteCount,
47  u8 Command,
48  u8 *WriteBfrPtr,
49  u8 *ReadBfrPtr
50);
51
52static u32 GetRealAddr(
53  XQspiPsu *QspiPsuPtr,
54  u32 Address
55);
56
57static int BulkErase(
58  XQspiPsu *QspiPsuPtr,
59  u8 *WriteBfrPtr
60);
61
62static int DieErase(
63  XQspiPsu *QspiPsuPtr,
64  u8 *WriteBfrPtr
65);
66
67static int QspiPsuSetupIntrSystem(
68  XQspiPsu *QspiPsuInstancePtr,
69  u16 QspiPsuIntrId
70);
71
72static void QspiPsuHandler(
73  void *CallBackRef,
74  u32 StatusEvent,
75  unsigned int ByteCount
76);
77
78static int FlashEnterExit4BAddMode(
79  XQspiPsu *QspiPsuPtr,
80  unsigned int Enable
81);
82
83static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr);
84
85u8 TxBfrPtr;
86u8 ReadBfrPtr[3];
87u32 FlashMake;
88u32 FCTIndex;   /* Flash configuration table index */
89
90static XQspiPsu_Msg FlashMsg[5];
91
92/*
93 * The following variables are shared between non-interrupt processing and
94 * interrupt processing such that they must be global.
95 */
96volatile int TransferInProgress;
97
98/*
99 * The following variable tracks any errors that occur during interrupt
100 * processing
101 */
102int Error;
103
104/*
105 * The following variable allows a test value to be added to the values that
106 * are written to the Flash such that unique values can be generated to
107 * guarantee the writes to the Flash were successful
108 */
109int Test = 1;
110
111/*
112 * The following variables are used to read and write to the flash and they
113 * are global to avoid having large buffers on the stack
114 * The buffer size accounts for maximum page size and maximum banks -
115 * for each bank separate read will be performed leading to that many
116 * (overhead+dummy) bytes
117 */
118#ifdef __ICCARM__
119#pragma data_alignment = 32
120u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8];
121#else
122u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
123#endif
124u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
125u8 CmdBfr[8];
126
127/*
128 * The following constants specify the max amount of data and the size of the
129 * the buffer required to hold the data and overhead to transfer the data to
130 * and from the Flash. Initialized to single flash page size.
131 */
132u32 MaxData = PAGE_COUNT*256;
133
134int QspiPsu_NOR_Initialize(
135  XQspiPsu *QspiPsuInstancePtr,
136  u16 QspiPsuIntrId
137)
138{
139  int Status;
140
141  if (QspiPsuInstancePtr == NULL) {
142    return XST_FAILURE;
143  }
144
145  /*
146   * Connect the QspiPsu device to the interrupt subsystem such that
147   * interrupts can occur. This function is application specific
148   */
149  Status = QspiPsuSetupIntrSystem(QspiPsuInstancePtr, QspiPsuIntrId);
150  if (Status != XST_SUCCESS) {
151    return XST_FAILURE;
152  }
153
154    /*
155   * Setup the handler for the QSPIPSU that will be called from the
156   * interrupt context when an QSPIPSU status occurs, specify a pointer to
157   * the QSPIPSU driver instance as the callback reference
158   * so the handler is able to access the instance data
159   */
160  XQspiPsu_SetStatusHandler(QspiPsuInstancePtr, QspiPsuInstancePtr,
161         (XQspiPsu_StatusHandler) QspiPsuHandler);
162
163  /*
164   * Set Manual Start
165   */
166  XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION);
167
168  /*
169   * Set the prescaler for QSPIPSU clock
170   */
171  XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8);
172
173  XQspiPsu_SelectFlash(QspiPsuInstancePtr,
174    XQSPIPSU_SELECT_FLASH_CS_LOWER,
175    XQSPIPSU_SELECT_FLASH_BUS_LOWER);
176
177  /*
178   * Read flash ID and obtain all flash related information
179   * It is important to call the read id function before
180   * performing proceeding to any operation, including
181   * preparing the WriteBuffer
182   */
183
184  Status = FlashReadID(QspiPsuInstancePtr);
185  if (Status != XST_SUCCESS) {
186    return XST_FAILURE;
187  }
188
189  /*
190   * Some flash needs to enable Quad mode before using
191   * quad commands.
192   */
193  Status = FlashEnableQuadMode(QspiPsuInstancePtr);
194  if (Status != XST_SUCCESS)
195    return XST_FAILURE;
196
197  /*
198   * Address size and read command selection
199   * Micron flash on REMUS doesn't support these 4B write/erase commands
200   */
201  if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
202    ReadCmd = FAST_READ_CMD;
203  else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
204    ReadCmd = DUAL_READ_CMD;
205  else
206    ReadCmd = QUAD_READ_CMD;
207
208  WriteCmd = WRITE_CMD;
209  SectorEraseCmd = SEC_ERASE_CMD;
210
211  if ((Flash_Config_Table[FCTIndex].NumDie > 1) &&
212      (FlashMake == MICRON_ID_BYTE0)) {
213    StatusCmd = READ_FLAG_STATUS_CMD;
214    FSRFlag = 1;
215  } else {
216    StatusCmd = READ_STATUS_CMD;
217    FSRFlag = 0;
218  }
219
220  if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
221    Status = FlashEnterExit4BAddMode(QspiPsuInstancePtr, ENTER_4B);
222    if (Status != XST_SUCCESS) {
223      return XST_FAILURE;
224    }
225    if (FlashMake == SPANSION_ID_BYTE0) {
226      if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
227        ReadCmd = FAST_READ_CMD_4B;
228      else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
229        ReadCmd = DUAL_READ_CMD_4B;
230      else
231        ReadCmd = QUAD_READ_CMD_4B;
232
233      WriteCmd = WRITE_CMD_4B;
234      SectorEraseCmd = SEC_ERASE_CMD_4B;
235    }
236  }
237
238  return XST_SUCCESS;
239}
240
241/*****************************************************************************/
242/**
243 *
244 * Callback handler.
245 *
246 * @param       CallBackRef is the upper layer callback reference passed back
247 *              when the callback function is invoked.
248 * @param       StatusEvent is the event that just occurred.
249 * @param       ByteCount is the number of bytes transferred up until the event
250 *              occurred.
251 *
252 * @return      None
253 *
254 * @note        None.
255 *
256 *****************************************************************************/
257static void QspiPsuHandler(
258  void *CallBackRef,
259  u32 StatusEvent,
260  unsigned int ByteCount
261)
262{
263  /*
264   * Indicate the transfer on the QSPIPSU bus is no longer in progress
265   * regardless of the status event
266   */
267  TransferInProgress = FALSE;
268
269  /*
270   * If the event was not transfer done, then track it as an error
271   */
272  if (StatusEvent != XST_SPI_TRANSFER_DONE) {
273    Error++;
274  }
275}
276
277/*****************************************************************************/
278/**
279 *
280 * Reads the flash ID and identifies the flash in FCT table.
281 *
282 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
283 *
284 * @return      XST_SUCCESS if successful, else XST_FAILURE.
285 *
286 * @note        None.
287 *
288 *****************************************************************************/
289static int FlashReadID(XQspiPsu *QspiPsuPtr)
290{
291  int Status;
292  u32 ReadId = 0;
293
294  /*
295   * Read ID
296   */
297  TxBfrPtr = READ_ID;
298  FlashMsg[0].TxBfrPtr = &TxBfrPtr;
299  FlashMsg[0].RxBfrPtr = NULL;
300  FlashMsg[0].ByteCount = 1;
301  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
302  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
303
304  FlashMsg[1].TxBfrPtr = NULL;
305  FlashMsg[1].RxBfrPtr = ReadBfrPtr;
306  FlashMsg[1].ByteCount = 3;
307  FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
308  FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
309
310  TransferInProgress = TRUE;
311  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
312  if (Status != XST_SUCCESS) {
313    return XST_FAILURE;
314  }
315  while (TransferInProgress);
316
317  /* In case of dual, read both and ensure they are same make/size */
318
319  /*
320   * Deduce flash make
321   */
322  FlashMake = ReadBfrPtr[0];
323
324  ReadId = ((ReadBfrPtr[0] << 16) | (ReadBfrPtr[1] << 8) | ReadBfrPtr[2]);
325  /*
326   * Assign corresponding index in the Flash configuration table
327   */
328  Status = CalculateFCTIndex(ReadId, &FCTIndex);
329  if (Status != XST_SUCCESS) {
330    return XST_FAILURE;
331  }
332
333  return XST_SUCCESS;
334}
335
336int QspiPsu_NOR_Write_Page(
337  XQspiPsu *QspiPsuPtr,
338  u32 Address,
339  u32 ByteCount,
340  u8 *WriteBfrPtr
341)
342{
343  u8 WriteEnableCmd;
344  u8 ReadStatusCmd;
345  u8 FlashStatus[2];
346  u8 WriteCmdBfr[5];
347  u32 RealAddr;
348  u32 CmdByteCount;
349  int Status;
350
351  WriteEnableCmd = WRITE_ENABLE_CMD;
352  /*
353   * Translate address based on type of connection
354   * If stacked assert the slave select based on address
355   */
356  RealAddr = GetRealAddr(QspiPsuPtr, Address);
357
358  /*
359   * Send the write enable command to the Flash so that it can be
360   * written to, this needs to be sent as a separate transfer before
361   * the write
362   */
363  FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
364  FlashMsg[0].RxBfrPtr = NULL;
365  FlashMsg[0].ByteCount = 1;
366  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
367  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
368
369  TransferInProgress = TRUE;
370
371  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
372  if (Status != XST_SUCCESS) {
373    return XST_FAILURE;
374  }
375
376  while (TransferInProgress);
377
378  WriteCmdBfr[COMMAND_OFFSET]   = WriteCmd;
379
380  /* To be used only if 4B address program cmd is supported by flash */
381  if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
382    WriteCmdBfr[ADDRESS_1_OFFSET] =
383        (u8)((RealAddr & 0xFF000000) >> 24);
384    WriteCmdBfr[ADDRESS_2_OFFSET] =
385        (u8)((RealAddr & 0xFF0000) >> 16);
386    WriteCmdBfr[ADDRESS_3_OFFSET] =
387        (u8)((RealAddr & 0xFF00) >> 8);
388    WriteCmdBfr[ADDRESS_4_OFFSET] =
389        (u8)(RealAddr & 0xFF);
390    CmdByteCount = 5;
391  } else {
392    WriteCmdBfr[ADDRESS_1_OFFSET] =
393        (u8)((RealAddr & 0xFF0000) >> 16);
394    WriteCmdBfr[ADDRESS_2_OFFSET] =
395        (u8)((RealAddr & 0xFF00) >> 8);
396    WriteCmdBfr[ADDRESS_3_OFFSET] =
397        (u8)(RealAddr & 0xFF);
398    CmdByteCount = 4;
399  }
400
401  FlashMsg[0].TxBfrPtr = WriteCmdBfr;
402  FlashMsg[0].RxBfrPtr = NULL;
403  FlashMsg[0].ByteCount = CmdByteCount;
404  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
405  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
406
407  FlashMsg[1].TxBfrPtr = WriteBfrPtr;
408  FlashMsg[1].RxBfrPtr = NULL;
409  FlashMsg[1].ByteCount = ByteCount;
410  FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
411  FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
412  if (QspiPsuPtr->Config.ConnectionMode ==
413      XQSPIPSU_CONNECTION_MODE_PARALLEL) {
414    FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
415  }
416
417  TransferInProgress = TRUE;
418
419  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
420  if (Status != XST_SUCCESS) {
421    return XST_FAILURE;
422  }
423
424  while (TransferInProgress);
425
426  /*
427   * Wait for the write command to the Flash to be completed, it takes
428   * some time for the data to be written
429   */
430  while (1) {
431    ReadStatusCmd = StatusCmd;
432    FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
433    FlashMsg[0].RxBfrPtr = NULL;
434    FlashMsg[0].ByteCount = 1;
435    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
436    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
437
438    FlashMsg[1].TxBfrPtr = NULL;
439    FlashMsg[1].RxBfrPtr = FlashStatus;
440    FlashMsg[1].ByteCount = 2;
441    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
442    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
443    if (QspiPsuPtr->Config.ConnectionMode ==
444        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
445      FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
446    }
447
448    TransferInProgress = TRUE;
449    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
450    if (Status != XST_SUCCESS) {
451      return XST_FAILURE;
452    }
453    while (TransferInProgress);
454
455    if (QspiPsuPtr->Config.ConnectionMode ==
456        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
457      if (FSRFlag) {
458        FlashStatus[1] &= FlashStatus[0];
459      } else {
460        FlashStatus[1] |= FlashStatus[0];
461      }
462    }
463
464    if (FSRFlag) {
465      if ((FlashStatus[1] & 0x80) != 0) {
466        break;
467      }
468    } else {
469      if ((FlashStatus[1] & 0x01) == 0) {
470        break;
471      }
472    }
473  }
474
475  return 0;
476}
477
478int QspiPsu_NOR_Write(
479  XQspiPsu *QspiPsuPtr,
480  u32 Address,
481  u32 ByteCount,
482  u8 *WriteBfrPtr
483)
484{
485  int Status;
486  size_t ByteCountRemaining = ByteCount;
487  unsigned char *WriteBfrPartial = WriteBfrPtr;
488  uint32_t AddressPartial = Address;
489  uint32_t PageSize = Flash_Config_Table[FCTIndex].PageSize;
490  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
491    PageSize *= 2;
492  }
493
494  while (ByteCountRemaining > 0) {
495    /* Get write boundary */
496    size_t WriteChunkLen = RTEMS_ALIGN_UP(AddressPartial + 1, PageSize);
497
498    /* Get offset to write boundary */
499    WriteChunkLen -= (size_t)AddressPartial;
500
501    /* Cap short writes */
502    if (WriteChunkLen > ByteCountRemaining) {
503      WriteChunkLen = ByteCountRemaining;
504    }
505
506    Status = QspiPsu_NOR_Write_Page(
507      QspiPsuPtr,
508      AddressPartial,
509      WriteChunkLen,
510      WriteBfrPartial
511    );
512    if ( Status != XST_SUCCESS ) {
513      return Status;
514    }
515
516    ByteCountRemaining -= WriteChunkLen;
517    AddressPartial += WriteChunkLen;
518    WriteBfrPartial += WriteChunkLen;
519  }
520  return Status;
521}
522
523int QspiPsu_NOR_Erase(
524  XQspiPsu *QspiPsuPtr,
525  u32 Address,
526  u32 ByteCount
527)
528{
529  u8 WriteEnableCmd;
530  u8 ReadStatusCmd;
531  u8 FlashStatus[2];
532  int Sector;
533  u32 RealAddr;
534  u32 NumSect;
535  int Status;
536  u32 SectSize;
537
538  WriteEnableCmd = WRITE_ENABLE_CMD;
539
540  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
541    SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
542    NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
543  } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
544    NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
545    SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
546  } else {
547    SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
548    NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
549  }
550
551  /*
552   * If erase size is same as the total size of the flash, use bulk erase
553   * command or die erase command multiple times as required
554   */
555  if (ByteCount == NumSect * SectSize) {
556
557    if (QspiPsuPtr->Config.ConnectionMode ==
558        XQSPIPSU_CONNECTION_MODE_STACKED) {
559      XQspiPsu_SelectFlash(QspiPsuPtr,
560        XQSPIPSU_SELECT_FLASH_CS_LOWER,
561        XQSPIPSU_SELECT_FLASH_BUS_LOWER);
562    }
563
564    if (Flash_Config_Table[FCTIndex].NumDie == 1) {
565      /*
566       * Call Bulk erase
567       */
568      BulkErase(QspiPsuPtr, CmdBfr);
569    }
570
571    if (Flash_Config_Table[FCTIndex].NumDie > 1) {
572      /*
573       * Call Die erase
574       */
575      DieErase(QspiPsuPtr, CmdBfr);
576    }
577    /*
578     * If stacked mode, bulk erase second flash
579     */
580    if (QspiPsuPtr->Config.ConnectionMode ==
581        XQSPIPSU_CONNECTION_MODE_STACKED) {
582
583      XQspiPsu_SelectFlash(QspiPsuPtr,
584        XQSPIPSU_SELECT_FLASH_CS_UPPER,
585        XQSPIPSU_SELECT_FLASH_BUS_LOWER);
586
587      if (Flash_Config_Table[FCTIndex].NumDie == 1) {
588        /*
589         * Call Bulk erase
590         */
591        BulkErase(QspiPsuPtr, CmdBfr);
592      }
593
594      if (Flash_Config_Table[FCTIndex].NumDie > 1) {
595        /*
596         * Call Die erase
597         */
598        DieErase(QspiPsuPtr, CmdBfr);
599      }
600    }
601
602    return 0;
603  }
604
605  /*
606   * If the erase size is less than the total size of the flash, use
607   * sector erase command
608   */
609
610  /*
611   * Calculate no. of sectors to erase based on byte count
612   */
613  u32 SectorStartBase = RTEMS_ALIGN_DOWN(Address, SectSize);
614  u32 SectorEndTop = RTEMS_ALIGN_UP(Address + ByteCount, SectSize);
615  NumSect = (SectorEndTop - SectorStartBase)/SectSize;
616
617  for (Sector = 0; Sector < NumSect; Sector++) {
618
619    /*
620     * Translate address based on type of connection
621     * If stacked assert the slave select based on address
622     */
623    RealAddr = GetRealAddr(QspiPsuPtr, Address);
624
625    /*
626     * Send the write enable command to the Flash so that it can be
627     * written to, this needs to be sent as a separate
628     * transfer before the write
629     */
630    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
631    FlashMsg[0].RxBfrPtr = NULL;
632    FlashMsg[0].ByteCount = 1;
633    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
634    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
635
636    TransferInProgress = TRUE;
637    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
638    if (Status != XST_SUCCESS) {
639      return XST_FAILURE;
640    }
641    while (TransferInProgress);
642
643    CmdBfr[COMMAND_OFFSET]   = SectorEraseCmd;
644
645    /*
646     * To be used only if 4B address sector erase cmd is
647     * supported by flash
648     */
649    if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
650      CmdBfr[ADDRESS_1_OFFSET] =
651          (u8)((RealAddr & 0xFF000000) >> 24);
652      CmdBfr[ADDRESS_2_OFFSET] =
653          (u8)((RealAddr & 0xFF0000) >> 16);
654      CmdBfr[ADDRESS_3_OFFSET] =
655          (u8)((RealAddr & 0xFF00) >> 8);
656      CmdBfr[ADDRESS_4_OFFSET] =
657          (u8)(RealAddr & 0xFF);
658      FlashMsg[0].ByteCount = 5;
659    } else {
660      CmdBfr[ADDRESS_1_OFFSET] =
661          (u8)((RealAddr & 0xFF0000) >> 16);
662      CmdBfr[ADDRESS_2_OFFSET] =
663          (u8)((RealAddr & 0xFF00) >> 8);
664      CmdBfr[ADDRESS_3_OFFSET] =
665          (u8)(RealAddr & 0xFF);
666      FlashMsg[0].ByteCount = 4;
667    }
668
669    FlashMsg[0].TxBfrPtr = CmdBfr;
670    FlashMsg[0].RxBfrPtr = NULL;
671    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
672    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
673
674    TransferInProgress = TRUE;
675    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
676    if (Status != XST_SUCCESS) {
677      return XST_FAILURE;
678    }
679    while (TransferInProgress);
680
681    /*
682     * Wait for the erase command to be completed
683     */
684    while (1) {
685      ReadStatusCmd = StatusCmd;
686      FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
687      FlashMsg[0].RxBfrPtr = NULL;
688      FlashMsg[0].ByteCount = 1;
689      FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
690      FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
691
692      FlashMsg[1].TxBfrPtr = NULL;
693      FlashMsg[1].RxBfrPtr = FlashStatus;
694      FlashMsg[1].ByteCount = 2;
695      FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
696      FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
697      if (QspiPsuPtr->Config.ConnectionMode ==
698          XQSPIPSU_CONNECTION_MODE_PARALLEL) {
699        FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
700      }
701
702      TransferInProgress = TRUE;
703      Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
704          FlashMsg, 2);
705      if (Status != XST_SUCCESS) {
706        return XST_FAILURE;
707      }
708      while (TransferInProgress);
709
710      if (QspiPsuPtr->Config.ConnectionMode ==
711          XQSPIPSU_CONNECTION_MODE_PARALLEL) {
712        if (FSRFlag) {
713          FlashStatus[1] &= FlashStatus[0];
714        } else {
715          FlashStatus[1] |= FlashStatus[0];
716        }
717      }
718
719      if (FSRFlag) {
720        if ((FlashStatus[1] & 0x80) != 0) {
721          break;
722        }
723      } else {
724        if ((FlashStatus[1] & 0x01) == 0) {
725          break;
726        }
727      }
728    }
729    Address += SectSize;
730  }
731
732  return 0;
733}
734
735int QspiPsu_NOR_Read(
736  XQspiPsu *QspiPsuPtr,
737  u32 Address,
738  u32 ByteCount,
739  u8 **ReadBfrPtr
740)
741{
742  u32 RealAddr;
743  u32 DiscardByteCnt;
744  u32 FlashMsgCnt;
745  int Status;
746
747  *ReadBfrPtr = ReadBuffer;
748
749  /* Check die boundary conditions if required for any flash */
750  if (Flash_Config_Table[FCTIndex].NumDie > 1) {
751
752    Status = MultiDieRead(QspiPsuPtr, Address, ByteCount, ReadCmd,
753              CmdBfr, *ReadBfrPtr);
754    if (Status != XST_SUCCESS)
755      return XST_FAILURE;
756  } else {
757    /* For Dual Stacked, split and read for boundary crossing */
758    /*
759     * Translate address based on type of connection
760     * If stacked assert the slave select based on address
761     */
762    RealAddr = GetRealAddr(QspiPsuPtr, Address);
763
764    CmdBfr[COMMAND_OFFSET]   = ReadCmd;
765    if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
766      CmdBfr[ADDRESS_1_OFFSET] =
767          (u8)((RealAddr & 0xFF000000) >> 24);
768      CmdBfr[ADDRESS_2_OFFSET] =
769          (u8)((RealAddr & 0xFF0000) >> 16);
770      CmdBfr[ADDRESS_3_OFFSET] =
771          (u8)((RealAddr & 0xFF00) >> 8);
772      CmdBfr[ADDRESS_4_OFFSET] =
773          (u8)(RealAddr & 0xFF);
774      DiscardByteCnt = 5;
775    } else {
776      CmdBfr[ADDRESS_1_OFFSET] =
777          (u8)((RealAddr & 0xFF0000) >> 16);
778      CmdBfr[ADDRESS_2_OFFSET] =
779          (u8)((RealAddr & 0xFF00) >> 8);
780      CmdBfr[ADDRESS_3_OFFSET] =
781          (u8)(RealAddr & 0xFF);
782      DiscardByteCnt = 4;
783    }
784
785    FlashMsg[0].TxBfrPtr = CmdBfr;
786    FlashMsg[0].RxBfrPtr = NULL;
787    FlashMsg[0].ByteCount = DiscardByteCnt;
788    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
789    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
790
791    FlashMsgCnt = 1;
792
793    /* It is recommended to have a separate entry for dummy */
794    if (ReadCmd == FAST_READ_CMD || ReadCmd == DUAL_READ_CMD ||
795        ReadCmd == QUAD_READ_CMD || ReadCmd == FAST_READ_CMD_4B ||
796        ReadCmd == DUAL_READ_CMD_4B ||
797        ReadCmd == QUAD_READ_CMD_4B) {
798      /* Update Dummy cycles as per flash specs for QUAD IO */
799
800      /*
801       * It is recommended that Bus width value during dummy
802       * phase should be same as data phase
803       */
804      if (ReadCmd == FAST_READ_CMD ||
805          ReadCmd == FAST_READ_CMD_4B) {
806        FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
807      }
808
809      if (ReadCmd == DUAL_READ_CMD ||
810          ReadCmd == DUAL_READ_CMD_4B) {
811        FlashMsg[1].BusWidth =
812          XQSPIPSU_SELECT_MODE_DUALSPI;
813      }
814
815      if (ReadCmd == QUAD_READ_CMD ||
816          ReadCmd == QUAD_READ_CMD_4B) {
817        FlashMsg[1].BusWidth =
818          XQSPIPSU_SELECT_MODE_QUADSPI;
819      }
820
821      FlashMsg[1].TxBfrPtr = NULL;
822      FlashMsg[1].RxBfrPtr = NULL;
823      FlashMsg[1].ByteCount = DUMMY_CLOCKS;
824      FlashMsg[1].Flags = 0;
825
826      FlashMsgCnt++;
827    }
828
829    /* Dummy cycles need to be changed as per flash specs
830     * for QUAD IO
831     */
832    if (ReadCmd == FAST_READ_CMD || ReadCmd == FAST_READ_CMD_4B)
833      FlashMsg[FlashMsgCnt].BusWidth =
834        XQSPIPSU_SELECT_MODE_SPI;
835
836    if (ReadCmd == DUAL_READ_CMD || ReadCmd == DUAL_READ_CMD_4B)
837      FlashMsg[FlashMsgCnt].BusWidth =
838        XQSPIPSU_SELECT_MODE_DUALSPI;
839
840    if (ReadCmd == QUAD_READ_CMD || ReadCmd == QUAD_READ_CMD_4B)
841      FlashMsg[FlashMsgCnt].BusWidth =
842        XQSPIPSU_SELECT_MODE_QUADSPI;
843
844    FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
845    FlashMsg[FlashMsgCnt].RxBfrPtr = *ReadBfrPtr;
846    FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
847    FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
848
849    if (QspiPsuPtr->Config.ConnectionMode ==
850        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
851      FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
852    }
853
854    TransferInProgress = TRUE;
855    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
856                FlashMsgCnt + 1);
857    if (Status != XST_SUCCESS)
858      return XST_FAILURE;
859
860    while (TransferInProgress);
861
862  }
863  return 0;
864}
865
866/*****************************************************************************/
867/**
868 *
869 * This function performs a read operation for multi die flash devices.
870 * Default setting is in DMA mode.
871 *
872 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
873 * @param       Address contains the address of the first sector which needs to
874 *              be erased.
875 * @param       ByteCount contains the total size to be erased.
876 * @param       Command is the command used to read data from the flash.
877 *              Supports normal, fast, dual and quad read commands.
878 * @param       WriteBfrPtr is pointer to the write buffer which contains data to be
879 *              transmitted
880 * @param       ReadBfrPtr is pointer to the read buffer to which valid received data
881 *              should be written
882 *
883 * @return      XST_SUCCESS if successful, else XST_FAILURE.
884 *
885 * @note        None.
886 *
887 ******************************************************************************/
888static int MultiDieRead(
889  XQspiPsu *QspiPsuPtr,
890  u32 Address,
891  u32 ByteCount,
892  u8 Command,
893  u8 *WriteBfrPtr,
894  u8 *ReadBfrPtr
895)
896{
897  u32 RealAddr;
898  u32 DiscardByteCnt;
899  u32 FlashMsgCnt;
900  int Status;
901  u32 cur_bank = 0;
902  u32 nxt_bank = 0;
903  u32 bank_size;
904  u32 remain_len = ByteCount;
905  u32 data_len;
906  u32 transfer_len;
907  u8 *ReadBuffer = ReadBfrPtr;
908
909  /*
910   * Some flash devices like N25Q512 have multiple dies
911   * in it. Read operation in these devices is bounded
912   * by its die segment. In a continuous read, across
913   * multiple dies, when the last byte of the selected
914   * die segment is read, the next byte read is the
915   * first byte of the same die segment. This is Die
916   * cross over issue. So to handle this issue, split
917   * a read transaction, that spans across multiple
918   * banks, into one read per bank. Bank size is 16MB
919   * for single and dual stacked mode and 32MB for dual
920   * parallel mode.
921   */
922  if (QspiPsuPtr->Config.ConnectionMode ==
923      XQSPIPSU_CONNECTION_MODE_PARALLEL)
924    bank_size = SIXTEENMB << 1;
925  else
926    bank_size = SIXTEENMB;
927
928  while (remain_len) {
929    cur_bank = Address / bank_size;
930    nxt_bank = (Address + remain_len) / bank_size;
931
932    if (cur_bank != nxt_bank) {
933      transfer_len = (bank_size * (cur_bank  + 1)) - Address;
934      if (remain_len < transfer_len)
935        data_len = remain_len;
936      else
937        data_len = transfer_len;
938    } else {
939      data_len = remain_len;
940    }
941    /*
942     * Translate address based on type of connection
943     * If stacked assert the slave select based on address
944     */
945    RealAddr = GetRealAddr(QspiPsuPtr, Address);
946
947    WriteBfrPtr[COMMAND_OFFSET]   = Command;
948    if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
949      WriteBfrPtr[ADDRESS_1_OFFSET] =
950          (u8)((RealAddr & 0xFF000000) >> 24);
951      WriteBfrPtr[ADDRESS_2_OFFSET] =
952          (u8)((RealAddr & 0xFF0000) >> 16);
953      WriteBfrPtr[ADDRESS_3_OFFSET] =
954          (u8)((RealAddr & 0xFF00) >> 8);
955      WriteBfrPtr[ADDRESS_4_OFFSET] =
956          (u8)(RealAddr & 0xFF);
957      DiscardByteCnt = 5;
958    } else {
959      WriteBfrPtr[ADDRESS_1_OFFSET] =
960          (u8)((RealAddr & 0xFF0000) >> 16);
961      WriteBfrPtr[ADDRESS_2_OFFSET] =
962          (u8)((RealAddr & 0xFF00) >> 8);
963      WriteBfrPtr[ADDRESS_3_OFFSET] =
964          (u8)(RealAddr & 0xFF);
965      DiscardByteCnt = 4;
966    }
967
968    FlashMsg[0].TxBfrPtr = WriteBfrPtr;
969    FlashMsg[0].RxBfrPtr = NULL;
970    FlashMsg[0].ByteCount = DiscardByteCnt;
971    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
972    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
973
974    FlashMsgCnt = 1;
975
976    /* It is recommended to have a separate entry for dummy */
977    if (Command == FAST_READ_CMD || Command == DUAL_READ_CMD ||
978        Command == QUAD_READ_CMD || Command == FAST_READ_CMD_4B ||
979        Command == DUAL_READ_CMD_4B ||
980        Command == QUAD_READ_CMD_4B) {
981      /* Update Dummy cycles as per flash specs for QUAD IO */
982
983      /*
984       * It is recommended that Bus width value during dummy
985       * phase should be same as data phase
986       */
987      if (Command == FAST_READ_CMD ||
988          Command == FAST_READ_CMD_4B) {
989        FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
990      }
991
992      if (Command == DUAL_READ_CMD ||
993          Command == DUAL_READ_CMD_4B) {
994        FlashMsg[1].BusWidth =
995          XQSPIPSU_SELECT_MODE_DUALSPI;
996      }
997
998      if (Command == QUAD_READ_CMD ||
999          Command == QUAD_READ_CMD_4B) {
1000        FlashMsg[1].BusWidth =
1001          XQSPIPSU_SELECT_MODE_QUADSPI;
1002      }
1003
1004      FlashMsg[1].TxBfrPtr = NULL;
1005      FlashMsg[1].RxBfrPtr = NULL;
1006      FlashMsg[1].ByteCount = DUMMY_CLOCKS;
1007      FlashMsg[1].Flags = 0;
1008
1009      FlashMsgCnt++;
1010    }
1011
1012    /* Dummy cycles need to be changed as per flash
1013     * specs for QUAD IO
1014     */
1015    if (Command == FAST_READ_CMD || Command == FAST_READ_CMD_4B)
1016      FlashMsg[FlashMsgCnt].BusWidth =
1017        XQSPIPSU_SELECT_MODE_SPI;
1018
1019    if (Command == DUAL_READ_CMD || Command == DUAL_READ_CMD_4B)
1020      FlashMsg[FlashMsgCnt].BusWidth =
1021        XQSPIPSU_SELECT_MODE_DUALSPI;
1022
1023    if (Command == QUAD_READ_CMD || Command == QUAD_READ_CMD_4B)
1024      FlashMsg[FlashMsgCnt].BusWidth =
1025        XQSPIPSU_SELECT_MODE_QUADSPI;
1026
1027    FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
1028    FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
1029    FlashMsg[FlashMsgCnt].ByteCount = data_len;
1030    FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
1031
1032    if (QspiPsuPtr->Config.ConnectionMode ==
1033        XQSPIPSU_CONNECTION_MODE_PARALLEL)
1034      FlashMsg[FlashMsgCnt].Flags |=
1035        XQSPIPSU_MSG_FLAG_STRIPE;
1036
1037    TransferInProgress = TRUE;
1038    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
1039                FlashMsgCnt + 1);
1040    if (Status != XST_SUCCESS)
1041      return XST_FAILURE;
1042
1043    while (TransferInProgress);
1044
1045
1046    ReadBuffer += data_len;
1047    Address += data_len;
1048    remain_len -= data_len;
1049  }
1050  return 0;
1051}
1052
1053/*****************************************************************************/
1054/**
1055 *
1056 * This functions performs a bulk erase operation when the
1057 * flash device has a single die. Works for both Spansion and Micron
1058 *
1059 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1060 * @param       WriteBfrPtr is the pointer to command+address to be sent
1061 *
1062 * @return      XST_SUCCESS if successful, else XST_FAILURE.
1063 *
1064 * @note        None.
1065 *
1066 ******************************************************************************/
1067static int BulkErase(
1068  XQspiPsu *QspiPsuPtr,
1069  u8 *WriteBfrPtr
1070)
1071{
1072  u8 WriteEnableCmd;
1073  u8 ReadStatusCmd;
1074  u8 FlashStatus[2];
1075  int Status;
1076
1077  WriteEnableCmd = WRITE_ENABLE_CMD;
1078  /*
1079   * Send the write enable command to the Flash so that it can be
1080   * written to, this needs to be sent as a separate transfer before
1081   * the write
1082   */
1083  FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1084  FlashMsg[0].RxBfrPtr = NULL;
1085  FlashMsg[0].ByteCount = 1;
1086  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1087  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1088
1089  TransferInProgress = TRUE;
1090  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1091  if (Status != XST_SUCCESS) {
1092    return XST_FAILURE;
1093  }
1094  while (TransferInProgress);
1095
1096  WriteBfrPtr[COMMAND_OFFSET]   = BULK_ERASE_CMD;
1097  FlashMsg[0].TxBfrPtr = WriteBfrPtr;
1098  FlashMsg[0].RxBfrPtr = NULL;
1099  FlashMsg[0].ByteCount = 1;
1100  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1101  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1102
1103  TransferInProgress = TRUE;
1104  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1105  if (Status != XST_SUCCESS) {
1106    return XST_FAILURE;
1107  }
1108  while (TransferInProgress);
1109
1110  /*
1111   * Wait for the write command to the Flash to be completed, it takes
1112   * some time for the data to be written
1113   */
1114  while (1) {
1115    ReadStatusCmd = StatusCmd;
1116    FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1117    FlashMsg[0].RxBfrPtr = NULL;
1118    FlashMsg[0].ByteCount = 1;
1119    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1120    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1121
1122    FlashMsg[1].TxBfrPtr = NULL;
1123    FlashMsg[1].RxBfrPtr = FlashStatus;
1124    FlashMsg[1].ByteCount = 2;
1125    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1126    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1127    if (QspiPsuPtr->Config.ConnectionMode ==
1128        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1129      FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1130    }
1131
1132    TransferInProgress = TRUE;
1133    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1134    if (Status != XST_SUCCESS) {
1135      return XST_FAILURE;
1136    }
1137    while (TransferInProgress);
1138
1139    if (QspiPsuPtr->Config.ConnectionMode ==
1140        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1141      if (FSRFlag) {
1142        FlashStatus[1] &= FlashStatus[0];
1143      } else {
1144        FlashStatus[1] |= FlashStatus[0];
1145      }
1146    }
1147
1148    if (FSRFlag) {
1149      if ((FlashStatus[1] & 0x80) != 0) {
1150        break;
1151      }
1152    } else {
1153      if ((FlashStatus[1] & 0x01) == 0) {
1154        break;
1155      }
1156    }
1157  }
1158
1159  return 0;
1160}
1161
1162/*****************************************************************************/
1163/**
1164 *
1165 * This functions performs a die erase operation on all the die in
1166 * the flash device. This function uses the die erase command for
1167 * Micron 512Mbit and 1Gbit
1168 *
1169 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1170 * @param       WriteBfrPtr is the pointer to command+address to be sent
1171 *
1172 * @return      XST_SUCCESS if successful, else XST_FAILURE.
1173 *
1174 * @note        None.
1175 *
1176 ******************************************************************************/
1177static int DieErase(
1178  XQspiPsu *QspiPsuPtr,
1179  u8 *WriteBfrPtr
1180)
1181{
1182  u8 WriteEnableCmd;
1183  u8 DieCnt;
1184  u8 ReadStatusCmd;
1185  u8 FlashStatus[2];
1186  int Status;
1187  u32 DieSize = 0;
1188  u32 Address;
1189  u32 RealAddr;
1190  u32 SectSize = 0;
1191  u32 NumSect = 0;
1192
1193  WriteEnableCmd = WRITE_ENABLE_CMD;
1194
1195  if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1196    SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
1197  } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
1198    NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
1199  } else {
1200    SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
1201    NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
1202  }
1203  DieSize = (NumSect * SectSize) / Flash_Config_Table[FCTIndex].NumDie;
1204
1205  for (DieCnt = 0;
1206    DieCnt < Flash_Config_Table[FCTIndex].NumDie;
1207    DieCnt++) {
1208    /*
1209     * Send the write enable command to the Flash so that it can be
1210     * written to, this needs to be sent as a separate transfer
1211     * before the write
1212     */
1213    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1214    FlashMsg[0].RxBfrPtr = NULL;
1215    FlashMsg[0].ByteCount = 1;
1216    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1217    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1218
1219    TransferInProgress = TRUE;
1220    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1221    if (Status != XST_SUCCESS) {
1222      return XST_FAILURE;
1223    }
1224    while (TransferInProgress);
1225
1226    WriteBfrPtr[COMMAND_OFFSET]   = DIE_ERASE_CMD;
1227
1228    Address = DieSize * DieCnt;
1229    RealAddr = GetRealAddr(QspiPsuPtr, Address);
1230    /*
1231     * To be used only if 4B address sector erase cmd is
1232     * supported by flash
1233     */
1234    if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
1235      WriteBfrPtr[ADDRESS_1_OFFSET] =
1236          (u8)((RealAddr & 0xFF000000) >> 24);
1237      WriteBfrPtr[ADDRESS_2_OFFSET] =
1238          (u8)((RealAddr & 0xFF0000) >> 16);
1239      WriteBfrPtr[ADDRESS_3_OFFSET] =
1240          (u8)((RealAddr & 0xFF00) >> 8);
1241      WriteBfrPtr[ADDRESS_4_OFFSET] =
1242          (u8)(RealAddr & 0xFF);
1243      FlashMsg[0].ByteCount = 5;
1244    } else {
1245      WriteBfrPtr[ADDRESS_1_OFFSET] =
1246          (u8)((RealAddr & 0xFF0000) >> 16);
1247      WriteBfrPtr[ADDRESS_2_OFFSET] =
1248          (u8)((RealAddr & 0xFF00) >> 8);
1249      WriteBfrPtr[ADDRESS_3_OFFSET] =
1250          (u8)(RealAddr & 0xFF);
1251      FlashMsg[0].ByteCount = 4;
1252    }
1253    FlashMsg[0].TxBfrPtr = WriteBfrPtr;
1254    FlashMsg[0].RxBfrPtr = NULL;
1255    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1256    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1257
1258    TransferInProgress = TRUE;
1259    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1260    if (Status != XST_SUCCESS) {
1261      return XST_FAILURE;
1262    }
1263    while (TransferInProgress);
1264
1265    /*
1266     * Wait for the write command to the Flash to be completed,
1267     * it takes some time for the data to be written
1268     */
1269    while (1) {
1270      ReadStatusCmd = StatusCmd;
1271      FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1272      FlashMsg[0].RxBfrPtr = NULL;
1273      FlashMsg[0].ByteCount = 1;
1274      FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1275      FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1276
1277      FlashMsg[1].TxBfrPtr = NULL;
1278      FlashMsg[1].RxBfrPtr = FlashStatus;
1279      FlashMsg[1].ByteCount = 2;
1280      FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1281      FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1282      if (QspiPsuPtr->Config.ConnectionMode ==
1283          XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1284        FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1285      }
1286
1287      TransferInProgress = TRUE;
1288      Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
1289          FlashMsg, 2);
1290      if (Status != XST_SUCCESS) {
1291        return XST_FAILURE;
1292      }
1293      while (TransferInProgress);
1294
1295      if (QspiPsuPtr->Config.ConnectionMode ==
1296          XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1297        if (FSRFlag) {
1298          FlashStatus[1] &= FlashStatus[0];
1299        } else {
1300          FlashStatus[1] |= FlashStatus[0];
1301        }
1302      }
1303
1304      if (FSRFlag) {
1305        if ((FlashStatus[1] & 0x80) != 0) {
1306          break;
1307        }
1308      } else {
1309        if ((FlashStatus[1] & 0x01) == 0) {
1310          break;
1311        }
1312      }
1313    }
1314  }
1315
1316  return 0;
1317}
1318
1319/*****************************************************************************/
1320/**
1321 *
1322 * This functions translates the address based on the type of interconnection.
1323 * In case of stacked, this function asserts the corresponding slave select.
1324 *
1325 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1326 * @param       Address which is to be accessed (for erase, write or read)
1327 *
1328 * @return      RealAddr is the translated address - for single it is unchanged;
1329 *              for stacked, the lower flash size is subtracted;
1330 *              for parallel the address is divided by 2.
1331 *
1332 * @note        In addition to get the actual address to work on flash this
1333 *              function also selects the CS and BUS based on the configuration
1334 *              detected.
1335 *
1336 ******************************************************************************/
1337static u32 GetRealAddr(
1338  XQspiPsu *QspiPsuPtr,
1339  u32 Address
1340)
1341{
1342  u32 RealAddr = 0;
1343
1344  switch (QspiPsuPtr->Config.ConnectionMode) {
1345  case XQSPIPSU_CONNECTION_MODE_SINGLE:
1346    XQspiPsu_SelectFlash(QspiPsuPtr,
1347      XQSPIPSU_SELECT_FLASH_CS_LOWER,
1348      XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1349    RealAddr = Address;
1350    break;
1351  case XQSPIPSU_CONNECTION_MODE_STACKED:
1352    /* Select lower or upper Flash based on sector address */
1353    if (Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) {
1354
1355      XQspiPsu_SelectFlash(QspiPsuPtr,
1356        XQSPIPSU_SELECT_FLASH_CS_UPPER,
1357        XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1358      /*
1359       * Subtract first flash size when accessing second flash
1360       */
1361      RealAddr = Address &
1362        (~Flash_Config_Table[FCTIndex].FlashDeviceSize);
1363    }else{
1364      /*
1365       * Set selection to L_PAGE
1366       */
1367      XQspiPsu_SelectFlash(QspiPsuPtr,
1368        XQSPIPSU_SELECT_FLASH_CS_LOWER,
1369        XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1370
1371      RealAddr = Address;
1372
1373    }
1374    break;
1375  case XQSPIPSU_CONNECTION_MODE_PARALLEL:
1376    /*
1377     * The effective address in each flash is the actual
1378     * address / 2
1379     */
1380    XQspiPsu_SelectFlash(QspiPsuPtr,
1381        XQSPIPSU_SELECT_FLASH_CS_BOTH,
1382        XQSPIPSU_SELECT_FLASH_BUS_BOTH);
1383    RealAddr = Address / 2;
1384    break;
1385  default:
1386    /* RealAddr wont be assigned in this case; */
1387  break;
1388
1389  }
1390
1391  return(RealAddr);
1392}
1393
1394/*****************************************************************************/
1395/**
1396 *
1397 * This function setups the interrupt system for a QspiPsu device.
1398 *
1399 * @param       QspiPsuInstancePtr is a pointer to the instance of the
1400 *              QspiPsu device.
1401 * @param       QspiPsuIntrId is the interrupt Id for an QSPIPSU device.
1402 *
1403 * @return      XST_SUCCESS if successful, otherwise XST_FAILURE.
1404 *
1405 * @note        None.
1406 *
1407 ******************************************************************************/
1408static int QspiPsuSetupIntrSystem(
1409  XQspiPsu *QspiPsuInstancePtr,
1410  u16 QspiPsuIntrId
1411)
1412{
1413  return rtems_interrupt_handler_install(
1414    QspiPsuIntrId,
1415    NULL,
1416    RTEMS_INTERRUPT_UNIQUE,
1417    (rtems_interrupt_handler) XQspiPsu_InterruptHandler,
1418    QspiPsuInstancePtr
1419  );
1420}
1421
1422/*****************************************************************************/
1423/**
1424 * @brief
1425 * This API enters the flash device into 4 bytes addressing mode.
1426 * As per the Micron and ISSI spec, before issuing the command
1427 * to enter into 4 byte addr mode, a write enable command is issued.
1428 * For Macronix and Winbond flash parts write
1429 * enable is not required.
1430 *
1431 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1432 * @param       Enable is a either 1 or 0 if 1 then enters 4 byte if 0 exits.
1433 *
1434 * @return
1435 *              - XST_SUCCESS if successful.
1436 *              - XST_FAILURE if it fails.
1437 *
1438 *
1439 ******************************************************************************/
1440static int FlashEnterExit4BAddMode(
1441  XQspiPsu *QspiPsuPtr,
1442  unsigned int Enable
1443)
1444{
1445  int Status;
1446  u8 WriteEnableCmd;
1447  u8 Cmd;
1448  u8 WriteDisableCmd;
1449  u8 ReadStatusCmd;
1450  u8 WriteBuffer[2] = {0};
1451  u8 FlashStatus[2] = {0};
1452
1453  if (Enable) {
1454    Cmd = ENTER_4B_ADDR_MODE;
1455  } else {
1456    if (FlashMake == ISSI_ID_BYTE0)
1457      Cmd = EXIT_4B_ADDR_MODE_ISSI;
1458    else
1459      Cmd = EXIT_4B_ADDR_MODE;
1460  }
1461
1462  switch (FlashMake) {
1463  case ISSI_ID_BYTE0:
1464  case MICRON_ID_BYTE0:
1465    WriteEnableCmd = WRITE_ENABLE_CMD;
1466    GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1467    /*
1468     * Send the write enable command to the Flash so that it can be
1469     * written to, this needs to be sent as a separate transfer
1470     * before the write
1471     */
1472    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1473    FlashMsg[0].RxBfrPtr = NULL;
1474    FlashMsg[0].ByteCount = 1;
1475    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1476    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1477
1478    TransferInProgress = TRUE;
1479    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1480    if (Status != XST_SUCCESS) {
1481      return XST_FAILURE;
1482    }
1483    while (TransferInProgress);
1484
1485    break;
1486
1487  case SPANSION_ID_BYTE0:
1488
1489    /* Read Extended Addres Register */
1490    WriteBuffer[0] = BANK_REG_RD;
1491    FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1492    FlashMsg[0].RxBfrPtr = NULL;
1493    FlashMsg[0].ByteCount = 1;
1494    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1495    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1496
1497    FlashMsg[1].TxBfrPtr = NULL;
1498    FlashMsg[1].RxBfrPtr = &WriteBuffer[1];
1499    FlashMsg[1].ByteCount = 1;
1500    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1501    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1502    TransferInProgress = TRUE;
1503    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1504    if (Status != XST_SUCCESS) {
1505      return XST_FAILURE;
1506    }
1507    while (TransferInProgress);
1508    if (Enable) {
1509      WriteBuffer[0] = BANK_REG_WR;
1510      WriteBuffer[1] |= 1 << 7;
1511    } else {
1512      WriteBuffer[0] = BANK_REG_WR;
1513      WriteBuffer[1] &= ~(0x01 << 7);
1514    }
1515
1516    FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1517    FlashMsg[0].RxBfrPtr = NULL;
1518    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1519    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1520    FlashMsg[0].ByteCount = 1;
1521    FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
1522    FlashMsg[2].RxBfrPtr = NULL;
1523    FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1524    FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_TX;
1525    FlashMsg[2].ByteCount = 1;
1526
1527    TransferInProgress = TRUE;
1528    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1529    if (Status != XST_SUCCESS) {
1530      return XST_FAILURE;
1531    }
1532    while (TransferInProgress);
1533    WriteBuffer[0] = BANK_REG_RD;
1534    FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1535    FlashMsg[0].RxBfrPtr = NULL;
1536    FlashMsg[0].ByteCount = 1;
1537    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1538    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1539
1540    FlashMsg[1].TxBfrPtr = NULL;
1541    FlashMsg[1].RxBfrPtr = &FlashStatus[0];
1542    FlashMsg[1].ByteCount = 1;
1543    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1544    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1545
1546    TransferInProgress = TRUE;
1547    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1548    if (Status != XST_SUCCESS) {
1549      return XST_FAILURE;
1550    }
1551    while (TransferInProgress);
1552
1553    return Status;
1554
1555  default:
1556    /*
1557     * For Macronix and Winbond flash parts
1558     * Write enable command is not required.
1559     */
1560    break;
1561  }
1562
1563  GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1564
1565  FlashMsg[0].TxBfrPtr = &Cmd;
1566  FlashMsg[0].RxBfrPtr = NULL;
1567  FlashMsg[0].ByteCount = 1;
1568  FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1569  FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1570
1571  TransferInProgress = TRUE;
1572  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1573  if (Status != XST_SUCCESS) {
1574    return XST_FAILURE;
1575  }
1576  while (TransferInProgress);
1577
1578  while (1) {
1579    ReadStatusCmd = StatusCmd;
1580
1581    FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1582    FlashMsg[0].RxBfrPtr = NULL;
1583    FlashMsg[0].ByteCount = 1;
1584    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1585    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1586
1587    FlashMsg[1].TxBfrPtr = NULL;
1588    FlashMsg[1].RxBfrPtr = FlashStatus;
1589    FlashMsg[1].ByteCount = 2;
1590    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1591    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1592
1593    if (QspiPsuPtr->Config.ConnectionMode ==
1594        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1595      FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1596    }
1597
1598    TransferInProgress = TRUE;
1599    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1600    if (Status != XST_SUCCESS) {
1601      return XST_FAILURE;
1602    }
1603    while (TransferInProgress);
1604
1605    if (QspiPsuPtr->Config.ConnectionMode ==
1606        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1607      if (FSRFlag) {
1608        FlashStatus[1] &= FlashStatus[0];
1609      } else {
1610        FlashStatus[1] |= FlashStatus[0];
1611      }
1612    }
1613
1614    if (FSRFlag) {
1615      if ((FlashStatus[1] & 0x80) != 0) {
1616        break;
1617      }
1618    } else {
1619      if ((FlashStatus[1] & 0x01) == 0) {
1620        break;
1621      }
1622    }
1623  }
1624
1625  switch (FlashMake) {
1626  case ISSI_ID_BYTE0:
1627  case MICRON_ID_BYTE0:
1628    WriteDisableCmd = WRITE_DISABLE_CMD;
1629    GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1630    /*
1631     * Send the write enable command to the Flash so that it can be
1632     * written to, this needs to be sent as a separate transfer
1633     * before the write
1634     */
1635    FlashMsg[0].TxBfrPtr = &WriteDisableCmd;
1636    FlashMsg[0].RxBfrPtr = NULL;
1637    FlashMsg[0].ByteCount = 1;
1638    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1639    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1640
1641    TransferInProgress = TRUE;
1642    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1643    if (Status != XST_SUCCESS) {
1644      return XST_FAILURE;
1645    }
1646    while (TransferInProgress);
1647
1648    break;
1649
1650  default:
1651    /*
1652     * For Macronix and Winbond flash parts
1653     * Write disable command is not required.
1654     */
1655    break;
1656  }
1657  return Status;
1658}
1659
1660/*****************************************************************************/
1661/**
1662 * @brief
1663 * This API enables Quad mode for the flash parts which require to enable quad
1664 * mode before using Quad commands.
1665 * For S25FL-L series flash parts this is required as the default configuration
1666 * is x1/x2 mode.
1667 *
1668 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1669 *
1670 * @return
1671 *              - XST_SUCCESS if successful.
1672 *              - XST_FAILURE if it fails.
1673 *
1674 *
1675 ******************************************************************************/
1676static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr)
1677{
1678  int Status;
1679  u8 WriteEnableCmd;
1680  u8 ReadStatusCmd;
1681  u8 FlashStatus[2];
1682  u8 StatusRegVal;
1683  u8 WriteBuffer[3] = {0};
1684
1685  switch (FlashMake) {
1686  case SPANSION_ID_BYTE0:
1687    TxBfrPtr = READ_CONFIG_CMD;
1688    FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1689    FlashMsg[0].RxBfrPtr = NULL;
1690    FlashMsg[0].ByteCount = 1;
1691    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1692    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1693
1694    FlashMsg[1].TxBfrPtr = NULL;
1695    FlashMsg[1].RxBfrPtr = &WriteBuffer[2];
1696    FlashMsg[1].ByteCount = 1;
1697    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1698    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1699
1700    TransferInProgress = TRUE;
1701    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
1702        FlashMsg, 2);
1703    if (Status != XST_SUCCESS) {
1704      return XST_FAILURE;
1705    }
1706    while (TransferInProgress);
1707
1708    WriteEnableCmd = WRITE_ENABLE_CMD;
1709    /*
1710     * Send the write enable command to the Flash
1711     * so that it can be written to, this needs
1712     * to be sent as a separate transfer before
1713     * the write
1714     */
1715    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1716    FlashMsg[0].RxBfrPtr = NULL;
1717    FlashMsg[0].ByteCount = 1;
1718    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1719    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1720
1721    TransferInProgress = TRUE;
1722    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
1723        FlashMsg, 1);
1724    if (Status != XST_SUCCESS) {
1725      return XST_FAILURE;
1726    }
1727    while (TransferInProgress);
1728
1729    GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1730
1731    WriteBuffer[0] = WRITE_CONFIG_CMD;
1732    WriteBuffer[1] |= 0x02;
1733    WriteBuffer[2] |= 0x01 << 1;
1734
1735    FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1736    FlashMsg[0].RxBfrPtr = NULL;
1737    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1738    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1739    FlashMsg[0].ByteCount = 1;
1740    FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
1741    FlashMsg[1].RxBfrPtr = NULL;
1742    FlashMsg[1].ByteCount = 2;
1743    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1744    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
1745
1746    TransferInProgress = TRUE;
1747    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
1748        FlashMsg, 2);
1749    if (Status != XST_SUCCESS) {
1750      return XST_FAILURE;
1751    }
1752    while (TransferInProgress);
1753
1754    while (1) {
1755      TxBfrPtr = READ_STATUS_CMD;
1756      FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1757      FlashMsg[0].RxBfrPtr = NULL;
1758      FlashMsg[0].ByteCount = 1;
1759      FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1760      FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1761
1762      FlashMsg[1].TxBfrPtr = NULL;
1763      FlashMsg[1].RxBfrPtr = FlashStatus;
1764      FlashMsg[1].ByteCount = 2;
1765      FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1766      FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1767
1768      TransferInProgress = TRUE;
1769      Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
1770          FlashMsg, 2);
1771      if (Status != XST_SUCCESS) {
1772        return XST_FAILURE;
1773      }
1774      while (TransferInProgress);
1775      if (QspiPsuPtr->Config.ConnectionMode ==
1776            XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1777        if (FSRFlag) {
1778          FlashStatus[1] &= FlashStatus[0];
1779        }else {
1780          FlashStatus[1] |= FlashStatus[0];
1781        }
1782      }
1783
1784      if ((FlashStatus[1] & 0x01) == 0x00)
1785        break;
1786    }
1787    TxBfrPtr = READ_CONFIG_CMD;
1788    FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1789    FlashMsg[0].RxBfrPtr = NULL;
1790    FlashMsg[0].ByteCount = 1;
1791    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1792    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1793
1794    FlashMsg[1].TxBfrPtr = NULL;
1795    FlashMsg[1].RxBfrPtr = ReadBfrPtr;
1796    FlashMsg[1].ByteCount = 1;
1797    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1798    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1799
1800    TransferInProgress = TRUE;
1801    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1802    if (Status != XST_SUCCESS) {
1803      return XST_FAILURE;
1804    }
1805    while (TransferInProgress);
1806    break;
1807  case ISSI_ID_BYTE0:
1808    /*
1809     * Read Status Register to a buffer
1810     */
1811    ReadStatusCmd = READ_STATUS_CMD;
1812    FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1813    FlashMsg[0].RxBfrPtr = NULL;
1814    FlashMsg[0].ByteCount = 1;
1815    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1816    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1817    FlashMsg[1].TxBfrPtr = NULL;
1818    FlashMsg[1].RxBfrPtr = FlashStatus;
1819    FlashMsg[1].ByteCount = 2;
1820    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1821    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1822    if (QspiPsuPtr->Config.ConnectionMode ==
1823        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1824      FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1825    }
1826    TransferInProgress = TRUE;
1827    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1828    if (Status != XST_SUCCESS) {
1829      return XST_FAILURE;
1830    }
1831    while (TransferInProgress);
1832    if (QspiPsuPtr->Config.ConnectionMode ==
1833        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1834      if (FSRFlag) {
1835        FlashStatus[1] &= FlashStatus[0];
1836      } else {
1837        FlashStatus[1] |= FlashStatus[0];
1838      }
1839    }
1840    /*
1841     * Set Quad Enable Bit in the buffer
1842     */
1843    StatusRegVal = FlashStatus[1];
1844    StatusRegVal |= 0x1 << QUAD_MODE_ENABLE_BIT;
1845
1846    /*
1847     * Write enable
1848     */
1849    WriteEnableCmd = WRITE_ENABLE_CMD;
1850    /*
1851    * Send the write enable command to the Flash so that it can be
1852    * written to, this needs to be sent as a separate transfer
1853    * before the write
1854    */
1855    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1856    FlashMsg[0].RxBfrPtr = NULL;
1857    FlashMsg[0].ByteCount = 1;
1858    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1859    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1860    TransferInProgress = TRUE;
1861    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1862    if (Status != XST_SUCCESS) {
1863      return XST_FAILURE;
1864    }
1865    while (TransferInProgress);
1866
1867    /*
1868     * Write Status register
1869     */
1870    WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_CMD;
1871    FlashMsg[0].TxBfrPtr = WriteBuffer;
1872    FlashMsg[0].RxBfrPtr = NULL;
1873    FlashMsg[0].ByteCount = 1;
1874    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1875    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1876
1877    FlashMsg[1].TxBfrPtr = &StatusRegVal;
1878    FlashMsg[1].RxBfrPtr = NULL;
1879    FlashMsg[1].ByteCount = 1;
1880    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1881    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
1882    if (QspiPsuPtr->Config.ConnectionMode ==
1883        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1884      FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1885    }
1886    TransferInProgress = TRUE;
1887    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1888    if (Status != XST_SUCCESS) {
1889      return XST_FAILURE;
1890    }
1891    while (TransferInProgress);
1892
1893    /*
1894     * Write Disable
1895     */
1896    WriteEnableCmd = WRITE_DISABLE_CMD;
1897    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1898    FlashMsg[0].RxBfrPtr = NULL;
1899    FlashMsg[0].ByteCount = 1;
1900    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1901    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1902    TransferInProgress = TRUE;
1903    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1904    if (Status != XST_SUCCESS) {
1905      return XST_FAILURE;
1906    }
1907    while (TransferInProgress);
1908    break;
1909
1910  case WINBOND_ID_BYTE0:
1911    ReadStatusCmd = READ_STATUS_REG_2_CMD;
1912    FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1913    FlashMsg[0].RxBfrPtr = NULL;
1914    FlashMsg[0].ByteCount = 1;
1915    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1916    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1917    FlashMsg[1].TxBfrPtr = NULL;
1918    FlashMsg[1].RxBfrPtr = FlashStatus;
1919    FlashMsg[1].ByteCount = 2;
1920    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1921    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1922    TransferInProgress = TRUE;
1923    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1924    if (Status != XST_SUCCESS) {
1925      return XST_FAILURE;
1926    }
1927    while (TransferInProgress);
1928
1929    if (QspiPsuPtr->Config.ConnectionMode ==
1930      XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1931      if (FSRFlag) {
1932        FlashStatus[1] &= FlashStatus[0];
1933      } else {
1934        FlashStatus[1] |= FlashStatus[0];
1935      }
1936    }
1937    /*
1938     * Set Quad Enable Bit in the buffer
1939     */
1940    StatusRegVal = FlashStatus[1];
1941    StatusRegVal |= 0x1 << WB_QUAD_MODE_ENABLE_BIT;
1942    /*
1943     * Write Enable
1944     */
1945    WriteEnableCmd = WRITE_ENABLE_CMD;
1946    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1947    FlashMsg[0].RxBfrPtr = NULL;
1948    FlashMsg[0].ByteCount = 1;
1949    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1950    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1951    TransferInProgress = TRUE;
1952    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
1953    if (Status != XST_SUCCESS) {
1954      return XST_FAILURE;
1955    }
1956    while (TransferInProgress);
1957    /*
1958     * Write Status register
1959     */
1960    WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_REG_2_CMD;
1961    FlashMsg[0].TxBfrPtr = WriteBuffer;
1962    FlashMsg[0].RxBfrPtr = NULL;
1963    FlashMsg[0].ByteCount = 1;
1964    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1965    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1966
1967    FlashMsg[1].TxBfrPtr = &StatusRegVal;
1968    FlashMsg[1].RxBfrPtr = NULL;
1969    FlashMsg[1].ByteCount = 1;
1970    FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1971    FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
1972    TransferInProgress = TRUE;
1973    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1974    if (Status != XST_SUCCESS) {
1975      return XST_FAILURE;
1976    }
1977    while (TransferInProgress);
1978
1979    while (1) {
1980      ReadStatusCmd = READ_STATUS_CMD;
1981      FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1982      FlashMsg[0].RxBfrPtr = NULL;
1983      FlashMsg[0].ByteCount = 1;
1984      FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1985      FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1986      FlashMsg[1].TxBfrPtr = NULL;
1987      FlashMsg[1].RxBfrPtr = FlashStatus;
1988      FlashMsg[1].ByteCount = 2;
1989      FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1990      FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1991      TransferInProgress = TRUE;
1992      Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
1993      if (Status != XST_SUCCESS) {
1994        return XST_FAILURE;
1995      }
1996      while (TransferInProgress);
1997
1998      if (QspiPsuPtr->Config.ConnectionMode ==
1999        XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2000        if (FSRFlag) {
2001          FlashStatus[1] &= FlashStatus[0];
2002        } else {
2003          FlashStatus[1] |= FlashStatus[0];
2004        }
2005      }
2006      if ((FlashStatus[1] & 0x01) == 0x00) {
2007        break;
2008      }
2009    }
2010    /*
2011     * Write Disable
2012     */
2013    WriteEnableCmd = WRITE_DISABLE_CMD;
2014    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
2015    FlashMsg[0].RxBfrPtr = NULL;
2016    FlashMsg[0].ByteCount = 1;
2017    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2018    FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
2019    TransferInProgress = TRUE;
2020    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
2021    if (Status != XST_SUCCESS) {
2022      return XST_FAILURE;
2023    }
2024    while (TransferInProgress);
2025    break;
2026
2027  default:
2028    /*
2029     * Currently only S25FL-L series requires the
2030     * Quad enable bit to be set to 1.
2031     */
2032    Status = XST_SUCCESS;
2033    break;
2034  }
2035
2036  return Status;
2037}
2038
2039static int MultiDieReadEcc(
2040  XQspiPsu *QspiPsuPtr,
2041  u32 Address,
2042  u32 ByteCount,
2043  u8 *WriteBfrPtr,
2044  u8 *ReadBfrPtr
2045);
2046
2047int QspiPsu_NOR_Read_Ecc(
2048  XQspiPsu *QspiPsuPtr,
2049  u32 Address,
2050  u8 *ReadBfrPtr
2051)
2052{
2053  u32 RealAddr;
2054  u32 DiscardByteCnt;
2055  u32 FlashMsgCnt;
2056  u8  EccBuffer[16];
2057  int ByteCount = sizeof(EccBuffer);
2058  int Status;
2059
2060  /* Check die boundary conditions if required for any flash */
2061  if (Flash_Config_Table[FCTIndex].NumDie > 1) {
2062
2063    Status = MultiDieReadEcc(QspiPsuPtr, Address, ByteCount,
2064              CmdBfr, EccBuffer);
2065    if (Status == XST_SUCCESS) {
2066      /* All bytes are the same, so copy one return byte into the output buffer */
2067      *ReadBfrPtr = EccBuffer[0];
2068    }
2069    return Status;
2070  }
2071
2072  /* For Dual Stacked, split and read for boundary crossing */
2073  /*
2074   * Translate address based on type of connection
2075   * If stacked assert the slave select based on address
2076   */
2077  RealAddr = GetRealAddr(QspiPsuPtr, Address);
2078
2079  CmdBfr[COMMAND_OFFSET]   = READ_ECCSR;
2080  CmdBfr[ADDRESS_1_OFFSET] =
2081      (u8)((RealAddr & 0xFF000000) >> 24);
2082  CmdBfr[ADDRESS_2_OFFSET] =
2083      (u8)((RealAddr & 0xFF0000) >> 16);
2084  CmdBfr[ADDRESS_3_OFFSET] =
2085      (u8)((RealAddr & 0xFF00) >> 8);
2086  CmdBfr[ADDRESS_4_OFFSET] =
2087      (u8)(RealAddr & 0xF0);
2088  DiscardByteCnt = 5;
2089
2090  FlashMsgCnt = 0;
2091
2092  FlashMsg[FlashMsgCnt].TxBfrPtr = CmdBfr;
2093  FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2094  FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
2095  FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2096  FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
2097
2098  FlashMsgCnt++;
2099
2100  FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2101  FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2102  FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
2103  FlashMsg[FlashMsgCnt].Flags = 0;
2104
2105  FlashMsgCnt++;
2106
2107  FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2108  FlashMsg[FlashMsgCnt].RxBfrPtr = EccBuffer;
2109  FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
2110  FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2111  FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
2112
2113  if (QspiPsuPtr->Config.ConnectionMode ==
2114      XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2115    FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
2116  }
2117
2118  TransferInProgress = TRUE;
2119  Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
2120              FlashMsgCnt + 1);
2121  if (Status == XST_SUCCESS) {
2122    while (TransferInProgress);
2123
2124    /* All bytes are the same, so copy one return byte into the output buffer */
2125    *ReadBfrPtr = EccBuffer[0];
2126  }
2127
2128  return Status;
2129}
2130
2131/*****************************************************************************/
2132/**
2133 *
2134 * This function performs an ECC read operation for multi die flash devices.
2135 * Default setting is in DMA mode.
2136 *
2137 * @param       QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
2138 * @param       Address contains the address of the first sector which needs to
2139 *              be erased.
2140 * @param       ByteCount contains the total size to be erased.
2141 * @param       WriteBfrPtr is pointer to the write buffer which contains data to be
2142 *              transmitted
2143 * @param       ReadBfrPtr is pointer to the read buffer to which valid received data
2144 *              should be written
2145 *
2146 * @return      XST_SUCCESS if successful, else XST_FAILURE.
2147 *
2148 * @note        None.
2149 *
2150 ******************************************************************************/
2151static int MultiDieReadEcc(
2152  XQspiPsu *QspiPsuPtr,
2153  u32 Address,
2154  u32 ByteCount,
2155  u8 *WriteBfrPtr,
2156  u8 *ReadBuffer
2157)
2158{
2159  u32 RealAddr;
2160  u32 DiscardByteCnt;
2161  u32 FlashMsgCnt;
2162  int Status;
2163  u32 cur_bank = 0;
2164  u32 nxt_bank = 0;
2165  u32 bank_size;
2166  u32 remain_len = ByteCount;
2167  u32 data_len;
2168  u32 transfer_len;
2169
2170  /*
2171   * Some flash devices like N25Q512 have multiple dies
2172   * in it. Read operation in these devices is bounded
2173   * by its die segment. In a continuous read, across
2174   * multiple dies, when the last byte of the selected
2175   * die segment is read, the next byte read is the
2176   * first byte of the same die segment. This is Die
2177   * cross over issue. So to handle this issue, split
2178   * a read transaction, that spans across multiple
2179   * banks, into one read per bank. Bank size is 16MB
2180   * for single and dual stacked mode and 32MB for dual
2181   * parallel mode.
2182   */
2183  if (QspiPsuPtr->Config.ConnectionMode ==
2184      XQSPIPSU_CONNECTION_MODE_PARALLEL)
2185    bank_size = SIXTEENMB << 1;
2186  else
2187    bank_size = SIXTEENMB;
2188
2189  while (remain_len) {
2190    cur_bank = Address / bank_size;
2191    nxt_bank = (Address + remain_len) / bank_size;
2192
2193    if (cur_bank != nxt_bank) {
2194      transfer_len = (bank_size * (cur_bank  + 1)) - Address;
2195      if (remain_len < transfer_len)
2196        data_len = remain_len;
2197      else
2198        data_len = transfer_len;
2199    } else {
2200      data_len = remain_len;
2201    }
2202    /*
2203     * Translate address based on type of connection
2204     * If stacked assert the slave select based on address
2205     */
2206    RealAddr = GetRealAddr(QspiPsuPtr, Address);
2207
2208    WriteBfrPtr[COMMAND_OFFSET]   = READ_ECCSR;
2209    WriteBfrPtr[ADDRESS_1_OFFSET] =
2210        (u8)((RealAddr & 0xFF000000) >> 24);
2211    WriteBfrPtr[ADDRESS_2_OFFSET] =
2212        (u8)((RealAddr & 0xFF0000) >> 16);
2213    WriteBfrPtr[ADDRESS_3_OFFSET] =
2214        (u8)((RealAddr & 0xFF00) >> 8);
2215    WriteBfrPtr[ADDRESS_4_OFFSET] =
2216        (u8)(RealAddr & 0xF0);
2217    DiscardByteCnt = 5;
2218
2219    FlashMsgCnt = 0;
2220
2221    FlashMsg[FlashMsgCnt].TxBfrPtr = WriteBfrPtr;
2222    FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2223    FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
2224    FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2225    FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
2226
2227    FlashMsgCnt++;
2228
2229    FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2230    FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2231    FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
2232    FlashMsg[FlashMsgCnt].Flags = 0;
2233
2234    FlashMsgCnt++;
2235
2236    FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2237    FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
2238    FlashMsg[FlashMsgCnt].ByteCount = data_len;
2239    FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2240    FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
2241
2242    if (QspiPsuPtr->Config.ConnectionMode ==
2243        XQSPIPSU_CONNECTION_MODE_PARALLEL)
2244      FlashMsg[FlashMsgCnt].Flags |=
2245        XQSPIPSU_MSG_FLAG_STRIPE;
2246
2247    TransferInProgress = TRUE;
2248    Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
2249                FlashMsgCnt + 1);
2250    if (Status != XST_SUCCESS)
2251      return XST_FAILURE;
2252
2253    while (TransferInProgress);
2254
2255    ReadBuffer += data_len;
2256    Address += data_len;
2257    remain_len -= data_len;
2258  }
2259  return 0;
2260}
2261
2262u32 QspiPsu_NOR_Get_Sector_Size(XQspiPsu *QspiPsuPtr)
2263{
2264  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2265    return Flash_Config_Table[FCTIndex].SectSize * 2;
2266  }
2267  return Flash_Config_Table[FCTIndex].SectSize;
2268}
2269
2270u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr)
2271{
2272  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
2273    return Flash_Config_Table[FCTIndex].FlashDeviceSize * 2;
2274  }
2275  return Flash_Config_Table[FCTIndex].FlashDeviceSize;
2276}
Note: See TracBrowser for help on using the repository browser.