mirror of
https://github.com/eclipse-threadx/levelx.git
synced 2026-09-14 04:06:00 +08:00
253 lines
8.2 KiB
C
253 lines
8.2 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 */
|
|
/** */
|
|
/** NOR Flash Simulator */
|
|
/** */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
|
|
/* Include necessary files. */
|
|
|
|
#include "lx_api.h"
|
|
|
|
/* Define constants for the NOR flash simulation. */
|
|
|
|
/* This configuration is for one physical sector of overhead. */
|
|
|
|
|
|
#define TOTAL_BLOCKS 8
|
|
#define PHYSICAL_SECTORS_PER_BLOCK 16 /* Min value of 2, max value of 120 for 1 sector of overhead. */
|
|
#define WORDS_PER_PHYSICAL_SECTOR 128
|
|
#define FREE_BIT_MAP_WORDS ((PHYSICAL_SECTORS_PER_BLOCK-1)/32)+1
|
|
#define USABLE_SECTORS_PER_BLOCK (PHYSICAL_SECTORS_PER_BLOCK-1)
|
|
#define UNUSED_METADATA_WORDS_PER_BLOCK (WORDS_PER_PHYSICAL_SECTOR-(3+FREE_BIT_MAP_WORDS+USABLE_SECTORS_PER_BLOCK))
|
|
|
|
|
|
typedef struct PHYSICAL_SECTOR_STRUCT
|
|
{
|
|
unsigned long memory[WORDS_PER_PHYSICAL_SECTOR];
|
|
} PHYSICAL_SECTOR;
|
|
|
|
|
|
typedef struct FLASH_BLOCK_STRUCT
|
|
{
|
|
unsigned long erase_count;
|
|
unsigned long min_log_sector;
|
|
unsigned long max_log_sector;
|
|
unsigned long free_bit_map[FREE_BIT_MAP_WORDS];
|
|
unsigned long sector_metadata[USABLE_SECTORS_PER_BLOCK];
|
|
unsigned long unused_words[UNUSED_METADATA_WORDS_PER_BLOCK];
|
|
PHYSICAL_SECTOR physical_sectors[USABLE_SECTORS_PER_BLOCK];
|
|
} FLASH_BLOCK;
|
|
|
|
FLASH_BLOCK nor_memory_area[TOTAL_BLOCKS];
|
|
|
|
ULONG nor_sector_memory[WORDS_PER_PHYSICAL_SECTOR];
|
|
|
|
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
|
|
UINT _lx_nor_flash_simulator_erase_all(VOID);
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words);
|
|
UINT _lx_nor_flash_simulator_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words);
|
|
UINT _lx_nor_flash_simulator_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
|
|
UINT _lx_nor_flash_simulator_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block);
|
|
UINT _lx_nor_flash_simulator_system_error(LX_NOR_FLASH *nor_flash, UINT error_code, ULONG block, ULONG sector);
|
|
#else
|
|
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words);
|
|
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words);
|
|
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count);
|
|
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block);
|
|
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector);
|
|
#endif
|
|
|
|
|
|
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash)
|
|
{
|
|
|
|
/* Setup the base address of the flash memory. */
|
|
nor_flash -> lx_nor_flash_base_address = (ULONG *) &nor_memory_area[0];
|
|
|
|
/* Setup geometry of the flash. */
|
|
nor_flash -> lx_nor_flash_total_blocks = TOTAL_BLOCKS;
|
|
nor_flash -> lx_nor_flash_words_per_block = sizeof(FLASH_BLOCK)/sizeof(ULONG);
|
|
|
|
/* Setup function pointers for the NOR flash services. */
|
|
nor_flash -> lx_nor_flash_driver_read = _lx_nor_flash_simulator_read;
|
|
nor_flash -> lx_nor_flash_driver_write = _lx_nor_flash_simulator_write;
|
|
nor_flash -> lx_nor_flash_driver_block_erase = _lx_nor_flash_simulator_block_erase;
|
|
nor_flash -> lx_nor_flash_driver_block_erased_verify = _lx_nor_flash_simulator_block_erased_verify;
|
|
|
|
/* Setup local buffer for NOR flash operation. This buffer must be the sector size of the NOR flash memory. */
|
|
nor_flash -> lx_nor_flash_sector_buffer = &nor_sector_memory[0];
|
|
|
|
/* Return success. */
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
|
|
#else
|
|
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words)
|
|
#endif
|
|
{
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
LX_PARAMETER_NOT_USED(nor_flash);
|
|
#endif
|
|
|
|
/* Loop to read flash. */
|
|
while (words--)
|
|
{
|
|
/* Copy word. */
|
|
*destination++ = *flash_address++;
|
|
}
|
|
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words)
|
|
#else
|
|
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words)
|
|
#endif
|
|
{
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
LX_PARAMETER_NOT_USED(nor_flash);
|
|
#endif
|
|
|
|
/* Loop to write flash. */
|
|
while (words--)
|
|
{
|
|
|
|
/* Copy word. */
|
|
*flash_address++ = *source++;
|
|
}
|
|
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count)
|
|
#else
|
|
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count)
|
|
#endif
|
|
{
|
|
|
|
ULONG *pointer;
|
|
ULONG words;
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
LX_PARAMETER_NOT_USED(nor_flash);
|
|
#endif
|
|
LX_PARAMETER_NOT_USED(erase_count);
|
|
|
|
/* Setup pointer. */
|
|
pointer = (ULONG *) &nor_memory_area[block];
|
|
|
|
/* Loop to erase block. */
|
|
words = sizeof(FLASH_BLOCK)/sizeof(ULONG);
|
|
while (words--)
|
|
{
|
|
|
|
/* Erase word of block. */
|
|
*pointer++ = (ULONG) 0xFFFFFFFF;
|
|
}
|
|
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
|
|
UINT _lx_nor_flash_simulator_erase_all(VOID)
|
|
{
|
|
|
|
ULONG *pointer;
|
|
ULONG words;
|
|
|
|
|
|
/* Setup pointer. */
|
|
pointer = (ULONG *) &nor_memory_area[0];
|
|
|
|
/* Loop to erase block. */
|
|
words = sizeof(nor_memory_area)/(sizeof(ULONG));
|
|
while (words--)
|
|
{
|
|
|
|
/* Erase word of block. */
|
|
*pointer++ = (ULONG) 0xFFFFFFFF;
|
|
}
|
|
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block)
|
|
#else
|
|
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block)
|
|
#endif
|
|
{
|
|
|
|
ULONG *word_ptr;
|
|
ULONG words;
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
LX_PARAMETER_NOT_USED(nor_flash);
|
|
#endif
|
|
|
|
/* Determine if the block is completely erased. */
|
|
|
|
/* Pickup the pointer to the first word of the block. */
|
|
word_ptr = (ULONG *) &nor_memory_area[block].erase_count;
|
|
|
|
/* Calculate the number of words in a block. */
|
|
words = sizeof(FLASH_BLOCK)/sizeof(ULONG);
|
|
|
|
/* Loop to check if the block is erased. */
|
|
while (words--)
|
|
{
|
|
|
|
/* Is this word erased? */
|
|
if (*word_ptr++ != 0xFFFFFFFF)
|
|
return(LX_ERROR);
|
|
}
|
|
|
|
/* Return success. */
|
|
return(LX_SUCCESS);
|
|
}
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
UINT _lx_nor_flash_simulator_system_error(LX_NOR_FLASH *nor_flash, UINT error_code, ULONG block, ULONG sector)
|
|
#else
|
|
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector)
|
|
#endif
|
|
{
|
|
|
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
|
LX_PARAMETER_NOT_USED(nor_flash);
|
|
#endif
|
|
LX_PARAMETER_NOT_USED(error_code);
|
|
LX_PARAMETER_NOT_USED(block);
|
|
LX_PARAMETER_NOT_USED(sector);
|
|
|
|
/* Custom processing goes here... all errors are fatal. */
|
|
return(LX_ERROR);
|
|
}
|
|
|