/** * @file module_driver_ospi.c * @author Flagchip * @brief OSPI driver type definition and API * @version 2.0.0 * @date 2023-08-02 * * SDK Version: 2.6.0 * * @copyright Copyright (c) 2020-2024 Flagchip Semiconductors Co., Ltd. * * @details */ /* ******************************************************************************** * Revision History: * * Version Date Initials CR# Descriptions * --------- ---------- ------------ ---------- --------------- * 0.1.0 2023-01-30 Flagchip087 N/A First version for FC7300 * 0.2.0 2023-08-02 Flagchip100 N/A Adjust the OSPI driver framework. * 0.3.0 2024-08-27 Flagchip122 N/A FC7xxx sdk 2.0 ******************************************************************************** */ #include "module_driver_ospi.h" #if OSPI_INSTANCE_COUNT > 0U /********* Local variable ************/ #define OSPI_LUT_KEY_VAL (0xFC03FC03UL) #ifndef OSPI_DEV_ERROR_REPORT #define OSPI_DEV_ERROR_REPORT STD_OFF #endif #if OSPI_DEV_ERROR_REPORT == STD_ON #define OSPI_ReportDevError(func, error) ReportDevError(OSPI_MODULE_ID, func, error) #endif /********* Global Functions ************/ /** * @brief Initialize OSPI configuration * * @param base OSPI peripheral base address * @param config the basic configurations of the OSPI */ void OSPI_Init(OSPI_Type *base, const OSPI_ConfigType *const pConfig) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(pConfig == NULL_PTR ) { OSPI_ReportDevError(OSPI_INIT_ID, OSPI_E_PARAM_POINTER); } else if((pConfig->bDdrEn == true) && (pConfig->eDqsSrcSel != DQS_EXTERNAL_PADINPUT)) { OSPI_ReportDevError(OSPI_INIT_ID, OSPI_E_PARAM_INVALID); } else { #endif OSPI_HWA_SetCtrlValue(base,CTRL_RST_VALUE); OSPI_HWA_SetSocCfgValue(base, 0U); OSPI_HWA_ModuleDisable(base); OSPI_HWA_InternalRefclkDiv(base, pConfig->eClkDivider); OSPI_HWA_InternalRefclkSource(base, pConfig->eClkMux); OSPI_HWA_EndianSelect(base, pConfig->eEndian); OSPI_HWA_PadIbeEnable(base); OSPI_HWA_InternalRefclkEnable(base); OSPI_HWA_DqsInvertedEnable(base); OSPI_HWA_DqsSource(base, pConfig->eDqsSrcSel); OSPI_HWA_DqsModeEnable(base); if (pConfig->eDqsSrcSel == DQS_EXTERNAL_PADINPUT) { if (pConfig->bDdrEn) { OSPI_HWA_DdrClkEnable(base); OSPI_HWA_DdrModeEnable(base); } OSPI_HWA_ObeTimRelaxEnable(base); OSPI_HWA_DqsOutEnable(base); OSPI_HWA_DqsLatEnable(base); OSPI_HWA_Dio3DefLow(base); OSPI_HWA_Dio2DefLow(base); OSPI_HWA_SetDataHoldTime(base, 1); } else if (pConfig->eDqsSrcSel == DQS_PAD_LOOPBACK) { OSPI_HWA_SetSampleDlyClkCycle(base, 0); OSPI_HWA_SelectRefClkEdge(base, 1); } else { } OSPI_HWA_ModuleEnable(base); OSPI_HWA_ClearTxFifo(base); #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Get OSPI configuration * * @param config the basic configurations of the OSPI */ void OSPI_GetDefaultConfig(OSPI_ConfigType *config) { config->bDdrEn = true; config->eDqsSrcSel = DQS_EXTERNAL_PADINPUT; config->eClkDivider = OSPI_CLOCK_DIV_4; config->eClkMux = OSPI_MUX_PLL1; config->eEndian = OSPI_LITTLE_ENDIAN; } /** * @brief De-initialize the OSPI * * @param base OSPI peripheral base address */ void OSPI_DeInit(OSPI_Type *base) { /* Set register to reset value */ OSPI_HWA_SetCtrlValue(base, CTRL_RST_VALUE); OSPI_HWA_SetSocCfgValue(base, 0); OSPI_HWA_ModuleDisable(base); } /** * @brief OSPI Config Flash Parameter * * @param base OSPI peripheral base address * @param pConfig the basic configurations of the OSPI */ void OSPI_FlashConfig(OSPI_Type *base, OSPI_DeviceConfigType *pConfig) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(pConfig == NULL_PTR) { OSPI_ReportDevError(OSPI_SET_FLASHCFG_ID, OSPI_E_PARAM_POINTER); } else if( (pConfig->u8CsHoldTime > (uint8_t)16) || (pConfig->u8CsSetupTime > (uint8_t)16) || (pConfig->u8FlashColAddressSpace > (uint8_t)16) ) { OSPI_ReportDevError(OSPI_SET_FLASHCFG_ID, OSPI_E_PARAM_INVALID); } else { #endif OSPI_HWA_SetCsHoldTime(base, pConfig->u8CsHoldTime); OSPI_HWA_SetCsSetupTime(base, pConfig->u8CsSetupTime); OSPI_HWA_CfgDelayLine(base, pConfig->u8DelayLine); OSPI_HWA_SetFlashAddr(base, pConfig->u32FlashAddress); OSPI_HWA_SetFlashTopAddr(base, pConfig->u32FlashTopAddress); OSPI_HWA_SetFlashAddrMode(base, pConfig->u8WordAddressable); OSPI_HWA_SetColAddrSpace(base, pConfig->u8FlashColAddressSpace); #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief OSPI Config LUT * * @param base OSPI peripheral base address * @param index index to be written * @param cmd Command sequence array * @param count Number of sequences * */ void OSPI_UpdateLUT(OSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(cmd == NULL_PTR) { OSPI_ReportDevError(OSPI_UPDATE_LUT_ID, OSPI_E_PARAM_POINTER); } else if((count > 16U) || (index >3U)) { OSPI_ReportDevError(OSPI_UPDATE_LUT_ID, OSPI_E_PARAM_INVALID); } else { #endif uint8_t i = 0; volatile uint32_t *lutBase; /* Wait for bus idle before change flash configuration. */ if (OSPI_Wait_Bus_Idle(base) != OSPI_STATUS_SUCCESS) { return; } /* Unlock LUT for update. */ base->LUT_KEY = OSPI_LUT_KEY_VAL; base->LUT_CFG = 0x02; lutBase = &base->LUT[index*4]; for (i = 0; i < count; i++) { *lutBase = *cmd; lutBase++; cmd++; } /* Lock LUT. */ base->LUT_KEY = OSPI_LUT_KEY_VAL; base->LUT_CFG = 0x01; #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief OSPI Wait bus command transaction done * * @param base OSPI peripheral base address * @return OSPI_StatusType whether the operation is successfully */ OSPI_StatusType OSPI_Wait_Cmd_Done(OSPI_Type *base) { OSPI_StatusType eRet = OSPI_STATUS_TIMEOUT; uint32_t timeout = 0xfffff; do { if ((OSPI_HWA_GetFlag(base) & OSPI_FLAG_BUSDF_MASK ) != (uint32_t)0) { OSPI_HWA_ClearFlag(base, OSPI_FLAG_BUSDF_MASK); eRet = OSPI_STATUS_SUCCESS; break; } timeout--; } while(timeout); return eRet; } /** * @brief OSPI Wait bus command transaction done * * @param base OSPI peripheral base address * @return OSPI_StatusType whether the operation is successfully */ OSPI_StatusType OSPI_Wait_Bus_Idle(OSPI_Type *base) { OSPI_StatusType eRet = OSPI_STATUS_TIMEOUT; uint32_t timeout = 0xfffff; do { if ((OSPI_HWA_GetStatus(base) & OSPI_STATUS_BUSY_MASK) == (uint32_t)0) { eRet = OSPI_STATUS_SUCCESS; break; } timeout--; } while(timeout); return eRet; } /** * @brief OSPI write fifo,fifo size is 16words. * * @param base OSPI peripheral base address * @param u8SeqId the cmd id location in lut. * @param pBuf the write buffer start address. * @param u16Size fifo size to be written. * @return OSPI_StatusType whether the operation is successfully */ OSPI_StatusType OSPI_Write_Fifo(OSPI_Type *base, uint8_t u8SeqId, uint32_t *pBuf, uint16_t u16Size) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(pBuf == NULL_PTR) { OSPI_ReportDevError(OSPI_WRITE_FIFO_ID, OSPI_E_PARAM_POINTER); } else if(u8SeqId > 3U) { OSPI_ReportDevError(OSPI_WRITE_FIFO_ID, OSPI_E_PARAM_INVALID); } else { #endif OSPI_StatusType eRet = OSPI_STATUS_SUCCESS; uint8_t u8LoopI, u8LoopMax; /* Data Register is 32-bit, so loop should div 4 */ u8LoopMax = (uint8_t)u16Size >> 2; for (u8LoopI = 0; u8LoopI < u8LoopMax; u8LoopI++) { OSPI_HWA_WriteTxData(base, pBuf[u8LoopI]); } OSPI_HWA_SetCmdIdSize(base, u8SeqId, u16Size); eRet = OSPI_Wait_Cmd_Done(base); if (eRet == OSPI_STATUS_SUCCESS) { eRet = OSPI_Wait_Bus_Idle(base); } return eRet; #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief OSPI read fifo,fifo size is 16words. * * @param base OSPI peripheral base address * @param u8SeqId the cmd id location in lut. * @param pBuf the read buffer start address. * @param u32Size fifo size to be read. * @return OSPI_StatusType whether the operation is successfully */ OSPI_StatusType OSPI_Read_Fifo(OSPI_Type *base, uint8_t u8SeqId, uint32_t *pBuf, uint16_t u16Size) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(pBuf == NULL_PTR) { OSPI_ReportDevError(OSPI_READ_FIFO_ID, OSPI_E_PARAM_POINTER); } else if(u8SeqId > 3U) { OSPI_ReportDevError(OSPI_READ_FIFO_ID, OSPI_E_PARAM_INVALID); } else { #endif OSPI_StatusType eRet = OSPI_STATUS_SUCCESS; uint8_t u8LoopI, u8LoopMax; OSPI_HWA_SetCmdIdSize(base, u8SeqId, u16Size); eRet = OSPI_Wait_Cmd_Done(base); if (eRet == OSPI_STATUS_SUCCESS) { u8LoopMax = OSPI_HWA_GetRxFifoFillLevel(base); for (u8LoopI = 0; u8LoopI < u8LoopMax; u8LoopI++) { pBuf[u8LoopI] = OSPI_HWA_ReadSecondaryRcvFifoReg(base); } } return eRet; #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief OSPI write sequence data. * * @param base OSPI peripheral base address * @param xfer pointer to the transfer structure * @return OSPI_StatusType whether the operation is successfully */ OSPI_StatusType OSPI_TransferBlocking(OSPI_Type *base, OSPI_TransferType *xfer) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(xfer == NULL_PTR) { OSPI_ReportDevError(OSPI_TRANSFER_BLOCKING_ID, OSPI_E_PARAM_POINTER); } else { #endif OSPI_StatusType eRet = OSPI_STATUS_SUCCESS; uint32_t u32TotalSize = xfer->dataSize; uint32_t u32BaseAddr = xfer->deviceAddress; uint32_t u32LoopCounter = 0; uint32_t u32CurrentSize = 0; if (xfer->cmdType == OSPI_OPERATION_WRITE) { while (u32TotalSize > 0) { OSPI_HWA_SetFlashAddr(base, u32BaseAddr + u32LoopCounter * OSPI_ONE_TRANSFER_SIZE_MAX); u32CurrentSize = u32TotalSize > OSPI_ONE_TRANSFER_SIZE_MAX ? OSPI_ONE_TRANSFER_SIZE_MAX : u32TotalSize; eRet = OSPI_Write_Fifo(base, xfer->seqIndex, xfer->data + u32LoopCounter * OSPI_FIFO_DEPTH_MAX, (uint16_t)u32CurrentSize); if (eRet == OSPI_STATUS_SUCCESS) { u32TotalSize -= u32CurrentSize; u32LoopCounter++; } else { break; } } } else if (xfer->cmdType == OSPI_OPERATION_READ) { while (u32TotalSize > 0) { OSPI_HWA_SetFlashAddr(base, u32BaseAddr + u32LoopCounter * OSPI_ONE_TRANSFER_SIZE_MAX); u32CurrentSize = u32TotalSize > OSPI_ONE_TRANSFER_SIZE_MAX ? OSPI_ONE_TRANSFER_SIZE_MAX : u32TotalSize; eRet = OSPI_Read_Fifo(base, xfer->seqIndex, xfer->data + u32LoopCounter * OSPI_FIFO_DEPTH_MAX, (uint16_t)u32CurrentSize); if (eRet == OSPI_STATUS_SUCCESS) { u32TotalSize -= u32CurrentSize; u32LoopCounter++; } else { break; } } } else { } return eRet; #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } OSPI_StatusType OSPI_TransferNonBlocking(OSPI_Type *base, OSPI_TransferType *xfer) { #if OSPI_DEV_ERROR_REPORT == STD_ON if(xfer == NULL_PTR) { OSPI_ReportDevError(OSPI_TRANSFER_NONBLOCKING_ID, OSPI_E_PARAM_POINTER); } else { #endif OSPI_StatusType eRet = OSPI_STATUS_SUCCESS; if ((xfer->cmdType == OSPI_OPERATION_WRITE) || (xfer->cmdType == OSPI_OPERATION_READ)) { OSPI_HWA_SetFlashAddr(base, xfer->deviceAddress); OSPI_HWA_SetCmdIdSize(base, xfer->seqIndex, xfer->dataSize); } else { } return eRet; #if OSPI_DEV_ERROR_REPORT == STD_ON } #endif } void OSPI_DriverIRQHandler(OSPI_Type *base) { (void)base; } #endif /* #if OSPI_INSTANCE_COUNT > 0U */