/** * \brief Writes the data and/or spare area of a page on a SkipBlock NandFlash. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param block Number of the block to write. * \param page Number of the page to write inside the given block. * \param data Data area buffer. * \param spare Spare area buffer. * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage(). */ uint8_t SkipBlockNandFlash_WritePage( const struct SkipBlockNandFlash *skipBlock, uint16_t block, uint16_t page, void *data, void *spare) { /* Check that the block is LIVE */ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { TRACE_ERROR("SkipBlockNandFlash_WritePage: Block is BAD.\n\r"); return NandCommon_ERROR_BADBLOCK; } /* Write data with ECC calculation */ return EccNandFlash_WritePage(ECC(skipBlock), block, page, data, spare); }
/** * \brief Reads the data and/or the spare area of a page on a SkipBlock nandflash. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param block Number of block to read page from. * \param page Number of page to read inside the given block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \note If one of the buffer pointer is 0, then the block MUST not be BAD. * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage(). */ uint8_t SkipBlockNandFlash_ReadPage( const struct SkipBlockNandFlash *skipBlock, uint16_t block, uint16_t page, void *data, void *spare) { #if !defined(OP_BOOTSTRAP_on) /* Check that the block is not BAD if data is requested */ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { TRACE_ERROR("SkipBlockNandFlash_ReadPage: Block is BAD.\n\r"); return NandCommon_ERROR_BADBLOCK; } /* Read data with ECC verification */ return EccNandFlash_ReadPage(ECC(skipBlock), block, page, data, spare); #else return RawNandFlash_ReadPage(RAW(skipBlock), block, page, data, spare); #endif }
/** * \brief Writes the data of a whole block on a SkipBlock nandflash. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param block Number of the block to write. * \param data Data area buffer. * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage(). */ uint8_t SkipBlockNandFlash_WriteBlock( const struct SkipBlockNandFlash *skipBlock, uint16_t block, void *data) { /* Number of pages per block */ uint32_t numPagesPerBlock; /* Page size */ uint32_t pageSize; /* Page index*/ uint16_t i; /* Error returned by SkipBlockNandFlash_WritePage*/ uint8_t error = 0; /* Retrieve model information*/ pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock)); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock)); /* Check that the block is LIVE*/ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r"); return NandCommon_ERROR_BADBLOCK; } for (i = 0; i < numPagesPerBlock; i++) { error = EccNandFlash_WritePage(ECC(skipBlock), block, i, data, 0); if (error) { TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block); return NandCommon_ERROR_CANNOTWRITE; } data = (void *) ((uint8_t *) data + pageSize); } return 0; }
/** * \brief Erases a block of a SkipBlock NandFlash. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param block Number of block to erase. * \return the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS. */ uint8_t SkipBlockNandFlash_EraseBlock( struct SkipBlockNandFlash *skipBlock, uint16_t block, uint32_t eraseType) { uint8_t error; const struct NandSpareScheme *scheme; uint8_t spare[NandCommon_MAXPAGESPARESIZE]; // TRACE_INFO("SkipBlockNandFlash_EraseBlock(%d)\n\r", block); if (eraseType != SCRUB_ERASE) { /* Check block status */ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { TRACE_INFO("SkipBlockNandFlash_EraseBlock: Block is BAD\n\r"); return NandCommon_ERROR_BADBLOCK; } } /* Erase block */ error = RawNandFlash_EraseBlock(RAW(skipBlock), block); if (error) { /* Try to mark the block as BAD */ TRACE_ERROR("SkipBlockNandFlash_EraseBlock: Cannot erase block, try to mark it BAD\n\r"); /* Retrieve model scheme */ scheme = NandFlashModel_GetScheme(MODEL(skipBlock)); memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE); NandSpareScheme_WriteBadBlockMarker(scheme, spare, NandBlockStatus_BAD_skip); return RawNandFlash_WritePage(RAW(skipBlock), block, 0, 0, spare); } return 0; }
/** * \brief Reads the data of a whole block on a SkipBlock nandflash. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param block Number of block to read page from. * \param page Number of page to read inside the given block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage(). */ unsigned char SkipBlockNandFlash_ReadBlock( const struct SkipBlockNandFlash *skipBlock, unsigned short block, void *data) { /* Number of pages per block */ unsigned int numPagesPerBlock, pageSize; /* Page index */ unsigned short i; /* Error returned by SkipBlockNandFlash_WritePage */ unsigned char error = 0; /* Retrieve model information */ pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock)); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock)); /* Check that the block is not BAD if data is requested */ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r"); return NandCommon_ERROR_BADBLOCK; } /* Read all the pages of the block */ for (i = 0; i < numPagesPerBlock; i++) { error = EccNandFlash_ReadPage(ECC(skipBlock), block, i, data, 0); if (error) { TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block); return error; } data = (void *) ((unsigned char *) data + pageSize); } return 0; }
//------------------------------------------------------------------------------ /// Applet main entry. This function decodes received command and executes it. /// \param argc always 1 /// \param argv Address of the argument area. //------------------------------------------------------------------------------ int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; unsigned int bufferSize, bufferAddr, memoryOffset; unsigned int bytesToWrite; unsigned int bytesRead = 0; unsigned int nbBadBlocks = 0; unsigned int nbBlocks = 0; // Temporary buffer used for non block aligned read / write unsigned int tempBufferAddr; unsigned short block, page, offset, i; // Index in source buffer during buffer copy unsigned int offsetInSourceBuff; // Index in destination buffer during buffer copy unsigned int offsetInTargetBuff; // Errors returned by SkipNandFlash functions unsigned char error = 0; // Configure the DBGU TRACE_CONFIGURE_ISP(DBGU_STANDARD, 115200, BOARD_MCK); // Configure SMC for Nandflash accesses (done each time applet is launched because of old ROM codes) BOARD_ConfigureNandFlash(nfBusWidth); PIO_Configure(pPinsNf, PIO_LISTSIZE(pPinsNf)); // ---------------------------------------------------------- // INIT: // ---------------------------------------------------------- if (pMailbox->command == APPLET_CMD_INIT) { // Save info of communication link comType = pMailbox->argument.inputInit.comType; #if (DYN_TRACES == 1) traceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- NandFlash applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("INIT command\n\r"); if (pPinsNf->pio == 0) { pMailbox->status = APPLET_NO_DEV; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; pMailbox->argument.outputInit.bufferAddress = (unsigned int) &end; TRACE_INFO("INIT command: No Nandflash defined for this board\n\r"); } else { memset(&skipBlockNf, 0, sizeof(skipBlockNf)); NandDisableInternalEcc(((struct RawNandFlash *) &skipBlockNf)); if (SkipBlockNandFlash_Initialize(&skipBlockNf, 0, cmdBytesAddr, addrBytesAddr, dataBytesAddr, nfCePin, nfRbPin)) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("\tDevice Unknown\n\r"); } else { // Check the data bus width of the NandFlash nfBusWidth = NandFlashModel_GetDataBusWidth((struct NandFlashModel *)&skipBlockNf); // Reconfigure bus width BOARD_ConfigureNandFlash(nfBusWidth); TRACE_INFO("\tNandflash driver initialized\n\r"); #if defined (at91sam3u) pMailbox->argument.outputInit.bufferAddress = 0x60000000; #elif defined (at91sam7se) pMailbox->argument.outputInit.bufferAddress = 0x21000000; #else pMailbox->argument.outputInit.bufferAddress = (unsigned int) &end; #endif // Get device parameters memSize = NandFlashModel_GetDeviceSizeInBytes(&skipBlockNf.ecc.raw.model); blockSize = NandFlashModel_GetBlockSizeInBytes(&skipBlockNf.ecc.raw.model); numBlocks = NandFlashModel_GetDeviceSizeInBlocks(&skipBlockNf.ecc.raw.model); pageSize = NandFlashModel_GetPageDataSize(&skipBlockNf.ecc.raw.model); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(&skipBlockNf.ecc.raw.model); pMailbox->status = APPLET_SUCCESS; pMailbox->argument.outputInit.bufferSize = blockSize; pMailbox->argument.outputInit.memorySize = memSize; TRACE_INFO("\t pageSize : 0x%x blockSize : 0x%x blockNb : 0x%x bus width : %d\n\r", pageSize, blockSize, numBlocks, nfBusWidth); TRACE_INFO("\t bufferAddr : 0x%x\n\r", (unsigned int) &end); } } } // ---------------------------------------------------------- // WRITE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_WRITE) { memoryOffset = pMailbox->argument.inputWrite.memoryOffset; bufferAddr = pMailbox->argument.inputWrite.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bytesToWrite = pMailbox->argument.inputWrite.bufferSize; TRACE_INFO("WRITE arguments : offset 0x%x, buffer at 0x%x, of 0x%x Bytes\n\r", memoryOffset, bufferAddr, bytesToWrite); pMailbox->argument.outputWrite.bytesWritten = 0; // Check word alignment if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } // Retrieve page and block addresses if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bytesToWrite, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } TRACE_INFO("WRITE at block 0x%x, page 0x%x, offset in page 0x%x\n\r", block, page, offset); if (page || offset || (bytesToWrite < blockSize)) { // We are not block aligned, retrieve block content to update it memset((unsigned int *)tempBufferAddr, 0xFF, blockSize); error = SkipBlockNandFlash_ReadBlock(&skipBlockNf, block, (unsigned int *)tempBufferAddr); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } // Fill retrieved block with data to be programmed offsetInTargetBuff = (page * pageSize) + offset; offsetInSourceBuff = 0; while ((offsetInTargetBuff < blockSize) && (bytesToWrite > 0)) { *(unsigned int *)(tempBufferAddr + offsetInTargetBuff) = *(unsigned int *)(bufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesToWrite -= 4; } } else { // Write a full and aligned block tempBufferAddr = bufferAddr; bytesToWrite = 0; } // Erase target block error = SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, NORMAL_ERASE); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } // Write target block error = SkipBlockNandFlash_WriteBlock(&skipBlockNf, block, (unsigned int *)tempBufferAddr); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputWrite.bytesWritten = pMailbox->argument.inputWrite.bufferSize - bytesToWrite; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // READ: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_READ) { memoryOffset = pMailbox->argument.inputRead.memoryOffset; bufferAddr = pMailbox->argument.inputRead.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bufferSize = pMailbox->argument.inputRead.bufferSize; TRACE_INFO("READ at offset: 0x%x buffer at : 0x%x of: 0x%x Bytes\n\r", memoryOffset, bufferAddr, bufferSize); pMailbox->argument.outputRead.bytesRead = 0; // Check word alignment if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } // Retrieve page and block addresses if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bufferSize, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } TRACE_INFO("READ at block 0x%x, page 0x%x, offset in page 0x%x\n\r", block, page, offset); if (page || offset) { memset((unsigned int *)tempBufferAddr, 0xFF, blockSize); error = SkipBlockNandFlash_ReadBlock(&skipBlockNf, block, (unsigned int *)tempBufferAddr); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } // Fill dest buffer with read data offsetInSourceBuff = (page * pageSize) + offset; offsetInTargetBuff = 0; while ((offsetInSourceBuff < blockSize) && (offsetInTargetBuff < blockSize) && (bytesRead < bufferSize)) { *(unsigned int *)(bufferAddr + offsetInTargetBuff) = *(unsigned int *)(tempBufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesRead += 4; } pMailbox->argument.outputRead.bytesRead = bytesRead; pMailbox->status = APPLET_SUCCESS; } else { memset((unsigned int *)bufferAddr, 0xFF, blockSize); error = SkipBlockNandFlash_ReadBlock(&skipBlockNf, block, (unsigned int *)bufferAddr); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputRead.bytesRead = bufferSize; pMailbox->status = APPLET_SUCCESS; } } // ---------------------------------------------------------- // FULL ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_FULL_ERASE) { TRACE_INFO("FULL ERASE command\n\r"); TRACE_INFO("\tForce erase flag: 0x%x\n\r", pMailbox->argument.inputFullErase.eraseType); for (i = 0; i < numBlocks; i++) { // Erase the block if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputFullErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", i); } } TRACE_INFO("Full Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // BATCH FULL ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_BATCH_ERASE) { TRACE_INFO("BATCH ERASE command\n\r"); block = pMailbox->argument.inputBatchErase.batch * (numBlocks / ERASE_BATCH); TRACE_INFO("Erase block from #%d to #%d\n\r", block, block + (numBlocks / ERASE_BATCH)); for (i = block ; i < block + (numBlocks / ERASE_BATCH) ; i++) { // Erase the block if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputBatchErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", i); } } if ((pMailbox->argument.inputBatchErase.batch + 1) == ERASE_BATCH) { TRACE_INFO("Full Erase achieved, erase type is %d\n\r", pMailbox->argument.inputBatchErase.eraseType); pMailbox->argument.outputBatchErase.nextBatch = 0; } else { pMailbox->argument.outputBatchErase.nextBatch = pMailbox->argument.inputBatchErase.batch + 1; TRACE_INFO("Batch Erase achieved\n\r"); } pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // FULL ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_ERASE_BLOCKS) { TRACE_INFO("BLOCKS ERASE command\n\r"); memoryOffset = pMailbox->argument.inputBlocksErase.memoryOffsetStart; if ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd > memSize) || (pMailbox->argument.inputBlocksErase.memoryOffsetEnd < memoryOffset) ) { TRACE_INFO("Out of memory space\n\r"); pMailbox->status = APPLET_ERASE_FAIL; goto exit; } nbBlocks = ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd- memoryOffset)/ blockSize) + 1; TRACE_INFO("Erase blocks from %d to %d \n\r", memoryOffset / blockSize, (memoryOffset / blockSize)+ nbBlocks ); // Erase blocks for (i = memoryOffset / blockSize; i < memoryOffset / blockSize + nbBlocks ; i++) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i , NORMAL_ERASE)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", i); } } TRACE_INFO("Blocks Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // LIST BAD BLOCKS: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_LIST_BAD_BLOCKS) { TRACE_INFO("LIST BAD BLOCKS command\n\r"); nbBadBlocks = 0; bufferAddr = (unsigned int) &end; pMailbox->argument.outputListBadBlocks.bufferAddress = bufferAddr; for (i = 0; i < numBlocks; i++) { // Erase the page if (SkipBlockNandFlash_CheckBlock(&skipBlockNf, i) == BADBLOCK) { nbBadBlocks++; *((unsigned int *)bufferAddr) = i; bufferAddr += 4; TRACE_INFO("Found block #%d BAD\n\r", i); } } TRACE_INFO("LIST BAD BLOCKS achieved\n\r"); pMailbox->argument.outputListBadBlocks.nbBadBlocks = nbBadBlocks; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // TAG BLOCK: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_TAG_BLOCK) { TRACE_INFO("TAG BLOCK command\n\r"); bufferAddr = (unsigned int) &end; block = pMailbox->argument.inputTagBlock.blockId; // To tag the block as good, just erase it without bad block check if ((unsigned char)pMailbox->argument.inputTagBlock.tag == 0xFF) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, SCRUB_ERASE)) { TRACE_INFO("Cannot erase block %d\n\r", block); pMailbox->status = APPLET_FAIL; goto exit; } } else { for (i = 0; i < 2; i++) { // Start by reading the spare memset((unsigned char *)bufferAddr, 0xFF, NandCommon_MAXSPAREECCBYTES); TRACE_INFO("Tag to write : 0x%x\n\r", (unsigned char)pMailbox->argument.inputTagBlock.tag); NandSpareScheme_WriteBadBlockMarker((struct NandSpareScheme *)(NandFlashModel_GetScheme((struct NandFlashModel *)(&skipBlockNf))), (unsigned char *)bufferAddr, ((unsigned char)pMailbox->argument.inputTagBlock.tag)); if (RawNandFlash_WritePage((struct RawNandFlash *)(&skipBlockNf), block, i, 0, (unsigned char *)bufferAddr)) { TRACE_ERROR("Failed to write spare data of page %d of block %d\n\r", i, block); pMailbox->status = APPLET_FAIL; goto exit; } } } TRACE_INFO("TAG BLOCK achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } exit : // Acknowledge the end of command TRACE_INFO("\tEnd of applet (command : %x --- status : %x)\n\r", pMailbox->command, pMailbox->status); // Notify the host application of the end of the command processing pMailbox->command = ~(pMailbox->command); // Send ACK character if (comType == DBGU_COM_TYPE) { DBGU_PutChar(0x6); } return 0; }
/** * \brief Initializes a SkipBlockNandFlash instance. Scans the device to retrieve or * create block status information. * * \param skipBlock Pointer to a SkipBlockNandFlash instance. * \param model Pointer to the underlying nand chip model. Can be 0. * \param commandAddress Address at which commands are sent. * \param addressAddress Address at which addresses are sent. * \param dataAddress Address at which data is sent. * \param pinChipEnable Pin controlling the CE signal of the NandFlash. * \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand. */ uint8_t SkipBlockNandFlash_Initialize( struct SkipBlockNandFlash *skipBlock, const struct NandFlashModel *model, uint32_t commandAddress, uint32_t addressAddress, uint32_t dataAddress, const Pin pinChipEnable, const Pin pinReadyBusy) { uint8_t error; #if !defined(OP_BOOTSTRAP_on) uint32_t numBlocks; uint32_t block; #endif TRACE_DEBUG("SkipBlockNandFlash_Initialize()\n\r"); /* Initialize SkipBlockNandFlash */ #if !defined(OP_BOOTSTRAP_on) error = EccNandFlash_Initialize(ECC(skipBlock), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy); #else error = RawNandFlash_Initialize(RAW(skipBlock), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy); #endif #if !defined(OP_BOOTSTRAP_on) if (error) { return error; } /* Retrieve model information */ numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(skipBlock)); /* Initialize block statuses */ TRACE_DEBUG("Retrieving bad block information ...\n\r"); /* Retrieve block status from their first page spare area */ for (block = 0; block < numBlocks; block++) { /* Read spare of first page */ error = SkipBlockNandFlash_CheckBlock(skipBlock, block); if (error != GOODBLOCK) { if (error == BADBLOCK) { TRACE_DEBUG("Block #%d is bad\n\r", (unsigned int)block); } else { TRACE_ERROR( "SkipBlockNandFlash_Initialize: Cannot retrieve info from block #%u\n\r",(unsigned int) block); } } } #endif return 0; }
/** * \brief Applet main entry. This function decodes received command and executes it. * * \param argc always 1 * \param argv Address of the argument area.. */ int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; uint32_t bufferSize, bufferAddr, memoryOffset, bytesToWrite; uint16_t pagesToWrite, pagesToRead; uint32_t bytesWritten = 0; uint32_t bytesRead = 0; uint32_t nbBadBlocks = 0; uint32_t nbBlocks = 0; /* Temporary buffer used for non block aligned read / write */ uint32_t tempBufferAddr; uint16_t block, page, offset, i; uint8_t unAlignedPage; /* Index in source buffer during buffer copy */ uint32_t offsetInSourceBuff; /* Index in destination buffer during buffer copy */ uint32_t offsetInTargetBuff; /* Errors returned by SkipNandFlash functions */ uint8_t error = 0; /* Global DMA driver instance for all DMA transfers in application. */ sDmad dmad; /*---------------------------------------------------------- * INIT: *----------------------------------------------------------*/ if (pMailbox->command == APPLET_CMD_INIT) { /* Save info of communication link */ comType = pMailbox->argument.inputInit.comType; /* Re-configurate UART (MCK maybe change in LowLevelInit()) */ UART_Configure(115200, BOARD_MCK); #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- NandFlash SAM-BA applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); TRACE_INFO("INIT command\n\r"); /* Initialize DMA driver instance with polling mode */ DMAD_Initialize( &dmad, 1 ); if ( NandFlashConfigureDmaChannels( &dmad )) { TRACE_INFO ("-E- Initialize DMA failed !"); } TRACE_INFO ("-I- Initialize DMA done.\n\r"); /* Configure SMC for Nandflash accesses */ BOARD_ConfigureNandFlash(SMC); PIO_PinConfigure(pPinsNf, PIO_LISTSIZE(pPinsNf)); if (pPinsNf->pio == 0) { pMailbox->status = APPLET_NO_DEV; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; pMailbox->argument.outputInit.bufferAddress = (uint32_t) &end; TRACE_INFO("INIT command: No Nandflash defined for this board\n\r"); } else { memset(&skipBlockNf, 0, sizeof(skipBlockNf)); if (SkipBlockNandFlash_Initialize(&skipBlockNf, 0, cmdBytesAddr, addrBytesAddr, dataBytesAddr, nfCePin, nfRbPin)) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("\tDevice Unknown\n\r"); } else { TRACE_INFO("\tNandflash driver initialized\n\r"); /* Get device parameters */ memSize = NandFlashModel_GetDeviceSizeInBytes(&skipBlockNf.ecc.raw.model); blockSize = NandFlashModel_GetBlockSizeInBytes(&skipBlockNf.ecc.raw.model); numBlocks = NandFlashModel_GetDeviceSizeInBlocks(&skipBlockNf.ecc.raw.model); pageSize = NandFlashModel_GetPageDataSize(&skipBlockNf.ecc.raw.model); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(&skipBlockNf.ecc.raw.model); latestErasedBlock = 0xFFFF; pMailbox->status = APPLET_SUCCESS; pMailbox->argument.outputInit.bufferAddress = (uint32_t)EBI_SDRAMC_ADDR; pMailbox->argument.outputInit.bufferSize = blockSize; pMailbox->argument.outputInit.memorySize = memSize; TRACE_INFO("\t pageSize : 0x%x blockSize : 0x%x blockNb : 0x%x \n\r", (unsigned int)pageSize, (unsigned int)blockSize, (unsigned int)numBlocks); } } } /*---------------------------------------------------------- * WRITE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_WRITE) { memoryOffset = pMailbox->argument.inputWrite.memoryOffset; bufferAddr = pMailbox->argument.inputWrite.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bytesToWrite = pMailbox->argument.inputWrite.bufferSize; unAlignedPage = 0; TRACE_INFO("WRITE arguments : offset 0x%x, buffer at 0x%x, of 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr, (unsigned int)bytesToWrite); pMailbox->argument.outputWrite.bytesWritten = 0; /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } /* Retrieve page and block addresses */ if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bytesToWrite, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } if (block != latestErasedBlock ){ /* Erase target block */ error = SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, NORMAL_ERASE); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } latestErasedBlock = block; latestErasedPage = 0xff; } if (page <= ((uint8_t)(latestErasedPage + 1))){ error = SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, NORMAL_ERASE); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } latestErasedBlock = block; latestErasedPage = page; } offsetInSourceBuff = 0; TRACE_INFO("WRITE at block 0x%x, page 0x%x, offset 0x%x in page \n\r", (unsigned int)block, (unsigned int)page, (unsigned int)offset); if (offset ) { /* We are not page aligned. */ offsetInTargetBuff = offset; memset((uint32_t *)tempBufferAddr, 0xFF, pageSize); while (offsetInTargetBuff < pageSize) { *(uint32_t *)(tempBufferAddr + offsetInTargetBuff) = *(uint32_t *)(bufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesWritten += 4; } error = SkipBlockNandFlash_WritePage(&skipBlockNf, block, page, ( void *)tempBufferAddr ,0); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } unAlignedPage++; } pagesToWrite = (bytesToWrite - bytesWritten) / pageSize; if (bytesToWrite - ((pagesToWrite + unAlignedPage) * pageSize)) { pagesToWrite++; } if ((pagesToWrite + page ) > numPagesPerBlock) { pagesToWrite = numPagesPerBlock - page; } /* Write target block */ error = SkipBlockNandFlash_WriteBlockUnaligned(&skipBlockNf, block, (page + unAlignedPage), pagesToWrite, ( void *)(bufferAddr + offsetInSourceBuff)); bytesWritten += pagesToWrite * pageSize; if (bytesWritten > bytesToWrite) { bytesWritten = bytesToWrite; } if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputWrite.bytesWritten = bytesWritten; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * READ: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_READ) { memoryOffset = pMailbox->argument.inputRead.memoryOffset; bufferAddr = pMailbox->argument.inputRead.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bufferSize = pMailbox->argument.inputRead.bufferSize; TRACE_INFO("READ at offset: 0x%x buffer at : 0x%x of: 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr, (unsigned int)bufferSize); pMailbox->argument.outputRead.bytesRead = 0; unAlignedPage = 0; /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } /* Retrieve page and block addresses */ if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bufferSize, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } TRACE_INFO("READ at block 0x%x, page 0x%x, offset in page 0x%x\n\r", (unsigned int)block, (unsigned int)page, (unsigned int)offset); offsetInTargetBuff = 0; if (offset) { memset((uint32_t *)tempBufferAddr, 0xFF, pageSize); error = SkipBlockNandFlash_ReadPage(&skipBlockNf, block, page, ( void *)tempBufferAddr ,0); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } /* Fill dest buffer with read data */ offsetInSourceBuff = offset; while (offsetInSourceBuff < pageSize) { *(uint32_t *)(bufferAddr + offsetInTargetBuff) = *(uint32_t *)(tempBufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesRead += 4; } unAlignedPage++; } pagesToRead = (bufferSize - bytesRead) / pageSize; if (bufferSize - ((pagesToRead + unAlignedPage)* pageSize)) { pagesToRead++; } if ((pagesToRead + page ) > numPagesPerBlock) { pagesToRead = numPagesPerBlock - page; } /* Read target block */ error = SkipBlockNandFlash_ReadBlockUnaligned(&skipBlockNf, block, (page + unAlignedPage), pagesToRead, ( void *)(bufferAddr + offsetInTargetBuff)); bytesRead += pagesToRead * pageSize; if (bytesRead > bufferSize) { bytesRead = bufferSize; } if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputRead.bytesRead = bytesRead; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * FULL ERASE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_FULL_ERASE) { TRACE_INFO("FULL ERASE command\n\r"); TRACE_INFO("\tForce erase flag: 0x%x\n\r", (unsigned int)pMailbox->argument.inputFullErase.eraseType); for (i = 0; i < numBlocks; i++) { /* Erase the page */ if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputFullErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } TRACE_INFO("Full Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * BATCH FULL ERASE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_BATCH_ERASE) { TRACE_INFO("BATCH ERASE command\n\r"); block = pMailbox->argument.inputBatchErase.batch * (numBlocks / ERASE_BATCH); TRACE_INFO("Erase block from #%d to #%d\n\r", (unsigned int)block, (unsigned int)(block + (numBlocks / ERASE_BATCH))); for (i = block ; i < block + (numBlocks / ERASE_BATCH) ; i++) { /* Erase the block */ if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputBatchErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } if ((pMailbox->argument.inputBatchErase.batch + 1) == ERASE_BATCH) { TRACE_INFO("Full Erase achieved, erase type is %d\n\r", (unsigned int)pMailbox->argument.inputBatchErase.eraseType); pMailbox->argument.outputBatchErase.nextBatch = 0; } else { pMailbox->argument.outputBatchErase.nextBatch = pMailbox->argument.inputBatchErase.batch + 1; TRACE_INFO("Batch Erase achieved\n\r"); } pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * ERASE_BLOCKS: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_ERASE_BLOCKS) { TRACE_INFO("BLOCKS ERASE command\n\r"); memoryOffset = pMailbox->argument.inputBlocksErase.memoryOffsetStart; if ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd > memSize) || (pMailbox->argument.inputBlocksErase.memoryOffsetEnd < memoryOffset) ) { TRACE_INFO("Out of memory space\n\r"); pMailbox->status = APPLET_ERASE_FAIL; goto exit; } nbBlocks = ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd- memoryOffset)/ blockSize) + 1; TRACE_INFO("Erase blocks from %d to %d \n\r", (unsigned int)(memoryOffset / blockSize),(unsigned int)((memoryOffset / blockSize)+ nbBlocks) ); /* Erase blocks */ for (i = memoryOffset / blockSize; i < memoryOffset / blockSize + nbBlocks ; i++) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i , NORMAL_ERASE)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } TRACE_INFO("Blocks Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * LIST BAD BLOCKS: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_LIST_BAD_BLOCKS) { TRACE_INFO("LIST BAD BLOCKS command\n\r"); nbBadBlocks = 0; bufferAddr = (uint32_t) &end; pMailbox->argument.outputListBadBlocks.bufferAddress = bufferAddr; for (i = 0; i < numBlocks; i++) { /* Erase the page */ if (SkipBlockNandFlash_CheckBlock(&skipBlockNf, i) == BADBLOCK) { nbBadBlocks++; *((uint32_t *)bufferAddr) = i; bufferAddr += 4; TRACE_INFO("Found block #%d BAD\n\r", i); } } TRACE_INFO("LIST BAD BLOCKS achieved\n\r"); pMailbox->argument.outputListBadBlocks.nbBadBlocks = nbBadBlocks; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * TAG BLOCK: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_TAG_BLOCK) { TRACE_INFO("TAG BLOCK command\n\r"); bufferAddr = (uint32_t) &end; block = pMailbox->argument.inputTagBlock.blockId; /* To tag the block as good, just erase it without bad block check */ if ((uint8_t)pMailbox->argument.inputTagBlock.tag == 0xFF) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, SCRUB_ERASE)) { TRACE_INFO("Cannot erase block %d\n\r", (unsigned int)block); pMailbox->status = APPLET_FAIL; goto exit; } } else { for (i = 0; i < 2; i++) { /* Start by reading the spare */ memset((uint8_t *)bufferAddr, 0xFF, NandCommon_MAXSPAREECCBYTES); TRACE_INFO("Tag to write : 0x%x\n\r", (unsigned int)pMailbox->argument.inputTagBlock.tag); NandSpareScheme_WriteBadBlockMarker((struct NandSpareScheme *)(NandFlashModel_GetScheme((struct NandFlashModel *)(&skipBlockNf))), (uint8_t *)bufferAddr, ((uint8_t)pMailbox->argument.inputTagBlock.tag)); if (RawNandFlash_WritePage((struct RawNandFlash *)(&skipBlockNf), block, i, 0, (uint8_t *)bufferAddr)) { TRACE_ERROR("Failed to write spare data of page %d of block %d\n\r", i, block); pMailbox->status = APPLET_FAIL; goto exit; } } } TRACE_INFO("TAG BLOCK achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } exit : /* Acknowledge the end of command */ TRACE_INFO("\tEnd of applet (command : %x --- status : %x)\n\r", (unsigned int)pMailbox->command, (unsigned int)pMailbox->status); /* Notify the host application of the end of the command processing */ pMailbox->command = ~(pMailbox->command); if (comType == DBGU_COM_TYPE) { UART_PutChar(0x6); } return 0; }