]> git.sur5r.net Git - freertos/blob
5c0346cc168981dd9c1e305ed557b0657ae68988
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2015 Xilinx, Inc. All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xnandpsu.c
36 *
37 * This file contains the implementation of the interface functions for
38 * XNandPsu driver. Refer to the header file xnandpsu.h for more detailed
39 * information.
40 *
41 * This module supports for NAND flash memory devices that conform to the
42 * "Open NAND Flash Interface" (ONFI) 3.0 Specification. This modules
43 * implements basic flash operations like read, write and erase.
44 *
45 * @note         Driver has been renamed to nandpsu after change in
46 *               naming convention.
47 *
48 * <pre>
49 * MODIFICATION HISTORY:
50 *
51 * Ver   Who    Date        Changes
52 * ----- ----   ----------  -----------------------------------------------
53 * 1.0   nm     05/06/2014  First release
54 * 2.0   sb     01/12/2015  Removed Null checks for Buffer passed
55 *                          as parameter to Read API's
56 *                          - XNandPsu_Read()
57 *                          - XNandPsu_ReadPage
58 *                          Modified
59 *                          - XNandPsu_SetFeature()
60 *                          - XNandPsu_GetFeature()
61 *                          and made them public.
62 *                          Removed Failure Return for BCF Error check in
63 *                          XNandPsu_ReadPage() and added BCH_Error counter
64 *                          in the instance pointer structure.
65 *                          Added XNandPsu_Prepare_Cmd API
66 *                          Replaced
67 *                          - XNandPsu_IntrStsEnable
68 *                          - XNandPsu_IntrStsClear
69 *                          - XNandPsu_IntrClear
70 *                          - XNandPsu_SetProgramReg
71 *                          with XNandPsu_WriteReg call
72 *                          Modified xnandpsu.c file API's with above changes.
73 *                          Corrected the program command for Set Feature API.
74 *                          Modified
75 *                          - XNandPsu_OnfiReadStatus
76 *                          - XNandPsu_GetFeature
77 *                          - XNandPsu_SetFeature
78 *                          to add support for DDR mode.
79 *                          Changed Convention for SLC/MLC
80 *                          SLC --> HAMMING
81 *                          MLC --> BCH
82 *                          SlcMlc --> IsBCH
83 *                          Removed extra DMA mode initialization from
84 *                          the XNandPsu_CfgInitialize API.
85 *                          Modified
86 *                          - XNandPsu_SetEccAddrSize
87 *                          ECC address now is calculated based upon the
88 *                          size of spare area
89 *                          Modified Block Erase API, removed clearing of
90 *                          packet register before erase.
91 *                          Clearing Data Interface Register before
92 *                          XNandPsu_OnfiReset call.
93 *                          Modified XNandPsu_ChangeTimingMode API supporting
94 *                          SDR and NVDDR interface for timing modes 0 to 5.
95 *                          Modified Bbt Signature and Version Offset value for
96 *                          Oob and No-Oob region.
97 * </pre>
98 *
99 ******************************************************************************/
100
101 /***************************** Include Files *********************************/
102 #include "xnandpsu.h"
103 #include "xnandpsu_bbm.h"
104 /************************** Constant Definitions *****************************/
105
106 const XNandPsu_EccMatrix EccMatrix[] = {
107         /*
108          * 512 byte page
109          */
110         {XNANDPSU_PAGE_SIZE_512, 9U, 1U, XNANDPSU_HAMMING, 0x20DU, 0x3U},
111         {XNANDPSU_PAGE_SIZE_512, 9U, 4U, XNANDPSU_BCH, 0x209U, 0x7U},
112         {XNANDPSU_PAGE_SIZE_512, 9U, 8U, XNANDPSU_BCH, 0x203U, 0xDU},
113         /*
114          * 2K byte page
115          */
116         {XNANDPSU_PAGE_SIZE_2K, 9U, 1U, XNANDPSU_HAMMING, 0x834U, 0xCU},
117         {XNANDPSU_PAGE_SIZE_2K, 9U, 4U, XNANDPSU_BCH, 0x826U, 0x1AU},
118         {XNANDPSU_PAGE_SIZE_2K, 9U, 8U, XNANDPSU_BCH, 0x80cU, 0x34U},
119         {XNANDPSU_PAGE_SIZE_2K, 9U, 12U, XNANDPSU_BCH, 0x822U, 0x4EU},
120         {XNANDPSU_PAGE_SIZE_2K, 10U, 24U, XNANDPSU_BCH, 0x81cU, 0x54U},
121         /*
122          * 4K byte page
123          */
124         {XNANDPSU_PAGE_SIZE_4K, 9U, 1U, XNANDPSU_HAMMING, 0x1068U, 0x18U},
125         {XNANDPSU_PAGE_SIZE_4K, 9U, 4U, XNANDPSU_BCH, 0x104cU, 0x34U},
126         {XNANDPSU_PAGE_SIZE_4K, 9U, 8U, XNANDPSU_BCH, 0x1018U, 0x68U},
127         {XNANDPSU_PAGE_SIZE_4K, 9U, 12U, XNANDPSU_BCH, 0x1044U, 0x9CU},
128         {XNANDPSU_PAGE_SIZE_4K, 10U, 24U, XNANDPSU_BCH, 0x1038U, 0xA8U},
129         /*
130          * 8K byte page
131          */
132         {XNANDPSU_PAGE_SIZE_8K, 9U, 1U, XNANDPSU_HAMMING, 0x20d0U, 0x30U},
133         {XNANDPSU_PAGE_SIZE_8K, 9U, 4U, XNANDPSU_BCH, 0x2098U, 0x68U},
134         {XNANDPSU_PAGE_SIZE_8K, 9U, 8U, XNANDPSU_BCH, 0x2030U, 0xD0U},
135         {XNANDPSU_PAGE_SIZE_8K, 9U, 12U, XNANDPSU_BCH, 0x2088U, 0x138U},
136         {XNANDPSU_PAGE_SIZE_8K, 10U, 24U, XNANDPSU_BCH, 0x2070U, 0x150U},
137         /*
138          * 16K byte page
139          */
140         {XNANDPSU_PAGE_SIZE_16K, 9U, 1U, XNANDPSU_HAMMING, 0x4460U, 0x60U},
141         {XNANDPSU_PAGE_SIZE_16K, 9U, 4U, XNANDPSU_BCH, 0x43f0U, 0xD0U},
142         {XNANDPSU_PAGE_SIZE_16K, 9U, 8U, XNANDPSU_BCH, 0x4320U, 0x1A0U},
143         {XNANDPSU_PAGE_SIZE_16K, 9U, 12U, XNANDPSU_BCH, 0x4250U, 0x270U},
144         {XNANDPSU_PAGE_SIZE_16K, 10U, 24U, XNANDPSU_BCH, 0x4220U, 0x2A0U}
145 };
146
147 /**************************** Type Definitions *******************************/
148 static u8 isQemuPlatform = 0U;
149 /***************** Macros (Inline Functions) Definitions *********************/
150
151 /************************** Function Prototypes ******************************/
152
153 static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr);
154
155 static void XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param);
156
157 static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param);
158
159 static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
160                                         u32 Mask, u32 Timeout);
161
162 static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
163                                                 u32 PktCount);
164
165 static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col);
166
167 static void XNandPsu_SetPageSize(XNandPsu *InstancePtr);
168
169 static void XNandPsu_SetBusWidth(XNandPsu *InstancePtr);
170
171 static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target);
172
173 static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target);
174
175 static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
176                                                         u16 *OnfiStatus);
177
178 static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
179                                                         u32 IdLen, u8 *Buf);
180
181 static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
182                                                 u8 *Buf);
183
184 static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
185                                                         u32 Col, u8 *Buf);
186
187 static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
188                                                         u32 Col, u8 *Buf);
189
190 static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr, OnfiParamPage *Param);
191
192 static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr);
193
194 static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
195                                         u32 Col, u32 PktSize, u32 PktCount,
196                                         u8 *Buf);
197
198 static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
199                                         u32 Col, u32 PktSize, u32 PktCount,
200                                         u8 *Buf);
201
202 static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm);
203
204 /*****************************************************************************/
205 /**
206 *
207 * This function initializes a specific XNandPsu instance. This function must
208 * be called prior to using the NAND flash device to read or write any data.
209 *
210 * @param        InstancePtr is a pointer to the XNandPsu instance.
211 * @param        ConfigPtr points to XNandPsu device configuration structure.
212 * @param        EffectiveAddr is the base address of NAND flash controller.
213 *
214 * @return
215 *               - XST_SUCCESS if successful.
216 *               - XST_FAILURE if fail.
217 *
218 * @note         The user needs to first call the XNandPsu_LookupConfig() API
219 *               which returns the Configuration structure pointer which is
220 *               passed as a parameter to the XNandPsu_CfgInitialize() API.
221 *
222 ******************************************************************************/
223 s32 XNandPsu_CfgInitialize(XNandPsu *InstancePtr, XNandPsu_Config *ConfigPtr,
224                                 u32 EffectiveAddr)
225 {
226         s32 Status = XST_FAILURE;
227
228         /*
229          * Assert the input arguments.
230          */
231         Xil_AssertNonvoid(InstancePtr != NULL);
232         Xil_AssertNonvoid(ConfigPtr != NULL);
233
234         /*
235          * Initialize InstancePtr Config structure
236          */
237         InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
238         InstancePtr->Config.BaseAddress = EffectiveAddr;
239         /*
240          * Operate in Polling Mode
241          */
242         InstancePtr->Mode = XNANDPSU_POLLING;
243         /*
244          * Enable MDMA mode by default
245          */
246         InstancePtr->DmaMode = XNANDPSU_MDMA;
247         InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
248
249         /*
250          * Temporary hack for disabling the ecc on qemu as currently there
251          * is no support in the utility for writing images with ecc enabled.
252          */
253         #define CSU_VER_REG 0xFFCA0044U
254         #define CSU_VER_PLATFORM_MASK 0xF000U
255         #define CSU_VER_PLATFORM_QEMU_VAL 0x3000U
256         if ((*(u32 *)CSU_VER_REG & CSU_VER_PLATFORM_MASK) ==
257                                         CSU_VER_PLATFORM_QEMU_VAL) {
258                 isQemuPlatform = 1U;
259         }
260         /*
261          * Initialize the NAND flash targets
262          */
263         Status = XNandPsu_FlashInit(InstancePtr);
264         if (Status != XST_SUCCESS) {
265 #ifdef XNANDPSU_DEBUG
266                 xil_printf("%s: Flash init failed\r\n",__func__);
267 #endif
268                 goto Out;
269         }
270         /*
271          * Set ECC mode
272          */
273         if (InstancePtr->Features.EzNand != 0U) {
274                 InstancePtr->EccMode = XNANDPSU_EZNAND;
275         } else if (InstancePtr->Features.OnDie != 0U) {
276                 InstancePtr->EccMode = XNANDPSU_ONDIE;
277         } else {
278                 InstancePtr->EccMode = XNANDPSU_HWECC;
279         }
280
281         if (isQemuPlatform != 0U) {
282                 InstancePtr->EccMode = XNANDPSU_NONE;
283                 goto Out;
284         }
285
286         /*
287          * Initialize Ecc Error flip counters
288          */
289          InstancePtr->Ecc_Stat_PerPage_flips = 0U;
290          InstancePtr->Ecc_Stats_total_flips = 0U;
291
292         /*
293          * Scan for the bad block table(bbt) stored in the flash & load it in
294          * memory(RAM).  If bbt is not found, create bbt by scanning factory
295          * marked bad blocks and store it in last good blocks of flash.
296          */
297         XNandPsu_InitBbtDesc(InstancePtr);
298         Status = XNandPsu_ScanBbt(InstancePtr);
299         if (Status != XST_SUCCESS) {
300 #ifdef XNANDPSU_DEBUG
301                 xil_printf("%s: BBT scan failed\r\n",__func__);
302 #endif
303                 goto Out;
304         }
305
306 Out:
307         return Status;
308 }
309
310 /*****************************************************************************/
311 /**
312 *
313 * This function initializes the NAND flash and gets the geometry information.
314 *
315 * @param        InstancePtr is a pointer to the XNandPsu instance.
316 *
317 * @return
318 *               - XST_SUCCESS if successful.
319 *               - XST_FAILURE if failed.
320 *
321 * @note         None
322 *
323 ******************************************************************************/
324 static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr)
325 {
326         u32 Target;
327         u8 Id[ONFI_SIG_LEN] = {0U};
328         OnfiParamPage Param = {0U};
329         s32 Status = XST_FAILURE;
330         u32 Index;
331         u32 Crc;
332         u32 PrmPgOff;
333         u32 PrmPgLen;
334         OnfiExtPrmPage ExtParam __attribute__ ((aligned(64)));
335
336         /*
337          * Assert the input arguments.
338          */
339         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
340
341         /*
342          * Clear Data Interface Register
343          */
344         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
345                         XNANDPSU_DATA_INTF_OFFSET, 0U);
346
347         /* Clear DMA Buffer Boundary Register */
348         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
349                         XNANDPSU_DMA_BUF_BND_OFFSET, 0U);
350
351         for (Target = 0U; Target < XNANDPSU_MAX_TARGETS; Target++) {
352                 /*
353                  * Reset the Target
354                  */
355                 Status = XNandPsu_OnfiReset(InstancePtr, Target);
356                 if (Status != XST_SUCCESS) {
357                         goto Out;
358                 }
359                 /*
360                  * Read ONFI ID
361                  */
362                 Status = XNandPsu_OnfiReadId(InstancePtr, Target,
363                                                 ONFI_READ_ID_ADDR,
364                                                 ONFI_SIG_LEN,
365                                                 (u8 *)&Id[0]);
366                 if (Status != XST_SUCCESS) {
367                         goto Out;
368                 }
369
370                 if (!IS_ONFI(Id)) {
371                         if (Target == 0U) {
372 #ifdef XNANDPSU_DEBUG
373                                 xil_printf("%s: ONFI ID doesn't match\r\n",
374                                                                 __func__);
375 #endif
376                                 Status = XST_FAILURE;
377                                 goto Out;
378                         }
379                 }
380
381                 /* Read Parameter Page */
382                 for(Index = 0U; Index < ONFI_MND_PRM_PGS; Index++) {
383                         if (Index == 0U) {
384                                 Status = XNandPsu_OnfiReadParamPage(InstancePtr,
385                                                         Target, (u8 *)&Param);
386                         } else {
387                                 PrmPgOff = Index * ONFI_PRM_PG_LEN;
388                                 PrmPgLen = ONFI_PRM_PG_LEN;
389                                 Status = XNandPsu_ChangeReadColumn(InstancePtr,
390                                                         Target,PrmPgOff,
391                                                         ONFI_PRM_PG_LEN, 1U,
392                                                         (u8 *) &Param);
393                         }
394                         if (Status != XST_SUCCESS) {
395                                 goto Out;
396                         }
397                         /* Check CRC */
398                         Crc = XNandPsu_OnfiParamPageCrc((u8*)&Param, 0U,
399                                                                 ONFI_CRC_LEN);
400                         if (Crc != Param.Crc) {
401 #ifdef XNANDPSU_DEBUG
402                                 xil_printf("%s: ONFI parameter page (%d) crc check failed\r\n",
403                                                         __func__, Index);
404 #endif
405                                 continue;
406                         } else {
407                                 break;
408                         }
409                 }
410                 if (Index >= ONFI_MND_PRM_PGS) {
411                         Status = XST_FAILURE;
412                         goto Out;
413                 }
414                 /* Fill Geometry for the first target */
415                 if (Target == 0U) {
416                         XNandPsu_InitGeometry(InstancePtr, &Param);
417                         XNandPsu_InitFeatures(InstancePtr, &Param);
418                         if ((!InstancePtr->Features.EzNand) != 0U) {
419                                 Status =XNandPsu_CheckOnDie(InstancePtr,&Param);
420                                 if (Status != XST_SUCCESS) {
421                                         InstancePtr->Features.OnDie = 0U;
422                                 }
423                         }
424                         if (isQemuPlatform != 0U) {
425                                 InstancePtr->Geometry.NumTargets++;
426                                 break;
427                         }
428                         if ((InstancePtr->Geometry.NumBitsECC == 0xFFU) &&
429                                 (InstancePtr->Features.ExtPrmPage != 0U)) {
430                                 /* ONFI 3.1 section 5.7.1.6 & 5.7.1.7 */
431                                 PrmPgLen = (u32)Param.ExtParamPageLen * 16U;
432                                         PrmPgOff = (u32)((u32)Param.NumOfParamPages *
433                                                         ONFI_PRM_PG_LEN) +
434                                                         (Index * (u32)PrmPgLen);
435                                         Status = XNandPsu_ChangeReadColumn(
436                                                         InstancePtr,
437                                                         Target,
438                                                         PrmPgOff,
439                                                         PrmPgLen, 1U,
440                                                         (u8 *)(void *)&ExtParam);
441                                         if (Status != XST_SUCCESS) {
442                                                 goto Out;
443                                         }
444                                         /*
445                                          * Check CRC
446                                          */
447                                         Crc = XNandPsu_OnfiParamPageCrc(
448                                                         (u8 *)&ExtParam,
449                                                         2U,
450                                                         PrmPgLen);
451                                         if (Crc != ExtParam.Crc) {
452 #ifdef XNANDPSU_DEBUG
453         xil_printf("%s: ONFI extended parameter page (%d) crc check failed\r\n",
454                                                         __func__, Index);
455 #endif
456                                                 Status = XST_FAILURE;
457                                                 goto Out;
458                                         }
459                                         /*
460                                          * Initialize Extended ECC info
461                                          */
462                                         Status = XNandPsu_InitExtEcc(
463                                                         InstancePtr,
464                                                         &ExtParam);
465                                         if (Status != XST_SUCCESS) {
466 #ifdef XNANDPSU_DEBUG
467         xil_printf("%s: Init extended ecc failed\r\n",__func__);
468 #endif
469                                                 goto Out;
470                                 }
471                         }
472                         /* Configure ECC settings */
473                         XNandPsu_SetEccAddrSize(InstancePtr);
474                 }
475                 InstancePtr->Geometry.NumTargets++;
476         }
477         /*
478          * Calculate total number of blocks and total size of flash
479          */
480         InstancePtr->Geometry.NumPages = InstancePtr->Geometry.NumTargets *
481                                         InstancePtr->Geometry.NumTargetPages;
482         InstancePtr->Geometry.NumBlocks = InstancePtr->Geometry.NumTargets *
483                                         InstancePtr->Geometry.NumTargetBlocks;
484         InstancePtr->Geometry.DeviceSize =
485                                         (u64)InstancePtr->Geometry.NumTargets *
486                                         InstancePtr->Geometry.TargetSize;
487
488         Status = XST_SUCCESS;
489 Out:
490         return Status;
491 }
492
493 /*****************************************************************************/
494 /**
495 *
496 * This function initializes the geometry information from ONFI parameter page.
497 *
498 * @param        InstancePtr is a pointer to the XNandPsu instance.
499 * @param        Param is pointer to the ONFI parameter page.
500 *
501 * @return
502 *               None
503 *
504 * @note         None
505 *
506 ******************************************************************************/
507 static void XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param)
508 {
509         /*
510          * Assert the input arguments.
511          */
512         Xil_AssertVoid(Param != NULL);
513
514         InstancePtr->Geometry.BytesPerPage = Param->BytesPerPage;
515         InstancePtr->Geometry.SpareBytesPerPage = Param->SpareBytesPerPage;
516         InstancePtr->Geometry.PagesPerBlock = Param->PagesPerBlock;
517         InstancePtr->Geometry.BlocksPerLun = Param->BlocksPerLun;
518         InstancePtr->Geometry.NumLuns = Param->NumLuns;
519         InstancePtr->Geometry.RowAddrCycles = Param->AddrCycles & 0xFU;
520         InstancePtr->Geometry.ColAddrCycles = (Param->AddrCycles >> 4U) & 0xFU;
521         InstancePtr->Geometry.NumBitsPerCell = Param->BitsPerCell;
522         InstancePtr->Geometry.NumBitsECC = Param->EccBits;
523         InstancePtr->Geometry.BlockSize = (Param->PagesPerBlock *
524                                                 Param->BytesPerPage);
525         InstancePtr->Geometry.NumTargetBlocks = (Param->BlocksPerLun *
526                                                 (u32)Param->NumLuns);
527         InstancePtr->Geometry.NumTargetPages = (Param->BlocksPerLun *
528                                                 (u32)Param->NumLuns *
529                                                 Param->PagesPerBlock);
530         InstancePtr->Geometry.TargetSize = ((u64)Param->BlocksPerLun *
531                                                 (u64)Param->NumLuns *
532                                                 (u64)Param->PagesPerBlock *
533                                                 (u64)Param->BytesPerPage);
534         InstancePtr->Geometry.EccCodeWordSize = 9U; /* 2 power of 9 = 512 */
535
536 #ifdef XNANDPSU_DEBUG
537         xil_printf("Manufacturer: %s\r\n", Param->DeviceManufacturer);
538         xil_printf("Device Model: %s\r\n", Param->DeviceModel);
539         xil_printf("Jedec ID: 0x%x\r\n", Param->JedecManufacturerId);
540         xil_printf("Bytes Per Page: 0x%x\r\n", Param->BytesPerPage);
541         xil_printf("Spare Bytes Per Page: 0x%x\r\n", Param->SpareBytesPerPage);
542         xil_printf("Pages Per Block: 0x%x\r\n", Param->PagesPerBlock);
543         xil_printf("Blocks Per LUN: 0x%x\r\n", Param->BlocksPerLun);
544         xil_printf("Number of LUNs: 0x%x\r\n", Param->NumLuns);
545         xil_printf("Number of bits per cell: 0x%x\r\n", Param->BitsPerCell);
546         xil_printf("Number of ECC bits: 0x%x\r\n", Param->EccBits);
547         xil_printf("Block Size: 0x%x\r\n", InstancePtr->Geometry.BlockSize);
548
549         xil_printf("Number of Target Blocks: 0x%x\r\n",
550                                         InstancePtr->Geometry.NumTargetBlocks);
551         xil_printf("Number of Target Pages: 0x%x\r\n",
552                                         InstancePtr->Geometry.NumTargetPages);
553
554 #endif
555 }
556
557 /*****************************************************************************/
558 /**
559 *
560 * This function initializes the feature list from ONFI parameter page.
561 *
562 * @param        InstancePtr is a pointer to the XNandPsu instance.
563 * @param        Param is pointer to ONFI parameter page buffer.
564 *
565 * @return
566 *               None
567 *
568 * @note         None
569 *
570 ******************************************************************************/
571 static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param)
572 {
573         /*
574          * Assert the input arguments.
575          */
576         Xil_AssertVoid(Param != NULL);
577
578         InstancePtr->Features.BusWidth = ((Param->Features & (1U << 0U)) != 0U) ?
579                                                 XNANDPSU_BUS_WIDTH_16 :
580                                                 XNANDPSU_BUS_WIDTH_8;
581         InstancePtr->Features.NvDdr = ((Param->Features & (1U << 5)) != 0U) ?
582                                                                 1U : 0U;
583         InstancePtr->Features.EzNand = ((Param->Features & (1U << 9)) != 0U) ?
584                                                                 1U : 0U;
585         InstancePtr->Features.ExtPrmPage = ((Param->Features & (1U << 7)) != 0U) ?
586                                                                 1U : 0U;
587 }
588
589 /*****************************************************************************/
590 /**
591 *
592 * This function checks if the flash supports on-die ECC.
593 *
594 * @param        InstancePtr is a pointer to the XNandPsu instance.
595 * @param        Param is pointer to ONFI parameter page.
596 *
597 * @return
598 *               None
599 *
600 * @note         None
601 *
602 ******************************************************************************/
603 static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr, OnfiParamPage *Param)
604 {
605         s32 Status = XST_FAILURE;
606         u8 JedecId[2] = {0U};
607         u8 EccSetFeature[4] = {0x08U, 0x00U, 0x00U, 0x00U};
608         u8 EccGetFeature[4] ={0U};
609
610         /*
611          * Assert the input arguments.
612          */
613         Xil_AssertNonvoid(Param != NULL);
614
615         /*
616          * Check if this flash supports On-Die ECC.
617          * For more information, refer to Micron TN2945.
618          * Micron Flash: MT29F1G08ABADA, MT29F1G08ABBDA
619          *               MT29F1G16ABBDA,
620          *               MT29F2G08ABBEA, MT29F2G16ABBEA,
621          *               MT29F2G08ABAEA, MT29F2G16ABAEA,
622          *               MT29F4G08ABBDA, MT29F4G16ABBDA,
623          *               MT29F4G08ABADA, MT29F4G16ABADA,
624          *               MT29F8G08ADBDA, MT29F8G16ADBDA,
625          *               MT29F8G08ADADA, MT29F8G16ADADA
626          */
627
628         /*
629          * Read JEDEC ID
630          */
631         Status = XNandPsu_OnfiReadId(InstancePtr, 0U, 0x00U, 2U, &JedecId[0]);
632         if (Status != XST_SUCCESS) {
633                 goto Out;
634         }
635
636         if ((JedecId[0] == 0x2CU) &&
637         /*
638          * 1 Gb flash devices
639          */
640         ((JedecId[1] == 0xF1U) ||
641         (JedecId[1] == 0xA1U) ||
642         (JedecId[1] == 0xB1U) ||
643         /*
644          * 2 Gb flash devices
645          */
646         (JedecId[1] == 0xAAU) ||
647         (JedecId[1] == 0xBAU) ||
648         (JedecId[1] == 0xDAU) ||
649         (JedecId[1] == 0xCAU) ||
650         /*
651          * 4 Gb flash devices
652          */
653         (JedecId[1] == 0xACU) ||
654         (JedecId[1] == 0xBCU) ||
655         (JedecId[1] == 0xDCU) ||
656         (JedecId[1] == 0xCCU) ||
657         /*
658          * 8 Gb flash devices
659          */
660         (JedecId[1] == 0xA3U) ||
661         (JedecId[1] == 0xB3U) ||
662         (JedecId[1] == 0xD3U) ||
663         (JedecId[1] == 0xC3U))) {
664 #ifdef XNANDPSU_DEBUG
665                 xil_printf("%s: Ondie flash detected, jedec id 0x%x 0x%x\r\n",
666                                         __func__, JedecId[0], JedecId[1]);
667 #endif
668                 /*
669                  * On-Die Set Feature
670                  */
671                 Status = XNandPsu_SetFeature(InstancePtr, 0U, 0x90U,
672                                                 &EccSetFeature[0]);
673                 if (Status != XST_SUCCESS) {
674 #ifdef XNANDPSU_DEBUG
675                         xil_printf("%s: Ondie set_feature failed\r\n",
676                                                                 __func__);
677 #endif
678                         goto Out;
679                 }
680                 /*
681                  * Check to see if ECC feature is set
682                  */
683                 Status = XNandPsu_GetFeature(InstancePtr, 0U, 0x90U,
684                                                 &EccGetFeature[0]);
685                 if (Status != XST_SUCCESS) {
686 #ifdef XNANDPSU_DEBUG
687                         xil_printf("%s: Ondie get_feature failed\r\n",
688                                                                 __func__);
689 #endif
690                         goto Out;
691                 }
692                 if ((EccGetFeature[0] & 0x08U) != 0U) {
693                         InstancePtr->Features.OnDie = 1U;
694                         Status = XST_SUCCESS;
695                 }
696         } else {
697                 /*
698                  * On-Die flash not found
699                  */
700                 Status = XST_FAILURE;
701         }
702 Out:
703         return Status;
704 }
705
706 /*****************************************************************************/
707 /**
708 *
709 * This function enables DMA mode of controller operation.
710 *
711 * @param        InstancePtr is a pointer to the XNandPsu instance.
712 *
713 * @return
714 *               None
715 *
716 * @note         None
717 *
718 ******************************************************************************/
719 void XNandPsu_EnableDmaMode(XNandPsu *InstancePtr)
720 {
721         /*
722          * Assert the input arguments.
723          */
724         Xil_AssertVoid(InstancePtr != NULL);
725         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
726
727         InstancePtr->DmaMode = XNANDPSU_MDMA;
728 }
729
730 /*****************************************************************************/
731 /**
732 *
733 * This function disables DMA mode of driver/controller operation.
734 *
735 * @param        InstancePtr is a pointer to the XNandPsu instance.
736 *
737 * @return
738 *               None
739 *
740 * @note         None
741 *
742 ******************************************************************************/
743 void XNandPsu_DisableDmaMode(XNandPsu *InstancePtr)
744 {
745         /*
746          * Assert the input arguments.
747          */
748         Xil_AssertVoid(InstancePtr != NULL);
749         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
750
751         InstancePtr->DmaMode = XNANDPSU_PIO;
752 }
753
754 /*****************************************************************************/
755 /**
756 *
757 * This function enables ECC mode of driver/controller operation.
758 *
759 * @param        InstancePtr is a pointer to the XNandPsu instance.
760 *
761 * @return
762 *               None
763 *
764 * @note         None
765 *
766 ******************************************************************************/
767 void XNandPsu_EnableEccMode(XNandPsu *InstancePtr)
768 {
769         /*
770          * Assert the input arguments.
771          */
772         Xil_AssertVoid(InstancePtr != NULL);
773         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
774
775         InstancePtr->EccMode = XNANDPSU_HWECC;
776 }
777
778 /*****************************************************************************/
779 /**
780 *
781 * This function disables ECC mode of driver/controller operation.
782 *
783 * @param        InstancePtr is a pointer to the XNandPsu instance.
784 *
785 * @return
786 *               None
787 *
788 * @note         None
789 *
790 ******************************************************************************/
791 void XNandPsu_DisableEccMode(XNandPsu *InstancePtr)
792 {
793         /*
794          * Assert the input arguments.
795          */
796         Xil_AssertVoid(InstancePtr != NULL);
797         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
798
799         InstancePtr->EccMode = XNANDPSU_NONE;
800 }
801
802 /*****************************************************************************/
803 /**
804 *
805 * This function enables storing bbt version in oob area.
806 *
807 * @param        InstancePtr is a pointer to the XNandPsu instance.
808 *
809 * @return
810 *                       None
811 *
812 * @note         None
813 *
814 ******************************************************************************/
815 void XNandPsu_EnableBbtOobMode(XNandPsu *InstancePtr)
816 {
817         /*
818          * Assert the input arguments.
819          */
820         Xil_AssertVoid(InstancePtr != NULL);
821         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
822         InstancePtr->BbtDesc.Option = XNANDPSU_BBT_OOB;
823         InstancePtr->BbtMirrorDesc.Option = XNANDPSU_BBT_OOB;
824         /*
825          * Setting the Signature and Version Offset
826          */
827         InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET;
828         InstancePtr->BbtMirrorDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET;
829         InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET;
830         InstancePtr->BbtMirrorDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET;
831 }
832
833 /*****************************************************************************/
834 /**
835 *
836 * This function enables storing bbt version in no oob area i.e. page memory.
837 *
838 * @param        InstancePtr is a pointer to the XNandPsu instance.
839 *
840 * @return
841 *                       None
842 *
843 * @note         None
844 *
845 ******************************************************************************/
846 void XNandPsu_DisableBbtOobMode(XNandPsu *InstancePtr)
847 {
848         /*
849          * Assert the input arguments.
850          */
851         Xil_AssertVoid(InstancePtr != NULL);
852         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
853         InstancePtr->BbtDesc.Option = XNANDPSU_BBT_NO_OOB;
854         InstancePtr->BbtMirrorDesc.Option = XNANDPSU_BBT_NO_OOB;
855         /*
856          * Setting the Signature and Version Offset
857          */
858         InstancePtr->BbtDesc.SigOffset = XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
859         InstancePtr->BbtMirrorDesc.SigOffset =
860                                         XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
861         InstancePtr->BbtDesc.VerOffset = XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
862         InstancePtr->BbtMirrorDesc.VerOffset =
863                                         XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
864 }
865
866 /*****************************************************************************/
867 /**
868 *
869 * This function polls for a register bit set status till the timeout.
870 *
871 * @param        InstancePtr is a pointer to the XNandPsu instance.
872 * @param        RegOffset is the offset of register.
873 * @param        Mask is the bitmask.
874 * @param        Timeout is the timeout value.
875 *
876 * @return
877 *               - XST_SUCCESS if successful.
878 *               - XST_FAILURE if failed.
879 *
880 * @note         None
881 *
882 ******************************************************************************/
883 static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset,
884                                         u32 Mask, u32 Timeout)
885 {
886         s32 Status = XST_FAILURE;
887         volatile u32 RegVal;
888         u32 TimeoutVar = Timeout;
889
890         while (TimeoutVar > 0U) {
891                 RegVal = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
892                                                 RegOffset);
893                 if ((RegVal & Mask) != 0U) {
894                         break;
895                 }
896                 TimeoutVar--;
897         }
898
899         if (TimeoutVar <= 0U) {
900                 Status = XST_FAILURE;
901         } else {
902                 Status = XST_SUCCESS;
903         }
904
905         return Status;
906 }
907
908 /*****************************************************************************/
909 /**
910 *
911 * This function sets packet size and packet count values in packet register.
912 *
913 * @param        InstancePtr is a pointer to the XNandPsu instance.
914 * @param        PktSize is the packet size.
915 * @param        PktCount is the packet count.
916 *
917 * @return
918 *               None
919 *
920 * @note         None
921 *
922 ******************************************************************************/
923 static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize,
924                                                 u32 PktCount)
925 {
926         /*
927          * Assert the input arguments.
928          */
929         Xil_AssertVoid(PktSize <= XNANDPSU_MAX_PKT_SIZE);
930         Xil_AssertVoid(PktCount <= XNANDPSU_MAX_PKT_COUNT);
931
932         /*
933          * Update Packet Register with pkt size and count
934          */
935         XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_PKT_OFFSET,
936                                 ((u32)XNANDPSU_PKT_PKT_SIZE_MASK |
937                                 (u32)XNANDPSU_PKT_PKT_CNT_MASK),
938                                 ((PktSize & XNANDPSU_PKT_PKT_SIZE_MASK) |
939                                 ((PktCount << XNANDPSU_PKT_PKT_CNT_SHIFT) &
940                                 XNANDPSU_PKT_PKT_CNT_MASK)));
941 }
942
943 /*****************************************************************************/
944 /**
945 *
946 * This function sets Page and Column values in the Memory address registers.
947 *
948 * @param        InstancePtr is a pointer to the XNandPsu instance.
949 * @param        Page is the page value.
950 * @param        Col is the column value.
951 *
952 * @return
953 *               None
954 *
955 * @note         None
956 *
957 ******************************************************************************/
958 static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col)
959 {
960         /*
961          * Program Memory Address Register 1
962          */
963         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
964                                 XNANDPSU_MEM_ADDR1_OFFSET,
965                                 ((Col & XNANDPSU_MEM_ADDR1_COL_ADDR_MASK) |
966                                 ((Page << (u32)XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
967                                 XNANDPSU_MEM_ADDR1_PG_ADDR_MASK)));
968         /*
969          * Program Memory Address Register 2
970          */
971         XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
972                                 XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK,
973                                 ((Page >> XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) &
974                                 XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK));
975 }
976
977 /*****************************************************************************/
978 /**
979 *
980 * This function sets the size of page in Command Register.
981 *
982 * @param        InstancePtr is a pointer to the XNandPsu instance.
983 *
984 * @return
985 *               None
986 *
987 * @note         None
988 *
989 ******************************************************************************/
990 static void XNandPsu_SetPageSize(XNandPsu *InstancePtr)
991 {
992         u32 PageSizeMask = 0;
993         u32 PageSize = InstancePtr->Geometry.BytesPerPage;
994
995         /*
996          * Calculate page size mask
997          */
998         switch(PageSize) {
999                 case XNANDPSU_PAGE_SIZE_512:
1000                         PageSizeMask = (0U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1001                         break;
1002                 case XNANDPSU_PAGE_SIZE_2K:
1003                         PageSizeMask = (1U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1004                         break;
1005                 case XNANDPSU_PAGE_SIZE_4K:
1006                         PageSizeMask = (2U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1007                         break;
1008                 case XNANDPSU_PAGE_SIZE_8K:
1009                         PageSizeMask = (3U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1010                         break;
1011                 case XNANDPSU_PAGE_SIZE_16K:
1012                         PageSizeMask = (4U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1013                         break;
1014                 case XNANDPSU_PAGE_SIZE_1K_16BIT:
1015                         PageSizeMask = (5U << XNANDPSU_CMD_PG_SIZE_SHIFT);
1016                         break;
1017                 default:
1018                         /*
1019                          * Not supported
1020                          */
1021                         break;
1022         }
1023         /*
1024          * Update Command Register
1025          */
1026         XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_CMD_OFFSET,
1027                                 XNANDPSU_CMD_PG_SIZE_MASK, PageSizeMask);
1028 }
1029
1030 /*****************************************************************************/
1031 /**
1032 *
1033 * This function setup the Ecc Register.
1034 *
1035 * @param        InstancePtr is a pointer to the XNandPsu instance.
1036 *
1037 * @return
1038 *               None
1039 *
1040 * @note         None
1041 *
1042 ******************************************************************************/
1043 static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr)
1044 {
1045         u32 PageSize = InstancePtr->Geometry.BytesPerPage;
1046         u32 CodeWordSize = InstancePtr->Geometry.EccCodeWordSize;
1047         u32 NumEccBits = InstancePtr->Geometry.NumBitsECC;
1048         u32 Index;
1049         u32 Found = 0U;
1050         u8 BchModeVal = 0U;
1051
1052         for (Index = 0U; Index < (sizeof(EccMatrix)/sizeof(XNandPsu_EccMatrix));
1053                                                 Index++) {
1054                 if ((EccMatrix[Index].PageSize == PageSize) &&
1055                         (EccMatrix[Index].CodeWordSize >= CodeWordSize)) {
1056                         if (EccMatrix[Index].NumEccBits >= NumEccBits) {
1057                                 Found = Index;
1058                                 break;
1059                         }
1060                         else {
1061                                 Found = Index;
1062                         }
1063                 }
1064         }
1065
1066         if (Found != 0U) {
1067                 if(InstancePtr->Geometry.SpareBytesPerPage < 64U) {
1068                         InstancePtr->EccCfg.EccAddr = PageSize;
1069                 }
1070                 else {
1071                         InstancePtr->EccCfg.EccAddr = PageSize +
1072                                 (InstancePtr->Geometry.SpareBytesPerPage
1073                                                 - EccMatrix[Found].EccSize);
1074                 }
1075                 InstancePtr->EccCfg.EccSize = EccMatrix[Found].EccSize;
1076                 InstancePtr->EccCfg.NumEccBits = EccMatrix[Found].NumEccBits;
1077                 InstancePtr->EccCfg.CodeWordSize =
1078                                                 EccMatrix[Found].CodeWordSize;
1079 #ifdef XNANDPSU_DEBUG
1080                 xil_printf("ECC: addr 0x%x size 0x%x numbits %d "
1081                                    "codesz %d\r\n",
1082                                    InstancePtr->EccCfg.EccAddr,
1083                                    InstancePtr->EccCfg.EccSize,
1084                                    InstancePtr->EccCfg.NumEccBits,
1085                                    InstancePtr->EccCfg.CodeWordSize);
1086 #endif
1087                 if (EccMatrix[Found].IsBCH == XNANDPSU_HAMMING) {
1088                         InstancePtr->EccCfg.IsBCH = 0U;
1089                 } else {
1090                         InstancePtr->EccCfg.IsBCH = 1U;
1091                 }
1092                 /*
1093                  * Write ECC register
1094                  */
1095                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
1096                                 (u32)XNANDPSU_ECC_OFFSET,
1097                                 ((u32)InstancePtr->EccCfg.EccAddr |
1098                                 ((u32)InstancePtr->EccCfg.EccSize << (u32)16) |
1099                                 ((u32)InstancePtr->EccCfg.IsBCH << (u32)27)));
1100
1101                 if (EccMatrix[Found].IsBCH == XNANDPSU_BCH) {
1102                         /*
1103                          * Write memory address register 2
1104                          */
1105                         switch(InstancePtr->EccCfg.NumEccBits) {
1106                                 case 16U:
1107                                         BchModeVal = 0x0U;
1108                                         break;
1109                                 case 12U:
1110                                         BchModeVal = 0x1U;
1111                                         break;
1112                                 case 8U:
1113                                         BchModeVal = 0x2U;
1114                                         break;
1115                                 case 4U:
1116                                         BchModeVal = 0x3U;
1117                                         break;
1118                                 case 24U:
1119                                         BchModeVal = 0x4U;
1120                                         break;
1121                                 default:
1122                                         BchModeVal = 0x0U;
1123                         }
1124                         XNandPsu_ReadModifyWrite(InstancePtr,
1125                                 XNANDPSU_MEM_ADDR2_OFFSET,
1126                                 XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_MASK,
1127                                 (BchModeVal <<
1128                                 (u32)XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_SHIFT));
1129                 }
1130         }
1131 }
1132
1133 /*****************************************************************************/
1134 /**
1135 *
1136 * This function setup the Ecc Spare Command Register.
1137 *
1138 * @param        InstancePtr is a pointer to the XNandPsu instance.
1139 *
1140 * @return
1141 *               None
1142 *
1143 * @note         None
1144 *
1145 ******************************************************************************/
1146 static void XNandPsu_SetEccSpareCmd(XNandPsu *InstancePtr, u16 SpareCmd,
1147                                                                 u8 AddrCycles)
1148 {
1149         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
1150                                 (u32)XNANDPSU_ECC_SPR_CMD_OFFSET,
1151                                 (u32)SpareCmd | ((u32)AddrCycles << 28U));
1152 }
1153
1154 /*****************************************************************************/
1155 /**
1156 *
1157 * This function sets the flash bus width in memory address2 register.
1158 *
1159 * @param        InstancePtr is a pointer to the XNandPsu instance.
1160 *
1161 * @return
1162 *               None
1163 *
1164 * @note         None
1165 *
1166 ******************************************************************************/
1167 static void XNandPsu_SetBusWidth(XNandPsu *InstancePtr)
1168 {
1169         /*
1170          * Update Memory Address2 register with bus width
1171          */
1172         XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
1173                                 XNANDPSU_MEM_ADDR2_BUS_WIDTH_MASK,
1174                                 (InstancePtr->Features.BusWidth <<
1175                                 XNANDPSU_MEM_ADDR2_BUS_WIDTH_SHIFT));
1176
1177 }
1178
1179 /*****************************************************************************/
1180 /**
1181 *
1182 * This function sets the chip select value in memory address2 register.
1183 *
1184 * @param        InstancePtr is a pointer to the XNandPsu instance.
1185 * @param        Target is the chip select value.
1186 *
1187 * @return
1188 *               None
1189 *
1190 * @note         None
1191 *
1192 ******************************************************************************/
1193 static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target)
1194 {
1195         /*
1196          * Update Memory Address2 register with chip select
1197          */
1198         XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET,
1199                         XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK,
1200                         ((Target << XNANDPSU_MEM_ADDR2_CHIP_SEL_SHIFT) &
1201                         XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK));
1202 }
1203
1204 /*****************************************************************************/
1205 /**
1206 *
1207 * This function sends ONFI Reset command to the flash.
1208 *
1209 * @param        InstancePtr is a pointer to the XNandPsu instance.
1210 * @param        Target is the chip select value.
1211 *
1212 * @return
1213 *               - XST_SUCCESS if successful.
1214 *               - XST_FAILURE if failed.
1215 *
1216 * @note         None
1217 *
1218 ******************************************************************************/
1219 static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target)
1220 {
1221         s32 Status = XST_FAILURE;
1222
1223         /*
1224          * Assert the input arguments.
1225          */
1226         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
1227
1228         /*
1229          * Enable Transfer Complete Interrupt in Interrupt Status Register
1230          */
1231         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1232                 XNANDPSU_INTR_STS_EN_OFFSET,
1233                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1234         /*
1235          * Program Command Register
1236          */
1237         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RST, ONFI_CMD_INVALID, 0U,
1238                         0U, 0U);
1239         /*
1240          * Program Memory Address Register2 for chip select
1241          */
1242         XNandPsu_SelectChip(InstancePtr, Target);
1243         /*
1244          * Set Reset in Program Register
1245          */
1246         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1247                 XNANDPSU_PROG_OFFSET, XNANDPSU_PROG_RST_MASK);
1248
1249         /*
1250          * Poll for Transfer Complete event
1251          */
1252         Status = XNandPsu_PollRegTimeout(
1253                         InstancePtr,
1254                         XNANDPSU_INTR_STS_OFFSET,
1255                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
1256                         XNANDPSU_INTR_POLL_TIMEOUT);
1257         if (Status != XST_SUCCESS) {
1258 #ifdef XNANDPSU_DEBUG
1259                 xil_printf("%s: Poll for xfer complete timeout\r\n",
1260                                                         __func__);
1261 #endif
1262                 goto Out;
1263         }
1264         /*
1265          * Clear Transfer Complete Interrupt in Interrupt Status Enable
1266          * Register
1267          */
1268         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1269                 (XNANDPSU_INTR_STS_EN_OFFSET), 0U);
1270         /*
1271          * Clear Transfer Complete Interrupt in Interrupt Status Register
1272          */
1273         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1274                         XNANDPSU_INTR_STS_OFFSET,
1275                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
1276
1277 Out:
1278         return Status;
1279 }
1280
1281 /*****************************************************************************/
1282 /**
1283 *
1284 * This function sends ONFI Read Status command to the flash.
1285 *
1286 * @param        InstancePtr is a pointer to the XNandPsu instance.
1287 * @param        Target is the chip select value.
1288 * @param        OnfiStatus is the ONFI status value to return.
1289 *
1290 * @return
1291 *               - XST_SUCCESS if successful.
1292 *               - XST_FAILURE if failed.
1293 *
1294 * @note         None
1295 *
1296 ******************************************************************************/
1297 static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target,
1298                                                         u16 *OnfiStatus)
1299 {
1300         s32 Status = XST_FAILURE;
1301
1302         /*
1303          * Assert the input arguments.
1304          */
1305         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
1306         Xil_AssertNonvoid(OnfiStatus != NULL);
1307         /*
1308          * Enable Transfer Complete Interrupt in Interrupt Status Register
1309          */
1310         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1311                 XNANDPSU_INTR_STS_EN_OFFSET,
1312                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1313         /*
1314          * Program Command Register
1315          */
1316         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_STS, ONFI_CMD_INVALID,
1317                                 0U, 0U, 0U);
1318         /*
1319          * Program Memory Address Register2 for chip select
1320          */
1321         XNandPsu_SelectChip(InstancePtr, Target);
1322         /*
1323          * Program Packet Size and Packet Count
1324          */
1325         if(InstancePtr->DataInterface == XNANDPSU_SDR){
1326                 XNandPsu_SetPktSzCnt(InstancePtr, 1U, 1U);
1327         }
1328         else{
1329                 XNandPsu_SetPktSzCnt(InstancePtr, 2U, 1U);
1330         }
1331
1332         /*
1333          * Set Read Status in Program Register
1334          */
1335         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1336                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_STS_MASK);
1337         /*
1338          * Poll for Transfer Complete event
1339          */
1340         Status = XNandPsu_PollRegTimeout(
1341                         InstancePtr,
1342                         XNANDPSU_INTR_STS_OFFSET,
1343                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
1344                         XNANDPSU_INTR_POLL_TIMEOUT);
1345         if (Status != XST_SUCCESS) {
1346 #ifdef XNANDPSU_DEBUG
1347                 xil_printf("%s: Poll for xfer complete timeout\r\n",
1348                                                         __func__);
1349 #endif
1350                 goto Out;
1351         }
1352         /*
1353          * Clear Transfer Complete Interrupt in Interrupt Status Enable
1354          * Register
1355          */
1356         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1357                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
1358         /*
1359          * Clear Transfer Complete Interrupt in Interrupt Status Register
1360          */
1361         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1362                         XNANDPSU_INTR_STS_OFFSET,
1363                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
1364         /*
1365          * Read Flash Status
1366          */
1367         *OnfiStatus = (u8) XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
1368                                                 XNANDPSU_FLASH_STS_OFFSET);
1369
1370 Out:
1371
1372         return Status;
1373 }
1374
1375 /*****************************************************************************/
1376 /**
1377 *
1378 * This function sends ONFI Read ID command to the flash.
1379 *
1380 * @param        InstancePtr is a pointer to the XNandPsu instance.
1381 * @param        Target is the chip select value.
1382 * @param        Buf is the ONFI ID value to return.
1383 *
1384 * @return
1385 *               - XST_SUCCESS if successful.
1386 *               - XST_FAILURE if failed.
1387 *
1388 * @note         None
1389 *
1390 ******************************************************************************/
1391 static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr,
1392                                                         u32 IdLen, u8 *Buf)
1393 {
1394         s32 Status = XST_FAILURE;
1395         u32 Index;
1396         u32 Rem;
1397         u32 *BufPtr = (u32 *)(void *)Buf;
1398         u32 RegVal;
1399         u32 RemIdx;
1400
1401         /*
1402          * Assert the input arguments.
1403          */
1404         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
1405         Xil_AssertNonvoid(Buf != NULL);
1406
1407         /*
1408          * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
1409          * Register
1410          */
1411         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1412                 XNANDPSU_INTR_STS_EN_OFFSET,
1413                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
1414         /*
1415          * Program Command
1416          */
1417         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_ID, ONFI_CMD_INVALID, 0U,
1418                                         0U, ONFI_READ_ID_ADDR_CYCLES);
1419
1420         /*
1421          * Program Column, Page, Block address
1422          */
1423         XNandPsu_SetPageColAddr(InstancePtr, 0U, IdAddr);
1424         /*
1425          * Program Memory Address Register2 for chip select
1426          */
1427         XNandPsu_SelectChip(InstancePtr, Target);
1428         /*
1429          * Program Packet Size and Packet Count
1430          */
1431         XNandPsu_SetPktSzCnt(InstancePtr, IdLen, 1U);
1432         /*
1433          * Set Read ID in Program Register
1434          */
1435         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1436                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_ID_MASK);
1437
1438         /*
1439          * Poll for Buffer Read Ready event
1440          */
1441         Status = XNandPsu_PollRegTimeout(
1442                 InstancePtr,
1443                 XNANDPSU_INTR_STS_OFFSET,
1444                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
1445                 XNANDPSU_INTR_POLL_TIMEOUT);
1446         if (Status != XST_SUCCESS) {
1447 #ifdef XNANDPSU_DEBUG
1448                 xil_printf("%s: Poll for buf read ready timeout\r\n",
1449                                                         __func__);
1450 #endif
1451                 goto Out;
1452         }
1453         /*
1454          * Enable Transfer Complete Interrupt in Interrupt
1455          * Status Enable Register
1456          */
1457
1458                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1459                 XNANDPSU_INTR_STS_EN_OFFSET,
1460                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1461
1462         /*
1463          * Clear Buffer Read Ready Interrupt in Interrupt Status
1464          * Register
1465          */
1466         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1467                         XNANDPSU_INTR_STS_OFFSET,
1468                         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
1469         /*
1470          * Read Packet Data from Data Port Register
1471          */
1472         for (Index = 0U; Index < (IdLen/4); Index++) {
1473                 BufPtr[Index] = XNandPsu_ReadReg(
1474                                         InstancePtr->Config.BaseAddress,
1475                                         XNANDPSU_BUF_DATA_PORT_OFFSET);
1476         }
1477         Rem = IdLen % 4;
1478         if (Rem != 0U) {
1479                 RegVal = XNandPsu_ReadReg(
1480                                         InstancePtr->Config.BaseAddress,
1481                                         XNANDPSU_BUF_DATA_PORT_OFFSET);
1482                 for (RemIdx = 0U; RemIdx < Rem; RemIdx++) {
1483                         Buf[(Index * 4U) + RemIdx] = (u8) (RegVal >>
1484                                                 (RemIdx * 8U)) & 0xFFU;
1485                 }
1486         }
1487
1488         /*
1489          * Poll for Transfer Complete event
1490          */
1491         Status = XNandPsu_PollRegTimeout(
1492                         InstancePtr,
1493                         XNANDPSU_INTR_STS_OFFSET,
1494                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
1495                         XNANDPSU_INTR_POLL_TIMEOUT);
1496         if (Status != XST_SUCCESS) {
1497 #ifdef XNANDPSU_DEBUG
1498                 xil_printf("%s: Poll for xfer complete timeout\r\n",
1499                                                         __func__);
1500 #endif
1501                 goto Out;
1502         }
1503         /*
1504          * Clear Transfer Complete Interrupt in Interrupt Status Enable
1505          * Register
1506          */
1507         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1508                 XNANDPSU_INTR_STS_EN_OFFSET,0U);
1509         /*
1510          * Clear Transfer Complete Interrupt in Interrupt Status Register
1511          */
1512         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1513                         XNANDPSU_INTR_STS_OFFSET,
1514                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
1515
1516 Out:
1517         return Status;
1518 }
1519
1520 /*****************************************************************************/
1521 /**
1522 *
1523 * This function sends the ONFI Read Parameter Page command to flash.
1524 *
1525 * @param        InstancePtr is a pointer to the XNandPsu instance.
1526 * @param        Target is the chip select value.
1527 * @param        PrmIndex is the index of parameter page.
1528 * @param        Buf is the parameter page information to return.
1529 *
1530 * @return
1531 *               - XST_SUCCESS if successful.
1532 *               - XST_FAILURE if failed.
1533 *
1534 * @note         None
1535 *
1536 ******************************************************************************/
1537 static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target,
1538                                                 u8 *Buf)
1539 {
1540         s32 Status = XST_FAILURE;
1541         u32 *BufPtr = (u32 *)(void *)Buf;
1542         u32 Index;
1543
1544         /*
1545          * Assert the input arguments.
1546          */
1547         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
1548         Xil_AssertNonvoid(Buf != NULL);
1549
1550         /*
1551          * Enable Buffer Read Ready Interrupt in Interrupt Status Enable
1552          * Register
1553          */
1554         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1555                 XNANDPSU_INTR_STS_EN_OFFSET,
1556                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
1557         /*
1558          * Program Command
1559          */
1560         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_PRM_PG, ONFI_CMD_INVALID,
1561                                         0U, 0U, ONFI_PRM_PG_ADDR_CYCLES);
1562         /*
1563          * Program Column, Page, Block address
1564          */
1565         XNandPsu_SetPageColAddr(InstancePtr, 0U, 0U);
1566         /*
1567          * Program Memory Address Register2 for chip select
1568          */
1569         XNandPsu_SelectChip(InstancePtr, Target);
1570         /*
1571          * Program Packet Size and Packet Count
1572          */
1573         XNandPsu_SetPktSzCnt(InstancePtr, ONFI_PRM_PG_LEN, 1U);
1574         /*
1575          * Set Read Parameter Page in Program Register
1576          */
1577         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1578                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_PRM_PG_MASK);
1579
1580         /*
1581          * Poll for Buffer Read Ready event
1582          */
1583          Status = XNandPsu_PollRegTimeout(
1584                         InstancePtr,
1585                         XNANDPSU_INTR_STS_OFFSET,
1586                         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
1587                         XNANDPSU_INTR_POLL_TIMEOUT);
1588          if (Status != XST_SUCCESS) {
1589 #ifdef XNANDPSU_DEBUG
1590                         xil_printf("%s: Poll for buf read ready timeout\r\n",
1591                                                         __func__);
1592 #endif
1593                         goto Out;
1594                 }
1595
1596
1597                         /*
1598                          * Enable Transfer Complete Interrupt in Interrupt
1599                          * Status Enable Register
1600                          */
1601                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1602                                 (XNANDPSU_INTR_STS_EN_OFFSET),
1603                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
1604                 /*
1605                  * Clear Buffer Read Ready Interrupt in Interrupt Status
1606                  * Register
1607                  */
1608                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1609                                 XNANDPSU_INTR_STS_OFFSET,
1610                                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
1611                 /*
1612                  * Read Packet Data from Data Port Register
1613                  */
1614                 for (Index = 0U; Index < (ONFI_PRM_PG_LEN/4); Index++) {
1615                         BufPtr[Index] = XNandPsu_ReadReg(
1616                                         InstancePtr->Config.BaseAddress,
1617                                                 XNANDPSU_BUF_DATA_PORT_OFFSET);
1618                 }
1619
1620         /*
1621          * Poll for Transfer Complete event
1622          */
1623         Status = XNandPsu_PollRegTimeout(
1624                         InstancePtr,
1625                         XNANDPSU_INTR_STS_OFFSET,
1626                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
1627                         XNANDPSU_INTR_POLL_TIMEOUT);
1628         if (Status != XST_SUCCESS) {
1629 #ifdef XNANDPSU_DEBUG
1630                 xil_printf("%s: Poll for xfer complete timeout\r\n",
1631                                                         __func__);
1632 #endif
1633                 goto Out;
1634         }
1635         /*
1636          * Clear Transfer Complete Interrupt in Interrupt Status Enable
1637          * Register
1638          */
1639         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1640                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
1641         /*
1642          * Clear Transfer Complete Interrupt in Interrupt Status Register
1643          */
1644         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
1645                         XNANDPSU_INTR_STS_OFFSET,
1646                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
1647
1648 Out:
1649         return Status;
1650 }
1651
1652 /*****************************************************************************/
1653 /**
1654 *
1655 * This function returns the length including bad blocks from a given offset and
1656 * length.
1657 *
1658 * @param        InstancePtr is the pointer to the XNandPsu instance.
1659 * @param        Offset is the flash data address to read from.
1660 * @param        Length is number of bytes to read.
1661 *
1662 * @return
1663 *               - Return actual length including bad blocks.
1664 *
1665 * @note         None.
1666 *
1667 ******************************************************************************/
1668 static s32 XNandPsu_CalculateLength(XNandPsu *InstancePtr, u64 Offset,
1669                                                         u64 Length)
1670 {
1671         s32 Status;
1672         u32 BlockSize;
1673         u32 BlockLen;
1674         u32 Block;
1675         u32 TempLen = 0;
1676         u64 OffsetVar = Offset;
1677
1678         BlockSize = InstancePtr->Geometry.BlockSize;
1679
1680         while (TempLen < Length) {
1681                 Block = (u32) ((u32)OffsetVar/BlockSize);
1682                 BlockLen = BlockSize - ((u32)OffsetVar % BlockSize);
1683                 /*
1684                  * Check if the block is bad
1685                  */
1686                 Status = XNandPsu_IsBlockBad(InstancePtr, Block);
1687                 if (Status != XST_SUCCESS) {
1688                         /*
1689                          * Good block
1690                          */
1691                         TempLen += BlockLen;
1692                 }
1693                 if (OffsetVar >= InstancePtr->Geometry.DeviceSize) {
1694                         Status = XST_FAILURE;
1695                         goto Out;
1696                 }
1697                 OffsetVar += BlockLen;
1698         }
1699
1700         Status = XST_SUCCESS;
1701 Out:
1702         return Status;
1703 }
1704
1705 /*****************************************************************************/
1706 /**
1707 *
1708 * This function writes to the flash.
1709 *
1710 * @param        InstancePtr is a pointer to the XNandPsu instance.
1711 * @param        Offset is the starting offset of flash to write.
1712 * @param        Length is the number of bytes to write.
1713 * @param        SrcBuf is the source data buffer to write.
1714 *
1715 * @return
1716 *               - XST_SUCCESS if successful.
1717 *               - XST_FAILURE if failed.
1718 *
1719 * @note         None
1720 *
1721 ******************************************************************************/
1722 s32 XNandPsu_Write(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *SrcBuf)
1723 {
1724         s32 Status = XST_FAILURE;
1725         u32 Page;
1726         u32 Col;
1727         u32 Target;
1728         u32 Block;
1729         u32 PartialBytes = 0;
1730         u32 NumBytes;
1731         u32 RemLen;
1732         u8 *BufPtr;
1733         u8 *Ptr = (u8 *)SrcBuf;
1734         u16 OnfiStatus;
1735         u64 OffsetVar = Offset;
1736         u64 LengthVar = Length;
1737
1738         /*
1739          * Assert the input arguments.
1740          */
1741         Xil_AssertNonvoid(InstancePtr != NULL);
1742         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1743         Xil_AssertNonvoid(SrcBuf != NULL);
1744         Xil_AssertNonvoid(LengthVar != 0U);
1745         Xil_AssertNonvoid((OffsetVar + LengthVar) <
1746                                 InstancePtr->Geometry.DeviceSize);
1747
1748         /*
1749          * Check if write operation exceeds flash size when including
1750          * bad blocks.
1751          */
1752         Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
1753         if (Status != XST_SUCCESS) {
1754                 goto Out;
1755         }
1756
1757         while (LengthVar > 0U) {
1758                 Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
1759                 /*
1760                  * Skip the bad blocks. Increment the offset by block size.
1761                  * For better results, always program the flash starting at
1762                  * a block boundary.
1763                  */
1764                 if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
1765                         OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
1766                         continue;
1767                 }
1768                 /*
1769                  * Calculate Page and Column address values
1770                  */
1771                 Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
1772                 Col = (u32) (OffsetVar &
1773                                 (InstancePtr->Geometry.BytesPerPage - 1U));
1774                 PartialBytes = 0U;
1775                 /*
1776                  * Check if partial write.
1777                  * If column address is > 0 or Length is < page size
1778                  */
1779                 if ((Col > 0U) ||
1780                         (LengthVar < InstancePtr->Geometry.BytesPerPage)) {
1781                         RemLen = InstancePtr->Geometry.BytesPerPage - Col;
1782                         PartialBytes = (RemLen < (u32)LengthVar) ?
1783                                         RemLen : (u32)LengthVar;
1784                 }
1785
1786                 Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
1787                 if (Page > InstancePtr->Geometry.NumTargetPages) {
1788                         Page %= InstancePtr->Geometry.NumTargetPages;
1789                 }
1790
1791                 /*
1792                  * Check if partial write
1793                  */
1794                 if (PartialBytes > 0U) {
1795                         BufPtr = &InstancePtr->PartialDataBuf[0];
1796                         memset(BufPtr, 0xFF,
1797                                         InstancePtr->Geometry.BytesPerPage);
1798                         memcpy(BufPtr + Col, Ptr, PartialBytes);
1799
1800                         NumBytes = PartialBytes;
1801                 } else {
1802                         BufPtr = (u8 *)Ptr;
1803                         NumBytes = (InstancePtr->Geometry.BytesPerPage <
1804                                         (u32)LengthVar) ?
1805                                         InstancePtr->Geometry.BytesPerPage :
1806                                         (u32)LengthVar;
1807                 }
1808                 /*
1809                  * Program page
1810                  */
1811                 Status = XNandPsu_ProgramPage(InstancePtr, Target, Page, 0U,
1812                                                                 BufPtr);
1813                 if (Status != XST_SUCCESS) {
1814                         goto Out;
1815                 }
1816                 /*
1817                  * ONFI ReadStatus
1818                  */
1819                 do {
1820                         Status = XNandPsu_OnfiReadStatus(InstancePtr, Target,
1821                                                                 &OnfiStatus);
1822                         if (Status != XST_SUCCESS) {
1823                                 goto Out;
1824                         }
1825                         if ((OnfiStatus & (1U << 6U)) != 0U) {
1826                                 if ((OnfiStatus & (1U << 0U)) != 0U) {
1827                                         Status = XST_FAILURE;
1828                                         goto Out;
1829                                 }
1830                         }
1831                 } while (((OnfiStatus >> 6U) & 0x1U) == 0U);
1832
1833                 Ptr += NumBytes;
1834                 OffsetVar += NumBytes;
1835                 LengthVar -= NumBytes;
1836         }
1837
1838         Status = XST_SUCCESS;
1839 Out:
1840         return Status;
1841 }
1842
1843 /*****************************************************************************/
1844 /**
1845 *
1846 * This function reads from the flash.
1847 *
1848 * @param        InstancePtr is a pointer to the XNandPsu instance.
1849 * @param        Offset is the starting offset of flash to read.
1850 * @param        Length is the number of bytes to read.
1851 * @param        DestBuf is the destination data buffer to fill in.
1852 *
1853 * @return
1854 *               - XST_SUCCESS if successful.
1855 *               - XST_FAILURE if failed.
1856 *
1857 * @note         None
1858 *
1859 ******************************************************************************/
1860 s32 XNandPsu_Read(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *DestBuf)
1861 {
1862         s32 Status = XST_FAILURE;
1863         u32 Page;
1864         u32 Col;
1865         u32 Target;
1866         u32 Block;
1867         u32 PartialBytes = 0U;
1868         u32 RemLen;
1869         u32 NumBytes;
1870         u8 *BufPtr;
1871         u8 *Ptr = (u8 *)DestBuf;
1872         u64 OffsetVar = Offset;
1873         u64 LengthVar = Length;
1874
1875         /*
1876          * Assert the input arguments.
1877          */
1878         Xil_AssertNonvoid(InstancePtr != NULL);
1879         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1880         Xil_AssertNonvoid(LengthVar != 0U);
1881         Xil_AssertNonvoid((OffsetVar + LengthVar) <
1882                                 InstancePtr->Geometry.DeviceSize);
1883
1884         /*
1885          * Check if read operation exceeds flash size when including
1886          * bad blocks.
1887          */
1888         Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
1889         if (Status != XST_SUCCESS) {
1890                 goto Out;
1891         }
1892
1893         while (LengthVar > 0U) {
1894                 Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
1895                 /*
1896                  * Skip the bad block. Increment the offset by block size.
1897                  * The flash programming utility must make sure to start
1898                  * writing always at a block boundary and skip blocks if any.
1899                  */
1900                 if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) {
1901                         OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
1902                         continue;
1903                 }
1904                 /*
1905                  * Calculate Page and Column address values
1906                  */
1907                 Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage);
1908                 Col = (u32) (OffsetVar &
1909                                 (InstancePtr->Geometry.BytesPerPage - 1U));
1910                 PartialBytes = 0U;
1911                 /*
1912                  * Check if partial write.
1913                  * If column address is > 0 or Length is < page size
1914                  */
1915                 if ((Col > 0U) ||
1916                         (LengthVar < InstancePtr->Geometry.BytesPerPage)) {
1917                         RemLen = InstancePtr->Geometry.BytesPerPage - Col;
1918                         PartialBytes = ((u32)RemLen < (u32)LengthVar) ?
1919                                                 (u32)RemLen : (u32)LengthVar;
1920                 }
1921
1922                 Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize);
1923                 if (Page > InstancePtr->Geometry.NumTargetPages) {
1924                         Page %= InstancePtr->Geometry.NumTargetPages;
1925                 }
1926                 /*
1927                  * Check if partial read
1928                  */
1929                 if (PartialBytes > 0U) {
1930                         BufPtr = &InstancePtr->PartialDataBuf[0];
1931                         NumBytes = PartialBytes;
1932                 } else {
1933                         BufPtr = Ptr;
1934                         NumBytes = (InstancePtr->Geometry.BytesPerPage <
1935                                         (u32)LengthVar) ?
1936                                         InstancePtr->Geometry.BytesPerPage :
1937                                         (u32)LengthVar;
1938                 }
1939                 /*
1940                  * Read page
1941                  */
1942                 Status = XNandPsu_ReadPage(InstancePtr, Target, Page, 0U,
1943                                                                 BufPtr);
1944                 if (Status != XST_SUCCESS) {
1945                         goto Out;
1946                 }
1947                 if (PartialBytes > 0U) {
1948                         memcpy(Ptr, BufPtr + Col, NumBytes);
1949                 }
1950                 Ptr += NumBytes;
1951                 OffsetVar += NumBytes;
1952                 LengthVar -= NumBytes;
1953         }
1954
1955         Status = XST_SUCCESS;
1956 Out:
1957         return Status;
1958 }
1959
1960 /*****************************************************************************/
1961 /**
1962 *
1963 * This function erases the flash.
1964 *
1965 * @param        InstancePtr is a pointer to the XNandPsu instance.
1966 * @param        Offset is the starting offset of flash to erase.
1967 * @param        Length is the number of bytes to erase.
1968 *
1969 * @return
1970 *               - XST_SUCCESS if successful.
1971 *               - XST_FAILURE if failed.
1972 *
1973 * @note
1974 *               The Offset and Length should be aligned to block size boundary
1975 *               to get better results.
1976 *
1977 ******************************************************************************/
1978 s32 XNandPsu_Erase(XNandPsu *InstancePtr, u64 Offset, u64 Length)
1979 {
1980         s32 Status = XST_FAILURE;
1981         u32 Target = 0;
1982         u32 StartBlock;
1983         u32 NumBlocks = 0;
1984         u32 Block;
1985         u32 AlignOff;
1986         u32 EraseLen;
1987         u32 BlockRemLen;
1988         u16 OnfiStatus;
1989         u64 OffsetVar = Offset;
1990         u64 LengthVar = Length;
1991
1992         /*
1993          * Assert the input arguments.
1994          */
1995         Xil_AssertNonvoid(InstancePtr != NULL);
1996         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1997         Xil_AssertNonvoid(LengthVar != 0U);
1998         Xil_AssertNonvoid((OffsetVar + LengthVar) <
1999                         InstancePtr->Geometry.DeviceSize);
2000
2001         /*
2002          * Check if erase operation exceeds flash size when including
2003          * bad blocks.
2004          */
2005         Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar);
2006         if (Status != XST_SUCCESS) {
2007                 goto Out;
2008         }
2009         /*
2010          * Calculate number of blocks to erase
2011          */
2012         StartBlock = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
2013
2014         while (LengthVar > 0U) {
2015                 Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize);
2016                 if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
2017                                                         XST_SUCCESS) {
2018                         OffsetVar += (u64)InstancePtr->Geometry.BlockSize;
2019                         NumBlocks++;
2020                         continue;
2021                 }
2022
2023                 AlignOff = (u32)OffsetVar &
2024                                 (InstancePtr->Geometry.BlockSize - (u32)1);
2025                 if (AlignOff > 0U) {
2026                         BlockRemLen = InstancePtr->Geometry.BlockSize -
2027                                                                 AlignOff;
2028                         EraseLen = (BlockRemLen < (u32)LengthVar) ?
2029                                                 BlockRemLen :(u32)LengthVar;
2030                 } else {
2031                         EraseLen = (InstancePtr->Geometry.BlockSize <
2032                                                 (u32)LengthVar) ?
2033                                         InstancePtr->Geometry.BlockSize:
2034                                                 (u32)LengthVar;
2035                 }
2036                 NumBlocks++;
2037                 OffsetVar += EraseLen;
2038                 LengthVar -= EraseLen;
2039         }
2040
2041         for (Block = StartBlock; Block < (StartBlock + NumBlocks); Block++) {
2042                 Target = Block/InstancePtr->Geometry.NumTargetBlocks;
2043                 Block %= InstancePtr->Geometry.NumTargetBlocks;
2044                 if (XNandPsu_IsBlockBad(InstancePtr, Block) ==
2045                                                         XST_SUCCESS) {
2046                         /*
2047                          * Don't erase bad block
2048                          */
2049                         continue;
2050                 }
2051                 /*
2052                  * Block Erase
2053                  */
2054                 Status = XNandPsu_EraseBlock(InstancePtr, Target, Block);
2055                 if (Status != XST_SUCCESS) {
2056                         goto Out;
2057                 }
2058                 /*
2059                  * ONFI ReadStatus
2060                  */
2061                 do {
2062                         Status = XNandPsu_OnfiReadStatus(InstancePtr, Target,
2063                                                                 &OnfiStatus);
2064                         if (Status != XST_SUCCESS) {
2065                                 goto Out;
2066                         }
2067                         if ((OnfiStatus & (1U << 6U)) != 0U) {
2068                                 if ((OnfiStatus & (1U << 0U)) != 0U) {
2069                                         Status = XST_FAILURE;
2070                                         goto Out;
2071                                 }
2072                         }
2073                 } while (((OnfiStatus >> 6U) & 0x1U) == 0U);
2074         }
2075
2076         Status = XST_SUCCESS;
2077 Out:
2078         return Status;
2079 }
2080
2081 /*****************************************************************************/
2082 /**
2083 *
2084 * This function sends ONFI Program Page command to flash.
2085 *
2086 * @param        InstancePtr is a pointer to the XNandPsu instance.
2087 * @param        Target is the chip select value.
2088 * @param        Page is the page address value to program.
2089 * @param        Col is the column address value to program.
2090 * @param        Buf is the data buffer to program.
2091 *
2092 * @return
2093 *               - XST_SUCCESS if successful.
2094 *               - XST_FAILURE if failed.
2095 *
2096 * @note         None
2097 *
2098 ******************************************************************************/
2099 static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
2100                                                         u32 Col, u8 *Buf)
2101 {
2102         u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2103                                 InstancePtr->Geometry.ColAddrCycles;
2104         u32 PktSize;
2105         u32 PktCount;
2106         u32 BufWrCnt = 0U;
2107         u32 *BufPtr = (u32 *)(void *)Buf;
2108         s32 Status = XST_FAILURE;
2109         u32 Index;
2110
2111         /*
2112          * Assert the input arguments.
2113          */
2114         Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
2115         Xil_AssertNonvoid(Buf != NULL);
2116
2117         if (InstancePtr->EccCfg.CodeWordSize > 9U) {
2118                 PktSize = 1024U;
2119         } else {
2120                 PktSize = 512U;
2121         }
2122         PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
2123
2124         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1, ONFI_CMD_PG_PROG2,
2125                                         1U, 1U, (u8)AddrCycles);
2126
2127         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2128
2129                 /*
2130                  * Enable DMA boundary Interrupt in Interrupt Status
2131                  * Enable Register
2132                  */
2133                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2134                         XNANDPSU_INTR_STS_EN_OFFSET,
2135                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
2136                         XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK);
2137         } else {
2138                 /*
2139                  * Enable Buffer Write Ready Interrupt in Interrupt Status
2140                  * Enable Register
2141                  */
2142                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2143                         XNANDPSU_INTR_STS_EN_OFFSET,
2144                         XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
2145         }
2146         /*
2147          * Program Page Size
2148          */
2149         XNandPsu_SetPageSize(InstancePtr);
2150         /*
2151          * Program Packet Size and Packet Count
2152          */
2153         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2154         /*
2155          * Program DMA system address and DMA buffer boundary
2156          */
2157         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2158                 /*
2159                  * Flush the Data Cache
2160                  */
2161                 Xil_DCacheFlushRange((INTPTR)Buf, (PktSize * PktCount));
2162
2163 #ifdef __aarch64__
2164                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2165                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
2166                                 (u32) (((INTPTR)Buf >> 32) & 0xFFFFFFFFU));
2167 #endif
2168                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2169                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
2170                                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
2171         }
2172         /*
2173          * Program Column, Page, Block address
2174          */
2175         XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
2176         /*
2177          * Set Bus Width
2178          */
2179         XNandPsu_SetBusWidth(InstancePtr);
2180         /*
2181          * Program Memory Address Register2 for chip select
2182          */
2183         XNandPsu_SelectChip(InstancePtr, Target);
2184         /*
2185          * Set ECC
2186          */
2187         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2188                 XNandPsu_SetEccSpareCmd(InstancePtr, ONFI_CMD_CHNG_WR_COL,
2189                                         InstancePtr->Geometry.ColAddrCycles);
2190         }
2191         /*
2192          * Set Page Program in Program Register
2193          */
2194         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2195                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
2196
2197         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2198                 goto WriteDmaDone;
2199         }
2200
2201         while (BufWrCnt < PktCount) {
2202                 /*
2203                  * Poll for Buffer Write Ready event
2204                  */
2205                 Status = XNandPsu_PollRegTimeout(
2206                         InstancePtr,
2207                         XNANDPSU_INTR_STS_OFFSET,
2208                         XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK,
2209                         XNANDPSU_INTR_POLL_TIMEOUT);
2210                 if (Status != XST_SUCCESS) {
2211 #ifdef XNANDPSU_DEBUG
2212                         xil_printf("%s: Poll for buf write ready timeout\r\n",
2213                                                         __func__);
2214 #endif
2215                         goto Out;
2216                 }
2217                 /*
2218                  * Increment Buffer Write Interrupt Count
2219                  */
2220                 BufWrCnt++;
2221
2222                 if (BufWrCnt == PktCount) {
2223                         /*
2224                          * Enable Transfer Complete Interrupt in Interrupt
2225                          * Status Enable Register
2226                          */
2227                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2228                                 XNANDPSU_INTR_STS_EN_OFFSET,
2229                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2230                 } else {
2231                         /*
2232                          * Clear Buffer Write Ready Interrupt in Interrupt
2233                          * Status Enable Register
2234                          */
2235                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2236                                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2237
2238                 }
2239                 /*
2240                  * Clear Buffer Write Ready Interrupt in Interrupt Status
2241                  * Register
2242                  */
2243                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2244                                 XNANDPSU_INTR_STS_OFFSET,
2245                                 XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK);
2246                 /*
2247                  * Write Packet Data to Data Port Register
2248                  */
2249                 for (Index = 0U; Index < (PktSize/4U); Index++) {
2250                         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2251                                                 XNANDPSU_BUF_DATA_PORT_OFFSET,
2252                                                 BufPtr[Index]);
2253                 }
2254                 BufPtr += (PktSize/4U);
2255
2256                 if (BufWrCnt < PktCount) {
2257                         /*
2258                          * Enable Buffer Write Ready Interrupt in Interrupt
2259                          * Status Enable Register
2260                          */
2261                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2262                                 XNANDPSU_INTR_STS_EN_OFFSET,
2263                                 XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
2264                 } else {
2265                         break;
2266                 }
2267         }
2268 WriteDmaDone:
2269         /*
2270          * Poll for Transfer Complete event
2271          */
2272         Status = XNandPsu_PollRegTimeout(
2273                         InstancePtr,
2274                         XNANDPSU_INTR_STS_OFFSET,
2275                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
2276                         XNANDPSU_INTR_POLL_TIMEOUT);
2277         if (Status != XST_SUCCESS) {
2278 #ifdef XNANDPSU_DEBUG
2279                 xil_printf("%s: Poll for xfer complete timeout\r\n",
2280                                                         __func__);
2281 #endif
2282                 goto Out;
2283         }
2284         /*
2285          * Clear Transfer Complete Interrupt in Interrupt Status Enable
2286          * Register
2287          */
2288         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2289                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2290
2291         /*
2292          * Clear Transfer Complete Interrupt in Interrupt Status Register
2293          */
2294         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2295                         XNANDPSU_INTR_STS_OFFSET,
2296                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
2297
2298 Out:
2299         return Status;
2300 }
2301
2302 /*****************************************************************************/
2303 /**
2304 *
2305 * This function sends ONFI Program Page command to flash.
2306 *
2307 * @param        InstancePtr is a pointer to the XNandPsu instance.
2308 * @param        Target is the chip select value.
2309 * @param        Page is the page address value to program.
2310 * @param        Col is the column address value to program.
2311 * @param        Buf is the data buffer to program.
2312 *
2313 * @return
2314 *               - XST_SUCCESS if successful.
2315 *               - XST_FAILURE if failed.
2316 *
2317 * @note         None
2318 *
2319 ******************************************************************************/
2320 s32 XNandPsu_WriteSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
2321 {
2322         u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2323                                 InstancePtr->Geometry.ColAddrCycles;
2324         u32 Col = InstancePtr->Geometry.BytesPerPage;
2325         u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
2326         u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
2327         u32 PktCount = 1U;
2328         u32 BufWrCnt = 0U;
2329         u32 *BufPtr = (u32 *)(void *)Buf;
2330         u16 PreEccSpareCol = 0U;
2331         u16 PreEccSpareWrCnt = 0U;
2332         u16 PostEccSpareCol = 0U;
2333         u16 PostEccSpareWrCnt = 0U;
2334         u32 PostWrite = 0U;
2335         OnfiCmdFormat Cmd;
2336         s32 Status = XST_FAILURE;
2337         u32 Index;
2338         u32 PageVar = Page;
2339
2340         /*
2341          * Assert the input arguments.
2342          */
2343         Xil_AssertNonvoid(InstancePtr != NULL);
2344         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
2345         Xil_AssertNonvoid(PageVar < InstancePtr->Geometry.NumPages);
2346         Xil_AssertNonvoid(Buf != NULL);
2347
2348         PageVar %= InstancePtr->Geometry.NumTargetPages;
2349
2350         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2351                 /*
2352                  * Calculate ECC free positions before and after ECC code
2353                  */
2354                 PreEccSpareCol = 0x0U;
2355                 PreEccSpareWrCnt = InstancePtr->EccCfg.EccAddr -
2356                                 (u16)InstancePtr->Geometry.BytesPerPage;
2357
2358                 PostEccSpareCol = PreEccSpareWrCnt +
2359                                         InstancePtr->EccCfg.EccSize;
2360                 PostEccSpareWrCnt = InstancePtr->Geometry.SpareBytesPerPage -
2361                                         PostEccSpareCol;
2362
2363                 PreEccSpareWrCnt = (PreEccSpareWrCnt/4U) * 4U;
2364                 PostEccSpareWrCnt = (PostEccSpareWrCnt/4U) * 4U;
2365
2366                 if (PreEccSpareWrCnt > 0U) {
2367                         PktSize = PreEccSpareWrCnt;
2368                         PktCount = 1U;
2369                         Col = InstancePtr->Geometry.BytesPerPage +
2370                                                         PreEccSpareCol;
2371                         BufPtr = (u32 *)(void *)Buf;
2372                         if (PostEccSpareWrCnt > 0U) {
2373                                 PostWrite = 1U;
2374                         }
2375                 } else if (PostEccSpareWrCnt > 0U) {
2376                         PktSize = PostEccSpareWrCnt;
2377                         PktCount = 1U;
2378                         Col = InstancePtr->Geometry.BytesPerPage +
2379                                                         PostEccSpareCol;
2380                         BufPtr = (u32 *)(void *)&Buf[Col];
2381                 } else {
2382                         /*
2383                          * No free spare bytes available for writing
2384                          */
2385                         Status = XST_FAILURE;
2386                         goto Out;
2387                 }
2388         }
2389
2390         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2391                 /*
2392                  * Enable Transfer Complete Interrupt in Interrupt Status
2393                  * Enable Register
2394                  */
2395                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2396                         XNANDPSU_INTR_STS_EN_OFFSET,
2397                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2398
2399         } else {
2400                 /*
2401                  * Enable Buffer Write Ready Interrupt in Interrupt Status
2402                  * Enable Register
2403                  */
2404                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2405                         XNANDPSU_INTR_STS_EN_OFFSET,
2406                         XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
2407
2408         }
2409         /*
2410          * Program Command hack for change write column
2411          */
2412         if (PostWrite > 0U) {
2413                 Cmd.Command1 = 0x80U;
2414                 Cmd.Command2 = 0x00U;
2415                 XNandPsu_Prepare_Cmd(InstancePtr, Cmd.Command1, Cmd.Command2,
2416                                 0U , 1U, (u8)AddrCycles);
2417
2418         } else {
2419                 XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1,
2420                                 ONFI_CMD_PG_PROG2, 0U , 1U, (u8)AddrCycles);
2421         }
2422         /*
2423          * Program Page Size
2424          */
2425         XNandPsu_SetPageSize(InstancePtr);
2426         /*
2427          * Program Packet Size and Packet Count
2428          */
2429         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2430         /*
2431          * Program DMA system address and DMA buffer boundary
2432          */
2433         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2434                 /*
2435                  * Flush the Data Cache
2436                  */
2437                 Xil_DCacheFlushRange((INTPTR)BufPtr, (PktSize * PktCount));
2438
2439 #ifdef __aarch64__
2440                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2441                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
2442                                 (u32) (((INTPTR)BufPtr >> 32) & 0xFFFFFFFFU));
2443 #endif
2444                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2445                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
2446                                 (u32) ((INTPTR)(void *)BufPtr & 0xFFFFFFFFU));
2447
2448                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2449                                 XNANDPSU_DMA_BUF_BND_OFFSET,
2450                                 XNANDPSU_DMA_BUF_BND_512K);
2451         }
2452         /*
2453          * Program Column, Page, Block address
2454          */
2455         XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
2456         /*
2457          * Set Bus Width
2458          */
2459         XNandPsu_SetBusWidth(InstancePtr);
2460         /*
2461          * Program Memory Address Register2 for chip select
2462          */
2463         XNandPsu_SelectChip(InstancePtr, Target);
2464         /*
2465          * Set Page Program in Program Register
2466          */
2467         if (PostWrite > 0U) {
2468                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2469                         XNANDPSU_PROG_OFFSET,((u32)XNANDPSU_PROG_PG_PROG_MASK |
2470                                 (u32)XNANDPSU_PROG_CHNG_ROW_ADDR_MASK));
2471         } else {
2472         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2473                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK);
2474         }
2475
2476         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2477                 goto WriteDmaDone;
2478         }
2479
2480         while (BufWrCnt < PktCount) {
2481                 /*
2482                  * Poll for Buffer Write Ready event
2483                  */
2484                 Status = XNandPsu_PollRegTimeout(
2485                         InstancePtr,
2486                         XNANDPSU_INTR_STS_OFFSET,
2487                         XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK,
2488                         XNANDPSU_INTR_POLL_TIMEOUT);
2489                 if (Status != XST_SUCCESS) {
2490 #ifdef XNANDPSU_DEBUG
2491                         xil_printf("%s: Poll for buf write ready timeout\r\n",
2492                                                         __func__);
2493 #endif
2494                         goto Out;
2495                 }
2496                 /*
2497                  * Increment Buffer Write Interrupt Count
2498                  */
2499                 BufWrCnt++;
2500
2501                 if (BufWrCnt == PktCount) {
2502                         /*
2503                          * Enable Transfer Complete Interrupt in Interrupt
2504                          * Status Enable Register
2505                          */
2506                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2507                                 XNANDPSU_INTR_STS_EN_OFFSET,
2508                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2509
2510                 } else {
2511                         /*
2512                          * Clear Buffer Write Ready Interrupt in Interrupt
2513                          * Status Enable Register
2514                          */
2515                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2516                                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2517                 }
2518                 /*
2519                  * Clear Buffer Write Ready Interrupt in Interrupt Status
2520                  * Register
2521                  */
2522                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2523                                 XNANDPSU_INTR_STS_OFFSET,
2524                                 XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK);
2525                 /*
2526                  * Write Packet Data to Data Port Register
2527                  */
2528                 for (Index = 0U; Index < (PktSize/4U); Index++) {
2529                         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2530                                                 XNANDPSU_BUF_DATA_PORT_OFFSET,
2531                                                 BufPtr[Index]);
2532                 }
2533                 BufPtr += (PktSize/4U);
2534
2535                 if (BufWrCnt < PktCount) {
2536                         /*
2537                          * Enable Buffer Write Ready Interrupt in Interrupt
2538                          * Status Enable Register
2539                          */
2540                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2541                                 XNANDPSU_INTR_STS_EN_OFFSET,
2542                                 XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
2543                 } else {
2544                         break;
2545                 }
2546         }
2547 WriteDmaDone:
2548         /*
2549          * Poll for Transfer Complete event
2550          */
2551         Status = XNandPsu_PollRegTimeout(
2552                         InstancePtr,
2553                         XNANDPSU_INTR_STS_OFFSET,
2554                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
2555                         XNANDPSU_INTR_POLL_TIMEOUT);
2556         if (Status != XST_SUCCESS) {
2557 #ifdef XNANDPSU_DEBUG
2558                 xil_printf("%s: Poll for xfer complete timeout\r\n",
2559                                                         __func__);
2560 #endif
2561                 goto Out;
2562         }
2563         /*
2564          * Clear Transfer Complete Interrupt in Interrupt Status Enable
2565          * Register
2566          */
2567         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2568                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2569
2570         /*
2571          * Clear Transfer Complete Interrupt in Interrupt Status Register
2572          */
2573         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2574                                 XNANDPSU_INTR_STS_OFFSET,
2575                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
2576
2577         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2578                 if (PostWrite > 0U) {
2579                         BufPtr = (u32 *)(void *)&Buf[PostEccSpareCol];
2580                         Status = XNandPsu_ChangeWriteColumn(InstancePtr,
2581                                         Target,
2582                                         PostEccSpareCol, PostEccSpareWrCnt, 1U,
2583                                         (u8 *)(void *)BufPtr);
2584                         if (Status != XST_SUCCESS) {
2585                                 goto Out;
2586                         }
2587                 }
2588         }
2589 Out:
2590
2591         return Status;
2592 }
2593
2594 /*****************************************************************************/
2595 /**
2596 *
2597 * This function sends ONFI Read Page command to flash.
2598 *
2599 * @param        InstancePtr is a pointer to the XNandPsu instance.
2600 * @param        Target is the chip select value.
2601 * @param        Page is the page address value to read.
2602 * @param        Col is the column address value to read.
2603 * @param        Buf is the data buffer to fill in.
2604 *
2605 * @return
2606 *               - XST_SUCCESS if successful.
2607 *               - XST_FAILURE if failed.
2608 *
2609 * @note         None
2610 *
2611 ******************************************************************************/
2612 static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page,
2613                                                         u32 Col, u8 *Buf)
2614 {
2615         u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2616                                 InstancePtr->Geometry.ColAddrCycles;
2617         u32 PktSize;
2618         u32 PktCount;
2619         u32 BufRdCnt = 0U;
2620         u32 *BufPtr = (u32 *)(void *)Buf;
2621         s32 Status = XST_FAILURE;
2622         u32 Index, RegVal;
2623
2624         /*
2625          * Assert the input arguments.
2626          */
2627         Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages);
2628         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
2629
2630         if (InstancePtr->EccCfg.CodeWordSize > 9U) {
2631                 PktSize = 1024U;
2632         } else {
2633                 PktSize = 512U;
2634         }
2635         PktCount = InstancePtr->Geometry.BytesPerPage/PktSize;
2636
2637         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2,
2638                                         1U, 1U, (u8)AddrCycles);
2639
2640         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2641
2642                 /*
2643                  * Enable DMA boundary Interrupt in Interrupt Status
2644                  * Enable Register
2645                  */
2646                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2647                         XNANDPSU_INTR_STS_EN_OFFSET,
2648                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
2649                         XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK);
2650
2651         } else {
2652                 /*
2653                  * Enable Buffer Read Ready Interrupt in Interrupt Status
2654                  * Enable Register
2655                  */
2656                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2657                         XNANDPSU_INTR_STS_EN_OFFSET,
2658                         XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
2659
2660         }
2661         /*
2662          * Enable Single bit error and Multi bit error
2663          */
2664         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2665                 /*
2666                  * Interrupt Status Enable Register
2667                  */
2668                 XNandPsu_IntrStsEnable(InstancePtr,
2669                         (XNANDPSU_INTR_STS_EN_MUL_BIT_ERR_STS_EN_MASK |
2670                         XNANDPSU_INTR_STS_EN_ERR_INTR_STS_EN_MASK));
2671         }
2672         /*
2673          * Program Page Size
2674          */
2675         XNandPsu_SetPageSize(InstancePtr);
2676         /*
2677          * Program Column, Page, Block address
2678          */
2679         XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col);
2680         /*
2681          * Program Packet Size and Packet Count
2682          */
2683         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2684         /*
2685          * Program DMA system address and DMA buffer boundary
2686          */
2687         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2688                 /*
2689                  * Invalidate the Data Cache
2690                  */
2691                 Xil_DCacheInvalidateRange((INTPTR)Buf, (PktSize * PktCount));
2692
2693 #ifdef __aarch64__
2694                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2695                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
2696                                 (u32) (((INTPTR)(void *)Buf >> 32) &
2697                                 0xFFFFFFFFU));
2698 #endif
2699                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2700                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
2701                                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
2702         }
2703         /*
2704          * Set Bus Width
2705          */
2706         XNandPsu_SetBusWidth(InstancePtr);
2707         /*
2708          * Program Memory Address Register2 for chip select
2709          */
2710         XNandPsu_SelectChip(InstancePtr, Target);
2711         /*
2712          * Set ECC
2713          */
2714         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2715                 XNandPsu_SetEccSpareCmd(InstancePtr,
2716                                         (ONFI_CMD_CHNG_RD_COL1 |
2717                                         (ONFI_CMD_CHNG_RD_COL2 << (u8)8U)),
2718                                         InstancePtr->Geometry.ColAddrCycles);
2719         }
2720
2721         /*
2722          * Set Read command in Program Register
2723          */
2724         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2725                                 XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
2726
2727         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2728                 goto ReadDmaDone;
2729         }
2730
2731         while (BufRdCnt < PktCount) {
2732                 /*
2733                  * Poll for Buffer Read Ready event
2734                  */
2735                 Status = XNandPsu_PollRegTimeout(
2736                         InstancePtr,
2737                         XNANDPSU_INTR_STS_OFFSET,
2738                         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
2739                         XNANDPSU_INTR_POLL_TIMEOUT);
2740                 if (Status != XST_SUCCESS) {
2741 #ifdef XNANDPSU_DEBUG
2742                         xil_printf("%s: Poll for buf read ready timeout\r\n",
2743                                                         __func__);
2744 #endif
2745                         goto CheckEccError;
2746                 }
2747                 /*
2748                  * Increment Buffer Read Interrupt Count
2749                  */
2750                 BufRdCnt++;
2751
2752                 if (BufRdCnt == PktCount) {
2753                         /*
2754                          * Enable Transfer Complete Interrupt in Interrupt
2755                          * Status Enable Register
2756                          */
2757                         RegVal = XNandPsu_ReadReg(
2758                                         (InstancePtr)->Config.BaseAddress,
2759                                         XNANDPSU_INTR_STS_EN_OFFSET);
2760                         RegVal &= ~XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK;
2761                         RegVal |= XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK;
2762                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2763                                 XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2764                 } else {
2765                         /*
2766                          * Clear Buffer Read Ready Interrupt in Interrupt
2767                          * Status Enable Register
2768                          */
2769                         RegVal = XNandPsu_ReadReg(
2770                                         (InstancePtr)->Config.BaseAddress,
2771                                         XNANDPSU_INTR_STS_EN_OFFSET);
2772                         RegVal &= ~XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK;
2773                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2774                                         XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2775                 }
2776                 /*
2777                  * Clear Buffer Read Ready Interrupt in Interrupt Status
2778                  * Register
2779                  */
2780                 RegVal = XNandPsu_ReadReg(
2781                                 (InstancePtr)->Config.BaseAddress,
2782                                 XNANDPSU_INTR_STS_OFFSET);
2783                 RegVal |= XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK;
2784                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2785                                 XNANDPSU_INTR_STS_OFFSET, RegVal);
2786                 /*
2787                  * Read Packet Data from Data Port Register
2788                  */
2789                 for (Index = 0U; Index < (PktSize/4); Index++) {
2790                         BufPtr[Index] = XNandPsu_ReadReg(
2791                                         InstancePtr->Config.BaseAddress,
2792                                         XNANDPSU_BUF_DATA_PORT_OFFSET);
2793                 }
2794                 BufPtr += (PktSize/4);
2795
2796                 if (BufRdCnt < PktCount) {
2797                         /*
2798                          * Enable Buffer Read Ready Interrupt in Interrupt
2799                          * Status Enable Register
2800                          */
2801                         RegVal = XNandPsu_ReadReg(
2802                                         (InstancePtr)->Config.BaseAddress,
2803                                         XNANDPSU_INTR_STS_EN_OFFSET);
2804                         RegVal |= XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK;
2805                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2806                                 XNANDPSU_INTR_STS_EN_OFFSET, RegVal);
2807                 } else {
2808                         break;
2809                 }
2810         }
2811 ReadDmaDone:
2812         /*
2813          * Poll for Transfer Complete event
2814          */
2815         Status = XNandPsu_PollRegTimeout(
2816                         InstancePtr,
2817                         XNANDPSU_INTR_STS_OFFSET,
2818                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
2819                         XNANDPSU_INTR_POLL_TIMEOUT);
2820         if (Status != XST_SUCCESS) {
2821 #ifdef XNANDPSU_DEBUG
2822                 xil_printf("%s: Poll for xfer complete timeout\r\n",
2823                                                         __func__);
2824 #endif
2825                 goto CheckEccError;
2826         }
2827         /*
2828          * Clear Transfer Complete Interrupt in Interrupt Status Enable
2829          * Register
2830          */
2831         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2832                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
2833
2834         /*
2835          * Clear Transfer Complete Interrupt in Interrupt Status Register
2836          */
2837         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2838                         XNANDPSU_INTR_STS_OFFSET,
2839                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
2840
2841 CheckEccError:
2842         /*
2843          * Check ECC Errors
2844          */
2845         if (InstancePtr->EccMode == XNANDPSU_HWECC) {
2846                 /*
2847                  * Hamming Multi Bit Errors
2848                  */
2849                 if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
2850                                 XNANDPSU_INTR_STS_OFFSET) &
2851                         (u32)XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK) != 0U) {
2852
2853                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2854                                 XNANDPSU_INTR_STS_OFFSET,
2855                                 XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK);
2856
2857 #ifdef XNANDPSU_DEBUG
2858                         xil_printf("%s: ECC Hamming multi bit error\r\n",
2859                                                         __func__);
2860 #endif
2861                         InstancePtr->Ecc_Stat_PerPage_flips =
2862                                         ((XNandPsu_ReadReg(
2863                                         InstancePtr->Config.BaseAddress,
2864                                         XNANDPSU_ECC_ERR_CNT_OFFSET) &
2865                                         0x1FF00U) >> 8U);
2866                         InstancePtr->Ecc_Stats_total_flips +=
2867                                         InstancePtr->Ecc_Stat_PerPage_flips;
2868                         Status = XST_FAILURE;
2869                 }
2870                 /*
2871                  * Hamming Single Bit or BCH Errors
2872                  */
2873                 if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress,
2874                                 XNANDPSU_INTR_STS_OFFSET) &
2875                         (u32)XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK) != 0U) {
2876
2877                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2878                                         XNANDPSU_INTR_STS_OFFSET,
2879                                         XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK);
2880
2881                         if (InstancePtr->EccCfg.IsBCH == 1U) {
2882                                 InstancePtr->Ecc_Stat_PerPage_flips =
2883                                                 ((XNandPsu_ReadReg(
2884                                                 InstancePtr->Config.BaseAddress,
2885                                                 XNANDPSU_ECC_ERR_CNT_OFFSET)&
2886                                                 0x1FF00U) >> 8U);
2887                                 InstancePtr->Ecc_Stats_total_flips +=
2888                                         InstancePtr->Ecc_Stat_PerPage_flips;
2889                                 Status = XST_SUCCESS;
2890                         }
2891                 }
2892         }
2893 Out:
2894         return Status;
2895 }
2896
2897 /*****************************************************************************/
2898 /**
2899 *
2900 * This function reads spare bytes from flash.
2901 *
2902 * @param        InstancePtr is a pointer to the XNandPsu instance.
2903 * @param        Target is the chip select value.
2904 * @param        Page is the page address value to read.
2905 * @param        Buf is the data buffer to fill in.
2906 *
2907 * @return
2908 *               - XST_SUCCESS if successful.
2909 *               - XST_FAILURE if failed.
2910 *
2911 * @note         None
2912 *
2913 ******************************************************************************/
2914 s32 XNandPsu_ReadSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf)
2915 {
2916         u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles +
2917                                 InstancePtr->Geometry.ColAddrCycles;
2918         u32 Col = InstancePtr->Geometry.BytesPerPage;
2919         u32 Target = Page/InstancePtr->Geometry.NumTargetPages;
2920         u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage;
2921         u32 PktCount = 1U;
2922         u32 BufRdCnt = 0U;
2923         u32 *BufPtr = (u32 *)(void *)Buf;
2924         s32 Status = XST_FAILURE;
2925         u32 Index;
2926         u32 PageVar = Page;
2927
2928         /*
2929          * Assert the input arguments.
2930          */
2931         Xil_AssertNonvoid(InstancePtr != NULL);
2932         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
2933         Xil_AssertNonvoid(PageVar < InstancePtr->Geometry.NumPages);
2934         Xil_AssertNonvoid(Buf != NULL);
2935
2936         PageVar %= InstancePtr->Geometry.NumTargetPages;
2937
2938         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2939                 /*
2940                  * Enable Transfer Complete Interrupt in Interrupt Status
2941                  * Enable Register
2942                  */
2943                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2944                                 XNANDPSU_INTR_STS_EN_OFFSET,
2945                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
2946         } else {
2947                 /*
2948                  * Enable Buffer Read Ready Interrupt in Interrupt Status
2949                  * Enable Register
2950                  */
2951                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
2952                                 XNANDPSU_INTR_STS_EN_OFFSET,
2953                                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
2954         }
2955         /*
2956          * Program Command
2957          */
2958         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2, 0U,
2959                                                 1U, (u8)AddrCycles);
2960         /*
2961          * Program Page Size
2962          */
2963         XNandPsu_SetPageSize(InstancePtr);
2964         /*
2965          * Program Column, Page, Block address
2966          */
2967         XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col);
2968         /*
2969          * Program Packet Size and Packet Count
2970          */
2971         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
2972         /*
2973          * Program DMA system address and DMA buffer boundary
2974          */
2975         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
2976
2977                 /*
2978                  * Invalidate the Data Cache
2979                  */
2980                 Xil_DCacheInvalidateRange((INTPTR)Buf, (PktSize * PktCount));
2981 #ifdef __aarch64__
2982                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2983                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
2984                                 (u32) (((INTPTR)(void *)Buf >> 32) &
2985                                 0xFFFFFFFFU));
2986 #endif
2987                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
2988                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
2989                                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
2990         }
2991         /*
2992          * Set Bus Width
2993          */
2994         XNandPsu_SetBusWidth(InstancePtr);
2995         /*
2996          * Program Memory Address Register2 for chip select
2997          */
2998         XNandPsu_SelectChip(InstancePtr, Target);
2999         /*
3000          * Set Read command in Program Register
3001          */
3002         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3003                                 XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
3004
3005         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3006                 goto ReadDmaDone;
3007         }
3008
3009         while (BufRdCnt < PktCount) {
3010                 /*
3011                  * Poll for Buffer Read Ready event
3012                  */
3013                 Status = XNandPsu_PollRegTimeout(
3014                         InstancePtr,
3015                         XNANDPSU_INTR_STS_OFFSET,
3016                         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
3017                         XNANDPSU_INTR_POLL_TIMEOUT);
3018                 if (Status != XST_SUCCESS) {
3019 #ifdef XNANDPSU_DEBUG
3020                         xil_printf("%s: Poll for buf read ready timeout\r\n",
3021                                                         __func__);
3022 #endif
3023                         goto Out;
3024                 }
3025                 /*
3026                  * Increment Buffer Read Interrupt Count
3027                  */
3028                 BufRdCnt++;
3029
3030                 if (BufRdCnt == PktCount) {
3031                         /*
3032                          * Enable Transfer Complete Interrupt in Interrupt
3033                          * Status Enable Register
3034                          */
3035                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3036                                 XNANDPSU_INTR_STS_EN_OFFSET,
3037                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
3038
3039                 } else {
3040                         /*
3041                          * Clear Buffer Read Ready Interrupt in Interrupt
3042                          * Status Enable Register
3043                          */
3044                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3045                                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3046
3047                 }
3048                 /*
3049                  * Clear Buffer Read Ready Interrupt in Interrupt Status
3050                  * Register
3051                  */
3052                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3053                                 XNANDPSU_INTR_STS_OFFSET,
3054                                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
3055                 /*
3056                  * Read Packet Data from Data Port Register
3057                  */
3058                 for (Index = 0U; Index < (PktSize/4); Index++) {
3059                         BufPtr[Index] = XNandPsu_ReadReg(
3060                                         InstancePtr->Config.BaseAddress,
3061                                         XNANDPSU_BUF_DATA_PORT_OFFSET);
3062                 }
3063                 BufPtr += (PktSize/4);
3064
3065                 if (BufRdCnt < PktCount) {
3066                         /*
3067                          * Enable Buffer Read Ready Interrupt in Interrupt
3068                          * Status Enable Register
3069                          */
3070                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3071                                 XNANDPSU_INTR_STS_EN_OFFSET,
3072                                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
3073                 } else {
3074                         break;
3075                 }
3076         }
3077 ReadDmaDone:
3078         /*
3079          * Poll for Transfer Complete event
3080          */
3081         Status = XNandPsu_PollRegTimeout(
3082                         InstancePtr,
3083                         XNANDPSU_INTR_STS_OFFSET,
3084                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3085                         XNANDPSU_INTR_POLL_TIMEOUT);
3086         if (Status != XST_SUCCESS) {
3087 #ifdef XNANDPSU_DEBUG
3088                 xil_printf("%s: Poll for xfer complete timeout\r\n",
3089                                                         __func__);
3090 #endif
3091                 goto Out;
3092         }
3093         /*
3094          * Clear Transfer Complete Interrupt in Interrupt Status Enable
3095          * Register
3096          */
3097         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3098                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3099
3100         /*
3101          * Clear Transfer Complete Interrupt in Interrupt Status Register
3102          */
3103         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3104                         XNANDPSU_INTR_STS_OFFSET,
3105                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3106 Out:
3107
3108         return Status;
3109 }
3110
3111 /*****************************************************************************/
3112 /**
3113 *
3114 * This function sends ONFI block erase command to the flash.
3115 *
3116 * @param        InstancePtr is a pointer to the XNandPsu instance.
3117 * @param        Target is the chip select value.
3118 * @param        Block is the block to erase.
3119 *
3120 * @return
3121 *               - XST_SUCCESS if successful.
3122 *               - XST_FAILURE if failed.
3123 *
3124 * @note         None
3125 *
3126 ******************************************************************************/
3127 s32 XNandPsu_EraseBlock(XNandPsu *InstancePtr, u32 Target, u32 Block)
3128 {
3129         s32 Status = XST_FAILURE;
3130         u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles;
3131         u32 Page;
3132         u32 ErasePage;
3133         u32 EraseCol;
3134
3135         /*
3136          * Assert the input arguments.
3137          */
3138         Xil_AssertNonvoid(InstancePtr != NULL);
3139         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
3140         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
3141         Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
3142
3143         Page = Block * InstancePtr->Geometry.PagesPerBlock;
3144         ErasePage = (Page >> 16U) & 0xFFFFU;
3145         EraseCol = Page & 0xFFFFU;
3146
3147         /*
3148          * Enable Transfer Complete Interrupt in Interrupt Status Enable
3149          * Register
3150          */
3151         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3152                         XNANDPSU_INTR_STS_EN_OFFSET,
3153                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
3154
3155         /*
3156          * Program Command
3157          */
3158         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_BLK_ERASE1,
3159                         ONFI_CMD_BLK_ERASE2, 0U , 0U, (u8)AddrCycles);
3160         /*
3161          * Program Column, Page, Block address
3162          */
3163         XNandPsu_SetPageColAddr(InstancePtr, ErasePage, (u16)EraseCol);
3164         /*
3165          * Program Memory Address Register2 for chip select
3166          */
3167         XNandPsu_SelectChip(InstancePtr, Target);
3168         /*
3169          * Set Block Erase in Program Register
3170          */
3171         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3172                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_BLK_ERASE_MASK);
3173         /*
3174          * Poll for Transfer Complete event
3175          */
3176         Status = XNandPsu_PollRegTimeout(
3177                         InstancePtr,
3178                         XNANDPSU_INTR_STS_OFFSET,
3179                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3180                         XNANDPSU_INTR_POLL_TIMEOUT);
3181         if (Status != XST_SUCCESS) {
3182 #ifdef XNANDPSU_DEBUG
3183                 xil_printf("%s: Poll for xfer complete timeout\r\n",
3184                                                         __func__);
3185 #endif
3186                 goto Out;
3187         }
3188         /*
3189          * Clear Transfer Complete Interrupt in Interrupt Status Enable
3190          * Register
3191          */
3192         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3193                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3194
3195         /*
3196          * Clear Transfer Complete Interrupt in Interrupt Status Register
3197          */
3198         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3199                         XNANDPSU_INTR_STS_OFFSET,
3200                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3201
3202 Out:
3203         return Status;
3204 }
3205
3206 /*****************************************************************************/
3207 /**
3208 *
3209 * This function sends ONFI Get Feature command to flash.
3210 *
3211 * @param        InstancePtr is a pointer to the XNandPsu instance.
3212 * @param        Target is the chip select value.
3213 * @param        Feature is the feature selector.
3214 * @param        Buf is the buffer to fill feature value.
3215 *
3216 * @return
3217 *               - XST_SUCCESS if successful.
3218 *               - XST_FAILURE if failed.
3219 *
3220 * @note         None
3221 *
3222 ******************************************************************************/
3223 s32 XNandPsu_GetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
3224                                                                 u8 *Buf)
3225 {
3226         s32 Status;
3227         u32 Index;
3228         u32 PktSize = 4;
3229         u32 PktCount = 1;
3230         u32 *BufPtr = (u32 *)(void *)Buf;
3231
3232         /*
3233          * Assert the input arguments.
3234          */
3235         Xil_AssertNonvoid(Buf != NULL);
3236
3237         if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
3238                 PktSize = 8U;
3239         }
3240
3241         /*
3242          * Enable Buffer Read Ready Interrupt in Interrupt Status
3243          * Enable Register
3244          */
3245         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3246                         XNANDPSU_INTR_STS_EN_OFFSET,
3247                         XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
3248         /*
3249          * Program Command
3250          */
3251         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_GET_FEATURES,
3252                                 ONFI_CMD_INVALID, 0U, 0U, 1U);
3253         /*
3254          * Program Column, Page, Block address
3255          */
3256         XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
3257         /*
3258          * Program Memory Address Register2 for chip select
3259          */
3260         XNandPsu_SelectChip(InstancePtr, Target);
3261         /*
3262          * Program Packet Size and Packet Count
3263          */
3264         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
3265         /*
3266          * Set Read Parameter Page in Program Register
3267          */
3268         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3269                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_GET_FEATURES_MASK);
3270         /*
3271          * Poll for Buffer Read Ready event
3272          */
3273         Status = XNandPsu_PollRegTimeout(
3274                 InstancePtr,
3275                 XNANDPSU_INTR_STS_OFFSET,
3276                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
3277                 XNANDPSU_INTR_POLL_TIMEOUT);
3278         if (Status != XST_SUCCESS) {
3279 #ifdef XNANDPSU_DEBUG
3280                 xil_printf("%s: Poll for buf read ready timeout\r\n",
3281                                                         __func__);
3282 #endif
3283                 goto Out;
3284         }
3285         /*
3286          * Clear Buffer Read Ready Interrupt in Interrupt Status Enable
3287          * Register
3288          */
3289         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3290                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3291
3292         /*
3293          * Clear Buffer Read Ready Interrupt in Interrupt Status Register
3294          */
3295         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3296                         XNANDPSU_INTR_STS_OFFSET,
3297                                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
3298         /*
3299          * Enable Transfer Complete Interrupt in Interrupt Status Enable
3300          * Register
3301          */
3302         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3303                         XNANDPSU_INTR_STS_EN_OFFSET,
3304                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
3305
3306         /*
3307          * Read Data from Data Port Register
3308          */
3309         for (Index = 0U; Index < (PktSize/4U); Index++) {
3310                 BufPtr[Index] = XNandPsu_ReadReg(
3311                                         InstancePtr->Config.BaseAddress,
3312                                         XNANDPSU_BUF_DATA_PORT_OFFSET);
3313         }
3314         /*
3315          * Poll for Transfer Complete event
3316          */
3317         Status = XNandPsu_PollRegTimeout(
3318                         InstancePtr,
3319                         XNANDPSU_INTR_STS_OFFSET,
3320                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3321                         XNANDPSU_INTR_POLL_TIMEOUT);
3322         if (Status != XST_SUCCESS) {
3323 #ifdef XNANDPSU_DEBUG
3324                 xil_printf("%s: Poll for xfer complete timeout\r\n",
3325                                                         __func__);
3326 #endif
3327                 goto Out;
3328         }
3329         /*
3330          * Clear Transfer Complete Interrupt in Interrupt Status Enable
3331          * Register
3332          */
3333         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3334                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3335
3336         /*
3337          * Clear Transfer Complete Interrupt in Interrupt Status Register
3338          */
3339         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3340                         XNANDPSU_INTR_STS_OFFSET,
3341                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3342
3343 Out:
3344         return Status;
3345 }
3346
3347 /*****************************************************************************/
3348 /**
3349 *
3350 * This function sends ONFI Set Feature command to flash.
3351 *
3352 * @param        InstancePtr is a pointer to the XNandPsu instance.
3353 * @param        Target is the chip select value.
3354 * @param        Feature is the feature selector.
3355 * @param        Buf is the feature value to send.
3356 *
3357 * @return
3358 *               - XST_SUCCESS if successful.
3359 *               - XST_FAILURE if failed.
3360 *
3361 * @note         None
3362 *
3363 ******************************************************************************/
3364 s32 XNandPsu_SetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature,
3365                                                                 u8 *Buf)
3366 {
3367         s32 Status;
3368         u32 Index;
3369         u32 PktSize = 4U;
3370         u32 PktCount = 1U;
3371         u32 *BufPtr = (u32 *)(void *)Buf;
3372
3373         /*
3374          * Assert the input arguments.
3375          */
3376         Xil_AssertNonvoid(Buf != NULL);
3377         if (InstancePtr->DataInterface == XNANDPSU_NVDDR) {
3378                 PktSize = 8U;
3379         }
3380
3381         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3382                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3383
3384         /*
3385          * Enable Buffer Write Ready Interrupt in Interrupt Status
3386          * Enable Register
3387          */
3388         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3389                         XNANDPSU_INTR_STS_EN_OFFSET,
3390                         XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
3391
3392         /*
3393          * Program Command
3394          */
3395         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_SET_FEATURES,
3396                                 ONFI_CMD_INVALID, 0U , 0U, 1U);
3397         /*
3398          * Program Column, Page, Block address
3399          */
3400         XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature);
3401         /*
3402          * Program Memory Address Register2 for chip select
3403          */
3404         XNandPsu_SelectChip(InstancePtr, Target);
3405         /*
3406          * Program Packet Size and Packet Count
3407          */
3408         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
3409         /*
3410          * Set Read Parameter Page in Program Register
3411          */
3412         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3413                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_SET_FEATURES_MASK);
3414         /*
3415          * Poll for Buffer Write Ready event
3416          */
3417         Status = XNandPsu_PollRegTimeout(
3418                 InstancePtr,
3419                 XNANDPSU_INTR_STS_OFFSET,
3420                 XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK,
3421                 XNANDPSU_INTR_POLL_TIMEOUT);
3422         if (Status != XST_SUCCESS) {
3423 #ifdef XNANDPSU_DEBUG
3424                 xil_printf("%s: Poll for buf write ready timeout\r\n",
3425                                                         __func__);
3426 #endif
3427                 goto Out;
3428         }
3429         /*
3430          * Clear Buffer Write Ready Interrupt in Interrupt Status Enable
3431          * Register
3432          */
3433         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3434                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3435
3436         /*
3437          * Clear Buffer Write Ready Interrupt in Interrupt Status Register
3438          */
3439         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3440                         XNANDPSU_INTR_STS_OFFSET,
3441                                 XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK);
3442         /*
3443          * Enable Transfer Complete Interrupt in Interrupt Status Enable
3444          * Register
3445          */
3446         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3447                         (XNANDPSU_INTR_STS_EN_OFFSET),
3448                         XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
3449         /*
3450          * Write Data to Data Port Register
3451          */
3452         for (Index = 0U; Index < (PktSize/4U); Index++) {
3453                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3454                                         XNANDPSU_BUF_DATA_PORT_OFFSET,
3455                                         BufPtr[Index]);
3456         }
3457         /*
3458          * Poll for Transfer Complete event
3459          */
3460         Status = XNandPsu_PollRegTimeout(
3461                         InstancePtr,
3462                         XNANDPSU_INTR_STS_OFFSET,
3463                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3464                         XNANDPSU_INTR_POLL_TIMEOUT);
3465         if (Status != XST_SUCCESS) {
3466 #ifdef XNANDPSU_DEBUG
3467                 xil_printf("%s: Poll for xfer complete timeout\r\n",
3468                                                         __func__);
3469 #endif
3470                 goto Out;
3471         }
3472         /*
3473          * Clear Transfer Complete Interrupt in Interrupt Status Enable
3474          * Register
3475          */
3476         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3477                         XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3478
3479         /*
3480          * Clear Transfer Complete Interrupt in Interrupt Status Register
3481          */
3482         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3483                         XNANDPSU_INTR_STS_OFFSET,
3484                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3485
3486 Out:
3487         return Status;
3488 }
3489
3490 /*****************************************************************************/
3491 /**
3492 *
3493 * This function changes clock frequency of flash controller.
3494 *
3495 * @param        InstancePtr is a pointer to the XNandPsu instance.
3496 * @param        ClockFreq is the clock frequency to change.
3497 *
3498 * @return
3499 *               None
3500 *
3501 * @note         None
3502 *
3503 ******************************************************************************/
3504 static void XNandPsu_ChangeClockFreq(XNandPsu *InstancePtr, u32 ClockFreq)
3505 {
3506         /*
3507          * Not implemented
3508          */
3509 }
3510 /*****************************************************************************/
3511 /**
3512 *
3513 * This function changes the data interface and timing mode.
3514 *
3515 * @param        InstancePtr is a pointer to the XNandPsu instance.
3516 * @param        NewIntf is the new data interface.
3517 * @param        NewMode is the new timing mode.
3518 *
3519 * @return
3520 *               - XST_SUCCESS if successful.
3521 *               - XST_FAILURE if failed.
3522 *
3523 * @note         None
3524 *
3525 ******************************************************************************/
3526 s32 XNandPsu_ChangeTimingMode(XNandPsu *InstancePtr,
3527                                 XNandPsu_DataInterface NewIntf,
3528                                 XNandPsu_TimingMode NewMode)
3529 {
3530         s32 Status;
3531         u32 Target;
3532         u32 Index;
3533         u32 Found = 0U;
3534         u32 RegVal;
3535         u8 Buf[4] = {0U};
3536         u32 *Feature = (u32 *)(void *)&Buf[0];
3537         u32 SetFeature = 0U;
3538         u32 NewModeVar = NewMode;
3539
3540         /*
3541          * Assert the input arguments.
3542          */
3543         Xil_AssertNonvoid(InstancePtr != NULL);
3544         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
3545
3546         /*
3547          * Check for valid input arguments
3548          */
3549         if((NewIntf != XNANDPSU_SDR && NewIntf != XNANDPSU_NVDDR) ||
3550                         (NewModeVar > 5U)){
3551                 Status = XST_FAILURE;
3552                 goto Out;
3553         }
3554
3555         if(NewIntf == XNANDPSU_NVDDR){
3556                 NewModeVar = NewModeVar | 0x10U;
3557         }
3558         /*
3559          * Get current data interface type and timing mode
3560          */
3561         XNandPsu_DataInterface CurIntf = InstancePtr->DataInterface;
3562         XNandPsu_TimingMode CurMode = InstancePtr->TimingMode;
3563
3564         /*
3565          * Check if the flash is in same mode
3566          */
3567         if ((CurIntf == NewIntf) && (CurMode == NewModeVar)) {
3568                 Status = XST_SUCCESS;
3569                 goto Out;
3570         }
3571
3572         if ((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_SDR)) {
3573
3574                 NewModeVar = XNANDPSU_SDR0;
3575
3576                 /*
3577                  * Change the clock frequency
3578                  */
3579                 XNandPsu_ChangeClockFreq(InstancePtr, XNANDPSU_SDR_CLK);
3580
3581                 /*
3582                  * Update Data Interface Register
3583                  */
3584                 RegVal = ((NewModeVar % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
3585                                 ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
3586                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3587                                         XNANDPSU_DATA_INTF_OFFSET, RegVal);
3588
3589                 for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
3590                                                         Target++) {
3591                         Status = XNandPsu_OnfiReset(InstancePtr, Target);
3592                         if (Status != XST_SUCCESS) {
3593                                 goto Out;
3594                         }
3595                 }
3596
3597                 /*
3598                  * Set Feature
3599                  */
3600                 for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
3601                                                                 Target++) {
3602                         Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
3603                                                         (u8 *)&NewModeVar);
3604                         if (Status != XST_SUCCESS) {
3605                                 goto Out;
3606                         }
3607                 }
3608
3609                 InstancePtr->DataInterface = NewIntf;
3610                 InstancePtr->TimingMode = NewModeVar;
3611
3612                 for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
3613                                                                 Target++) {
3614                         Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
3615                                                                 &Buf[0]);
3616                         if (Status != XST_SUCCESS) {
3617                                 goto Out;
3618                         }
3619                         /*
3620                          * Check if set_feature was successful
3621                          */
3622                         if ((u32)*Feature != (u32)NewModeVar) {
3623                                 Status = XST_FAILURE;
3624                                 goto Out;
3625                         }
3626                 }
3627
3628                 goto Out;
3629         }
3630
3631         SetFeature = NewModeVar;
3632         if(CurIntf == XNANDPSU_NVDDR && NewIntf == XNANDPSU_NVDDR){
3633                 SetFeature |= SetFeature << 8U;
3634         }
3635         /*
3636          * Set Feature
3637          */
3638         for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
3639                                                         Target++) {
3640                 Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U,
3641                                                 (u8 *)&SetFeature);
3642                 if (Status != XST_SUCCESS) {
3643                         goto Out;
3644                 }
3645         }
3646
3647         InstancePtr->DataInterface = NewIntf;
3648         InstancePtr->TimingMode = NewModeVar;
3649         /*
3650          * Update Data Interface Register
3651          */
3652         RegVal = ((NewMode % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) |
3653                         ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT);
3654         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3655                                 XNANDPSU_DATA_INTF_OFFSET, RegVal);
3656
3657         /*
3658          * Get Feature
3659          */
3660         for (Target = 0U; Target < InstancePtr->Geometry.NumTargets;
3661                                                         Target++) {
3662                 Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U,
3663                                                         &Buf[0]);
3664                 if (Status != XST_SUCCESS) {
3665                         goto Out;
3666                 }
3667
3668                 /*
3669                  * Check if set_feature was successful
3670                  */
3671                 if (*Feature != NewModeVar) {
3672                         Status = XST_FAILURE;
3673                         goto Out;
3674                 }
3675         }
3676
3677         Status = XST_SUCCESS;
3678 Out:
3679         return Status;
3680 }
3681
3682 /*****************************************************************************/
3683 /**
3684 *
3685 * This function issues change read column and reads the data into buffer
3686 * specified by user.
3687 *
3688 * @param        InstancePtr is a pointer to the XNandPsu instance.
3689 * @param        Target is the chip select value.
3690 * @param        Col is the coulmn address.
3691 * @param        PktSize is the number of bytes to read.
3692 * @param        PktCount is the number of transactions to read.
3693 * @param        Buf is the data buffer to fill in.
3694 *
3695 * @return
3696 *               - XST_SUCCESS if successful.
3697 *               - XST_FAILURE if failed.
3698 *
3699 * @note         None
3700 *
3701 ******************************************************************************/
3702 static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target,
3703                                         u32 Col, u32 PktSize, u32 PktCount,
3704                                         u8 *Buf)
3705 {
3706         u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
3707         u32 BufRdCnt = 0U;
3708         u32 *BufPtr = (u32 *)(void *)Buf;
3709         s32 Status = XST_FAILURE;
3710         u32 Index;
3711
3712         /*
3713          * Assert the input arguments.
3714          */
3715         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
3716         Xil_AssertNonvoid(Buf != NULL);
3717
3718         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3719                 /*
3720                  * Enable DMA boundary Interrupt in Interrupt Status
3721                  * Enable Register
3722                  */
3723                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3724                                 XNANDPSU_INTR_STS_EN_OFFSET,
3725                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
3726                                 XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK);
3727         } else {
3728                 /*
3729                  * Enable Buffer Read Ready Interrupt in Interrupt Status
3730                  * Enable Register
3731                  */
3732                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3733                                 XNANDPSU_INTR_STS_EN_OFFSET,
3734                                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
3735         }
3736         /*
3737          * Program Command
3738          */
3739         XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_CHNG_RD_COL1,
3740                         ONFI_CMD_CHNG_RD_COL2, 0U , 1U, (u8)AddrCycles);
3741         /*
3742          * Program Page Size
3743          */
3744         XNandPsu_SetPageSize(InstancePtr);
3745         /*
3746          * Program Column, Page, Block address
3747          */
3748         XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
3749         /*
3750          * Program Packet Size and Packet Count
3751          */
3752         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
3753         /*
3754          * Program DMA system address and DMA buffer boundary
3755          */
3756         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3757                 /*
3758                  * Invalidate the Data Cache
3759                  */
3760                 Xil_DCacheInvalidateRange((INTPTR)Buf, (PktSize * PktCount));
3761 #ifdef __aarch64__
3762                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3763                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
3764                                 (u32) (((INTPTR)Buf >> 32) & 0xFFFFFFFFU));
3765 #endif
3766                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3767                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
3768                                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
3769         }
3770         /*
3771          * Set Bus Width
3772          */
3773         XNandPsu_SetBusWidth(InstancePtr);
3774         /*
3775          * Program Memory Address Register2 for chip select
3776          */
3777         XNandPsu_SelectChip(InstancePtr, Target);
3778         /*
3779          * Set Read command in Program Register
3780          */
3781         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3782                         XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK);
3783
3784         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3785                 goto ReadDmaDone;
3786         }
3787
3788         while (BufRdCnt < PktCount) {
3789                 /*
3790                  * Poll for Buffer Read Ready event
3791                  */
3792                 Status = XNandPsu_PollRegTimeout(
3793                         InstancePtr,
3794                         XNANDPSU_INTR_STS_OFFSET,
3795                         XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK,
3796                         XNANDPSU_INTR_POLL_TIMEOUT);
3797                 if (Status != XST_SUCCESS) {
3798 #ifdef XNANDPSU_DEBUG
3799                         xil_printf("%s: Poll for buf read ready timeout\r\n",
3800                                                         __func__);
3801 #endif
3802                         goto Out;
3803                 }
3804                 /*
3805                  * Increment Buffer Read Interrupt Count
3806                  */
3807                 BufRdCnt++;
3808
3809                 if (BufRdCnt == PktCount) {
3810                         /*
3811                          * Enable Transfer Complete Interrupt in Interrupt
3812                          * Status Enable Register
3813                          */
3814                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3815                                 XNANDPSU_INTR_STS_EN_OFFSET,
3816                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
3817                 } else {
3818                         /*
3819                          * Clear Buffer Read Ready Interrupt in Interrupt
3820                          * Status Enable Register
3821                          */
3822                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3823                                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3824
3825                 }
3826                 /*
3827                  * Clear Buffer Read Ready Interrupt in Interrupt Status
3828                  * Register
3829                  */
3830                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3831                                 XNANDPSU_INTR_STS_OFFSET,
3832                                 XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK);
3833                 /*
3834                  * Read Packet Data from Data Port Register
3835                  */
3836                 for (Index = 0U; Index < (PktSize/4); Index++) {
3837                         BufPtr[Index] = XNandPsu_ReadReg(
3838                                                 InstancePtr->Config.BaseAddress,
3839                                                 XNANDPSU_BUF_DATA_PORT_OFFSET);
3840                 }
3841                 BufPtr += (PktSize/4U);
3842
3843                 if (BufRdCnt < PktCount) {
3844                         /*
3845                          * Enable Buffer Read Ready Interrupt in Interrupt
3846                          * Status Enable Register
3847                          */
3848                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3849                                 XNANDPSU_INTR_STS_EN_OFFSET,
3850                                 XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK);
3851                 } else {
3852                         break;
3853                 }
3854         }
3855 ReadDmaDone:
3856         /*
3857          * Poll for Transfer Complete event
3858          */
3859         Status = XNandPsu_PollRegTimeout(
3860                         InstancePtr,
3861                         XNANDPSU_INTR_STS_OFFSET,
3862                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
3863                         XNANDPSU_INTR_POLL_TIMEOUT);
3864         if (Status != XST_SUCCESS) {
3865 #ifdef XNANDPSU_DEBUG
3866                 xil_printf("%s: Poll for xfer complete timeout\r\n",
3867                                                         __func__);
3868 #endif
3869                 goto Out;
3870         }
3871         /*
3872          * Clear Transfer Complete Interrupt in Interrupt Status Enable
3873          * Register
3874          */
3875         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3876                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
3877
3878         /*
3879          * Clear Transfer Complete Interrupt in Interrupt Status Register
3880          */
3881         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3882                                 XNANDPSU_INTR_STS_OFFSET,
3883                                 XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
3884 Out:
3885         return Status;
3886 }
3887
3888 /*****************************************************************************/
3889 /**
3890 *
3891 * This function issues change read column and reads the data into buffer
3892 * specified by user.
3893 *
3894 * @param        InstancePtr is a pointer to the XNandPsu instance.
3895 * @param        Target is the chip select value.
3896 * @param        Col is the coulmn address.
3897 * @param        PktSize is the number of bytes to read.
3898 * @param        PktCount is the number of transactions to read.
3899 * @param        Buf is the data buffer to fill in.
3900 *
3901 * @return
3902 *               - XST_SUCCESS if successful.
3903 *               - XST_FAILURE if failed.
3904 *
3905 * @note         None
3906 *
3907 ******************************************************************************/
3908 static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target,
3909                                         u32 Col, u32 PktSize, u32 PktCount,
3910                                         u8 *Buf)
3911 {
3912         u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles;
3913         u32 BufWrCnt = 0U;
3914         u32 *BufPtr = (u32 *)(void *)Buf;
3915         s32 Status = XST_FAILURE;
3916         OnfiCmdFormat OnfiCommand;
3917         u32 Index;
3918
3919         /*
3920          * Assert the input arguments.
3921          */
3922         Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS);
3923         Xil_AssertNonvoid(Buf != NULL);
3924
3925         if (PktCount == 0U) {
3926                 return XST_SUCCESS;
3927         }
3928
3929         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3930                 /*
3931                  * Enable DMA boundary Interrupt in Interrupt Status
3932                  * Enable Register
3933                  */
3934                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3935                                 XNANDPSU_INTR_STS_EN_OFFSET,
3936                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK |
3937                                 XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK);
3938         } else {
3939                 /*
3940                  * Enable Buffer Write Ready Interrupt in Interrupt Status
3941                  * Enable Register
3942                  */
3943                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3944                                 XNANDPSU_INTR_STS_EN_OFFSET,
3945                                 XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
3946         }
3947         /*
3948          * Change write column hack
3949          */
3950         OnfiCommand.Command1 = 0x85U;
3951         OnfiCommand.Command2 = 0x10U;
3952         XNandPsu_Prepare_Cmd(InstancePtr, OnfiCommand.Command1,
3953                                 OnfiCommand.Command2, 0U , 0U, (u8)AddrCycles);
3954
3955         /*
3956          * Program Page Size
3957          */
3958         XNandPsu_SetPageSize(InstancePtr);
3959         /*
3960          * Program Column, Page, Block address
3961          */
3962         XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col);
3963         /*
3964          * Program Packet Size and Packet Count
3965          */
3966         XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount);
3967         /*
3968          * Program DMA system address and DMA buffer boundary
3969          */
3970         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3971 #ifdef __aarch64__
3972                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3973                                 XNANDPSU_DMA_SYS_ADDR1_OFFSET,
3974                                 (u32) (((INTPTR)Buf >> 32U) & 0xFFFFFFFFU));
3975 #endif
3976                 XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
3977                                 XNANDPSU_DMA_SYS_ADDR0_OFFSET,
3978                                 (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU));
3979         }
3980         /*
3981          * Set Bus Width
3982          */
3983         XNandPsu_SetBusWidth(InstancePtr);
3984         /*
3985          * Program Memory Address Register2 for chip select
3986          */
3987         XNandPsu_SelectChip(InstancePtr, Target);
3988         /*
3989          * Set Page Program in Program Register
3990          */
3991         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
3992                 XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_CHNG_ROW_ADDR_END_MASK);
3993
3994         if (InstancePtr->DmaMode == XNANDPSU_MDMA) {
3995                 goto WriteDmaDone;
3996         }
3997
3998         while (BufWrCnt < PktCount) {
3999                 /*
4000                  * Poll for Buffer Write Ready event
4001                  */
4002                 Status = XNandPsu_PollRegTimeout(
4003                         InstancePtr,
4004                         XNANDPSU_INTR_STS_OFFSET,
4005                         XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK,
4006                         XNANDPSU_INTR_POLL_TIMEOUT);
4007                 if (Status != XST_SUCCESS) {
4008 #ifdef XNANDPSU_DEBUG
4009                         xil_printf("%s: Poll for buf write ready timeout\r\n",
4010                                                         __func__);
4011 #endif
4012                         goto Out;
4013                 }
4014                 /*
4015                  * Increment Buffer Write Interrupt Count
4016                  */
4017                 BufWrCnt++;
4018
4019                 if (BufWrCnt == PktCount) {
4020                         /*
4021                          * Enable Transfer Complete Interrupt in Interrupt
4022                          * Status Enable Register
4023                          */
4024                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4025                                 XNANDPSU_INTR_STS_EN_OFFSET,
4026                                 XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK);
4027                 } else {
4028                         /*
4029                          * Clear Buffer Write Ready Interrupt in Interrupt
4030                          * Status Enable Register
4031                          */
4032                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4033                                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
4034                 }
4035                 /*
4036                  * Clear Buffer Write Ready Interrupt in Interrupt Status
4037                  * Register
4038                  */
4039                 XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4040                                 XNANDPSU_INTR_STS_OFFSET,
4041                                 XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK);
4042                 /*
4043                  * Write Packet Data to Data Port Register
4044                  */
4045                 for (Index = 0U; Index < (PktSize/4U); Index++) {
4046                         XNandPsu_WriteReg(InstancePtr->Config.BaseAddress,
4047                                                 XNANDPSU_BUF_DATA_PORT_OFFSET,
4048                                                 BufPtr[Index]);
4049                 }
4050                 BufPtr += (PktSize/4U);
4051
4052                 if (BufWrCnt < PktCount) {
4053                         /*
4054                          * Enable Buffer Write Ready Interrupt in Interrupt
4055                          * Status Enable Register
4056                          */
4057                         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4058                                 XNANDPSU_INTR_STS_EN_OFFSET,
4059                                 XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK);
4060                 } else {
4061                         break;
4062                 }
4063         }
4064 WriteDmaDone:
4065         /*
4066          * Poll for Transfer Complete event
4067          */
4068         Status = XNandPsu_PollRegTimeout(
4069                         InstancePtr,
4070                         XNANDPSU_INTR_STS_OFFSET,
4071                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK,
4072                         XNANDPSU_INTR_POLL_TIMEOUT);
4073         if (Status != XST_SUCCESS) {
4074 #ifdef XNANDPSU_DEBUG
4075                 xil_printf("%s: Poll for xfer complete timeout\r\n",
4076                                                         __func__);
4077 #endif
4078                 goto Out;
4079         }
4080         /*
4081          * Clear Transfer Complete Interrupt in Interrupt Status Enable
4082          * Register
4083          */
4084         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4085                 XNANDPSU_INTR_STS_EN_OFFSET, 0U);
4086
4087         /*
4088          * Clear Transfer Complete Interrupt in Interrupt Status Register
4089          */
4090         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4091                 XNANDPSU_INTR_STS_OFFSET,
4092                         XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK);
4093
4094 Out:
4095         return Status;
4096 }
4097
4098 /*****************************************************************************/
4099 /**
4100 *
4101 * This function initializes extended parameter page ECC information.
4102 *
4103 * @param        InstancePtr is a pointer to the XNandPsu instance.
4104 * @param        ExtPrm is the Extended parameter page buffer.
4105 *
4106 * @return
4107 *               - XST_SUCCESS if successful.
4108 *               - XST_FAILURE if failed.
4109 *
4110 * @note         None
4111 *
4112 ******************************************************************************/
4113 static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm)
4114 {
4115         s32 Status = XST_FAILURE;
4116         u32 Index;
4117         u32 SectionType;
4118         u32 SectionLen;
4119         u32 Offset = 0U;
4120         u32 Found = 0U;
4121         OnfiExtEccBlock *EccBlock;
4122
4123         if (ExtPrm->Section0Type != 0x2U) {
4124                 Offset += (u32)ExtPrm->Section0Len;
4125                 if (ExtPrm->Section1Type != 0x2U) {
4126 #ifdef XNANDPSU_DEBUG
4127                 xil_printf("%s: Extended ECC section not found\r\n",__func__);
4128 #endif
4129                         Status = XST_FAILURE;
4130                 } else {
4131                         Found = 1U;
4132                 }
4133         } else {
4134                 Found = 1U;
4135         }
4136
4137         if (Found != 0U) {
4138                 EccBlock = (OnfiExtEccBlock *)&ExtPrm->SectionData[Offset];
4139                 Xil_AssertNonvoid(EccBlock != NULL);
4140                 if (EccBlock->CodeWordSize == 0U) {
4141                         Status = XST_FAILURE;
4142                 } else {
4143                         InstancePtr->Geometry.NumBitsECC =
4144                                                 EccBlock->NumBitsEcc;
4145                         InstancePtr->Geometry.EccCodeWordSize =
4146                                                 (u32)EccBlock->CodeWordSize;
4147                         Status = XST_SUCCESS;
4148                 }
4149         }
4150         return Status;
4151 }
4152
4153 /*****************************************************************************/
4154 /**
4155 *
4156 * This function prepares command to be written into command register.
4157 *
4158 * @param        InstancePtr is a pointer to the XNandPsu instance.
4159 * @param        Cmd1 is the first Onfi Command.
4160 * @param        Cmd1 is the second Onfi Command.
4161 * @param        EccState is the flag to set Ecc State.
4162 * @param        DmaMode is the flag to set DMA mode.
4163 *
4164 * @return
4165 *               None
4166 *
4167 * @note         None
4168 *
4169 ******************************************************************************/
4170 void XNandPsu_Prepare_Cmd(XNandPsu *InstancePtr, u8 Cmd1, u8 Cmd2, u8 EccState,
4171                         u8 DmaMode, u8 AddrCycles)
4172 {
4173         u32 RegValue = 0U;
4174
4175         Xil_AssertVoid(InstancePtr != NULL);
4176
4177         RegValue = (u32)Cmd1 | (((u32)Cmd2 << (u32)XNANDPSU_CMD_CMD2_SHIFT) &
4178                         (u32)XNANDPSU_CMD_CMD2_MASK);
4179
4180         if ((EccState != 0U) && (InstancePtr->EccMode == XNANDPSU_HWECC)) {
4181                 RegValue |= 1U << XNANDPSU_CMD_ECC_ON_SHIFT;
4182         }
4183
4184         if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA)) {
4185                 RegValue |= XNANDPSU_MDMA << XNANDPSU_CMD_DMA_EN_SHIFT;
4186         }
4187
4188         if (AddrCycles != 0U) {
4189                 RegValue |= (u32)AddrCycles <<
4190                                 (u32)XNANDPSU_CMD_ADDR_CYCLES_SHIFT;
4191         }
4192
4193         XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress,
4194                         XNANDPSU_CMD_OFFSET, RegValue);
4195 }