/**************************************************************************//**
  * \file     CPU.c
  * \brief    Processers driver file
  * \details
  * \author   Zhang Xuan
  * \version  V1.0.0
  * \date     30-Aug-2018
  * \par      History:
  *           V1.0.0 Initial release
  * \par      Copyright:
  *           (c) Heilongjiang TYW Electronics co., LTD
******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "cpu.h"

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

/*** MPU control ***/

/** Bits and Bit fields in c1, Coprocessor System Control Registers */
typedef struct stc_mpu_control_field
{
  /** 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;
  /** 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;
  /** 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;
  /** 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;
  /** 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;
  /** 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;
  /** 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;
  /** 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;
  /**  MPU background region enable
   **/
  uint_io32_t u1BR :0x01;
  /** reserved (SBO)*/
  uint_io32_t :0x01;
  /** 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;
  /**  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;
  /**  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;
  /**  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;
  /**  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;
  /** TEX Remap Enable
   ** TEX Remap Enable
   ** On the processor this bit is SBZ.
   **/
  uint_io32_t u1TRE :0x01;
  /** Access Flag Enable.
   ** Access Flag Enable.
   ** On the processor this bit is SBZ.
   **/
  uint_io32_t u1AFE :0x01;
  /** 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;
  /** 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;

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

/*** MPU region size ***/

/** Bits and Bit fields in Coprocessor MPU Region Size and Enable Registers */
typedef struct stc_mpu_regionsize_field
{
  /** 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;
  /** 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;
  /** 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;

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

/*** MPU region access ***/

/** Bits and Bit fields in Coprocessor MPU Region Access Control Register */
typedef struct stc_mpu_regionaccess_field
{
  /** B bit
   ** For more information on this region attribute,
   ** see Table 4-36 in Cortex r5 manual
   **/
  uint_io32_t u1B :0x01;
  /** C bit
   ** For more information on this region attribute,
   ** see Table 4-36 in Cortex r5 manual
   **/
  uint_io32_t u1C :0x01;
  /** 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;
  /** 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;
  /** 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;
  /** 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;

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

/*** MPU type ***/

/** Bits and Bit fields in Coprocessor MPU Type Register */
typedef struct stc_mpu_type_field
{
  /** 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;
  /** 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;

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

/*** MPU region settings ***/

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

/** 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       = 0U,  /*!< Strongly Ordered memory */
  MpuRegionMainAttribDeviceShareable       = 1U,  /*!< Shareable Device memory */
  MpuRegionMainAttribNormalWtNoWa          = 2U,  /*!< Normal memory, with outer & inner write-through, no write-allocate cache policy */
  MpuRegionMainAttribNormalWbNoWa          = 3U,  /*!< Normal memory, with outer & inner write-back, no write-allocate cache policy */
  MpuRegionMainAttribNormalNonCacheable    = 4U,  /*!< Normal memory, non-cacheable */
  MpuRegionMainAttribNormalWtWa            = 7U,  /*!< Normal memory, with outer & inner write-back, write-allocate cache policy */
  MpuRegionMainAttribDeviceNonShareable    = 8U,  /*!< Non-shareable Device memory */
  MpuRegionMainAttribNormalDiffCachePolicy = 16U, /*!< Normal memory, that can have different outer & inner cache policies */
}en_mpu_region_main_attrib_t;

/** 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 = 0U,  /*!< Memory region is non-shareable */
  MpuRegionShareAttribShareable    = 1U,  /*!< Memory region is shareable */
}en_mpu_region_share_attrib_t;

/** 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  = 0U,  /*!< all instruction fetches enabled */
  MpuRegionExecDisable = 1U   /*!< no instruction fetches enabled. */
}en_mpu_region_exec_never_t;

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

/* Private define ------------------------------------------------------------*/
/** Macros for ECC configuration of the I-cache and the D-cache */
#define	  CPU_CACHE_CEC_SETTING             0x2U   /* enable ECC, force write through, enable ABORT generation */
#define   CPU_CACHE_DBWR_SETTING            0x1U   /* ACTLR.DBWR = 1 */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

/*** MPU region settings ***/

static const stc_mpu_region_settings_t CPUMPURegionSettings[16] = 
{
    /* Each region settings */
    /* Region 0             */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x00000000UL,                      /* 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 */
        0x00800000UL,                      /* 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 */
        0x01000000UL,                      /* 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 */
        0x02000000UL,                      /* 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 */
        0x02800000UL,                      /* 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 */
        0x04000000UL,                      /* 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 */
        0x0E000000UL,                      /* Region base address           */
        MpuRegionSize1MB,                  /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribDeviceNonShareable,  /* None shareable divice */
        MpuRegionShareAttribNonShareable,       /* None Shareable        */
    },
    /* Region 7 */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x0E200000UL,                      /* Region base address           */
        MpuRegionSize1MB,                  /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribDeviceNonShareable,  /* None shareable divice */
        MpuRegionShareAttribNonShareable,       /* None Shareable        */
    },
    /* Region 8 */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x0E300000UL,                      /* 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 */
        0x0E800000UL,                      /* Region base address           */
        MpuRegionSize64kB,                 /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribDeviceNonShareable,  /* None shareable divice */
        MpuRegionShareAttribNonShareable,       /* None Shareable        */
    },
    /* Region 10 */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x50000000UL,                      /* 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 */
        0x50200000UL,                      /* Region base address           */
        MpuRegionSize2MB,                  /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribStronglyOrdered,  /* Strongly-ordered */
        MpuRegionShareAttribShareable,       /* Shareable        */
    },
    /* Region 12 */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x50400000UL,                      /* Region base address           */
        MpuRegionSize2MB,                  /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribStronglyOrdered,  /* Strongly-ordered */
        MpuRegionShareAttribShareable,       /* Shareable        */
    },
    /* Region 13 */
    {
        TRUE,                              /* Enable Region                 */
        MpuRegionExecEnable,               /* Instrunction fetch is enabled */
        0x90000000UL,                      /* Region base address           */
        MpuRegionSize256MB,                /* Region size                   */
        /* Memory region attributes */
        MpuRegionMainAttribStronglyOrdered,  /* Strongly-ordered */
        MpuRegionShareAttribShareable,       /* Shareable        */
    },
    /* Region 14 */
    {
        TRUE,                              /* Enable Region                  */
        MpuRegionExecDisable,              /* Instrunction fetch is disabled */
        0xB0000000UL,                      /* Region base address            */
        MpuRegionSize256MB,                /* Region size                    */
        /* Memory region attributes */
        MpuRegionMainAttribDeviceShareable,  /* Shareable device */
        MpuRegionShareAttribNonShareable,    /* None Shareable   */
    },
    /* Region 15 */
    {
        FALSE,                             /* Disable Region                 */
        MpuRegionExecEnable,
        0x00000000UL,
        MpuRegionSize32Byte,
        /* Memory region attributes */
        MpuRegionMainAttribStronglyOrdered,
        MpuRegionShareAttribNonShareable,
    }
};

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/**************************************************************************//**
  * \brief      Configures MPU
  * \retval     None
******************************************************************************/  
void CPU_Config_MPU(void)
{
  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(15U, 0U, 0U, 0U, 4U);
  for (i = 0U; i < unMpuType.stcField.u8DRegion; i++)
  {
    if (CPUMPURegionSettings[i].bEnable == TRUE)
    {
      /* Select MPU region number for configuration */
      MCR(15U, 0U, i, 6U, 2U, 0U);

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

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

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

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

/**************************************************************************//**
  * \brief      Configures caches
  * \retval     None
******************************************************************************/  
void CPU_Config_Caches(void)
{
  uint32_t u32CtrlReg ;
      
  /*----------------------------------------------------------------------------
   Enable Cache ECC

   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(15U, 0U, 1U, 0U, 1U);    /* get C1 Auxiliary Control Register */
  /* Set CEC bit and DBWR bit setting */
  u32CtrlReg = (u32CtrlReg & 0xFFFFFFC7UL) | (CPU_CACHE_CEC_SETTING << 3) | (CPU_CACHE_DBWR_SETTING << 14);
  /* Write Auxiliary Control Register */
  MCR(15U, 0U, u32CtrlReg, 1U, 0U, 1U);    /* set C1 Auxiliary Control Register */
  
  /*** Enable L1 Instruction Cache***/

  /* Procedure according to ARM DDI 0460D chapter 8.5.5 */

  /* Read System Control Register configuration data */
  u32CtrlReg = MRC(15U, 0U, 1U, 0U, 0U);       /* get CP15 System Control Register */
  /* Set data cache enable bit (I-bit) */
  u32CtrlReg |= (1U << 12);                    /* ORR R1, R1, #0x1  <<12 */
  /* Invalidate entire instruction cache */
  MCR( 15U, 0U, 0U, 7U, 5U, 0U );              /* MCR p15, 0, r0, c7, c5, 0 */
  /* Enable entire instruction cache */
  MCR(15U, 0U, u32CtrlReg, 1U, 0U, 0U);        /* set CP15 System Control Register */
  /* Flush processor pipeline */
  ISB();                                       /* ISB */
  
  /*** Enable L1 Data Cache ***/
  
  /* Procedure according to ARM DDI 0460D chapter 8.5.5 */

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

/**
 *****************************************************************************
 ** \addtogroup CpuGroup CPU Mode Functions
 *****************************************************************************/
/* @{ */

/**
 *****************************************************************************
 ** \brief  Check if CPU is in privileged mode
 **
 ** \retval TRUE if CPU is any mode other than the user mode
 **         FALSE if CPU is in user mode
 *****************************************************************************/
boolean_t Cpu_CpuIsInPrivilegedMode(void)
{
    return (Cpu_GetSystemMode() != (uint32_t)CpuUserMode) ? TRUE : FALSE ;
} /* Cpu_CpuIsInPrivilegedMode */


/**
 *****************************************************************************
 ** \brief    Function to read the current system mode.
 **
 ** This needs to be done in assembler since the compiler intrinsic functions
 ** to read CPSR are only allowed in privileged mode. This routine also runs in
 ** user mode.
 *****************************************************************************/
uint32_t Cpu_GetSystemMode(void)
{
    uint32_t u32Cpsr;
    
    u32Cpsr = GET_CPSR();
    return (u32Cpsr & 0x0000001FUL);
} /* Cpu_GetSystemMode */


/**
 *****************************************************************************
 ** \brief  Invalidates the cache content of certain memory area
 **
 ** If the content of a cached RAM area has been changed by a different master
 ** than the CPU, this function can be used to invalidate the cache content of
 ** this area, so that the CPU can work with the updated data.
 ** Alternatively, this memory area could be assigned a non-cacheable attribute
 ** by using the Cortex-R5 MPU
 **
 ** \note This function expects arguments based on the cache line granularity
 **       (1 cache line is 32 bytes), so that user does not invalidate other
 **       areas by accident
 **
 ** \retval Ok                    Invalidation was successful
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **                               - u32StartAddress is not 32-byte aligned
 **                               - u32ByteSize is not an integer multiple
 **                                 of 32 (bytes)
 *****************************************************************************/
en_result_t Cpu_InvalidateDCacheArea(uint32_t u32StartAddress, uint32_t u32ByteSize)
{
  const uint32_t u32EndAddress = u32StartAddress + u32ByteSize - 1U;
  en_result_t enResult;
    
  /* Check start address alignment to avoid invalidating of unwanted areas (cache lines are 32-byte aligned) */
  if((u32StartAddress & 0x1FU) != 0U)
  {
    enResult = ErrorInvalidParameter;
  }
  else
  {
    /* Check that size is a multiple of the cache line size to avoid invalidating of unwanted areas */
    if((u32ByteSize % 32U) != 0U)
    {
      enResult = ErrorInvalidParameter;
    }
    else
    {
      for( ; u32StartAddress < u32EndAddress; u32StartAddress += 32U)
      {
        /* Invalidate data cache line by MVA to PoC (refer ARM Cortex-R5 TRM) */
        MCR(15U, 0U, u32StartAddress, 7U, 6U, 1U);    
      }

      enResult = Ok;
    }
  }
  
  return enResult;
} /* Cpu_InvalidateDCacheArea */


/*! @} */


/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
