551 lines
15 KiB
C
551 lines
15 KiB
C
/*
|
|
* Copyright (c) 2016, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2022 NXP
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "fsl_flexspi.h"
|
|
#include "app.h"
|
|
#if (defined CACHE_MAINTAIN) && (CACHE_MAINTAIN == 1)
|
|
#include "fsl_cache.h"
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
*****************************************************************************/
|
|
extern flexspi_device_config_t deviceconfig;
|
|
extern const uint32_t customLUT[CUSTOM_LUT_LENGTH];
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
#if (defined CACHE_MAINTAIN) && (CACHE_MAINTAIN == 1)
|
|
void flexspi_nor_disable_cache(flexspi_cache_status_t *cacheStatus)
|
|
{
|
|
#if (defined __CORTEX_M) && (__CORTEX_M == 7U)
|
|
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
/* Disable D cache. */
|
|
if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR))
|
|
{
|
|
SCB_DisableDCache();
|
|
cacheStatus->DCacheEnableFlag = true;
|
|
}
|
|
#endif /* __DCACHE_PRESENT */
|
|
|
|
#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
/* Disable I cache. */
|
|
if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR))
|
|
{
|
|
SCB_DisableICache();
|
|
cacheStatus->ICacheEnableFlag = true;
|
|
}
|
|
#endif /* __ICACHE_PRESENT */
|
|
|
|
#elif (defined FSL_FEATURE_SOC_LMEM_COUNT) && (FSL_FEATURE_SOC_LMEM_COUNT != 0U)
|
|
/* Disable code bus cache and system bus cache */
|
|
if (LMEM_PCCCR_ENCACHE_MASK == (LMEM_PCCCR_ENCACHE_MASK & LMEM->PCCCR))
|
|
{
|
|
L1CACHE_DisableCodeCache();
|
|
cacheStatus->codeCacheEnableFlag = true;
|
|
}
|
|
if (LMEM_PSCCR_ENCACHE_MASK == (LMEM_PSCCR_ENCACHE_MASK & LMEM->PSCCR))
|
|
{
|
|
L1CACHE_DisableSystemCache();
|
|
cacheStatus->systemCacheEnableFlag = true;
|
|
}
|
|
|
|
#elif (defined FSL_FEATURE_SOC_CACHE64_CTRL_COUNT) && (FSL_FEATURE_SOC_CACHE64_CTRL_COUNT != 0U)
|
|
/* Disable cache */
|
|
CACHE64_DisableCache(EXAMPLE_CACHE);
|
|
cacheStatus->CacheEnableFlag = true;
|
|
#endif
|
|
}
|
|
|
|
void flexspi_nor_enable_cache(flexspi_cache_status_t cacheStatus)
|
|
{
|
|
#if (defined __CORTEX_M) && (__CORTEX_M == 7U)
|
|
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
if (cacheStatus.DCacheEnableFlag)
|
|
{
|
|
/* Enable D cache. */
|
|
SCB_EnableDCache();
|
|
}
|
|
#endif /* __DCACHE_PRESENT */
|
|
|
|
#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
if (cacheStatus.ICacheEnableFlag)
|
|
{
|
|
/* Enable I cache. */
|
|
SCB_EnableICache();
|
|
}
|
|
#endif /* __ICACHE_PRESENT */
|
|
|
|
#elif (defined FSL_FEATURE_SOC_LMEM_COUNT) && (FSL_FEATURE_SOC_LMEM_COUNT != 0U)
|
|
if (cacheStatus.codeCacheEnableFlag)
|
|
{
|
|
/* Enable code cache. */
|
|
L1CACHE_EnableCodeCache();
|
|
}
|
|
|
|
if (cacheStatus.systemCacheEnableFlag)
|
|
{
|
|
/* Enable system cache. */
|
|
L1CACHE_EnableSystemCache();
|
|
}
|
|
|
|
#elif (defined FSL_FEATURE_SOC_CACHE64_CTRL_COUNT) && (FSL_FEATURE_SOC_CACHE64_CTRL_COUNT != 0U)
|
|
if (cacheStatus.CacheEnableFlag)
|
|
{
|
|
/* Enable cache. */
|
|
CACHE64_EnableCache(EXAMPLE_CACHE);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr)
|
|
{
|
|
flexspi_transfer_t flashXfer;
|
|
status_t status;
|
|
|
|
/* Write enable */
|
|
flashXfer.deviceAddress = baseAddr;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Command;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;
|
|
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base)
|
|
{
|
|
/* Wait status ready. */
|
|
bool isBusy;
|
|
uint32_t readValue;
|
|
status_t status;
|
|
flexspi_transfer_t flashXfer;
|
|
|
|
flashXfer.deviceAddress = 0;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Read;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG;
|
|
flashXfer.data = &readValue;
|
|
flashXfer.dataSize = 1;
|
|
|
|
do
|
|
{
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
if (FLASH_BUSY_STATUS_POL)
|
|
{
|
|
if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
|
|
{
|
|
isBusy = true;
|
|
}
|
|
else
|
|
{
|
|
isBusy = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
|
|
{
|
|
isBusy = false;
|
|
}
|
|
else
|
|
{
|
|
isBusy = true;
|
|
}
|
|
}
|
|
|
|
} while (isBusy);
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base)
|
|
{
|
|
flexspi_transfer_t flashXfer;
|
|
status_t status;
|
|
uint32_t writeValue = FLASH_QUAD_ENABLE;
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Write enable */
|
|
status = flexspi_nor_write_enable(base, 0);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Enable quad mode. */
|
|
flashXfer.deviceAddress = 0;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Write;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG;
|
|
flashXfer.data = &writeValue;
|
|
flashXfer.dataSize = 1;
|
|
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
/* Do software reset. */
|
|
FLEXSPI_SoftwareReset(base);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
#if defined(NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER) && NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER
|
|
status_t flexspi_nor_set_read_parameter(
|
|
FLEXSPI_Type *base, uint8_t burstLength, bool enableWrap, uint8_t dummyCycle, bool resetPinSelected)
|
|
{
|
|
flexspi_transfer_t flashXfer;
|
|
status_t status;
|
|
uint32_t readParameterRegVal = ((uint32_t)resetPinSelected << RESET_PIN_SELECTED_REG_SHIFT) |
|
|
((uint32_t)dummyCycle << DUMMY_CYCLES_REG_SHIFT) |
|
|
((uint32_t)enableWrap << WRAP_ENABLE_REG_SHIFT) |
|
|
((uint32_t)burstLength << BURST_LEGNTH_REG_SHIFT);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Write enable */
|
|
status = flexspi_nor_write_enable(base, 0);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
flashXfer.deviceAddress = 0;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Write;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER;
|
|
flashXfer.data = &readParameterRegVal;
|
|
flashXfer.dataSize = 1;
|
|
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
/* Do software reset. */
|
|
FLEXSPI_SoftwareReset(base);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address)
|
|
{
|
|
status_t status;
|
|
flexspi_transfer_t flashXfer;
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Write enable */
|
|
flashXfer.deviceAddress = address;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Command;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;
|
|
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
flashXfer.deviceAddress = address;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Command;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
/* Do software reset. */
|
|
FLEXSPI_SoftwareReset(base);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_flash_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t length)
|
|
{
|
|
status_t status;
|
|
flexspi_transfer_t flashXfer;
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Write enable */
|
|
status = flexspi_nor_write_enable(base, dstAddr);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Prepare page program command */
|
|
flashXfer.deviceAddress = dstAddr;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Write;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
|
|
flashXfer.data = (uint32_t *)src;
|
|
flashXfer.dataSize = length;
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
/* Do software reset or clear AHB buffer directly. */
|
|
#if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \
|
|
defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)
|
|
base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;
|
|
base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK);
|
|
#else
|
|
FLEXSPI_SoftwareReset(base);
|
|
#endif
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src)
|
|
{
|
|
status_t status;
|
|
flexspi_transfer_t flashXfer;
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* To make sure external flash be in idle status, added wait for busy before program data for
|
|
an external flash without RWW(read while write) attribute.*/
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
if (kStatus_Success != status)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Write enable. */
|
|
status = flexspi_nor_write_enable(base, dstAddr);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Prepare page program command */
|
|
flashXfer.deviceAddress = dstAddr;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Write;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
|
|
flashXfer.data = (uint32_t *)src;
|
|
flashXfer.dataSize = FLASH_PAGE_SIZE;
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
/* Do software reset or clear AHB buffer directly. */
|
|
#if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \
|
|
defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)
|
|
base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;
|
|
base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK);
|
|
#else
|
|
FLEXSPI_SoftwareReset(base);
|
|
#endif
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId)
|
|
{
|
|
uint32_t temp;
|
|
flexspi_transfer_t flashXfer;
|
|
flashXfer.deviceAddress = 0;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Read;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READID;
|
|
flashXfer.data = &temp;
|
|
flashXfer.dataSize = 1;
|
|
|
|
status_t status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
*vendorId = temp;
|
|
|
|
/* Do software reset or clear AHB buffer directly. */
|
|
#if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \
|
|
defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)
|
|
base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;
|
|
base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK);
|
|
#else
|
|
FLEXSPI_SoftwareReset(base);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t flexspi_nor_erase_chip(FLEXSPI_Type *base)
|
|
{
|
|
status_t status;
|
|
flexspi_transfer_t flashXfer;
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Write enable */
|
|
status = flexspi_nor_write_enable(base, 0);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
flashXfer.deviceAddress = 0;
|
|
flashXfer.port = FLASH_PORT;
|
|
flashXfer.cmdType = kFLEXSPI_Command;
|
|
flashXfer.SeqNumber = 1;
|
|
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASECHIP;
|
|
|
|
status = FLEXSPI_TransferBlocking(base, &flashXfer);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = flexspi_nor_wait_bus_busy(base);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
void flexspi_nor_flash_init(FLEXSPI_Type *base)
|
|
{
|
|
flexspi_config_t config;
|
|
/* To store custom's LUT table in local. */
|
|
uint32_t tempLUT[CUSTOM_LUT_LENGTH] = {0x00U};
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_cache_status_t cacheStatus;
|
|
flexspi_nor_disable_cache(&cacheStatus);
|
|
#endif
|
|
|
|
/* Copy LUT information from flash region into RAM region, because LUT update maybe corrupt read sequence(LUT[0])
|
|
* and load wrong LUT table from FLASH region. */
|
|
memcpy(tempLUT, customLUT, sizeof(tempLUT));
|
|
|
|
flexspi_clock_init();
|
|
|
|
/*Get FLEXSPI default settings and configure the flexspi. */
|
|
FLEXSPI_GetDefaultConfig(&config);
|
|
|
|
/*Set AHB buffer size for reading data through AHB bus. */
|
|
config.ahbConfig.enableAHBPrefetch = true;
|
|
config.ahbConfig.enableAHBBufferable = true;
|
|
config.ahbConfig.enableReadAddressOpt = true;
|
|
config.ahbConfig.enableAHBCachable = true;
|
|
config.rxSampleClock = EXAMPLE_FLEXSPI_RX_SAMPLE_CLOCK;
|
|
FLEXSPI_Init(base, &config);
|
|
|
|
/* Configure flash settings according to serial flash feature. */
|
|
FLEXSPI_SetFlashConfig(base, &deviceconfig, FLASH_PORT);
|
|
|
|
/* Update LUT table. */
|
|
FLEXSPI_UpdateLUT(base, 0, tempLUT, CUSTOM_LUT_LENGTH);
|
|
|
|
/* Do software reset. */
|
|
FLEXSPI_SoftwareReset(base);
|
|
|
|
#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
|
|
flexspi_nor_enable_cache(cacheStatus);
|
|
#endif
|
|
}
|