Example #1
0
//------------------------------------------------------------------------------
/// Initializes an EccNandFlash instance.
/// \param ecc  Pointer to an EccNandFlash 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.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_Initialize(
    struct EccNandFlash *ecc,
    const struct NandFlashModel *model,
    unsigned int commandAddress,
    unsigned int addressAddress,
    unsigned int dataAddress,
    const Pin pinChipEnable,
    const Pin pinReadyBusy)
{
    unsigned char rc;
    rc = RawNandFlash_Initialize(RAW(ecc),
                                 model,
                                 commandAddress,
                                 addressAddress,
                                 dataAddress,
                                 pinChipEnable,
                                 pinReadyBusy);
#if defined(HARDWARE_ECC)
    {   unsigned int ecc_page;
        switch(NandFlashModel_GetPageDataSize(MODEL(ecc))) {
        case  512: ecc_page = AT91C_HSMC4_PAGESIZE_528_Bytes;  break;
        case 1024: ecc_page = AT91C_HSMC4_PAGESIZE_1056_Bytes; break;
        case 2048: ecc_page = AT91C_HSMC4_PAGESIZE_2112_Bytes; break;
        case 4096: ecc_page = AT91C_HSMC4_PAGESIZE_4224_Bytes; break;
        default:
            TRACE_ERROR("PageSize %d not compatible with ECC\n\r",
                        NandFlashModel_GetPageDataSize(MODEL(ecc)));
            return NandCommon_ERROR_ECC_NOT_COMPATIBLE;
        }
        HSMC4_EccConfigure(AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES,
                           ecc_page);
    }
#endif
    return rc;
}
/**
 * \brief  Read the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to read.
 * \param pageOffsetInBlock  Number of the page to read inside the given block.
 * \param data  Data area buffer.
 * \param numPages  number of pages to read.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
uint8_t SkipBlockNandFlash_ReadBlockUnaligned(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    uint16_t pageOffsetInBlock,
    uint16_t numPages,
    void *data
    )
{
    /* Page size*/
    uint32_t pageSize;
    /* Page index*/
    uint16_t i;
    /* Error returned by SkipBlockNandFlash_ReadPage*/
    uint8_t error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));

    for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
        error = SkipBlockNandFlash_ReadPage(skipBlock, block, i, data, 0);
        if (error == NandCommon_ERROR_BADBLOCK) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
            return NandCommon_ERROR_BADBLOCK;
        }
        else if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTREAD;
        }
        data = (void *) ((uint8_t *) data + pageSize);
    }

    return 0;
}
/**
 * \brief  Reads the data and/or the spare area of a page on a translated nandflash.
 * If the block is not currently mapped but could be (i.e. there are available
 * physical blocks), then the data/spare is filled with 0xFF.
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \param block  Logical block number.
 * \param page  Number of page to read inside logical block.
 * \param data  Data area buffer, can be 0.
 * \param spare  Spare area buffer, can be 0.
 * \return 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS
 */
unsigned char TranslatedNandFlash_ReadPage( const struct TranslatedNandFlash *translated, unsigned short block,
                                            unsigned short page, void *data, void *spare )
{
    unsigned char error ;

    TRACE_INFO("TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);

    /* If the page to read is in the current block, there is a previous physical
       block and the page is clean -> read the page in the old block since the
       new one does not contain meaningful data*/
    if ( (block == translated->currentLogicalBlock) && (translated->previousPhysicalBlock != -1)
         && (PageIsClean(translated, page)) )
    {
        TRACE_DEBUG("Reading page from current block\n\r");
        return ManagedNandFlash_ReadPage( MANAGED( translated ), translated->previousPhysicalBlock,
                                          page, data, spare ) ;
    }
    else
    {
        /* Try to read the page from the logical block*/
        error = MappedNandFlash_ReadPage(MAPPED(translated), block, page, data, spare);

        /* Block was not mapped*/
        if ( error == NandCommon_ERROR_BLOCKNOTMAPPED )
        {
            assert( !spare ) ; /* "Cannot read the spare information of an unmapped block\n\r" */

            /* Check if a block can be allocated*/
            if ( BlockCanBeAllocated( translated ) )
            {
                /* Return 0xFF in buffers with no error*/
                TRACE_DEBUG("Block #%d is not mapped but can be allocated, filling buffer with 0xFF\n\r", block);
                if (data)
                {
                    memset(data, 0xFF, NandFlashModel_GetPageDataSize(MODEL(translated)));
                }
                if (spare)
                {
                    memset(spare, 0xFF, NandFlashModel_GetPageSpareSize(MODEL(translated)));
                }
            }
            else
            {
                TRACE_ERROR("Block #%d is not mapped and there are no more blocks available\n\r", block);
                return NandCommon_ERROR_NOMOREBLOCKS;
            }
        }
        /* Error*/
        else
        {
            if (error)
            {
                return error;
            }
        }
    }

    return 0;
}
Example #4
0
/**
 * \brief Sends the column address to the NandFlash chip.
 *
 * \param raw  Pointer to a RawNandFlash instance.
 * \param columnAddress  Column address to send.
 */
static void WriteColumnAddress(
    const struct RawNandFlash *raw,
    unsigned short columnAddress)
{
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));

    /* Check the data bus width of the NandFlash */
    if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
        /* Div 2 is because we address in word and not in byte */
        columnAddress >>= 1;
    }
Example #5
0
//------------------------------------------------------------------------------
/// Reads the data and/or spare of a page of a nandflash chip, and verify that
/// the data is valid using the ECC information contained in the spare. If one
/// buffer pointer is 0, the corresponding area is not saved.
/// Returns 0 if the data has been read and is valid; otherwise returns either
/// NandCommon_ERROR_CORRUPTEDDATA or ...
/// \param ecc  Pointer to an EccNandFlash instance.
/// \param block  Number of block to read from.
/// \param page  Number of page to read inside given block.
/// \param data  Data area buffer.
/// \param spare  Spare area buffer.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_ReadPage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned char error;
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));

    TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);

    // Start by reading the spare and the data
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
        return error;
    }

    // Retrieve ECC information from page and verify the data
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming);
    error = Hamming_Verify256x(tmpData, pageDataSize, hamming);
    if (error && (error != Hamming_ERROR_SINGLEBIT)) {

        TRACE_ERROR("EccNandFlash_ReadPage: Unrecoverable data\n\r");
        return NandCommon_ERROR_CORRUPTEDDATA;
    }

    // Copy data and/or spare into final buffers
    if (data) {

        memcpy(data, tmpData, pageDataSize);
    }
    if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }

    return 0;
}
Example #6
0
//------------------------------------------------------------------------------
/// Writes the data and/or spare area of a nandflash page, after calculating an
/// ECC for the data area and storing it in the spare. If no data buffer is
/// provided, the ECC is read from the existing page spare. If no spare buffer
/// is provided, the spare area is still written with the ECC information
/// calculated on the data buffer.
/// Returns 0 if successful; otherwise returns an error code.
/// \param ecc Pointer to an EccNandFlash instance.
/// \param block  Number of the block to write in.
/// \param page  Number of the page to write inside the given block.
/// \param data  Data area buffer, can be 0.
/// \param spare  Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_WritePage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char error;
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];

    ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r");
    TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);

    // Compute ECC on the new data, if provided
    // If not provided, hamming code set to 0xFFFF.. to keep existing bytes
    memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
    if (data) {

        // Compute hamming code on data
        Hamming_Compute256x(data, pageDataSize, hamming);
    }

    // Store code in spare buffer (if no buffer provided, use a temp. one)
    if (!spare) {

        spare = tmpSpare;
        memset(spare, 0xFF, pageSpareSize);
    }
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming);

    // Perform write operation
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error) {

        TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
        return error;
    }

    return 0;
}
Example #7
0
//------------------------------------------------------------------------------
/// Translates the given column and row address into first and other (1-4) address
/// cycles. The resulting values are stored in the provided variables if they are not null.
/// \param columnAddress  Column address to translate.
/// \param rowAddress  Row address to translate.
/// \param pAddressCycle0  First address cycle.
/// \param pAddressCycle1234 four address cycles.
//------------------------------------------------------------------------------
void NFC_TranslateAddress(
    const struct RawNandFlash *raw,
    unsigned short columnAddress,
    unsigned int rowAddress,
    unsigned int *pAddressCycle0,
    unsigned int *pAddressCycle1234,
    unsigned char useFiveAddress)
{
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
    unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw));
    unsigned char numAddressCycles = 0;
    unsigned int addressCycle0 = 0;
    unsigned int addressCycle1234 = 0;
    
    // Check the data bus width of the NandFlash 
    if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
        // Div 2 is because we address in word and not in byte 
        columnAddress >>= 1;
    }
/**
 * \brief  Read the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to read.
 * \param pageOffsetInBlock  Number of the page to read inside the given block.
 * \param data  Data area buffer.
 * \param numPages  number of pages to read.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
unsigned char SkipBlockNandFlash_ReadBlockUnaligned(
    const struct SkipBlockNandFlash *skipBlock,
    unsigned short block,
    unsigned short pageOffsetInBlock,
    unsigned short numPages,
    void *data
    )
{
    /* Number of pages per block*/
    unsigned int numPagesPerBlock;
    /* Page size*/
    unsigned int pageSize;
    /* Page index*/
    unsigned short i;
    /* Error returned by SkipBlockNandFlash_ReadPage*/
    unsigned char error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
        error = SkipBlockNandFlash_ReadPage(skipBlock, block, i, data, 0);
        if (error == NandCommon_ERROR_BADBLOCK) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
            return NandCommon_ERROR_BADBLOCK;
        }
        else if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTREAD;
        }
        data = (void *) ((unsigned char *) data + pageSize);
    }

    return 0;
}
/**
 * \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 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;
}
/**
 * \brief  Scans a mapped nandflash to find an existing logical block mapping. If a
 * block contains the mapping, its index is stored in the provided variable (if
 * pointer is not 0).
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param logicalMappingBlock  Pointer to a variable for storing the block number.
 * \return  0 if mapping has been found; otherwise returns
 * NandCommon_ERROR_NOMAPPING if no mapping exists, or another NandCommon_ERROR_xxx code.
 */
static unsigned char FindLogicalMappingBlock(
    const struct MappedNandFlash *mapped,
    signed short *logicalMappingBlock)
{
    unsigned short block;
    unsigned char found;
    unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned int i;

    //TRACE_INFO("FindLogicalMappingBlock ~%d\n\r", numBlocks);

    /* Search each LIVE block */
    found = 0;
    block = 0;
    while (!found && (block < numBlocks)) {

        /* Check that block is LIVE*/
        if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) {

            /* Read block*/
            TRACE_INFO("Checking LIVE block #%d\n\r", block);
            error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0);
            if (!error) {

                /* Compare data with logical mapping pattern*/
                i = 0;
                found = 1;
                while ((i < pageDataSize) && found) {

                    if (data[i] != PATTERN(i)) {

                        found = 0;
                    }
                    i++;
                }

                /* If this is the mapping, stop looking*/
                if (found) {

                    TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r",
                                     block);
                    if (logicalMappingBlock) {

                        *logicalMappingBlock = block;
                    }
                    return 0;
                }
            }
            else if (error != NandCommon_ERROR_WRONGSTATUS) {

                TRACE_ERROR(
                          "FindLogicalMappingBlock: Failed to scan block #%d\n\r",
                          block);
                return error;
            }
        }

        block++;
    }

    TRACE_WARNING("No logical mapping found in device\n\r");
    return NandCommon_ERROR_NOMAPPING;
}
/**
 * \brief  Saves the logical mapping on a FREE, unmapped physical block. Allocates the
 * new block, releases the previous one (if any) and save the mapping.
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param physicalBlock  Physical block number.
 * \return  0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS
 * if the block is not LIVE, or a NandCommon_ERROR code.
 */
unsigned char MappedNandFlash_SaveLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    /*unsigned short numBlocks =
                    ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));*/
    unsigned int i;
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int writeSize;
    signed short previousPhysicalBlock;

    TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock);

    /* If mapping has not been modified, do nothing*/
    if (!mapped->mappingModified) {

        return 0;
    }

    /* Allocate new block*/
    error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
    if (error) {

        return error;
    }

    /* Save mapping*/
    previousPhysicalBlock = mapped->logicalMappingBlock;
    mapped->logicalMappingBlock = physicalBlock;

    /* Save actual mapping in pages #1-#XXX*/
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        writeSize = min(remainingSize, pageDataSize);
        memset(data, 0xFF, pageDataSize);
        memcpy(data, currentBuffer, writeSize);
        error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                           physicalBlock,
                                           currentPage,
                                           data,
                                           0);
        if (error) {

            TRACE_ERROR(
             "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r");
            return error;
        }

        currentBuffer += writeSize;
        remainingSize -= writeSize;
        currentPage++;
    }

    /* Mark page #0 of block with a distinguishible pattern, so the mapping can
       be retrieved at startup*/
    for (i=0; i < pageDataSize; i++) {

        data[i] = PATTERN(i);
    }
    error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                       physicalBlock, 0,
                                       data, 0);
    if (error) {

        TRACE_ERROR(
            "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r");
        return error;
    }

    /* Mapping is not modified anymore*/
    mapped->mappingModified = 0;

    /* Release previous block (if any)*/
    if (previousPhysicalBlock != -1) {

        TRACE_DEBUG("Previous physical block was #%d\n\r",
                    previousPhysicalBlock);
        error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped),
                                              previousPhysicalBlock);
        if (error) {

            return error;
        }
    }

    TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock);

    return 0;
}
/**
 * \brief  Loads the logical mapping contained in the given physical block.
 * block contains the mapping, its index is stored in the provided variable (if
 * pointer is not 0).
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param physicalBlock  Physical block number.
 * \return  0 if successful; otherwise, returns a NandCommon_ERROR code.
 */
static unsigned char LoadLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned short numBlocks =
                    ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int readSize;
    unsigned int i;
    unsigned char status;
    signed short logicalBlock;
    /*signed short firstBlock, lastBlock;*/

    TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock);

    /* Load mapping from pages #1 - #XXX of block*/
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        /* Read page*/
        readSize = min(remainingSize, pageDataSize);
        error = ManagedNandFlash_ReadPage(MANAGED(mapped),
                                          physicalBlock,
                                          currentPage,
                                          data,
                                          0);
        if (error) {

            TRACE_ERROR(
                      "LoadLogicalMapping: Failed to load mapping\n\r");
            return error;
        }

        /* Copy page info*/
        memcpy(currentBuffer, data, readSize);

        currentBuffer += readSize;
        remainingSize -= readSize;
        currentPage++;
    }

    /* Store mapping block index*/
    mapped->logicalMappingBlock = physicalBlock;

    /* Power-loss recovery*/
    for (i=0; i < numBlocks; i++) {

        /* Check that this is not the logical mapping block*/
        if (i != physicalBlock) {

            status = mapped->managed.blockStatuses[i].status;
            logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i);

            /* Block is LIVE*/
            if (status == NandBlockStatus_LIVE) {

                /* Block is not mapped -> release it*/
                if (logicalBlock == -1) {

                    TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r",
                                     i);
                    ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i);
                }
            }
            /* Block is DIRTY*/
            else if (status == NandBlockStatus_DIRTY) {

                /* Block is mapped -> fake it as live*/
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r",
                                     i);
                    mapped->managed.blockStatuses[i].status =
                                                    NandBlockStatus_LIVE;
                }
            }
            /* Block is FREE or BAD*/
            else {

                /* Block is mapped -> remove it from mapping*/
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i);
                    mapped->logicalMapping[logicalBlock] = -1;
                }
            }
        }
    }

    TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock);

    return 0;
}
Example #14
0
//------------------------------------------------------------------------------
/// Writes the data and/or spare area of a nandflash page, after calculating an
/// ECC for the data area and storing it in the spare. If no data buffer is
/// provided, the ECC is read from the existing page spare. If no spare buffer
/// is provided, the spare area is still written with the ECC information
/// calculated on the data buffer.
/// Returns 0 if successful; otherwise returns an error code.
/// \param ecc Pointer to an EccNandFlash instance.
/// \param block  Number of the block to write in.
/// \param page  Number of the page to write inside the given block.
/// \param data  Data area buffer, can be 0.
/// \param spare  Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_WritePage(
    struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char error;
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
    unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(ecc));

    ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r");
    TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);
#ifndef HARDWARE_ECC
    // Compute ECC on the new data, if provided
    // If not provided, hamming code set to 0xFFFF.. to keep existing bytes
    memset(ecc->hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
    if (data) {

        // Compute hamming code on data
        Hamming_Compute256x(data, pageDataSize, ecc->hamming);
    }

    // Store code in spare buffer (if no buffer provided, use a temp. one)
    if (!spare) {

        spare = pSpareBuffer;
        memset(spare, 0xFF, pageSpareSize);
    }
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, ecc->hamming);

    // Perform write operation
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error)
        goto error;

#else
    // Store code in spare buffer (if no buffer provided, use a temp. one)
    if (!spare) {
        spare = pSpareBuffer;
        memset(spare, 0xFF, pageSpareSize);
    }
    // Perform write operation
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error)
      goto error;

    HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
    // Perform write operation
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao);
    error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare);
    if (error) 
      goto error;
#endif        
    RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
    return 0;
    
error:
      RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
      TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
      return error;
}
Example #15
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;
}
Example #16
0
//------------------------------------------------------------------------------
/// Reads the data and/or spare of a page of a nandflash chip, and verify that
/// the data is valid using the ECC information contained in the spare. If one
/// buffer pointer is 0, the corresponding area is not saved.
/// Returns 0 if the data has been read and is valid; otherwise returns either
/// NandCommon_ERROR_CORRUPTEDDATA or ...
/// \param ecc  Pointer to an EccNandFlash instance.
/// \param block  Number of block to read from.
/// \param page  Number of page to read inside given block.
/// \param data  Data area buffer.
/// \param spare  Spare area buffer.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_ReadPage(
    struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char error;
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
    unsigned char *pDataBuffer;
    unsigned char *pSpareBuffer;

    TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);

    pDataBuffer = (data)   ? data  : RawNandFlash_GetDataBuffer(RAW(ecc));
    pSpareBuffer = (spare) ? spare : RawNandFlash_GetSpareBuffer(RAW(ecc));
    
#ifndef HARDWARE_ECC
    // Start by reading the spare and the data
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, pDataBuffer, pSpareBuffer);
    if (error) {
       TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                block, page);
        goto error;
    }

    // Retrieve ECC information from page and verify the data
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), pSpareBuffer, ecc->hamming);
    error = Hamming_Verify256x(pDataBuffer, pageDataSize, ecc->hamming);
#else
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare);
    if (error) {
        TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                block, page);
        goto error;
    }

    // Retrieve ECC information from page
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, ecc->hsiaoInSpare);
    HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
    // Verify the data
    error = HSMC4_VerifyHsiao((unsigned char*) data,
                              pageDataSize, 
                              ecc->hsiaoInSpare,
                              ecc->hsiao,
                              NandFlashModel_GetDataBusWidth(MODEL(ecc)));
#endif    
    if (error && (error != Hamming_ERROR_SINGLEBIT)) {
        error = NandCommon_ERROR_CORRUPTEDDATA;
        TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                block, page);
        goto error;
    }
#ifndef HARDWARE_ECC
#else
     if (spare) {

        memcpy(spare, pSpareBuffer, pageSpareSize);
    }    
#endif
error: 
    if (data == (unsigned char *) 0)
      RawNandFlash_ReleaseDataBuffer(RAW(ecc));
    if (spare == (unsigned char *) 0)
        RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
    return error;   
}
Example #17
0
/**
 * \brief  Reads the data and/or spare of a page of a nandflash chip, and verify that
 * the data is valid using the ECC information contained in the spare. If one
 * buffer pointer is 0, the corresponding area is not saved.
 * \param ecc  Pointer to an EccNandFlash instance.
 * \param block  Number of block to read from.
 * \param page  Number of page to read inside given block.
 * \param data  Data area buffer.
 * \param spare  Spare area buffer.
 * \return 0 if the data has been read and is valid; otherwise returns either
 * NandCommon_ERROR_CORRUPTEDDATA or ...
 */
unsigned char EccNandFlash_ReadPage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned char error;
#ifndef HARDWARE_ECC
//    unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
#else
    unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES];
    unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
#endif

    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));

    TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
#ifndef HARDWARE_ECC
    /* Start by reading the spare and the data */
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, gdwNandFlashTempBuffer, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
        return error;
    }

    /* Retrieve ECC information from page and verify the data */
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming);
    error = Hamming_Verify256x(gdwNandFlashTempBuffer, pageDataSize, hamming);
#else
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                    block, page);
        return error;
    }
    /* Retrieve ECC information from page */
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hsiaoInSpare);
    HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
    /* Verify the data */
    error = HSMC4_VerifyHsiao((unsigned char*) data,
                              pageDataSize,
                              hsiaoInSpare,
                              hsiao,
                              NandFlashModel_GetDataBusWidth(MODEL(ecc)));
#endif
    if (error && (error != Hamming_ERROR_SINGLEBIT)) {

        TRACE_ERROR("EccNandFlash_ReadPage: at B%d.P%d Unrecoverable data\n\r",
                    block, page);
        return NandCommon_ERROR_CORRUPTEDDATA;
    }
#ifndef HARDWARE_ECC
    /* Copy data and/or spare into final buffers */
    if (data) {

        memcpy(data, gdwNandFlashTempBuffer, pageDataSize);
    }
    if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }
#else
     if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }
#endif
    return 0;
}
Example #18
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;
    unsigned int bufferSize, bufferAddr, memoryOffset, 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;
    /* Communication type with SAM-BA GUI. */
    unsigned char comType;
    /* current pmecc parameter header value */
    unsigned int currentPmeccHeaderValue;
    /* Index and value of pmecc command  */
    unsigned int nIndex, nValue;
    /* Number of ECC bits required */
    unsigned char eccBitReq2TT [5] = {2, 4, 8, 12, 24};
    /* Ecc mode to be swtich */
    unsigned int eccMode;
    unsigned int trimPage;
    /* Save communication link type */
    comType = pMailbox->argument.inputInit.comType;
    /* ---------------------------------------------------------- */
    /* INIT:                                                      */
    /* ---------------------------------------------------------- */
    if (pMailbox->command == APPLET_CMD_INIT) {
    
#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");

        /* 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));
        /* Tries to detect NAND Flash device connected to EBI CS3, with data lines connected to D0-D7, 
           then on NAND Flash connected to D16-D23. */
        if (!NandEbiDetect()) {
            pMailbox->status = APPLET_DEV_UNKNOWN;
            TRACE_INFO("\tDevice Unknown\n\r");
            goto exit;
        }
        memset(&skipBlockNf, 0, sizeof(skipBlockNf));
        NandGetOnfiPageParam (&OnfiPageParameter);
        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 */
            if ( nfBusWidth != 8) {
                SMC->SMC_CS_NUMBER[3].SMC_MODE = SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE | SMC_MODE_DBW(nfBusWidth/16) | SMC_MODE_TDF_CYCLES(1); 
            }
            TRACE_INFO("\tNandflash driver initialized\n\r");
            pMailbox->argument.outputInit.bufferAddress = (unsigned int) &_end;
            /* 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);
            spareSize = NandFlashModel_GetPageSpareSize(&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;
            pMailbox->argument.outputInit.pmeccParamHeader = 0;
            TRACE_INFO("\tpageSize : 0x%x blockSize : 0x%x blockNb : 0x%x \n\r",  pageSize, blockSize, numBlocks);
        }
        /* By default, we use pmecc, except MICRON MLC nand with internal ECC controller */
        eccOffset = 2;
        /* By defaut, 2 error bit correction, eccOffset = 2 */
        PMECC_Initialize(&pmeccDesc, 0, eccCorrectability, pageSize, spareSize, eccOffset, 0);
        TRACE_INFO("\tNandflash PMECC initialized\n\r");
        DMAD_Initialize( &dmad, POLLING_MODE ); 
        if ( NandFlashConfigureDmaChannels( &dmad )) {
            pMailbox->status =APPLET_DEV_UNKNOWN;
            goto exit;
        }
        /* Initialize current pmecc parameter header, This 32-bit word is configured below */
        currentPmeccHeader.usePmecc = 1;
        currentPmeccHeader.nbSectorPerPage = pmeccDesc.pageSize >> 8;
        currentPmeccHeader.spareSize = spareSize;
        currentPmeccHeader.eccBitReq = pmeccDesc.errBitNbrCapability;
        currentPmeccHeader.sectorSize = pmeccDesc.sectorSize;
        currentPmeccHeader.eccOffset = pmeccDesc.eccStartAddr;
        currentPmeccHeader.reserved = 0;
        currentPmeccHeader.key = 12;
        memcpy(&backupPmeccHeader, &currentPmeccHeader, sizeof(nfParamHeader_t));
        memcpy(&currentPmeccHeaderValue, &currentPmeccHeader, sizeof(nfParamHeader_t));
        pMailbox->argument.outputInit.pmeccParamHeader = currentPmeccHeaderValue;
        /* The Boot Program reads the first page without ECC check, to determine if the NAND parameter 
           header is present. The header is made of 52 times the same 32-bit word (for redundancy
           reasons) which must contain NAND and PMECC parameters used to correctly perform the read of the rest 
           of the data in the NAND. */
        for (i = 0; i< 52; i++) memcpy(&bootNfParamHeader[i], &currentPmeccHeader, sizeof(nfParamHeader_t));
        NandSwitchEcc(ECC_PMECC);
        pMailbox->status = APPLET_SUCCESS;
    }
/**
 * \brief   Returns the number of available data bytes in a translated nandflash.
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \return the number of available data bytes in a translated nandflash.
 */
unsigned long long TranslatedNandFlash_GetDeviceSizeInBytes(
   const struct TranslatedNandFlash *translated)
{
    return TranslatedNandFlash_GetDeviceSizeInPages(translated)
           * NandFlashModel_GetPageDataSize(MODEL(translated));
}
Example #20
0
//------------------------------------------------------------------------------
/// Reads the data and/or spare of a page of a nandflash chip, and verify that
/// the data is valid using the ECC information contained in the spare. If one
/// buffer pointer is 0, the corresponding area is not saved.
/// Returns 0 if the data has been read and is valid; otherwise returns either
/// NandCommon_ERROR_CORRUPTEDDATA or ...
/// \param ecc  Pointer to an EccNandFlash instance.
/// \param block  Number of block to read from.
/// \param page  Number of page to read inside given block.
/// \param data  Data area buffer.
/// \param spare  Spare area buffer.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_ReadPage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned char error;
#ifndef HARDWARE_ECC    
    unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
#else    
    unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES];
    unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
#endif
    unsigned char tmpNoEcc;

    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));

    TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
#ifndef HARDWARE_ECC
    // Start by reading the spare data
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
        return error;
    }

    // Then reading the data
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, 0);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
        return error;
    }

    tmpNoEcc = EccNandlfash_GetNoECC();
    if(!tmpNoEcc){
        // Retrieve ECC information from page and verify the data
        NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming);
        error = Hamming_Verify256x(tmpData, pageDataSize, hamming);
    }
#else
    // Start by reading the spare area
    // Note: Can't read data and spare at the same time, otherwise, the ECC parity generation will be incorrect.
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                    block, page);
        return error;
    }
        // Retrieve ECC information from page and verify the data
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hsiaoInSpare);
    
    // Reading the main data area
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, 0);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
                    block, page);
        return error;
    }
    HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
    error = HSMC4_VerifyHsiao((unsigned char*) data,
                              pageDataSize, 
                              hsiaoInSpare,
                              hsiao,
                              NandFlashModel_GetDataBusWidth(MODEL(ecc)));
#endif    
    if (error && (error != Hamming_ERROR_SINGLEBIT) && (!tmpNoEcc)) {

        TRACE_ERROR("EccNandFlash_ReadPage: at B%d.P%d Unrecoverable data\n\r",
                    block, page);
        return NandCommon_ERROR_CORRUPTEDDATA;
    }
#ifndef HARDWARE_ECC
    // Copy data and/or spare into final buffers
    if (data) {

        memcpy(data, tmpData, pageDataSize);
    }
    if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }
#else
     if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }    
#endif
    return 0;
}
//------------------------------------------------------------------------------
/// Loads the logical mapping contained in the given physical block.
/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code.
/// \param mapped  Pointer to a MappedNandFlash instance.
/// \param physicalBlock  Physical block number.
//------------------------------------------------------------------------------
static unsigned char LoadLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned short numBlocks =
                    ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned char *pDataBuffer =  RawNandFlash_GetDataBuffer(RAW(mapped));
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int readSize;
    unsigned int i;
    unsigned char status;
    signed short logicalBlock;
    //signed short firstBlock, lastBlock;

    TRACE_INFO("LoadLogicalMapping(B#%d)\r\n", physicalBlock);

    // Load mapping from pages #1 - #XXX of block
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        // Read page
        readSize = min(remainingSize, pageDataSize);
        error = ManagedNandFlash_ReadPage(MANAGED(mapped),
                                          physicalBlock,
                                          currentPage,
                                          pDataBuffer,
                                          0);
        if (error) {

            RawNandFlash_ReleaseDataBuffer(RAW(mapped));
            TRACE_ERROR(
                      "LoadLogicalMapping: Failed to load mapping\r\n");
            return error;
        }

        // Copy page info
        memcpy(currentBuffer, pDataBuffer, readSize);

        currentBuffer += readSize;
        remainingSize -= readSize;
        currentPage++;
    }

    // Store mapping block index
    mapped->logicalMappingBlock = physicalBlock;

    // Power-loss recovery
    for (i=0; i < numBlocks; i++) {

        // Check that this is not the logical mapping block
        if (i != physicalBlock) {

            status = mapped->managed.blockStatuses[i].status;
            logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i);

            // Block is LIVE
            if (status == NandBlockStatus_LIVE) {

                // Block is not mapped -> release it
                if (logicalBlock == -1) {

                    TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\r\n",
                                     i);
                    ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i);
                }
            }
            // Block is DIRTY
            else if (status == NandBlockStatus_DIRTY) {

                // Block is mapped -> fake it as live
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\r\n",
                                     i);
                    mapped->managed.blockStatuses[i].status =
                                                    NandBlockStatus_LIVE;
                }
            }
            // Block is FREE or BAD
            else {

                // Block is mapped -> remove it from mapping
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\r\n", i);
                    mapped->logicalMapping[logicalBlock] = -1;
                }
            }
        }
    }

    RawNandFlash_ReleaseDataBuffer(RAW(mapped));
    TRACE_WARNING_WP("-I- Mapping loaded from block #%d\r\n", physicalBlock);

    return 0;
}
Example #22
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;
}
Example #23
0
/**
 * \brief  Writes the data and/or spare area of a nandflash page, after calculating an
 * ECC for the data area and storing it in the spare. If no data buffer is
 * provided, the ECC is read from the existing page spare. If no spare buffer
 * is provided, the spare area is still written with the ECC information
 * calculated on the data buffer.
 * \param ecc  Pointer to an EccNandFlash instance.
 * \param block  Number of block to read from.
 * \param page  Number of page to read inside given block.
 * \param data  Data area buffer.
 * \param spare  Spare area buffer.
 * \return 0 if successful; otherwise returns an error code.
 */
unsigned char EccNandFlash_WritePage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char error;
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
#ifndef HARDWARE_ECC
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
#else
    unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
#endif

    assert( (data != NULL) || (spare != NULL) ) ;
//    TRACE_DEBUG(  "EccNandFlash_WritePage: At least one area must be written\n\r" ) ;
    TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);
#ifndef HARDWARE_ECC
    /* Compute ECC on the new data, if provided */
    /* If not provided, hamming code set to 0xFFFF.. to keep existing bytes */
    memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
    if (data) {

        /* Compute hamming code on data */
        Hamming_Compute256x(data, pageDataSize, hamming);
    }

    /* Store code in spare buffer (if no buffer provided, use a temp. one) */
    if (!spare) {

        spare = tmpSpare;
        memset(spare, 0xFF, pageSpareSize);
    }
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming);

    /* Perform write operation */
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error) {

        TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
        return error;
    }

#else
    /* Store code in spare buffer (if no buffer provided, use a temp. one) */
    if (!spare) {
        spare = tmpSpare;
        memset(spare, 0xFF, pageSpareSize);
    }
    /* Perform write operation */
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error) {

        TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
        return error;
    }
    HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
    /* Perform write operation */
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao);
    error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare);
    if (error) {
        TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
        return error;
    }
#endif
    return 0;
}