circuitpython/ports/mimxrt10xx/supervisor/flexspi_nor_flash_ops.c

149 lines
3.9 KiB
C

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