/*!
 * @file      apm32e10x_smc.c
 *
 * @brief     This file provides all the SMC firmware functions
 *
 * @version     V1.0.3
 *
 * @date        2025-06-17
 *
 * @attention
 *
 *  Copyright (C) 2022-2025 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes ***************************************************************/
#include "apm32e10x_smc.h"
#include "apm32e10x_rcm.h"

/* Private includes *******************************************************/

/* Private macro **********************************************************/

/* Private typedef ********************************************************/

/* Private variables ******************************************************/

/* Private function prototypes ********************************************/

/* External variables *****************************************************/

/* External functions *****************************************************/

/*!
 * @brief     Rest the SMC NOR/SRAM Banks registers
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK1_NORSRAM_1: SMC Bank1 NOR/SRAM1
 *                  @arg SMC_BANK1_NORSRAM_2: SMC Bank1 NOR/SRAM2
 *                  @arg SMC_BANK1_NORSRAM_3: SMC Bank1 NOR/SRAM3
 *                  @arg SMC_BANK1_NORSRAM_4: SMC Bank1 NOR/SRAM4
 *
 * @retval    None
 */
void SMC_ResetNORSRAM(SMC_BANK1_NORSRAM_T bank)
{
    if (bank == SMC_BANK1_NORSRAM_1)
    {
        SMC_Bank1->CSCTRL1 = 0x000030DB;
        SMC_Bank1->CSTIM1 = 0x0FFFFFFF;
        SMC_Bank1E->WRTTIM1 = 0x0FFFFFFF;
    }
    else if (bank == SMC_BANK1_NORSRAM_2)
    {
        SMC_Bank1->CSCTRL2 =  0x000030D2;
        SMC_Bank1->CSTIM2 =   0x0FFFFFFF;
        SMC_Bank1E->WRTTIM2 = 0x0FFFFFFF;
    }
    else if (bank == SMC_BANK1_NORSRAM_3)
    {
        SMC_Bank1->CSCTRL3 =  0x000030D2;
        SMC_Bank1->CSTIM3 =   0x0FFFFFFF;
        SMC_Bank1E->WRTTIM3 = 0x0FFFFFFF;
    }
    else if (bank == SMC_BANK1_NORSRAM_4)
    {
        SMC_Bank1->CSCTRL4 =  0x000030D2;
        SMC_Bank1->CSTIM4 =   0x0FFFFFFF;
        SMC_Bank1E->WRTTIM4 = 0x0FFFFFFF;
    }
}

/*!
 * @brief     Rest the SMC NAND Banks registers
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    None
 */
void SMC_ResetNAND(SMC_BANK_NAND_T bank)
{
    if(bank == SMC_BANK2_NAND)
    {
        /* Set the SMC_Bank2 registers to their reset values */
        SMC_Bank2->CTRL2 = 0x00000018;
        SMC_Bank2->STSINT2 = 0x00000040;
        SMC_Bank2->CMSTIM2 = 0xFCFCFCFC;
        SMC_Bank2->AMSTIM2 = 0xFCFCFCFC;
    }
    /** SMC_BANK3_NAND */
    else if (bank == SMC_BANK3_NAND)
    {
        /* Set the SMC_Bank3 registers to their reset values */
        SMC_Bank3->CTRL3 = 0x00000018;
        SMC_Bank3->STSINT3 = 0x00000040;
        SMC_Bank3->CMSTIM3 = 0xFCFCFCFC;
        SMC_Bank3->AMSTIM3 = 0xFCFCFCFC;
    }
}

/*!
 * @brief     Reset the SMC PCCARD Banks registers
 *
 * @param     None
 *
 * @retval    None
 */
void SMC_ResetPCCard(void)
{
    /** Set the SMC_Bank4 registers to their reset values */
    SMC_Bank4->CTRL4 = 0x00000018;
    SMC_Bank4->STSINT4 = 0x00000040;
    SMC_Bank4->CMSTIM4 = 0xFCFCFCFC;
    SMC_Bank4->AMSTIM4 = 0xFCFCFCFC;
    SMC_Bank4->IOSTIM4 = 0xFCFCFCFC;
}

/*!
 * @brief     Config the SMC NOR/SRAM Banks according to the specified parameters in the smcNORSRAMConfig.
 *
 * @param     smcNORSRAMConfig: Point to a SMC_NORSRAMConfig_T structure
 *
 * @retval    None
 */
void SMC_ConfigNORSRAM(SMC_NORSRAMConfig_T* smcNORSRAMConfig)
{
    if (smcNORSRAMConfig->bank == SMC_BANK1_NORSRAM_1)
    {
        SMC_Bank1->CSCTRL1_B.ADMUXEN   = smcNORSRAMConfig->dataAddressMux;
        SMC_Bank1->CSCTRL1_B.MTYPECFG  = smcNORSRAMConfig->memoryType;
        SMC_Bank1->CSCTRL1_B.MDBWIDCFG = smcNORSRAMConfig->memoryDataWidth;
        SMC_Bank1->CSCTRL1_B.BURSTEN = smcNORSRAMConfig->burstAcceesMode;
        SMC_Bank1->CSCTRL1_B.WSASYNCEN = smcNORSRAMConfig->asynchronousWait;
        SMC_Bank1->CSCTRL1_B.WSPOLCFG = smcNORSRAMConfig->waitSignalPolarity;
        SMC_Bank1->CSCTRL1_B.WRAPBEN = smcNORSRAMConfig->wrapMode;
        SMC_Bank1->CSCTRL1_B.WTIMCFG = smcNORSRAMConfig->waitSignalActive;
        SMC_Bank1->CSCTRL1_B.WREN = smcNORSRAMConfig->writeOperation;
        SMC_Bank1->CSCTRL1_B.WAITEN = smcNORSRAMConfig->waiteSignal;
        SMC_Bank1->CSCTRL1_B.EXTMODEEN = smcNORSRAMConfig->extendedMode;
        SMC_Bank1->CSCTRL1_B.WRBURSTEN = smcNORSRAMConfig->writeBurst;

        if (smcNORSRAMConfig->memoryType == SMC_MEMORY_TYPE_NOR)
        {
            SMC_Bank1->CSCTRL1_B.NORFMACCEN = BIT_SET;
        }

        SMC_Bank1->CSTIM1_B.ADDRSETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressSetupTime;
        SMC_Bank1->CSTIM1_B.ADDRHLDCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressHodeTime;
        SMC_Bank1->CSTIM1_B.DATASETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataSetupTime;
        SMC_Bank1->CSTIM1_B.BUSTURNCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->busTurnaroundTime;
        SMC_Bank1->CSTIM1_B.CLKDIVCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->clockDivision;
        SMC_Bank1->CSTIM1_B.DATALATCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataLatency;
        SMC_Bank1->CSTIM1_B.ASYNCACCCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->accessMode;

        if (smcNORSRAMConfig->extendedMode == SMC_EXTENDEN_MODE_ENABLE)
        {
            SMC_Bank1E->WRTTIM1_B.ADDRSETCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressSetupTime;
            SMC_Bank1E->WRTTIM1_B.ADDRHLDCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressHodeTime;
            SMC_Bank1E->WRTTIM1_B.DATASETCFG = \
                smcNORSRAMConfig->writeTimingStruct->dataSetupTime;
            SMC_Bank1E->WRTTIM1_B.BUSTURNCFG = \
                smcNORSRAMConfig->writeTimingStruct->busTurnaroundTime;
            SMC_Bank1E->WRTTIM1_B.ASYNCACCCFG = \
                smcNORSRAMConfig->writeTimingStruct->accessMode;
        }
        else
        {
            SMC_Bank1E->WRTTIM1 = 0x0FFFFFFF;
        }
    }
    else if (smcNORSRAMConfig->bank == SMC_BANK1_NORSRAM_2)
    {
        SMC_Bank1->CSCTRL2_B.ADMUXEN   = smcNORSRAMConfig->dataAddressMux;
        SMC_Bank1->CSCTRL2_B.MTYPECFG  = smcNORSRAMConfig->memoryType;
        SMC_Bank1->CSCTRL2_B.MDBWIDCFG = smcNORSRAMConfig->memoryDataWidth;
        SMC_Bank1->CSCTRL2_B.BURSTEN = smcNORSRAMConfig->burstAcceesMode;
        SMC_Bank1->CSCTRL2_B.WSASYNCEN = smcNORSRAMConfig->asynchronousWait;
        SMC_Bank1->CSCTRL2_B.WSPOLCFG = smcNORSRAMConfig->waitSignalPolarity;
        SMC_Bank1->CSCTRL2_B.WRAPBEN = smcNORSRAMConfig->wrapMode;
        SMC_Bank1->CSCTRL2_B.WTIMCFG = smcNORSRAMConfig->waitSignalActive;
        SMC_Bank1->CSCTRL2_B.WREN = smcNORSRAMConfig->writeOperation;
        SMC_Bank1->CSCTRL2_B.WAITEN = smcNORSRAMConfig->waiteSignal;
        SMC_Bank1->CSCTRL2_B.EXTMODEEN = smcNORSRAMConfig->extendedMode;
        SMC_Bank1->CSCTRL2_B.WRBURSTEN = smcNORSRAMConfig->writeBurst;

        if (smcNORSRAMConfig->memoryType == SMC_MEMORY_TYPE_NOR)
        {
            SMC_Bank1->CSCTRL2_B.NORFMACCEN = BIT_SET;
        }

        SMC_Bank1->CSTIM2_B.ADDRSETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressSetupTime;
        SMC_Bank1->CSTIM2_B.ADDRHLDCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressHodeTime;
        SMC_Bank1->CSTIM2_B.DATASETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataSetupTime;
        SMC_Bank1->CSTIM2_B.BUSTURNCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->busTurnaroundTime;
        SMC_Bank1->CSTIM2_B.CLKDIVCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->clockDivision;
        SMC_Bank1->CSTIM2_B.DATALATCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataLatency;
        SMC_Bank1->CSTIM2_B.ASYNCACCCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->accessMode;

        if (smcNORSRAMConfig->extendedMode == SMC_EXTENDEN_MODE_ENABLE)
        {
            SMC_Bank1E->WRTTIM2_B.ADDRSETCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressSetupTime;
            SMC_Bank1E->WRTTIM2_B.ADDRHLDCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressHodeTime;
            SMC_Bank1E->WRTTIM2_B.DATASETCFG = \
                smcNORSRAMConfig->writeTimingStruct->dataSetupTime;
            SMC_Bank1E->WRTTIM2_B.BUSTURNCFG = \
                smcNORSRAMConfig->writeTimingStruct->busTurnaroundTime;
            SMC_Bank1E->WRTTIM2_B.ASYNCACCCFG = \
                smcNORSRAMConfig->writeTimingStruct->accessMode;
        }
        else
        {
            SMC_Bank1E->WRTTIM2 = 0x0FFFFFFF;
        }
    }
    else if (smcNORSRAMConfig->bank == SMC_BANK1_NORSRAM_3)
    {
        SMC_Bank1->CSCTRL3_B.ADMUXEN   = smcNORSRAMConfig->dataAddressMux;
        SMC_Bank1->CSCTRL3_B.MTYPECFG  = smcNORSRAMConfig->memoryType;
        SMC_Bank1->CSCTRL3_B.MDBWIDCFG = smcNORSRAMConfig->memoryDataWidth;
        SMC_Bank1->CSCTRL3_B.BURSTEN = smcNORSRAMConfig->burstAcceesMode;
        SMC_Bank1->CSCTRL3_B.WSASYNCEN = smcNORSRAMConfig->asynchronousWait;
        SMC_Bank1->CSCTRL3_B.WSPOLCFG = smcNORSRAMConfig->waitSignalPolarity;
        SMC_Bank1->CSCTRL3_B.WRAPBEN = smcNORSRAMConfig->wrapMode;
        SMC_Bank1->CSCTRL3_B.WTIMCFG = smcNORSRAMConfig->waitSignalActive;
        SMC_Bank1->CSCTRL3_B.WREN = smcNORSRAMConfig->writeOperation;
        SMC_Bank1->CSCTRL3_B.WAITEN = smcNORSRAMConfig->waiteSignal;
        SMC_Bank1->CSCTRL3_B.EXTMODEEN = smcNORSRAMConfig->extendedMode;
        SMC_Bank1->CSCTRL3_B.WRBURSTEN = smcNORSRAMConfig->writeBurst;

        if (smcNORSRAMConfig->memoryType == SMC_MEMORY_TYPE_NOR)
        {
            SMC_Bank1->CSCTRL3_B.NORFMACCEN = BIT_SET;
        }

        SMC_Bank1->CSTIM3_B.ADDRSETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressSetupTime;
        SMC_Bank1->CSTIM3_B.ADDRHLDCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressHodeTime;
        SMC_Bank1->CSTIM3_B.DATASETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataSetupTime;
        SMC_Bank1->CSTIM3_B.BUSTURNCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->busTurnaroundTime;
        SMC_Bank1->CSTIM3_B.CLKDIVCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->clockDivision;
        SMC_Bank1->CSTIM3_B.DATALATCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataLatency;
        SMC_Bank1->CSTIM3_B.ASYNCACCCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->accessMode;

        if (smcNORSRAMConfig->extendedMode == SMC_EXTENDEN_MODE_ENABLE)
        {
            SMC_Bank1E->WRTTIM3_B.ADDRSETCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressSetupTime;
            SMC_Bank1E->WRTTIM3_B.ADDRHLDCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressHodeTime;
            SMC_Bank1E->WRTTIM3_B.DATASETCFG = \
                smcNORSRAMConfig->writeTimingStruct->dataSetupTime;
            SMC_Bank1E->WRTTIM3_B.BUSTURNCFG = \
                smcNORSRAMConfig->writeTimingStruct->busTurnaroundTime;
            SMC_Bank1E->WRTTIM3_B.ASYNCACCCFG = \
                smcNORSRAMConfig->writeTimingStruct->accessMode;
        }
        else
        {
            SMC_Bank1E->WRTTIM3 = 0x0FFFFFFF;
        }
    }
    else if (smcNORSRAMConfig->bank == SMC_BANK1_NORSRAM_4)
    {
        SMC_Bank1->CSCTRL4_B.ADMUXEN   = smcNORSRAMConfig->dataAddressMux;
        SMC_Bank1->CSCTRL4_B.MTYPECFG  = smcNORSRAMConfig->memoryType;
        SMC_Bank1->CSCTRL4_B.MDBWIDCFG = smcNORSRAMConfig->memoryDataWidth;
        SMC_Bank1->CSCTRL4_B.BURSTEN = smcNORSRAMConfig->burstAcceesMode;
        SMC_Bank1->CSCTRL4_B.WSASYNCEN = smcNORSRAMConfig->asynchronousWait;
        SMC_Bank1->CSCTRL4_B.WSPOLCFG = smcNORSRAMConfig->waitSignalPolarity;
        SMC_Bank1->CSCTRL4_B.WRAPBEN = smcNORSRAMConfig->wrapMode;
        SMC_Bank1->CSCTRL4_B.WTIMCFG = smcNORSRAMConfig->waitSignalActive;
        SMC_Bank1->CSCTRL4_B.WREN = smcNORSRAMConfig->writeOperation;
        SMC_Bank1->CSCTRL4_B.WAITEN = smcNORSRAMConfig->waiteSignal;
        SMC_Bank1->CSCTRL4_B.EXTMODEEN = smcNORSRAMConfig->extendedMode;
        SMC_Bank1->CSCTRL4_B.WRBURSTEN = smcNORSRAMConfig->writeBurst;

        if (smcNORSRAMConfig->memoryType == SMC_MEMORY_TYPE_NOR)
        {
            SMC_Bank1->CSCTRL4_B.NORFMACCEN = BIT_SET;
        }

        SMC_Bank1->CSTIM4_B.ADDRSETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressSetupTime;
        SMC_Bank1->CSTIM4_B.ADDRHLDCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->addressHodeTime;
        SMC_Bank1->CSTIM4_B.DATASETCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataSetupTime;
        SMC_Bank1->CSTIM4_B.BUSTURNCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->busTurnaroundTime;
        SMC_Bank1->CSTIM4_B.CLKDIVCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->clockDivision;
        SMC_Bank1->CSTIM4_B.DATALATCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->dataLatency;
        SMC_Bank1->CSTIM4_B.ASYNCACCCFG = \
            smcNORSRAMConfig->readWriteTimingStruct->accessMode;

        if (smcNORSRAMConfig->extendedMode == SMC_EXTENDEN_MODE_ENABLE)
        {
            SMC_Bank1E->WRTTIM4_B.ADDRSETCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressSetupTime;
            SMC_Bank1E->WRTTIM4_B.ADDRHLDCFG = \
                smcNORSRAMConfig->writeTimingStruct->addressHodeTime;
            SMC_Bank1E->WRTTIM4_B.DATASETCFG = \
                smcNORSRAMConfig->writeTimingStruct->dataSetupTime;
            SMC_Bank1E->WRTTIM4_B.BUSTURNCFG = \
                smcNORSRAMConfig->writeTimingStruct->busTurnaroundTime;
            SMC_Bank1E->WRTTIM4_B.ASYNCACCCFG = \
                smcNORSRAMConfig->writeTimingStruct->accessMode;
        }
        else
        {
            SMC_Bank1E->WRTTIM4 = 0x0FFFFFFF;
        }
    }
}

/*!
 * @brief     Config the SMC NAND Banks according to the specified parameters in the smcNANDConfig.
 *
 * @param     smcNANDConfig : Point to a SMC_NANDConfig_T structure.
 *
 * @retval    None
 */
void SMC_ConfigNAND(SMC_NANDConfig_T* smcNANDConfig)
{
    if (smcNANDConfig->bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->CTRL2_B.WAITFEN = smcNANDConfig->waitFeature;
        SMC_Bank2->CTRL2_B.DBWIDCFG = smcNANDConfig->memoryDataWidth;
        SMC_Bank2->CTRL2_B.ECCEN = smcNANDConfig->ECC;
        SMC_Bank2->CTRL2_B.ECCPSCFG = smcNANDConfig->ECCPageSize;
        SMC_Bank2->CTRL2_B.C2RDCFG = smcNANDConfig->TCLRSetupTime;
        SMC_Bank2->CTRL2_B.A2RDCFG = smcNANDConfig->TARSetupTime;
        SMC_Bank2->CTRL2_B.MTYPECFG = BIT_SET;

        SMC_Bank2->CMSTIM2_B.SET2 = \
            smcNANDConfig->commonSpaceTimingStruct->setupTime;
        SMC_Bank2->CMSTIM2_B.WAIT2 = \
            smcNANDConfig->commonSpaceTimingStruct->waitSetupTime;
        SMC_Bank2->CMSTIM2_B.HLD2 = \
            smcNANDConfig->commonSpaceTimingStruct->holdSetupTime;
        SMC_Bank2->CMSTIM2_B.HIZ2 = \
            smcNANDConfig->commonSpaceTimingStruct->HiZSetupTime;

        SMC_Bank2->AMSTIM2_B.SET2 = \
            smcNANDConfig->attributeSpaceTimingStruct->setupTime;
        SMC_Bank2->AMSTIM2_B.WAIT2 = \
            smcNANDConfig->attributeSpaceTimingStruct->waitSetupTime;
        SMC_Bank2->AMSTIM2_B.HLD2 = \
            smcNANDConfig->attributeSpaceTimingStruct->holdSetupTime;
        SMC_Bank2->AMSTIM2_B.HIZ2 = \
            smcNANDConfig->attributeSpaceTimingStruct->HiZSetupTime;
    }
    else if (smcNANDConfig->bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->CTRL3_B.WAITFEN = smcNANDConfig->waitFeature;
        SMC_Bank3->CTRL3_B.DBWIDCFG = smcNANDConfig->memoryDataWidth;
        SMC_Bank3->CTRL3_B.ECCEN = smcNANDConfig->ECC;
        SMC_Bank3->CTRL3_B.ECCPSCFG = smcNANDConfig->ECCPageSize;
        SMC_Bank3->CTRL3_B.C2RDCFG = smcNANDConfig->TCLRSetupTime;
        SMC_Bank3->CTRL3_B.A2RDCFG = smcNANDConfig->TARSetupTime;
        SMC_Bank3->CTRL3_B.MTYPECFG = BIT_SET;

        SMC_Bank3->CMSTIM3_B.SET3 = \
            smcNANDConfig->commonSpaceTimingStruct->setupTime;
        SMC_Bank3->CMSTIM3_B.WAIT3 = \
            smcNANDConfig->commonSpaceTimingStruct->waitSetupTime;
        SMC_Bank3->CMSTIM3_B.HLD3 = \
            smcNANDConfig->commonSpaceTimingStruct->holdSetupTime;
        SMC_Bank3->CMSTIM3_B.HIZ3 = \
            smcNANDConfig->commonSpaceTimingStruct->HiZSetupTime;

        SMC_Bank3->AMSTIM3_B.SET3 = \
            smcNANDConfig->attributeSpaceTimingStruct->setupTime;
        SMC_Bank3->AMSTIM3_B.WAIT3 = \
            smcNANDConfig->attributeSpaceTimingStruct->waitSetupTime;
        SMC_Bank3->AMSTIM3_B.HLD3 = \
            smcNANDConfig->attributeSpaceTimingStruct->holdSetupTime;
        SMC_Bank3->AMSTIM3_B.HIZ3 = \
            smcNANDConfig->attributeSpaceTimingStruct->HiZSetupTime;
    }
}

/*!
 * @brief     Config the SMC PCCARD according to the specified parameters in the smcPCCardConfig.
 *
 * @param     smcPCCardConfig: Point to a SMC_PCCARDConfig_T structure.
 *
 * @retval    None
 */
void SMC_ConfigPCCard(SMC_PCCARDConfig_T* smcPCCardConfig)
{
    SMC_Bank4->CTRL4_B.WAITFEN = smcPCCardConfig->waitFeature;
    SMC_Bank4->CTRL4_B.C2RDCFG = smcPCCardConfig->TCLRSetupTime;
    SMC_Bank4->CTRL4_B.A2RDCFG = smcPCCardConfig->TARSetupTime;
    SMC_Bank4->CTRL4_B.DBWIDCFG = BIT_SET;

    SMC_Bank4->CMSTIM4_B.SET4 = \
        smcPCCardConfig->commonSpaceTimingStruct->setupTime;
    SMC_Bank4->CMSTIM4_B.WAIT4 = \
        smcPCCardConfig->commonSpaceTimingStruct->waitSetupTime;
    SMC_Bank4->CMSTIM4_B.HLD4 = \
        smcPCCardConfig->commonSpaceTimingStruct->holdSetupTime;
    SMC_Bank4->CMSTIM4_B.HIZ4 = \
        smcPCCardConfig->commonSpaceTimingStruct->HiZSetupTime;

    SMC_Bank4->AMSTIM4_B.SET4 = \
        smcPCCardConfig->attributeSpaceTimingStruct->setupTime;
    SMC_Bank4->AMSTIM4_B.WAIT4 = \
        smcPCCardConfig->attributeSpaceTimingStruct->waitSetupTime;
    SMC_Bank4->AMSTIM4_B.HLD4 = \
        smcPCCardConfig->attributeSpaceTimingStruct->holdSetupTime;
    SMC_Bank4->AMSTIM4_B.HIZ4 = \
        smcPCCardConfig->attributeSpaceTimingStruct->HiZSetupTime;

    SMC_Bank4->IOSTIM4_B.SET = \
        smcPCCardConfig->IOSpaceTimingStruct->setupTime;
    SMC_Bank4->IOSTIM4_B.WAIT = \
        smcPCCardConfig->IOSpaceTimingStruct->waitSetupTime;
    SMC_Bank4->IOSTIM4_B.HLD = \
        smcPCCardConfig->IOSpaceTimingStruct->holdSetupTime;
    SMC_Bank4->IOSTIM4_B.HIZ = \
        smcPCCardConfig->IOSpaceTimingStruct->HiZSetupTime;
}

/*!
 * @brief     Fills each smcNORSRAMConfig member with its default value.
 *
 * @param     smcNORSRAMConfig : Point to a SMC_NORSRAMConfig_T structure.
 *
 * @retval    None
 */
void SMC_ConfigNORSRAMStructInit(SMC_NORSRAMConfig_T* smcNORSRAMConfig)
{
    /* Reset NOR/SRAM Init structure parameters values */
    smcNORSRAMConfig->bank = SMC_BANK1_NORSRAM_1;
    smcNORSRAMConfig->dataAddressMux = SMC_DATA_ADDRESS_MUX_ENABLE;
    smcNORSRAMConfig->memoryType = SMC_MEMORY_TYPE_SRAM;
    smcNORSRAMConfig->memoryDataWidth = SMC_MEMORY_DATA_WIDTH_8BIT;
    smcNORSRAMConfig->burstAcceesMode = SMC_BURST_ACCESS_MODE_DISABLE;
    smcNORSRAMConfig->asynchronousWait = SMC_ASYNCHRONOUS_WAIT_DISABLE;
    smcNORSRAMConfig->waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
    smcNORSRAMConfig->wrapMode = SMC_WRAP_MODE_DISABLE;
    smcNORSRAMConfig->waitSignalActive = SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
    smcNORSRAMConfig->writeOperation = SMC_WRITE_OPERATION_ENABLE;
    smcNORSRAMConfig->waiteSignal = SMC_WAITE_SIGNAL_ENABLE;
    smcNORSRAMConfig->extendedMode = SMC_EXTENDEN_MODE_DISABLE;
    smcNORSRAMConfig->writeBurst = SMC_WRITE_BURST_DISABLE;
    smcNORSRAMConfig->readWriteTimingStruct->addressSetupTime = 0xF;
    smcNORSRAMConfig->readWriteTimingStruct->addressHodeTime = 0xF;
    smcNORSRAMConfig->readWriteTimingStruct->dataSetupTime = 0xFF;
    smcNORSRAMConfig->readWriteTimingStruct->busTurnaroundTime = 0xF;
    smcNORSRAMConfig->readWriteTimingStruct->clockDivision = 0xF;
    smcNORSRAMConfig->readWriteTimingStruct->dataLatency = 0xF;
    smcNORSRAMConfig->readWriteTimingStruct->accessMode = SMC_ACCESS_MODE_A;
    smcNORSRAMConfig->writeTimingStruct->addressSetupTime = 0xF;
    smcNORSRAMConfig->writeTimingStruct->addressHodeTime = 0xF;
    smcNORSRAMConfig->writeTimingStruct->dataSetupTime = 0xFF;
    smcNORSRAMConfig->writeTimingStruct->busTurnaroundTime = 0xF;
    smcNORSRAMConfig->writeTimingStruct->clockDivision = 0xF;
    smcNORSRAMConfig->writeTimingStruct->dataLatency = 0xF;
    smcNORSRAMConfig->writeTimingStruct->accessMode = SMC_ACCESS_MODE_A;

}

/*!
 * @brief     Fills each smcNANDConfig member with its default value.
 *
 * @param     smcNANDConfig : Point to a SMC_NANDConfig_T structure.
 *
 * @retval    None
 */
void SMC_ConfigNANDStructInit(SMC_NANDConfig_T* smcNANDConfig)
{
    /* Reset NAND Init structure parameters values */
    smcNANDConfig->bank = SMC_BANK2_NAND;
    smcNANDConfig->waitFeature = SMC_WAIT_FEATURE_DISABLE;
    smcNANDConfig->memoryDataWidth = SMC_MEMORY_DATA_WIDTH_8BIT;
    smcNANDConfig->ECC = SMC_ECC_DISABLE;
    smcNANDConfig->ECCPageSize = SMC_ECC_PAGE_SIZE_BYTE_256;
    smcNANDConfig->TCLRSetupTime = 0x0;
    smcNANDConfig->TARSetupTime = 0x0;
    smcNANDConfig->commonSpaceTimingStruct->setupTime = 0xFC;
    smcNANDConfig->commonSpaceTimingStruct->waitSetupTime = 0xFC;
    smcNANDConfig->commonSpaceTimingStruct->holdSetupTime = 0xFC;
    smcNANDConfig->commonSpaceTimingStruct->HiZSetupTime = 0xFC;
    smcNANDConfig->attributeSpaceTimingStruct->setupTime = 0xFC;
    smcNANDConfig->attributeSpaceTimingStruct->waitSetupTime = 0xFC;
    smcNANDConfig->attributeSpaceTimingStruct->holdSetupTime = 0xFC;
    smcNANDConfig->attributeSpaceTimingStruct->HiZSetupTime = 0xFC;
}

/*!
 * @brief     Fills each smcPCCardConfig member with its default value.
 *
 * @param     smcPCCardConfig : Point to a SMC_PCCARDConfig_T structure.
 *
 * @retval    None
 */
void SMC_ConfigPCCardStructInit(SMC_PCCARDConfig_T* smcPCCardConfig)
{
    /* Reset PCCARD Init structure parameters values */
    smcPCCardConfig->waitFeature = SMC_WAIT_FEATURE_DISABLE;
    smcPCCardConfig->TCLRSetupTime = 0x0;
    smcPCCardConfig->TARSetupTime = 0x0;
    smcPCCardConfig->commonSpaceTimingStruct->setupTime = 0xFC;
    smcPCCardConfig->commonSpaceTimingStruct->waitSetupTime = 0xFC;
    smcPCCardConfig->commonSpaceTimingStruct->holdSetupTime = 0xFC;
    smcPCCardConfig->commonSpaceTimingStruct->HiZSetupTime = 0xFC;
    smcPCCardConfig->attributeSpaceTimingStruct->setupTime = 0xFC;
    smcPCCardConfig->attributeSpaceTimingStruct->waitSetupTime = 0xFC;
    smcPCCardConfig->attributeSpaceTimingStruct->holdSetupTime = 0xFC;
    smcPCCardConfig->attributeSpaceTimingStruct->HiZSetupTime = 0xFC;
    smcPCCardConfig->IOSpaceTimingStruct->setupTime = 0xFC;
    smcPCCardConfig->IOSpaceTimingStruct->waitSetupTime = 0xFC;
    smcPCCardConfig->IOSpaceTimingStruct->holdSetupTime = 0xFC;
    smcPCCardConfig->IOSpaceTimingStruct->HiZSetupTime = 0xFC;
}

/*!
 * @brief     Enables the specified NOR/SRAM Memory Bank.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK1_NORSRAM_1: SMC Bank1 NOR/SRAM1
 *                  @arg SMC_BANK1_NORSRAM_2: SMC Bank1 NOR/SRAM2
 *                  @arg SMC_BANK1_NORSRAM_3: SMC Bank1 NOR/SRAM3
 *                  @arg SMC_BANK1_NORSRAM_4: SMC Bank1 NOR/SRAM4
 *
 * @retval    None
 */
void SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_T bank)
{
    if (bank == SMC_BANK1_NORSRAM_1)
    {
        SMC_Bank1->CSCTRL1_B.MBKEN = BIT_SET;
    }
    else if (bank == SMC_BANK1_NORSRAM_2)
    {
        SMC_Bank1->CSCTRL2_B.MBKEN = BIT_SET;
    }
    else if (bank == SMC_BANK1_NORSRAM_3)
    {
        SMC_Bank1->CSCTRL3_B.MBKEN = BIT_SET;
    }
    else if (bank == SMC_BANK1_NORSRAM_4)
    {
        SMC_Bank1->CSCTRL4_B.MBKEN = BIT_SET;
    }
}

/*!
 * @brief     Disbles the specified NOR/SRAM Memory Bank.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK1_NORSRAM_1: SMC Bank1 NOR/SRAM1
 *                  @arg SMC_BANK1_NORSRAM_2: SMC Bank1 NOR/SRAM2
 *                  @arg SMC_BANK1_NORSRAM_3: SMC Bank1 NOR/SRAM3
 *                  @arg SMC_BANK1_NORSRAM_4: SMC Bank1 NOR/SRAM4
 *
 * @retval    None
 */
void SMC_DisableNORSRAM(SMC_BANK1_NORSRAM_T bank)
{
    if (bank == SMC_BANK1_NORSRAM_1)
    {
        SMC_Bank1->CSCTRL1_B.MBKEN = BIT_RESET;
    }
    else if (bank == SMC_BANK1_NORSRAM_2)
    {
        SMC_Bank1->CSCTRL2_B.MBKEN = BIT_RESET;
    }
    else if (bank == SMC_BANK1_NORSRAM_3)
    {
        SMC_Bank1->CSCTRL3_B.MBKEN = BIT_RESET;
    }
    else if (bank == SMC_BANK1_NORSRAM_4)
    {
        SMC_Bank1->CSCTRL4_B.MBKEN = BIT_RESET;
    }
}
/*!
 * @brief     Enables the specified NAND Memory Bank.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    None
 */
void SMC_EnableNAND(SMC_BANK_NAND_T bank)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->CTRL2_B.MBKEN = BIT_SET;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->CTRL3_B.MBKEN = BIT_SET;
    }
}

/*!
 * @brief     Disbles the specified NAND Memory Bank.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    None
 */
void SMC_DisableNAND(SMC_BANK_NAND_T bank)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->CTRL2_B.MBKEN = BIT_RESET;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->CTRL3_B.MBKEN = BIT_RESET;
    }
}

/*!
 * @brief     Enables the specified PC Card Memory Bank.
 *
 * @param     None
 *
 * @retval    None
 */
void SMC_EnablePCCARD(void)
{
    SMC_Bank4->CTRL4_B.MBKEN = BIT_SET;
}

/*!
 * @brief     Disables the specified PC Card Memory Bank.
 *
 * @param     None
 *
 * @retval    None
 */
void SMC_DisablePCCARD(void)
{
    SMC_Bank4->CTRL4_B.MBKEN = BIT_RESET;
}

/*!
 * @brief     Enbles the SMC NAND ECC feature.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    None
 */
void SMC_EnableNANDECC(SMC_BANK_NAND_T bank)
{
    if (bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->CTRL2_B.ECCEN = BIT_SET;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->CTRL3_B.ECCEN = BIT_SET;
    }
}

/*!
 * @brief     Disbles or disables the SMC NAND ECC feature.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    None
 *
 * @note
 */
void SMC_DisableNANDECC(SMC_BANK_NAND_T bank)
{
    if (bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->CTRL2_B.ECCEN = BIT_RESET;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->CTRL3_B.ECCEN = BIT_RESET;
    }
}

/*!
 * @brief     Read the error correction code register value.
 *
 * @param     bank: Selects the SMC Bank.
 *                  The parameter can be one of following values:
 *                  @arg SMC_BANK2_NAND: SMC Bank2 NAND
 *                  @arg SMC_BANK3_NAND: SMC Bank3 NAND
 *
 * @retval    The value of Error Correction Code (ECC).
 */
uint32_t  SMC_ReadECC(SMC_BANK_NAND_T bank)
{
    uint32_t eccval = 0x00000000;

    if(bank == SMC_BANK2_NAND)
    {
        eccval = SMC_Bank2->ECCRS2;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        eccval = SMC_Bank3->ECCRS3;
    }
    return eccval;
}

/*!
 * @brief    Enables the specified SMC interrupts.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    interrupt: Select the SMC interrupt sources.
 *                      This parameter can be any combination of the following values:
 *                      @arg SMC_INT_EDGE_RISING : Rising edge detection interrupt.
 *                      @arg SMC_INT_LEVEL_HIGH  : High level detection interrupt.
 *                      @arg SMC_INT_EDGE_FALLING: Falling edge detection interrupt.
 *
 * @retval   None
 */
void SMC_EnableInterrupt(SMC_BANK_NAND_T bank, uint32_t interrupt)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->STSINT2 |= interrupt;
    }
    else if(bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->STSINT3 |= interrupt;
    }
    else
    {
        SMC_Bank4->STSINT4 |= interrupt;
    }
}

/*!
 * @brief    Enables the specified SMC interrupts.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    interrupt: Select the SMC interrupt sources.
 *                      This parameter can be any combination of the following values:
 *                      @arg SMC_INT_EDGE_RISING : Rising edge detection interrupt.
 *                      @arg SMC_INT_LEVEL_HIGH  : High level edge detection interrupt.
 *                      @arg SMC_INT_EDGE_FALLING: Falling edge detection interrupt.
 *
 * @retval   None
 */
void SMC_DisableInterrupt(SMC_BANK_NAND_T bank, uint32_t interrupt)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->STSINT2 &= ~interrupt;
    }
    else if(bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->STSINT3 &= ~interrupt;
    }
    else
    {
        SMC_Bank4->STSINT4 &= ~interrupt;
    }
}

/*!
 * @brief    Read the status of specified SMC flag.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    flag: Select the SMC interrupt sources.
 *                 This parameter can be one of the following values:
 *                 @arg SMC_FLAG_EDGE_RISING : Rising egde detection Flag.
 *                 @arg SMC_FLAG_LEVEL_HIGH  : High level detection Flag.
 *                 @arg SMC_FLAG_EDGE_FALLING: Falling egde detection Flag.
 *                 @arg SMC_FLAG_FIFO_EMPTY  : FIFO empty Flag.
 *
 * @retval    SET or RESET
 *
 * @note
 */
uint16_t SMC_ReadStatusFlag(SMC_BANK_NAND_T bank, SMC_FLAG_T flag)
{
    if (bank == SMC_BANK2_NAND)
    {
        return (SMC_Bank2->STSINT2 & flag) ? SET : RESET;
    }
    else if (bank == SMC_BANK3_NAND)
    {
        return (SMC_Bank3->STSINT3 & flag) ? SET : RESET;
    }
    else
    {
        return (SMC_Bank4->STSINT4 & flag) ? SET : RESET;
    }
}

/*!
 * @brief    Clears the SMC's pending flags.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    flag: Select the SMC interrupt sources.
 *                 This parameter can be any combination of the following values:
 *                 @arg SMC_FLAG_EDGE_RISING : Rising egde detection Flag.
 *                 @arg SMC_FLAG_LEVEL_HIGH  : High level detection Flag.
 *                 @arg SMC_FLAG_EDGE_FALLING: Falling egde detection Flag.
 *
 * @retval    None
 */
void SMC_ClearStatusFlag(SMC_BANK_NAND_T bank, uint32_t flag)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->STSINT2 &= ~flag;
    }
    else if(bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->STSINT3 &= ~flag;
    }
    else
    {
        SMC_Bank4->STSINT4 &= ~flag;
    }
}

/*!
 * @brief    Read the specified SMC interrupt has occurred or not.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    interrupt: Select the SMC interrupt source.
 *                      This parameter can be one of the following values:
 *                      @arg SMC_INT_EDGE_RISING : Rising edge detection interrupt.
 *                      @arg SMC_INT_LEVEL_HIGH  : High level edge detection interrupt.
 *                      @arg SMC_INT_EDGE_FALLING: Falling edge detection interrupt.
 *
 * @retval   The status of specified SMC interrupt source.
 */
uint16_t  SMC_ReadIntFlag(SMC_BANK_NAND_T bank, SMC_INT_T flag)
{
    uint32_t tmpsr = 0x0, itstatus = 0x0, itenable = 0x0;

    if(bank == SMC_BANK2_NAND)
    {
        tmpsr = SMC_Bank2->STSINT2;
    }
    else if(bank == SMC_BANK3_NAND)
    {
        tmpsr = SMC_Bank3->STSINT3;
    }
    else
    {
        tmpsr = SMC_Bank4->STSINT4;
    }

    itstatus = tmpsr & flag;
    itenable = tmpsr & (flag >> 3);

    if((itstatus != RESET) && (itenable != RESET))
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/*!
 * @brief    Clears the SMC's interrupt Flag.
 *
 * @param    bank: Selects the SMC Bank.
 *                 The parameter can be one of following values:
 *                 @arg SMC_BANK2_NAND  : SMC Bank2 NAND
 *                 @arg SMC_BANK3_NAND  : SMC Bank3 NAND
 *                 @arg SMC_BANK4_PCCARD: SMC Bank4 PCCARD
 *
 * @param    interrupt: Select the SMC interrupt sources.
 *                      This parameter can be any combination of the following values:
 *                      @arg SMC_INT_EDGE_RISING : Rising edge detection interrupt.
 *                      @arg SMC_INT_LEVEL_HIGH  : High level edge detection interrupt.
 *                      @arg SMC_INT_EDGE_FALLING: Falling edge detection interrupt.
 *
 * @retval   None
 */
void SMC_ClearIntFlag(SMC_BANK_NAND_T bank, uint32_t flag)
{
    if(bank == SMC_BANK2_NAND)
    {
        SMC_Bank2->STSINT2 &= ~(flag >> 3);
    }
    else if(bank == SMC_BANK3_NAND)
    {
        SMC_Bank3->STSINT3 &= ~(flag >> 3);
    }
    else
    {
        SMC_Bank4->STSINT4 &= ~(flag >> 3);
    }
}

