1 /******************************************************************************
3 * Copyright (C) 2015 Xilinx, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
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
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.
31 ******************************************************************************/
32 /*****************************************************************************/
35 * @file xnandpsu_bbm.c
37 * This file implements the Bad Block Management (BBM) functionality.
38 * See xnandpsu_bbm.h for more details.
43 * MODIFICATION HISTORY:
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.
54 ******************************************************************************/
56 /***************************** Include Files *********************************/
57 #include <string.h> /**< For memcpy and memset */
58 #include "xil_types.h"
60 #include "xnandpsu_bbm.h"
62 /************************** Constant Definitions *****************************/
64 /**************************** Type Definitions *******************************/
66 /***************** Macros (Inline Functions) Definitions *********************/
68 /************************** Function Prototypes ******************************/
69 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target);
71 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
74 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target);
76 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target);
78 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
79 XNandPsu_BbtDesc *MirrorDesc, u32 Target);
81 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
84 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target);
86 /************************** Variable Definitions *****************************/
88 /*****************************************************************************/
90 * This function initializes the Bad Block Table(BBT) descriptors with a
91 * predefined pattern for searching Bad Block Table(BBT) in flash.
93 * @param InstancePtr is a pointer to the XNandPsu instance.
98 ******************************************************************************/
99 void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr)
103 Xil_AssertVoid(InstancePtr != NULL);
104 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
107 * Initialize primary Bad Block Table(BBT)
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;
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;
121 InstancePtr->BbtDesc.SigOffset =
122 XNANDPSU_BBT_DESC_SIG_OFFSET;
123 InstancePtr->BbtDesc.VerOffset =
124 XNANDPSU_BBT_DESC_VER_OFFSET;
127 InstancePtr->BbtDesc.SigOffset =
128 XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
129 InstancePtr->BbtDesc.VerOffset =
130 XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
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;
138 InstancePtr->BbtDesc.Valid = 0U;
141 * Assuming that the flash device will have at least 4 blocks.
143 if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
145 InstancePtr->BbtDesc.MaxBlocks = 4U;
149 * Initialize mirror Bad Block Table(BBT)
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;
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;
163 InstancePtr->BbtMirrorDesc.SigOffset =
164 XNANDPSU_BBT_DESC_SIG_OFFSET;
165 InstancePtr->BbtMirrorDesc.VerOffset =
166 XNANDPSU_BBT_DESC_VER_OFFSET;
169 InstancePtr->BbtMirrorDesc.SigOffset =
170 XNANDPSU_NO_OOB_BBT_DESC_SIG_OFFSET;
171 InstancePtr->BbtMirrorDesc.VerOffset =
172 XNANDPSU_NO_OOB_BBT_DESC_VER_OFFSET;
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;
180 InstancePtr->BbtMirrorDesc.Valid = 0U;
183 * Assuming that the flash device will have at least 4 blocks.
185 if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr->
186 BbtMirrorDesc.MaxBlocks){
187 InstancePtr->BbtMirrorDesc.MaxBlocks = 4U;
191 * Initialize Bad block search pattern structure
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;
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;
207 for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) {
208 InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN;
212 /*****************************************************************************/
214 * This function scans the NAND flash for factory marked bad blocks and creates
215 * a RAM based Bad Block Table(BBT).
217 * @param InstancePtr is a pointer to the XNandPsu instance.
222 ******************************************************************************/
223 static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target)
232 u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
233 u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
234 u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks;
238 * Number of pages to search for bad block pattern
240 if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U)
247 * Scan all the blocks for factory marked bad blocks
249 for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks);
252 * Block offset in Bad Block Table(BBT) entry
254 BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
256 * Block shift value in the byte
258 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
259 Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock;
261 * Search for the bad block pattern
263 for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) {
264 Status = XNandPsu_ReadSpareBytes(InstancePtr,
265 (Page + PageIndex), &Buf[0]);
267 if (Status != XST_SUCCESS) {
268 /* Marking as bad block */
269 InstancePtr->Bbt[BlockOffset] |=
270 (u8)(XNANDPSU_BLOCK_FACTORY_BAD <<
275 * Read the spare bytes to check for bad block
278 for(Length = 0U; Length <
279 InstancePtr->BbPattern.Length; Length++) {
280 if (Buf[InstancePtr->BbPattern.Offset + Length]
282 InstancePtr->BbPattern.Pattern[Length])
284 /* Bad block found */
285 InstancePtr->Bbt[BlockOffset] |=
287 (XNANDPSU_BLOCK_FACTORY_BAD <<
296 /*****************************************************************************/
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.
302 * @param InstancePtr is a pointer to the XNandPsu instance.
305 * - XST_SUCCESS if successful.
306 * - XST_FAILURE if fail.
308 ******************************************************************************/
309 s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr)
315 Xil_AssertNonvoid(InstancePtr != NULL);
316 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
319 * Zero the RAM based Bad Block Table(BBT) entries
321 BbtLen = InstancePtr->Geometry.NumBlocks >>
322 XNANDPSU_BBT_BLOCK_SHIFT;
323 memset(&InstancePtr->Bbt[0], 0, BbtLen);
325 for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) {
327 if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) {
329 * Create memory based Bad Block Table(BBT)
331 XNandPsu_CreateBbt(InstancePtr, Index);
333 * Write the Bad Block Table(BBT) to the flash
335 Status = XNandPsu_WriteBbt(InstancePtr,
336 &InstancePtr->BbtDesc,
337 &InstancePtr->BbtMirrorDesc, Index);
338 if (Status != XST_SUCCESS) {
342 * Write the Mirror Bad Block Table(BBT) to the flash
344 Status = XNandPsu_WriteBbt(InstancePtr,
345 &InstancePtr->BbtMirrorDesc,
346 &InstancePtr->BbtDesc, Index);
347 if (Status != XST_SUCCESS) {
351 * Mark the blocks containing Bad Block Table
354 Status = XNandPsu_MarkBbt(InstancePtr,
355 &InstancePtr->BbtDesc,
357 if (Status != XST_SUCCESS) {
360 Status = XNandPsu_MarkBbt(InstancePtr,
361 &InstancePtr->BbtMirrorDesc,
363 if (Status != XST_SUCCESS) {
369 Status = XST_SUCCESS;
374 /*****************************************************************************/
376 * This function converts the Bad Block Table(BBT) read from the flash to the
377 * RAM based Bad Block Table(BBT).
379 * @param InstancePtr is a pointer to the XNandPsu instance.
380 * @param Buf is the buffer which contains BBT read from flash.
385 ******************************************************************************/
386 static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target)
393 u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >>
394 XNANDPSU_BBT_BLOCK_SHIFT;
395 u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks;
397 for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen);
399 Data = *(Buf + BlockOffset);
401 * Clear the RAM based Bad Block Table(BBT) contents
403 InstancePtr->Bbt[BlockOffset] = 0x0U;
405 * Loop through the every 4 blocks in the bitmap
407 for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
409 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
410 BlockType = (u8) ((Data >> BlockShift) &
411 XNANDPSU_BLOCK_TYPE_MASK);
413 case XNANDPSU_FLASH_BLOCK_FAC_BAD:
414 /* Factory bad block */
415 InstancePtr->Bbt[BlockOffset] |=
417 (XNANDPSU_BLOCK_FACTORY_BAD <<
420 case XNANDPSU_FLASH_BLOCK_RESERVED:
422 InstancePtr->Bbt[BlockOffset] |=
424 (XNANDPSU_BLOCK_RESERVED <<
427 case XNANDPSU_FLASH_BLOCK_BAD:
428 /* Bad block due to wear */
429 InstancePtr->Bbt[BlockOffset] |=
430 (u8)(XNANDPSU_BLOCK_BAD <<
435 /* The BBT entry already defaults to
443 /*****************************************************************************/
445 * This function searches the Bad Bloock Table(BBT) in flash and loads into the
446 * memory based Bad Block Table(BBT).
448 * @param InstancePtr is the pointer to the XNandPsu instance.
450 * - XST_SUCCESS if successful.
451 * - XST_FAILURE if fail.
453 ******************************************************************************/
454 static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target)
457 u8 Buf[XNANDPSU_BBT_BUF_LENGTH]
458 __attribute__ ((aligned(64))) = {0U};
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;
473 * Search the Bad Block Table(BBT) in flash
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__);
481 Status = XST_FAILURE;
484 #ifdef XNANDPSU_DEBUG
485 xil_printf("%s: Bad block table found\r\n",__func__);
488 * Bad Block Table found
490 if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) {
492 * Valid BBT & Mirror BBT found
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,
499 if (Status != XST_SUCCESS) {
503 if (Desc->Option == XNANDPSU_BBT_NO_OOB){
504 BufPtr = BufPtr + Desc->VerOffset +
505 XNANDPSU_BBT_VERSION_LENGTH;
508 * Convert flash BBT to memory based BBT
510 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
511 MirrorDesc->Version[Target] = Desc->Version[Target];
514 * Write the BBT to Mirror BBT location in flash
516 Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc,
518 if (Status != XST_SUCCESS) {
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,
527 if (Status != XST_SUCCESS) {
530 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
531 BufPtr = BufPtr + Desc->VerOffset +
532 XNANDPSU_BBT_VERSION_LENGTH;
535 * Convert flash BBT to memory based BBT
537 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
538 Desc->Version[Target] = MirrorDesc->Version[Target];
541 * Write the Mirror BBT to BBT location in flash
543 Status = XNandPsu_WriteBbt(InstancePtr, Desc,
545 if (Status != XST_SUCCESS) {
549 /* Both are up-to-date */
550 Offset = (u64)Desc->PageOffset[Target] *
551 (u64)InstancePtr->Geometry.BytesPerPage;
552 Status = XNandPsu_Read(InstancePtr, Offset, BufLen,
554 if (Status != XST_SUCCESS) {
558 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
559 BufPtr = BufPtr + Desc->VerOffset +
560 XNANDPSU_BBT_VERSION_LENGTH;
564 * Convert flash BBT to memory based BBT
566 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
568 } else if (Desc->Valid != 0U) {
570 * Valid Primary BBT found
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) {
578 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
579 BufPtr = BufPtr + Desc->VerOffset +
580 XNANDPSU_BBT_VERSION_LENGTH;
583 * Convert flash BBT to memory based BBT
585 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
586 MirrorDesc->Version[Target] = Desc->Version[Target];
589 * Write the BBT to Mirror BBT location in flash
591 Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc,
593 if (Status != XST_SUCCESS) {
598 * Valid Mirror BBT found
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) {
606 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
607 BufPtr = BufPtr + Desc->VerOffset +
608 XNANDPSU_BBT_VERSION_LENGTH;
612 * Convert flash BBT to memory based BBT
614 XNandPsu_ConvertBbt(InstancePtr, &BufPtr[0], Target);
615 Desc->Version[Target] = MirrorDesc->Version[Target];
618 * Write the Mirror BBT to BBT location in flash
620 Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc,
622 if (Status != XST_SUCCESS) {
627 Status = XST_SUCCESS;
632 /*****************************************************************************/
634 * This function searches the BBT in flash.
636 * @param InstancePtr is the pointer to the XNandPsu instance.
637 * @param Desc is the BBT descriptor pattern to search.
640 * - XST_SUCCESS if successful.
641 * - XST_FAILURE if fail.
643 ******************************************************************************/
644 static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
653 u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U};
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;
667 * Read the last 4 blocks for Bad Block Table(BBT) signature
669 for(Block = 0U; Block < MaxBlocks; Block++) {
670 PageOff = (StartBlock - Block) *
671 InstancePtr->Geometry.PagesPerBlock;
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]);
678 Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]);
680 if (Status != XST_SUCCESS) {
684 * Check the Bad Block Table(BBT) signature
686 for(Offset = 0U; Offset < SigLength; Offset++) {
687 if (Buf[Offset + SigOffset] !=
688 (u8)(Desc->Signature[Offset]))
690 break; /* Check the next blocks */
693 if (Offset >= SigLength) {
695 * Bad Block Table(BBT) found
697 Desc->PageOffset[Target] = PageOff;
698 Desc->Version[Target] = Buf[VerOffset];
701 Status = XST_SUCCESS;
706 * Bad Block Table(BBT) not found
708 Status = XST_FAILURE;
713 /*****************************************************************************/
715 * This function writes Bad Block Table(BBT) from RAM to flash.
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.
722 * - XST_SUCCESS if successful.
723 * - XST_FAILURE if fail.
725 ******************************************************************************/
726 static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc,
727 XNandPsu_BbtDesc *MirrorDesc, u32 Target)
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};
744 u32 BbtLen = InstancePtr->Geometry.NumBlocks >>
745 XNANDPSU_BBT_BLOCK_SHIFT;
747 if (Desc->Option == XNANDPSU_BBT_NO_OOB) {
748 BufLen += Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH;
752 * Find a valid block to write the Bad Block Table(BBT)
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;
763 case XNANDPSU_BLOCK_BAD:
764 case XNANDPSU_BLOCK_FACTORY_BAD:
770 Desc->PageOffset[Target] = Block *
771 InstancePtr->Geometry.PagesPerBlock;
772 if (Desc->PageOffset[Target] !=
773 MirrorDesc->PageOffset[Target]) {
774 /* Free block found */
781 * Block not found for writing Bad Block Table(BBT)
783 if (Index >= Desc->MaxBlocks) {
784 #ifdef XNANDPSU_DEBUG
785 xil_printf("%s: Blocks unavailable for writing BBT\r\n",
788 Status = XST_FAILURE;
792 Block = Desc->PageOffset[Target] /
793 InstancePtr->Geometry.PagesPerBlock;
796 * Convert the memory based BBT to flash based table
798 memset(Buf, 0xff, BufLen);
800 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
801 BufPtr = BufPtr + Desc->VerOffset + XNANDPSU_BBT_VERSION_LENGTH;
804 * Loop through the number of blocks
806 for(BlockOffset = 0U; BlockOffset < BufLen; BlockOffset++) {
807 Data = InstancePtr->Bbt[BlockOffset];
809 * Calculate the bit mask for 4 blocks at a time in loop
811 for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS;
813 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
814 BufPtr[BlockOffset] &= ~(Mask[Data &
815 XNANDPSU_BLOCK_TYPE_MASK] <<
817 Data >>= XNANDPSU_BBT_BLOCK_SHIFT;
821 * Write the Bad Block Table(BBT) to flash
823 Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block);
824 if (Status != XST_SUCCESS) {
828 if(Desc->Option == XNANDPSU_BBT_NO_OOB){
830 * Copy the signature and version to the Buffer
832 memcpy(Buf + Desc->SigOffset, &Desc->Signature[0],
834 memcpy(Buf + Desc->VerOffset, &Desc->Version[Target], 1U);
836 * Write the Buffer to page offset
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) {
846 * Write the BBT to page offset
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) {
855 * Write the signature and version in the spare data area
857 memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage);
858 Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target],
860 if (Status != XST_SUCCESS) {
864 memcpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0],
866 memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U);
868 Status = XNandPsu_WriteSpareBytes(InstancePtr,
869 Desc->PageOffset[Target], &SpareBuf[0]);
870 if (Status != XST_SUCCESS) {
875 Status = XST_SUCCESS;
880 /*****************************************************************************/
882 * This function updates the primary and mirror Bad Block Table(BBT) in the
885 * @param InstancePtr is the pointer to the XNandPsu instance.
887 * - XST_SUCCESS if successful.
888 * - XST_FAILURE if fail.
890 ******************************************************************************/
891 static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target)
897 * Update the version number
899 Version = InstancePtr->BbtDesc.Version[Target];
900 InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version +
901 (u16)1) % (u16)256U);
903 Version = InstancePtr->BbtMirrorDesc.Version[Target];
904 InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version +
907 * Update the primary Bad Block Table(BBT) in flash
909 Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc,
910 &InstancePtr->BbtMirrorDesc,
912 if (Status != XST_SUCCESS) {
917 * Update the mirrored Bad Block Table(BBT) in flash
919 Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc,
920 &InstancePtr->BbtDesc,
922 if (Status != XST_SUCCESS) {
926 Status = XST_SUCCESS;
931 /*****************************************************************************/
933 * This function marks the block containing Bad Block Table as reserved
934 * and updates the BBT.
936 * @param InstancePtr is the pointer to the XNandPsu instance.
937 * @param Desc is the BBT descriptor pointer.
939 * - XST_SUCCESS if successful.
940 * - XST_FAILURE if fail.
942 ******************************************************************************/
943 static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc,
956 * Mark the last four blocks as Reserved
958 BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) -
959 Desc->MaxBlocks - (u32)1;
961 for(Index = 0U; Index < Desc->MaxBlocks; Index++) {
963 BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
964 BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
965 OldVal = InstancePtr->Bbt[BlockOffset];
966 NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED <<
968 InstancePtr->Bbt[BlockOffset] = NewVal;
970 if (OldVal != NewVal) {
977 * Update the BBT to flash
979 if (UpdateBbt != 0U) {
980 Status = XNandPsu_UpdateBbt(InstancePtr, Target);
981 if (Status != XST_SUCCESS) {
986 Status = XST_SUCCESS;
991 /*****************************************************************************/
994 * This function checks whether a block is bad or not.
996 * @param InstancePtr is the pointer to the XNandPsu instance.
998 * @param Block is the block number.
1001 * - XST_SUCCESS if successful.
1002 * - XST_FAILURE if fail.
1004 ******************************************************************************/
1005 s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block)
1013 Xil_AssertNonvoid(InstancePtr != NULL);
1014 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1015 Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
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;
1022 if ((BlockType != XNANDPSU_BLOCK_GOOD) &&
1023 (BlockType != XNANDPSU_BLOCK_RESERVED)) {
1024 Status = XST_SUCCESS;
1027 Status = XST_FAILURE;
1032 /*****************************************************************************/
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.
1037 * @param InstancePtr is the pointer to the XNandPsu instance.
1038 * @param Block is the block number.
1041 * - XST_SUCCESS if successful.
1042 * - XST_FAILURE if fail.
1044 ******************************************************************************/
1045 s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block)
1055 Xil_AssertNonvoid(InstancePtr != NULL);
1056 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1057 Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks);
1059 Target = Block / InstancePtr->Geometry.NumTargetBlocks;
1061 BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT;
1062 BlockShift = XNandPsu_BbtBlockShift(Block);
1063 Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */
1066 * Mark the block as bad in the RAM based Bad Block Table
1069 Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift);
1070 Data |= (XNANDPSU_BLOCK_BAD << BlockShift);
1072 InstancePtr->Bbt[BlockOffset] = Data;
1075 * Update the Bad Block Table(BBT) in flash
1077 if (OldVal != NewVal) {
1078 Status = XNandPsu_UpdateBbt(InstancePtr, Target);
1079 if (Status != XST_SUCCESS) {
1084 Status = XST_SUCCESS;