/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************/
/** \file start.c
 **
 ** \brief Device independent, tool-chain independent C-like code for 
 ** clock, memory and cache initialization.
 **
 ** This file implements functions that are called from the startup script.
 **
 ** \note Some of the functions may be called prior to global variable
 ** initialization.
 **
 ** History:
 **   - 2015-09-01  0.01  HS  Initial version for Traveo
 *****************************************************************************/

// File version 0xYYXX = vYY.XX
#define START_C_VERSION          0x0001

#ifndef __FILE_VERSION_CHECK__

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "common_include.h"
#include "start.h"
#include "base_types.h"
#include "exceptions.h"
#include "interrupts.h"
#include "abstract.h"
#include "mcu_settings.h"

#pragma location="BACKUP_RAM_CONTENT"
uint32_t TestBackupRam;
/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

//------------------------------------------------------------------
//  Macros for ECC memory initialization
//------------------------------------------------------------------

/** DMA transfer width setting for 32-bit access (register DMACB0:TW) */
#define DMA_TRANSFER_WIDTH_32BIT    2
/** DMA transfer width setting for 64-bit access (register DMACB0:TW) */
#define DMA_TRANSFER_WIDTH_64BIT    3

/** DMA block size in byte (valid range: 1...16) */
#define DMA_BLOCK_SIZE         16

/** Start address of TCM RAM setting in startup file (asm) where the start-up stack is located (for validation purposes only). */
#define STARTUP_TCMRAM_START_ADDRESS    0x00000000

/** TCMRAM maximal supported access width (set DMA_TRANSFER_WIDTH_???) */
#define TCMRAM_MAX_ACCESS_WIDTH     DMA_TRANSFER_WIDTH_64BIT
/** Key to unlock the TCMRAM configuration registers by writing to TRCFGn_TCMUNLOCK register */
#define TCMRAM_KEY_UNLOCK           0xACC55ECC
/** Key to lock the TCMRAM configuration registers by writing to TRCFGn_TCMUNLOCK register */
#define TCMRAM_KEY_LOCK             0x5ECCB10C

/** System RAM maximal supported access width (set DMA_TRANSFER_WIDTH_???) */
#define SYSRAM_MAX_ACCESS_WIDTH     DMA_TRANSFER_WIDTH_64BIT
/** Key to unlock the System RAM configuration registers by writing to SRCFG_KEY register */
#define SYSRAM_KEY_UNLOCK           0x5ECC551F
/** Key to lock the System RAM configuration registers by writing to SRCFG_KEY register */
#define SYSRAM_KEY_LOCK             0x551FB10C

/** Key to unlock the TCFLASH configuration registers by writing to TCFCFG_FCPROTKEY register */
#define TCFLASH_KEY_UNLOCK          0xCF61F1A5

/** Key to unlock the WorkFlash configuration registers by writing to WFCFG_CPR register */
#define WFLASH_KEY_UNLOCK          	0xCF6DF1A5

//------------------------------------------------------------------
//  Macros for clock selection and PLL settings
//------------------------------------------------------------------
#if MCU_DEVICE == MCU_DEVICE_S6J336C
    /** Main PLL output divider and multipilier settings. */
//    #define SYSC_MAIN_PLL_DIVN          (33)
    #define SYSC_MAIN_PLL_DIVN          (20)
    #define SYSC_MAIN_PLL_DIVM          (2 / 2)
    #define SYSC_PLL_DIVL               (1 / 2)


    /** Main SSCG output divider and multipilier settings. */

    #define SYSC_MAIN_SSCG_DIVN          (33)
    #define SYSC_MAIN_SSCG_DIVM          (2 / 2)
    #define SYSC_SSCG_DIVL               (1 / 2)

#else
    #error MCU_DEVICE invalid
#endif

/** Key to unlock one access to a System Controller configuration register by writing to SYSC0_PROTKEYR/SYSC1_PROTKEYR register */
#define SYSC_KEY_UNLOCK				0x5CACCE55

/** Trigger to start state transition to RUN profile settings by writing to SYSC0_TRGRUNCNTR register */
#define SYSC_TRIGGER_APPLY_RUN_PROFILE      0xAB

/** Main source clock timer pre-scaler for main osc. stabilization time.
 ** Effective value: 2^SYSC_MAIN_SCT_PRESCALER */
#define SYSC_MAINSCT_PRESCALER     	6

/** Calculate main oscillation stabilization time setting */
#define SYSC_MAINSCT_CMPR          (((MCU_FREQ_CLK_MAIN_HZ / (1 << (SYSC_MAINSCT_PRESCALER))) * MCU_STAB_TIME_CLK_MAIN_MS + 500UL) / 1000UL)

/** PLL oscillation stabilization time setting. */
#define SYSC_PLLST_PLLSTABS         (MCU_STAB_TIME_CLK_PLL)

/** Calculate TCFLASH wait states setting */
#if (MCU_FREQ_CLK_MAIN_PLL_HZ % MCU_TCFLASH_MAXIMUM_FREQUENCY) != 0
    #define TCFLASH_WAIT            (MCU_FREQ_CLK_MAIN_PLL_HZ / MCU_TCFLASH_MAXIMUM_FREQUENCY)
#else
    #define TCFLASH_WAIT            (MCU_FREQ_CLK_MAIN_PLL_HZ / MCU_TCFLASH_MAXIMUM_FREQUENCY - 1)
#endif

/** Calculate WCFLASH wait states setting */
#if (MCU_FREQ_CLK_MAIN_PLL_HZ % MCU_WFLASH_MAXIMUM_FREQUENCY) != 0
    #define WFLASH_WAIT            ((MCU_FREQ_CLK_MAIN_PLL_HZ / MCU_WFLASH_MAXIMUM_FREQUENCY) / (TCFLASH_WAIT + 1))
#else
    #define WFLASH_WAIT            ((MCU_FREQ_CLK_MAIN_PLL_HZ / MCU_WFLASH_MAXIMUM_FREQUENCY) / (TCFLASH_WAIT + 1) - 1)
#endif

//------------------------------------------------------------------
//  Macros for Watchdog configuration
//------------------------------------------------------------------

#define	WDG_KEY_UNLOCK    0xEDACCE55     // Write this key to unlock the Watchdog registers for writing


//------------------------------------------------------------------
//  Macros for ECC configuration of the I-cache and the D-cache
//------------------------------------------------------------------
/* C1 Auxiliary Control Register CEC bit setting */
#if MCU_CACHE_ECC_ENABLE == MCU_ENABLE
    #if MCU_CACHE_ECC_ABORT_ENABLE == MCU_ENABLE
        #if MCU_CACHE_ECC_FORCE_WRITE_THROUGH == MCU_ENABLE
            #define	CACHE_CEC_SETTING   0x2 /* enable ECC, force write through, enable ABORT generation */
        #else
            #define	CACHE_CEC_SETTING   0x0 /* enable ECC, enable ABORT generation */
        #endif
    #else
        #if MCU_CACHE_ECC_FORCE_WRITE_THROUGH == MCU_ENABLE
            #define	CACHE_CEC_SETTING   0x6 /* enable ECC, force write through, disable ABORT generation */
        #else
            #define	CACHE_CEC_SETTING   0x5 /* enable ECC, disable ABORT generation */
        #endif
    #endif
    #define CACHE_DBWR_SETTING  0x1 /* ACTLR.DBWR = 1 */
#else
    #define	CACHE_CEC_SETTING   0x4 /* disable ECC */
    #define CACHE_DBWR_SETTING  0x0 /* ACTLR.DBWR = 0 */
#endif

//------------------------------------------------------------------
//  Check macro values
//------------------------------------------------------------------

// Check DMA block size settings
#if (((DMA_BLOCK_SIZE) < 1) || ((DMA_BLOCK_SIZE) > 16))
    #error DMA_BLOCK_SIZE invalid (valid range: 1...16)
#endif

// Check memory start addresses
#if (((SYSRAM_START_ADDRESS) % (1 << (SYSRAM_MAX_ACCESS_WIDTH))) != 0)
    #error SYSRAM_START_ADDRESS invalid (multiple of DMA transfer width required)
#endif

// Check memory sizes
#if (((MCU_TCMRAM_SIZE_BYTE) % ((1 << (TCMRAM_MAX_ACCESS_WIDTH)) * (DMA_BLOCK_SIZE))) != 0)
    #error MCU_TCMRAM_SIZE_BYTE invalid (multiple of (DMA_BLOCK_SIZE * DMA transfer width) required)
#endif
#if (((SYSRAM_SIZE_BYTE) % ((1 << (SYSRAM_MAX_ACCESS_WIDTH)) * (DMA_BLOCK_SIZE))) != 0)
    #error SYSRAM_SIZE_BYTE invalid (multiple of (DMA_BLOCK_SIZE * DMA transfer width) required)
#endif

#if (MCU_SYSRAM_INIT_SIZE_BYTE > MCU_SYSRAM_SIZE_BYTE)
    #error MCU_SYSRAM_INIT_SIZE invalid (INIT_SIZE must less than or equal to SIZE_BYTE)
#endif

// Check consistency of ASM and C pre-processor macros
#if ((STARTUP_TCMRAM_START_ADDRESS) != (MCU_TCMRAM_TCM_INTERFACE_BASE_ADDRESS))
    #error Value mismatch (STARTUP_TCMRAM_START_ADDRESS != MCU_TCMRAM_TCM_INTERFACE_BASE_ADDRESS)!
#endif

// Check for main osc. stabilization time minimum value (to prevent 0-setting)
#if ((MCU_STAB_TIME_CLK_MAIN_MS) < 5UL)
  #error MCU_STAB_TIME_CLK_MAIN_MS invalid (below minimum value)!
#endif
// Check for main osc. stabilization time maximum value (16-bit counter)
#if (((65535UL * 1000UL) / (MCU_FREQ_CLK_MAIN_HZ / (1 << (SYSC_MAINSCT_PRESCALER)))) < (MCU_STAB_TIME_CLK_MAIN_MS))
  #error MCU_STAB_TIME_CLK_MAIN_MS invalid (exceeds maximum value for current MCU_FREQ_CLK_MAIN_HZ and SYSC_MAINSCT_PRESCALER)!
#endif

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/
extern const uint32_t ADDRESS_BOOT_USR_STACK_END;

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/
/** \brief Bits and Bit fields in c1, Coprocessor System Control Registers */
typedef struct stc_mpu_control_field
{
    /** \brief MPU Enable
     ** Enables the MPU:
     ** 0 => MPU disabled. This is the reset value.
     ** 1 => MPU enabled.
     ** If no MPU is implemented, this bit is SBZ.
     **/
    uint_io32_t u1M :0x01;
    /** \brief strict alignment Enable
     ** Enables strict alignment of data to detect alignment faults in data accesses:
     ** 0 => strict alignment fault checking disabled. This is the reset value.
     ** 1 => strict alignment fault checking enabled.
     **/
    uint_io32_t u1A :0x01;
    /** \brief L1 data cache Enable
     ** Enables L1 data cache:
     ** 0 = data caching disabled. This is the reset value.
     ** 1 = data caching enabled.
     ** If no data cache is implemented, then this bit is SBZ.
     **/
    uint_io32_t u1C :0x01;
    /** reserved (SBO) */
    uint_io32_t :0x04;
    /** reserved (SBZ)*/
    uint_io32_t :0x03;
    /** \brief  Enables SWP and SWPB instructions
     ** 0 = SWP and SWPB are Undefined
     ** 1 = SWP and SWPB are executed with full locking support on the bus
     ** The reset value of this bit is 0.
     **/
    uint_io32_t u1SW :0x01;
    /** \brief  Branch prediction enable bit.
     ** The processor supports branch prediction. This bit is SBO.
     ** The ACTLR can control branch prediction,
     ** see c1, Auxiliary Control Register on page 4-41 of ARM Cortex r5 manual.
     **/
    uint_io32_t u1Z :0x01;
    /** \brief  L1 instruction cache enable bit.
     ** Enables L1 instruction cache:
     ** 0 = instruction caching disabled. This is the reset value.
     ** 1 = instruction caching enabled.
     ** If no instruction cache is implemented, then this bit is SBZ.
     **/
    uint_io32_t u1I :0x01;
    /** \brief  Determines the location of exception vectors:
     ** 0 => normal exception vectors selected,
     **      address range = 0x00000000-0x0000001C
     ** 1 => high exception vectors (HIVECS) selected,
     **      address range = 0xFFFF0000-0xFFFF001C.
     ** The primary input VINITHI defines the reset value.
     **/
    uint_io32_t u1V :0x01;
    /** \brief  Round-robin bit.
     ** controls replacement strategy for instruction and data caches:
     ** 0 = random replacement strategy
     ** 1 = round-robin replacement strategy.
     ** The reset value of this bit is 0.
     ** The processor always uses a random replacement strategy,regardless of
     ** the state of this bit.
     **/
    uint_io32_t u1RR :0x01;
    /** reserved (SBZ) */
    uint_io32_t :0x01;
    /** reserved (SBO)*/
    uint_io32_t :0x01;
    /** \brief  MPU background region enable
     **/
    uint_io32_t u1BR :0x01;
    /** reserved (SBO)*/
    uint_io32_t :0x01;
    /** \brief  Divide by zero:.
     ** Divide by zero
     ** 0 = do not generate an Undefined Instruction exception
     ** 1 = generate an Undefined Instruction exception.
     ** The reset value of this bit is 0.
     **/
    uint_io32_t u1DZ :0x01;
    /** reserved (SBZ)*/
    uint_io32_t :0x01;
    /** \brief  Fast Interrupts enable.
     ** On the processor Fast Interrupts are always enabled.
     ** This bit is SBO.
     **/
    uint_io32_t u1FI :0x01;
    /** reserved (SBO)*/
    uint_io32_t :0x02;
    /** \brief  vectored interrupt configuration.
     ** Configures vectored interrupt:
     ** 0 = exception vector address for IRQ is 0x00000018 or 0xFFFF0018.
     **     See V bit.
     ** 1 = VIC controller provides handler address for IRQ.
     ** The reset value of this bit is 0.
     **/
    uint_io32_t u1VE :0x01;
    /** \brief  EE
     ** Determines how the E bit in the CPSR is set on an exception:
     ** 0 => CPSR E bit is set to 0 on an exception
     ** 1 => CPSR E bit is set to 1 on an exception.
     ** The primary input CFGEE defines the reset value.
     **/
    uint_io32_t u1EE :0x01;
    /** reserved (SBZ)*/
    uint_io32_t :0x01;
    /** \brief  NMFI
     ** NMFI, non-maskable fast interrupt enable:
     ** 0 => Software can disable FIQs
     ** 1 => Software cannot disable FIQs.
     ** This bit is read-only.
     ** The configuration input CFGNMFI defines its value.
     **/
    uint_io32_t u1NMFI :0x01;
    /** \brief TEX Remap Enable
     ** TEX Remap Enable
     ** On the processor this bit is SBZ.
     **/
    uint_io32_t u1TRE :0x01;
    /** \brief Access Flag Enable.
     ** Access Flag Enable.
     ** On the processor this bit is SBZ.
     **/
    uint_io32_t u1AFE :0x01;
    /** \brief Thumb exception enable
     ** 0 => enable ARM exception generation
     ** 1 => enable Thumb exception generation.
     ** The primary input TEINIT defines the reset value.
     **/
    uint_io32_t u1TE :0x01;
    /** \brief little or big instruction endianness identification
     ** Identifies little or big instruction endianness in use:
     ** 0 => little-endianness
     ** 1 => big-endianness.
     ** The primary input CFGIE defines the reset value. This bit is read-only.
     **/
    uint_io32_t u1IE :0x01;
}stc_mpu_control_field_t;

/** \brief Type for Coprocessor System Control Registers */
typedef union un_mpu_control
{
    /** Full register */
    uint_io32_t                     u32Register;
    /** Bits and Bit fields */
    stc_mpu_control_field_t         stcField;
    /** Standard fields */
    uint_io8_t                      au8Byte[4];
    uint_io16_t                     au16Halfword[2];
} un_mpu_control_t;

/** \brief Bits and Bit fields in Coprocessor MPU Region Size and Enable Registers */
typedef struct stc_mpu_regionsize_field
{
    /** \brief Enable
     ** Enables or disables a memory region:
     ** 0 => Memory region disabled.
     **      Memory regions are disabled on reset.
     ** 1 => Memory region enabled.
     **      A memory region must be enabled before it is used.
     **/
    uint_io32_t u1Enable :0x01;
    /** \brief Region size
     ** Defines the region size:         b01100 = 8KB      b10110 = 8MB
     ** b00000 - b00011=Unpredictable    b01101 = 16KB     b10111 = 16MB
     ** b00100 = 32 bytes                b01110 = 32KB     b11000 = 32MB
     ** b00101 = 64 bytes                b01111 = 64KB     b11001 = 64MB
     ** b00110 = 128 bytes               b10000 = 128KB    b11010 = 128MB
     ** b00111 = 256 bytes               b10001 = 256KB    b11011 = 256MB
     ** b01000 = 512 bytes               b10010 = 512KB    b11100 = 512MB
     ** b01001 = 1KB                     b10011 = 1MB      b11101 = 1GB
     ** b01010 = 2KB                     b10100 = 2MB      b11110 = 2GB
     ** b01011 = 4KB                     b10101 = 4MB      b11111 = 4GB.
     **/
    uint_io32_t u5RegionSize :0x05;
    /** reserved (SBZ)*/
    uint_io32_t :0x02;
    /** \brief Sub-region disable
     ** Enables or disables a memory region:
     ** Each bit position represents a sub-region, 0-7.
     ** Bit [8] corresponds to sub-region 0
     ** ...
     ** Bit [15] corresponds to sub-region 7
     ** The meaning of each bit is:
     ** 0 = address range is part of this region
     ** 1 = address range is not part of this region.
     **/
    uint_io32_t u8SubRegionDisable :0x08;
    /** reserved (SBZ)*/
    uint_io32_t :0x10;
}stc_mpu_regionsize_field_t;

/** \brief Type for Coprocessor MPU Region Size and Enable Registers */
typedef union un_mpu_regionsize
{
    /** Full register */
    uint_io32_t                     u32Register;
    /** Bits and Bit fields */
    stc_mpu_regionsize_field_t      stcField;
    /** Standard fields */
    uint_io8_t                      au8Byte[4];
    uint_io16_t                     au16Halfword[2];
} un_mpu_regionsize_t;

/** \brief Bits and Bit fields in Coprocessor MPU Region Access Control Register */
typedef struct stc_mpu_regionaccess_field
{
    /** \brief B bit
     ** For more information on this region attribute,
     ** see Table 4-36 in Cortex r5 manual
     **/
    uint_io32_t u1B :0x01;
    /** \brief C bit
     ** For more information on this region attribute,
     ** see Table 4-36 in Cortex r5 manual
     **/
    uint_io32_t u1C :0x01;
    /** \brief Share
     ** Determines if the memory region is Shared or Non-shared:
     ** 0 => Non-shared.
     ** 1 => Shared.
     ** This bit only applies to Normal, not Device or Strongly-ordered memory.
     **/
    uint_io32_t u1S :0x01;
    /** \brief Type extension[2:0]
     **  Defines the type extension attribute.
     ** For more information on this region attribute,
     ** see Table 4-36 in Cortex r5 manual
     **/
    uint_io32_t u3TEX :0x03;
    /** reserved (SBZ) */
    uint_io32_t :0x02;
    /** \brief Access permission[2:0]
     ** AP bit values  Privileged permissions  User permissions  Description
     **    b000        No access               No access         All accesses generate a permission fault
     **    b001        Read/write              No access         Privileged access only
     **    b010        Read/write              Read-only         Writes in User mode generate permission faults
     **    b011        Read/write              Read/write        Full access
     **    b100        UNP                     UNP               Reserved
     **    b101        Read-only               No access         Privileged read-only
     **    b110        Read-only               Read-only         Privileged/User read-only
     **    b111        UNP                     UNP               Reserved
     **/
    uint_io32_t u3AP :0x03;
    /** reserved */
    uint_io32_t :0x01;
    /** \brief Execute Never.
     ** Determines if a region of memory is executable:
     ** 0 => all instruction fetches enabled
     ** 1 => no instruction fetches enabled.
     **/
    uint_io32_t u1XN :0x01;
    /** reserved (SBZ) */
    uint_io32_t :0x13;
}stc_mpu_regionaccess_field_t;

/** \brief Type for Coprocessor MPU Region Access Control Register */
typedef union un_mpu_regionaccess
{
    /** Full register */
    uint_io32_t                     u32Register;
    /** Bits and Bit fields */
    stc_mpu_regionaccess_field_t    stcField;
    /** Standard fields */
    uint_io8_t                      au8Byte[4];
    uint_io16_t                     au16Halfword[2];
} un_mpu_regionaccess_t;

/** \brief Bits and Bit fields in Coprocessor MPU Type Register */
typedef struct stc_mpu_type_field
{
    /** \brief type of MPU regions
     ** Specifies the type of MPU regions, unified or separate, in the processor.
     ** Always set to 0, the processor has unified memory regions.
     **/
    uint_io32_t u1S :0x01;
    /** reserved (SBZ) */
    uint_io32_t :0x07;
    /** \brief Number of unified MPU regions
     ** Specifies the number of unified MPU regions.
     ** Set to 0, 8 or 12 data MPU regions.
     **/
    uint_io32_t u8DRegion :0x08;
    /** reserved (SBZ) */
    uint_io32_t :0x10;
}stc_mpu_type_field_t;

/** \brief Type for Coprocessor MPU Type Register */
typedef union un_mpu_type
{
    /** Full register */
    uint_io32_t                     u32Register;
    /** Bits and Bit fields */
    stc_mpu_type_field_t            stcField;
    /** Standard fields */
    uint_io8_t                      au8Byte[4];
    uint_io16_t                     au16Halfword[2];
} un_mpu_type_t;


/** \brief Region size definition
 ** For further information refer to ARM Cortex-R5 Technical Reference Manual. */
typedef enum en_mpu_region_size
{
    MpuRegionSize32Byte  = 4,    /*!< Region size 32 Byte */
    MpuRegionSize64Byte  = 5,    /*!< Region size 64 Byte */
    MpuRegionSize128Byte = 6,    /*!< Region size 128 Byte */
    MpuRegionSize256Byte = 7,    /*!< Region size 256 Byte */
    MpuRegionSize512Byte = 8,    /*!< Region size 512 Byte */
    MpuRegionSize1kB     = 9,    /*!< Region size 1 kB */
    MpuRegionSize2kB     = 10,   /*!< Region size 2 kB */
    MpuRegionSize4kB     = 11,   /*!< Region size 4 kB */
    MpuRegionSize8kB     = 12,   /*!< Region size 8 kB */
    MpuRegionSize16kB    = 13,   /*!< Region size 16 kB */
    MpuRegionSize32kB    = 14,   /*!< Region size 32 kB */
    MpuRegionSize64kB    = 15,   /*!< Region size 64 kB */
    MpuRegionSize128kB   = 16,   /*!< Region size 128 kB */
    MpuRegionSize256kB   = 17,   /*!< Region size 256 kB */
    MpuRegionSize512kB   = 18,   /*!< Region size 512 kB */
    MpuRegionSize1MB     = 19,   /*!< Region size 1M MB */
    MpuRegionSize2MB     = 20,   /*!< Region size 2 MB */
    MpuRegionSize4MB     = 21,   /*!< Region size 4 MB */
    MpuRegionSize8MB     = 22,   /*!< Region size 8 MB */
    MpuRegionSize16MB    = 23,   /*!< Region size 16 MB */
    MpuRegionSize32MB    = 24,   /*!< Region size 32 MB */
    MpuRegionSize64MB    = 25,   /*!< Region size 64 MB */
    MpuRegionSize128MB   = 26,   /*!< Region size 128 MB */
    MpuRegionSize256MB   = 27,   /*!< Region size 256 MB */
    MpuRegionSize512MB   = 28,   /*!< Region size 512 MB */
    MpuRegionSize1GB     = 29,   /*!< Region size 1 GB */
    MpuRegionSize2GB     = 30,   /*!< Region size 2 GB */
    MpuRegionSize4GB     = 31,   /*!< Region size 4 GB */
} en_mpu_region_size_t;


/** \brief Main memory attribute definition for a region, the other attributes
 **        may be dependend on what is selected here
 ** For further information refer to ARM Cortex-R5 Technical Reference Manual. */
typedef enum en_mpu_region_main_attrib
{
    MpuRegionMainAttribStronglyOrdered       = 0,  /*!< Strongly Ordered memory */
    MpuRegionMainAttribDeviceShareable       = 1,  /*!< Shareable Device memory */
    MpuRegionMainAttribNormalWtNoWa          = 2,  /*!< Normal memory, with outer & inner write-through, no write-allocate cache policy */
    MpuRegionMainAttribNormalWbNoWa          = 3,  /*!< Normal memory, with outer & inner write-back, no write-allocate cache policy */
    MpuRegionMainAttribNormalNonCacheable    = 4,  /*!< Normal memory, non-cacheable */
    MpuRegionMainAttribNormalWtWa            = 7,  /*!< Normal memory, with outer & inner write-back, write-allocate cache policy */
    MpuRegionMainAttribDeviceNonShareable    = 8,  /*!< Non-shareable Device memory */
    MpuRegionMainAttribNormalDiffCachePolicy = 16, /*!< Normal memory, that can have different outer & inner cache policies */
} en_mpu_region_main_attrib_t;


/** \brief Shareable memory attribute definition for a region (only effective
 **        if main memory attribute defines a "Normal" memory type)
 ** For further information refer to ARM Cortex-R5 Technical Reference Manual. */
typedef enum en_mpu_region_share_attrib
{
    MpuRegionShareAttribNonShareable = 0,  /*!< Memory region is non-shareable */
    MpuRegionShareAttribShareable = 1,     /*!< Memory region is shareable */
} en_mpu_region_share_attrib_t;


/** \brief Execute Never. Determines if a region of memory is executable.
 ** For further information refer to ARM Cortex-R5 Technical Reference Manual. */
typedef enum en_mpu_region_exec_never
{
    MpuRegionExecEnable = 0,   /*!< all instruction fetches enabled */
    MpuRegionExecDisable = 1   /*!< no instruction fetches enabled. */
} en_mpu_region_exec_never_t;


/** \brief MPU region settings */
typedef struct stc_mpu_region_settings
{
    boolean_t                    bEnable;             /*!< Enable or disable memory region. */
    en_mpu_region_exec_never_t   enExecNever;         /*!< See definition of #en_mpu_region_exec_never_t.*/
    uint32_t                     u32StartAddress;     /*!< 32 bit Start address. */
    en_mpu_region_size_t         enRegionSize;        /*!< Region Size (see #en_mpu_region_size_t) */
    en_mpu_region_main_attrib_t  enMainMemAttribute;  /*!< Main memory attribute */
    en_mpu_region_share_attrib_t enShareAttribute;    /*!< Defines shareability in case main memory attribute specifies "Normal" memory */
} stc_mpu_region_settings_t;


/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/
static void ConfigureClocks(void);
static void ConfigureMemories(void);
static void ClearEccRamStart(void);
static void ClearEccRamWaitCompletion(void);
static void ConfigureCaches(void);
static void EnableInstructionCache(void);
static void EnableDataCache(void);
static void EnableCacheECC(void);
static void SetMpuConfig(const stc_mpu_region_settings_t* pstcConfig);

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
#ifdef __TOOLCHAIN_IAR__
#pragma data_alignment = 8 /* align = 8byte */
#endif
#ifdef __TOOLCHAIN_GHS_MULTI__
#pragma alignvar (8) /* align = 8byte */
#endif
static const uint64_t u64ClearValue[DMA_BLOCK_SIZE] = {0x0000000000000000};

static const stc_mpu_region_settings_t stcRegionSettings[16] = 
{
    // Each region settings
    // Region 0
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x00000000,                        // Region base address
        MpuRegionSize8MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 1
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x00800000,                        // Region base address
        MpuRegionSize8MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 2
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x01000000,                        // Region base address
        MpuRegionSize16MB,                 // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 3
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x02000000,                        // Region base address
        MpuRegionSize8MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 4
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x02800000,                        // Region base address
        MpuRegionSize64kB,                 // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 5
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x04000000,                        // Region base address
        MpuRegionSize32MB,                 // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 6
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x0E000000,                        // Region base address
        MpuRegionSize1MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribDeviceNonShareable,  // None shareable divice
    },
    // Region 7
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x0E200000,                        // Region base address
        MpuRegionSize1MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribDeviceNonShareable,  // None shareable divice
    },
    // Region 8
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x0E300000,                        // Region base address
        MpuRegionSize1MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalWbNoWa,   // Normal, Write-Back, No Write allocate
        MpuRegionShareAttribNonShareable,  // None Shareable
    },
    // Region 9
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x0E800000,                        // Region base address
        MpuRegionSize64kB,                 // Region size
        // Memory region attributes
        MpuRegionMainAttribDeviceNonShareable,  // None shareable divice
    },
    // Region 10
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x50000000,                        // Region base address
        MpuRegionSize2MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribNormalNonCacheable,  // Normal, None cacheable
        MpuRegionShareAttribShareable,          // Shareable
    },
    // Region 11
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x50200000,                        // Region base address
        MpuRegionSize2MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribStronglyOrdered,  // Strongly-ordered
        MpuRegionShareAttribShareable,       // Shareable
    },
    // Region 12
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x50400000,                        // Region base address
        MpuRegionSize2MB,                  // Region size
        // Memory region attributes
        MpuRegionMainAttribStronglyOrdered,  // Strongly-ordered
        MpuRegionShareAttribShareable,       // Shareable
    },
    // Region 13
    {
        TRUE,                              // Enable Region
        MpuRegionExecEnable,               // Instrunction fetch is enabled
        0x90000000,                        // Region base address
        MpuRegionSize256MB,                // Region size
        // Memory region attributes
        MpuRegionMainAttribStronglyOrdered,  // Strongly-ordered
        MpuRegionShareAttribShareable,       // Shareable
    },
    // Region 14
    {
        TRUE,                              // Enable Region
        MpuRegionExecDisable,              // Instrunction fetch is disabled
        0xB0000000,                        // Region base address
        MpuRegionSize256MB,                // Region size
        // Memory region attributes
        MpuRegionMainAttribDeviceShareable,  // Shareable device
    }
};




/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

/******************************************************************************
 ** \brief Speed-up the system before initialization
 ** 
 ** \e Purpose: Start_PreInit shall make all the settings that should be made 
 ** before start of the system library initialization. These settings are 
 ** concerning execution speed-up like clock settings and caching.
 **
 ** \pre C-like code can be executed. I.e. no global variables/Objects are 
 ** initialized and no calls to standard lib may be done.
 ** Interrupts are disabled.
 **
 ** \post The system is in a state where the initialization of the system 
 ** library can be performed.
 **
 ** \e Side \e effects: There may be clocks (e.g. PLL) that do not take effect 
 ** immediately, but need some time to stabilize. Hence the clock frequency is 
 ** not guaranteed after return from Start_PreInit and may change at some 
 ** point in the future.
 **
 ** \note Waiting for clock stabilization could optionally be done before 
 ** returning. Depending on the clock configuration waiting for clock 
 ** stabilization within Start_PreInit can probably take a lot of time. 
 ** Therefore the system start-up time can be reduced by doing tasks in the 
 ** meantime that are not clock-dependent. In general the initialization of 
 ** the system library is such a task. Wait for clock stabilization can also 
 ** be done after initialization of the system library.
 *****************************************************************************/
void Start_PreInit(void)
{
    // Now we are running on Fast-CR Clock
    // Release I/O-resets (3V, 3/5V domains)
    SYSC0_PROTKEYR = SYSC_KEY_UNLOCK;
    SYSC0_SPECFGR_IO35RSTC = 0;
    SYSC0_PROTKEYR = SYSC_KEY_UNLOCK;
    SYSC0_SPECFGR_IO3RSTC = 0;
     
    // Re-map exception vectors of BootROM's vector table to
    // application specific exception handlers
    Exceptions_Init();
#if 1 //boot select  0 boot 
    // Configure internal memories
    ConfigureMemories();

    // Start to clear all RAM areas that have ECC logic enabled
    ClearEccRamStart();
    
    // Configure clocks
    ConfigureClocks();
    
    // Wait for completion of ECC RAM clearing
    ClearEccRamWaitCompletion();
    
    // Configure MPU
    SetMpuConfig(stcRegionSettings);

    // Configure cache
    ConfigureCaches();
    
#else
    
    // Configure MPU
    SetMpuConfig(stcRegionSettings);

    // Configure cache
    ConfigureCaches();

#endif
    
    if(SYSC0_SPECFGR_HOLDIO_PD2) 
    {	
        if (TestBackupRam != 0x11223344) {
            while (1);
        }
        SYSC0_PROTKEYR = 0x5cacce55;
        SYSC0_SPECFGR = 0x00000000;		// HOLDIO release
    }
    else
    {
        BSP_RTC_Init();
        if (TestBackupRam != 0xaabbccdd) {
            memset((void*)0x02000000, 0, 24*1024);
            TestBackupRam = 0x11223344;
        } else {
            TestBackupRam = 0x11223344;
        }
    }
    
    /* 
    Now everything is ready to initialize the memories i.e.
    copy initial values from flash to RAM.
    
    The zero sections can be skipped (if the toolchain allows)
    as all ECC RAMs are set to '0' via DMA already.
    */
}

/******************************************************************************
 ** \brief Finalize system initialization
 **
 ** \e Purpose: Start_Init shall make all the settings that should be made 
 ** after initialization of the system library but before application 
 ** execution. This will initialize the interrupts (IRQ and NMI) and enable
 ** them globally.
 **
 ** \pre System library initialization is finished, i.e. all global and static  
 ** variables/objects are initialized and all C/C++ library functionality is 
 ** available.
 **
 ** \post The system is in a defined state, depending on the configuration.
 *****************************************************************************/
void Start_Init(void)
{
    // Initialize interrupts (NMIs)
    Interrupts_InitNmi();

    // Globally enable NMIs (cannot be disabled anymore)
    NMI_ENABLE();

    // Initialize interrupts (IRQs)
    Interrupts_InitIrq();

    // Globally enable IRQs
    IRQ_ENABLE();
}

/******************************************************************************
 ** \brief Configures clocks
 **
 ** The function will configure a RUN profile according to the settings
 ** below. It will synchronously wait for the completion of the state
 ** transition to the new RUN profile.
 **
 ** RUN profile settings:
 ** - all Power Domains enabled (PD2,PD3,PD4,PD5,PD6)
 ** - Source oscillation:
 **   > Main Oscillation:           enabled
 **   > Sub Oscillation:            disabled
 **   > Fast RC Oscillation:        enabled
 **   > Slow RC Oscillation:        enabled
 ** - PLLs:
 **   > Main PLL:   enabled, configured for MCU_FREQ_CLK_MAIN_PLL_HZ
 **   > SSCG PLL:   enabled, configured for MCU_FREQ_CLK_SSCG_PLL_HZ
 **                 clock modulation is disabled.
 ** - Clock selection:
 **   > See comment below in the code
 ** - Oscillation stabilization wait time (default)
 ** - Low Voltage Detection (default settings, will cause reset in case of LV)
 ** - Clock Supervisors (all disabled)
 **
 ** \note The sub-oscillator will be disabled in this function, to speed up
 **       the start-up process. Otherwise the time for switching system
 **       clock to PLL would be prolonged by the sub-oscillator stabilization
 **       time, typically about 300 ms (default 2 s).
 **       It is recommended to enable the sub-oscillator after this function
 **       and without synchronously waiting for RUN-2-RUN completion.
 *****************************************************************************/
static void ConfigureClocks(void)
{
    unsigned int  ErrorFlag = 0;
    unsigned int  waitTime = 0;
    unsigned char gotoCount = 0;
    // At first, disable PSS profile update.
    // This setting is for wakeup from shutdown mode.
    // note: SYSC1 was cleared by hardware after PSS profile is updated, but SYSC0 was not cleared.
ClkReset:
    SYSC0_PROTKEYR        = SYSC_KEY_UNLOCK;
    SYSC0_PSSENR_0_PSSEN0 = 0;
   
    //------------------------------------------------------------------
    //  Set main oscillator and main PLL stabilization time
    //------------------------------------------------------------------

    // Main Clock settings
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    
    SYSC_7.unMOSCCNTR.stcField      =   (stc_sysc_7_mosccntr_field_t){      .u1DIV2SEL  = 0,    // Main clock not divided by 2
                                                                            .u2MCGAIN   = 1,    // Main clock gain characteristic for 8MHz
                                                                            .u1MCMODE   = 1,    // Main clock amplifier oscillation mode
                                                                            .u1FCIMEN   = 0 };  // Fast clock input mode is disabled

    // Set new main oscillation stabilization time and trigger data update
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC_6.unMOCTCPR.stcField       =   (stc_sysc_6_moctcpr_field_t){      .u4PSCL      = SYSC_MAINSCT_PRESCALER,   // pre-scaler
                                                                           .u16CMPR     = SYSC_MAINSCT_CMPR };      // compare value
    // trigger configuration capture
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC_6.unMOCTTRGR.stcField      =   (stc_sysc_6_mocttrgr_field_t){     .u1CGCPT     = 1 };
    
    // Set PLL / SSCG stabilization time
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC_7.unPLLSSCGSTCNTR.stcField = (stc_sysc_7_pllsscgstcntr_field_t){  .u4PLLSTABS  = SYSC_PLLST_PLLSTABS,
                                                                           .u4SSCGSTABS = SYSC_PLLST_PLLSTABS, };
    
    //------------------------------------------------------------------
    //  Configure run profile
    //------------------------------------------------------------------
    // Enable power domains
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNPDCFGR.stcField    =   (stc_sysc0_1_runpdcfgr_field_t){    .u1PD4_1EN  =   1,  // switch on PD4_1 (Backup RAM1)
                                                                            .u1PD4_0EN  =   1,  // switch on PD4_0 (Backup RAM0)
                                                                            .u1PD2EN    =   1 };// always on (Peripheral)
    
    // Enable oscillators
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNCKSRER.stcField    =   (stc_sysc0_1_runcksrer_field_t){    .u1SSCG0EN  =   1,  // enable SSCG0
                                                                            .u1PLL0EN   =   1,  // enable PLL0
                                                                            .u1SOSCEN   =   0,  // enable Sub Oscillation
                                                                            .u1MOSCEN   =   1,  // enable Main Oscillation
                                                                            .u1CROSCEN  =   1,  // RC Osc. (always on in RUN state)
                                                                            .u1SCROSCEN =   1 };// Slow RC Osc. (always on in RUN state)
    
    //------------------------------------------------------------------
    // Write Main PLL0 settings
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNPLL0CNTR.stcField  =   (stc_sysc0_1_runpll0cntr_field_t){  .u1PLL0ISEL =   0,                     // use Main Clock as PLL input clock
                                                                            .u8PLL0DIVN =   (SYSC_MAIN_PLL_DIVN),  // set PLL input multiplication value
                                                                            .u4PLL0DIVM =   (SYSC_MAIN_PLL_DIVM),  // set PLL output divider
                                                                            .u2PLL0DIVL =   (SYSC_PLL_DIVL)};      // set PLL input divider

    // Clock gear
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC_7.unPLL0CGCNTR.stcField    =   (stc_sysc_7_pllncgcntr_field_t){    .u8PLLCGLP  =   4,  // Loops per step
                                                                            .u2PLLCGSTP =   1,  // 2 steps
                                                                            .u6PLLCGSSN =   8,  // Start step = 8
                                                                            .u1PLLCGSTR =   0,  // Start gear operation
                                                                            .u1PLLCGEN  =   1}; // Enable

    //------------------------------------------------------------------
    // Write SSCG PLL0 settings
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNSSCG0CNTR0.stcField = (stc_sysc0_1_runsscg0cntr0_field_t){ .u1SSCG0ISEL =  0,                      // use Main Clock as PLL input clock
                                                                            .u8SSCG0DIVN =  (SYSC_MAIN_SSCG_DIVN),  // set SSCG PLL input multiplication value
                                                                            .u4SSCG0DIVM =  (SYSC_MAIN_SSCG_DIVM),  // set SSCG PLL output divider
                                                                            .u2SSCG0DIVL =  (SYSC_SSCG_DIVL)};      // set SSCG PLL input divider

    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNSSCG0CNTR1.stcField = (stc_sysc0_1_runsscg0cntr1_field_t){ .u1SSCG0SSEN  =  0,   // Disable modulation
                                                                            .u2SSCG0FREQ  =  0,   // set modulation frequency
                                                                            .u1SSCG0MODE  =  0,   // set modulation mode
                                                                            .u10SSCG0RATE =  41}; // modulation ratio

    // Clock gear
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC_7.unSSCG0CGCNTR.stcField    =   (stc_sysc_7_sscgncgcntr_field_t){  .u8SSCGCGLP  =   4,  // Loops per step
                                                                            .u2SSCGCGSTP =   1,  // 2 steps
                                                                            .u6SSCGCGSSN =   8,  // Start step = 8
                                                                            .u1SSCGCGSTR =   0,  // Start gear operation
                                                                            .u1SSCGCGEN  =   1}; // Enable


    //------------------------------------------------------------------
    // Select clock sources
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0 
    SYSC0_1.unRUNCKSELR.stcField    =   (stc_sysc0_1_runckselr_field_t){    .u3CDMCUCCSL=   5}; // Clock domain MCUC clock = SSCG0
    
    /*
    In case of CLK_LCP0A and CLK_LCP1A with PLL0, not need to keep this specific ratio between
    CLK_CPU and CLK_LCP0A, CLK_LCP1A.
    */
    
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKSELR0.stcField     =   (stc_sysc1_runckselr0_field_t){     .u4HSSPICSL =   0,  // Hsspi clock domain = PLL0
                                                                            .u1LAPP1ACSL=   0,  // LAPP1A clock = CD0 (1=PLL0)
                                                                            .u1LAPP0ACSL=   0,  // LAPP0A clock = CD0 (1=PLL0)
                                                                            .u1LCP1ACSL =   0,  // LCP1A clock = CD0 (1=PLL0)
                                                                            .u1LCP0ACSL =   0,  // LCP0A clock = CD0 (1=PLL0)
                                                                            .u3CD0CSL   =   5}; // CD0 clock domain = SSCG0

    //non-existent CD1-5  qitiancun
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKSELR1.stcField     =   (stc_sysc1_runckselr1_field_t){     .u4CD4CSL   =   0,  // CD4 clock domain = default 
                                                                            .u4CD3CSL   =   0,  // CD3 clock domain = default 
                                                                            .u4CD2CSL   =   0,  // CD2 clock domain = default 
                                                                            .u4CD1CSL   =   0}; // CD1 clock domain = default 

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKSELR2.stcField     =   (stc_sysc1_runckselr2_field_t){     .u3TRCCSL   =   4,  // TRC clock = PLL0
                                                                            .u4CD5CSL   =   0}; // CD5 clock domain = default 
    
    //------------------------------------------------------------------
    // Enable clocks
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    
    SYSC1.unRUNCKER0.stcField       =   (stc_sysc1_runcker0_field_t) {      .u1ENCLKCPU0    =   1,      // Enable CPU0
                                                                            .u1ENCLKATB     =   1,      // Enable ATB
                                                                            .u1ENCLKDBG     =   1,      // Enable DBG
                                                                            .u1ENCLKTRC     =   1,      // Enable TRC
                                                                            .u1ENCLKHPM2    =   1,      // Enable HPM2
                                                                            .u1ENCLKHPM     =   1,      // Enable HPM
                                                                            .u1ENCLKDMA     =   1,      // Enable DMA
                                                                            .u1ENCLKMEMC    =   1,      // Enable MEMC
                                                                            .u1ENCLKEXTBUS  =   1,      // Enable EXTBUS
                                                                            .u1ENCLKSYSC1   =   1,      // Enable SYSC1
                                                                            .u1ENCLKHAPP0A0 =   1,      // Enable HAPP0A0
                                                                            .u1ENCLKHAPP0A1 =   1,      // Enable HAPP0A1
                                                                            .u1ENCLKHAPP1B0 =   1,      // Enable HAPP1B0
                                                                            .u1ENCLKHAPP1B1 =   1,      // Enable HAPP1B1
                                                                            .u1ENCLKLLPBM   =   1,      // Enable LLPBM
                                                                            .u1ENCLKLLPBM2  =   1,      // Enable LLPBM2
                                                                            .u1ENCLKLCP     =   1,      // Enable LCP
                                                                            .u1ENCLKLCP0    =   1,      // Enable LCP0
                                                                            .u1ENCLKLCP1    =   1,      // Enable LCP1
                                                                            .u1ENCLKLAPP0   =   1,      // Enable LAPP0
                                                                            .u1ENCLKLAPP1   =   1,      // Enable LAPP1
                                                                            .u1ENCLKLCP0A   =   1,      // Enable LCP0A
                                                                            .u1ENCLKLCP1A   =   1,      // Enable LCP1A
                                                                            .u1ENCLKLAPP0A  =   1,      // Enable LAPP0A
                                                                            .u1ENCLKLAPP1A  =   1 };    // Enable LAPP1A

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKER1.stcField       =   (stc_sysc1_runcker1_field_t) {      .u1ENCLKCD3B1   =   0,  // Disable CD3B1
                                                                            .u1ENCLKCD3B0   =   0,  // Disable CD3B0
                                                                            .u1ENCLKCD3A1   =   0,  // Disable CD3A1
                                                                            .u1ENCLKCD3A0   =   0,  // Disable CD3A0
                                                                            .u1ENCLKCD3     =   0,  // Disable CD3
                                                                            .u1ENCLKCD2B1   =   0,  // Disable CD2B1
                                                                            .u1ENCLKCD2B0   =   0,  // Disable CD2B0
                                                                            .u1ENCLKCD2A1   =   0,  // Disable CD2A1
                                                                            .u1ENCLKCD2A0   =   0,  // Disable CD2A0
                                                                            .u1ENCLKCD2     =   0,  // Disable CD2
                                                                            .u1ENCLKCD1B1   =   0,  // Disable CD1B1
                                                                            .u1ENCLKCD1B0   =   0,  // Disable CD1B0
                                                                            .u1ENCLKCD1A1   =   0,  // Disable CD1A1
                                                                            .u1ENCLKCD1A0   =   0,  // Disable CD1A0
                                                                            .u1ENCLKCD1     =   0,  // Disable CD1
                                                                            .u1ENCLKHSSPI   =   0}; // Disable HSSPI

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKER2.stcField       =   (stc_sysc1_runcker2_field_t) {      .u1ENCLKCD5B1   =   0,  // Disable CD5B1
                                                                            .u1ENCLKCD5B0   =   0,  // Disable CD5B0
                                                                            .u1ENCLKCD5A1   =   0,  // Disable CD5A1
                                                                            .u1ENCLKCD5A0   =   0,  // Disable CD5A0
                                                                            .u1ENCLKCD5     =   0,  // Disable CD5
                                                                            .u1ENCLKCD4B1   =   0,  // Disable CD4B1
                                                                            .u1ENCLKCD4B0   =   0,  // Disable CD4B0
                                                                            .u1ENCLKCD4A1   =   0,  // Disable CD4A1
                                                                            .u1ENCLKCD4A0   =   0,  // Disable CD4A0
                                                                            .u1ENCLKCD4     =   0}; // Disable CD4

    //------------------------------------------------------------------

    // Set clock dividers (valid setting for all main-PLL frequencies)
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_1.unRUNCKDIVR.stcField    =   (stc_sysc0_1_runckdivr_field_t) {   .u5MCUCHDIV     =   3}; // MCUconfig AHB clock divider = 4  33MHz

    // Set clock dividers (valid setting for all main-PLL frequencies)
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR0.stcField     =   (stc_sysc1_runckdivr0_field_t) {    .u3HPMDIV       =   3,  // HPM clock divider = 4    33MHz
                                                                            .u5TRCDIV       =   1,  // TRC Clock divider = 2
                                                                            .u2DBGDIV       =   3,  // DBG Clock divider = 4    33MHz
                                                                            .u2ATBDIV       =   1,  // ATB Clock divider = 2    66MHz
                                                                            .u5SYSDIV       =   0}; // System Clock divider = 1



    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR1.stcField     =   (stc_sysc1_runckdivr1_field_t) {    .u4HAPP1B1DIV   =   0,  // HAPP1B1 clock divider = 1
                                                                            .u4HAPP1B0DIV   =   0,  // HAPP1B0 Clock divider = 1
                                                                            .u4HAPP0A1DIV   =   0,  // HAPP0A1 Clock divider = 1
                                                                            .u4HAPP0A0DIV   =   0,  // HAPP0A0 Clock divider = 1
                                                                            .u4SYSC1DIV     =   3,  // SYSC1 Clock divider = 4   33MHz
                                                                            .u3EXTBUSDIV    =   0}; // EXTBUS Clock divider = 1

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR2.stcField     =   (stc_sysc1_runckdivr2_field_t) {    .u4LAPP1DIV     =   1,  // LAPP1 clock divider = 2
                                                                            .u4LAPP0DIV     =   1,  // LAPP0 Clock divider = 2
                                                                            .u4LCP1DIV      =   3,  // LCP1 Clock divider = 4   33MHz
                                                                            .u4LCP0DIV      =   3,  // LCP0 Clock divider = 4   33MHz
                                                                            .u2LCPDIV       =   1}; // LCP Clock divider = 2    66MHz

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR3.stcField     =   (stc_sysc1_runckdivr3_field_t) {    .u5LAPP1ADIV    =   1,  // LAPP1A clock divider = 2
                                                                            .u5LAPP0ADIV    =   1,  // LAPP0A Clock divider = 2
                                                                            .u5LCP1ADIV     =   3,  // LCP1A Clock divider = 4   33MHz
                                                                            .u5LCP0ADIV     =   3}; // LCP0A Clock divider = 4   33MHz

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR4.stcField     =   (stc_sysc1_runckdivr4_field_t){     .u5HSSPIDIV     =   0 };// HSSPI clock divider = 1

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR5.stcField     =   (stc_sysc1_runckdivr5_field_t){     .u4CD1B1DIV     =   0,  // CD1B1DIV clock divider = 1
                                                                            .u4CD1B0DIV     =   0,  // CD1B0DIV clock divider = 1
                                                                            .u4CD1A1DIV     =   0,  // CD1A1DIV clock divider = 1
                                                                            .u4CD1A0DIV     =   0,  // CD1A0DIV clock divider = 1
                                                                            .u5CD1DIV       =   0}; // CD1DIV clock divider = 1 

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR6.stcField     =   (stc_sysc1_runckdivr6_field_t){     .u4CD2B1DIV     =   0,  // CD2B1DIV clock divider = 1
                                                                            .u4CD2B0DIV     =   0,  // CD2B0DIV clock divider = 1
                                                                            .u4CD2A1DIV     =   0,  // CD2A1DIV clock divider = 1
                                                                            .u4CD2A0DIV     =   0,  // CD2A0DIV clock divider = 1
                                                                            .u5CD2DIV       =   0}; // CD2DIV clock divider = 1 
 
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR7.stcField     =   (stc_sysc1_runckdivr7_field_t){     .u4CD3B1DIV     =   0,  // CD3B1DIV clock divider = 1
                                                                            .u4CD3B0DIV     =   0,  // CD3B0DIV clock divider = 1
                                                                            .u4CD3A1DIV     =   0,  // CD3A1DIV clock divider = 1
                                                                            .u4CD3A0DIV     =   0,  // CD3A0DIV clock divider = 1
                                                                            .u5CD3DIV       =   0}; // CD3DIV clock divider = 1 

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR8.stcField     =   (stc_sysc1_runckdivr8_field_t){     .u4CD4B1DIV     =   0,  // CD4B1DIV clock divider = 1
                                                                            .u4CD4B0DIV     =   0,  // CD4B0DIV clock divider = 1
                                                                            .u4CD4A1DIV     =   0,  // CD4A1DIV clock divider = 1
                                                                            .u4CD4A0DIV     =   0,  // CD4A0DIV clock divider = 1
                                                                            .u5CD4DIV       =   0}; // CD4DIV clock divider = 1 

    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1.unRUNCKDIVR9.stcField     =   (stc_sysc1_runckdivr9_field_t){     .u4CD5B1DIV     =   0,  // CD5B1DIV clock divider = 1
                                                                            .u4CD5B0DIV     =   0,  // CD5B0DIV clock divider = 1
                                                                            .u4CD5A1DIV     =   0,  // CD5A1DIV clock divider = 1
                                                                            .u4CD5A0DIV     =   0,  // CD5A0DIV clock divider = 1
                                                                            .u5CD5DIV       =   0}; // CD5DIV clock divider = 1 


    //
    bsp_HDOG_Feed();
    ErrorFlag = SYSC0_SYSRUNPEFR;
    while(ErrorFlag & 0x7FF)
    {
        ErrorFlag = SYSC0_SYSRUNPEFR;
        waitTime ++;
        if(waitTime > 5000)
        {
            break;
        }
        //bsp_HDOG_Feed();
    }
    if(ErrorFlag & 0x7FF)
    {
        gotoCount ++;
        if(gotoCount < 3) {
            waitTime = 0;
            goto ClkReset;
        } else {
            IRQ_DISABLE_LOCAL();
            HWDG_TRG0 = 123456;
            HWDG_TRG1 = 123456;
            IRQ_RESTORE();
        }
    }
    //------------------------------------------------------------------
    // RUN Profile update enable
    SYSC1_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC1
    SYSC1_RUNENR_0_RUNEN1           =   SYSC_TRIGGER_APPLY_RUN_PROFILE;

    // Write the trigger value to apply the RUN profile
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_TRGRUNCNTR                =   SYSC_TRIGGER_APPLY_RUN_PROFILE;    // trigger RUN-->RUN transition
    
    // Wait until the RUN profile is applied
    while (SYSC0_SYSSTSR_RUNDF0 == 0)
    {

    }

    // Clear RUN Profile Done flag (SYSC_SYSSTSR_RUNDN)
    SYSC0_PROTKEYR                  =   SYSC_KEY_UNLOCK;    // unlock SYSC0
    SYSC0_SYSICLR_RUNDFCLR0         =   1;

    //------------------------------------------------------------------
    // Clock gear (Trigger)
    // Trigger (SSCG) PLL Clock gearing if it is not already geared up

    if (SYSC_PLL0CGCNTR_PLLCGSTS == 0)  // Gear up status: 0 - stop gear at min frequency
    {
        SYSC0_PROTKEYR              =   SYSC_KEY_UNLOCK;    // unlock SYSC0
        SYSC_PLL0CGCNTR_PLLCGSTR    =   1;                  // Start gear operation (PLL0)
    }

    if (SYSC_SSCG0CGCNTR_SSCGCGSTS == 0)  // Gear up status: 0 - stop gear at min frequency
    {
        SYSC0_PROTKEYR              =   SYSC_KEY_UNLOCK;    // unlock SYSC0
        SYSC_SSCG0CGCNTR_SSCGCGSTR  =   1;                  // Start gear operation (SSCG0)
    }

    //------------------------------------------------------------------
    // Ensure that PLL clock gearing has also finished
    while ((SYSC_PLL0CGCNTR_PLLCGSTS) != 2)                 // Gear up status: 2 - stop gear at max frequency
    {
    }

    while ((SYSC_SSCG0CGCNTR_SSCGCGSTS) != 2)               // Gear up status: 2 - stop gear at max frequency
    {
    }

    //------------------------------------------------------------------
    //Main clock period[s]  * EXPLLxCNTR.PLLxSTABS setting cycle > 100-6[s]
    // Expand PLL 0
    EP.unEXPLL0CNTR.stcField  =   (stc_ep_expll0cntr_field_t){  .u4PLL0STABS =   10,   // Stabilization time
                                                                .u8PLL0DIVN  =   35,  // set PLL input multiplication value 
                                                                .u4PLL0DIVM  =   1,   // set PLL output divider
                                                                .u2PLL0DIVL  =   0};  // set PLL input divider

    
    // Expand PLL 1
    EP.unEXPLL1CNTR.stcField  =   (stc_ep_expll1cntr_field_t){  .u4PLL1STABS =   10,   // Stabilization time
                                                                .u8PLL1DIVN  =   60, // set PLL input multiplication value
                                                                .u4PLL1DIVM  =   2,   // set PLL output divider
                                                                .u2PLL1DIVL  =   0};  // set PLL input divider

    // Expand PLL 2
    EP.unEXPLL2CNTR.stcField  =   (stc_ep_expll2cntr_field_t){  .u4PLL2STABS =   10,   // Stabilization time
                                                                .u8PLL21DIVN =   50, // set PLL input multiplication value
                                                                .u4PLL2DIVM  =   2,   // set PLL output divider
                                                                .u2PLL2DIVL  =   0};  // set PLL input divider
                                                                //.u4PLL2DIVM  =   2 / 2,   // set PLL output divider
                                                                //.u2PLL2DIVL  =   1 / 2};  // set PLL input divider

    // Clock divider configuration
    // Expand PLL0
    EP.unEXCKDIVR0.stcField  =   (stc_ep_exckdivr0_field_t){  .u5Expand_CLKCD0  =   0,  // CLKCD0 clock divider  
                                                              .u4Expand_CLKCD0A =   0,  // CLKCD0A clock divider
                                                              .u4Expand_CLKCD0B =   0}; // CLKCD0B clock divider

    
    // Expand PLL1
    EP.unEXCKDIVR1.stcField  =   (stc_ep_exckdivr1_field_t){  .u5Expand_CLKCD1  =   0,  // CLKCD0 clock divider
                                                              .u4Expand_CLKCD1A =   0,  // CLKCD0A clock divider
                                                              .u4Expand_CLKCD1B =   1}; // CLKCD0B clock divider

    // Expand PLL2
    EP.unEXCKDIVR2.stcField  =   (stc_ep_exckdivr2_field_t){  .u5Expand_CLKCD2  =   0,  // CLKCD0 clock divider
                                                              .u4Expand_CLKCD2A =   0,  // CLKCD0A clock divider
                                                              .u4Expand_CLKCD2B =   0}; // CLKCD0B clock divider

    // PLL operation enable
    EP.unEXPLLEN.stcField  =   (stc_ep_expllen_field_t){  .u1EXPLL0EN =   1,  // Enable oscillation of the PLL0 clock
                                                          .u1EXPLL1EN =   1,  // Enable oscillation of the PLL1 clock
                                                          .u1EXPLL2EN =   1}; // Enable oscillation of the PLL2 clock

    // The waiting of oscillation stability
    while ((EP_EXPLLEN_EXPLL0RDY) != 1)
    {
    }

    while ((EP_EXPLLEN_EXPLL1RDY) != 1)
    {
    }

    while ((EP_EXPLLEN_EXPLL2RDY) != 1)
    {
    }

    // Switches clock from CLK_LCP1 to PLL clock
    EP.unEXPLLSEL.stcField  =   (stc_ep_expllsel_field_t){  .u1EXPLLSEL0 =   1,  // Expand_PLL Clock
                                                            .u1EXPLLSEL1 =   1,  // Expand_PLL Clock
                                                            .u1EXPLLSEL2 =   1}; // Expand_PLL Clock

}

/******************************************************************************
 ** \brief Configures internal memories
 **
 ** This function will set TCMRAM, System RAM and Backup RAM
 ** to 0 wait states as all these RAMs support maximum clock without
 ** wait states). Additionally, the appropriate ECC logic will be enabled
 ** disabled according to the settings in start.h.
 **
 ** \note Some registers written here are write-once registers. Ensure to
 **       call this function only one time during system start-up, otherwise
 **       an exception will be generated.
 **
 *****************************************************************************/
static void ConfigureMemories(void)
{
    //------------------------------------------------------------------
    //  TCFLASH
    //------------------------------------------------------------------
    
    // Unlock configuration registers for next write access
    TCFCFG0_FCPROTKEY = TCFLASH_KEY_UNLOCK;

    // Set wait states
    TCFCFG0_FCFGR_FAWC = TCFLASH_WAIT;

    // Unlock configuration registers for next write access
    TCFCFG0_FCPROTKEY = TCFLASH_KEY_UNLOCK;
    // Enable/disable ECC logic (write-once register)
    TCFCFG0_FECCCTRL_ECCOFF = (MCU_TCFLASH_ECC_ENABLE == MCU_ENABLE) ? 0 : 1;

    //------------------------------------------------------------------
    //  WorkFlash
    //------------------------------------------------------------------

    // Unlock configuration registers for next write access
    WFCFG_CPR = WFLASH_KEY_UNLOCK;
    // Set wait states
    WFCFG_CR_FAWC = WFLASH_WAIT;

    //------------------------------------------------------------------
    //  TCMRAM
    //------------------------------------------------------------------
    
    // Unlock configuration registers
    TRCFG0_TCMUNLOCK = TCMRAM_KEY_UNLOCK;
    while (TRCFG0_TCMCFG0_LOCKSTATUS == 1)
    {
    }
    
    // Set 0 wait states
    TRCFG0_TCMCFG0_DWAIT = 0;
    
    // Lock configuration registers
    TRCFG0_TCMUNLOCK = TCMRAM_KEY_LOCK;
    while (TRCFG0_TCMCFG0_LOCKSTATUS == 0)
    {
    }

    //------------------------------------------------------------------
    //  System RAM
    //------------------------------------------------------------------
    if (Start_stcClearEccMemories.u32SysRamSizeByte > 0) 
    {
        // Unlock configuration registers
        SRCFG_KEY = SYSRAM_KEY_UNLOCK;
        while (SRCFG_CFG0_LOCK_STATUS == 1)
        {
        }
    
        // Set 0 wait states
        SRCFG_CFG0_RDWAIT = 0;
        SRCFG_CFG0_WRWAIT = 0;
    
        // Enable/disable ECC logic (write-once register)
        SRCFG_ECCE_ECCEN = (MCU_SYSRAM_ECC_ENABLE == MCU_ENABLE) ? 1 : 0;
    
        // Lock configuration registers
        SRCFG_KEY = SYSRAM_KEY_LOCK;
        while (SRCFG_CFG0_LOCK_STATUS == 0)
        {
        }
    }
}

/******************************************************************************
 ** \brief Starts DMA operation(s) to clear all RAM areas that have ECC logic enabled
 **
 ** One ore more DMA channels are configured to clear all RAM areas to '0'
 ** to force initial calculation of ECC bits.
 **
 ** \note No interrupts are used
 **
 ** \post One or more DMA channels may be operating. Use ClearEccRamWaitCompletion()
 **       to wait for completion of all DMA operations.
 *****************************************************************************/
static void ClearEccRamStart(void)
{
    un_dma0_an_t    unDmaA0;
    un_dma0_bn_t    unDmaB0;
    un_dma0_cn_t    unDmaC0;
    un_dma0_dn_1_t  unDmaD0_Byte1;
    un_dma0_dn_3_t  unDmaD0_Byte3;
    uint32_t        u32ClearValueAddress;

    // Set source address (consecutive DMA_BLOCK_SIZE_BYTE x 0x0000000000000000)
    // DMA can access the TCM via only AXI interface, so it is necessary to convert the DMA source address.
    //if (Start_stcClearEccMemories.u32SysRamSizeByte == 0) 
    //{
    //    u32ClearValueAddress = (uint32_t)u64ClearValue;
    //}
    //else 
    if (Start_stcClearEccMemories.u32TcmRamSizeByte == 0)
    {
        u32ClearValueAddress = MCU_TCMRAM_ADDRESS_TCM2AXI(u64ClearValue);
    }
    else
    {
        // Flash code
        u32ClearValueAddress = MCU_FLASH_ADDRESS_TCM2CPUAXISLAVE(u64ClearValue);
    }

    // Generate common DMA settings
    unDmaA0.stcField        =   (stc_dma0_an_field_t){ .u2BL = 3,                         // Beat limit = INCR16
                                                       .u4BC = DMA_BLOCK_SIZE - 1,        // Block count
                                                       .u4TO = 0xf,                       // Timeout (reserved in this product, keep default)
                                                     };

    unDmaB0.stcField        =   (stc_dma0_bn_field_t){ .u2MS = 1,           // Burst transfer mode
                                                       .u4SP = 2 | 1,       // Source protection (keep default value) = priv. data access, not cacheable/bufferable
                                                       .u4DP = 2 | 1,       // Destination protection (keep default value) = priv. data access, not cacheable/bufferable
                                                       .u7PN = 0x7f,        // Priority (keep default value) = 127 
                                                     };
    unDmaC0.stcField        =   (stc_dma0_cn_field_t){  .u1CD = 1 };        // Clear DMA0_DMACB0_DQ flag
    unDmaD0_Byte1.stcField  =   (stc_dma0_dn_1_field_t){.u1FD = 0 };        // Increment destination address
                                                       
    unDmaD0_Byte3.stcField  =   (stc_dma0_dn_3_field_t){ .u1FS  = 0,        // increment source address (within one block)
                                                         .u1FBS = 1,        // source address for each block is fixed (SA)
                                                       };
    // // Globally enable DMA operations
    DMA0.unR.stcField       =   (stc_dma0_r_field_t){ .u1DE  = 1,           // Enable all DMA channels
                                                      .u2PR  = 0,           // Priority type (keep default value) = fixed
                                                    };

    if (Start_stcClearEccMemories.u32TcmRamSizeByte > 0) 
    {
        // Set memory specific transfer count and width
        unDmaA0.stcField.u16TC = ((Start_stcClearEccMemories.u32TcmRamSizeByte - ADDRESS_BOOT_USR_STACK_END) / (DMA_BLOCK_SIZE * (1 << TCMRAM_MAX_ACCESS_WIDTH))) - 1;
        unDmaB0.stcField.u2TW  = TCMRAM_MAX_ACCESS_WIDTH;
        // Set (fixed) source and destination addresses
        // - source:      Flash  (via AXI interface, no DMA access via TCM port)
        // - destination: TCMRAM (via AXI bus slave interface, no DMA access via TCM port)
        DMA0_SA0 = u32ClearValueAddress;
        DMA0_DA0 = Start_stcClearEccMemories.u32TcmRamStartAddress + ADDRESS_BOOT_USR_STACK_END;
        // Configure DMA channel 0
        DMA0_A0     = unDmaA0.u32Register;
        DMA0_B0     = unDmaB0.u32Register;
        DMA0_C0     = unDmaC0.u32Register;
        DMA0_D0_1   = unDmaD0_Byte1.u8Register;
        DMA0_D0_3   = unDmaD0_Byte3.u8Register;
        // Enable DMA channel 0
        DMA0_A0_EB  = 1;
        // Start DMA channel 0 (Software trigger)
        DMA0_A0_ST  = 1;
    }

    //if (Start_stcClearEccMemories.u32SysRamSizeByte > 0) 
    //{
    //    // Set memory specific transfer count and width
    //    unDmaA0.stcField.u16TC = (Start_stcClearEccMemories.u32SysRamSizeByte / (DMA_BLOCK_SIZE * (1 << SYSRAM_MAX_ACCESS_WIDTH))) - 1;
    //    unDmaB0.stcField.u2TW  = SYSRAM_MAX_ACCESS_WIDTH;
    //    // Set (fixed) source and destination addresses
    //    // - source:      Flash  (via AXI interface, no DMA access via TCM port)
    //    // - destination: System RAM
    //    DMA0_SA1 = u32ClearValueAddress;
    //    DMA0_DA1 = Start_stcClearEccMemories.u32SysRamStartAddress;
    //    // Configure DMA channel 1
    //    DMA0_A1     = unDmaA0.u32Register;
    //    DMA0_B1     = unDmaB0.u32Register;
    //    DMA0_C1     = unDmaC0.u32Register;
    //    DMA0_D1_1   = unDmaD0_Byte1.u8Register;
    //    DMA0_D1_3   = unDmaD0_Byte3.u8Register;
    //    // Enable DMA channel 1
    //    DMA0_A1_EB  = 1;
    //    // Start DMA channel 1 (Software trigger)
    //    DMA0_A1_ST  = 1;
    //}
}

/******************************************************************************
 ** \brief Waits until all DMA operations for clearing the ECC RAM areas are completed.
 **
 ** \pre ClearEccRamStart() must be called otherwise this function will never return.
 **
 ** \post All DMA operations are completed, DMA channels 0...3 are disabled,
 **       DMA registers for channel 0...3 may be different from reset state
 *****************************************************************************/
static void ClearEccRamWaitCompletion(void)
{
    if (Start_stcClearEccMemories.u32TcmRamSizeByte > 0) 
    {
        // Check DMA channel 0 completion status
        while (DMA0_B0_DQ == 0)
        {
            /* wait for completion */
        }
        // Disable channel 0
        DMA0_A0_EB = 0;
        // Clear DQ flag
        DMA0_C0_CD = 1;
    }

    //if (Start_stcClearEccMemories.u32SysRamSizeByte > 0) 
    //{
    //    // Check DMA channel 1 completion status
    //    while (DMA0_B1_DQ == 0)
    //    {
    //        /* wait for completion */
    //    }
    //    // Disable channel 1
    //    DMA0_A1_EB = 0;
    //    // Clear DQ flag
    //    DMA0_C1_CD = 1;
    //}

    // Globally disable DMA operations
    DMA0_R = 0;
}


/******************************************************************************
 ** \brief Enable Cache ECC
 **
 ** \note
 **
 ** \post
 **
 *****************************************************************************/
static void EnableCacheECC(void)
{
    uint32_t u32CtrlReg ;

    // The I-cache and the D-cache are disabled yet,
    // so disabling the caches and cleaning the D-cache are omitted.
    // Disable the caches and clean entire D-cache If the caches are already enabled.

    // Procedure according to ARM DDI 0460D chapter 8.5.5

    // To avoid ARM CR-5 erratum, Set ACTLR.DBWR((bit [14]) to 1.)
    // This workaround reduces the performance of the processor.
    // For more information, see
    //  Cortex-R5 and Cortex-R5F Software Developers Errata Notice
    //  780125: Processor might deadlock or lose data when configured with cache-ECC

    // Read Auxiliary Control Register
    u32CtrlReg = MRC(15, 0, 1, 0, 1);    // get C1 Auxiliary Control Register  ;
    // Set CEC bit and DBWR bit setting
    u32CtrlReg = (u32CtrlReg & 0xFFFFFFC7) | (CACHE_CEC_SETTING << 3) | (CACHE_DBWR_SETTING << 14);
    // Write Auxiliary Control Register
    MCR(15, 0, u32CtrlReg, 1, 0, 1);    // set C1 Auxiliary Control Register ;
}

/******************************************************************************
 ** \brief Enable L1 Instruction Cache
 **
 ** \note
 **
 ** \post
 **
 *****************************************************************************/
static void EnableInstructionCache(void)
{
    uint32_t u32CtrlReg ;

    // Procedure according to ARM DDI 0460D chapter 8.5.5

    // Read System Control Register configuration data
    u32CtrlReg = MRC(15, 0, 1, 0, 0);       // get CP15 System Control Register ;
    // Set data cache enable bit (I-bit)
    u32CtrlReg |= (1 << 12);                // ORR R1, R1, #0x1  <<12 ;
    // Invalidate entire instruction cache
    MCR( 15, 0, 0, 7, 5, 0 );               // MCR p15, 0, r0, c7, c5, 0 ;
    // Enable entire instruction cache
    MCR(15, 0, u32CtrlReg, 1, 0, 0);        // set CP15 System Control Register ;
    // Flush processor pipeline
    ISB();                                  // ISB ;
} // EnableInstructionCache(void)

/******************************************************************************
 ** \brief Enable L1 Data Cache
 **
 ** \note
 **
 ** \post
 **
 *****************************************************************************/
static void EnableDataCache(void)
{
    uint32_t u32CtrlReg ;

    // Procedure according to ARM DDI 0460D chapter 8.5.5

    // Read System Control Register configuration data
    u32CtrlReg = MRC(15, 0, 1, 0, 0);       // get CP15 System Control Register  ;
    // Set data cache enable bit
    u32CtrlReg |= (1 << 2);                 // ORR R1, R1, #0x1 <<2 ;
    // Ensure completion of memory accesses
    DSB();                                  // DSB ;
    // Invalidate entire data cache
    MCR( 15, 0, 0, 15, 5, 0 );              // MCR p15, 0, r0, c15, c5, 0 ;
    // Enable data cache
    MCR(15, 0, u32CtrlReg, 1, 0, 0);        // set CP15 System Control Register ;
} // EnableDataCache(void)

/******************************************************************************
 ** \brief L1 Data cache and instruction cache configuration
 **
 ** \note
 **
 ** \post
 **
 *****************************************************************************/
static void ConfigureCaches(void)
{
    if (MCU_CACHE_ECC_ENABLE == MCU_ENABLE)
    {
        EnableCacheECC();
    }
    if (MCU_I_CACHE_ENABLE == MCU_ENABLE)
    {
        EnableInstructionCache();
    }
    if (MCU_D_CACHE_ENABLE == MCU_ENABLE)
    {
        EnableDataCache();
    }

} // ConfigureCaches(void)

/**
 *****************************************************************************
 ** \brief Setup MPU configuration.
 **
 ** \pre Must be in privileged mode.
 **
 ** \param [in]  pstcConfig         MPU configuration parameters.
 **                                 See #stc_mpu_region_settings_t
 *****************************************************************************/
void SetMpuConfig(const stc_mpu_region_settings_t* pstcConfig)
{
    un_mpu_control_t        unMpuControl;
    un_mpu_type_t           unMpuType;
    un_mpu_regionsize_t     unMpuRegionsize;
    un_mpu_regionaccess_t   unMpuAccess;
    uint32_t                i;

    /* Get number of the undefined MPU regions */
    unMpuType.u32Register = MRC(15, 0, 0, 0, 4);
    for (i = 0; i < unMpuType.stcField.u8DRegion; i++)
    {
        if (pstcConfig[i].bEnable == TRUE)
        {
            /* Select MPU region number for configuration */
            MCR(15, 0, i, 6, 2, 0);

            /* Set region base address */
            MCR(15, 0, pstcConfig[i].u32StartAddress, 6, 1, 0);

            /* Set region size and enable */
            unMpuRegionsize.u32Register = MRC(15, 0, 6, 1, 2);
            unMpuRegionsize.stcField.u5RegionSize = pstcConfig[i].enRegionSize;
            unMpuRegionsize.stcField.u1Enable = 1;
            /* Setting of sub region disable bits */
            /* All Sub Regions are enabled */
            unMpuRegionsize.stcField.u8SubRegionDisable = 0;
            MCR(15, 0, unMpuRegionsize.u32Register, 6, 1, 2);

            /* Set region access control */
            unMpuAccess.u32Register = MRC(15, 0, 6, 1, 4);
            unMpuAccess.stcField.u3AP  = 3;
            unMpuAccess.stcField.u1B   = pstcConfig[i].enMainMemAttribute & 0x1;
            unMpuAccess.stcField.u1C   = (pstcConfig[i].enMainMemAttribute & 0x2) >> 1;
            unMpuAccess.stcField.u3TEX = (pstcConfig[i].enMainMemAttribute & 0x1c) >> 2;
            unMpuAccess.stcField.u1S   = pstcConfig[i].enShareAttribute;
            unMpuAccess.stcField.u1XN  = pstcConfig[i].enExecNever;
            MCR(15, 0, unMpuAccess.u32Register, 6, 1, 4);
        }
        else
        {
            /* Select MPU region number for configuration */
            MCR(15, 0, i, 6, 2, 0);
            /* Set region disable */
            unMpuRegionsize.u32Register = MRC(15, 0, 6, 1, 2);
            unMpuRegionsize.stcField.u1Enable = 0;
            MCR(15, 0, unMpuRegionsize.u32Register, 6, 1, 2);
        }
    }

    /* Enable MPU */
    unMpuControl.u32Register = MRC(15, 0, 1, 0, 0); /* Read CP15 register 1 */
    DSB();                                          /* Ensure the completion of memory accesses, */
    unMpuControl.stcField.u1M = 1;                  /* Enable MPU */
    unMpuControl.stcField.u1BR = 1;                 /* Enable Background region */
    MCR(15, 0, unMpuControl.u32Register, 1, 0, 0);  /* Copy settings back to CP15 */
    ISB();                                          /* Instruction Synchronization Barrier. */

    return;
}

#endif /* __FILE_VERSION_CHECK__ */

