diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c index de36efc0a..8b8714cb6 100644 --- a/plat/xilinx/versal/bl31_versal_setup.c +++ b/plat/xilinx/versal/bl31_versal_setup.c @@ -117,6 +117,40 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); } +static interrupt_type_handler_t type_el3_interrupt_handler; + +int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler) +{ + /* Validate 'handler'*/ + if (!handler) { + return -EINVAL; + } + + type_el3_interrupt_handler = handler; + + return 0; +} + +static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags, + void *handle, void *cookie) +{ + uint32_t intr_id; + interrupt_type_handler_t handler; + + intr_id = plat_ic_get_pending_interrupt_id(); + /* Currently we support one interrupt */ + if (intr_id != PLAT_VERSAL_IPI_IRQ) { + WARN("Unexpected interrupt call: 0x%x\n", intr_id); + return 0; + } + + handler = type_el3_interrupt_handler; + if (handler) { + return handler(intr_id, flags, handle, cookie); + } + + return 0; +} void bl31_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ @@ -126,6 +160,15 @@ void bl31_platform_setup(void) void bl31_plat_runtime_setup(void) { + uint64_t flags = 0; + uint64_t rc; + + set_interrupt_rm_flag(flags, NON_SECURE); + rc = register_interrupt_type_handler(INTR_TYPE_EL3, + rdo_el3_interrupt_handler, flags); + if (rc) { + panic(); + } } /* diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h index e302096eb..d12d13af8 100644 --- a/plat/xilinx/versal/include/plat_private.h +++ b/plat/xilinx/versal/include/plat_private.h @@ -8,6 +8,7 @@ #define PLAT_PRIVATE_H #include +#include void versal_config_setup(void); @@ -22,5 +23,10 @@ void plat_versal_gic_save(void); void plat_versal_gic_resume(void); unsigned int versal_calc_core_pos(u_register_t mpidr); +/* + * Register handler to specific GIC entrance + * for INTR_TYPE_EL3 type of interrupt + */ +int request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler); #endif /* PLAT_PRIVATE_H */ diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h index 4cdaea219..8b513ef3a 100644 --- a/plat/xilinx/versal/include/platform_def.h +++ b/plat/xilinx/versal/include/platform_def.h @@ -91,11 +91,14 @@ */ #define PLAT_VERSAL_G1S_IRQS VERSAL_IRQ_SEC_PHY_TIMER #define PLAT_VERSAL_G0_IRQS VERSAL_IRQ_SEC_PHY_TIMER +#define PLAT_VERSAL_IPI_IRQ 62 #define PLAT_VERSAL_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(VERSAL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) -#define PLAT_VERSAL_G0_IRQ_PROPS(grp) +#define PLAT_VERSAL_G0_IRQ_PROPS(grp) \ + INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_EDGE), \ #endif /* PLATFORM_DEF_H */ diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c index a57854374..15fe187eb 100644 --- a/plat/xilinx/versal/pm_service/pm_api_sys.c +++ b/plat/xilinx/versal/pm_service/pm_api_sys.c @@ -15,6 +15,8 @@ #include "pm_api_sys.h" #include "pm_client.h" #include "pm_defs.h" +#include "pm_svc_main.h" +#include "../drivers/arm/gic/v3/gicv3_private.h" /********************************************************************* * Target module IDs macros @@ -22,6 +24,7 @@ #define LIBPM_MODULE_ID 0x2 #define LOADER_MODULE_ID 0x7 +#define MODE 0x80000000 /* default shutdown/reboot scope is system(2) */ static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM; @@ -861,6 +864,7 @@ enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, uint32_t flag) { uint32_t payload[PAYLOAD_ARG_CNT]; + int ret; switch (ioctl_id) { case IOCTL_SET_PLL_FRAC_MODE: @@ -871,6 +875,15 @@ enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag); case IOCTL_GET_PLL_FRAC_DATA: return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag); + case IOCTL_SET_SGI: + /* Get the sgi number */ + ret = pm_register_sgi(arg1); + if (ret) { + return PM_RET_ERROR_ARGS; + } + gicd_write_irouter(gicv3_driver_data->gicd_base, + PLAT_VERSAL_IPI_IRQ, MODE); + return PM_RET_SUCCESS; default: /* Send request to the PMC */ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_IOCTL, diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h index 793f75009..ccb2617ca 100644 --- a/plat/xilinx/versal/pm_service/pm_defs.h +++ b/plat/xilinx/versal/pm_service/pm_defs.h @@ -92,6 +92,7 @@ #define IOCTL_GET_PLL_FRAC_MODE 9 #define IOCTL_SET_PLL_FRAC_DATA 10 #define IOCTL_GET_PLL_FRAC_DATA 11 +#define IOCTL_SET_SGI 25 /* Parameter ID for PLL IOCTLs */ /* Fractional data portion for PLL */ diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c index 55a095662..87ba73278 100644 --- a/plat/xilinx/versal/pm_service/pm_svc_main.c +++ b/plat/xilinx/versal/pm_service/pm_svc_main.c @@ -13,12 +13,64 @@ #include #include #include +#include #include "pm_api_sys.h" #include "pm_client.h" #include "pm_ipi.h" +#include + +#define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U +#define INVALID_SGI 0xFF +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6) /* pm_up = true - UP, pm_up = false - DOWN */ static bool pm_up; +static unsigned int sgi = INVALID_SGI; + +static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, + void *cookie) +{ + int cpu; + unsigned int reg; + + (void)plat_ic_acknowledge_interrupt(); + cpu = plat_my_core_pos() + 1; + + if (sgi != INVALID_SGI) { + reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT)); + write_icc_asgi1r_el1(reg); + } + + /* Clear FIQ */ + plat_ic_end_of_interrupt(id); + + return 0; +} + +/** + * pm_register_sgi() - PM register the IPI interrupt + * + * @sgi - SGI number to be used for communication. + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Update the SGI number to be used. + * + */ +int pm_register_sgi(unsigned int sgi_num) +{ + if (sgi != INVALID_SGI) { + return -EBUSY; + } + + if (sgi_num >= GICV3_MAX_SGI_TARGETS) { + return -EINVAL; + } + + sgi = sgi_num; + return 0; +} /** * pm_setup() - PM service setup @@ -46,6 +98,18 @@ int pm_setup(void) pm_up = true; } + /* + * Enable IPI IRQ + * assume the rich OS is OK to handle callback IRQs now. + * Even if we were wrong, it would not enable the IRQ in + * the GIC. + */ + pm_ipi_irq_enable(primary_proc); + + ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler); + if (ret) { + WARN("BL31: registering IPI interrupt failed\n"); + } return ret; } diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h index 71329ca93..4f8dc2b7f 100644 --- a/plat/xilinx/versal/pm_service/pm_svc_main.h +++ b/plat/xilinx/versal/pm_service/pm_svc_main.h @@ -14,4 +14,5 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags); +int pm_register_sgi(unsigned int sgi_num); #endif /* PM_SVC_MAIN_H */