Files
rtems/cpukit/include/dev/flash/flashdev.h
Kinsey Moore 38e8e5c286 cpukit/flashdev: Add full support for NAND devices
This extends the flashdev API to support the additional calls required
by NAND device backends. This also adds region-relative IOCTLs to
prevent reimplementation of offset logic in top-end flashdev/filesystem
adapters.
2025-10-02 20:12:51 -04:00

756 lines
19 KiB
C

/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup Flash
*
* @brief Generic Flash API
*/
/*
* Copyright (C) 2023 Aaron Nyholm
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_FLASHDEV_H
#define _DEV_FLASHDEV_H
#include <rtems/thread.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rtems_flashdev rtems_flashdev;
/**
* @defgroup Generic Flash API
*
* @ingroup RTEMSDeviceDrivers
*
* @brief Generic Flash API to wrap specific device drivers.
*
* @{
*/
/* IOCTL Calls */
/**
* @brief Obtains the flash device.
*
* This command has no argument.
*/
#define RTEMS_FLASHDEV_IOCTL_OBTAIN 0
/**
* @brief Releases the flash device.
*
* This command has no argument.
*/
#define RTEMS_FLASHDEV_IOCTL_RELEASE 1
/**
* @brief Returns the JEDEC ID of the flash device. This IOCTL call
* is informational only.
*
* @param[out] jedec_id Pointer to uint32_t in which the JEDEC ID is
* returned in.
*/
#define RTEMS_FLASHDEV_IOCTL_JEDEC_ID 2
/**
* @brief Erases flash device.
*
* @param[in] erase_args Pointer to rtems_flashdev_region struct
* containing offset and size of erase to be performed.
*/
#define RTEMS_FLASHDEV_IOCTL_ERASE 3
/**
* @brief Set a region that limits read, write and erase calls to within it.
* Regions are file descriptor specific and limited to a single region per
* file descriptor and 32 regions total per flash device. Regions can be
* changed or updated by calling this IOCTL again.
*
* @param[in] region Pointer to rtems_flashdev_region struct containing
* base and length of defined region.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_SET 4
/**
* @brief Removes the set region on the file descriptor.
*
* This command has no argument.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_UNSET 5
/**
* @brief Returns the type of flash device (e.g. NOR or NAND).
*
* @param[out] flash_type Pointer to integer which is set to the flash
* type macro value.
*/
#define RTEMS_FLASHDEV_IOCTL_TYPE 6
/**
* @brief Get the size and address of flash page at given offset
*
* The offset ignores the region limiting. To find page of region
* limited offset add the base of the region to the desired offset.
*
* @param[in,out] rtems_flashdev_ioctl_page_info arg Pointer to struct
* with offset and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_OFFSET 7
/**
* @brief Get the size and address of nth flash page where n is index passed in.
*
* The index ignores the region limiting.
*
* @param[in,out] rtems_flashdev_ioctl_page_info arg Pointer to struct
* with index and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_INDEX 8
/**
* @brief Get the number of pages in flash device.
*
* @param[out] count Integer containing the number of pages.
*/
#define RTEMS_FLASHDEV_IOCTL_PAGE_COUNT 9
/**
* @brief Get the minimum write size supported by the driver.
*
* @param[out] count Integer containing the minimum write size.
*/
#define RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE 10
/**
* @brief Get the size and address of flash erase sector at given offset
*
* The offset ignores the region limiting. To find sector of region
* limited offset add the base of the region to the desired offset.
*
* @param[in,out] rtems_flashdev_ioctl_sector_info arg Pointer to struct
* with offset and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_SECTORINFO_BY_OFFSET 11
/**
* @brief Get the number of erase sectors in flash device.
*
* @param[out] count Integer containing the number of sectors.
*/
#define RTEMS_FLASHDEV_IOCTL_SECTOR_COUNT 12
/**
* @brief Get the size and address of flash erase sector at given offset
*
* The offset ignores the region limiting. To find sector of region
* limited offset add the base of the region to the desired offset.
*
* @param[in,out] rtems_flashdev_ioctl_sector_info arg Pointer to struct
* with offset and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_SECTORINFO_BY_OFFSET 13
/**
* @brief Get the number of bytes per page of out of band space.
*
* This IOCTL is only applicable to devices which have out of band space,
* typically NAND.
*
* @param[out] count size_t containing the number of bytes.
*/
#define RTEMS_FLASHDEV_IOCTL_OOB_BYTES_PER_PAGE 14
/**
* @brief Read bytes from the out of band space.
*
* This IOCTL is only applicable to devices which have out of band space,
* typically NAND.
*
* @param[in,out] rtems_flashdev_ioctl_oob_rw_info arg Pointer to struct
* with offset and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_OOB_READ 15
/**
* @brief Read bytes from the out of band space.
*
* This IOCTL is only applicable to devices which have out of band space,
* typically NAND.
*
* @param[in,out] rtems_flashdev_ioctl_oob_rw_info arg Pointer to struct
* with offset and space for return values.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_OOB_WRITE 16
/**
* @brief Mark a sector as bad.
*
* Sectors are referred to as blocks in NAND devices. Not all devices have bad
* sector management.
*
* @param[in,out] off_t arg Pointer to a off_t holding the offset of the
* sector to be marked bad
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_SECTOR_MARK_BAD 17
/**
* @brief Check whether a sector is bad.
*
* Sectors are referred to as blocks in NAND devices. Not all devices have bad
* sector management.
*
* @param[in,out] rtems_flashdev_ioctl_sector_health arg Pointer to struct
* with offset and return value.
*/
#define RTEMS_FLASHDEV_IOCTL_REGION_SECTOR_HEALTH 18
/**
* @brief The maximum number of region limited file descriptors
* allowed to be open at once.
*/
#define RTEMS_FLASHDEV_MAX_REGIONS 32
/**
* @brief Enum for flash type returned from IOCTL call.
*/
typedef enum rtems_flashdev_flash_type {
/**
* @brief The flash device is NOR flash.
**/
RTEMS_FLASHDEV_NOR,
/**
* @brief The flash device is NAND flash.
*/
RTEMS_FLASHDEV_NAND
} rtems_flashdev_flash_type;
/**
* @brief General definition for on flash device.
*/
typedef struct rtems_flashdev_region {
/**
* @brief Base of region.
*/
off_t offset;
/**
* @brief Length of region.
*/
size_t size;
} rtems_flashdev_region;
/**
* @brief Struct holding region definitions
*/
typedef struct rtems_flashdev_region_table {
/**
* @brief The maximum regions that can be defined at once.
*/
int max_regions;
/**
* @brief Pointer to array of rtems_flashdev_region of length
* max_regions
*/
rtems_flashdev_region* regions;
/**
* @brief Array of uint32_t acting as bit allocator
* for regions array.
*/
uint32_t *bit_allocator;
} rtems_flashdev_region_table;
/**
* @brief Page information returned from IOCTL calls.
*/
typedef struct rtems_flashdev_ioctl_page_info {
/**
* @brief Offset or index to find page at.
*/
off_t location;
/**
* @brief Information returned about the page. Including the
* base offset and size of page.
*/
rtems_flashdev_region page_info;
} rtems_flashdev_ioctl_page_info;
/**
* @brief Sector information returned from IOCTL calls.
*/
typedef struct rtems_flashdev_ioctl_sector_info {
/**
* @brief Offset or index to find sector at.
*/
off_t location;
/**
* @brief Information returned about the sector. Including the
* base offset and size of sector.
*/
rtems_flashdev_region sector_info;
} rtems_flashdev_ioctl_sector_info;
/**
* @brief Sector information returned from IOCTL calls.
*/
typedef struct rtems_flashdev_ioctl_sector_health {
/**
* @brief Offset or index to find sector at.
*/
off_t location;
/**
* @brief Health information returned about the sector.
*
* Non-zero value indicates the sector is bad.
*/
uint8_t sector_bad;
} rtems_flashdev_ioctl_sector_health;
/**
* @brief Read/write information used with OOB IOCTL calls.
*/
typedef struct rtems_flashdev_ioctl_oob_rw_info {
/**
* @brief Offset at which to operate.
*/
off_t offset;
/**
* @brief Buffer on which to operate.
*/
void *buffer;
/**
* @brief Number of bytes to transfer.
*/
size_t count;
} rtems_flashdev_ioctl_oob_rw_info;
/**
* @brief Flash device.
*/
struct rtems_flashdev {
/**
* @brief Call to the device driver to read the flash device.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address to read from.
* @param[in] count Number of bytes to read.
* @param[out] buffer Buffer for data to be read into.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *read )(
rtems_flashdev *flash,
uintptr_t offset,
size_t count,
void *buffer
);
/**
* @brief Call to the device driver to write to the flash device.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address to write to.
* @param[in] count Number of bytes to read.
* @param[in] buffer Buffer for data to be written from.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *write )(
rtems_flashdev *flash,
uintptr_t offset,
size_t count,
const void *buffer
);
/**
* @brief Call to the device driver to erase the flash device.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address to erase at.
* @param[in] count Number of bytes to erase.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *erase )(
rtems_flashdev *flash,
uintptr_t offset,
size_t count
);
/**
* @brief Call to the device driver to return the JEDEC ID.
*
* @param[in] flash The flash device.
*
* @retval JEDEC ID.
*/
uint32_t ( *jedec_id )(
rtems_flashdev *flash
);
/**
* @brief Call to the device driver to return the flash type.
*
* @param[in] flash The flash device.
* @param[out] type The type of flash device.
*
* @retval 0 Success
* @retbal Other Failure
*/
int ( *flash_type )(
rtems_flashdev *flash,
rtems_flashdev_flash_type *type
);
/**
* @brief Call to device driver to get size and offset of page at
* given offset.
*
* @param[in] flash The flash device
* @param[in] search_offset The offset of the page which info is to be
* returned.
* @param[out] page_offset The offset of the start of the page
* @param[out] page_size The size of the page
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *page_info_by_offset )(
rtems_flashdev *flash,
off_t search_offset,
off_t *page_offset,
size_t *page_size
);
/**
* @brief Call to device driver to get size and offset of page at
* given index.
*
* @param[in] flash The flash device
* @param[in] search_index The index of the page which info is to be returned.
* @param[out] page_offset The offset of the start of the page
* @param[out] page_size The size of the page
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *page_info_by_index )(
rtems_flashdev *flashdev,
off_t search_index,
off_t *page_offset,
size_t *page_size
);
/**
* @brief Call to device driver to return the number of pages on the flash
* device.
*
* @param[out] page_count The number of pages on the flash device.
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *page_count )(
rtems_flashdev *flashdev,
int *page_count
);
/**
* @brief Call to device driver to return the minimum write size of the
* flash device.
*
* @param[out] write_block_size The minimum write size of the flash device.
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *write_block_size )(
rtems_flashdev *flashdev,
size_t *write_block_size
);
/**
* @brief Call to device driver to get size and offset of sector at
* given offset.
*
* @param[in] flash The flash device
* @param[in] search_offset The offset of the sector which info is to be
* returned.
* @param[out] sector_offset The offset of the start of the sector
* @param[out] sector_size The size of the sector
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *sector_info_by_offset )(
rtems_flashdev *flash,
off_t search_offset,
off_t *sector_offset,
size_t *sector_size
);
/**
* @brief Call to device driver to return the number of sectors on the flash
* device.
*
* @param[in] flashdev The flash device
* @param[out] sector_count The number of sectors on the flash device. On NAND
* devices these are called blocks.
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *sector_count )(
rtems_flashdev *flashdev,
int *sector_count
);
/**
* @brief Call to device driver to return the size of the out of band space.
*
* @param[in] flashdev Pointer to flash device.
* @param[out] oob_bytes_per_page The number of bytes of OOB space per page.
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *oob_bytes_per_page )(
rtems_flashdev *flashdev,
size_t *oob_bytes_per_page
);
/**
* @brief Call to the device driver to read the out of band space of the flash
* device.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address to read from.
* @param[in] count Number of bytes to read.
* @param[out] buffer Buffer for data to be read into.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *oob_read )(
rtems_flashdev *flash,
uintptr_t offset,
size_t count,
void *buffer
);
/**
* @brief Call to the device driver to write to the out of band space of the
* flash device.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address to write to.
* @param[in] count Number of bytes to read.
* @param[in] buffer Buffer for data to be written from.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *oob_write )(
rtems_flashdev *flash,
uintptr_t offset,
size_t count,
const void *buffer
);
/**
* @brief Call to the device driver to mark a sector as being bad.
*
* Sectors are referred to as blocks in NAND devices. Not all devices have bad
* sector management.
*
* @param[in] flash Pointer to flash device.
* @param[in] offset Address of the beginning of the sector.
*
* @retval 0 Successful operation.
* @retval 1 Failed operation.
*/
int ( *sector_mark_bad )(
rtems_flashdev *flash,
off_t offset
);
/**
* @brief Call to device driver to get health of sector at given offset.
*
* @param[in] flash The flash device
* @param[in] search_offset The offset of the sector which info is to be
* returned.
* @param[out] sector_bad The disposition of the sector, non-zero being bad
*
* @retval 0 Success.
* @retval non-zero Failed.
*/
int ( *sector_health )(
rtems_flashdev *flash,
off_t search_offset,
uint8_t *sector_bad
);
/**
* @brief Destroys the flash device.
*
* @param[in] flash Pointer to flash device.
*/
void ( *destroy )(
rtems_flashdev *flashdev
);
/**
* @brief Callback to destroy private data not owned directly by the flashdev
* framework.
*
* @param[in] flash Pointer to flash device.
*/
void ( *priv_destroy )(
rtems_flashdev *flashdev
);
/**
* @brief Pointer to device driver.
*/
void *driver;
/**
* @brief Mutex to protect the flash device access.
*/
rtems_recursive_mutex mutex;
/**
* @brief Region table defining size and memory for region allocations
*/
rtems_flashdev_region_table *region_table;
};
/**
* @brief Allocate and initialize the flash device.
*
* After a successful allocation and initialization of the flash device
* it must be destroyed via rtems_flashdev_destroy_and_free().
*
* @param[in] size The number of bytes to allocate.
*
* @retval NULL Failed to set up flash device.
* @retval non-NULL The new flash device.
*/
rtems_flashdev *rtems_flashdev_alloc_and_init(
size_t size
);
/**
* @brief Initialize the flash device.
*
* After a successful initialization of the flash device it must be
* destroyed via rtems_flashdev_destory().
*
* After initialization and before registration read, write, erase, jedec_id
* and flash_type functions need to be set in the flashdev.
*
* @param[in] flash The flash device to initialize.
*
* @retval 1 Failed to set up flash device.
* @retval 0 Successful set up of flash device.
*/
int rtems_flashdev_init(
rtems_flashdev *flash
);
/**
* @brief Register the flash device.
*
* This function always claims ownership of the flash device passed to it. Once
* registered, the flash device can only be destroyed by unregistering it.
*
* After initialization and before registration read, write, erase, jedec_id
* and flash_type functions need to be set in the flashdev.
*
* @param[in] flash The flash device.
* @param[in] flash_path The path to the flash device file.
*
* @retval 0 Successful operation.
* @retval non-zero Failed operation.
*/
int rtems_flashdev_register(
rtems_flashdev *flash,
const char *flash_path
);
/**
* @brief Unregister the flash device.
*
* @param[in] flash The flash device.
*
* @retval 0 Successful operation.
* @retval non-zero Failed operation.
*/
int rtems_flashdev_unregister(
const char *flash_path
);
/**
* @brief Destroys the flash device.
*
* This function must only be used on rtems_flashdev instances that have not
* been registered.
*
* @param[in] flash The flash device.
*/
void rtems_flashdev_destroy(
rtems_flashdev *flash
);
/**
* @brief Destroys the flash device and frees its memory.
*
* This function must only be used on rtems_flashdev instances that have not
* been registered.
*
* @param[in] flash The flash device.
*/
void rtems_flashdev_destroy_and_free(
rtems_flashdev *flash
);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* _DEV_FLASHDEV_H */