Driver API for Storage Device Interface (Driver_Storage.h) More...
Content | |
Use of Storage APIs | |
Sample Use of Storage Driver | |
Data Structures | |
struct | ARM_STORAGE_BLOCK_ATTRIBUTES |
Attributes of the storage range within a storage block. More... | |
struct | ARM_STORAGE_BLOCK |
A storage block is a range of memory with uniform attributes. More... | |
struct | ARM_STORAGE_INFO |
struct | ARM_DRIVER_STORAGE |
struct | ARM_STORAGE_CAPABILITIES |
Storage Driver API Capabilities. More... | |
struct | ARM_STORAGE_STATUS |
Operating status of the storage controller. More... | |
Typedefs | |
typedef void(* | ARM_Storage_Callback_t) (int32_t status, ARM_STORAGE_OPERATION operation) |
Functions | |
ARM_DRIVER_VERSION | ARM_Storage_GetVersion (void) |
Get driver version. | |
ARM_STOR_CAPABILITIES | ARM_Storage_GetCapabilities (void) |
Get driver capabilities. | |
int32_t | ARM_Storage_Initialize (ARM_Storage_Callback_t callback) |
Initialize the Storage interface. | |
int32_t | ARM_Storage_Uninitialize (void) |
De-initialize the Storage Interface. | |
int32_t | ARM_Storage_PowerControl (ARM_POWER_STATE state) |
Control the Storage interface power. | |
int32_t | ARM_Storage_ReadData (uint64_t addr, void *data, uint32_t size) |
Read data from Storage. | |
int32_t | ARM_Storage_ProgramData (uint64_t addr, const void *data, uint32_t size) |
Program data to Storage. | |
int32_t | ARM_Storage_Erase (uint64_t addr, uint32_t size) |
Erase Storage range. | |
int32_t | ARM_Storage_EraseAll (void) |
Erase complete Storage. | |
ARM_Storage_STATUS | ARM_Storage_GetStatus (void) |
Get Storage status. | |
int32_t | ARM_Storage_GetInfo (ARM_STORAGE_INFO *info) |
Get Storage information. | |
uint32_t | ARM_Storage_ResolveAddress (uint64_t addr) |
Resolve an address relative to the storage controller into a memory address. | |
int32_t | ARM_Storage_GetNextBlock (const ARM_STORAGE_BLOCK *prev_block, ARM_STORAGE_BLOCK *next_block) |
Advance to the successor of the current block (iterator). | |
int32_t | ARM_Storage_GetBlock (uint64_t addr, ARM_STORAGE_BLOCK *block) |
Find the storage block (iterator) encompassing a given storage address. | |
Driver API for Storage Device Interface (Driver_Storage.h)
This is an abstraction for a storage controller. It offers an interface to access an address space of storage locations, comprising APIs for initialization, erase, access, program, and status-fetch operations. It also offers APIs to iterate over the available Storage Blocks (ARM_STORAGE_BLOCK), allowing the discovery of block attributes such as write/erase granularities. Using the Storage abstraction, it becomes possible to write generic algorithms, such as block copy, to operate on any conforming storage device.
Here's a picture to help locate the storage abstraction in the software stack. The part below the box labeled 'Storage abstraction layer' is implemented by a storage driver.
Storage API
The following header files define the Application Programming Interface (API) for the Flash interface:
Driver Functions
The driver functions are published in the access struct as explained in Use of Storage APIs
A sample use for the driver can be found at: Sample Use of Storage Driver
struct ARM_STORAGE_BLOCK_ATTRIBUTES |
Data Fields | ||
---|---|---|
uint32_t | erasable: 1 |
Erasing blocks is permitted with a minimum granularity of 'erase_unit'.
|
uint32_t | programmable: 1 | Writing to ranges is permitted with a minimum granularity of 'program_unit'. Writes are typically achieved through the ProgramData operation (following an erase); if storage isn't erasable (see 'erasable' above) but is memory-mapped (i.e. 'memory_mapped'), it can be written directly using memory-store operations. |
uint32_t | executable: 1 | This storage block can hold program data; the processor can fetch and execute code sourced from it. Often this is accompanied with the device being 'memory_mapped' (see ARM_STORAGE_INFO). |
uint32_t | protectable: 1 | The entire block can be protected from program and erase operations. Once protection is enabled for a block, its 'erasable' and 'programmable' bits are turned off. |
uint32_t | reserved: 28 | |
uint32_t | erase_unit |
Minimum erase size in bytes. The offset of the start of the erase-range should also be aligned with this value. Applicable if the 'erasable' attribute is set for the block.
|
uint32_t | protection_unit | Minimum protectable size in bytes. Applicable if the 'protectable' attribute is set for the block. This should be a divisor of the block's size. A block can be considered to be made up of consecutive, individually-protectable fragments. |
struct ARM_STORAGE_BLOCK |
A storage block is a range of memory with uniform attributes.
Storage blocks combine to make up the address map of a storage controller.
Data Fields | ||
---|---|---|
uint64_t | addr | This is the start address of the storage block. It is expressed as an offset from the start of the storage map maintained by the owning storage controller. |
uint64_t | size | This is the size of the storage block, in units of bytes. Together with addr, it describes a range [addr, addr+size). |
ARM_STORAGE_BLOCK_ATTRIBUTES | attributes | Attributes for this block. |
struct ARM_STORAGE_INFO |
Device level metadata regarding the Storage implementation.
It describes the characteristics of a Storage device. This includes total storage, programming size, a default value for erased memory etc. This information can be obtained from the Storage device datasheet and is used by the middleware in order to properly interact with the Storage device.
Total available storage (in bytes) is contained in total_storage. Minimum programming size (in bytes) is described by program_unit (applicable only if the programmable attribute is set for a block). It defines the granularity for programming data. The offset of the start of a program-range and the size should also be aligned with program_unit.
Optimal programming page-size (in bytes) is specified by optimal_program_unit. Some storage controllers have internal buffers into which to receive data. Writing in chunks of optimal_program_unit would achieve maximum programming speed. Like with program_unit, this is applicable only if the programmable attribute is set for the underlying storage block(s).
program_cycles is a measure of endurance for reprogramming. A value of ARM_STORAGE_PROGRAM_CYCLES_INFINITE may be used to signify infinite or unknown endurance.
Contents of erased memory is specified by the erased_value. It is usually 1 to indicate erased bytes with state 0xFF.
memory_mapped can be set to 1 to indicate that the storage device has a mapping onto the processor's memory address space.
The field programmability holds a value to indicate storage programmability. Similarly, retention_level holds a for encoding data-retention levels for all storage blocks.
Returned by:
Data Fields | ||
---|---|---|
uint64_t | total_storage | Total available storage, in bytes. |
uint32_t | program_unit |
Minimum programming size in bytes. The offset of the start of the program-range should also be aligned with this value. Applicable only if the 'programmable' attribute is set for a block.
|
uint32_t | optimal_program_unit | Optimal programming page-size in bytes. Some storage controllers have internal buffers into which to receive data. Writing in chunks of 'optimal_program_unit' would achieve maximum programming speed. Applicable only if the 'programmable' attribute is set for the underlying block(s). |
uint32_t | program_cycles | A measure of endurance for reprogramming. Use ARM_STORAGE_PROGRAM_CYCLES_INFINITE for infinite or unknown endurance. |
uint32_t | erased_value: 1 | Contents of erased memory (usually 1 to indicate erased bytes with state 0xFF). |
uint32_t | memory_mapped: 1 |
This storage device has a mapping onto the processor's memory address space.
|
uint32_t | programmability: 4 | A value to indicate storage programmability. |
uint32_t | retention_level: 4 | |
uint32_t | reserved: 22 | |
ARM_STORAGE_SECURITY_FEATURES | security | ARM_STORAGE_SECURITY_FEATURES |
struct ARM_DRIVER_STORAGE |
The set of operations constituting the Storage driver.
This is the set of operations constituting the Storage driver. Their implementation is platform-specific, and needs to be supplied by the porting effort. The functions of the Storage driver are accessed by function pointers exposed by this structure. Refer to Use of Storage APIs for overview information.
Each instance of a Storage interface provides such an access structure. The instance is identified by a postfix number in the symbol name of the access structure, for example:
A middleware configuration setting allows connecting the middleware to a specific driver instance Driver_Flashn. The default is 0, which connects a middleware to the first instance of a driver.
Data Fields | |
ARM_DRIVER_VERSION(* | GetVersion )(void) |
Pointer to ARM_Storage_GetVersion : Get driver version. | |
ARM_STORAGE_CAPABILITIES(* | GetCapabilities )(void) |
Pointer to ARM_Storage_GetCapabilities : Get driver capabilities. | |
int32_t(* | Initialize )(ARM_Storage_Callback_t callback) |
Pointer to ARM_Storage_Initialize : Initialize the Storage Interface. | |
int32_t(* | Uninitialize )(void) |
Pointer to ARM_Storage_Uninitialize : De-initialize the Storage Interface. | |
int32_t(* | PowerControl )(ARM_POWER_STATE state) |
Pointer to ARM_Storage_PowerControl : Control the Storage interface power. | |
int32_t(* | ReadData )(uint64_t addr, void *data, uint32_t size) |
Pointer to ARM_Storage_ReadData : Read data from Storage. | |
int32_t(* | ProgramData )(uint64_t addr, const void *data, uint32_t size) |
Pointer to ARM_Storage_ProgramData : Program data to Storage. | |
int32_t(* | Erase )(uint64_t addr, uint32_t size) |
Pointer to ARM_Storage_Erase : Erase Storage range. | |
int32_t(* | EraseAll )(void) |
Pointer to ARM_Storage_EraseAll : Erase complete Storage. | |
ARM_STORAGE_STATUS(* | GetStatus )(void) |
Pointer to ARM_Storage_GetStatus : Get Storage status. | |
int32_t(* | GetInfo )(ARM_STORAGE_INFO *info) |
Pointer to ARM_Storage_GetInfo : Get Storage information. | |
uint32_t(* | ResolveAddress )(uint64_t addr) |
Pointer to ARM_Storage_ResolveAddress : Resolve a storage address. | |
int32_t(* | GetNextBlock )(const ARM_STORAGE_BLOCK *prev, ARM_STORAGE_BLOCK *next) |
Pointer to ARM_Storage_GetNextBlock : fetch successor for current block. | |
int32_t(* | GetBlock )(uint64_t addr, ARM_STORAGE_BLOCK *block) |
Pointer to ARM_Storage_GetBlock : | |
ARM_DRIVER_VERSION(* GetVersion) (void) |
Pointer to ARM_Storage_GetVersion : Get driver version.
ARM_STORAGE_CAPABILITIES(* GetCapabilities) (void) |
Pointer to ARM_Storage_GetCapabilities : Get driver capabilities.
int32_t(* Initialize) (ARM_Storage_Callback_t callback) |
Pointer to ARM_Storage_Initialize : Initialize the Storage Interface.
int32_t(* Uninitialize) (void) |
Pointer to ARM_Storage_Uninitialize : De-initialize the Storage Interface.
int32_t(* PowerControl) (ARM_POWER_STATE state) |
Pointer to ARM_Storage_PowerControl : Control the Storage interface power.
int32_t(* ReadData) (uint64_t addr, void *data, uint32_t size) |
Pointer to ARM_Storage_ReadData : Read data from Storage.
int32_t(* ProgramData) (uint64_t addr, const void *data, uint32_t size) |
Pointer to ARM_Storage_ProgramData : Program data to Storage.
int32_t(* Erase) (uint64_t addr, uint32_t size) |
Pointer to ARM_Storage_Erase : Erase Storage range.
int32_t(* EraseAll) (void) |
Pointer to ARM_Storage_EraseAll : Erase complete Storage.
ARM_STORAGE_STATUS(* GetStatus) (void) |
Pointer to ARM_Storage_GetStatus : Get Storage status.
int32_t(* GetInfo) (ARM_STORAGE_INFO *info) |
Pointer to ARM_Storage_GetInfo : Get Storage information.
uint32_t(* ResolveAddress) (uint64_t addr) |
Pointer to ARM_Storage_ResolveAddress : Resolve a storage address.
int32_t(* GetNextBlock) (const ARM_STORAGE_BLOCK *prev, ARM_STORAGE_BLOCK *next) |
Pointer to ARM_Storage_GetNextBlock : fetch successor for current block.
int32_t(* GetBlock) (uint64_t addr, ARM_STORAGE_BLOCK *block) |
Pointer to ARM_Storage_GetBlock :
struct ARM_STORAGE_CAPABILITIES |
Storage Driver API Capabilities.
A Storage driver can be implemented with different capabilities. The data fields of this struct encode the API capabilities implemented by this driver.
The element asynchronous_ops indicates if APIs like initialize, read, erase, program, etc. can operate in asynchronous mode. Having this bit set to 1 means that the driver is capable of launching asynchronous operations; command completion for asynchronous operations is signaled by the invocation of a completion callback. If set to 1, drivers may still complete asynchronous operations synchronously as necessary–in which case they return a positive error code to indicate synchronous completion. If asynchronous_ops is not set, then all such APIs execute synchronously, and control returns to the caller with a status code only after the completion of the operation (or the discovery of a failure condition).
The element erase_all specifies that the ARM_Storage_EraseAll function is supported. Typically full chip erase is much faster than erasing the whole device using ARM_Storage_Erase.
Returned by:
struct ARM_STORAGE_STATUS |
Operating status of the storage controller.
Structure with information about the status of the Storage device.
The flag busy indicates that the driver is busy executing read/program/erase operation.
The flag error flag is cleared on start of read/program/erase operation and is set at the end of the current operation in case of error.
Returned by:
Data Fields | ||
---|---|---|
uint32_t | busy: 1 | Controller busy flag. |
uint32_t | error: 1 | Read/Program/Erase error flag (cleared on start of next operation) |
uint32_t | reserved: 30 |
ARM_Storage_Callback_t |
Provides the typedef for the callback function ARM_Storage_Callback_t.
Provides the typedef for the callback function ARM_Storage_Callback_t.
[in] | status | A code to indicate the status of the completed operation. For data transfer operations, the status field is overloaded in case of success to return the count of bytes successfully transferred; this can be done safely because error codes are negative values. |
[in] | operation | The command op-code. This value isn't essential, but it is expected that this information could be a quick and useful filter for the handler. |
Parameter for:
Command opcodes for Storage.
Command opcodes for the Storage interface. Completion callbacks use these codes to refer to completing commands. Refer to ARM_Storage_Callback_t.
ARM_DRIVER_VERSION ARM_Storage_GetVersion | ( | void | ) |
Get driver version.
The function ARM_Storage_GetVersion returns version information of the driver implementation in ARM_DRIVER_VERSION.
Example:
ARM_STORAGE_CAPABILITIES ARM_Storage_GetCapabilities | ( | void | ) |
Get driver capabilities.
The function ARM_Storage_GetCapabilities returns information about capabilities in this driver implementation. The data fields of the struct ARM_STORAGE_CAPABILITIES encode various capabilities, for example if the device is able to execute operations asynchronously.
Example:
int32_t ARM_Storage_Initialize | ( | ARM_Storage_Callback_t | callback | ) |
Initialize the Storage interface.
[in] | callback | Pointer to ARM_Storage_Callback_t. Caller-defined callback to be invoked upon command completion for asynchronous APIs (including the completion of initialization). Use a NULL pointer when no callback signals are required. |
The function ARM_Storage_Initialize is called when the middleware component starts operation. In addition to bringing the controller to a ready state, Initialize() receives a callback handler to be invoked upon completion of asynchronous operations.
ARM_Storage_Initialize() needs to be called explicitly before powering the peripheral using ARM_Storage_PowerControl(), and before initiating other accesses to the storage controller.
The function performs the following operations:
To start working with a peripheral the functions ARM_Storage_Initialize and ARM_Storage_PowerControl() need to be called in this order:
To stop working with a peripheral the functions ARM_Storage_PowerControl() and ARM_Storage_Uninitialize() need to be called in this order:
The functions ARM_Storage_PowerControl() and ARM_Storage_Uninitialize() always execute and can be used to put the peripheral into a Safe State, for example after any data transmission errors. To restart the peripheral in an error condition, you should first execute the Stop Sequence and then the Start Sequence.
int32_t ARM_Storage_Uninitialize | ( | void | ) |
De-initialize the Storage Interface.
It is called when the middleware component stops operation, and wishes to release the software resources used by the interface.
int32_t ARM_Storage_PowerControl | ( | ARM_POWER_STATE | state | ) |
Control the Storage interface power.
[in] | state | Power state |
The function ARM_Storage_PowerControl operates the power modes of the Storage interface.
To start working with a peripheral the functions Initialize and PowerControl need to be called in this order:
To stop working with a peripheral the functions PowerControl and Uninitialize need to be called in this order:
The functions ARM_Storage_PowerControl and ARM_Storage_Uninitialize always execute and can be used to put the peripheral into a Safe State, for example after any data transmission errors. To restart the peripheral in an error condition, you should first execute the Stop Sequence and then the Start Sequence.
The parameter state can have the following values:
int32_t ARM_Storage_ReadData | ( | uint64_t | addr, |
void * | data, | ||
uint32_t | size | ||
) |
Read data from Storage.
[in] | addr | Data address. |
[out] | data | Pointer to a buffer storing the data read from Storage. |
[in] | size | Number of bytes to read. The data buffer should be at least as large as this size. |
Read the contents of a range of storage memory into a buffer supplied by the caller. The buffer is owned by the caller and should remain accessible for the lifetime of this command.
int32_t ARM_Storage_ProgramData | ( | uint64_t | addr, |
const void * | data, | ||
uint32_t | size | ||
) |
Program data to Storage.
[in] | addr | This is the start address of the range to be written into. It needs to be aligned to the device's program_unit specified in ARM_STORAGE_INFO. |
[in] | data | The source of the write operation. The buffer is owned by the caller and should remain accessible for the lifetime of this command. |
[in] | size | The number of bytes requested to be written. The buffer should be at least as large as this size. |
Write the contents of a given memory buffer into a range of storage memory. In the case of flash memory, the destination range in storage memory typically has its contents in an erased state from a preceding erase operation. The source memory buffer is owned by the caller and should remain accessible for the lifetime of this command.
int32_t ARM_Storage_Erase | ( | uint64_t | addr, |
uint32_t | size | ||
) |
Erase Storage range.
[in] | addr | This is the start-address of the range to be erased. It must start at an 'erase_unit' boundary of the underlying block. |
[in] | size | Size (in bytes) of the range to be erased. 'addr + size' must be aligned with the 'erase_unit' of the underlying block. |
This function erases a range of storage specified by [addr, addr + size). Both 'addr' and 'addr + size' should align with the 'erase_unit'(s) of the respective owning storage block(s) (see ARM_STORAGE_BLOCK and ARM_STORAGE_BLOCK_ATTRIBUTES). The range to be erased will have its contents returned to the un-programmed state– i.e. to ARM_STORAGE_INFO::erased_value, which is usually 1 to indicate the pattern of all ones: 0xFF.
int32_t ARM_Storage_EraseAll | ( | void | ) |
Erase complete Storage.
This optional function erases the complete device. If the device does not support global erase then the function returns the error value ARM_DRIVER_ERROR_UNSUPPORTED. The data field 'erase_all' = 1 of the structure ARM_STORAGE_CAPABILITIES encodes that ARM_Storage_EraseAll is supported.
ARM_STORAGE_STATUS ARM_Storage_GetStatus | ( | void | ) |
Get Storage status.
Get the status of the current (or previous) command executed by the storage controller; stored in the structure ARM_STORAGE_STATUS.
int32_t ARM_Storage_GetInfo | ( | ARM_STORAGE_INFO * | info | ) |
Get Storage information.
[out] | info | A caller-supplied buffer capable of being filled in with an ARM_STORAGE_INFO. |
Get information about the Storage device; stored in the structure ARM_STORAGE_INFO.
uint32_t ARM_Storage_ResolveAddress | ( | uint64_t | addr | ) |
Resolve an address relative to the storage controller into a memory address.
[in] | addr | The address for which we want a resolution to the processor's physical address space. It is an offset from the start of the storage map maintained by the owning storage controller. |
Only applicable to devices with memory-mapped storage.
int32_t ARM_Storage_GetNextBlock | ( | const ARM_STORAGE_BLOCK * | prev_block, |
ARM_STORAGE_BLOCK * | next_block | ||
) |
Advance to the successor of the current block (iterator).
[in] | prev_block | An existing block (iterator) within the same storage controller. The memory buffer holding this block is owned by the caller. This pointer may be NULL; if so, the invocation fills in the first block into the out parameter: 'next_block'. |
[out] | next_block | A caller-owned buffer large enough to be filled in with the following ARM_STORAGE_BLOCK. It is legal to provide the same buffer using 'next_block' as was passed in with 'prev_block'. It is also legal to pass a NULL into this parameter if the caller isn't interested in populating a buffer with the next block, i.e. if the caller only wishes to establish the presence of a next block. |
This helper function fetches (an iterator to) the next block (or the first block if 'prev_block' is passed in as NULL). In the failure case, a terminating, invalid block iterator is filled into the out parameter: 'next_block'. In combination with ARM_STORAGE_VALID_BLOCK, it can be used to iterate over the sequence of blocks within the storage map:
int32_t ARM_Storage_GetBlock | ( | uint64_t | addr, |
ARM_STORAGE_BLOCK * | block | ||
) |
Find the storage block (iterator) encompassing a given storage address.
[in] | addr | Storage address in bytes. |
[out] | block | A caller-owned buffer large enough to be filled in with the ARM_STORAGE_BLOCK encapsulating the given address. This value can also be passed in as NULL if the caller isn't interested in populating a buffer with the block, if the caller only wishes to establish the presence of a containing storage block. |