/* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2019 NXP * All rights reserved. * * * SPDX-License-Identifier: BSD-3-Clause */ #include "sdk/drivers/flexspi/fsl_flexspi.h" #include "internal_flash.h" #include "boards/flash_config.h" #include "supervisor/internal_flash.h" #include "supervisor/linker.h" STATIC uint8_t _busy_bit_shift; STATIC bool _busy_bit_polarity; STATIC bool _inited = false; void flexspi_nor_init(void) { // Copy busy bit info into RAM so we can use if when flash isn't available. _busy_bit_shift = qspiflash_config.memConfig.busyOffset; _busy_bit_polarity = qspiflash_config.memConfig.busyBitPolarity; _inited = true; } STATIC status_t PLACE_IN_ITCM(flexspi_nor_write_enable)(FLEXSPI_Type * base, uint32_t baseAddr) { flexspi_transfer_t flashXfer; status_t status; /* Write enable */ flashXfer.deviceAddress = baseAddr; flashXfer.port = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Command; flashXfer.SeqNumber = 1; flashXfer.seqIndex = ROM_INDEX_WRITEENABLE; status = FLEXSPI_TransferBlocking(base, &flashXfer); return status; } STATIC status_t PLACE_IN_ITCM(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 = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Read; flashXfer.SeqNumber = 1; flashXfer.seqIndex = ROM_INDEX_READSTATUSREG; flashXfer.data = &readValue; flashXfer.dataSize = 1; do { status = FLEXSPI_TransferBlocking(base, &flashXfer); if (status != kStatus_Success) { return status; } bool busyBit = (readValue >> _busy_bit_shift) & 0x1; isBusy = busyBit != _busy_bit_polarity; } while (isBusy); return status; } status_t PLACE_IN_ITCM(flexspi_nor_flash_erase_sector)(FLEXSPI_Type * base, uint32_t address) { status_t status; flexspi_transfer_t flashXfer; /* Write enable */ flashXfer.deviceAddress = address; flashXfer.port = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Command; flashXfer.SeqNumber = 1; flashXfer.seqIndex = ROM_INDEX_WRITEENABLE; status = FLEXSPI_TransferBlocking(base, &flashXfer); if (status != kStatus_Success) { return status; } flashXfer.deviceAddress = address; flashXfer.port = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Command; flashXfer.SeqNumber = 1; flashXfer.seqIndex = ROM_INDEX_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); return status; } status_t PLACE_IN_ITCM(flexspi_nor_flash_page_program)(FLEXSPI_Type * base, uint32_t dstAddr, const uint32_t *src) { status_t status; flexspi_transfer_t flashXfer; /* Write enable */ status = flexspi_nor_write_enable(base, dstAddr); if (status != kStatus_Success) { return status; } /* Prepare page program command */ flashXfer.deviceAddress = dstAddr; flashXfer.port = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Write; flashXfer.SeqNumber = 1; flashXfer.seqIndex = ROM_INDEX_PAGEPROGRAM; 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. */ #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && FSL_FEATURE_SOC_OTFAD_COUNT == 1 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; }