//***************************************************************************** // //! @file am_devices_mspi_s25fs064s.c //! //! @brief General Multibit SPI S25fs064s driver. // //***************************************************************************** //***************************************************************************** // // Copyright (c) 2020, Ambiq Micro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // Third party software included in this distribution is subject to the // additional license terms as defined in the /docs/licenses directory. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // This is part of revision 2.4.2 of the AmbiqSuite Development Package. // //***************************************************************************** #include "am_mcu_apollo.h" #include "am_devices_mspi_s25fs064s.h" #include "am_util_stdio.h" #include "am_bsp.h" #include "am_util_delay.h" //***************************************************************************** // // Global variables. // //***************************************************************************** #define AM_DEVICES_MSPI_S25FS064S_TIMEOUT 1000000 #define AM_DEVICES_MSPI_S25FS064S_ERASE_TIMEOUT 1000000 typedef struct { uint32_t ui32Module; void *pMspiHandle; am_hal_mspi_dev_config_t stSetting; bool bOccupied; } am_devices_mspi_s25fs064s_t; am_devices_mspi_s25fs064s_t gAmS25fs064s[AM_DEVICES_MSPI_S25FS064S_MAX_DEVICE_NUM]; am_hal_mspi_dev_config_t MSPI_S25fs064s_Serial_CE0_MSPIConfig = { .ui8TurnAround = 3, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_FAST_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, .eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE0, .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .bSendAddr = true, .bSendInstr = true, .bSeparateIO = true, .bTurnaround = true, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; am_hal_mspi_dev_config_t MSPI_S25fs064s_Serial_CE1_MSPIConfig = { .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .ui8TurnAround = 3, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE1, .bSeparateIO = true, .bSendInstr = true, .bSendAddr = true, .bTurnaround = true, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_FAST_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; am_hal_mspi_dev_config_t MSPI_S25fs064s_Dual_CE0_MSPIConfig = { .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .ui8TurnAround = 3, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .eDeviceConfig = AM_HAL_MSPI_FLASH_DUAL_CE0, .bSeparateIO = false, .bSendInstr = true, .bSendAddr = true, .bTurnaround = true, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_DUAL_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; am_hal_mspi_dev_config_t MSPI_S25fs064s_Dual_CE1_MSPIConfig = { .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .ui8TurnAround = 3, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .eDeviceConfig = AM_HAL_MSPI_FLASH_DUAL_CE1, .bSeparateIO = false, .bSendInstr = true, .bSendAddr = true, .bTurnaround = true, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_DUAL_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; am_hal_mspi_dev_config_t MSPI_S25fs064s_Quad_CE0_MSPIConfig = { .ui8TurnAround = 3, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_QUAD_IO_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, .eDeviceConfig = AM_HAL_MSPI_FLASH_QUAD_CE0, .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .bSendAddr = true, .bSendInstr = true, .bSeparateIO = false, .bTurnaround = true, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; am_hal_mspi_dev_config_t MSPI_S25fs064s_Quad_CE1_MSPIConfig = { .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, .eClockFreq = AM_HAL_MSPI_CLK_24MHZ, .ui8TurnAround = 5, .eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE, .eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE, .eDeviceConfig = AM_HAL_MSPI_FLASH_QUAD_CE1, .bSeparateIO = false, .bSendInstr = true, .bSendAddr = true, .bTurnaround = true, .ui8ReadInstr = AM_DEVICES_MSPI_S25FS064S_QUAD_IO_READ, .ui8WriteInstr = AM_DEVICES_MSPI_S25FS064S_PAGE_PROGRAM, #if defined(AM_PART_APOLLO3P) .ui8WriteLatency = 0, .bEnWriteLatency = false, .bEmulateDDR = false, .ui16DMATimeLimit = 0, .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, #endif .ui32TCBSize = 0, .pTCB = NULL, .scramblingStartAddr = 0, .scramblingEndAddr = 0, }; //! MSPI interrupts. static const IRQn_Type mspi_s25fs064s_interrupts[] = { MSPI0_IRQn, #if defined(AM_PART_APOLLO3P) MSPI1_IRQn, MSPI2_IRQn, #endif }; struct { am_hal_mspi_device_e eHalDeviceEnum; am_hal_mspi_dev_config_t *psDevConfig; }g_MSPIS25fs064s_DevConfig[] = { {AM_HAL_MSPI_FLASH_SERIAL_CE0, &MSPI_S25fs064s_Serial_CE0_MSPIConfig}, {AM_HAL_MSPI_FLASH_SERIAL_CE1, &MSPI_S25fs064s_Serial_CE1_MSPIConfig}, {AM_HAL_MSPI_FLASH_DUAL_CE0, &MSPI_S25fs064s_Dual_CE0_MSPIConfig}, {AM_HAL_MSPI_FLASH_DUAL_CE1, &MSPI_S25fs064s_Dual_CE1_MSPIConfig}, {AM_HAL_MSPI_FLASH_QUAD_CE0, &MSPI_S25fs064s_Quad_CE0_MSPIConfig}, {AM_HAL_MSPI_FLASH_QUAD_CE1, &MSPI_S25fs064s_Quad_CE1_MSPIConfig}, }; // // Forward declarations. // static uint32_t am_devices_mspi_s25fsp64s_command_write(void *pHandle, uint8_t ui8Instr, bool bSendAddr, uint32_t ui32Addr, uint32_t *pData, uint32_t ui32NumBytes); static uint32_t am_devices_mspi_s25fsp64s_command_read(void *pHandle, uint8_t ui8Instr, bool bSendAddr, uint32_t ui32Addr, uint32_t *pData, uint32_t ui32NumBytes); //***************************************************************************** // // Cypress S25FS064S Support // //***************************************************************************** // // Device specific initialization function. // static uint32_t am_device_init_flash(void *pHandle) { uint32_t ui32Status = AM_HAL_STATUS_SUCCESS; uint8_t ui8Value = 0; uint32_t ui32PIOBuffer[32] = {0}; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // // Configure the Cypress S25FS064S Configuration Register 1 Volatile based on the MSPI configuration. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } #if 0 switch (psMSPISettings->eDeviceConfig) { case AM_HAL_MSPI_FLASH_SERIAL_CE0: case AM_HAL_MSPI_FLASH_SERIAL_CE1: ui8Value = AM_DEVICES_MSPI_S25FS064S_SERIAL_MODE; break; case AM_HAL_MSPI_FLASH_DUAL_CE0: case AM_HAL_MSPI_FLASH_DUAL_CE1: ui8Value = AM_DEVICES_MSPI_S25FS064S_DUAL_MODE; break; case AM_HAL_MSPI_FLASH_QUAD_CE0: case AM_HAL_MSPI_FLASH_QUAD_CE1: case AM_HAL_MSPI_FLASH_QUADPAIRED: case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL: ui8Value = AM_DEVICES_MSPI_S25FS064S_QUAD_MODE; break; case AM_HAL_MSPI_FLASH_OCTAL_CE0: case AM_HAL_MSPI_FLASH_OCTAL_CE1: return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; //break; } #endif ui32PIOBuffer[0] = AM_DEVICES_MSPI_S25FS064S_CR1V | AM_DEVICES_MSPI_S25FS064S_CR1V_VALUE(AM_DEVICES_MSPI_S25FS064S_SERIAL_MODE); ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ANY_REG, false, 0, ui32PIOBuffer, 4); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Configure the Cypress S25FS064S Configuration Register 3 Volatile based on the MSPI configuration. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32PIOBuffer[0] = AM_DEVICES_MSPI_S25FS064S_CR3V | AM_DEVICES_MSPI_S25FS064S_CR3V_VALUE; ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ANY_REG, false, 0, ui32PIOBuffer, 4); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Configure the Cypress S25FS064S Configuration Register 4 Volatile based on the MSPI configuration. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32PIOBuffer[0] = AM_DEVICES_MSPI_S25FS064S_CR4V | AM_DEVICES_MSPI_S25FS064S_CR4V_VALUE; ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ANY_REG, false, 0, ui32PIOBuffer, 4); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Configure the Cypress S25FS064S Configuration Register 2 Volatile based on the MSPI configuration. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Configure the Addressing mode. // switch (pFlash->stSetting.eAddrCfg) { case AM_HAL_MSPI_ADDR_1_BYTE: case AM_HAL_MSPI_ADDR_2_BYTE: case AM_HAL_MSPI_ADDR_3_BYTE: ui8Value = 0; // Use the Cypress MSPI Flash in 3-byte mode. break; case AM_HAL_MSPI_ADDR_4_BYTE: ui8Value = 0x80; // Use the Cypress MSPI Flash in 4-byte mode. break; } // // Configure the read latency turnaround value. // switch (pFlash->stSetting.eXipMixedMode) { case AM_HAL_MSPI_XIPMIXED_NORMAL: case AM_HAL_MSPI_XIPMIXED_D2: case AM_HAL_MSPI_XIPMIXED_D4: ui8Value |= pFlash->stSetting.ui8TurnAround; // Read latency break; case AM_HAL_MSPI_XIPMIXED_AD2: ui8Value |= pFlash->stSetting.ui8TurnAround - AM_DEVICES_MSPI_S25FS064S_ADDR_DUAL_EXT_DELAY; // Read latency + Mode Bits break; case AM_HAL_MSPI_XIPMIXED_AD4: ui8Value |= pFlash->stSetting.ui8TurnAround - AM_DEVICES_MSPI_S25FS064S_ADDR_QUAD_EXT_DELAY; // Read latency + Mode Bits break; } switch (pFlash->stSetting.eDeviceConfig) { case AM_HAL_MSPI_FLASH_SERIAL_CE0: case AM_HAL_MSPI_FLASH_SERIAL_CE1: case AM_HAL_MSPI_FLASH_DUAL_CE0: case AM_HAL_MSPI_FLASH_DUAL_CE1: break; case AM_HAL_MSPI_FLASH_QUAD_CE0: case AM_HAL_MSPI_FLASH_QUAD_CE1: ui8Value |= 0x40; break; case AM_HAL_MSPI_FLASH_OCTAL_CE0: case AM_HAL_MSPI_FLASH_OCTAL_CE1: case AM_HAL_MSPI_FLASH_QUADPAIRED: case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL: return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32PIOBuffer[0] = AM_DEVICES_MSPI_S25FS064S_CR2V | AM_DEVICES_MSPI_S25FS064S_CR2V_VALUE(ui8Value); ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ANY_REG, false, 0, ui32PIOBuffer, 4); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } // // Device specific de-initialization function. // static uint32_t am_device_deinit_flash(void *pHandle) { uint32_t ui32Status = AM_HAL_STATUS_SUCCESS; uint32_t ui32PIOBuffer[32] = {0}; // // Configure the Cypress S25FS064S Configuration Register 1 Volatile back to serial mode. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32PIOBuffer[0] = AM_DEVICES_MSPI_S25FS064S_CR1V | AM_DEVICES_MSPI_S25FS064S_CR1V_VALUE(AM_DEVICES_MSPI_S25FS064S_SERIAL_MODE); ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ANY_REG, false, 0, ui32PIOBuffer, 4); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } else { return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } } am_devices_mspi_s25fs064s_config_t am_devices_mspi_s25fs064s_mode_switch(void *pHandle, am_devices_mspi_s25fs064s_config_t *psMSPISettings) { uint32_t ui32Status = AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; am_devices_mspi_s25fs064s_config_t MSPISettingsBak; am_hal_mspi_dev_config_t *psConfig = NULL; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; for ( uint32_t i = 0; i < (sizeof(g_MSPIS25fs064s_DevConfig) / sizeof(g_MSPIS25fs064s_DevConfig[0])); i++ ) { if ( psMSPISettings->eDeviceConfig == g_MSPIS25fs064s_DevConfig[i].eHalDeviceEnum ) { psConfig = g_MSPIS25fs064s_DevConfig[i].psDevConfig; psConfig->eClockFreq = psMSPISettings->eClockFreq; psConfig->pTCB = psMSPISettings->pNBTxnBuf; psConfig->ui32TCBSize = psMSPISettings->ui32NBTxnBufLength; psConfig->scramblingStartAddr = psMSPISettings->ui32ScramblingStartAddr; psConfig->scramblingEndAddr = psMSPISettings->ui32ScramblingEndAddr; psConfig->eXipMixedMode = psMSPISettings->eMixedMode; break; } } MSPISettingsBak.eClockFreq = pFlash->stSetting.eClockFreq; MSPISettingsBak.eDeviceConfig = pFlash->stSetting.eDeviceConfig; MSPISettingsBak.eMixedMode = pFlash->stSetting.eXipMixedMode; MSPISettingsBak.pNBTxnBuf = pFlash->stSetting.pTCB; MSPISettingsBak.ui32NBTxnBufLength = pFlash->stSetting.ui32TCBSize; MSPISettingsBak.ui32ScramblingEndAddr = pFlash->stSetting.scramblingEndAddr; MSPISettingsBak.ui32ScramblingStartAddr = pFlash->stSetting.scramblingStartAddr; pFlash->stSetting = *psConfig; ui32Status = am_hal_mspi_disable(pFlash->pMspiHandle); ui32Status |= am_hal_mspi_device_configure(pFlash->pMspiHandle, &pFlash->stSetting); ui32Status |= am_hal_mspi_enable(pFlash->pMspiHandle); am_bsp_mspi_pins_enable(pFlash->ui32Module, pFlash->stSetting.eDeviceConfig); ui32Status |= am_hal_mspi_interrupt_clear(pFlash->pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); ui32Status |= am_hal_mspi_interrupt_enable(pFlash->pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); NVIC_EnableIRQ(mspi_s25fs064s_interrupts[pFlash->ui32Module]); return MSPISettingsBak; } #if defined (MSPI_XIPMIXED) static am_hal_mspi_dev_config_t am_devices_mspi_s25fs064s_mode_switch_static(void *pHandle, am_hal_mspi_dev_config_t *pMSPISettings) { uint32_t ui32Status = AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; am_hal_mspi_dev_config_t MSPISettingsBak; if ( pMSPISettings ) { MSPISettingsBak = pFlash->stSetting; pFlash->stSetting = *pMSPISettings; ui32Status = am_hal_mspi_disable(pFlash->pMspiHandle); ui32Status |= am_hal_mspi_device_configure(pFlash->pMspiHandle, &pFlash->stSetting); ui32Status |= am_hal_mspi_enable(pFlash->pMspiHandle); am_bsp_mspi_pins_enable(pFlash->ui32Module, pFlash->stSetting.eDeviceConfig); ui32Status |= am_hal_mspi_interrupt_clear(pFlash->pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); ui32Status |= am_hal_mspi_interrupt_enable(pFlash->pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); NVIC_EnableIRQ(mspi_s25fs064s_interrupts[pFlash->ui32Module]); } return MSPISettingsBak; } #endif //***************************************************************************** // // Generic Command Write function. // //***************************************************************************** static uint32_t am_devices_mspi_s25fsp64s_command_write(void *pHandle, uint8_t ui8Instr, bool bSendAddr, uint32_t ui32Addr, uint32_t *pData, uint32_t ui32NumBytes) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; am_hal_mspi_pio_transfer_t stMSPIFlashPIOTransaction = {0}; // Create the individual write transaction. stMSPIFlashPIOTransaction.ui32NumBytes = ui32NumBytes; stMSPIFlashPIOTransaction.eDirection = AM_HAL_MSPI_TX; stMSPIFlashPIOTransaction.bSendAddr = bSendAddr; stMSPIFlashPIOTransaction.ui32DeviceAddr = ui32Addr; stMSPIFlashPIOTransaction.bSendInstr = true; stMSPIFlashPIOTransaction.ui16DeviceInstr = ui8Instr; stMSPIFlashPIOTransaction.bTurnaround = false; #if 0 // A3DS-25 Deprecate MSPI CONT stMSPIFlashPIOTransaction.bContinue = false; #endif // A3DS-25 stMSPIFlashPIOTransaction.bQuadCmd = false; stMSPIFlashPIOTransaction.pui32Buffer = pData; #if defined (MSPI_XIPMIXED) am_hal_mspi_dev_config_t mode = am_devices_mspi_s25fs064s_mode_switch_static(pHandle, &MSPI_S25fs064s_Serial_CE0_MSPIConfig); #endif // Execute the transction over MSPI. ui32Status = am_hal_mspi_blocking_transfer(pFlash->pMspiHandle, &stMSPIFlashPIOTransaction, AM_DEVICES_MSPI_S25FS064S_TIMEOUT); #if defined (MSPI_XIPMIXED) am_devices_mspi_s25fs064s_mode_switch_static(pHandle, &mode); #endif return ui32Status; } //***************************************************************************** // // Generic Command Read function. // //***************************************************************************** static uint32_t am_devices_mspi_s25fsp64s_command_read(void *pHandle, uint8_t ui8Instr, bool bSendAddr, uint32_t ui32Addr, uint32_t *pData, uint32_t ui32NumBytes) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; am_hal_mspi_pio_transfer_t stMSPIFlashPIOTransaction = {0}; // Create the individual write transaction. stMSPIFlashPIOTransaction.eDirection = AM_HAL_MSPI_RX; stMSPIFlashPIOTransaction.bSendAddr = bSendAddr; stMSPIFlashPIOTransaction.ui32DeviceAddr = ui32Addr; stMSPIFlashPIOTransaction.bSendInstr = true; stMSPIFlashPIOTransaction.ui16DeviceInstr = ui8Instr; stMSPIFlashPIOTransaction.bTurnaround = false; #if 0 // A3DS-25 Deprecate MSPI CONT stMSPIFlashPIOTransaction.bContinue = false; #endif // A3DS-25 stMSPIFlashPIOTransaction.ui32NumBytes = ui32NumBytes; stMSPIFlashPIOTransaction.bQuadCmd = false; stMSPIFlashPIOTransaction.pui32Buffer = pData; #if defined (MSPI_XIPMIXED) am_hal_mspi_dev_config_t mode = am_devices_mspi_s25fs064s_mode_switch_static(pHandle, &MSPI_S25fs064s_Serial_CE0_MSPIConfig); #endif // Execute the transction over MSPI. ui32Status = am_hal_mspi_blocking_transfer(pFlash->pMspiHandle, &stMSPIFlashPIOTransaction, AM_DEVICES_MSPI_S25FS064S_TIMEOUT); #if defined (MSPI_XIPMIXED) am_devices_mspi_s25fs064s_mode_switch_static(pHandle, &mode); #endif return ui32Status; } static void pfnMSPI_S25FS064S_Callback(void *pCallbackCtxt, uint32_t status) { // Set the DMA complete flag. *(volatile bool *)pCallbackCtxt = true; } //***************************************************************************** // //! @brief Initialize the mspi_s25fs064s driver. //! //! @param psIOMSettings - IOM device structure describing the target spiflash. //! @param pfnWriteFunc - Function to use for spi writes. //! @param pfnReadFunc - Function to use for spi reads. //! //! This function should be called before any other am_devices_spiflash //! functions. It is used to set tell the other functions how to communicate //! with the external spiflash hardware. //! //! The \e pfnWriteFunc and \e pfnReadFunc variables may be used to provide //! alternate implementations of SPI write and read functions respectively. If //! they are left set to 0, the default functions am_hal_iom_spi_write() and //! am_hal_iom_spi_read() will be used. //! //! @return None. // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_init(uint32_t ui32Module, am_devices_mspi_s25fs064s_config_t *psMSPISettings, void **ppHandle, void **ppMspiHandle) { uint32_t ui32Status; am_hal_mspi_dev_config_t *psConfig = g_MSPIS25fs064s_DevConfig[0].psDevConfig; void *pMspiHandle; uint32_t ui32Index = 0; if ((ui32Module > AM_REG_MSPI_NUM_MODULES) || (psMSPISettings == NULL)) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Allocate a vacant device handle for ( ui32Index = 0; ui32Index < AM_DEVICES_MSPI_S25FS064S_MAX_DEVICE_NUM; ui32Index++ ) { if ( gAmS25fs064s[ui32Index].bOccupied == false ) { break; } } if ( ui32Index == AM_DEVICES_MSPI_S25FS064S_MAX_DEVICE_NUM ) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } for ( uint32_t i = 0; i < (sizeof(g_MSPIS25fs064s_DevConfig) / sizeof(g_MSPIS25fs064s_DevConfig[0])); i++ ) { if ( psMSPISettings->eDeviceConfig == g_MSPIS25fs064s_DevConfig[i].eHalDeviceEnum ) { psConfig = g_MSPIS25fs064s_DevConfig[i].psDevConfig; psConfig->eClockFreq = psMSPISettings->eClockFreq; psConfig->pTCB = psMSPISettings->pNBTxnBuf; psConfig->ui32TCBSize = psMSPISettings->ui32NBTxnBufLength; psConfig->scramblingStartAddr = psMSPISettings->ui32ScramblingStartAddr; psConfig->scramblingEndAddr = psMSPISettings->ui32ScramblingEndAddr; psConfig->eXipMixedMode = psMSPISettings->eMixedMode; break; } } // // Enable fault detection. // #if AM_APOLLO3_MCUCTRL am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_ENABLE, 0); #else // AM_APOLLO3_MCUCTRL am_hal_mcuctrl_fault_capture_enable(); #endif // AM_APOLLO3_MCUCTRL // // Configure the MSPI for Serial or Quad-Paired Serial operation during initialization. // switch (psConfig->eDeviceConfig) { case AM_HAL_MSPI_FLASH_SERIAL_CE0: case AM_HAL_MSPI_FLASH_DUAL_CE0: case AM_HAL_MSPI_FLASH_QUAD_CE0: gAmS25fs064s[ui32Index].stSetting = MSPI_S25fs064s_Serial_CE0_MSPIConfig; if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_initialize(ui32Module, &pMspiHandle)) { am_util_stdio_printf("Error - Failed to initialize MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(pMspiHandle, AM_HAL_SYSCTRL_WAKE, false)) { am_util_stdio_printf("Error - Failed to power on MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_device_configure(pMspiHandle, &MSPI_S25fs064s_Serial_CE0_MSPIConfig)) { am_util_stdio_printf("Error - Failed to configure MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_enable(pMspiHandle)) { am_util_stdio_printf("Error - Failed to enable MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } am_bsp_mspi_pins_enable(ui32Module, MSPI_S25fs064s_Serial_CE0_MSPIConfig.eDeviceConfig); break; case AM_HAL_MSPI_FLASH_SERIAL_CE1: case AM_HAL_MSPI_FLASH_DUAL_CE1: case AM_HAL_MSPI_FLASH_QUAD_CE1: gAmS25fs064s[ui32Index].stSetting = MSPI_S25fs064s_Serial_CE1_MSPIConfig; if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_initialize(ui32Module, &pMspiHandle)) { am_util_stdio_printf("Error - Failed to initialize MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(pMspiHandle, AM_HAL_SYSCTRL_WAKE, false)) { am_util_stdio_printf("Error - Failed to power on MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_device_configure(pMspiHandle, &MSPI_S25fs064s_Serial_CE1_MSPIConfig)) { am_util_stdio_printf("Error - Failed to configure MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_enable(pMspiHandle)) { am_util_stdio_printf("Error - Failed to enable MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } am_bsp_mspi_pins_enable(ui32Module, MSPI_S25fs064s_Serial_CE1_MSPIConfig.eDeviceConfig); break; case AM_HAL_MSPI_FLASH_OCTAL_CE0: case AM_HAL_MSPI_FLASH_OCTAL_CE1: case AM_HAL_MSPI_FLASH_QUADPAIRED: case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL: return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; //break; } gAmS25fs064s[ui32Index].pMspiHandle = pMspiHandle; gAmS25fs064s[ui32Index].ui32Module = ui32Module; if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_s25fs064s_reset((void*)&gAmS25fs064s[ui32Index])) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Initialize the MSPI settings for the MSPI_S25FS064S. // gAmS25fs064s[ui32Index].stSetting = *psConfig; // // Device specific MSPI Flash initialization. // ui32Status = am_device_init_flash((void*)&gAmS25fs064s[ui32Index]); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Disable MSPI defore re-configuring it ui32Status = am_hal_mspi_disable(pMspiHandle); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Re-Configure the MSPI for the requested operation mode. // ui32Status = am_hal_mspi_device_configure(pMspiHandle, psConfig); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Re-Enable MSPI ui32Status = am_hal_mspi_enable(pMspiHandle); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Configure the MSPI pins. // am_bsp_mspi_pins_enable(ui32Module, psConfig->eDeviceConfig); // // Enable MSPI interrupts. // ui32Status = am_hal_mspi_interrupt_clear(pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32Status = am_hal_mspi_interrupt_enable(pMspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR ); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Return the handle. // gAmS25fs064s[ui32Index].bOccupied = true; *ppMspiHandle = pMspiHandle; *ppHandle = (void *)&gAmS25fs064s[ui32Index]; // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief De-Initialization the mspi_s25fs064s driver. //! //! @param psIOMSettings - IOM device structure describing the target spiflash. //! @param pfnWriteFunc - Function to use for spi writes. //! @param pfnReadFunc - Function to use for spi reads. //! //! This function should be called before any other am_devices_spiflash //! functions. It is used to set tell the other functions how to communicate //! with the external spiflash hardware. //! //! The \e pfnWriteFunc and \e pfnReadFunc variables may be used to provide //! alternate implementations of SPI write and read functions respectively. If //! they are left set to 0, the default functions am_hal_iom_spi_write() and //! am_hal_iom_spi_read() will be used. //! //! @return None. // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_deinit(void *pHandle) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // // Device specific MSPI Flash de-initialization. // ui32Status = am_device_deinit_flash(pHandle); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_s25fs064s_reset(pHandle)) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Disable and clear the interrupts to start with. // ui32Status = am_hal_mspi_interrupt_disable(pFlash->pMspiHandle, 0xFFFFFFFF); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } ui32Status = am_hal_mspi_interrupt_clear(pFlash->pMspiHandle, 0xFFFFFFFF); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Disable the MSPI instance. // ui32Status = am_hal_mspi_disable(pFlash->pMspiHandle); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(pFlash->pMspiHandle, AM_HAL_SYSCTRL_DEEPSLEEP, false)) { am_util_stdio_printf("Error - Failed to power on MSPI.\n"); return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Deinitialize the MSPI instance. // ui32Status = am_hal_mspi_deinitialize(pFlash->pMspiHandle); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Free this device handle pFlash->bOccupied = false; // // Clear the Flash Caching. // #if AM_CMSIS_REGS CACHECTRL->CACHECFG = 0; #else // AM_CMSIS_REGS AM_REG(CACHECTRL, CACHECFG) = 0; #endif // AM_CMSIS_REGS // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Reads the current status of the external s25fs064s //! //! @param ui32DeviceNumber - Device number of the external s25fs064s //! //! This function reads the device ID register of the external s25fs064s, and returns //! the result as an 32-bit unsigned integer value. //! //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_reset(void *pHandle) { uint32_t ui32PIOBuffer[32] = {0}; // // Send the command sequence to reset the device and return status. // if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_RESET_ENABLE, false, 0, ui32PIOBuffer, 0)) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_RESET_MEMORY, false, 0, ui32PIOBuffer, 0)) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Reads the ID of the external s25fs064s and returns the value. //! //! @param pDeviceID - Pointer to the return buffer for the Device ID. //! //! This function reads the device ID register of the external s25fs064s, and returns //! the result as an 32-bit unsigned integer value. //! //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_id(void *pHandle) { uint32_t ui32Status; uint32_t ui32DeviceID; // // Send the command sequence to read the Device ID and return status. // ui32Status = am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_ID, false, 0, &ui32DeviceID, 3); am_util_stdio_printf("Flash ID is %8.8X\n", ui32DeviceID); if ( ((ui32DeviceID & AM_DEVICES_MSPI_S25FS064S_ID_MASK) == AM_DEVICES_MSPI_S25FS064S_ID) && (AM_HAL_STATUS_SUCCESS == ui32Status) ) { return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } else { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } //***************************************************************************** // //! @brief Reads the current status of the external s25fs064s //! //! This function reads the status register of the external s25fs064s, and returns //! the result as an 8-bit unsigned integer value. The processor will block //! during the data transfer process, but will return as soon as the status //! register had been read. //! //! Macro definitions for interpreting the contents of the status register are //! included in the header file. //! //! @return 8-bit status register contents // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_status(void *pHandle, uint32_t *pStatus) { uint32_t ui32Status; // // Send the command sequence to read the device status. // ui32Status = am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_STATUS, false, 0, pStatus, 1); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } uint32_t am_devices_mspi_s25fs064s_read_adv(void *pHandle, uint8_t *pui8RxBuffer, uint32_t ui32ReadAddress, uint32_t ui32NumBytes, uint32_t ui32PauseCondition, uint32_t ui32StatusSetClr, am_hal_mspi_callback_t pfnCallback, void *pCallbackCtxt) { am_hal_mspi_dma_transfer_t Transaction; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // Set the DMA priority Transaction.ui8Priority = 1; // Set the transfer direction to RX (Read) Transaction.eDirection = AM_HAL_MSPI_RX; // Set the transfer count in bytes. Transaction.ui32TransferCount = ui32NumBytes; // Set the address to read data from. Transaction.ui32DeviceAddress = ui32ReadAddress; // Set the target SRAM buffer address. Transaction.ui32SRAMAddress = (uint32_t)pui8RxBuffer; // Clear the CQ stimulus. Transaction.ui32PauseCondition = ui32PauseCondition; // Clear the post-processing Transaction.ui32StatusSetClr = ui32StatusSetClr; // Check the transaction status. ui32Status = am_hal_mspi_nonblocking_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, pfnCallback, pCallbackCtxt); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Reads the contents of the external s25fs064s into a buffer. //! //! @param pui8RxBuffer - Buffer to store the received data from the s25fs064s //! @param ui32ReadAddress - Address of desired data in external s25fs064s //! @param ui32NumBytes - Number of bytes to read from external s25fs064s //! //! This function reads the external s25fs064s at the provided address and stores //! the received data into the provided buffer location. This function will //! only store ui32NumBytes worth of data. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_read(void *pHandle, uint8_t *pui8RxBuffer, uint32_t ui32ReadAddress, uint32_t ui32NumBytes, bool bWaitForCompletion) { am_hal_mspi_dma_transfer_t Transaction; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // Set the DMA priority Transaction.ui8Priority = 1; // Set the transfer direction to RX (Read) Transaction.eDirection = AM_HAL_MSPI_RX; // Set the transfer count in bytes. Transaction.ui32TransferCount = ui32NumBytes; // Set the address to read data from. Transaction.ui32DeviceAddress = ui32ReadAddress; // Set the target SRAM buffer address. Transaction.ui32SRAMAddress = (uint32_t)pui8RxBuffer; // Clear the CQ stimulus. Transaction.ui32PauseCondition = 0; // Clear the post-processing Transaction.ui32StatusSetClr = 0; if (bWaitForCompletion) { // Start the transaction. volatile bool bDMAComplete = false; ui32Status = am_hal_mspi_nonblocking_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, pfnMSPI_S25FS064S_Callback, (void *)&bDMAComplete); // Check the transaction status. if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Wait for DMA Complete or Timeout for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_TIMEOUT; i++) { if (bDMAComplete) { break; } // // Call the BOOTROM cycle function to delay for about 1 microsecond. // am_hal_flash_delay( FLASH_CYCLES_US(1) ); } // Check the status. if (!bDMAComplete) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } else { // Check the transaction status. ui32Status = am_hal_mspi_nonblocking_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, NULL, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Reads the contents of the external s25fs064s into a buffer. //! //! @param pui8RxBuffer - Buffer to store the received data from the s25fs064s //! @param ui32ReadAddress - Address of desired data in external s25fs064s //! @param ui32NumBytes - Number of bytes to read from external s25fs064s //! //! This function reads the external s25fs064s at the provided address and stores //! the received data into the provided buffer location. This function will //! only store ui32NumBytes worth of data. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_read_hiprio(void *pHandle, uint8_t *pui8RxBuffer, uint32_t ui32ReadAddress, uint32_t ui32NumBytes, bool bWaitForCompletion) { am_hal_mspi_dma_transfer_t Transaction; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // Set the DMA priority Transaction.ui8Priority = 1; // Set the transfer direction to RX (Read) Transaction.eDirection = AM_HAL_MSPI_RX; // Set the transfer count in bytes. Transaction.ui32TransferCount = ui32NumBytes; // Set the address to read data from. Transaction.ui32DeviceAddress = ui32ReadAddress; // Set the target SRAM buffer address. Transaction.ui32SRAMAddress = (uint32_t)pui8RxBuffer; // Clear the CQ stimulus. Transaction.ui32PauseCondition = 0; // Clear the post-processing Transaction.ui32StatusSetClr = 0; if (bWaitForCompletion) { // Start the transaction. volatile bool bDMAComplete = false; ui32Status = am_hal_mspi_highprio_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, pfnMSPI_S25FS064S_Callback, (void*)&bDMAComplete); // Check the transaction status. if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Wait for DMA Complete or Timeout for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_TIMEOUT; i++) { if (bDMAComplete) { break; } // // Call the BOOTROM cycle function to delay for about 1 microsecond. // am_hal_flash_delay( FLASH_CYCLES_US(1) ); } // Check the status. if (!bDMAComplete) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } else { // Check the transaction status. ui32Status = am_hal_mspi_highprio_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, NULL, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Programs the given range of s25fs064s addresses. //! //! @param ui32DeviceNumber - Device number of the external s25fs064s //! @param pui8TxBuffer - Buffer to write the external s25fs064s data from //! @param ui32WriteAddress - Address to write to in the external s25fs064s //! @param ui32NumBytes - Number of bytes to write to the external s25fs064s //! //! This function uses the data in the provided pui8TxBuffer and copies it to //! the external s25fs064s at the address given by ui32WriteAddress. It will copy //! exactly ui32NumBytes of data from the original pui8TxBuffer pointer. The //! user is responsible for ensuring that they do not overflow the target s25fs064s //! memory or underflow the pui8TxBuffer array // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_write(void *pHandle, uint8_t *pui8TxBuffer, uint32_t ui32WriteAddress, uint32_t ui32NumBytes, bool bWaitForCompletion) { am_hal_mspi_dma_transfer_t Transaction; bool bWriteComplete = false; uint32_t ui32BytesLeft = ui32NumBytes; uint32_t ui32PageAddress = ui32WriteAddress; uint32_t ui32BufferAddress = (uint32_t)pui8TxBuffer; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; uint32_t ui32PIOBuffer[32] = {0}; while (ui32BytesLeft > 0) { // // Send the command sequence to enable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Set the DMA priority Transaction.ui8Priority = 1; // Set the transfer direction to TX (Write) Transaction.eDirection = AM_HAL_MSPI_TX; if (ui32BytesLeft > AM_DEVICES_MSPI_S25FS064S_PAGE_SIZE) { // Set the transfer count in bytes. Transaction.ui32TransferCount = AM_DEVICES_MSPI_S25FS064S_PAGE_SIZE; ui32BytesLeft -= AM_DEVICES_MSPI_S25FS064S_PAGE_SIZE; } else { // Set the transfer count in bytes. Transaction.ui32TransferCount = ui32BytesLeft; ui32BytesLeft = 0; } // Set the address configuration for the read // Transaction.eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE; // Transaction.eAddrExtSize = AM_HAL_MSPI_ADDR_EXT_0_BYTE; // Transaction.ui8AddrExtValue = 0; // Set the address to read data to. Transaction.ui32DeviceAddress = ui32PageAddress; ui32PageAddress += AM_DEVICES_MSPI_S25FS064S_PAGE_SIZE; // Set the source SRAM buffer address. Transaction.ui32SRAMAddress = ui32BufferAddress; ui32BufferAddress += AM_DEVICES_MSPI_S25FS064S_PAGE_SIZE; // Clear the CQ stimulus. Transaction.ui32PauseCondition = 0; // Clear the post-processing Transaction.ui32StatusSetClr = 0; // Start the transaction. volatile bool bDMAComplete = false; ui32Status = am_hal_mspi_nonblocking_transfer(pFlash->pMspiHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, pfnMSPI_S25FS064S_Callback, (void*)&bDMAComplete); // Check the transaction status. if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // Wait for DMA Complete or Timeout for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_TIMEOUT; i++) { if (bDMAComplete) { break; } // // Call the BOOTROM cycle function to delay for about 1 microsecond. // am_hal_flash_delay( FLASH_CYCLES_US(1) ); } // Check the status. if (!bDMAComplete) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Wait for the Write In Progress to indicate the erase is complete. // for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_TIMEOUT; i++) { ui32Status = am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_STATUS, false, 0, ui32PIOBuffer, 1); if ((AM_HAL_MSPI_FLASH_QUADPAIRED == pFlash->stSetting.eDeviceConfig) || (AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL == pFlash->stSetting.eDeviceConfig)) { bWriteComplete = ((0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)) && (0 == ((ui32PIOBuffer[0] >> 8) & AM_DEVICES_MSPI_S25FS064S_WIP))); } else { bWriteComplete = (0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)); } am_util_delay_us(100); if (bWriteComplete) { break; } } // // Send the command sequence to disable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_DISABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Erases the entire contents of the external s25fs064s //! //! @param ui32DeviceNumber - Device number of the external s25fs064s //! //! This function uses the "Bulk Erase" instruction to erase the entire //! contents of the external s25fs064s. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_mass_erase(void *pHandle) { bool bEraseComplete = false; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; uint32_t ui32PIOBuffer[32] = {0}; // // Send the command sequence to enable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Send the command sequence to do the mass erase. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_BULK_ERASE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Wait for the Write In Progress to indicate the erase is complete. // for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_ERASE_TIMEOUT; i++) { ui32PIOBuffer[0] = 0; am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_STATUS, false, 0, ui32PIOBuffer, 1); if ((AM_HAL_MSPI_FLASH_QUADPAIRED == pFlash->stSetting.eDeviceConfig) || (AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL == pFlash->stSetting.eDeviceConfig)) { bEraseComplete = ((0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)) && (0 == ((ui32PIOBuffer[0] >> 8) & AM_DEVICES_MSPI_S25FS064S_WIP))); } else { bEraseComplete = (0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)); } if (bEraseComplete) { break; } am_util_delay_ms(10); } // // Check the status. // if (!bEraseComplete) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Send the command sequence to disable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_DISABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Erases the contents of a single sector of s25fs064s //! //! @param ui32DeviceNumber - Device number of the external s25fs064s //! @param ui32SectorAddress - Address to erase in the external s25fs064s //! //! This function erases a single sector of the external s25fs064s as specified by //! ui32EraseAddress. The entire sector where ui32EraseAddress will //! be erased. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_sector_erase(void *pHandle, uint32_t ui32SectorAddress) { bool bEraseComplete = false; uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; uint32_t ui32PIOBuffer[32] = {0}; // // Send the command sequence to enable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Send the command sequence to do the sector erase. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_SECTOR_ERASE, true, ui32SectorAddress, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Wait for the Write In Progress to indicate the erase is complete. // for (uint32_t i = 0; i < AM_DEVICES_MSPI_S25FS064S_ERASE_TIMEOUT; i++) { ui32PIOBuffer[0] = 0; am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_STATUS, false, 0, ui32PIOBuffer, 1); if ((AM_HAL_MSPI_FLASH_QUADPAIRED == pFlash->stSetting.eDeviceConfig) || (AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL == pFlash->stSetting.eDeviceConfig)) { bEraseComplete = ((0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)) && (0 == ((ui32PIOBuffer[0] >> 8) & AM_DEVICES_MSPI_S25FS064S_WIP))); } else { bEraseComplete = (0 == (ui32PIOBuffer[0] & AM_DEVICES_MSPI_S25FS064S_WIP)); } if (bEraseComplete) { break; } am_util_delay_ms(10); } // // Check the status. // if (!bEraseComplete) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } uint32_t ui32EraseStatus = 0; // // Send the command sequence to check the erase status. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_EVAL_ERASE_STATUS, true, ui32SectorAddress, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Send the command sequence to read the device status. // ui32Status = am_devices_mspi_s25fsp64s_command_read(pHandle, AM_DEVICES_MSPI_S25FS064S_READ_STATUS2, false, 0, &ui32EraseStatus, 1); if ( (AM_HAL_STATUS_SUCCESS != ui32Status) || ((AM_DEVICES_MSPI_S25FS064S_ERASE_SUCCESS & ui32EraseStatus) == 0) ) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Send the command sequence to disable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_DISABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Return the status. // return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Sets up the MSPI and external S25FS064S into XIP mode. //! //! This function sets the external psram device and the MSPI into XIP mode. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_enable_xip(void *pHandle) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // // Enable XIP on the MSPI. // ui32Status = am_hal_mspi_control(pFlash->pMspiHandle, AM_HAL_MSPI_REQ_XIP_EN, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } #if !MSPI_USE_CQ // Disable the DMA interrupts. ui32Status = am_hal_mspi_interrupt_disable(pFlash->pMspiHandle, AM_HAL_MSPI_INT_DMAERR | AM_HAL_MSPI_INT_DMACMP ); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } #endif return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Removes the MSPI and external S25FS064S from XIP mode. //! //! This function removes the external device and the MSPI from XIP mode. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_disable_xip(void *pHandle) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; uint32_t ui32PIOBuffer[32] = {0}; // // Send the command to enable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Disable XIP on the MSPI. // ui32Status = am_hal_mspi_control(pFlash->pMspiHandle, AM_HAL_MSPI_REQ_XIP_DIS, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Sets up the MSPI and external S25FS064S into scrambling mode. //! //! This function sets the external psram device and the MSPI into scrambling mode. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_enable_scrambling(void *pHandle) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; // // Enable scrambling on the MSPI. // ui32Status = am_hal_mspi_control(pFlash->pMspiHandle, AM_HAL_MSPI_REQ_SCRAMB_EN, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Removes the MSPI and external S25FS064S from scrambling mode. //! //! This function removes the external device and the MSPI from scrambling mode. // //! @return 32-bit status // //***************************************************************************** uint32_t am_devices_mspi_s25fs064s_disable_scrambling(void *pHandle) { uint32_t ui32Status; am_devices_mspi_s25fs064s_t *pFlash = (am_devices_mspi_s25fs064s_t *)pHandle; uint32_t ui32PIOBuffer[32] = {0}; // // Send the command to enable writing. // ui32Status = am_devices_mspi_s25fsp64s_command_write(pHandle, AM_DEVICES_MSPI_S25FS064S_WRITE_ENABLE, false, 0, ui32PIOBuffer, 0); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } // // Disable Scrambling on the MSPI. // ui32Status = am_hal_mspi_control(pFlash->pMspiHandle, AM_HAL_MSPI_REQ_SCRAMB_DIS, NULL); if (AM_HAL_STATUS_SUCCESS != ui32Status) { return AM_DEVICES_MSPI_S25FS064S_STATUS_ERROR; } return AM_DEVICES_MSPI_S25FS064S_STATUS_SUCCESS; }