From 481505ed1e012218bcbd9fdadec3a20ca1288e86 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 09:06:02 +0000 Subject: [PATCH 1/9] aarch64: Fix exception table Ensure the exception table is aligned to the next 2K, as required by VBAR_ELx. We are using SP_ELX, not SP_EL0 so provide the set of exception vectors for this too. Provide the remaining set of exception vectors for lower ELs for completeness too. Replace some tabs with spaces. Signed-off-by: Peter Hoyes --- arch/arm/aarch64/src/arch_exceptions.S | 29 +++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/arm/aarch64/src/arch_exceptions.S b/arch/arm/aarch64/src/arch_exceptions.S index 14796f5bb..75107934e 100644 --- a/arch/arm/aarch64/src/arch_exceptions.S +++ b/arch/arm/aarch64/src/arch_exceptions.S @@ -7,16 +7,35 @@ .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 err_exception /* 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 -- GitLab From 3fdc53710b2d9d700a8738a47155ccd4f54bb399 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 09:18:39 +0000 Subject: [PATCH 2/9] aarch64: Enable interrupt routing to S-EL2 In order to route interrupts to the highest exception level in Armv8-R64, it is necessary to enable the FMO, IMO and AMO bits in HCR_EL2 during EL2 initialization. Signed-off-by: Peter Hoyes --- arch/arm/aarch64/include/arch_reg.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/aarch64/include/arch_reg.h b/arch/arm/aarch64/include/arch_reg.h index aec8cbcda..fc30054cb 100644 --- a/arch/arm/aarch64/include/arch_reg.h +++ b/arch/arm/aarch64/include/arch_reg.h @@ -86,7 +86,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 -- GitLab From a4c094313bbfb63ad911fc2a11252de5a1564d36 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 09:25:56 +0000 Subject: [PATCH 3/9] aarch64: Implement interrupt setup and handling The AArch64 minimal interrupt support is based on the architectrual GIC (General Interrupt Controller). It has the following limitations in order to conform to the framework interrupt API: * All interrupts have the same priority (0). * NMIs (non-maskable interrupts) are not supported. * The extended SPI and PPI ranges are not supported. In order to configure interrupts, the address of the GIC distributor and redistributor are required. These are provided by the header file fmw_gic.h, which must be provided by an AArch64 product. The GIC and CPU interface initialization will be deferred to a dedicated module, so that additional initialization can be performed prior to the primary GIC (e.g. for multiview configuration). Only Group 0 interrupts are enabled, which are handled by the FIQ handler at the highest implemented exception level. Implement the fiq_handler and replace the stubs in arch_gic.c with the implementation. Also implement the interrupt enable/disable methods in arch_helpers.h. Update the AArch64 documentation. Signed-off-by: Peter Hoyes --- arch/arm/aarch64/include/arch_helpers.h | 9 +- arch/arm/aarch64/include/arch_reg.h | 30 +++- arch/arm/aarch64/src/arch_exceptions.S | 44 ++++- arch/arm/aarch64/src/arch_gic.c | 229 ++++++++++++++++++++++-- doc/aarch64.md | 14 ++ 5 files changed, 306 insertions(+), 20 deletions(-) diff --git a/arch/arm/aarch64/include/arch_helpers.h b/arch/arm/aarch64/include/arch_helpers.h index 3803ab557..ec8b3cd02 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 fc30054cb..c35c9eec3 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 @@ -97,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 75107934e..01c8ff30a 100644 --- a/arch/arm/aarch64/src/arch_exceptions.S +++ b/arch/arm/aarch64/src/arch_exceptions.S @@ -22,7 +22,7 @@ exception_vectors: /* current EL, SP_ELX */ ventry err_exception /* synchronous */ ventry err_exception /* IRQ */ - ventry err_exception /* FIQ */ + ventry fiq_handler /* FIQ */ ventry err_exception /* SError */ /* lower EL using AArch64 */ @@ -40,3 +40,45 @@ exception_vectors: 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 3f94ebedf..0217e2045 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 8d8f334b5..94deec64a 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 -- GitLab From 46cf06225372252fb0d30cb9b90b4b3d9fb27a51 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 09:49:47 +0000 Subject: [PATCH 4/9] gicx00: Introduce module Introduce a module to perform the GIC initialization prior to unmasking interrupts. It contains specific logic to power on the redistributors of GIC600/GIC600AE/GIC720AE interrupt controllers. This logic is performed by a module instead of in the AArch64 architecture to allow for other initialization to happen prior to the GIC (e.g. for multiview configuration). Signed-off-by: Peter Hoyes --- module/CMakeLists.txt | 1 + module/gicx00/CMakeLists.txt | 14 ++ module/gicx00/Module.cmake | 10 ++ module/gicx00/doc/gicx00.md | 19 +++ module/gicx00/include/internal/gicx00_reg.h | 68 ++++++++++ module/gicx00/include/mod_gicx00.h | 38 ++++++ module/gicx00/src/gicx00_reg.c | 29 +++++ module/gicx00/src/mod_gicx00.c | 137 ++++++++++++++++++++ 8 files changed, 316 insertions(+) create mode 100644 module/gicx00/CMakeLists.txt create mode 100644 module/gicx00/Module.cmake create mode 100644 module/gicx00/doc/gicx00.md create mode 100644 module/gicx00/include/internal/gicx00_reg.h create mode 100644 module/gicx00/include/mod_gicx00.h create mode 100644 module/gicx00/src/gicx00_reg.c create mode 100644 module/gicx00/src/mod_gicx00.c diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index f05d41c3c..af1d4ad5f 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 000000000..f3c180fff --- /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 000000000..ec0894eb4 --- /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 000000000..5bc67748f --- /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 000000000..dee0ab6c4 --- /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 000000000..5c26d9cbe --- /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 000000000..bd63a2975 --- /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 000000000..e4ff76c05 --- /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, +}; -- GitLab From 3e8e73ce8183d894d800e8ff0b02e3454901af8f Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Thu, 31 Oct 2024 09:05:42 +0000 Subject: [PATCH 5/9] gicx00: Introduce unit tests Add unit tests for the gicx00 module which: * Validate that the GIC fields are initialized correctly * Validate that the GICX00-specific fields are initialized correctly Signed-off-by: Peter Hoyes --- module/gicx00/test/CMakeLists.txt | 27 ++ module/gicx00/test/config_gicx00.h | 24 ++ module/gicx00/test/fwk_module_idx.h | 21 ++ module/gicx00/test/mocks/.clang-format | 4 + module/gicx00/test/mocks/Mockgicx00_reg.c | 419 ++++++++++++++++++++++ module/gicx00/test/mocks/Mockgicx00_reg.h | 76 ++++ module/gicx00/test/mod_gicx00_unit_test.c | 95 +++++ unit_test/CMakeLists.txt | 1 + 8 files changed, 667 insertions(+) create mode 100644 module/gicx00/test/CMakeLists.txt create mode 100644 module/gicx00/test/config_gicx00.h create mode 100644 module/gicx00/test/fwk_module_idx.h create mode 100644 module/gicx00/test/mocks/.clang-format create mode 100644 module/gicx00/test/mocks/Mockgicx00_reg.c create mode 100644 module/gicx00/test/mocks/Mockgicx00_reg.h create mode 100644 module/gicx00/test/mod_gicx00_unit_test.c diff --git a/module/gicx00/test/CMakeLists.txt b/module/gicx00/test/CMakeLists.txt new file mode 100644 index 000000000..d817683a8 --- /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 000000000..f85e71f54 --- /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 000000000..41a39526d --- /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 000000000..eeca2395f --- /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 000000000..3a20cbfa4 --- /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 000000000..0ddbba620 --- /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 000000000..859b2bf5f --- /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/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt index 21109531c..1cb5f69fe 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) -- GitLab From 4e5ff9078997a6f79d8a2a44e4c327407bc29e58 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 09:57:31 +0000 Subject: [PATCH 6/9] sp805: Support usage without clock module Add ifdefs to the SP805 (watchdog timer) module, so that it can be used in the absence of the clock module. Signed-off-by: Peter Hoyes --- module/sp805/src/mod_sp805.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/module/sp805/src/mod_sp805.c b/module/sp805/src/mod_sp805.c index 966778efc..cf79fdc35 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; } -- GitLab From b1a35bc9cf45081a89499b8962026a51fc938c49 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Fri, 1 Nov 2024 16:27:03 +0000 Subject: [PATCH 7/9] fvp-baser-aemv8r: Use cortex-r82 CPU tune Now that the supported toolchain has been updated to 13.3rel1, use a more appropriate CPU tune for the fvp-baser-aemv8r product with the GNU toolchain. Signed-off-by: Peter Hoyes --- product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake b/product/fvp-baser-aemv8r/fw/Toolchain-GNU.cmake index 049616bb3..f137c75ed 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-") -- GitLab From 84132b8bea09743e48a1fc0630d21118820a9824 Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 10:02:31 +0000 Subject: [PATCH 8/9] fvp-baser-aemv8r: Add GIC support Add the GIC addresses to the memory map and MPU regions. Add the gicx00 module and configure. Provide fmw_gic.h Signed-off-by: Peter Hoyes --- product/fvp-baser-aemv8r/fw/CMakeLists.txt | 1 + product/fvp-baser-aemv8r/fw/Firmware.cmake | 1 + .../fvp-baser-aemv8r/fw/config_armv8r_mpu.c | 10 ++++++++++ product/fvp-baser-aemv8r/fw/config_gicx00.c | 18 ++++++++++++++++++ product/fvp-baser-aemv8r/fw/fmw_gic.h | 16 ++++++++++++++++ .../fw/fvp_baser_aemv8r_mmap.h | 4 ++++ 6 files changed, 50 insertions(+) create mode 100644 product/fvp-baser-aemv8r/fw/config_gicx00.c create mode 100644 product/fvp-baser-aemv8r/fw/fmw_gic.h diff --git a/product/fvp-baser-aemv8r/fw/CMakeLists.txt b/product/fvp-baser-aemv8r/fw/CMakeLists.txt index c79ff32d4..bd1f01418 100644 --- a/product/fvp-baser-aemv8r/fw/CMakeLists.txt +++ b/product/fvp-baser-aemv8r/fw/CMakeLists.txt @@ -11,4 +11,5 @@ 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" ) diff --git a/product/fvp-baser-aemv8r/fw/Firmware.cmake b/product/fvp-baser-aemv8r/fw/Firmware.cmake index 7fa43d164..e3687c4d4 100644 --- a/product/fvp-baser-aemv8r/fw/Firmware.cmake +++ b/product/fvp-baser-aemv8r/fw/Firmware.cmake @@ -17,4 +17,5 @@ set(SCP_ARCHITECTURE "aarch64") list(APPEND SCP_MODULES "armv8r-mpu" "pl011" + "gicx00" ) diff --git a/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c b/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c index cfe1e925c..641ac228d 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, 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 000000000..69e345ecd --- /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/fmw_gic.h b/product/fvp-baser-aemv8r/fw/fmw_gic.h new file mode 100644 index 000000000..2d00c54b2 --- /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 ac34c360b..03499fb0a 100644 --- a/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h +++ b/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h @@ -17,6 +17,10 @@ #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) -- GitLab From 07e4e8f231a2f4d45bee342c479514c790553ebe Mon Sep 17 00:00:00 2001 From: Peter Hoyes Date: Wed, 30 Oct 2024 10:05:06 +0000 Subject: [PATCH 9/9] fvp-baser-aemv8r: Demonstrate GIC usage using SP805 Enable and configure the sp805 module, which generates regular SPI interrupts. Signed-off-by: Peter Hoyes --- product/fvp-baser-aemv8r/fw/CMakeLists.txt | 1 + product/fvp-baser-aemv8r/fw/Firmware.cmake | 1 + .../fvp-baser-aemv8r/fw/config_armv8r_mpu.c | 10 ++++++ product/fvp-baser-aemv8r/fw/config_sp805.c | 32 +++++++++++++++++++ .../fw/fvp_baser_aemv8r_mmap.h | 2 ++ 5 files changed, 46 insertions(+) create mode 100644 product/fvp-baser-aemv8r/fw/config_sp805.c diff --git a/product/fvp-baser-aemv8r/fw/CMakeLists.txt b/product/fvp-baser-aemv8r/fw/CMakeLists.txt index bd1f01418..fc7ca9a80 100644 --- a/product/fvp-baser-aemv8r/fw/CMakeLists.txt +++ b/product/fvp-baser-aemv8r/fw/CMakeLists.txt @@ -12,4 +12,5 @@ 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 e3687c4d4..251908ed0 100644 --- a/product/fvp-baser-aemv8r/fw/Firmware.cmake +++ b/product/fvp-baser-aemv8r/fw/Firmware.cmake @@ -18,4 +18,5 @@ list(APPEND SCP_MODULES "armv8r-mpu" "pl011" "gicx00" + "sp805" ) diff --git a/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c b/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c index 641ac228d..6596db97d 100644 --- a/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c +++ b/product/fvp-baser-aemv8r/fw/config_armv8r_mpu.c @@ -60,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_sp805.c b/product/fvp-baser-aemv8r/fw/config_sp805.c new file mode 100644 index 000000000..1ff23f2af --- /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/fvp_baser_aemv8r_mmap.h b/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h index 03499fb0a..2d7291d9b 100644 --- a/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h +++ b/product/fvp-baser-aemv8r/fw/fvp_baser_aemv8r_mmap.h @@ -23,5 +23,7 @@ #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 */ -- GitLab