]> git.sur5r.net Git - freertos/blob
2410f7af646814d07be78ea823f9c1bcef35bcce
[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_bbm.c
36 *
37 * This file implements the Bad Block Management (BBM) functionality.
38 * See xnandpsu_bbm.h for more details.
39 *
40 * @note         None
41 *
42 * <pre>
43 * MODIFICATION HISTORY:
44 *
45 * Ver   Who    Date        Changes
46 * ----- ----   ----------  -----------------------------------------------
47 * 1.0   nm     05/06/2014  First release
48 * 2.0   sb     01/12/2015  Added support for writing BBT signature and version
49 *                          in page section by enabling XNANDPSU_BBT_NO_OOB.
50 *                          Modified Bbt Signature and Version Offset value for
51 *                          Oob and No-Oob region.
52 * </pre>
53 *
54 ******************************************************************************/
55
56 /***************************** Include Files *********************************/
57 #include <string.h>     /**< For memcpy and memset */
58 #include "xil_types.h"
59 #include "xnandpsu.h"
60 #include "xnandpsu_bbm.h"
61
62 /************************** Constant Definitions *****************************/
63
64 /**************************** Type Definitions *******************************/
65
66 /***************** Macros (Inline Functions) Definitions *********************/
67
68 /************************** Function Prototypes ******************************/
69 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target);
70
71 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
72                                                         u32 Target);
73
74 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target);
75
76 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target);
77
78 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
79                                 XNandPsu_BbtDesc *MirrorDesc, u32 Target);
80
81 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
82                                                         u32 Target);
83
84 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target);
85
86 /************************** Variable Definitions *****************************/
87
88 /*****************************************************************************/
89 /**
90 * This function initializes the Bad Block Table(BBT) descriptors with a
91 * predefined pattern for searching Bad Block Table(BBT) in flash.
92 *
93 * @param        InstancePtr is a pointer to the XNandPsu instance.
94 *
95 * @return
96 *               - NONE
97 *
98 ******************************************************************************/
99 void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr)
100 {
101         u32 Index;
102
103         Xil_AssertVoid(InstancePtr != NULL);
104         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
105
106         /*
107          * Initialize primary Bad Block Table(BBT)
108          */
109         InstancePtr->BbtDesc.Option = XNANDPSU_BBT_OOB;
110         for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
111                 InstancePtr->BbtDesc.PageOffset[Index] =
112                                                 XNANDPSU_BBT_DESC_PAGE_OFFSET;
113         }
114         if(InstancePtr->BbtDesc.Option == XNANDPSU_BBT_OOB) {
115                 if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
116                         InstancePtr->BbtDesc.SigOffset =
117                                                 XNANDPSU_ONDIE_SIG_OFFSET;
118                         InstancePtr->BbtDesc.VerOffset =
119                                                 XNANDPSU_ONDIE_VER_OFFSET;
120                 } else {
121                         InstancePtr->BbtDesc.SigOffset =
122                                                 XNANDPSU_BBT_DESC_SIG_OFFSET;
123                         InstancePtr->BbtDesc.VerOffset =
124                                                 XNANDPSU_BBT_DESC_VER_OFFSET;
125                 }
126         } else {
127                 InstancePtr->BbtDesc.SigOffset =
128                                         XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
129                 InstancePtr->BbtDesc.VerOffset =
130                                         XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
131         }
132         InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
133         InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
134         (void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0");
135         for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
136                 InstancePtr->BbtDesc.Version[Index] = 0U;
137         }
138         InstancePtr->BbtDesc.Valid = 0U;
139
140         /*
141          * Assuming that the flash device will have at least 4 blocks.
142          */
143         if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
144                                                         BbtDesc.MaxBlocks){
145                 InstancePtr->BbtDesc.MaxBlocks = 4U;
146         }
147
148         /*
149          * Initialize mirror Bad Block Table(BBT)
150          */
151         InstancePtr->BbtMirrorDesc.Option = XNANDPSU_BBT_OOB;
152         for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
153                 InstancePtr->BbtMirrorDesc.PageOffset[Index] =
154                                                 XNANDPSU_BBT_DESC_PAGE_OFFSET;
155         }
156         if(InstancePtr->BbtMirrorDesc.Option == XNANDPSU_BBT_OOB) {
157                 if (InstancePtr->EccMode == XNANDPSU_ONDIE) {
158                         InstancePtr->BbtMirrorDesc.SigOffset =
159                                                 XNANDPSU_ONDIE_SIG_OFFSET;
160                         InstancePtr->BbtMirrorDesc.VerOffset =
161                                                 XNANDPSU_ONDIE_VER_OFFSET;
162                 } else {
163                         InstancePtr->BbtMirrorDesc.SigOffset =
164                                                 XNANDPSU_BBT_DESC_SIG_OFFSET;
165                         InstancePtr->BbtMirrorDesc.VerOffset =
166                                                 XNANDPSU_BBT_DESC_VER_OFFSET;
167                 }
168         } else {
169                 InstancePtr->BbtMirrorDesc.SigOffset =
170                                         XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
171                 InstancePtr->BbtMirrorDesc.VerOffset =
172                                         XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
173         }
174         InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN;
175         InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS;
176         (void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB");
177         for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) {
178                 InstancePtr->BbtMirrorDesc.Version[Index] = 0U;
179         }
180         InstancePtr->BbtMirrorDesc.Valid = 0U;
181
182         /*
183          * Assuming that the flash device will have at least 4 blocks.
184          */
185         if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
186                                                 BbtMirrorDesc.MaxBlocks){
187                 InstancePtr->BbtMirrorDesc.MaxBlocks = 4U;
188         }
189
190         /*
191          * Initialize Bad block search pattern structure
192          */
193         if (InstancePtr->Geometry.BytesPerPage > 512U) {
194                 /* For flash page size > 512 bytes */
195                 InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
196                 InstancePtr->BbPattern.Offset =
197                         XNANDPSU_BB_PTRN_OFF_LARGE_PAGE;
198                 InstancePtr->BbPattern.Length =
199                         XNANDPSU_BB_PTRN_LEN_LARGE_PAGE;
200         } else {
201                 InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE;
202                 InstancePtr->BbPattern.Offset =
203                         XNANDPSU_BB_PTRN_OFF_SML_PAGE;
204                 InstancePtr->BbPattern.Length =
205                         XNANDPSU_BB_PTRN_LEN_SML_PAGE;
206         }
207         for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) {
208                 InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN;
209         }
210 }
211
212 /*****************************************************************************/
213 /**
214 * This function scans the NAND flash for factory marked bad blocks and creates
215 * a RAM based Bad Block Table(BBT).
216 *
217 * @param        InstancePtr is a pointer to the XNandPsu instance.
218 *
219 * @return
220 *               - NONE
221 *
222 ******************************************************************************/
223 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target)
224 {
225         u32 BlockIndex;
226         u32 PageIndex;
227         u32 Length;
228         u32 BlockOffset;
229         u8 BlockShift;
230         u32 NumPages;
231         u32 Page;
232         u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
233         u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
234         u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks;
235         s32 Status;
236
237         /*
238          * Number of pages to search for bad block pattern
239          */
240         if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U)
241         {
242                 NumPages = 2U;
243         } else {
244                 NumPages = 1U;
245         }
246         /*
247          * Scan all the blocks for factory marked bad blocks
248          */
249         for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks);
250                                                         BlockIndex++) {
251                 /*
252                  * Block offset in Bad Block Table(BBT) entry
253                  */
254                 BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
255                 /*
256                  * Block shift value in the byte
257                  */
258                 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
259                 Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock;
260                 /*
261                  * Search for the bad block pattern
262                  */
263                 for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) {
264                         Status = XNandPsu_ReadSpareBytes(InstancePtr,
265                                         (Page + PageIndex), &Buf[0]);
266
267                         if (Status != XST_SUCCESS) {
268                                 /* Marking as bad block */
269                                 InstancePtr->Bbt[BlockOffset] |=
270                                         (u8)(XNANDPSU_BLOCK_FACTORY_BAD <<
271                                          BlockShift);
272                                 break;
273                         }
274                         /*
275                          * Read the spare bytes to check for bad block
276                          * pattern
277                          */
278                         for(Length = 0U; Length <
279                                 InstancePtr->BbPattern.Length; Length++) {
280                                 if (Buf[InstancePtr->BbPattern.Offset + Length]
281                                                 !=
282                                         InstancePtr->BbPattern.Pattern[Length])
283                                 {
284                                         /* Bad block found */
285                                         InstancePtr->Bbt[BlockOffset] |=
286                                                 (u8)
287                                                 (XNANDPSU_BLOCK_FACTORY_BAD <<
288                                                  BlockShift);
289                                         break;
290                                 }
291                         }
292                 }
293         }
294 }
295
296 /*****************************************************************************/
297 /**
298 * This function reads the Bad Block Table(BBT) if present in flash. If not it
299 * scans the flash for detecting factory marked bad blocks and creates a bad
300 * block table and write the Bad Block Table(BBT) into the flash.
301 *
302 * @param        InstancePtr is a pointer to the XNandPsu instance.
303 *
304 * @return
305 *               - XST_SUCCESS if successful.
306 *               - XST_FAILURE if fail.
307 *
308 ******************************************************************************/
309 s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr)
310 {
311         s32 Status;
312         u32 Index;
313         u32 BbtLen;
314
315         Xil_AssertNonvoid(InstancePtr != NULL);
316         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
317
318         /*
319          * Zero the RAM based Bad Block Table(BBT) entries
320          */
321         BbtLen = InstancePtr->Geometry.NumBlocks >>
322                                         XNANDPSU_BBT_BLOCK_SHIFT;
323         memset(&InstancePtr->Bbt[0], 0, BbtLen);
324
325         for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) {
326
327                 if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) {
328                         /*
329                          * Create memory based Bad Block Table(BBT)
330                          */
331                         XNandPsu_CreateBbt(InstancePtr, Index);
332                         /*
333                          * Write the Bad Block Table(BBT) to the flash
334                          */
335                         Status = XNandPsu_WriteBbt(InstancePtr,
336                                         &InstancePtr->BbtDesc,
337                                         &InstancePtr->BbtMirrorDesc, Index);
338                         if (Status != XST_SUCCESS) {
339                                 goto Out;
340                         }
341                         /*
342                          * Write the Mirror Bad Block Table(BBT) to the flash
343                          */
344                         Status = XNandPsu_WriteBbt(InstancePtr,
345                                         &InstancePtr->BbtMirrorDesc,
346                                         &InstancePtr->BbtDesc, Index);
347                         if (Status != XST_SUCCESS) {
348                                 goto Out;
349                         }
350                         /*
351                          * Mark the blocks containing Bad Block Table
352                          * (BBT) as Reserved
353                          */
354                         Status = XNandPsu_MarkBbt(InstancePtr,
355                                                         &InstancePtr->BbtDesc,
356                                                         Index);
357                         if (Status != XST_SUCCESS) {
358                                 goto Out;
359                         }
360                         Status = XNandPsu_MarkBbt(InstancePtr,
361                                                 &InstancePtr->BbtMirrorDesc,
362                                                         Index);
363                         if (Status != XST_SUCCESS) {
364                                 goto Out;
365                         }
366                 }
367         }
368
369         Status = XST_SUCCESS;
370 Out:
371         return Status;
372 }
373
374 /*****************************************************************************/
375 /**
376 * This function converts the Bad Block Table(BBT) read from the flash to the
377 * RAM based Bad Block Table(BBT).
378 *
379 * @param        InstancePtr is a pointer to the XNandPsu instance.
380 * @param        Buf is the buffer which contains BBT read from flash.
381 *
382 * @return
383 *               - NONE.
384 *
385 ******************************************************************************/
386 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target)
387 {
388         u32 BlockOffset;
389         u8 BlockShift;
390         u32 Data;
391         u8 BlockType;
392         u32 BlockIndex;
393         u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >>
394                                         XNANDPSU_BBT_BLOCK_SHIFT;
395         u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
396
397         for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen);
398                                                 BlockOffset++) {
399                 Data = *(Buf + BlockOffset);
400                 /*
401                  * Clear the RAM based Bad Block Table(BBT) contents
402                  */
403                 InstancePtr->Bbt[BlockOffset] = 0x0U;
404                 /*
405                  * Loop through the every 4 blocks in the bitmap
406                  */
407                 for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
408                                 BlockIndex++) {
409                         BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
410                         BlockType = (u8) ((Data >> BlockShift) &
411                                 XNANDPSU_BLOCK_TYPE_MASK);
412                         switch(BlockType) {
413                                 case XNANDPSU_FLASH_BLOCK_FAC_BAD:
414                                         /* Factory bad block */
415                                         InstancePtr->Bbt[BlockOffset] |=
416                                                 (u8)
417                                                 (XNANDPSU_BLOCK_FACTORY_BAD <<
418                                                 BlockShift);
419                                         break;
420                                 case XNANDPSU_FLASH_BLOCK_RESERVED:
421                                         /* Reserved block */
422                                         InstancePtr->Bbt[BlockOffset] |=
423                                                 (u8)
424                                                 (XNANDPSU_BLOCK_RESERVED <<
425                                                 BlockShift);
426                                         break;
427                                 case XNANDPSU_FLASH_BLOCK_BAD:
428                                         /* Bad block due to wear */
429                                         InstancePtr->Bbt[BlockOffset] |=
430                                                 (u8)(XNANDPSU_BLOCK_BAD <<
431                                                 BlockShift);
432                                         break;
433                                 default:
434                                         /* Good block */
435                                         /* The BBT entry already defaults to
436                                          * zero */
437                                         break;
438                         }
439                 }
440         }
441 }
442
443 /*****************************************************************************/
444 /**
445 * This function searches the Bad Bloock Table(BBT) in flash and loads into the
446 * memory based Bad Block Table(BBT).
447 *
448 * @param        InstancePtr is the pointer to the XNandPsu instance.
449 * @return
450 *               - XST_SUCCESS if successful.
451 *               - XST_FAILURE if fail.
452 *
453 ******************************************************************************/
454 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target)
455 {
456         u64 Offset;
457         u8 Buf[XNANDPSU_BBT_BUF_LENGTH]
458                                          __attribute__ ((aligned(64))) = {0U};
459         s32 Status1;
460         s32 Status2;
461         s32 Status;
462         u32 BufLen;
463         u8 * BufPtr = Buf;
464
465         XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc;
466         XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc;
467         BufLen = InstancePtr->Geometry.NumBlocks >>
468                         XNANDPSU_BBT_BLOCK_SHIFT;
469         if (Desc->Option == XNANDPSU_BBT_NO_OOB) {
470                 BufLen += Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH;
471         }
472         /*
473          * Search the Bad Block Table(BBT) in flash
474          */
475         Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target);
476         Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target);
477         if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) {
478 #ifdef XNANDPSU_DEBUG
479                 xil_printf("%s: Bad block table not found\r\n",__func__);
480 #endif
481                 Status = XST_FAILURE;
482                 goto Out;
483         }
484 #ifdef XNANDPSU_DEBUG
485         xil_printf("%s: Bad block table found\r\n",__func__);
486 #endif
487         /*
488          * Bad Block Table found
489          */
490         if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) {
491                 /*
492                  * Valid BBT & Mirror BBT found
493                  */
494                 if (Desc->Version[Target] > MirrorDesc->Version[Target]) {
495                         Offset = (u64)Desc->PageOffset[Target] *
496                                 (u64)InstancePtr->Geometry.BytesPerPage;
497                         Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
498                                                                 &BufPtr[0]);
499                         if (Status != XST_SUCCESS) {
500                                 goto Out;
501                         }
502
503                         if (Desc->Option == XNANDPSU_BBT_NO_OOB){
504                                 BufPtr = BufPtr + Desc->VerOffset +
505                                                 XNANDPSU_BBT_VERSION_LENGTH;
506                         }
507                         /*
508                          * Convert flash BBT to memory based BBT
509                          */
510                         XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
511                         MirrorDesc->Version[Target] = Desc->Version[Target];
512
513                         /*
514                          * Write the BBT to Mirror BBT location in flash
515                          */
516                         Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc,
517                                                         Desc, Target);
518                         if (Status != XST_SUCCESS) {
519                                 goto Out;
520                         }
521                 } else if (Desc->Version[Target] <
522                                                 MirrorDesc->Version[Target]) {
523                         Offset = (u64)MirrorDesc->PageOffset[Target] *
524                                 (u64)InstancePtr->Geometry.BytesPerPage;
525                         Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
526                                                                 &BufPtr[0]);
527                         if (Status != XST_SUCCESS) {
528                                 goto Out;
529                         }
530                         if(Desc->Option == XNANDPSU_BBT_NO_OOB){
531                                 BufPtr = BufPtr + Desc->VerOffset +
532                                                 XNANDPSU_BBT_VERSION_LENGTH;
533                         }
534                         /*
535                          * Convert flash BBT to memory based BBT
536                          */
537                         XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
538                         Desc->Version[Target] = MirrorDesc->Version[Target];
539
540                         /*
541                          * Write the Mirror BBT to BBT location in flash
542                          */
543                         Status = XNandPsu_WriteBbt(InstancePtr, Desc,
544                                                         MirrorDesc, Target);
545                         if (Status != XST_SUCCESS) {
546                                 goto Out;
547                         }
548                 } else {
549                         /* Both are up-to-date */
550                         Offset = (u64)Desc->PageOffset[Target] *
551                                 (u64)InstancePtr->Geometry.BytesPerPage;
552                         Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
553                                                                 &BufPtr[0]);
554                         if (Status != XST_SUCCESS) {
555                                 goto Out;
556                         }
557
558                         if(Desc->Option == XNANDPSU_BBT_NO_OOB){
559                                 BufPtr = BufPtr + Desc->VerOffset +
560                                                 XNANDPSU_BBT_VERSION_LENGTH;
561                         }
562
563                         /*
564                          * Convert flash BBT to memory based BBT
565                          */
566                         XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
567                 }
568         } else if (Desc->Valid != 0U) {
569                 /*
570                  * Valid Primary BBT found
571                  */
572                 Offset = (u64)Desc->PageOffset[Target] *
573                         (u64)InstancePtr->Geometry.BytesPerPage;
574                 Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &BufPtr[0]);
575                 if (Status != XST_SUCCESS) {
576                         goto Out;
577                 }
578                 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
579                         BufPtr = BufPtr + Desc->VerOffset +
580                                 XNANDPSU_BBT_VERSION_LENGTH;
581                 }
582                 /*
583                  * Convert flash BBT to memory based BBT
584                  */
585                 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
586                 MirrorDesc->Version[Target] = Desc->Version[Target];
587
588                 /*
589                  * Write the BBT to Mirror BBT location in flash
590                  */
591                 Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc,
592                                                                 Target);
593                 if (Status != XST_SUCCESS) {
594                         goto Out;
595                 }
596         } else {
597                 /*
598                  * Valid Mirror BBT found
599                  */
600                 Offset = (u64)MirrorDesc->PageOffset[Target] *
601                         (u64)InstancePtr->Geometry.BytesPerPage;
602                 Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &BufPtr[0]);
603                 if (Status != XST_SUCCESS) {
604                         goto Out;
605                 }
606                 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
607                         BufPtr = BufPtr + Desc->VerOffset +
608                                 XNANDPSU_BBT_VERSION_LENGTH;
609                 }
610
611                 /*
612                  * Convert flash BBT to memory based BBT
613                  */
614                 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
615                 Desc->Version[Target] = MirrorDesc->Version[Target];
616
617                 /*
618                  * Write the Mirror BBT to BBT location in flash
619                  */
620                 Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc,
621                                                                 Target);
622                 if (Status != XST_SUCCESS) {
623                         goto Out;
624                 }
625         }
626
627         Status = XST_SUCCESS;
628 Out:
629         return Status;
630 }
631
632 /*****************************************************************************/
633 /**
634 * This function searches the BBT in flash.
635 *
636 * @param        InstancePtr is the pointer to the XNandPsu instance.
637 * @param        Desc is the BBT descriptor pattern to search.
638 *
639 * @return
640 *               - XST_SUCCESS if successful.
641 *               - XST_FAILURE if fail.
642 *
643 ******************************************************************************/
644 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
645                                                                 u32 Target)
646 {
647         u32 StartBlock;
648         u32 SigOffset;
649         u32 VerOffset;
650         u32 MaxBlocks;
651         u32 PageOff;
652         u32 SigLength;
653         u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
654         u32 Block;
655         u32 Offset;
656         s32 Status;
657         u64 BlockOff;
658
659         StartBlock = ((Target + (u32)1) *
660                                 InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
661         SigOffset = Desc->SigOffset;
662         VerOffset = Desc->VerOffset;
663         MaxBlocks = Desc->MaxBlocks;
664         SigLength = Desc->SigLength;
665
666         /*
667          * Read the last 4 blocks for Bad Block Table(BBT) signature
668          */
669         for(Block = 0U; Block < MaxBlocks; Block++) {
670                 PageOff = (StartBlock - Block) *
671                         InstancePtr->Geometry.PagesPerBlock;
672
673                 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
674                         BlockOff = (u64)PageOff * (u64)InstancePtr->Geometry.BytesPerPage;
675                         Status = XNandPsu_Read(InstancePtr, BlockOff,
676                                 Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH, &Buf[0]);
677                 }else{
678                         Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]);
679                 }
680                 if (Status != XST_SUCCESS) {
681                         continue;
682                 }
683                 /*
684                  * Check the Bad Block Table(BBT) signature
685                  */
686                 for(Offset = 0U; Offset < SigLength; Offset++) {
687                         if (Buf[Offset + SigOffset] !=
688                                 (u8)(Desc->Signature[Offset]))
689                         {
690                                 break; /* Check the next blocks */
691                         }
692                 }
693                 if (Offset >= SigLength) {
694                         /*
695                          * Bad Block Table(BBT) found
696                          */
697                         Desc->PageOffset[Target] = PageOff;
698                         Desc->Version[Target] = Buf[VerOffset];
699                         Desc->Valid = 1U;
700
701                         Status = XST_SUCCESS;
702                         goto Out;
703                 }
704         }
705         /*
706          * Bad Block Table(BBT) not found
707          */
708         Status = XST_FAILURE;
709 Out:
710         return Status;
711 }
712
713 /*****************************************************************************/
714 /**
715 * This function writes Bad Block Table(BBT) from RAM to flash.
716 *
717 * @param        InstancePtr is the pointer to the XNandPsu instance.
718 * @param        Desc is the BBT descriptor to be written to flash.
719 * @param        MirrorDesc is the mirror BBT descriptor.
720 *
721 * @return
722 *               - XST_SUCCESS if successful.
723 *               - XST_FAILURE if fail.
724 *
725 ******************************************************************************/
726 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
727                                 XNandPsu_BbtDesc *MirrorDesc, u32 Target)
728 {
729         u64 Offset;
730         u32 Block = {0U};
731         u32 EndBlock = ((Target + (u32)1) *
732                         InstancePtr->Geometry.NumTargetBlocks) - (u32)1;
733         u8 Buf[XNANDPSU_BBT_BUF_LENGTH]
734                                          __attribute__ ((aligned(64))) = {0U};
735         u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
736         u8 Mask[4] = {0x00U, 0x01U, 0x02U, 0x03U};
737         u8 Data;
738         u32 BlockOffset;
739         u8 BlockShift;
740         s32 Status;
741         u32 BlockIndex;
742         u32 Index;
743         u8 BlockType;
744         u32 BbtLen = InstancePtr->Geometry.NumBlocks >>
745                                                 XNANDPSU_BBT_BLOCK_SHIFT;
746         u32 BufLen = BbtLen;
747         if (Desc->Option == XNANDPSU_BBT_NO_OOB) {
748                 BufLen += Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH;
749         }
750         u8* BufPtr = Buf;
751         /*
752          * Find a valid block to write the Bad Block Table(BBT)
753          */
754         if ((!Desc->Valid) != 0U) {
755                 for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
756                         Block  = (EndBlock - Index);
757                         BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
758                         BlockShift = XNandPsu_BbtBlockShift(Block);
759                         BlockType = (InstancePtr->Bbt[BlockOffset] >>
760                                         BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
761                         switch(BlockType)
762                         {
763                                 case XNANDPSU_BLOCK_BAD:
764                                 case XNANDPSU_BLOCK_FACTORY_BAD:
765                                         continue;
766                                 default:
767                                         /* Good Block */
768                                         break;
769                         }
770                         Desc->PageOffset[Target] = Block *
771                                 InstancePtr->Geometry.PagesPerBlock;
772                         if (Desc->PageOffset[Target] !=
773                                         MirrorDesc->PageOffset[Target]) {
774                                 /* Free block found */
775                                 Desc->Valid = 1U;
776                                 break;
777                         }
778                 }
779
780                 /*
781                  * Block not found for writing Bad Block Table(BBT)
782                  */
783                 if (Index >= Desc->MaxBlocks) {
784 #ifdef XNANDPSU_DEBUG
785                 xil_printf("%s: Blocks unavailable for writing BBT\r\n",
786                                                                 __func__);
787 #endif
788                         Status = XST_FAILURE;
789                         goto Out;
790                 }
791         } else {
792                 Block = Desc->PageOffset[Target] /
793                                         InstancePtr->Geometry.PagesPerBlock;
794         }
795         /*
796          * Convert the memory based BBT to flash based table
797          */
798         memset(Buf, 0xff, BufLen);
799
800         if(Desc->Option == XNANDPSU_BBT_NO_OOB){
801                 BufPtr = BufPtr + Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH;
802         }
803         /*
804          * Loop through the number of blocks
805          */
806         for(BlockOffset = 0U; BlockOffset < BufLen; BlockOffset++) {
807                 Data = InstancePtr->Bbt[BlockOffset];
808                 /*
809                  * Calculate the bit mask for 4 blocks at a time in loop
810                  */
811                 for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
812                                 BlockIndex++) {
813                         BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
814                         BufPtr[BlockOffset] &= ~(Mask[Data &
815                                         XNANDPSU_BLOCK_TYPE_MASK] <<
816                                         BlockShift);
817                         Data >>= XNANDPSU_BBT_BLOCK_SHIFT;
818                 }
819         }
820         /*
821          * Write the Bad Block Table(BBT) to flash
822          */
823         Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block);
824         if (Status != XST_SUCCESS) {
825                 goto Out;
826         }
827
828         if(Desc->Option == XNANDPSU_BBT_NO_OOB){
829                 /*
830                  * Copy the signature and version to the Buffer
831                  */
832                 memcpy(Buf + Desc->SigOffset, &Desc->Signature[0],
833                                                         Desc->SigLength);
834                 memcpy(Buf + Desc->VerOffset, &Desc->Version[Target], 1U);
835                 /*
836                  * Write the Buffer to page offset
837                  */
838                 Offset = (u64)Desc->PageOffset[Target] *
839                                 (u64)InstancePtr->Geometry.BytesPerPage;
840                 Status = XNandPsu_Write(InstancePtr, Offset, BufLen, &Buf[0]);
841                 if (Status != XST_SUCCESS) {
842                         goto Out;
843                 }
844         }else{
845                 /*
846                  * Write the BBT to page offset
847                  */
848                 Offset = (u64)Desc->PageOffset[Target] *
849                                 (u64)InstancePtr->Geometry.BytesPerPage;
850                 Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]);
851                 if (Status != XST_SUCCESS) {
852                         goto Out;
853                 }
854                 /*
855                  * Write the signature and version in the spare data area
856                  */
857                 memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage);
858                 Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target],
859                                 &SpareBuf[0]);
860                 if (Status != XST_SUCCESS) {
861                         goto Out;
862                 }
863
864                 memcpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0],
865                                                         Desc->SigLength);
866                 memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U);
867
868                 Status = XNandPsu_WriteSpareBytes(InstancePtr,
869                                 Desc->PageOffset[Target], &SpareBuf[0]);
870                 if (Status != XST_SUCCESS) {
871                         goto Out;
872                 }
873         }
874
875         Status = XST_SUCCESS;
876 Out:
877         return Status;
878 }
879
880 /*****************************************************************************/
881 /**
882 * This function updates the primary and mirror Bad Block Table(BBT) in the
883 * flash.
884 *
885 * @param        InstancePtr is the pointer to the XNandPsu instance.
886 * @return
887 *               - XST_SUCCESS if successful.
888 *               - XST_FAILURE if fail.
889 *
890 ******************************************************************************/
891 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target)
892 {
893         s32 Status;
894         u8 Version;
895
896         /*
897          * Update the version number
898          */
899         Version = InstancePtr->BbtDesc.Version[Target];
900         InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version +
901                                                         (u16)1) % (u16)256U);
902
903         Version = InstancePtr->BbtMirrorDesc.Version[Target];
904         InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version +
905                                                         (u16)1) % (u16)256);
906         /*
907          * Update the primary Bad Block Table(BBT) in flash
908          */
909         Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc,
910                                                 &InstancePtr->BbtMirrorDesc,
911                                                 Target);
912         if (Status != XST_SUCCESS) {
913                 goto Out;
914         }
915
916         /*
917          * Update the mirrored Bad Block Table(BBT) in flash
918          */
919         Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc,
920                                                 &InstancePtr->BbtDesc,
921                                                 Target);
922         if (Status != XST_SUCCESS) {
923                 goto Out;
924         }
925
926         Status = XST_SUCCESS;
927 Out:
928         return Status;
929 }
930
931 /*****************************************************************************/
932 /**
933 * This function marks the block containing Bad Block Table as reserved
934 * and updates the BBT.
935 *
936 * @param        InstancePtr is the pointer to the XNandPsu instance.
937 * @param        Desc is the BBT descriptor pointer.
938 * @return
939 *               - XST_SUCCESS if successful.
940 *               - XST_FAILURE if fail.
941 *
942 ******************************************************************************/
943 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
944                                                                 u32 Target)
945 {
946         u32 BlockIndex;
947         u32 BlockOffset;
948         u8 BlockShift;
949         u8 OldVal;
950         u8 NewVal;
951         s32 Status;
952         u32 UpdateBbt = 0U;
953         u32 Index;
954
955         /*
956          * Mark the last four blocks as Reserved
957          */
958         BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) -
959                                                 Desc->MaxBlocks - (u32)1;
960
961         for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
962
963                 BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
964                 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
965                 OldVal = InstancePtr->Bbt[BlockOffset];
966                 NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED <<
967                                                         BlockShift));
968                 InstancePtr->Bbt[BlockOffset] = NewVal;
969
970                 if (OldVal != NewVal) {
971                         UpdateBbt = 1U;
972                 }
973                 BlockIndex++;
974         }
975
976         /*
977          * Update the BBT to flash
978          */
979         if (UpdateBbt != 0U) {
980                 Status = XNandPsu_UpdateBbt(InstancePtr, Target);
981                 if (Status != XST_SUCCESS) {
982                         goto Out;
983                 }
984         }
985
986         Status = XST_SUCCESS;
987 Out:
988         return Status;
989 }
990
991 /*****************************************************************************/
992 /**
993 *
994 * This function checks whether a block is bad or not.
995 *
996 * @param        InstancePtr is the pointer to the XNandPsu instance.
997 *
998 * @param        Block is the block number.
999 *
1000 * @return
1001 *               - XST_SUCCESS if successful.
1002 *               - XST_FAILURE if fail.
1003 *
1004 ******************************************************************************/
1005 s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block)
1006 {
1007         u8 Data;
1008         u8 BlockShift;
1009         u8 BlockType;
1010         u32 BlockOffset;
1011         s32 Status;
1012
1013         Xil_AssertNonvoid(InstancePtr != NULL);
1014         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1015         Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
1016
1017         BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
1018         BlockShift = XNandPsu_BbtBlockShift(Block);
1019         Data = InstancePtr->Bbt[BlockOffset];   /* Block information in BBT */
1020         BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
1021
1022         if ((BlockType != XNANDPSU_BLOCK_GOOD) &&
1023                 (BlockType != XNANDPSU_BLOCK_RESERVED)) {
1024                 Status = XST_SUCCESS;
1025         }
1026         else {
1027                 Status = XST_FAILURE;
1028         }
1029         return Status;
1030 }
1031
1032 /*****************************************************************************/
1033 /**
1034 * This function marks a block as bad in the RAM based Bad Block Table(BBT). It
1035 * also updates the Bad Block Table(BBT) in the flash.
1036 *
1037 * @param        InstancePtr is the pointer to the XNandPsu instance.
1038 * @param        Block is the block number.
1039 *
1040 * @return
1041 *               - XST_SUCCESS if successful.
1042 *               - XST_FAILURE if fail.
1043 *
1044 ******************************************************************************/
1045 s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block)
1046 {
1047         u8 Data;
1048         u8 BlockShift;
1049         u32 BlockOffset;
1050         u8 OldVal;
1051         u8 NewVal;
1052         s32 Status;
1053         u32 Target;
1054
1055         Xil_AssertNonvoid(InstancePtr != NULL);
1056         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1057         Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
1058
1059         Target = Block / InstancePtr->Geometry.NumTargetBlocks;
1060
1061         BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
1062         BlockShift = XNandPsu_BbtBlockShift(Block);
1063         Data = InstancePtr->Bbt[BlockOffset];   /* Block information in BBT */
1064
1065         /*
1066          * Mark the block as bad in the RAM based Bad Block Table
1067          */
1068         OldVal = Data;
1069         Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift);
1070         Data |= (XNANDPSU_BLOCK_BAD << BlockShift);
1071         NewVal = Data;
1072         InstancePtr->Bbt[BlockOffset] = Data;
1073
1074         /*
1075          * Update the Bad Block Table(BBT) in flash
1076          */
1077         if (OldVal != NewVal) {
1078                 Status = XNandPsu_UpdateBbt(InstancePtr, Target);
1079                 if (Status != XST_SUCCESS) {
1080                         goto Out;
1081                 }
1082         }
1083
1084         Status = XST_SUCCESS;
1085 Out:
1086         return Status;
1087 }