diff --git a/hal/storage_abstraction/Driver_Common.h b/hal/storage_abstraction/Driver_Common.h deleted file mode 100644 index f61ff2cc1c..0000000000 --- a/hal/storage_abstraction/Driver_Common.h +++ /dev/null @@ -1,60 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* - * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DRIVER_COMMON_H -#define __DRIVER_COMMON_H - -#include -#include -#include - -/****** This file has been deprecated since mbed-os-5.5 *****/ - -#define ARM_DRIVER_VERSION_MAJOR_MINOR(major,minor) (((major) << 8) | (minor)) - -/** -\brief Driver Version -*/ -typedef struct _ARM_DRIVER_VERSION { - uint16_t api; ///< API version - uint16_t drv; ///< Driver version -} ARM_DRIVER_VERSION; - -/* General return codes */ -#define ARM_DRIVER_OK 0 ///< Operation succeeded -#define ARM_DRIVER_ERROR -1 ///< Unspecified error -#define ARM_DRIVER_ERROR_BUSY -2 ///< Driver is busy -#define ARM_DRIVER_ERROR_TIMEOUT -3 ///< Timeout occurred -#define ARM_DRIVER_ERROR_UNSUPPORTED -4 ///< Operation not supported -#define ARM_DRIVER_ERROR_PARAMETER -5 ///< Parameter error -#define ARM_DRIVER_ERROR_SPECIFIC -6 ///< Start of driver specific errors - -/** -\brief General power states -*/ -typedef enum _ARM_POWER_STATE { - ARM_POWER_OFF, ///< Power off: no operation possible - ARM_POWER_LOW, ///< Low Power mode: retain state, detect and signal wake-up events - ARM_POWER_FULL ///< Power on: full operation at maximum performance -} ARM_POWER_STATE; - -#endif /* __DRIVER_COMMON_H */ - -/** @}*/ diff --git a/hal/storage_abstraction/Driver_Storage.h b/hal/storage_abstraction/Driver_Storage.h deleted file mode 100644 index 363a26541f..0000000000 --- a/hal/storage_abstraction/Driver_Storage.h +++ /dev/null @@ -1,775 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* - * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DRIVER_STORAGE_H -#define __DRIVER_STORAGE_H - -#include - -/****** This file has been deprecated since mbed-os-5.5 *****/ - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#include "Driver_Common.h" - -#define ARM_STORAGE_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,00) /* API version */ - - -#define _ARM_Driver_Storage_(n) Driver_Storage##n -#define ARM_Driver_Storage_(n) _ARM_Driver_Storage_(n) - -#define ARM_STORAGE_INVALID_OFFSET (0xFFFFFFFFFFFFFFFFULL) ///< Invalid address (relative to a storage controller's - ///< address space). A storage block may never start at this address. - -#define ARM_STORAGE_INVALID_ADDRESS (0xFFFFFFFFUL) ///< Invalid address within the processor's memory address space. - ///< Refer to memory-mapped storage, i.e. < \ref ARM_DRIVER_STORAGE::ResolveAddress(). - -/****** Storage specific error codes *****/ -#define ARM_STORAGE_ERROR_NOT_ERASABLE (ARM_DRIVER_ERROR_SPECIFIC - 1) ///< Part (or all) of the range provided to Erase() isn't erasable. -#define ARM_STORAGE_ERROR_NOT_PROGRAMMABLE (ARM_DRIVER_ERROR_SPECIFIC - 2) ///< Part (or all) of the range provided to ProgramData() isn't programmable. -#define ARM_STORAGE_ERROR_PROTECTED (ARM_DRIVER_ERROR_SPECIFIC - 3) ///< Part (or all) of the range to Erase() or ProgramData() is protected. -#define ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE (ARM_DRIVER_ERROR_SPECIFIC - 4) ///< Runtime or sanity-check failure. - -/** - * \brief Attributes of the storage range within a storage block. - */ -typedef struct _ARM_STORAGE_BLOCK_ATTRIBUTES { - uint32_t erasable : 1; ///< Erasing blocks is permitted with a minimum granularity of 'erase_unit'. - ///< @note: if 'erasable' is 0--i.e. the 'erase' operation isn't available--then - ///< 'erase_unit' (see below) is immaterial and should be 0. - 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 \ref 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. - ///< @note: if 'erasable' (see above) is 0--i.e. the 'erase' operation isn't available--then - ///< 'erase_unit' is immaterial and should be 0. - 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. -} ARM_STORAGE_BLOCK_ATTRIBUTES; - -/** - * \brief A storage block is a range of memory with uniform attributes. Storage blocks - * combine to make up the address map of a storage controller. - */ -typedef struct _ARM_STORAGE_BLOCK { - 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. -} ARM_STORAGE_BLOCK; - -/** - * The check for a valid ARM_STORAGE_BLOCK. - */ -#define ARM_STORAGE_VALID_BLOCK(BLK) (((BLK)->addr != ARM_STORAGE_INVALID_OFFSET) && ((BLK)->size != 0)) - -/** - * \brief Values for encoding storage memory-types with respect to programmability. - * - * Please ensure that the maximum of the following memory types doesn't exceed 16; we - * encode this in a 4-bit field within ARM_STORAGE_INFO::programmability. - */ -#define ARM_STORAGE_PROGRAMMABILITY_RAM (0x0) -#define ARM_STORAGE_PROGRAMMABILITY_ROM (0x1) ///< Read-only memory. -#define ARM_STORAGE_PROGRAMMABILITY_WORM (0x2) ///< write-once-read-only-memory (WORM). -#define ARM_STORAGE_PROGRAMMABILITY_ERASABLE (0x3) ///< re-programmable based on erase. Supports multiple writes. - -/** - * Values for encoding data-retention levels for storage blocks. - * - * Please ensure that the maximum of the following retention types doesn't exceed 16; we - * encode this in a 4-bit field within ARM_STORAGE_INFO::retention_level. - */ -#define ARM_RETENTION_WHILE_DEVICE_ACTIVE (0x0) ///< Data is retained only during device activity. -#define ARM_RETENTION_ACROSS_SLEEP (0x1) ///< Data is retained across processor sleep. -#define ARM_RETENTION_ACROSS_DEEP_SLEEP (0x2) ///< Data is retained across processor deep-sleep. -#define ARM_RETENTION_BATTERY_BACKED (0x3) ///< Data is battery-backed. Device can be powered off. -#define ARM_RETENTION_NVM (0x4) ///< Data is retained in non-volatile memory. - -/** - * Device Data Security Protection Features. Applicable mostly to EXTERNAL_NVM. - */ -typedef struct _ARM_STORAGE_SECURITY_FEATURES { - uint32_t acls : 1; ///< Protection against internal software attacks using ACLs. - uint32_t rollback_protection : 1; ///< Roll-back protection. Set to true if the creator of the storage - ///< can ensure that an external attacker can't force an - ///< older firmware to run or to revert back to a previous state. - uint32_t tamper_proof : 1; ///< Tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors). - uint32_t internal_flash : 1; ///< Internal flash. - uint32_t reserved1 : 12; - - /** - * Encode support for hardening against various classes of attacks. - */ - uint32_t software_attacks : 1; ///< device software (malware running on the device). - uint32_t board_level_attacks : 1; ///< board level attacks (debug probes, copy protection fuses.) - uint32_t chip_level_attacks : 1; ///< chip level attacks (tamper-protection). - uint32_t side_channel_attacks : 1; ///< side channel attacks. - uint32_t reserved2 : 12; -} ARM_STORAGE_SECURITY_FEATURES; - -#define ARM_STORAGE_PROGRAM_CYCLES_INFINITE (0UL) /**< Infinite or unknown endurance for reprogramming. */ - -/** - * \brief Storage information. This contains device-metadata. It is the return - * value from calling GetInfo() on the storage driver. - * - * \details These fields serve a different purpose than the ones contained in - * \ref ARM_STORAGE_CAPABILITIES, which is another structure containing - * device-level metadata. ARM_STORAGE_CAPABILITIES describes the API - * capabilities, whereas ARM_STORAGE_INFO describes the device. Furthermore - * ARM_STORAGE_CAPABILITIES fits within a single word, and is designed to be - * passed around by value; ARM_STORAGE_INFO, on the other hand, contains - * metadata which doesn't fit into a single word and requires the use of - * pointers to be moved around. - */ -typedef struct _ARM_STORAGE_INFO { - 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. - ///< @note: setting program_unit to 0 has the effect of disabling the size and alignment - ///< restrictions (setting it to 1 also has the same effect). - 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. - ///< @note: For a memory-mapped block which isn't erasable but is programmable (i.e. if - ///< 'erasable' is set to 0, but 'programmable' is 1), writes should be possible directly to - ///< the memory-mapped storage without going through the ProgramData operation. - uint32_t programmability : 4; ///< A value to indicate storage programmability. - uint32_t retention_level : 4; - uint32_t reserved : 22; - ARM_STORAGE_SECURITY_FEATURES security; ///< \ref ARM_STORAGE_SECURITY_FEATURES -} ARM_STORAGE_INFO; - -/** -\brief Operating status of the storage controller. -*/ -typedef struct _ARM_STORAGE_STATUS { - uint32_t busy : 1; ///< Controller busy flag - uint32_t error : 1; ///< Read/Program/Erase error flag (cleared on start of next operation) -} ARM_STORAGE_STATUS; - -/** - * \brief Storage Driver API Capabilities. - * - * This data structure is designed to fit within a single word so that it can be - * fetched cheaply using a call to driver->GetCapabilities(). - */ -typedef struct _ARM_STORAGE_CAPABILITIES { - uint32_t asynchronous_ops : 1; ///< Used to indicate if APIs like initialize, - ///< read, erase, program, etc. can operate in asynchronous mode. - ///< Setting this bit to 1 means that the driver is capable - ///< of launching asynchronous operations; command completion 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. - uint32_t erase_all : 1; ///< Supports EraseAll operation. - uint32_t reserved : 30; -} ARM_STORAGE_CAPABILITIES; - -/** - * Command opcodes for Storage. Completion callbacks use these codes to refer to - * completing commands. Refer to \ref ARM_Storage_Callback_t. - */ -typedef enum _ARM_STORAGE_OPERATION { - ARM_STORAGE_OPERATION_GET_VERSION, - ARM_STORAGE_OPERATION_GET_CAPABILITIES, - ARM_STORAGE_OPERATION_INITIALIZE, - ARM_STORAGE_OPERATION_UNINITIALIZE, - ARM_STORAGE_OPERATION_POWER_CONTROL, - ARM_STORAGE_OPERATION_READ_DATA, - ARM_STORAGE_OPERATION_PROGRAM_DATA, - ARM_STORAGE_OPERATION_ERASE, - ARM_STORAGE_OPERATION_ERASE_ALL, - ARM_STORAGE_OPERATION_GET_STATUS, - ARM_STORAGE_OPERATION_GET_INFO, - ARM_STORAGE_OPERATION_RESOLVE_ADDRESS, - ARM_STORAGE_OPERATION_GET_NEXT_BLOCK, - ARM_STORAGE_OPERATION_GET_BLOCK -} ARM_STORAGE_OPERATION; - -/** - * Declaration of the callback-type for command completion. - * - * @param [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 items successfully transferred; this - * can be done safely because error codes are negative values. - * - * @param [in] operation - * The command op-code. This value isn't essential for the callback in - * the presence of the command instance-id, but it is expected that - * this information could be a quick and useful filter. - */ -typedef void (*ARM_Storage_Callback_t)(int32_t status, ARM_STORAGE_OPERATION operation); - -/** - * This is the set of operations constituting the Storage driver. Their - * implementation is platform-specific, and needs to be supplied by the - * porting effort. - * - * Some APIs within `ARM_DRIVER_STORAGE` will always operate synchronously: - * GetVersion, GetCapabilities, GetStatus, GetInfo, ResolveAddress, - * GetNextBlock, and GetBlock. This means that control returns to the caller - * with a relevant status code only after the completion of the operation (or - * the discovery of a failure condition). - * - * The remainder of the APIs: Initialize, Uninitialize, PowerControl, ReadData, - * ProgramData, Erase, EraseAll, can function asynchronously if the underlying - * controller supports it--i.e. if ARM_STORAGE_CAPABILITIES::asynchronous_ops is - * set. In the case of asynchronous operation, the invocation returns early - * (with ARM_DRIVER_OK) and results in a completion callback later. If - * ARM_STORAGE_CAPABILITIES::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). - * - * If ARM_STORAGE_CAPABILITIES::asynchronous_ops is set, a storage driver may - * still choose to execute asynchronous operations in a synchronous manner. If - * so, the driver returns a positive value to indicate successful synchronous - * completion (or an error code in case of failure) and no further invocation of - * completion callback should be expected. The expected return value for - * synchronous completion of such asynchronous operations varies depending on - * the operation. For operations involving data access, it often equals the - * amount of data transferred or affected. For non data-transfer operations, - * such as EraseAll or Initialize, it is usually 1. - * - * Here's a code snippet to suggest how asynchronous APIs might be used by - * callers to handle both synchronous and asynchronous execution by the - * underlying storage driver: - * \code - * ASSERT(ARM_DRIVER_OK == 0); // this is a precondition; it doesn't need to be put in code - * int32_t returnValue = drv->asynchronousAPI(...); - * if (returnValue < ARM_DRIVER_OK) { - * // handle error. - * } else if (returnValue == ARM_DRIVER_OK) { - * ASSERT(drv->GetCapabilities().asynchronous_ops == 1); - * // handle early return from asynchronous execution; remainder of the work is done in the callback handler. - * } else { - * ASSERT(returnValue == EXPECTED_RETURN_VALUE_FOR_SYNCHRONOUS_COMPLETION); - * // handle synchronous completion. - * } - * \endcode - */ -typedef struct _ARM_DRIVER_STORAGE { - /** - * \brief Get driver version. - * - * The function GetVersion() returns version information of the driver implementation in ARM_DRIVER_VERSION. - * - * - API version is the version of the CMSIS-Driver specification used to implement this driver. - * - Driver version is source code version of the actual driver implementation. - * - * Example: - * \code - * extern ARM_DRIVER_STORAGE *drv_info; - * - * void read_version (void) { - * ARM_DRIVER_VERSION version; - * - * version = drv_info->GetVersion (); - * if (version.api < 0x10A) { // requires at minimum API version 1.10 or higher - * // error handling - * return; - * } - * } - * \endcode - * - * @return \ref ARM_DRIVER_VERSION. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - * - * @note The function GetVersion() can be called any time to obtain the - * required information from the driver (even before initialization). It - * always returns the same information. - */ - ARM_DRIVER_VERSION (*GetVersion)(void); - - /** - * \brief Get driver capabilities. - * - * \details The function 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: - * \code - * extern ARM_DRIVER_STORAGE *drv_info; - * - * void read_capabilities (void) { - * ARM_STORAGE_CAPABILITIES drv_capabilities; - * - * drv_capabilities = drv_info->GetCapabilities (); - * // interrogate capabilities - * - * } - * \endcode - * - * @return \ref ARM_STORAGE_CAPABILITIES. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - * - * @note The function GetCapabilities() can be called any time to obtain the - * required information from the driver (even before initialization). It - * always returns the same information. - */ - ARM_STORAGE_CAPABILITIES (*GetCapabilities)(void); - - /** - * \brief Initialize the Storage Interface. - * - * The function 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. - * - * Initialize() needs to be called explicitly before - * powering the peripheral using PowerControl(), and before initiating other - * accesses to the storage controller. - * - * The function performs the following operations: - * - Initializes the resources needed for the Storage interface. - * - Registers the \ref ARM_Storage_Callback_t callback function. - * - * To start working with a peripheral the functions Initialize and PowerControl need to be called in this order: - * drv->Initialize (...); // Allocate I/O pins - * drv->PowerControl (ARM_POWER_FULL); // Power up peripheral, setup IRQ/DMA - * - * - Initialize() typically allocates the I/O resources (pins) for the - * peripheral. The function can be called multiple times; if the I/O resources - * are already initialized it performs no operation and just returns with - * ARM_DRIVER_OK. - * - * - PowerControl (ARM_POWER_FULL) sets the peripheral registers including - * interrupt (NVIC) and optionally DMA. The function can be called multiple - * times; if the registers are already set it performs no operation and just - * returns with ARM_DRIVER_OK. - * - * To stop working with a peripheral the functions PowerControl and Uninitialize need to be called in this order: - * drv->PowerControl (ARM_POWER_OFF); // Terminate any pending transfers, reset IRQ/DMA, power off peripheral - * drv->Uninitialize (...); // Release I/O pins - * - * The functions PowerControl and 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. - * - * @param [in] callback - * 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. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with a status value of ARM_DRIVER_OK or an error-code. In the - * case of synchronous execution, control returns after completion with a - * value of 1. Return values less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*Initialize)(ARM_Storage_Callback_t callback); - - /** - * \brief De-initialize the Storage Interface. - * - * The function Uninitialize() de-initializes the resources of Storage interface. - * - * It is called when the middleware component stops operation, and wishes to - * release the software resources used by the interface. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with a status value of ARM_DRIVER_OK or an error-code. In the - * case of synchronous execution, control returns after completion with a - * value of 1. Return values less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*Uninitialize)(void); - - /** - * \brief Control the Storage interface power. - * - * The function \b 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: - * drv->Initialize (...); // Allocate I/O pins - * drv->PowerControl (ARM_POWER_FULL); // Power up peripheral, setup IRQ/DMA - * - * - Initialize() typically allocates the I/O resources (pins) for the - * peripheral. The function can be called multiple times; if the I/O resources - * are already initialized it performs no operation and just returns with - * ARM_DRIVER_OK. - * - * - PowerControl (ARM_POWER_FULL) sets the peripheral registers including - * interrupt (NVIC) and optionally DMA. The function can be called multiple - * times; if the registers are already set it performs no operation and just - * returns with ARM_DRIVER_OK. - * - * To stop working with a peripheral the functions PowerControl and Uninitialize need to be called in this order: - * - * drv->PowerControl (ARM_POWER_OFF); // Terminate any pending transfers, reset IRQ/DMA, power off peripheral - * drv->Uninitialize (...); // Release I/O pins - * - * The functions PowerControl and 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. - * - * @param state - * \ref ARM_POWER_STATE. The target power-state for the storage controller. - * The parameter state can have the following values: - * - ARM_POWER_FULL : set-up peripheral for data transfers, enable interrupts - * (NVIC) and optionally DMA. Can be called multiple times. If the peripheral - * is already in this mode, then the function performs no operation and returns - * with ARM_DRIVER_OK. - * - ARM_POWER_LOW : may use power saving. Returns ARM_DRIVER_ERROR_UNSUPPORTED when not implemented. - * - ARM_POWER_OFF : terminates any pending data transfers, disables peripheral, disables related interrupts and DMA. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with a status value of ARM_DRIVER_OK or an error-code. In the - * case of synchronous execution, control returns after completion with a - * value of 1. Return values less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*PowerControl)(ARM_POWER_STATE state); - - /** - * \brief read the contents of a given address range from the storage device. - * - * \details 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. - * - * @param [in] addr - * This specifies the address from where to read data. - * - * @param [out] data - * The destination of the read operation. The buffer - * is owned by the caller and should remain accessible for the - * lifetime of this command. - * - * @param [in] size - * The number of bytes requested to read. The data buffer - * should be at least as large as this size. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with the number of successfully transferred bytes passed in as - * the 'status' parameter. In the case of synchronous execution, control - * returns after completion with a positive transfer-count. Return values - * less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*ReadData)(uint64_t addr, void *data, uint32_t size); - - /** - * \brief program (write into) the contents of a given address range of the storage device. - * - * \details 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. - * - * @param [in] addr - * This is the start address of the range to be written into. It - * needs to be aligned to the device's \em program_unit - * specified in \ref ARM_STORAGE_INFO. - * - * @param [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. - * - * @param [in] size - * The number of bytes requested to be written. The buffer - * should be at least as large as this size. \note 'size' should - * be a multiple of the device's 'program_unit' (see \ref - * ARM_STORAGE_INFO). - * - * @note It is best for the middleware to write in units of - * 'optimal_program_unit' (\ref ARM_STORAGE_INFO) of the device. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with the number of successfully transferred bytes passed in as - * the 'status' parameter. In the case of synchronous execution, control - * returns after completion with a positive transfer-count. Return values - * less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*ProgramData)(uint64_t addr, const void *data, uint32_t size); - - /** - * @brief Erase Storage range. - * - * @details 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 \ref - * ARM_STORAGE_BLOCK and \ref ARM_STORAGE_BLOCK_ATTRIBUTES). The range to - * be erased will have its contents returned to the un-programmed state-- - * i.e. to 'erased_value' (see \ref ARM_STORAGE_BLOCK_ATTRIBUTES), which - * is usually 1 to indicate the pattern of all ones: 0xFF. - * - * @param [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. - * - * @param [in] size - * Size (in bytes) of the range to be erased. 'addr + size' - * must be aligned with the 'erase_unit' of the underlying - * block. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return - * If the range to be erased doesn't align with the erase_units of the - * respective start and end blocks, ARM_DRIVER_ERROR_PARAMETER is returned. - * If any part of the range is protected, ARM_STORAGE_ERROR_PROTECTED is - * returned. If any part of the range is not erasable, - * ARM_STORAGE_ERROR_NOT_ERASABLE is returned. All such sanity-check - * failures result in the error code being returned synchronously and the - * storage bytes within the range remain unaffected. - * Otherwise the function executes in the following ways: - * If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with the number of successfully erased bytes passed in as - * the 'status' parameter. In the case of synchronous execution, control - * returns after completion with a positive erase-count. Return values - * less than ARM_DRIVER_OK (0) signify errors. - * - * @note Erase() may return a smaller (positive) value than the size of the - * requested range. The returned value indicates the actual number of bytes - * erased. It is the caller's responsibility to follow up with an appropriate - * request to complete the operation. - * - * @note in the case of a failed erase (except when - * ARM_DRIVER_ERROR_PARAMETER, ARM_STORAGE_ERROR_PROTECTED, or - * ARM_STORAGE_ERROR_NOT_ERASABLE is returned synchronously), the - * requested range should be assumed to be in an unknown state. The - * previous contents may not be retained. - */ - int32_t (*Erase)(uint64_t addr, uint32_t size); - - /** - * @brief Erase complete storage. Optional function for faster erase of the complete device. - * - * This optional function erases the complete device. If the device does not - * support global erase then the function returns the error value \ref - * ARM_DRIVER_ERROR_UNSUPPORTED. The data field \em 'erase_all' = 1 - * of the structure \ref ARM_STORAGE_CAPABILITIES encodes that - * ARM_STORAGE_EraseAll is supported. - * - * @note This API may execute asynchronously if - * ARM_STORAGE_CAPABILITIES::asynchronous_ops is set. Asynchronous - * execution is optional even if 'asynchronous_ops' is set. - * - * @return - * If any part of the storage range is protected, - * ARM_STORAGE_ERROR_PROTECTED is returned. If any part of the storage - * range is not erasable, ARM_STORAGE_ERROR_NOT_ERASABLE is returned. All - * such sanity-check failures result in the error code being returned - * synchronously and the storage bytes within the range remain unaffected. - * Otherwise the function executes in the following ways: - * If asynchronous activity is launched, an invocation returns - * ARM_DRIVER_OK, and the caller can expect to receive a callback in the - * future with ARM_DRIVER_OK passed in as the 'status' parameter. In the - * case of synchronous execution, control returns after completion with a - * value of 1. Return values less than ARM_DRIVER_OK (0) signify errors. - */ - int32_t (*EraseAll)(void); - - /** - * @brief Get the status of the current (or previous) command executed by the - * storage controller; stored in the structure \ref ARM_STORAGE_STATUS. - * - * @return - * The status of the underlying controller. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - */ - ARM_STORAGE_STATUS (*GetStatus)(void); - - /** - * @brief Get information about the Storage device; stored in the structure \ref ARM_STORAGE_INFO. - * - * @param [out] info - * A caller-supplied buffer capable of being filled in with an - * \ref ARM_STORAGE_INFO. - * - * @return ARM_DRIVER_OK if a ARM_STORAGE_INFO structure containing top level - * metadata about the storage controller is filled into the supplied - * buffer, else an appropriate error value. - * - * @note It is the caller's responsibility to ensure that the buffer passed in - * is able to be initialized with a \ref ARM_STORAGE_INFO. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - */ - int32_t (*GetInfo)(ARM_STORAGE_INFO *info); - - /** - * \brief For memory-mapped storage, resolve an address relative to - * the storage controller into a memory address. - * - * @param addr - * This is 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. - * - * @return - * The resolved address in the processor's address space; else - * ARM_STORAGE_INVALID_ADDRESS, if no resolution is possible. - * - * @note This API returns synchronously. The invocation should return quickly, - * and result in a resolved address. - */ - uint32_t (*ResolveAddress)(uint64_t addr); - - /** - * @brief Advance to the successor of the current block (iterator), or fetch - * the first block (if 'prev_block' is passed in as NULL). - * - * @details 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 \ref - * ARM_STORAGE_VALID_BLOCK(), it can be used to iterate over the sequence - * of blocks within the storage map: - * - * \code - * ARM_STORAGE_BLOCK block; - * for (drv->GetNextBlock(NULL, &block); ARM_STORAGE_VALID_BLOCK(&block); drv->GetNextBlock(&block, &block)) { - * // make use of block - * } - * \endcode - * - * @param[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'. - * - * @param[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. - * - * @return ARM_DRIVER_OK if a valid next block is found (or first block, if - * prev_block is passed as NULL); upon successful operation, the contents - * of the next (or first) block are filled into the buffer pointed to by - * the parameter 'next_block' and ARM_STORAGE_VALID_BLOCK(next_block) is - * guaranteed to be true. Upon reaching the end of the sequence of blocks - * (iterators), or in case the driver is unable to fetch information about - * the next (or first) block, an error (negative) value is returned and an - * invalid StorageBlock is populated into the supplied buffer. If - * prev_block is NULL, the first block is returned. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - */ - int32_t (*GetNextBlock)(const ARM_STORAGE_BLOCK* prev_block, ARM_STORAGE_BLOCK *next_block); - - /** - * @brief Find the storage block (iterator) encompassing a given storage address. - * - * @param[in] addr - * Storage address in bytes. - * - * @param[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. - * - * @return ARM_DRIVER_OK if a containing storage-block is found. In this case, - * if block is non-NULL, the buffer pointed to by it is populated with - * the contents of the storage block--i.e. if block is valid and a block is - * found, ARM_STORAGE_VALID_BLOCK(block) would return true following this - * call. If there is no storage block containing the given offset, or in - * case the driver is unable to resolve an address to a storage-block, an - * error (negative) value is returned and an invalid StorageBlock is - * populated into the supplied buffer. - * - * @note This API returns synchronously--it does not result in an invocation - * of a completion callback. - */ - int32_t (*GetBlock)(uint64_t addr, ARM_STORAGE_BLOCK *block); -} const ARM_DRIVER_STORAGE; - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif /* __DRIVER_STORAGE_H */ - -/** @}*/ diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/storage_driver.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/storage_driver.c deleted file mode 100644 index 845fbe4842..0000000000 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/storage_driver.c +++ /dev/null @@ -1,1244 +0,0 @@ -/* - * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Driver_Storage.h" -#include "cmsis_nvic.h" -#include "MK64F12.h" - -#if defined(MCU_MEM_MAP_VERSION) && ((MCU_MEM_MAP_VERSION > 0x0200u) || ((MCU_MEM_MAP_VERSION == 0x0200u) && (MCU_MEM_MAP_VERSION_MINOR >= 0x0008u))) -#define USING_KSDK2 1 -#endif - -#ifndef USING_KSDK2 -#include "device/MK64F12/MK64F12_ftfe.h" -#else -#include "fsl_flash.h" -#endif - -#include - -/* Redefine this macro to a printf equivalent to print trace */ -#define tr_debug(...) - - -#ifdef USING_KSDK2 -/*! - * @name Misc utility defines - * @{ - */ -#ifndef ALIGN_DOWN -#define ALIGN_DOWN(x, a) ((x) & (uint32_t)(-((int32_t)(a)))) -#endif -#ifndef ALIGN_UP -#define ALIGN_UP(x, a) (-((int32_t)((uint32_t)(-((int32_t)(x))) & (uint32_t)(-((int32_t)(a)))))) -#endif - -#define BYTES_JOIN_TO_WORD_1_3(x, y) ((((uint32_t)(x)&0xFFU) << 24) | ((uint32_t)(y)&0xFFFFFFU)) -#define BYTES_JOIN_TO_WORD_2_2(x, y) ((((uint32_t)(x)&0xFFFFU) << 16) | ((uint32_t)(y)&0xFFFFU)) -#define BYTES_JOIN_TO_WORD_3_1(x, y) ((((uint32_t)(x)&0xFFFFFFU) << 8) | ((uint32_t)(y)&0xFFU)) -#define BYTES_JOIN_TO_WORD_1_1_2(x, y, z) \ - ((((uint32_t)(x)&0xFFU) << 24) | (((uint32_t)(y)&0xFFU) << 16) | ((uint32_t)(z)&0xFFFFU)) -#define BYTES_JOIN_TO_WORD_1_2_1(x, y, z) \ - ((((uint32_t)(x)&0xFFU) << 24) | (((uint32_t)(y)&0xFFFFU) << 8) | ((uint32_t)(z)&0xFFU)) -#define BYTES_JOIN_TO_WORD_2_1_1(x, y, z) \ - ((((uint32_t)(x)&0xFFFFU) << 16) | (((uint32_t)(y)&0xFFU) << 8) | ((uint32_t)(z)&0xFFU)) -#define BYTES_JOIN_TO_WORD_1_1_1_1(x, y, z, w) \ - ((((uint32_t)(x)&0xFFU) << 24) | (((uint32_t)(y)&0xFFU) << 16) | (((uint32_t)(z)&0xFFU) << 8) | \ - ((uint32_t)(w)&0xFFU)) -/*@}*/ - -/*! - * @name Common flash register info defines - * @{ - */ -#if defined(FTFA) -#define FTFx FTFA -#define FTFx_BASE FTFA_BASE -#define FTFx_FSTAT_CCIF_MASK FTFA_FSTAT_CCIF_MASK -#define FTFx_FSTAT_RDCOLERR_MASK FTFA_FSTAT_RDCOLERR_MASK -#define FTFx_FSTAT_ACCERR_MASK FTFA_FSTAT_ACCERR_MASK -#define FTFx_FSTAT_FPVIOL_MASK FTFA_FSTAT_FPVIOL_MASK -#define FTFx_FSTAT_MGSTAT0_MASK FTFA_FSTAT_MGSTAT0_MASK -#define FTFx_FSEC_SEC_MASK FTFA_FSEC_SEC_MASK -#define FTFx_FSEC_KEYEN_MASK FTFA_FSEC_KEYEN_MASK -#define FTFx_FCNFG_CCIF_MASK FTFA_FCNFG_CCIE_MASK -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM -#define FTFx_FCNFG_RAMRDY_MASK FTFA_FCNFG_RAMRDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */ -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM -#define FTFx_FCNFG_EEERDY_MASK FTFA_FCNFG_EEERDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */ -#elif defined(FTFE) -#define FTFx FTFE -#define FTFx_BASE FTFE_BASE -#define FTFx_FSTAT_CCIF_MASK FTFE_FSTAT_CCIF_MASK -#define FTFx_FSTAT_RDCOLERR_MASK FTFE_FSTAT_RDCOLERR_MASK -#define FTFx_FSTAT_ACCERR_MASK FTFE_FSTAT_ACCERR_MASK -#define FTFx_FSTAT_FPVIOL_MASK FTFE_FSTAT_FPVIOL_MASK -#define FTFx_FSTAT_MGSTAT0_MASK FTFE_FSTAT_MGSTAT0_MASK -#define FTFx_FSEC_SEC_MASK FTFE_FSEC_SEC_MASK -#define FTFx_FSEC_KEYEN_MASK FTFE_FSEC_KEYEN_MASK -#define FTFx_FCNFG_CCIF_MASK FTFE_FCNFG_CCIE_MASK -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM -#define FTFx_FCNFG_RAMRDY_MASK FTFE_FCNFG_RAMRDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */ -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM -#define FTFx_FCNFG_EEERDY_MASK FTFE_FCNFG_EEERDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */ -#elif defined(FTFL) -#define FTFx FTFL -#define FTFx_BASE FTFL_BASE -#define FTFx_FSTAT_CCIF_MASK FTFL_FSTAT_CCIF_MASK -#define FTFx_FSTAT_RDCOLERR_MASK FTFL_FSTAT_RDCOLERR_MASK -#define FTFx_FSTAT_ACCERR_MASK FTFL_FSTAT_ACCERR_MASK -#define FTFx_FSTAT_FPVIOL_MASK FTFL_FSTAT_FPVIOL_MASK -#define FTFx_FSTAT_MGSTAT0_MASK FTFL_FSTAT_MGSTAT0_MASK -#define FTFx_FSEC_SEC_MASK FTFL_FSEC_SEC_MASK -#define FTFx_FSEC_KEYEN_MASK FTFL_FSEC_KEYEN_MASK -#define FTFx_FCNFG_CCIF_MASK FTFL_FCNFG_CCIE_MASK -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM -#define FTFx_FCNFG_RAMRDY_MASK FTFL_FCNFG_RAMRDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */ -#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM -#define FTFx_FCNFG_EEERDY_MASK FTFL_FCNFG_EEERDY_MASK -#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */ -#else -#error "Unknown flash controller" -#endif -/*@}*/ - -/*! @brief Access to FTFx->FCCOB */ -extern volatile uint32_t *const kFCCOBx; - -#endif /* #ifdef USING_KSDK2 */ - -#ifdef USING_KSDK2 -#define ERASE_UNIT (FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE) -#define BLOCK1_START_ADDR (FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE) -#define BLOCK1_SIZE (FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE) -#define PROGRAM_UNIT (FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE) -#define OPTIMAL_PROGRAM_UNIT (1024UL) -#define PROGRAM_PHRASE_SIZEOF_INLINE_DATA (8) -#define SIZEOF_DOUBLE_PHRASE (FSL_FEATURE_FLASH_PFLASH_SECTION_CMD_ADDRESS_ALIGMENT) -#else /* ifdef USING_KSDK2 */ -#define ERASE_UNIT (4096) -#define BLOCK1_START_ADDR (0x80000UL) -#define BLOCK1_SIZE (0x80000UL) -#define PROGRAM_UNIT (8UL) -#define OPTIMAL_PROGRAM_UNIT (1024UL) -#define PROGRAM_PHRASE_SIZEOF_INLINE_DATA (8) -#define SIZEOF_DOUBLE_PHRASE (16) -#endif /* #ifdef USING_KSDK2 */ - -/* While the K64F flash controller is capable of launching operations asynchronously and - * allowing program execution to continue while an erase/program is active, it - * doesn't allow simultaneous read accesses while and erase/program is active on - * the same block of flash. - * - * Read/fetch accesses can originate arbitrarily as a result of program - * execution. This means that code which operates on flash should not reside in - * flash; or at least it should not reside in the same bank of flash as it is - * operating upon. The only way to ensure that application code and flash driver - * are residing on separate banks of flash is to reserve bank-0 (or BLOCK0) for - * the application and bank-1 (BLOCK1) for the driver--this also happens to be - * the default setting. - * - * But it is quite likely that this default will be over-ridden by the use of - * config options depending upon the actual application. If we don't have a - * clean separation between the application and the space managed by this - * driver, then we need to enforce the following: - * - * - Force synchronous mode of execution in the storage_driver. - * - Disable interrupts during erase/program operations. - * - Ensure all code and data structures used in the storage driver execute - * out of RAM. Refer to __RAMFUNC (below) which allows for this. - * - * It is difficult to determine the application's span of internal-flash at - * compile time. Therefore we assume that STORAGE_START_ADDR is the - * boundary between application and this driver. When this boundary is set to - * lie at BLOCK1_START_ADDR, there is no possibility of read-while-write run- - * time errors. - * - * In the following, caps.asynchronous_ops is defined to be 1 if and only if - * asynchronous operation mode is requested and there doesn't exist the - * possibility of concurrent reads. - */ - -#if (defined(STORAGE_START_ADDR) && (STORAGE_START_ADDR != BLOCK1_START_ADDR)) -#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 1 -#else -#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 0 -#endif - -/* Define '__RAMFUNC' as an attribute to mark a function as residing in RAM. - * Use of __RAMFUNC puts a function in the .data section--i.e. the - * initialized data section. This will be copied into RAM automatically by the - * startup sequence. */ -#ifndef __RAMFUNC -#if defined(__GNUC__) || defined(__clang__) // GCC and llvm/clang -#define __RAMFUNC __attribute__ ((section (".data#"), noinline)) /* The '#' following ".data" needs a bit of - * explanation. Without it, we are liable to get the following warning 'Warning: ignoring - * changed section attributes for .data'. This is because __attribute__((section(".data"))) - * generates the following assembly: - * - * .section .data,"ax",%progbits - * - * But .data doesn't need the 'x' (execute) attribute bit. To remove the warning, we specify - * the attribute with a '#' at the tail, which emits: - * - * .section .data#,"ax",%progbits - * - * Note that '#' (in the above) acts like a comment-start, and masks the additional - * attributes which don't apply to '.data'. - */ -#elif defined (__CC_ARM) -#define __RAMFUNC __attribute__ ((section(".ramfunc"), noinline)) -#elif defined ( __ICCARM__ ) -#define __RAMFUNC __ramfunc -#else // unknown compiler - #error "This compiler is not yet supported. If you can contribute support for defining a function to be RAM resident, please provide a definition for __RAMFUNC" -#endif -#endif /* #ifndef __RAMFUNC */ - -/* - * forward declarations - */ -static int32_t getBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP); -static int32_t nextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP); - -/* - * Global state for the driver. - */ -struct mtd_k64f_data { - ARM_Storage_Callback_t commandCompletionCallback; - bool initialized; - ARM_POWER_STATE powerState; - - ARM_STORAGE_OPERATION currentCommand; - uint64_t currentOperatingStorageAddress; - size_t sizeofCurrentOperation; - size_t amountLeftToOperate; - const uint8_t *currentOperatingData; -} mtd_k64f_data; - -/* - * Static configuration. - */ -static const ARM_STORAGE_BLOCK blockTable[] = { - { - /**< This is the start address of the flash block. */ -#ifdef STORAGE_START_ADDR - .addr = STORAGE_START_ADDR, -#else - .addr = BLOCK1_START_ADDR, -#endif - - /**< This is the size of the flash block, in units of bytes. - * Together with addr, it describes a range [addr, addr+size). */ -#ifdef STORAGE_SIZE - .size = STORAGE_SIZE, -#else - .size = BLOCK1_SIZE, -#endif - - .attributes = { /**< Attributes for this block. */ - .erasable = 1, - .programmable = 1, - .executable = 1, - .protectable = 1, - .erase_unit = ERASE_UNIT, - .protection_unit = BLOCK1_SIZE / 32, - } - } -}; - -static const ARM_DRIVER_VERSION version = { - .api = ARM_STORAGE_API_VERSION, - .drv = ARM_DRIVER_VERSION_MAJOR_MINOR(1,00) -}; - - -#if ((!defined(STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) && \ - !EXISTS_POSSIBILITY_OF_CONCURRENT_READ) -#define ASYNC_OPS 1 -#else -#define ASYNC_OPS 0 -#endif - -static const ARM_STORAGE_CAPABILITIES caps = { - /**< Signal Flash Ready event. In other words, can APIs like initialize, - * read, erase, program, etc. operate in asynchronous mode? - * Setting this bit to 1 means that the driver is capable of launching - * asynchronous operations; command completion is signaled by the - * generation of an event or the invocation of a completion callback - * (depending on how the flash controller has been initialized). 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. */ - .asynchronous_ops = ASYNC_OPS, - - /* Enable chip-erase functionality if we own all of block-1. */ - #if ((!defined (STORAGE_START_ADDR) || (STORAGE_START_ADDR == BLOCK1_START_ADDR)) && \ - (!defined (STORAGE_SIZE) || (STORAGE_SIZE == BLOCK1_SIZE))) - .erase_all = 1, /**< Supports EraseChip operation. */ - #else - .erase_all = 0, /**< Supports EraseChip operation. */ - #endif -}; - -static const ARM_STORAGE_INFO info = { -#ifdef STORAGE_SIZE - .total_storage = STORAGE_SIZE, /**< Total available storage, in units of octets. */ -#else - .total_storage = BLOCK1_SIZE, /**< Total available storage, in units of octets. By default, BLOCK0 is reserved to hold program code. */ -#endif - - .program_unit = PROGRAM_UNIT, - .optimal_program_unit = OPTIMAL_PROGRAM_UNIT, - - .program_cycles = ARM_STORAGE_PROGRAM_CYCLES_INFINITE, /**< A measure of endurance for reprogramming. - * Use ARM_STOR_PROGRAM_CYCLES_INFINITE for infinite or unknown endurance. */ - - .erased_value = 0x1, /**< Contents of erased memory (1 to indicate erased octets with state 0xFF). */ - .memory_mapped = 1, - - .programmability = ARM_STORAGE_PROGRAMMABILITY_ERASABLE, /**< A value of type enum ARM_STOR_PROGRAMMABILITY. */ - .retention_level = ARM_RETENTION_NVM, - .security = { - .acls = 0, /**< against internal software attacks using ACLs. */ - .rollback_protection = 0, /**< roll-back protection. */ - .tamper_proof = 0, /**< tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors). */ - .internal_flash = 1, /**< Internal flash. */ - - .software_attacks = 0, - .board_level_attacks = 0, - .chip_level_attacks = 0, - .side_channel_attacks = 0, - } -}; - -/** - * This is the command code written into the first FCCOB register, FCCOB0. - */ -enum FlashCommandOps { - RD1SEC = (uint8_t)0x01, /* read 1s section */ - PGM8 = (uint8_t)0x07, /* program phrase */ - ERSBLK = (uint8_t)0x08, /* erase block */ - ERSSCR = (uint8_t)0x09, /* erase flash sector */ - PGMSEC = (uint8_t)0x0B, /* program section */ - SETRAM = (uint8_t)0x81, /* Set FlexRAM. (unused for now) */ -}; - -/** - * Read out the CCIF (Command Complete Interrupt Flag) to ensure all previous - * operations have completed. - */ -static inline bool controllerCurrentlyBusy(void) -{ -#ifdef USING_KSDK2 - return ((FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK) == 0); -#else - return (BR_FTFE_FSTAT_CCIF(FTFE) == 0); -#endif -} - -static inline bool failedWithAccessError(void) -{ -#ifdef USING_KSDK2 - /* Get flash status register value */ - uint8_t registerValue = FTFx->FSTAT; - - /* checking access error */ - return registerValue & FTFx_FSTAT_ACCERR_MASK; -#else /* ifdef USING_KSDK2 */ - return BR_FTFE_FSTAT_ACCERR(FTFE); -#endif /* ifdef USING_KSDK2 */ -} - -static inline bool failedWithProtectionError() -{ -#ifdef USING_KSDK2 - /* Get flash status register value */ - uint8_t registerValue = FTFx->FSTAT; - - /* checking protection error */ - return registerValue & FTFx_FSTAT_FPVIOL_MASK; -#else /* ifdef USING_KSDK2 */ - return BR_FTFE_FSTAT_FPVIOL(FTFE); -#endif /* ifdef USING_KSDK2 */ -} - -static inline bool failedWithRunTimeError() -{ -#ifdef USING_KSDK2 - /* Get flash status register value */ - uint8_t registerValue = FTFx->FSTAT; - - /* checking MGSTAT0 non-correctable error */ - return registerValue & FTFx_FSTAT_MGSTAT0_MASK; -#else /* ifdef USING_KSDK2 */ - return BR_FTFE_FSTAT_MGSTAT0(FTFE); -#endif /* ifdef USING_KSDK2 */ -} - -static inline void clearAccessError(void) -{ -#ifdef USING_KSDK2 - FTFx->FSTAT |= FTFx_FSTAT_ACCERR_MASK; -#else - BW_FTFE_FSTAT_ACCERR(FTFE, 1); -#endif -} - -static inline void clearProtectionError(void) -{ -#ifdef USING_KSDK2 - FTFx->FSTAT |= FTFx_FSTAT_FPVIOL_MASK; -#else - BW_FTFE_FSTAT_FPVIOL(FTFE, 1); -#endif -} - -/** - * @brief Clear the error bits before launching a command. - * - * The ACCERR error bit indicates an illegal access has occurred to an FTFE - * resource caused by a violation of the command write sequence or issuing an - * illegal FTFE command. While ACCERR is set, the CCIF flag cannot be cleared to - * launch a command. The ACCERR bit is cleared by writing a 1 to it. - * - * The FPVIOL error bit indicates an attempt was made to program or erase an - * address in a protected area of program flash or data flash memory during a - * command write sequence or a write was attempted to a protected area of the - * FlexRAM while enabled for EEPROM. While FPVIOL is set, the CCIF flag cannot - * be cleared to launch a command. The FPVIOL bit is cleared by writing a 1 to - * it. - */ -static inline void clearErrorStatusBits() -{ - if (failedWithAccessError()) { - clearAccessError(); - } - if (failedWithProtectionError()) { - clearProtectionError(); - } -} - -/* The following functions are only needed if using interrupt-driven operation. */ -#if ASYNC_OPS -static inline void enableCommandCompletionInterrupt(void) -{ -#ifdef USING_KSDK2 - FTFx->FCNFG |= FTFE_FCNFG_CCIE_MASK; -#else - BW_FTFE_FCNFG_CCIE((uintptr_t)FTFE, 1); /* enable interrupt to detect CCIE being set. */ -#endif -} - -static inline void disbleCommandCompletionInterrupt(void) -{ -#ifdef USING_KSDK2 - FTFx->FCNFG &= ~FTFE_FCNFG_CCIE_MASK; -#else - BW_FTFE_FCNFG_CCIE((uintptr_t)FTFE, 0); /* disable command completion interrupt. */ -#endif -} - -static inline bool commandCompletionInterruptEnabled(void) -{ -#ifdef USING_KSDK2 - return ((FTFx->FCNFG & FTFE_FCNFG_CCIE_MASK) != 0); -#else - return (BR_FTFE_FCNFG_CCIE((uintptr_t)FTFE) != 0); -#endif -} - -/** - * Once all relevant command parameters have been loaded, the user launches the - * command by clearing the FSTAT[CCIF] bit by writing a '1' to it. The CCIF flag - * remains zero until the FTFE command completes. - */ -static inline void launchCommand(void) -{ -#ifdef USING_KSDK2 - FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; -#else - BW_FTFE_FSTAT_CCIF(FTFE, 1); -#endif -} - -#else /* #if !ASYNC_OPS */ - -#if EXISTS_POSSIBILITY_OF_CONCURRENT_READ -/* This function needs to execute from RAM to avoid read-while-write errors. */ -__RAMFUNC -#endif -static void launchCommandAndWaitForCompletion() -{ - // It contains the inlined equivalent of the following code snippet: - // launchCommand(); - // while (controllerCurrentlyBusy()) { - // /* Spin waiting for the command execution to complete. */ - // } - -#ifdef USING_KSDK2 - FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; /* launchcommand() */ - while ((FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK) == 0) { - /* Spin waiting for the command execution to complete. */ - } -#else - BW_FTFE_FSTAT_CCIF(FTFE, 1); /* launchCommand() */ - while (BR_FTFE_FSTAT_CCIF(FTFE) == 0) { - /* Spin waiting for the command execution to complete. */ - } -#endif -} -#endif /* #if !ASYNC_OPS */ - -#ifndef USING_KSDK2 -static inline void setupAddressInCCOB123(uint64_t addr) -{ - BW_FTFE_FCCOB1_CCOBn((uintptr_t)FTFE, (addr >> 16) & 0xFFUL); /* bits [23:16] of the address. */ - BW_FTFE_FCCOB2_CCOBn((uintptr_t)FTFE, (addr >> 8) & 0xFFUL); /* bits [15:8] of the address. */ - BW_FTFE_FCCOB3_CCOBn((uintptr_t)FTFE, (addr >> 0) & 0xFFUL); /* bits [7:0] of the address. */ -} -#endif /* ifndef USING_KSDK2 */ - -static inline void setupRead1sSection(uint64_t addr, size_t cnt) -{ -#ifdef USING_KSDK2 - kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(RD1SEC, addr); - kFCCOBx[1] = BYTES_JOIN_TO_WORD_2_1_1(cnt >> 4, 0 /* normal read level */, 0); -#else - BW_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE, RD1SEC); - setupAddressInCCOB123(addr); - BW_FTFE_FCCOB4_CCOBn((uintptr_t)FTFE, ((cnt >> 4) >> 8) & 0xFFUL); /* bits [15:8] of cnt in units of 128-bits. */ - BW_FTFE_FCCOB5_CCOBn((uintptr_t)FTFE, ((cnt >> 4) >> 0) & 0xFFUL); /* bits [7:0] of cnt in units of 128-bits. */ - BW_FTFE_FCCOB6_CCOBn((uintptr_t)FTFE, 0); /* use normal read level for 1s. */ -#endif -} - -static inline bool currentCommandByteIsRD1SEC(void) -{ -#ifdef USING_KSDK2 - return ((kFCCOBx[0] >> 24) == RD1SEC); -#else - return (BR_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE) == RD1SEC); -#endif -} - -static inline bool currentCommandSetupIsAnEraseCheck(const struct mtd_k64f_data *context) -{ - return ((context->currentCommand == ARM_STORAGE_OPERATION_ERASE) && currentCommandByteIsRD1SEC()); -} - -static inline void setupEraseSector(uint64_t addr) -{ -#ifdef USING_KSDK2 - kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(ERSSCR, addr); -#else - BW_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE, ERSSCR); - setupAddressInCCOB123(addr); -#endif -} - -static inline void setupEraseBlock(uint64_t addr) -{ -#ifdef USING_KSDK2 - kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(ERSBLK, addr); -#else - BW_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE, ERSBLK); - setupAddressInCCOB123(addr); -#endif -} - -static inline void setup8ByteWrite(uint64_t addr, const void *data) -{ - /* Program FCCOB to load the required command parameters. */ -#ifdef USING_KSDK2 - kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(PGM8, addr); - - /* Program 8 bytes of data into FCCOB(4..11)_CCOBn */ - kFCCOBx[1] = ((const uint32_t *)data)[0]; - kFCCOBx[2] = ((const uint32_t *)data)[1]; -#else /* ifdef USING_KSDK2 */ - BW_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE, PGM8); - setupAddressInCCOB123(addr); - - BW_FTFE_FCCOB4_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[3]); /* byte 3 of program value. */ - BW_FTFE_FCCOB5_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[2]); /* byte 2 of program value. */ - BW_FTFE_FCCOB6_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[1]); /* byte 1 of program value. */ - BW_FTFE_FCCOB7_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[0]); /* byte 0 of program value. */ - BW_FTFE_FCCOB8_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[7]); /* byte 7 of program value. */ - BW_FTFE_FCCOB9_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[6]); /* byte 6 of program value. */ - BW_FTFE_FCCOBA_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[5]); /* byte 5 of program value. */ - BW_FTFE_FCCOBB_CCOBn((uintptr_t)FTFE, ((const uint8_t *)data)[4]); /* byte 4 of program value. */ -#endif /* ifdef USING_KSDK2 */ -} - -static inline void setupProgramSection(uint64_t addr, const void *data, size_t cnt) -{ -#ifdef USING_KSDK2 - static const uintptr_t FlexRAMBase = FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS; - memcpy((void *)FlexRAMBase, (const uint8_t *)data, cnt); - - kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(PGMSEC, addr); - kFCCOBx[1] = BYTES_JOIN_TO_WORD_2_2(cnt >> 4, 0xFFFFU); -#else /* ifdef USING_KSDK2 */ - static const uintptr_t FlexRAMBase = 0x14000000; - memcpy((void *)FlexRAMBase, (const uint8_t *)data, cnt); - - BW_FTFE_FCCOB0_CCOBn((uintptr_t)FTFE, PGMSEC); - setupAddressInCCOB123(addr); - - BW_FTFE_FCCOB4_CCOBn((uintptr_t)FTFE, ((((uint32_t)(cnt >> 4)) & (0x0000FF00)) >> 8)); /* number of 128-bits to program [15:8] */ - BW_FTFE_FCCOB5_CCOBn((uintptr_t)FTFE, (((uint32_t)(cnt >> 4)) & (0x000000FF))); /* number of 128-bits to program [7:0] */ -#endif /* ifdef USING_KSDK2 */ -} - -/** - * Compute the size of the largest 'program-section' operation which is - * possible for the range [addr, addr+size) starting from addr. It is assumed - * that 'addr' is aligned to a double-phrase boundary (see \ref - * SIZEOF_DOUBLE_PHRASE)--if not, then only a single phrase (8-bytes) write is possible. - */ -static inline size_t sizeofLargestProgramSection(uint64_t addr, size_t size) -{ - /* ensure 'size' is aligned to a double-phrase boundary */ - if ((size % SIZEOF_DOUBLE_PHRASE) == PROGRAM_PHRASE_SIZEOF_INLINE_DATA) { - size -= PROGRAM_PHRASE_SIZEOF_INLINE_DATA; - } - - /* ensure 'size' isn't larger than OPTIMAL_PROGRAM_UNIT */ - if (size > OPTIMAL_PROGRAM_UNIT) { - size = OPTIMAL_PROGRAM_UNIT; - } - - /* ensure that the operation doesn't cross an erase boundary */ - size_t amountLeftInEraseUnit = ERASE_UNIT - (size_t)(addr % ERASE_UNIT); - if (size > amountLeftInEraseUnit) { - size = amountLeftInEraseUnit; - } - - return size; -} - -/** - * Advance the state machine for program-data. This function is called only if - * amountLeftToOperate is non-zero. - */ -static inline void setupNextProgramData(struct mtd_k64f_data *context) -{ - if ((context->amountLeftToOperate == PROGRAM_PHRASE_SIZEOF_INLINE_DATA) || - ((context->currentOperatingStorageAddress % SIZEOF_DOUBLE_PHRASE) == PROGRAM_PHRASE_SIZEOF_INLINE_DATA)) { - setup8ByteWrite(context->currentOperatingStorageAddress, context->currentOperatingData); - tr_debug("setupNextProgramData: W8, [%lu]", (uint32_t)context->currentOperatingStorageAddress); - - context->amountLeftToOperate -= PROGRAM_PHRASE_SIZEOF_INLINE_DATA; - context->currentOperatingStorageAddress += PROGRAM_PHRASE_SIZEOF_INLINE_DATA; - context->currentOperatingData += PROGRAM_PHRASE_SIZEOF_INLINE_DATA; - } else { - size_t amount = sizeofLargestProgramSection(context->currentOperatingStorageAddress, context->amountLeftToOperate); - setupProgramSection(context->currentOperatingStorageAddress, context->currentOperatingData, amount); - tr_debug("setupNextProgramData: W%u, [%lu]", amount, (uint32_t)context->currentOperatingStorageAddress); - - context->amountLeftToOperate -= amount; - context->currentOperatingStorageAddress += amount; - context->currentOperatingData += amount; - } -} - -/* Setup a command to determine if erase is needed for the range - * [context->currentOperatingStorageAddress, context->currentOperatingStorageAddress + ERASE_UNIT). - * If any byte within the range isn't 0xFF, this command results in a run-time - * error. - * - * Upon launch, if any byte within the given range isn't 0xFF then this command - * will terminate in a run-time error. - */ -static inline void setupNextEraseCheck(const struct mtd_k64f_data *context) -{ - setupRead1sSection(context->currentOperatingStorageAddress, ERASE_UNIT); /* setup check for erased */ -} - -static inline void progressEraseContextByEraseUnit(struct mtd_k64f_data *context) -{ - context->amountLeftToOperate -= ERASE_UNIT; - context->currentOperatingStorageAddress += ERASE_UNIT; -} - -/** - * Advance the state machine for erase. This function is called only if - * amountLeftToOperate is non-zero. - */ -static inline void setupNextErase(struct mtd_k64f_data *context) -{ - setupEraseSector(context->currentOperatingStorageAddress); /* Program FCCOB to load the required command parameters. */ - progressEraseContextByEraseUnit(context); -} - -static int32_t executeCommand(struct mtd_k64f_data *context) -{ - tr_debug("executeCommand: top"); - -#if ASYNC_OPS - /* Asynchronous operation */ - (void)context; /* avoid compiler warning about un-used variables */ - launchCommand(); - - /* At this point, The FTFE reads the command code and performs a series of - * parameter checks and protection checks, if applicable, which are unique - * to each command. */ - /* Spin waiting for the command execution to begin. */ - while (!controllerCurrentlyBusy() && !failedWithAccessError() && !failedWithProtectionError()); - if (failedWithAccessError() || failedWithProtectionError()) { - clearErrorStatusBits(); - return ARM_DRIVER_ERROR_PARAMETER; - } - - enableCommandCompletionInterrupt(); - - tr_debug("executeCommand: async. return"); - return ARM_DRIVER_OK; /* signal asynchronous completion. An interrupt will signal completion later. */ -#else /* #if ASYNC_OPS */ - /* Synchronous operation. This is the common case. */ - - while (1) { - tr_debug("executeCommand: synchronous iteration"); - - #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ - __disable_irq(); - #endif - launchCommandAndWaitForCompletion(); - #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ - __enable_irq(); - #endif - - /* Execution may result in failure. Check for errors */ - if (failedWithAccessError() || failedWithProtectionError()) { - clearErrorStatusBits(); - return ARM_DRIVER_ERROR_PARAMETER; - } - if (failedWithRunTimeError()) { - /* filter away run-time errors which may legitimately arise from an erase-check operation. */ - if (!currentCommandSetupIsAnEraseCheck(context)) { - return ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE; - } - } - - /* signal synchronous completion. */ - switch (context->currentCommand) { - case ARM_STORAGE_OPERATION_PROGRAM_DATA: - if (context->amountLeftToOperate == 0) { - return context->sizeofCurrentOperation; - } - - /* start the successive program operation */ - setupNextProgramData(context); - /* continue on to the next iteration of the parent loop */ - break; - - case ARM_STORAGE_OPERATION_ERASE: - if (currentCommandSetupIsAnEraseCheck(context)) { - if (failedWithRunTimeError()) { - /* a run-time failure from an erase-check indicates at an erase operation is necessary */ - setupNextErase(context); - /* continue on to the next iteration of the parent loop */ - break; - } else { - /* erase can be skipped since this sector is already erased. */ - tr_debug("fast forward erase"); - progressEraseContextByEraseUnit(context); - } - } - if (context->amountLeftToOperate == 0) { - return context->sizeofCurrentOperation; - } - - setupNextEraseCheck(context); /* start the erase check on the successive erase sector */ - /* continue on to the next iteration of the parent loop */ - break; - - default: - return 1; - } - } -#endif /* #ifdef ASYNC_OPS */ -} - -#if ASYNC_OPS -static inline void launchCommandFromIRQ(const struct mtd_k64f_data *context) -{ - launchCommand(); - - while (!controllerCurrentlyBusy() && !failedWithAccessError() && !failedWithProtectionError()); - if (failedWithAccessError() || failedWithProtectionError()) { - clearErrorStatusBits(); - if (context->commandCompletionCallback) { - tr_debug("irq: invoking callback with error"); - context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, context->currentCommand); - } - return; - } - - enableCommandCompletionInterrupt(); -} - -static void ftfe_ccie_irq_handler(void) -{ - disbleCommandCompletionInterrupt(); - - struct mtd_k64f_data *context = &mtd_k64f_data; - /* check for errors */ - if (failedWithAccessError() || failedWithProtectionError()) { - clearErrorStatusBits(); - if (context->commandCompletionCallback) { - context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, context->currentCommand); - } - return; - } - if (failedWithRunTimeError()) { - /* filter away run-time errors which may legitimately arise from an erase-check operation. */ - if (!currentCommandSetupIsAnEraseCheck(context)) { - if (context->commandCompletionCallback) { - context->commandCompletionCallback(ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE, context->currentCommand); - } - return; - } - } - - switch (context->currentCommand) { - case ARM_STORAGE_OPERATION_PROGRAM_DATA: - if (context->amountLeftToOperate == 0) { - if (context->commandCompletionCallback) { - tr_debug("irq: [PROGRAM] invoking callback"); - context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_PROGRAM_DATA); - } - return; - } - - /* start the successive program operation */ - setupNextProgramData(context); - launchCommandFromIRQ(context); - break; - - case ARM_STORAGE_OPERATION_ERASE: - if (currentCommandSetupIsAnEraseCheck(context)) { - if (failedWithRunTimeError()) { - /* a run-time failure from an erase-check indicates at an erase operation is necessary */ - setupNextErase(context); - launchCommandFromIRQ(context); - break; - } else { - /* erase can be skipped since this sector is already erased. */ - tr_debug("fast forward erase"); - progressEraseContextByEraseUnit(context); - } - } - if (context->amountLeftToOperate == 0) { - if (context->commandCompletionCallback) { - tr_debug("irq: [ERASE] invoking callback"); - context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_ERASE); - } - return; - } - - setupNextEraseCheck(context); /* start the erase check on the successive erase sector */ - launchCommandFromIRQ(context); - break; - - default: - if (context->commandCompletionCallback) { - tr_debug("irq: [default] invoking callback"); - context->commandCompletionCallback(ARM_DRIVER_OK, context->currentCommand); - } - break; - } -} -#endif /* #if ASYNC_OPS */ - -/** - * This is a helper function which can be used to do arbitrary sanity checking - * on a range. - * - * It applies the 'check' function to every block in a given range. If any of - * the check() calls return failure (i.e. something other ARM_DRIVER_OK), - * validation terminates. Otherwise an ARM_DRIVER_OK is returned. - */ -static int32_t checkForEachBlockInRange(uint64_t startAddr, uint32_t size, int32_t (*check)(const ARM_STORAGE_BLOCK *block)) -{ - uint64_t addrBeingValidated = startAddr; - ARM_STORAGE_BLOCK block; - if (getBlock(addrBeingValidated, &block) != ARM_DRIVER_OK) { - return ARM_DRIVER_ERROR_PARAMETER; - } - while (addrBeingValidated < (startAddr + size)) { - int32_t rc; - if ((rc = check(&block)) != ARM_DRIVER_OK) { - return rc; - } - - /* move on to the following block */ - if (nextBlock(&block, &block) != ARM_DRIVER_OK) { - break; - } - addrBeingValidated = block.addr; - } - - return ARM_DRIVER_OK; -} - -static int32_t blockIsProgrammable(const ARM_STORAGE_BLOCK *blockP) -{ - if (!blockP->attributes.programmable) { - return ARM_STORAGE_ERROR_NOT_PROGRAMMABLE; - } - - return ARM_DRIVER_OK; -} - -static int32_t blockIsErasable(const ARM_STORAGE_BLOCK *blockP) -{ - if (!blockP->attributes.erasable) { - return ARM_STORAGE_ERROR_NOT_ERASABLE; - } - - return ARM_DRIVER_OK; -} - -static ARM_DRIVER_VERSION getVersion(void) -{ - return version; -} - -static ARM_STORAGE_CAPABILITIES getCapabilities(void) -{ - return caps; -} - -static int32_t initialize(ARM_Storage_Callback_t callback) -{ - tr_debug("called initialize(%p)", callback); - - struct mtd_k64f_data *context = &mtd_k64f_data; - memset(context, 0, sizeof(mtd_k64f_data)); - context->currentCommand = ARM_STORAGE_OPERATION_INITIALIZE; - - if (context->initialized) { - context->commandCompletionCallback = callback; - - return 1; /* synchronous completion. */ - } - - if (controllerCurrentlyBusy()) { - /* The user cannot initiate any further FTFE commands until notified that the - * current command has completed.*/ - return (int32_t)ARM_DRIVER_ERROR_BUSY; - } - - clearErrorStatusBits(); - - context->commandCompletionCallback = callback; - - /* Enable the command-completion interrupt. */ -#if ASYNC_OPS - NVIC_SetVector(FTFE_IRQn, (uint32_t)ftfe_ccie_irq_handler); - NVIC_ClearPendingIRQ(FTFE_IRQn); - NVIC_EnableIRQ(FTFE_IRQn); -#endif - - context->initialized = true; - - return 1; /* synchronous completion. */ -} - -static int32_t uninitialize(void) -{ - tr_debug("called uninitialize"); - - struct mtd_k64f_data *context = &mtd_k64f_data; - context->currentCommand = ARM_STORAGE_OPERATION_UNINITIALIZE; - - if (!context->initialized) { - return ARM_DRIVER_ERROR; - } - - /* Disable the command-completion interrupt. */ -#if ASYNC_OPS - if (commandCompletionInterruptEnabled()) { - disbleCommandCompletionInterrupt(); - NVIC_DisableIRQ(FTFE_IRQn); - NVIC_ClearPendingIRQ(FTFE_IRQn); - } -#endif - - context->commandCompletionCallback = NULL; - context->initialized = false; - return 1; /* synchronous completion. */ -} - -static int32_t powerControl(ARM_POWER_STATE state) -{ - tr_debug("called powerControl(%u)", state); - - struct mtd_k64f_data *context = &mtd_k64f_data; - context->currentCommand = ARM_STORAGE_OPERATION_POWER_CONTROL; - - context->powerState = state; - return 1; /* signal synchronous completion. */ -} - -static int32_t readData(uint64_t addr, void *data, uint32_t size) -{ - tr_debug("called ReadData(%lu, %lu)", (uint32_t)addr, size); - - struct mtd_k64f_data *context = &mtd_k64f_data; - context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA; - - if (!context->initialized) { - return ARM_DRIVER_ERROR; /* illegal */ - } - - /* Argument validation. */ - if ((data == NULL) || (size == 0)) { - return ARM_DRIVER_ERROR_PARAMETER; /* illegal */ - } - if ((getBlock(addr, NULL) != ARM_DRIVER_OK) || (getBlock(addr + size - 1, NULL) != ARM_DRIVER_OK)) { - return ARM_DRIVER_ERROR_PARAMETER; /* illegal address range */ - } - - context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA; - memcpy(data, (const void *)(uintptr_t)addr, size); - return size; /* signal synchronous completion. */ -} - -static int32_t programData(uint64_t addr, const void *data, uint32_t size) -{ - tr_debug("called ProgramData(%lu, %lu)", (uint32_t)addr, size); - - struct mtd_k64f_data *context = &mtd_k64f_data; - if (!context->initialized) { - return (int32_t)ARM_DRIVER_ERROR; /* illegal */ - } - - /* argument validation */ - if ((data == NULL) || (size == 0)) { - return ARM_DRIVER_ERROR_PARAMETER; /* illegal */ - } - /* range check */ - if ((getBlock(addr, NULL) != ARM_DRIVER_OK) || (getBlock(addr + size - 1, NULL) != ARM_DRIVER_OK)) { - return ARM_DRIVER_ERROR_PARAMETER; /* illegal address range */ - } - /* alignment */ - if (((addr % PROGRAM_UNIT) != 0) || ((size % PROGRAM_UNIT) != 0)) { - return ARM_DRIVER_ERROR_PARAMETER; - } - /* programmability */ - if (checkForEachBlockInRange(addr, size, blockIsProgrammable) != ARM_DRIVER_OK) { - return ARM_STORAGE_ERROR_NOT_PROGRAMMABLE; - } - - if (controllerCurrentlyBusy()) { - /* The user cannot initiate any further FTFE commands until notified that the - * current command has completed.*/ - return ARM_DRIVER_ERROR_BUSY; - } - - context->currentCommand = ARM_STORAGE_OPERATION_PROGRAM_DATA; - context->sizeofCurrentOperation = size; - context->amountLeftToOperate = size; - context->currentOperatingData = data; - context->currentOperatingStorageAddress = addr; - - clearErrorStatusBits(); - setupNextProgramData(context); - return executeCommand(context); -} - -static int32_t erase(uint64_t addr, uint32_t size) -{ - tr_debug("called erase(%lu, %lu)", (uint32_t)addr, size); - - struct mtd_k64f_data *context = &mtd_k64f_data; - - if (!context->initialized) { - return (int32_t)ARM_DRIVER_ERROR; /* illegal */ - } - /* argument validation */ - if (size == 0) { - return ARM_DRIVER_ERROR_PARAMETER; - } - /* range check */ - if ((getBlock(addr, NULL) != ARM_DRIVER_OK) || (getBlock(addr + size - 1, NULL) != ARM_DRIVER_OK)) { - return ARM_DRIVER_ERROR_PARAMETER; /* illegal address range */ - } - /* alignment */ - if (((addr % ERASE_UNIT) != 0) || ((size % ERASE_UNIT) != 0)) { - return ARM_DRIVER_ERROR_PARAMETER; - } - /* erasability */ - if (checkForEachBlockInRange(addr, size, blockIsErasable) != ARM_DRIVER_OK) { - return ARM_STORAGE_ERROR_NOT_ERASABLE; - } - - if (controllerCurrentlyBusy()) { - /* The user cannot initiate any further FTFE commands until notified that the - * current command has completed.*/ - return (int32_t)ARM_DRIVER_ERROR_BUSY; - } - - context->currentCommand = ARM_STORAGE_OPERATION_ERASE; - context->currentOperatingStorageAddress = addr; - context->sizeofCurrentOperation = size; - context->amountLeftToOperate = size; - - clearErrorStatusBits(); - setupNextEraseCheck(context); - return executeCommand(context); -} - -static int32_t eraseAll(void) -{ - tr_debug("called eraseAll"); - - struct mtd_k64f_data *context = &mtd_k64f_data; - - if (!context->initialized) { - return (int32_t)ARM_DRIVER_ERROR; /* illegal */ - } - - /* unless we are managing all of block 1, we shouldn't allow chip-erase. */ - if ((caps.erase_all != 1) || - ((sizeof(blockTable) / sizeof(ARM_STORAGE_BLOCK)) != 1) || /* there are more than one flash blocks */ - (blockTable[0].addr != BLOCK1_START_ADDR) || - (blockTable[0].size != BLOCK1_SIZE)) { - return ARM_DRIVER_ERROR_UNSUPPORTED; - } - - if (controllerCurrentlyBusy()) { - /* The user cannot initiate any further FTFE commands until notified that the - * current command has completed.*/ - return (int32_t)ARM_DRIVER_ERROR_BUSY; - } - - context->currentCommand = ARM_STORAGE_OPERATION_ERASE_ALL; - - clearErrorStatusBits(); - - /* Program FCCOB to load the required command parameters. */ - setupEraseBlock(BLOCK1_START_ADDR); - return executeCommand(context); -} - -static ARM_STORAGE_STATUS getStatus(void) -{ - struct mtd_k64f_data *context = &mtd_k64f_data; - - ARM_STORAGE_STATUS status = { - .busy = 0, - .error = 0, - }; - - if (!context->initialized) { - status.error = 1; - return status; - } - - if (controllerCurrentlyBusy()) { - status.busy = 1; - } else if (failedWithAccessError() || failedWithProtectionError() || failedWithRunTimeError()) { - status.error = 1; - } - return status; -} - -static int32_t getInfo(ARM_STORAGE_INFO *infoP) -{ - memcpy(infoP, &info, sizeof(ARM_STORAGE_INFO)); - - return ARM_DRIVER_OK; -} - -static uint32_t resolveAddress(uint64_t addr) -{ - return (uint32_t)addr; -} - -int32_t nextBlock(const ARM_STORAGE_BLOCK *prevP, ARM_STORAGE_BLOCK *nextP) -{ - if (prevP == NULL) { - /* fetching the first block (instead of next) */ - if (nextP) { - memcpy(nextP, &blockTable[0], sizeof(ARM_STORAGE_BLOCK)); - } - return ARM_DRIVER_OK; - } - - static const size_t NUM_SEGMENTS = sizeof(blockTable) / sizeof(ARM_STORAGE_BLOCK); - for (size_t index = 0; (NUM_SEGMENTS > 1) && (index < (NUM_SEGMENTS - 1)); index++) { - if ((blockTable[index].addr == prevP->addr) && (blockTable[index].size == prevP->size)) { - if (nextP) { - memcpy(nextP, &blockTable[index + 1], sizeof(ARM_STORAGE_BLOCK)); - } - return ARM_DRIVER_OK; - } - } - - if (nextP) { - nextP->addr = ARM_STORAGE_INVALID_OFFSET; - nextP->size = 0; - } - return ARM_DRIVER_ERROR; -} - -int32_t getBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP) -{ - static const size_t NUM_SEGMENTS = sizeof(blockTable) / sizeof(ARM_STORAGE_BLOCK); - - const ARM_STORAGE_BLOCK *iter = &blockTable[0]; - for (size_t index = 0; index < NUM_SEGMENTS; ++index, ++iter) { - if ((addr >= iter->addr) && (addr < (iter->addr + iter->size))) { - if (blockP) { - memcpy(blockP, iter, sizeof(ARM_STORAGE_BLOCK)); - } - return ARM_DRIVER_OK; - } - } - - if (blockP) { - blockP->addr = ARM_STORAGE_INVALID_OFFSET; - blockP->size = 0; - } - return ARM_DRIVER_ERROR; -} - -ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F = { - .GetVersion = getVersion, - .GetCapabilities = getCapabilities, - .Initialize = initialize, - .Uninitialize = uninitialize, - .PowerControl = powerControl, - .ReadData = readData, - .ProgramData = programData, - .Erase = erase, - .EraseAll = eraseAll, - .GetStatus = getStatus, - .GetInfo = getInfo, - .ResolveAddress = resolveAddress, - .GetNextBlock = nextBlock, - .GetBlock = getBlock -};