Files
levelx/common/src/lx_nand_flash_data_page_copy.c
T

247 lines
11 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2026-present Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef LX_DISABLE_ERROR_CHECKING
#define LX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_data_page_copy PORTABLE C */
/* 6.4.0 */
/* AUTHOR */
/* */
/* Xiuwen Cai, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function copies logical sectors into new block. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector number */
/* source_block Source block number */
/* src_block_status Source block status */
/* destination_block Destination block number */
/* dest_block_status_ptr Pointer to destination block */
/* status */
/* sectors Number of sectors to copy */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* lx_nand_flash_driver_pages_copy Driver pages copy */
/* lx_nand_flash_driver_pages_read Driver pages read */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/**************************************************************************/
UINT _lx_nand_flash_data_page_copy(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG source_block, USHORT src_block_status,
ULONG destination_block, USHORT* dest_block_status_ptr, ULONG sectors)
{
LONG source_page;
ULONG destination_page;
UINT status = LX_SUCCESS;
UINT i;
ULONG available_pages;
ULONG spare_data1;
UCHAR *spare_buffer_ptr;
ULONG dest_block_status;
ULONG number_of_pages;
/* Get the destination block status. */
dest_block_status = *dest_block_status_ptr;
/* Get the current page number of the destination block. */
destination_page = dest_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
/* Get the available pages in the source block. */
available_pages = (src_block_status & LX_NAND_BLOCK_STATUS_FULL) ? (nand_flash -> lx_nand_flash_pages_per_block) : (src_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK);
/* Check if pages in the source block are sequential. */
if (src_block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
{
/* Get buffer for spare data. */
spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
/* Loop to copy the data. */
for (i = 0; i < sectors; i++)
{
/* Loop to search the page. */
for (source_page = (LONG)(available_pages - 1); source_page >= 0; source_page--)
{
/* Read one page. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_read)(source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
#endif
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, source_block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Get the spare data. */
spare_data1 = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
/* Check the address match. */
if ((spare_data1 & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == (logical_sector + i))
{
/* Check if the page contains valid data. */
if ((spare_data1 & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA))
{
/* Call the driver to copy the page. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer);
#endif
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, source_block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Check if the pages in destination block is still sequential. */
if (destination_page != ((logical_sector + i) % nand_flash -> lx_nand_flash_pages_per_block))
{
/* Mark the block status as non sequential. */
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
}
/* Update the available pages. */
destination_page++;
/* Check if available page count reaches pages per block. */
if (destination_page == nand_flash -> lx_nand_flash_pages_per_block)
{
/* Set block full flag. */
dest_block_status |= LX_NAND_BLOCK_STATUS_FULL;
}
}
break;
}
}
}
}
else
{
/* Get the source page number. */
source_page = (LONG)(logical_sector % nand_flash -> lx_nand_flash_pages_per_block);
/* Check if the page to copy is greater than the available pages. */
number_of_pages = ((ULONG)source_page + sectors) > available_pages ?
(available_pages > (ULONG)source_page ? available_pages - (ULONG)source_page : 0) : sectors;
/* Check if there is any pages to be copied. */
if (number_of_pages)
{
/* Call the driver to copy pages. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer);
#endif
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, source_block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Check if the pages in destination block is still sequential. */
if ((ULONG)source_page != destination_page)
{
/* Mark the block status as non sequential. */
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
}
/* Update the available pages. */
destination_page += number_of_pages;
/* Check if available page count reaches pages per block. */
if (destination_page == nand_flash -> lx_nand_flash_pages_per_block)
{
/* Set block full flag. */
dest_block_status |= LX_NAND_BLOCK_STATUS_FULL;
}
}
}
/* Return the block status. */
*dest_block_status_ptr = (USHORT)(destination_page | (dest_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
/* Return status. */
return(status);
}