diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index c7b8b9a7de07cf998490a5c24a4a4c39f18eb62a..15e12fa8e7a10466b136b637047af7581ccf34eb 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -557,3 +557,16 @@ enum pm_ret_status pm_get_chipid(uint32_t *value) PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID); return pm_ipi_send_sync(primary_proc, payload, value, 2); } + +/** + * pm_get_callbackdata() - Read from IPI response buffer + * @data - array of PAYLOAD_ARG_CNT elements + * + * Read value from ipi buffer response buffer. + */ +void pm_get_callbackdata(uint32_t *data, size_t count) +{ + + pm_ipi_buff_read_callb(data, count); + pm_ipi_irq_clear(); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h index 8cbd13b2f54b99f5cbe3c5c0a27817d443934998..7e229488fd3b3439870c4392ec3e6b1e6db39155 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -116,5 +116,6 @@ enum pm_ret_status pm_fpga_load(uint32_t address_high, enum pm_ret_status pm_fpga_get_status(unsigned int *value); enum pm_ret_status pm_get_chipid(uint32_t *value); +void pm_get_callbackdata(uint32_t *data, size_t count); #endif /* _PM_API_SYS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c index df3b854d83ef2a1b6a06ae7a19c6f65cee36f590..9148f90942dfc20ef4878f4ecb20f8e9cb837437 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -56,6 +56,8 @@ #define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U #define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U +#define IPI_BUFFER_MAX_WORDS 8 + #define IPI_BUFFER_REQ_OFFSET 0x0U #define IPI_BUFFER_RESP_OFFSET 0x20U @@ -217,6 +219,29 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, return mmio_read_32(buffer_base); } +/** + * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt + * @value Used to return value from IPI buffer element (optional) + * @count Number of values to return in @value + * + * @return Returns status, either success or error+reason + */ +void pm_ipi_buff_read_callb(unsigned int *value, size_t count) +{ + size_t i; + uintptr_t buffer_base = IPI_BUFFER_PMU_BASE + + IPI_BUFFER_TARGET_APU_OFFSET + + IPI_BUFFER_REQ_OFFSET; + + if (count > IPI_BUFFER_MAX_WORDS) + count = IPI_BUFFER_MAX_WORDS; + + for (i = 0; i <= count; i++) { + *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); + value++; + } +} + /** * pm_ipi_send_sync() - Sends IPI request to the PMU * @proc Pointer to the processor who is initiating request @@ -258,3 +283,8 @@ void pm_ipi_irq_disable(void) { mmio_write_32(IPI_APU_IDR, IPI_APU_IXR_PMU_0_MASK); } + +void pm_ipi_irq_clear(void) +{ + mmio_write_32(IPI_APU_ISR, IPI_APU_IXR_PMU_0_MASK); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.h b/plat/xilinx/zynqmp/pm_service/pm_ipi.h index fefe89ab7c943e90d6f07451241266d82b78a6a6..b314b80aeef7b8d7d50b73fbf117f23aaf7443f3 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.h +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.h @@ -40,7 +40,9 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], unsigned int *value, size_t count); +void pm_ipi_buff_read_callb(unsigned int *value, size_t count); void pm_ipi_irq_enable(void); void pm_ipi_irq_disable(void); +void pm_ipi_irq_clear(void); #endif /* _PM_IPI_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index 8a4bba617beb5c0b8c1c5932514448d6168074ba..036ed8a20299608a88a85db2e8d0e67f4f5d6a7a 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -42,6 +42,8 @@ #include "pm_ipi.h" #include "../zynqmp_private.h" +#define PM_GET_CALLBACK_DATA 0xa01 + /* 0 - UP, !0 - DOWN */ static int32_t pm_down = !0; @@ -257,6 +259,16 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, result[1]); } + case PM_GET_CALLBACK_DATA: + { + uint32_t result[4]; + + pm_get_callbackdata(result, sizeof(result)); + SMC_RET2(handle, + (uint64_t)result[0] | ((uint64_t)result[1] << 32), + (uint64_t)result[2] | ((uint64_t)result[3] << 32)); + } + default: WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK);