Merge pull request #2219 from rgrover/improvements_to_mtd_k64_storage_driver

Improvements to k64 internal-flash storage driver
pull/2250/head
Sam Grove 2016-07-26 22:17:40 -05:00 committed by GitHub
commit 09f9c0e50d
2 changed files with 141 additions and 62 deletions

View File

@ -18,6 +18,8 @@
#ifndef __DRIVER_STORAGE_H
#define __DRIVER_STORAGE_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
@ -40,6 +42,7 @@ extern "C" {
#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.

View File

@ -15,14 +15,8 @@
* limitations under the License.
*/
/**
* This is a mock driver using the flash abstraction layer. It allows for writing tests.
*/
#if DEVICE_STORAGE
#include <string.h>
#include "Driver_Storage.h"
#include "cmsis_nvic.h"
#include "MK64F12.h"
@ -34,9 +28,11 @@
#ifndef USING_KSDK2
#include "device/MK64F12/MK64F12_ftfe.h"
#else
#include "drivers/fsl_flash.h"
#include "fsl_flash.h"
#endif
#include <string.h>
#ifdef USING_KSDK2
/*!
* @name Misc utility defines
@ -146,7 +142,6 @@ extern volatile uint32_t *const kFCCOBx;
#define SIZEOF_DOUBLE_PHRASE (16)
#endif /* #ifdef USING_KSDK2 */
/*
* forward declarations
*/
@ -174,16 +169,16 @@ struct mtd_k64f_data {
static const ARM_STORAGE_BLOCK blockTable[] = {
{
/**< This is the start address of the flash block. */
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_START_ADDR
.addr = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_START_ADDR,
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR
.addr = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_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 DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE
.size = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE,
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
.size = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE,
#else
.size = BLOCK1_SIZE,
#endif
@ -205,7 +200,7 @@ static const ARM_DRIVER_VERSION version = {
};
#if (!defined(DEVICE_STORAGE_CONFIG_HARDWARE_MTD_ASYNC_OPS) || DEVICE_STORAGE_CONFIG_HARDWARE_MTD_ASYNC_OPS)
#if (!defined(DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS)
#define ASYNC_OPS 1
#else
#define ASYNC_OPS 0
@ -224,8 +219,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
.asynchronous_ops = ASYNC_OPS,
/* Enable chip-erase functionality if we own all of block-1. */
#if ((!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_START_ADDR) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_START_ADDR == BLOCK1_START_ADDR)) && \
(!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE == BLOCK1_SIZE)))
#if ((!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR == BLOCK1_START_ADDR)) && \
(!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE == BLOCK1_SIZE)))
.erase_all = 1, /**< Supports EraseChip operation. */
#else
.erase_all = 0, /**< Supports EraseChip operation. */
@ -233,8 +228,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
};
static const ARM_STORAGE_INFO info = {
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE
.total_storage = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_SIZE, /**< Total available storage, in units of octets. */
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
.total_storage = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_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
@ -267,6 +262,7 @@ static const ARM_STORAGE_INFO info = {
* 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 */
@ -369,6 +365,8 @@ static inline void clearErrorStatusBits()
}
}
/* The following functions are only needed if using interrupt-driven operation. */
#if ASYNC_OPS
static inline void enableCommandCompletionInterrupt(void)
{
#ifdef USING_KSDK2
@ -410,6 +408,23 @@ static inline void launchCommand(void)
#endif
}
#else /* #if !ASYNC_OPS */
static void launchCommandAndWaitForCompletion()
{
// It contains the inlined equivalent of the following code snippet:
// launchCommand();
// while (controllerCurrentlyBusy()) {
// /* Spin waiting for the command execution to complete. */
// }
FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; /* launchcommand() */
while ((FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK) == 0) {
/* Spin waiting for the command execution to complete. */
}
}
#endif /* #if !ASYNC_OPS */
#ifndef USING_KSDK2
static inline void setupAddressInCCOB123(uint64_t addr)
{
@ -419,6 +434,34 @@ static inline void setupAddressInCCOB123(uint64_t addr)
}
#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
@ -533,6 +576,25 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
}
}
/* 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.
@ -540,24 +602,19 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
static inline void setupNextErase(struct mtd_k64f_data *context)
{
setupEraseSector(context->currentOperatingStorageAddress); /* Program FCCOB to load the required command parameters. */
context->amountLeftToOperate -= ERASE_UNIT;
context->currentOperatingStorageAddress += ERASE_UNIT;
progressEraseContextByEraseUnit(context);
}
static int32_t executeCommand(struct mtd_k64f_data *context)
{
#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. */
#if ASYNC_OPS
/* Asynchronous operation */
(void)context; /* avoid compiler warning about un-used variables */
/* Spin waiting for the command execution to begin. */
while (!controllerCurrentlyBusy() && !failedWithAccessError() && !failedWithProtectionError());
if (failedWithAccessError() || failedWithProtectionError()) {
@ -572,8 +629,7 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
/* Synchronous operation. */
while (1) {
/* Spin waiting for the command execution to complete. */
while (controllerCurrentlyBusy());
launchCommandAndWaitForCompletion();
/* Execution may result in failure. Check for errors */
if (failedWithAccessError() || failedWithProtectionError()) {
@ -581,7 +637,10 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
return ARM_DRIVER_ERROR_PARAMETER;
}
if (failedWithRunTimeError()) {
return ARM_DRIVER_ERROR; /* unspecified runtime error. */
/* 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. */
@ -593,17 +652,26 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
/* start the successive program operation */
setupNextProgramData(context);
launchCommand();
/* 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. */
progressEraseContextByEraseUnit(context);
}
}
if (context->amountLeftToOperate == 0) {
return context->sizeofCurrentOperation;
}
setupNextErase(context); /* start the successive erase operation */
launchCommand();
setupNextEraseCheck(context); /* start the erase check on the successive erase sector */
/* continue on to the next iteration of the parent loop */
break;
@ -615,6 +683,22 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
}
#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) {
context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, context->currentCommand);
}
return;
}
enableCommandCompletionInterrupt();
}
static void ftfe_ccie_irq_handler(void)
{
disbleCommandCompletionInterrupt();
@ -629,10 +713,13 @@ static void ftfe_ccie_irq_handler(void)
return;
}
if (failedWithRunTimeError()) {
if (context->commandCompletionCallback) {
context->commandCompletionCallback(ARM_DRIVER_ERROR, context->currentCommand);
/* 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;
}
return;
}
switch (context->currentCommand) {
@ -646,21 +733,21 @@ static void ftfe_ccie_irq_handler(void)
/* start the successive program operation */
setupNextProgramData(context);
launchCommand();
while (!controllerCurrentlyBusy() && !failedWithAccessError() && !failedWithProtectionError());
if (failedWithAccessError() || failedWithProtectionError()) {
clearErrorStatusBits();
if (context->commandCompletionCallback) {
context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, ARM_STORAGE_OPERATION_PROGRAM_DATA);
}
return;
}
enableCommandCompletionInterrupt();
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. */
progressEraseContextByEraseUnit(context);
}
}
if (context->amountLeftToOperate == 0) {
if (context->commandCompletionCallback) {
context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_ERASE);
@ -668,19 +755,8 @@ static void ftfe_ccie_irq_handler(void)
return;
}
setupNextErase(context);
launchCommand();
while (!controllerCurrentlyBusy() && !failedWithAccessError() && !failedWithProtectionError());
if (failedWithAccessError() || failedWithProtectionError()) {
clearErrorStatusBits();
if (context->commandCompletionCallback) {
context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, ARM_STORAGE_OPERATION_ERASE);
}
return;
}
enableCommandCompletionInterrupt();
setupNextEraseCheck(context); /* start the erase check on the successive erase sector */
launchCommandFromIRQ(context);
break;
default:
@ -831,7 +907,7 @@ static int32_t readData(uint64_t addr, void *data, uint32_t size)
return ARM_DRIVER_ERROR_PARAMETER; /* illegal address range */
}
context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA;
context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA;
memcpy(data, (const void *)(uintptr_t)addr, size);
return size; /* signal synchronous completion. */
}
@ -913,7 +989,7 @@ static int32_t erase(uint64_t addr, uint32_t size)
context->amountLeftToOperate = size;
clearErrorStatusBits();
setupNextErase(context);
setupNextEraseCheck(context);
return executeCommand(context);
}