diff --git a/arch/arm/aarch64/include/arch_helpers.h b/arch/arm/aarch64/include/arch_helpers.h index 3803ab557b0f1a47d9c0d92b350cfcc2ab97d30c..ec8b3cd02148b1f1edf2123aff5ef6645210dfc4 100644 --- a/arch/arm/aarch64/include/arch_helpers.h +++ b/arch/arm/aarch64/include/arch_helpers.h @@ -10,6 +10,8 @@ #include +#include + /*! * \brief Enables global CPU interrupts. * @@ -18,7 +20,7 @@ */ inline static void arch_interrupts_enable(unsigned int not_used) { - /* TODO when GIC support is implemented */ + __asm__ volatile("msr DAIFClr, %0" ::"i"(DAIF_FIQ) : "memory"); } /*! @@ -29,8 +31,9 @@ inline static void arch_interrupts_enable(unsigned int not_used) */ inline static unsigned int arch_interrupts_disable() { - /* TODO when GIC support is implemented */ - return FWK_E_SUPPORT; + __asm__ volatile("msr DAIFSet, %0" ::"i"(DAIF_FIQ) : "memory"); + + return 0; } /*! diff --git a/arch/arm/aarch64/include/arch_reg.h b/arch/arm/aarch64/include/arch_reg.h index aec8cbcdade6c9d32494d8de00197cd6ea9913d0..c35c9eec39492828d0be2c7db9091ad09b6be6a5 100644 --- a/arch/arm/aarch64/include/arch_reg.h +++ b/arch/arm/aarch64/include/arch_reg.h @@ -29,10 +29,12 @@ #define BARRIER_ISYNC_FENCE_FULL() ({ __asm__ volatile("isb" ::: "memory"); }) -#define mpuir_el2 S3_4_c0_c0_4 -#define prselr_el2 S3_4_c6_c2_1 -#define prbar_el2 S3_4_c6_c8_0 -#define prlar_el2 S3_4_c6_c8_1 +#define icc_iar_el1 S3_0_c12_c8_0 +#define icc_eoir0_el1 S3_0_c12_c8_1 +#define mpuir_el2 S3_4_c0_c0_4 +#define prselr_el2 S3_4_c6_c2_1 +#define prbar_el2 S3_4_c6_c8_0 +#define prlar_el2 S3_4_c6_c8_1 /* * PRBAR values @@ -86,7 +88,10 @@ * HCR_EL2 values */ #define HCR_EL2_SWIO FWK_BIT(1) -#define HCR_EL2_RESET HCR_EL2_SWIO +#define HCR_EL2_FMO FWK_BIT(3) +#define HCR_EL2_IMO FWK_BIT(4) +#define HCR_EL2_AMO FWK_BIT(5) +#define HCR_EL2_RESET (HCR_EL2_SWIO | HCR_EL2_FMO | HCR_EL2_IMO | HCR_EL2_AMO) /* * ID_AA64MMFR0_EL1 values @@ -94,4 +99,24 @@ #define ID_AA64MMFR0_EL1_MSA_MASK FWK_GEN_MASK_64(51, 48) #define ID_AA64MMFR0_EL1_MSA_FRAC_MASK FWK_GEN_MASK_64(55, 52) +/* + * DAIF bits + */ +#define DAIF_FIQ FWK_BIT(0) + +/* + * GIC registers + */ +#define GICR_SGI_BASE 0x10000u + +#define GICR_ISENABLER0 0x0100u +#define GICR_ICENABLER0 0x0180u +#define GICR_ISPENDR0 0x0200u +#define GICR_ICPENDR0 0x0280u + +#define GICD_ISENABLER(N) (0x0100u + (4 * (N))) +#define GICD_ICENABLER(N) (0x0180u + (4 * (N))) +#define GICD_ISPENDR(N) (0x0200u + (4 * (N))) +#define GICD_ICPENDR(N) (0x0280u + (4 * (N))) + #endif /* ARCH_REG_H */ diff --git a/arch/arm/aarch64/src/arch_exceptions.S b/arch/arm/aarch64/src/arch_exceptions.S index 14796f5bbde80370761f7e099d5c9ee9f6c90942..01c8ff30a77a11d716b8f2793fdc5f0392c7f5ed 100644 --- a/arch/arm/aarch64/src/arch_exceptions.S +++ b/arch/arm/aarch64/src/arch_exceptions.S @@ -7,17 +7,78 @@ .macro ventry label .align 7 -b \label +b \label .endm +.align 11 .global exception_vectors exception_vectors: /* current EL, SP_EL0 */ - ventry err_exception /* synchronous */ - ventry err_exception /* IRQ */ - ventry err_exception /* FIQ */ - ventry err_exception /* SError */ + ventry err_exception /* synchronous */ + ventry err_exception /* IRQ */ + ventry err_exception /* FIQ */ + ventry err_exception /* SError */ + + /* current EL, SP_ELX */ + ventry err_exception /* synchronous */ + ventry err_exception /* IRQ */ + ventry fiq_handler /* FIQ */ + ventry err_exception /* SError */ + + /* lower EL using AArch64 */ + ventry err_exception /* synchronous */ + ventry err_exception /* IRQ */ + ventry err_exception /* FIQ */ + ventry err_exception /* SError */ + + /* lower EL using AArch32 */ + ventry err_exception /* synchronous */ + ventry err_exception /* IRQ */ + ventry err_exception /* FIQ */ + ventry err_exception /* SError */ err_exception: wfe b err_exception + +fiq_handler: + /* Save registers onto stack */ + str x30, [sp, #-16]! + stp x28, x29, [sp, #-16]! + stp x26, x27, [sp, #-16]! + stp x24, x25, [sp, #-16]! + stp x22, x23, [sp, #-16]! + stp x20, x21, [sp, #-16]! + stp x18, x19, [sp, #-16]! + stp x16, x17, [sp, #-16]! + stp x14, x15, [sp, #-16]! + stp x12, x13, [sp, #-16]! + stp x10, x11, [sp, #-16]! + stp x8, x9, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x0, x1, [sp, #-16]! + +.extern irq_global + bl irq_global + + /* Restore registers from stack */ + ldp x0, x1, [sp], #16 + ldp x2, x3, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x8, x9, [sp], #16 + ldp x10, x11, [sp], #16 + ldp x12, x13, [sp], #16 + ldp x14, x15, [sp], #16 + ldp x16, x17, [sp], #16 + ldp x18, x19, [sp], #16 + ldp x20, x21, [sp], #16 + ldp x22, x23, [sp], #16 + ldp x24, x25, [sp], #16 + ldp x26, x27, [sp], #16 + ldp x28, x29, [sp], #16 + ldr x30, [sp], #16 + + eret diff --git a/arch/arm/aarch64/src/arch_gic.c b/arch/arm/aarch64/src/arch_gic.c index 3f94ebedf5caf788ac6a34db3ce3c5d4f212ffa0..0217e20453ab51c8bcf057f9d0694b17b08a2295 100644 --- a/arch/arm/aarch64/src/arch_gic.c +++ b/arch/arm/aarch64/src/arch_gic.c @@ -6,51 +6,236 @@ */ #include +#include #include +#include + +#include +#include + +#include + +#define INTERRUPT_ID_SGI_LIMIT 16 +#define INTERRUPT_ID_PPI_LIMIT 32 +#define INTERRUPT_ID_SPI_LIMIT 1020 +#define INTERRUPT_ID_ISR_LIMIT INTERRUPT_ID_SPI_LIMIT +#define INTERRUPT_ID_INVALID 1024 + +enum interrupt_type { + INTERRUPT_TYPE_SGI, + INTERRUPT_TYPE_PPI, + INTERRUPT_TYPE_SPI, + INTERRUPT_TYPE_OTHER, +}; + +static enum interrupt_type interrupt_type_from_id(unsigned int interrupt) +{ + if (interrupt < INTERRUPT_ID_SGI_LIMIT) { + return INTERRUPT_TYPE_SGI; + } else if (interrupt < INTERRUPT_ID_PPI_LIMIT) { + return INTERRUPT_TYPE_PPI; + } else if (interrupt < INTERRUPT_ID_SPI_LIMIT) { + return INTERRUPT_TYPE_SPI; + } else { + return INTERRUPT_TYPE_OTHER; + } +} + +struct isr_callback { + union { + void (*func)(); + void (*func_with_param)(uintptr_t); + }; + uintptr_t param; +}; + +static unsigned int current_iar = INTERRUPT_ID_INVALID; +static struct isr_callback callback[INTERRUPT_ID_ISR_LIMIT] = { 0 }; + +static uint64_t read_icc_iar0_el1(void) +{ + return READ_SYSREG(icc_iar_el1); +} + +static void write_icc_eoir0_el1(uint64_t value) +{ + return WRITE_SYSREG(icc_eoir0_el1, value); +} + +void irq_global(void) +{ + struct isr_callback *entry; + + current_iar = read_icc_iar0_el1(); + if (current_iar >= INTERRUPT_ID_ISR_LIMIT) { + return; + } + + entry = &callback[current_iar]; + + if (entry->func != NULL) { + if (entry->param == 0) { + entry->func(); + } else { + entry->func_with_param(entry->param); + } + } + + write_icc_eoir0_el1(current_iar); + current_iar = INTERRUPT_ID_INVALID; +} static int global_enable(void) { - return FWK_E_SUPPORT; + arch_interrupts_enable(0); + + return FWK_SUCCESS; } static int global_disable(void) { - return FWK_E_SUPPORT; + arch_interrupts_disable(); + + return FWK_SUCCESS; } static int is_enabled(unsigned int interrupt, bool *enabled) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + *enabled = + (fwk_mmio_read_32(FMW_GICR_BASE + GICR_SGI_BASE + GICR_ISENABLER0) & + FWK_BIT(interrupt)) != 0; + break; + case INTERRUPT_TYPE_SPI: + *enabled = + (fwk_mmio_read_32(FMW_GICD_BASE + GICD_ISENABLER(interrupt / 32)) & + FWK_BIT(interrupt % 32)) != 0; + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int enable(unsigned int interrupt) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + fwk_mmio_write_32( + FMW_GICR_BASE + GICR_SGI_BASE + GICR_ISENABLER0, + FWK_BIT(interrupt)); + break; + case INTERRUPT_TYPE_SPI: + fwk_mmio_write_32( + FMW_GICD_BASE + GICD_ISENABLER(interrupt / 32), + FWK_BIT(interrupt % 32)); + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int disable(unsigned int interrupt) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + fwk_mmio_write_32( + FMW_GICR_BASE + GICR_SGI_BASE + GICR_ICENABLER0, + FWK_BIT(interrupt)); + break; + case INTERRUPT_TYPE_SPI: + fwk_mmio_write_32( + FMW_GICD_BASE + GICD_ICENABLER(interrupt / 32), + FWK_BIT(interrupt % 32)); + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int is_pending(unsigned int interrupt, bool *pending) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + fwk_mmio_write_32( + FMW_GICR_BASE + GICR_SGI_BASE + GICR_ICENABLER0, + FWK_BIT(interrupt)); + break; + case INTERRUPT_TYPE_SPI: + fwk_mmio_write_32( + FMW_GICD_BASE + GICD_ICENABLER(interrupt / 32), + FWK_BIT(interrupt % 32)); + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int set_pending(unsigned int interrupt) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + fwk_mmio_write_32( + FMW_GICR_BASE + GICR_SGI_BASE + GICR_ISPENDR0, FWK_BIT(interrupt)); + break; + case INTERRUPT_TYPE_SPI: + fwk_mmio_write_32( + FMW_GICD_BASE + GICD_ISPENDR(interrupt / 32), + FWK_BIT(interrupt % 32)); + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int clear_pending(unsigned int interrupt) { - return FWK_E_SUPPORT; + switch (interrupt_type_from_id(interrupt)) { + case INTERRUPT_TYPE_SGI: + case INTERRUPT_TYPE_PPI: + fwk_mmio_write_32( + FMW_GICR_BASE + GICR_SGI_BASE + GICR_ICPENDR0, FWK_BIT(interrupt)); + break; + case INTERRUPT_TYPE_SPI: + fwk_mmio_write_32( + FMW_GICD_BASE + GICD_ICPENDR(interrupt / 32), + FWK_BIT(interrupt % 32)); + break; + case INTERRUPT_TYPE_OTHER: + return FWK_E_SUPPORT; + } + + return FWK_SUCCESS; } static int set_isr_irq(unsigned int interrupt, void (*isr)(void)) { - return FWK_E_SUPPORT; + struct isr_callback *entry; + + if (interrupt >= INTERRUPT_ID_ISR_LIMIT || isr == NULL) { + return FWK_E_PARAM; + } + + entry = &callback[interrupt]; + entry->func = isr; + entry->param = 0; + + return FWK_SUCCESS; } static int set_isr_irq_param( @@ -58,7 +243,17 @@ static int set_isr_irq_param( void (*isr)(uintptr_t param), uintptr_t parameter) { - return FWK_E_SUPPORT; + struct isr_callback *entry; + + if (interrupt >= INTERRUPT_ID_ISR_LIMIT || isr == NULL || parameter == 0) { + return FWK_E_PARAM; + } + + entry = &callback[interrupt]; + entry->func_with_param = isr; + entry->param = parameter; + + return FWK_SUCCESS; } static int set_isr_dummy(void (*isr)(void)) @@ -75,12 +270,18 @@ static int set_isr_dummy_param( static int get_current(unsigned int *interrupt) { - return FWK_E_SUPPORT; + if (interrupt == NULL) { + return FWK_E_PARAM; + } + + *interrupt = current_iar; + + return FWK_SUCCESS; } static bool is_interrupt_context(void) { - return false; + return current_iar != INTERRUPT_ID_INVALID; } const struct fwk_arch_interrupt_driver arm_gic_driver = { @@ -103,6 +304,10 @@ const struct fwk_arch_interrupt_driver arm_gic_driver = { int arch_gic_init(const struct fwk_arch_interrupt_driver **driver) { + if (driver == NULL) { + return FWK_E_PARAM; + } + *driver = &arm_gic_driver; return FWK_SUCCESS; diff --git a/doc/aarch64.md b/doc/aarch64.md index 8d8f334b578605090d2b2a4d62b978cd2ed64523..94deec64a6996794881f19c1541170f39139b578 100644 --- a/doc/aarch64.md +++ b/doc/aarch64.md @@ -17,6 +17,20 @@ attempts are made to initialize the EL1/0 environment. Both GCC and Clang are supported, but not Arm Clang. +## Interrupt handling + +A minimal interrupt controller is provided with the following limitations: + + * All interrupts have the same priority. + * NMIs (non-maskable interrupts) are not supported. + * The extended SPI and PPI ranges are not supported. + +AArch64 products must provide a `fmw_gic.h` header which defines: + + * `GICD_BASE` - the base address of the GIC distributor + * `GICR_BASE` - the base address of the GIC redstributor corresponding to the + core on which SCP-firmware is running + ## Usage To use the AArch64 architecture in a product, including the following in diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index f05d41c3ce9e811b06d4d465744af9280466b10b..af1d4ad5f7a38f9c19b8f3631cbe038bb8d07c25 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -38,6 +38,7 @@ list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dmc620") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dvfs") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dw_apb_i2c") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/atu_mmio") +list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/gicx00") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/gtimer") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/i2c") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/isys_rom") diff --git a/module/gicx00/CMakeLists.txt b/module/gicx00/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3c180fff7456517b85af0e29ba8faafea8d0f9a --- /dev/null +++ b/module/gicx00/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_sources(${SCP_MODULE_TARGET} + PRIVATE "src/mod_gicx00.c" + "src/gicx00_reg.c") diff --git a/module/gicx00/Module.cmake b/module/gicx00/Module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..ec0894eb4a559fde51c48559d7462d213843cee6 --- /dev/null +++ b/module/gicx00/Module.cmake @@ -0,0 +1,10 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "gicx00") + +set(SCP_MODULE_TARGET "module-gicx00") diff --git a/module/gicx00/doc/gicx00.md b/module/gicx00/doc/gicx00.md new file mode 100644 index 0000000000000000000000000000000000000000..5bc67748f9b17c20e6f92094c1579162b45e034a --- /dev/null +++ b/module/gicx00/doc/gicx00.md @@ -0,0 +1,19 @@ +\ingroup GroupModules Modules +\addtogroup GroupGICx00 Arm GICx00 + +# Arm GICx00 configuration module + +This module complements the base interrupt support in the AArch64 architecture. +The module initializes the GIC (Generic Interrupt Controller), then the +architecture interface is used to configure interrupts, via the +`fwk_interrupt_*` functions. + +The module takes a configuration struct with base addresses to the GIC +distributor and GIC redistributor corresponding to the execution core. There are +no runtime APIs. + +Registers specific to certain GIC hardware are detected at runtime based on the +IIDR register. + +`gicx00` should be listed in a product's `SCP_MODULES` definition prior to +any module that uses interrupts. diff --git a/module/gicx00/include/internal/gicx00_reg.h b/module/gicx00/include/internal/gicx00_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..dee0ab6c4df82154739276b1a297bfe94c6ef064 --- /dev/null +++ b/module/gicx00/include/internal/gicx00_reg.h @@ -0,0 +1,68 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef INTERNAL_GICX00_REG_H +#define INTERNAL_GICX00_REG_H + +#include + +#define GICD_CTLR 0x0000u +#define GICD_TYPER 0x0004u + +#define GICR_WAKER 0x0014u +#define GICR_IIDR 0x0004u +#define GICR_PWRR 0x0024u + +#define GICD_TYPER_IT_LINES_NUMBER 0x1Fu + +#define GICD_CTLR_ENABLE_GROUP_0 FWK_BIT(0) +#define GICD_CTLR_ARE_S FWK_BIT(4) +#define GICD_CTLR_DS FWK_BIT(6) + +#define GICR_IIDR_PRODUCT_ID FWK_GEN_MASK(31, 24) +#define GICR_IIDR_IMPLEMENTER_ID FWK_GEN_MASK(11, 0) +#define GICR_IIDR_GIC600 0x0200043Bu +#define GICR_IIDR_GIC600AE 0x0300043Bu +#define GICR_IIDR_GIC720AE 0x0700043Bu + +#define GICR_WAKER_PROCESSOR_SLEEP FWK_BIT(1) +#define GICR_WAKER_CHILDREN_ASLEEP FWK_BIT(2) + +#define GICR_PWRR_RDPD FWK_BIT(0) + +#define GICR_SGI_BASE 0x10000u + +#define GICR_IGROUPR0 0x0080u +#define GICR_ISENABLER0 0x0100u +#define GICR_IPRIORITYR(N) (0x0400u + (4 * (N))) +#define GICR_ICFGR1 0x0C04u +#define GICR_IGRPMODR0 0x0D00u + +#define GICD_IGROUPR(N) (0x0080u + (4 * (N))) +#define GICD_ISENABLER(N) (0x0100u + (4 * (N))) +#define GICD_IPRIORITYR(N) (0x0400u + (4 * (N))) +#define GICD_ICFGR(N) (0x0C00u + (4 * (N))) +#define GICD_IGRPMODR(N) (0x0D00u + (4 * (N))) +#define GICD_IROUTER(N) (0x6000u + (8 * (N))) + +#define ICC_SRE_SRE FWK_BIT(0) +#define ICC_SRE_DFB FWK_BIT(1) +#define ICC_SRE_DIB FWK_BIT(2) +#define ICC_SRE_ENABLE FWK_BIT(3) + +#define ICC_IGRPEN0_ENABLE FWK_BIT(0) + +#define ICC_PMR_MAX 0xFFu + +#define INTERRUPT_ID_PPI_LIMIT 32u +#define INTERRUPT_ID_LIMIT 1020u + +void write_icc_sre(uint64_t value); +void write_igrpen0_el1(uint64_t value); +void write_icc_pmr(uint64_t value); + +#endif /* INTERNAL_GICX00_REG_H */ diff --git a/module/gicx00/include/mod_gicx00.h b/module/gicx00/include/mod_gicx00.h new file mode 100644 index 0000000000000000000000000000000000000000..5c26d9cbe4f8ef785ba1ceb157f0f2c8724aee85 --- /dev/null +++ b/module/gicx00/include/mod_gicx00.h @@ -0,0 +1,38 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_GICX00_H +#define MOD_GICX00_H + +#include + +/*! + * \ingroup GroupModules + * \addtogroup GroupGICx00 Arm GICx00 + * \{ + */ + +/*! + * \brief Module configuration. + */ +struct mod_gicx00_config { + /*! + * \brief GIC distributor base address + */ + uintptr_t gicd_base; + + /*! + * \brief GIC redistributor base address + */ + uintptr_t gicr_base; +}; + +/*! + * \} + */ + +#endif /* MOD_GICX00_H */ diff --git a/module/gicx00/src/gicx00_reg.c b/module/gicx00/src/gicx00_reg.c new file mode 100644 index 0000000000000000000000000000000000000000..bd63a2975602f40291e552ced2754c9da4924bb7 --- /dev/null +++ b/module/gicx00/src/gicx00_reg.c @@ -0,0 +1,29 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "internal/gicx00_reg.h" + +#include + +#define ICC_SRE_EL2 S3_4_C12_C9_5 +#define ICC_IGRPEN0_el1 S3_0_C12_C12_6 +#define ICC_PMR_EL1 S3_0_C4_C6_0 + +void write_icc_sre(uint64_t value) +{ + WRITE_SYSREG(ICC_SRE_EL2, value); +} + +void write_igrpen0_el1(uint64_t value) +{ + WRITE_SYSREG(ICC_IGRPEN0_el1, value); +} + +void write_icc_pmr(uint64_t value) +{ + WRITE_SYSREG(ICC_PMR_EL1, value); +} diff --git a/module/gicx00/src/mod_gicx00.c b/module/gicx00/src/mod_gicx00.c new file mode 100644 index 0000000000000000000000000000000000000000..e4ff76c0571376469dded800e96d8553f7b358c3 --- /dev/null +++ b/module/gicx00/src/mod_gicx00.c @@ -0,0 +1,137 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "internal/gicx00_reg.h" + +#ifndef BUILD_TESTS +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include + +static void gic600_init(const struct mod_gicx00_config *config) +{ + uint32_t reg; + + /* Power on redistributor */ + fwk_mmio_write_32(config->gicr_base + GICR_PWRR, 0); + do { + reg = fwk_mmio_read_32(config->gicr_base + GICR_PWRR); + } while ((reg & GICR_PWRR_RDPD) != 0); +} + +static void initialize_interrupts(const struct mod_gicx00_config *config) +{ + uint32_t num_irqs; + uint32_t index; + + num_irqs = fwk_mmio_read_32(config->gicd_base + GICD_TYPER) & + GICD_TYPER_IT_LINES_NUMBER; + /* The formula for the maximum SPI interrupt ID is taken from + section 12.9.38 of the GIC specification */ + num_irqs = 32 * (num_irqs + 1); + fwk_assert(num_irqs >= INTERRUPT_ID_PPI_LIMIT); + fwk_assert(num_irqs < INTERRUPT_ID_LIMIT); + + /* Initialize SGI/PPI registers */ + fwk_mmio_write_32(config->gicr_base + GICR_SGI_BASE + GICR_IGROUPR0, 0); + fwk_mmio_write_32(config->gicr_base + GICR_SGI_BASE + GICR_ISENABLER0, 0); + fwk_mmio_write_32(config->gicr_base + GICR_SGI_BASE + GICR_ICFGR1, 0); + fwk_mmio_write_32(config->gicr_base + GICR_SGI_BASE + GICR_IGRPMODR0, 0); + for (index = 0u; index < INTERRUPT_ID_PPI_LIMIT / 4; index++) { + fwk_mmio_write_32( + config->gicr_base + GICR_SGI_BASE + GICR_IPRIORITYR(index), 0); + } + + /* Initialize SPI registers */ + for (index = INTERRUPT_ID_PPI_LIMIT / 32; index < num_irqs / 32; index++) { + fwk_mmio_write_32(config->gicd_base + GICD_IGROUPR(index), 0); + fwk_mmio_write_32(config->gicd_base + GICD_ISENABLER(index), 0); + fwk_mmio_write_32(config->gicd_base + GICD_IGRPMODR(index), 0); + } + for (index = INTERRUPT_ID_PPI_LIMIT / 16; index < num_irqs / 16; index++) { + fwk_mmio_write_32(config->gicd_base + GICD_ICFGR(index), 0); + } + for (index = INTERRUPT_ID_PPI_LIMIT / 4; index < num_irqs / 4; index++) { + fwk_mmio_write_32(config->gicd_base + GICD_IPRIORITYR(index), 0); + } + for (index = INTERRUPT_ID_PPI_LIMIT; index < num_irqs; index++) { + fwk_mmio_write_64(config->gicd_base + GICD_IROUTER(index), 0); + } +} + +static int gicx00_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + const struct mod_gicx00_config *config; + uint32_t reg; + + fwk_assert(element_count == 0); + fwk_assert(data != NULL); + + config = data; + + /* Initialize GICD_CTLR */ + fwk_mmio_write_32( + config->gicd_base + GICD_CTLR, + GICD_CTLR_ENABLE_GROUP_0 | GICD_CTLR_ARE_S | GICD_CTLR_DS); + + /* Perform GIC-specific initialization */ + reg = fwk_mmio_read_32(config->gicr_base + GICR_IIDR) & + (GICR_IIDR_PRODUCT_ID | GICR_IIDR_IMPLEMENTER_ID); + switch (reg) { + case GICR_IIDR_GIC600: + case GICR_IIDR_GIC600AE: + case GICR_IIDR_GIC720AE: + gic600_init(config); + break; + default: + break; + } + + /* Wake up redistributor */ + reg = fwk_mmio_read_32(config->gicr_base + GICR_WAKER); + reg &= ~GICR_WAKER_PROCESSOR_SLEEP; + fwk_mmio_write_32(config->gicr_base + GICR_WAKER, reg); + do { + reg = fwk_mmio_read_32(config->gicr_base + GICR_WAKER); + } while (reg & GICR_WAKER_CHILDREN_ASLEEP); + + /* Initialize interrupt registers */ + initialize_interrupts(config); + + /* Enable CPU interface */ + write_icc_sre(ICC_SRE_ENABLE | ICC_SRE_DIB | ICC_SRE_DFB | ICC_SRE_SRE); + write_icc_pmr(ICC_PMR_MAX); + write_igrpen0_el1(ICC_IGRPEN0_ENABLE); +#ifndef BUILD_TESTS + BARRIER_DSYNC_FENCE_FULL(); + BARRIER_ISYNC_FENCE_FULL(); +#endif + + /* Unmask interrupts */ + fwk_interrupt_global_enable(0); + + return FWK_SUCCESS; +} + +/* Module description */ +const struct fwk_module module_gicx00 = { + .type = FWK_MODULE_TYPE_DRIVER, + .init = gicx00_init, +}; diff --git a/module/gicx00/test/CMakeLists.txt b/module/gicx00/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d817683a8187156bf8a01e6458db5b781d7c2763 --- /dev/null +++ b/module/gicx00/test/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(TEST_SRC mod_gicx00) +set(TEST_FILE mod_gicx00) + +set(UNIT_TEST_TARGET mod_${TEST_MODULE}_unit_test) + +set(MODULE_SRC ${MODULE_ROOT}/${TEST_MODULE}/src) +set(MODULE_INC ${MODULE_ROOT}/${TEST_MODULE}/include) +set(MODULE_UT_SRC ${CMAKE_CURRENT_LIST_DIR}) +set(MODULE_UT_INC ${CMAKE_CURRENT_LIST_DIR}) +set(MODULE_UT_MOCK_SRC ${CMAKE_CURRENT_LIST_DIR}/mocks) + +list(APPEND MOCK_REPLACEMENTS fwk_module) +list(APPEND MOCK_REPLACEMENTS fwk_notification) +list(APPEND MOCK_REPLACEMENTS fwk_id) + +include(${SCP_ROOT}/unit_test/module_common.cmake) + +target_sources(${UNIT_TEST_TARGET} + PRIVATE + ${MODULE_UT_MOCK_SRC}/Mockgicx00_reg.c) diff --git a/module/gicx00/test/config_gicx00.h b/module/gicx00/test/config_gicx00.h new file mode 100644 index 0000000000000000000000000000000000000000..f85e71f544411f9ad8987db68d62125ccbe85a55 --- /dev/null +++ b/module/gicx00/test/config_gicx00.h @@ -0,0 +1,24 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include + +#define GICD_SIZE (256 * FWK_KIB) +#define GICR_SIZE (256 * FWK_KIB) + +static uint8_t gicd_reg[GICD_SIZE]; +static uint8_t gicr_reg[GICR_SIZE]; + +const struct fwk_module_config config_gicx00_ut = { + .data = &((struct mod_gicx00_config){ + .gicd_base = (uintptr_t)&gicd_reg, + .gicr_base = (uintptr_t)&gicr_reg, + }), +}; diff --git a/module/gicx00/test/fwk_module_idx.h b/module/gicx00/test/fwk_module_idx.h new file mode 100644 index 0000000000000000000000000000000000000000..41a39526d13663a5585bb30db2049b8f472ba43e --- /dev/null +++ b/module/gicx00/test/fwk_module_idx.h @@ -0,0 +1,21 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TEST_FWK_MODULE_MODULE_IDX_H +#define TEST_FWK_MODULE_MODULE_IDX_H + +#include + +enum fwk_module_idx { + FWK_MODULE_IDX_GICX00, + FWK_MODULE_IDX_COUNT, +}; + +static const fwk_id_t fwk_module_id_gicx00 = + FWK_ID_MODULE_INIT(FWK_MODULE_IDX_GICX00); + +#endif /* TEST_FWK_MODULE_MODULE_IDX_H */ diff --git a/module/gicx00/test/mocks/.clang-format b/module/gicx00/test/mocks/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..eeca2395f4c7551e2016f0d10a971844a3684994 --- /dev/null +++ b/module/gicx00/test/mocks/.clang-format @@ -0,0 +1,4 @@ +{ + "DisableFormat": true, + "SortIncludes": false, +} diff --git a/module/gicx00/test/mocks/Mockgicx00_reg.c b/module/gicx00/test/mocks/Mockgicx00_reg.c new file mode 100644 index 0000000000000000000000000000000000000000..3a20cbfa47be77ff78875ec0078e7a1520c78e68 --- /dev/null +++ b/module/gicx00/test/mocks/Mockgicx00_reg.c @@ -0,0 +1,419 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#include +#include +#include +#include "cmock.h" +#include "Mockgicx00_reg.h" + +static const char* CMockString_value = "value"; +static const char* CMockString_write_icc_pmr = "write_icc_pmr"; +static const char* CMockString_write_icc_sre = "write_icc_sre"; +static const char* CMockString_write_igrpen0_el1 = "write_igrpen0_el1"; + +typedef struct _CMOCK_write_icc_sre_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + uint64_t Expected_value; + char IgnoreArg_value; + +} CMOCK_write_icc_sre_CALL_INSTANCE; + +typedef struct _CMOCK_write_igrpen0_el1_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + uint64_t Expected_value; + char IgnoreArg_value; + +} CMOCK_write_igrpen0_el1_CALL_INSTANCE; + +typedef struct _CMOCK_write_icc_pmr_CALL_INSTANCE +{ + UNITY_LINE_TYPE LineNumber; + char ExpectAnyArgsBool; + uint64_t Expected_value; + char IgnoreArg_value; + +} CMOCK_write_icc_pmr_CALL_INSTANCE; + +static struct Mockgicx00_regInstance +{ + char write_icc_sre_IgnoreBool; + char write_icc_sre_CallbackBool; + CMOCK_write_icc_sre_CALLBACK write_icc_sre_CallbackFunctionPointer; + int write_icc_sre_CallbackCalls; + CMOCK_MEM_INDEX_TYPE write_icc_sre_CallInstance; + char write_igrpen0_el1_IgnoreBool; + char write_igrpen0_el1_CallbackBool; + CMOCK_write_igrpen0_el1_CALLBACK write_igrpen0_el1_CallbackFunctionPointer; + int write_igrpen0_el1_CallbackCalls; + CMOCK_MEM_INDEX_TYPE write_igrpen0_el1_CallInstance; + char write_icc_pmr_IgnoreBool; + char write_icc_pmr_CallbackBool; + CMOCK_write_icc_pmr_CALLBACK write_icc_pmr_CallbackFunctionPointer; + int write_icc_pmr_CallbackCalls; + CMOCK_MEM_INDEX_TYPE write_icc_pmr_CallInstance; +} Mock; + +extern jmp_buf AbortFrame; + +void Mockgicx00_reg_Verify(void) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_MEM_INDEX_TYPE call_instance; + call_instance = Mock.write_icc_sre_CallInstance; + if (Mock.write_icc_sre_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_write_icc_sre); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.write_icc_sre_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } + call_instance = Mock.write_igrpen0_el1_CallInstance; + if (Mock.write_igrpen0_el1_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_write_igrpen0_el1); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.write_igrpen0_el1_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } + call_instance = Mock.write_icc_pmr_CallInstance; + if (Mock.write_icc_pmr_IgnoreBool) + call_instance = CMOCK_GUTS_NONE; + if (CMOCK_GUTS_NONE != call_instance) + { + UNITY_SET_DETAIL(CMockString_write_icc_pmr); + UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess); + } + if (Mock.write_icc_pmr_CallbackFunctionPointer != NULL) + { + call_instance = CMOCK_GUTS_NONE; + (void)call_instance; + } +} + +void Mockgicx00_reg_Init(void) +{ + Mockgicx00_reg_Destroy(); +} + +void Mockgicx00_reg_Destroy(void) +{ + CMock_Guts_MemFreeAll(); + memset(&Mock, 0, sizeof(Mock)); +} + +void write_icc_sre(uint64_t value) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_write_icc_sre); + cmock_call_instance = (CMOCK_write_icc_sre_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.write_icc_sre_CallInstance); + Mock.write_icc_sre_CallInstance = CMock_Guts_MemNext(Mock.write_icc_sre_CallInstance); + if (Mock.write_icc_sre_IgnoreBool) + { + UNITY_CLR_DETAILS(); + return; + } + if (!Mock.write_icc_sre_CallbackBool && + Mock.write_icc_sre_CallbackFunctionPointer != NULL) + { + Mock.write_icc_sre_CallbackFunctionPointer(value, Mock.write_icc_sre_CallbackCalls++); + UNITY_CLR_DETAILS(); + return; + } + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore); + cmock_line = cmock_call_instance->LineNumber; + if (!cmock_call_instance->ExpectAnyArgsBool) + { + if (!cmock_call_instance->IgnoreArg_value) + { + UNITY_SET_DETAILS(CMockString_write_icc_sre,CMockString_value); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_value), (void*)(&value), sizeof(uint64_t), cmock_line, CMockStringMismatch); + } + } + if (Mock.write_icc_sre_CallbackFunctionPointer != NULL) + { + Mock.write_icc_sre_CallbackFunctionPointer(value, Mock.write_icc_sre_CallbackCalls++); + } + UNITY_CLR_DETAILS(); +} + +void CMockExpectParameters_write_icc_sre(CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance, uint64_t value); +void CMockExpectParameters_write_icc_sre(CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance, uint64_t value) +{ + memcpy((void*)(&cmock_call_instance->Expected_value), (void*)(&value), + sizeof(uint64_t[sizeof(value) == sizeof(uint64_t) ? 1 : -1])); /* add uint64_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_value = 0; +} + +void write_icc_sre_CMockIgnore(void) +{ + Mock.write_icc_sre_IgnoreBool = (char)1; +} + +void write_icc_sre_CMockStopIgnore(void) +{ + Mock.write_icc_sre_IgnoreBool = (char)0; +} + +void write_icc_sre_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_icc_sre_CALL_INSTANCE)); + CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_sre_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_icc_sre_CallInstance = CMock_Guts_MemChain(Mock.write_icc_sre_CallInstance, cmock_guts_index); + Mock.write_icc_sre_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ExpectAnyArgsBool = (char)1; +} + +void write_icc_sre_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_icc_sre_CALL_INSTANCE)); + CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_sre_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_icc_sre_CallInstance = CMock_Guts_MemChain(Mock.write_icc_sre_CallInstance, cmock_guts_index); + Mock.write_icc_sre_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_write_icc_sre(cmock_call_instance, value); +} + +void write_icc_sre_AddCallback(CMOCK_write_icc_sre_CALLBACK Callback) +{ + Mock.write_icc_sre_IgnoreBool = (char)0; + Mock.write_icc_sre_CallbackBool = (char)1; + Mock.write_icc_sre_CallbackFunctionPointer = Callback; +} + +void write_icc_sre_Stub(CMOCK_write_icc_sre_CALLBACK Callback) +{ + Mock.write_icc_sre_IgnoreBool = (char)0; + Mock.write_icc_sre_CallbackBool = (char)0; + Mock.write_icc_sre_CallbackFunctionPointer = Callback; +} + +void write_icc_sre_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_write_icc_sre_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_sre_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.write_icc_sre_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_value = 1; +} + +void write_igrpen0_el1(uint64_t value) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_write_igrpen0_el1); + cmock_call_instance = (CMOCK_write_igrpen0_el1_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.write_igrpen0_el1_CallInstance); + Mock.write_igrpen0_el1_CallInstance = CMock_Guts_MemNext(Mock.write_igrpen0_el1_CallInstance); + if (Mock.write_igrpen0_el1_IgnoreBool) + { + UNITY_CLR_DETAILS(); + return; + } + if (!Mock.write_igrpen0_el1_CallbackBool && + Mock.write_igrpen0_el1_CallbackFunctionPointer != NULL) + { + Mock.write_igrpen0_el1_CallbackFunctionPointer(value, Mock.write_igrpen0_el1_CallbackCalls++); + UNITY_CLR_DETAILS(); + return; + } + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore); + cmock_line = cmock_call_instance->LineNumber; + if (!cmock_call_instance->ExpectAnyArgsBool) + { + if (!cmock_call_instance->IgnoreArg_value) + { + UNITY_SET_DETAILS(CMockString_write_igrpen0_el1,CMockString_value); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_value), (void*)(&value), sizeof(uint64_t), cmock_line, CMockStringMismatch); + } + } + if (Mock.write_igrpen0_el1_CallbackFunctionPointer != NULL) + { + Mock.write_igrpen0_el1_CallbackFunctionPointer(value, Mock.write_igrpen0_el1_CallbackCalls++); + } + UNITY_CLR_DETAILS(); +} + +void CMockExpectParameters_write_igrpen0_el1(CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance, uint64_t value); +void CMockExpectParameters_write_igrpen0_el1(CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance, uint64_t value) +{ + memcpy((void*)(&cmock_call_instance->Expected_value), (void*)(&value), + sizeof(uint64_t[sizeof(value) == sizeof(uint64_t) ? 1 : -1])); /* add uint64_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_value = 0; +} + +void write_igrpen0_el1_CMockIgnore(void) +{ + Mock.write_igrpen0_el1_IgnoreBool = (char)1; +} + +void write_igrpen0_el1_CMockStopIgnore(void) +{ + Mock.write_igrpen0_el1_IgnoreBool = (char)0; +} + +void write_igrpen0_el1_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_igrpen0_el1_CALL_INSTANCE)); + CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_igrpen0_el1_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_igrpen0_el1_CallInstance = CMock_Guts_MemChain(Mock.write_igrpen0_el1_CallInstance, cmock_guts_index); + Mock.write_igrpen0_el1_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ExpectAnyArgsBool = (char)1; +} + +void write_igrpen0_el1_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_igrpen0_el1_CALL_INSTANCE)); + CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_igrpen0_el1_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_igrpen0_el1_CallInstance = CMock_Guts_MemChain(Mock.write_igrpen0_el1_CallInstance, cmock_guts_index); + Mock.write_igrpen0_el1_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_write_igrpen0_el1(cmock_call_instance, value); +} + +void write_igrpen0_el1_AddCallback(CMOCK_write_igrpen0_el1_CALLBACK Callback) +{ + Mock.write_igrpen0_el1_IgnoreBool = (char)0; + Mock.write_igrpen0_el1_CallbackBool = (char)1; + Mock.write_igrpen0_el1_CallbackFunctionPointer = Callback; +} + +void write_igrpen0_el1_Stub(CMOCK_write_igrpen0_el1_CALLBACK Callback) +{ + Mock.write_igrpen0_el1_IgnoreBool = (char)0; + Mock.write_igrpen0_el1_CallbackBool = (char)0; + Mock.write_igrpen0_el1_CallbackFunctionPointer = Callback; +} + +void write_igrpen0_el1_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_write_igrpen0_el1_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_igrpen0_el1_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.write_igrpen0_el1_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_value = 1; +} + +void write_icc_pmr(uint64_t value) +{ + UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM; + CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance; + UNITY_SET_DETAIL(CMockString_write_icc_pmr); + cmock_call_instance = (CMOCK_write_icc_pmr_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.write_icc_pmr_CallInstance); + Mock.write_icc_pmr_CallInstance = CMock_Guts_MemNext(Mock.write_icc_pmr_CallInstance); + if (Mock.write_icc_pmr_IgnoreBool) + { + UNITY_CLR_DETAILS(); + return; + } + if (!Mock.write_icc_pmr_CallbackBool && + Mock.write_icc_pmr_CallbackFunctionPointer != NULL) + { + Mock.write_icc_pmr_CallbackFunctionPointer(value, Mock.write_icc_pmr_CallbackCalls++); + UNITY_CLR_DETAILS(); + return; + } + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore); + cmock_line = cmock_call_instance->LineNumber; + if (!cmock_call_instance->ExpectAnyArgsBool) + { + if (!cmock_call_instance->IgnoreArg_value) + { + UNITY_SET_DETAILS(CMockString_write_icc_pmr,CMockString_value); + UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_value), (void*)(&value), sizeof(uint64_t), cmock_line, CMockStringMismatch); + } + } + if (Mock.write_icc_pmr_CallbackFunctionPointer != NULL) + { + Mock.write_icc_pmr_CallbackFunctionPointer(value, Mock.write_icc_pmr_CallbackCalls++); + } + UNITY_CLR_DETAILS(); +} + +void CMockExpectParameters_write_icc_pmr(CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance, uint64_t value); +void CMockExpectParameters_write_icc_pmr(CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance, uint64_t value) +{ + memcpy((void*)(&cmock_call_instance->Expected_value), (void*)(&value), + sizeof(uint64_t[sizeof(value) == sizeof(uint64_t) ? 1 : -1])); /* add uint64_t to :treat_as_array if this causes an error */ + cmock_call_instance->IgnoreArg_value = 0; +} + +void write_icc_pmr_CMockIgnore(void) +{ + Mock.write_icc_pmr_IgnoreBool = (char)1; +} + +void write_icc_pmr_CMockStopIgnore(void) +{ + Mock.write_icc_pmr_IgnoreBool = (char)0; +} + +void write_icc_pmr_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_icc_pmr_CALL_INSTANCE)); + CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_pmr_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_icc_pmr_CallInstance = CMock_Guts_MemChain(Mock.write_icc_pmr_CallInstance, cmock_guts_index); + Mock.write_icc_pmr_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + cmock_call_instance->ExpectAnyArgsBool = (char)1; +} + +void write_icc_pmr_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value) +{ + CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_write_icc_pmr_CALL_INSTANCE)); + CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_pmr_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory); + memset(cmock_call_instance, 0, sizeof(*cmock_call_instance)); + Mock.write_icc_pmr_CallInstance = CMock_Guts_MemChain(Mock.write_icc_pmr_CallInstance, cmock_guts_index); + Mock.write_icc_pmr_IgnoreBool = (char)0; + cmock_call_instance->LineNumber = cmock_line; + cmock_call_instance->ExpectAnyArgsBool = (char)0; + CMockExpectParameters_write_icc_pmr(cmock_call_instance, value); +} + +void write_icc_pmr_AddCallback(CMOCK_write_icc_pmr_CALLBACK Callback) +{ + Mock.write_icc_pmr_IgnoreBool = (char)0; + Mock.write_icc_pmr_CallbackBool = (char)1; + Mock.write_icc_pmr_CallbackFunctionPointer = Callback; +} + +void write_icc_pmr_Stub(CMOCK_write_icc_pmr_CALLBACK Callback) +{ + Mock.write_icc_pmr_IgnoreBool = (char)0; + Mock.write_icc_pmr_CallbackBool = (char)0; + Mock.write_icc_pmr_CallbackFunctionPointer = Callback; +} + +void write_icc_pmr_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line) +{ + CMOCK_write_icc_pmr_CALL_INSTANCE* cmock_call_instance = (CMOCK_write_icc_pmr_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.write_icc_pmr_CallInstance)); + UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp); + cmock_call_instance->IgnoreArg_value = 1; +} + diff --git a/module/gicx00/test/mocks/Mockgicx00_reg.h b/module/gicx00/test/mocks/Mockgicx00_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..0ddbba6209360f3a6e981088ea84511fc7c4c322 --- /dev/null +++ b/module/gicx00/test/mocks/Mockgicx00_reg.h @@ -0,0 +1,76 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#ifndef _MOCKGICX00_REG_H +#define _MOCKGICX00_REG_H + +#include "unity.h" +#include "gicx00_reg.h" + +/* Ignore the following warnings, since we are copying code */ +#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0))) +#pragma GCC diagnostic push +#endif +#if !defined(__clang__) +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wduplicate-decl-specifier" +#endif + +void Mockgicx00_reg_Init(void); +void Mockgicx00_reg_Destroy(void); +void Mockgicx00_reg_Verify(void); + + + + +#define write_icc_sre_Ignore() write_icc_sre_CMockIgnore() +void write_icc_sre_CMockIgnore(void); +#define write_icc_sre_StopIgnore() write_icc_sre_CMockStopIgnore() +void write_icc_sre_CMockStopIgnore(void); +#define write_icc_sre_ExpectAnyArgs() write_icc_sre_CMockExpectAnyArgs(__LINE__) +void write_icc_sre_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line); +#define write_icc_sre_Expect(value) write_icc_sre_CMockExpect(__LINE__, value) +void write_icc_sre_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value); +typedef void (* CMOCK_write_icc_sre_CALLBACK)(uint64_t value, int cmock_num_calls); +void write_icc_sre_AddCallback(CMOCK_write_icc_sre_CALLBACK Callback); +void write_icc_sre_Stub(CMOCK_write_icc_sre_CALLBACK Callback); +#define write_icc_sre_StubWithCallback write_icc_sre_Stub +#define write_icc_sre_IgnoreArg_value() write_icc_sre_CMockIgnoreArg_value(__LINE__) +void write_icc_sre_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line); +#define write_igrpen0_el1_Ignore() write_igrpen0_el1_CMockIgnore() +void write_igrpen0_el1_CMockIgnore(void); +#define write_igrpen0_el1_StopIgnore() write_igrpen0_el1_CMockStopIgnore() +void write_igrpen0_el1_CMockStopIgnore(void); +#define write_igrpen0_el1_ExpectAnyArgs() write_igrpen0_el1_CMockExpectAnyArgs(__LINE__) +void write_igrpen0_el1_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line); +#define write_igrpen0_el1_Expect(value) write_igrpen0_el1_CMockExpect(__LINE__, value) +void write_igrpen0_el1_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value); +typedef void (* CMOCK_write_igrpen0_el1_CALLBACK)(uint64_t value, int cmock_num_calls); +void write_igrpen0_el1_AddCallback(CMOCK_write_igrpen0_el1_CALLBACK Callback); +void write_igrpen0_el1_Stub(CMOCK_write_igrpen0_el1_CALLBACK Callback); +#define write_igrpen0_el1_StubWithCallback write_igrpen0_el1_Stub +#define write_igrpen0_el1_IgnoreArg_value() write_igrpen0_el1_CMockIgnoreArg_value(__LINE__) +void write_igrpen0_el1_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line); +#define write_icc_pmr_Ignore() write_icc_pmr_CMockIgnore() +void write_icc_pmr_CMockIgnore(void); +#define write_icc_pmr_StopIgnore() write_icc_pmr_CMockStopIgnore() +void write_icc_pmr_CMockStopIgnore(void); +#define write_icc_pmr_ExpectAnyArgs() write_icc_pmr_CMockExpectAnyArgs(__LINE__) +void write_icc_pmr_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line); +#define write_icc_pmr_Expect(value) write_icc_pmr_CMockExpect(__LINE__, value) +void write_icc_pmr_CMockExpect(UNITY_LINE_TYPE cmock_line, uint64_t value); +typedef void (* CMOCK_write_icc_pmr_CALLBACK)(uint64_t value, int cmock_num_calls); +void write_icc_pmr_AddCallback(CMOCK_write_icc_pmr_CALLBACK Callback); +void write_icc_pmr_Stub(CMOCK_write_icc_pmr_CALLBACK Callback); +#define write_icc_pmr_StubWithCallback write_icc_pmr_Stub +#define write_icc_pmr_IgnoreArg_value() write_icc_pmr_CMockIgnoreArg_value(__LINE__) +void write_icc_pmr_CMockIgnoreArg_value(UNITY_LINE_TYPE cmock_line); + +#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0))) +#pragma GCC diagnostic pop +#endif +#endif + +#endif diff --git a/module/gicx00/test/mod_gicx00_unit_test.c b/module/gicx00/test/mod_gicx00_unit_test.c new file mode 100644 index 0000000000000000000000000000000000000000..859b2bf5f5b2cd49c46fa947ef70224b0544017c --- /dev/null +++ b/module/gicx00/test/mod_gicx00_unit_test.c @@ -0,0 +1,95 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "internal/gicx00_reg.h" +#include "scp_unity.h" +#include "unity.h" + +#include +#include +#include + +#include + +#include UNIT_TEST_SRC + +#define FWK_MODULE_IDX_GICX00 0 + +void setUp(void) +{ + memset(gicd_reg, 0, GICD_SIZE); + memset(gicr_reg, 0, GICR_SIZE); +} + +void tearDown(void) +{ +} + +void test_mod_gicx00_init_gic720ae(void) +{ + fwk_id_t id; + int status; + uint32_t reg; + + id = FWK_ID_MODULE(FWK_MODULE_IDX_GICX00); + + write_icc_sre_Expect(0xF); + write_icc_pmr_Expect(0xFF); + write_igrpen0_el1_Expect(0x1); + + /* Configure as a GIC720AE and initialize the GICR_PWRR register */ + fwk_mmio_write_32((uintptr_t)(gicr_reg + GICR_IIDR), GICR_IIDR_GIC720AE); + fwk_mmio_write_32((uintptr_t)(gicr_reg + GICR_PWRR), GICR_PWRR_RDPD); + + status = gicx00_init(id, 0, config_gicx00_ut.data); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + + /* Verify that PWRR was cleared */ + reg = fwk_mmio_read_32((uintptr_t)(gicr_reg + GICR_PWRR)); + TEST_ASSERT_EQUAL(0, reg); +} + +void test_mod_gicx00_init(void) +{ + fwk_id_t id; + int status; + uint32_t reg; + + id = FWK_ID_MODULE(FWK_MODULE_IDX_GICX00); + + write_icc_sre_Expect(0xF); + write_icc_pmr_Expect(0xFF); + write_igrpen0_el1_Expect(0x1); + + /* Initialize GICR_WAKER */ + fwk_mmio_write_32( + (uintptr_t)(gicr_reg + GICR_WAKER), GICR_WAKER_PROCESSOR_SLEEP); + + status = gicx00_init(id, 0, config_gicx00_ut.data); + TEST_ASSERT_EQUAL(FWK_SUCCESS, status); + + /* Verify GIC registers */ + reg = fwk_mmio_read_32((uintptr_t)(gicd_reg + GICD_CTLR)); + TEST_ASSERT_EQUAL(0x51, reg); + reg = fwk_mmio_read_32((uintptr_t)(gicr_reg + GICR_WAKER)); + TEST_ASSERT_EQUAL(0, reg); +} + +int template_test_main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_mod_gicx00_init); + RUN_TEST(test_mod_gicx00_init_gic720ae); + return UNITY_END(); +} + +#if !defined(TEST_ON_TARGET) +int main(void) +{ + return template_test_main(); +} +#endif diff --git a/module/sp805/src/mod_sp805.c b/module/sp805/src/mod_sp805.c index 966778efc93aba3a6df984f3726ceaeffcd4b0c7..cf79fdc35d6dfb1143a3669057b32e4f7b63025f 100644 --- a/module/sp805/src/mod_sp805.c +++ b/module/sp805/src/mod_sp805.c @@ -1,11 +1,14 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#include +#ifdef BUILD_HAS_MOD_CLOCK +# include +#endif + #include #include @@ -89,6 +92,7 @@ static int mod_sp805_init( static int mod_sp805_start(fwk_id_t id) { +#ifdef BUILD_HAS_MOD_CLOCK if (!fwk_id_is_type(ctx.config->driver_id, FWK_ID_TYPE_NONE)) { /* Register for clock state notifications */ return fwk_notification_subscribe( @@ -96,6 +100,9 @@ static int mod_sp805_start(fwk_id_t id) } else { enable_sp805_interrupt(); } +#else + enable_sp805_interrupt(); +#endif return FWK_SUCCESS; } @@ -104,6 +111,7 @@ static int mod_sp805_process_notification( const struct fwk_event *event, struct fwk_event *resp_event) { +#ifdef BUILD_HAS_MOD_CLOCK struct clock_notification_params *params; fwk_assert( @@ -114,6 +122,7 @@ static int mod_sp805_process_notification( enable_sp805_interrupt(); } +#endif return FWK_SUCCESS; } diff --git a/product/fvp-baser-aemv8r/fw/CMakeLists.txt b/product/fvp-baser-aemv8r/fw/CMakeLists.txt index c79ff32d408be46dcba9ed4fcc9aab7055dd6202..fc7ca9a804f93ce70fbe5bee4fe2bf59b64e06c0 100644 --- a/product/fvp-baser-aemv8r/fw/CMakeLists.txt +++ b/product/fvp-baser-aemv8r/fw/CMakeLists.txt @@ -11,4 +11,6 @@ target_include_directories(fvp-baser-aemv8r PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" target_sources(fvp-baser-aemv8r PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/config_pl011.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_armv8r_mpu.c" + "${CMAKE_CURRENT_SOURCE_DIR}/config_gicx00.c" + "${CMAKE_CURRENT_SOURCE_DIR}/config_sp805.c" ) diff --git a/product/fvp-baser-aemv8r/fw/Firmware.cmake b/product/fvp-baser-aemv8r/fw/Firmware.cmake index 7fa43d1643d75ce70fc45a29e529615075c7a794..251908ed07da3b44299931ffc387686333cacb9c 100644 --- a/product/fvp-baser-aemv8r/fw/Firmware.cmake +++ b/product/fvp-baser-aemv8r/fw/Firmware.cmake @@ -17,4 +17,6 @@ set(SCP_ARCHITECTURE "aarch64") list(APPEND SCP_MODULES "armv8r-mpu" "pl011" + "gicx00" + "sp805" ) diff --git a/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake b/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake index 049616bb32cc2295e94de923e8695b588dacabe2..f137c75ed53164a24d6b2a1a8d21a02a6fb6530f 100644 --- a/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake +++ b/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake @@ -9,8 +9,7 @@ include_guard() set(CMAKE_SYSTEM_PROCESSOR "aarch64") -# TODO: Change to cortex-r82 once available in the supported toolchain -set(SCP_AARCH64_PROCESSOR_TARGET "generic") +set(SCP_AARCH64_PROCESSOR_TARGET "cortex-r82") set(CMAKE_TOOLCHAIN_PREFIX "aarch64-none-elf-") diff --git a/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c b/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c index cfe1e925c05a2791e110e6de8bcc759d3029cb41..6596db97dfa36b6e28fb4b407213adaa1ea28af7 100644 --- a/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c +++ b/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c @@ -41,6 +41,16 @@ static struct mod_armv8r_mpu_region mem_regions[] = { PRLAR_NS_SECURE, MPU_ATTR_0, PRLAR_EN_ENABLED) }, + { .prbar = PRBAR_VALUE( + FVP_GIC_BASE, + PRBAR_SH_NON_SHAREABLE, + PRBAR_AP_RW_EL2, + PRBAR_XN_NOT_PERMITTED), + .prlar = PRLAR_VALUE( + FVP_GIC_BASE + FVP_GIC_SIZE - 1, + PRLAR_NS_SECURE, + MPU_ATTR_1, + PRLAR_EN_ENABLED) }, { .prbar = PRBAR_VALUE( FVP_UART_BASE, PRBAR_SH_NON_SHAREABLE, @@ -50,6 +60,16 @@ static struct mod_armv8r_mpu_region mem_regions[] = { FVP_UART_BASE + FVP_UART_SIZE - 1, PRLAR_NS_SECURE, MPU_ATTR_1, + PRLAR_EN_ENABLED) }, + { .prbar = PRBAR_VALUE( + FVP_WATCHDOG_BASE, + PRBAR_SH_NON_SHAREABLE, + PRBAR_AP_RW_EL2, + PRBAR_XN_NOT_PERMITTED), + .prlar = PRLAR_VALUE( + FVP_WATCHDOG_BASE + FVP_WATCHDOG_SIZE - 1, + PRLAR_NS_SECURE, + MPU_ATTR_1, PRLAR_EN_ENABLED) } }; diff --git a/product/fvp-baser-aemv8r/fw/config_gicx00.c b/product/fvp-baser-aemv8r/fw/config_gicx00.c new file mode 100644 index 0000000000000000000000000000000000000000..69e345ecd660953a33e6e927f01646a0dd6fc4f1 --- /dev/null +++ b/product/fvp-baser-aemv8r/fw/config_gicx00.c @@ -0,0 +1,18 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fvp_baser_aemv8r_mmap.h" +#include "mod_gicx00.h" + +#include + +const struct fwk_module_config config_gicx00 = { + .data = &((struct mod_gicx00_config){ + .gicd_base = FVP_GICD_BASE, + .gicr_base = FVP_GICR_BASE, + }), +}; diff --git a/product/fvp-baser-aemv8r/fw/config_sp805.c b/product/fvp-baser-aemv8r/fw/config_sp805.c new file mode 100644 index 0000000000000000000000000000000000000000..1ff23f2afa6314dd1f1f8a48597cda3d2828241c --- /dev/null +++ b/product/fvp-baser-aemv8r/fw/config_sp805.c @@ -0,0 +1,32 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fvp_baser_aemv8r_mmap.h" + +#include + +#include +#include + +/* FVP watchdog interrupt line */ +#define FVP_WATCHDOG_IRQ 32 + +/* Reload value for the WdogLoad register */ +#define LOAD_VALUE 0x0fffffff + +/* + * Watch Dog Timer Driver configuration + */ +const struct fwk_module_config config_sp805 = { + .data = + &(struct mod_sp805_config){ + .reg_base = FVP_WATCHDOG_BASE, + .wdt_load_value = LOAD_VALUE, + .driver_id = FWK_ID_NONE_INIT, + .sp805_irq = FVP_WATCHDOG_IRQ, + } +}; diff --git a/product/fvp-baser-aemv8r/fw/fmw_gic.h b/product/fvp-baser-aemv8r/fw/fmw_gic.h new file mode 100644 index 0000000000000000000000000000000000000000..2d00c54b2ddfc5587674f787dc225cb16a8f1a4f --- /dev/null +++ b/product/fvp-baser-aemv8r/fw/fmw_gic.h @@ -0,0 +1,16 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FMW_GIC_H +#define FMW_GIC_H + +#include "fvp_baser_aemv8r_mmap.h" + +#define FMW_GICD_BASE FVP_GICD_BASE +#define FMW_GICR_BASE FVP_GICR_BASE + +#endif /* FMW_GIC_H */ diff --git a/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h b/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h index ac34c360bd6bbcb4919f664ff583af417f7f5bd6..2d7291d9b347305ceaadd713805c4abe25ad2955 100644 --- a/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h +++ b/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h @@ -17,7 +17,13 @@ #define FVP_DTC_RAM_BASE (FVP_DRAM_BASE + FVP_ITC_RAM_SIZE) #define FVP_PERIPHERAL_BASE 0x80000000 +#define FVP_GICD_BASE (FVP_PERIPHERAL_BASE + 0x2F000000) +#define FVP_GICR_BASE (FVP_PERIPHERAL_BASE + 0x2F100000) +#define FVP_GIC_BASE FVP_GICD_BASE +#define FVP_GIC_SIZE (16 * FWK_MIB) #define FVP_UART_BASE (FVP_PERIPHERAL_BASE + 0x1C090000) #define FVP_UART_SIZE (64 * FWK_KIB) +#define FVP_WATCHDOG_BASE (FVP_PERIPHERAL_BASE + 0x1C0F0000) +#define FVP_WATCHDOG_SIZE (64 * FWK_KIB) #endif /* FVP_BASER_AEMV8R_MMAP_H */ diff --git a/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt index 21109531cc6461a83bad882e25ec636214e7bbf3..1cb5f69fef5b4889abc52096a2ee99983bb08a68 100644 --- a/unit_test/CMakeLists.txt +++ b/unit_test/CMakeLists.txt @@ -113,6 +113,7 @@ list(APPEND UNIT_MODULE atu) list(APPEND UNIT_MODULE ccsm) list(APPEND UNIT_MODULE dvfs) list(APPEND UNIT_MODULE fch_polled) +list(APPEND UNIT_MODULE gicx00) list(APPEND UNIT_MODULE gtimer) list(APPEND UNIT_MODULE metrics_analyzer) list(APPEND UNIT_MODULE mhu3)