/* * 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 }