From 466675c23daf37f6f9971b7321910e47c0c0b794 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 16 Sep 2016 10:34:47 -0700 Subject: [PATCH 1/9] zynqmp: Read silicon ID register only once The silicon ID does not change at runtime. Skip the IO access if the ID has been read before. Signed-off-by: Soren Brinkmann Acked-by: Michal Simek --- plat/xilinx/zynqmp/aarch64/zynqmp_common.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c index 60a16058f0..562cac83b2 100644 --- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -49,11 +49,14 @@ const mmap_region_t plat_arm_mmap[] = { static unsigned int zynqmp_get_silicon_ver(void) { - unsigned int ver; + static unsigned int ver; - ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); - ver &= ZYNQMP_SILICON_VER_MASK; - ver >>= ZYNQMP_SILICON_VER_SHIFT; + if (!ver) { + ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + + ZYNQMP_CSU_VERSION_OFFSET); + ver &= ZYNQMP_SILICON_VER_MASK; + ver >>= ZYNQMP_SILICON_VER_SHIFT; + } return ver; } From e89f4af7dd308d43b3a1bd922b514ea9e0b030c7 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 16 Sep 2016 10:31:06 -0700 Subject: [PATCH 2/9] zynqmp: Do not alter system counter On ZynqMP the FSBL will configure the system counter. Hence, remove the initialization of the system counter with hardcoded values from the ATF and use the setup provided by the bootloader. Signed-off-by: Soren Brinkmann Acked-by: Michal Simek --- plat/xilinx/zynqmp/aarch64/zynqmp_common.c | 40 ++++++---------------- plat/xilinx/zynqmp/zynqmp_def.h | 6 ---- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c index 562cac83b2..11a9e760ed 100644 --- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -77,22 +77,6 @@ unsigned int zynqmp_get_uart_clk(void) return 100000000; } -static unsigned int zynqmp_get_system_timer_freq(void) -{ - unsigned int ver = zynqmp_get_silicon_ver(); - - switch (ver) { - case ZYNQMP_CSU_VERSION_VELOCE: - return 10000; - case ZYNQMP_CSU_VERSION_EP108: - return 4000000; - case ZYNQMP_CSU_VERSION_QEMU: - return 50000000; - } - - return 100000000; -} - unsigned int zynqmp_get_silicon_id(void) { uint32_t id; @@ -284,25 +268,21 @@ void zynqmp_config_setup(void) { zynqmp_discover_pmufw(); zynqmp_print_platform_name(); - - /* Global timer init - Program time stamp reference clk */ - uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL); - val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; - mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val); - - /* Program freq register in System counter and enable system counter. */ - mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq()); - mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN); - generic_delay_timer_init(); } unsigned int plat_get_syscnt_freq2(void) { - unsigned int counter_base_frequency; + unsigned int ver = zynqmp_get_silicon_ver(); - /* FIXME: Read the frequency from Frequency modes table */ - counter_base_frequency = zynqmp_get_system_timer_freq(); + switch (ver) { + case ZYNQMP_CSU_VERSION_VELOCE: + return 10000; + case ZYNQMP_CSU_VERSION_EP108: + return 4000000; + case ZYNQMP_CSU_VERSION_QEMU: + return 50000000; + } - return counter_base_frequency; + return mmio_read_32(IOU_SCNTRS_BASEFREQ); } diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h index 65bc25f821..1f1bf0f4c9 100644 --- a/plat/xilinx/zynqmp/zynqmp_def.h +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -69,12 +69,9 @@ /* CRL registers and bitfields */ #define CRL_APB_BASE 0xFF5E0000 #define CRL_APB_RPLL_CTRL (CRL_APB_BASE + 0x30) -#define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_BASE + 0x128) #define CRL_APB_BOOT_MODE_USER (CRL_APB_BASE + 0x200) #define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218) -#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 24) - #define CRL_APB_RPLL_CTRL_BYPASS (1 << 3) #define CRL_APB_RESET_CTRL_SOFT_RESET (1 << 4) @@ -84,11 +81,8 @@ /* system counter registers and bitfields */ #define IOU_SCNTRS_BASE 0xFF260000 -#define IOU_SCNTRS_CONTROL (IOU_SCNTRS_BASE + 0) #define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20) -#define IOU_SCNTRS_CONTROL_EN (1 << 0) - /* APU registers and bitfields */ #define APU_BASE 0xFD5C0000 #define APU_CONFIG_0 (APU_BASE + 0x20) From dc0c5a42d61e5efc7d85fffffc22a910130227d2 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Thu, 22 Sep 2016 11:35:47 -0700 Subject: [PATCH 3/9] zynqmp: pm: Allow obtaining additional return values from FW Allow reading more than just a single value from the message buffer. Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 24 +++++++++++----------- plat/xilinx/zynqmp/pm_service/pm_ipi.c | 19 ++++++++++------- plat/xilinx/zynqmp/pm_service/pm_ipi.h | 2 +- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index e859ee39ee..a466687184 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -101,7 +101,7 @@ enum pm_ret_status pm_self_suspend(enum pm_node_id nid, /* Send request to the PMU */ PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, state, address, (address >> 32)); - return pm_ipi_send_sync(proc, payload, NULL); + return pm_ipi_send_sync(proc, payload, NULL, 0); } /** @@ -123,7 +123,7 @@ enum pm_ret_status pm_req_suspend(enum pm_node_id target, /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state); if (ack == REQ_ACK_BLOCKING) - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } @@ -165,7 +165,7 @@ enum pm_ret_status pm_req_wakeup(enum pm_node_id target, encoded_address >> 32, ack); if (ack == REQ_ACK_BLOCKING) - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } @@ -187,7 +187,7 @@ enum pm_ret_status pm_force_powerdown(enum pm_node_id target, PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack); if (ack == REQ_ACK_BLOCKING) - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } @@ -272,7 +272,7 @@ enum pm_ret_status pm_req_node(enum pm_node_id nid, PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack); if (ack == REQ_ACK_BLOCKING) - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } @@ -299,7 +299,7 @@ enum pm_ret_status pm_set_requirement(enum pm_node_id nid, ack); if (ack == REQ_ACK_BLOCKING) - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } @@ -348,7 +348,7 @@ enum pm_ret_status pm_get_api_version(unsigned int *version) /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION); - return pm_ipi_send_sync(primary_proc, payload, version); + return pm_ipi_send_sync(primary_proc, payload, version, 1); } /** @@ -418,7 +418,7 @@ enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid, /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type); - return pm_ipi_send_sync(primary_proc, payload, result); + return pm_ipi_send_sync(primary_proc, payload, result, 1); } /* Direct-Control API functions */ @@ -454,7 +454,7 @@ enum pm_ret_status pm_reset_get_status(unsigned int reset, /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset); - return pm_ipi_send_sync(primary_proc, payload, reset_status); + return pm_ipi_send_sync(primary_proc, payload, reset_status, 1); } /** @@ -476,7 +476,7 @@ enum pm_ret_status pm_mmio_write(uintptr_t address, /* Send request to the PMU */ PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value); - return pm_ipi_send_sync(primary_proc, payload, NULL); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** @@ -495,7 +495,7 @@ enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value) /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address); - return pm_ipi_send_sync(primary_proc, payload, value); + return pm_ipi_send_sync(primary_proc, payload, value, 1); } /** @@ -539,5 +539,5 @@ enum pm_ret_status pm_fpga_get_status(unsigned int *value) /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS); - return pm_ipi_send_sync(primary_proc, payload, value); + return pm_ipi_send_sync(primary_proc, payload, value, 1); } diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c index c3e7ccb505..6648fec732 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -188,13 +188,15 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, /** * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt * @proc Pointer to the processor who is waiting and reading response - * @value Used to return value from 2nd IPI buffer element (optional) + * @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 */ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, - unsigned int *value) + unsigned int *value, size_t count) { + size_t i; uintptr_t buffer_base = proc->ipi->buffer_base + IPI_BUFFER_TARGET_PMU_OFFSET + IPI_BUFFER_RESP_OFFSET; @@ -208,8 +210,10 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, * buf-2: unused * buf-3: unused */ - if (value != NULL) - *value = mmio_read_32(buffer_base + PAYLOAD_ARG_SIZE); + for (i = 1; i <= count; i++) { + *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); + value++; + } return mmio_read_32(buffer_base); } @@ -218,7 +222,8 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, * pm_ipi_send_sync() - Sends IPI request to the PMU * @proc Pointer to the processor who is initiating request * @payload API id and call arguments to be written in IPI buffer - * @value Used to return value from 2nd IPI buffer element (optional) + * @value Used to return value from IPI buffer element (optional) + * @count Number of values to return in @value * * Send an IPI request to the power controller and wait for it to be handled. * @@ -227,7 +232,7 @@ static enum pm_ret_status pm_ipi_buff_read(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) + unsigned int *value, size_t count) { enum pm_ret_status ret; @@ -237,7 +242,7 @@ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, if (ret != PM_RET_SUCCESS) goto unlock; - ret = pm_ipi_buff_read(proc, value); + ret = pm_ipi_buff_read(proc, value, count); unlock: bakery_lock_release(&pm_secure_lock); diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.h b/plat/xilinx/zynqmp/pm_service/pm_ipi.h index d92e648c86..108aef4961 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.h +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.h @@ -39,6 +39,6 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT]); enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], - unsigned int *value); + unsigned int *value, size_t count); #endif /* _PM_IPI_H_ */ From 46cb684f32f1aad8fb7f104a331b90b2a122505b Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Thu, 22 Sep 2016 12:21:11 -0700 Subject: [PATCH 4/9] zynqmp: pm: Plumb get_chipid through FW interface Use the PMUFW get_chipid call to obtain IDCODE and version register. Cc: Michal Simek Cc: Siva Durga Prasad Paladugu Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/aarch64/zynqmp_common.c | 24 ++++++++++----------- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 16 ++++++++++++++ plat/xilinx/zynqmp/pm_service/pm_api_sys.h | 2 ++ plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 8 ++++++- plat/xilinx/zynqmp/zynqmp_private.h | 1 - 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c index 11a9e760ed..8e461d3ced 100644 --- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -77,18 +77,6 @@ unsigned int zynqmp_get_uart_clk(void) return 100000000; } -unsigned int zynqmp_get_silicon_id(void) -{ - uint32_t id; - - id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); - - id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK; - id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; - - return id; -} - #if LOG_LEVEL >= LOG_LEVEL_NOTICE static const struct { unsigned int id; @@ -140,6 +128,18 @@ static const struct { }, }; +static unsigned int zynqmp_get_silicon_id(void) +{ + uint32_t id; + + id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); + + id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK; + id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; + + return id; +} + static char *zynqmp_get_silicon_idcode_name(void) { unsigned int id; diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index a466687184..b990606064 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -541,3 +541,19 @@ enum pm_ret_status pm_fpga_get_status(unsigned int *value) PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS); return pm_ipi_send_sync(primary_proc, payload, value, 1); } + +/** + * pm_get_chipid() - Read silicon ID registers + * @value Buffer for return values. Must be large enough + * to hold 8 bytes. + * + * @return Returns silicon ID registers + */ +enum pm_ret_status pm_get_chipid(uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID); + return pm_ipi_send_sync(primary_proc, payload, value, 2); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h index 26d83e75a8..1f68118010 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -115,4 +115,6 @@ enum pm_ret_status pm_fpga_load(uint32_t address_high, uint32_t flags); enum pm_ret_status pm_fpga_get_status(unsigned int *value); +enum pm_ret_status pm_get_chipid(uint32_t *value); + #endif /* _PM_API_SYS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index 9c08ffb9a3..d635583401 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -242,7 +242,13 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, } case PM_GET_CHIPID: - SMC_RET1(handle, zynqmp_get_silicon_id()); + { + uint32_t result[2]; + + ret = pm_get_chipid(result); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32), + result[1]); + } default: WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h index abcdebc39f..ddef37b8f3 100644 --- a/plat/xilinx/zynqmp/zynqmp_private.h +++ b/plat/xilinx/zynqmp/zynqmp_private.h @@ -39,7 +39,6 @@ void zynqmp_config_setup(void); unsigned int zynqmp_get_uart_clk(void); int zynqmp_is_pmu_up(void); unsigned int zynqmp_get_bootmode(void); -unsigned int zynqmp_get_silicon_id(void); /* For FSBL handover */ void fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info, From 83531703218d5bf4d9327464806d7442732250da Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 2 Sep 2016 09:50:54 -0700 Subject: [PATCH 5/9] zynqmp: PM: Migrate to new shutdown interface Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/plat_psci.c | 6 ++++-- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 4 ++-- plat/xilinx/zynqmp/pm_service/pm_api_sys.h | 2 +- plat/xilinx/zynqmp/pm_service/pm_defs.h | 11 +++++++++++ plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c index 55227ea944..7f7e0322d2 100644 --- a/plat/xilinx/zynqmp/plat_psci.c +++ b/plat/xilinx/zynqmp/plat_psci.c @@ -270,7 +270,8 @@ static void __dead2 zynqmp_system_off(void) plat_arm_interconnect_exit_coherency(); /* Send the power down request to the PMU */ - pm_system_shutdown(0); + pm_system_shutdown(PMF_SHUTDOWN_TYPE_SHUTDOWN, + PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM); while (1) wfi(); @@ -304,7 +305,8 @@ static void __dead2 zynqmp_system_reset(void) plat_arm_interconnect_exit_coherency(); /* Send the system reset request to the PMU */ - pm_system_shutdown(1); + pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, + PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM); while (1) wfi(); diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index b990606064..9416016922 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -243,11 +243,11 @@ enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, * * @return Returns status, either success or error+reason */ -enum pm_ret_status pm_system_shutdown(unsigned int restart) +enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype) { uint32_t payload[PAYLOAD_ARG_CNT]; - PM_PACK_PAYLOAD2(payload, PM_SYSTEM_SHUTDOWN, restart); + PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype); return pm_ipi_send(primary_proc, payload); } diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h index 1f68118010..8cbd13b2f5 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -61,7 +61,7 @@ enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, enum pm_node_id wkup_node, unsigned int enable); -enum pm_ret_status pm_system_shutdown(unsigned int restart); +enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype); enum pm_ret_status pm_init_suspend_cb(enum pm_suspend_reason reason, unsigned int latency, diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h index aec335a5e7..0c071c1f27 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_defs.h +++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h @@ -225,4 +225,15 @@ enum pm_boot_status { PM_BOOT_ERROR, }; +enum pm_shutdown_type { + PMF_SHUTDOWN_TYPE_SHUTDOWN, + PMF_SHUTDOWN_TYPE_RESET, +}; + +enum pm_shutdown_subtype { + PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM, + PMF_SHUTDOWN_SUBTYPE_PS_ONLY, + PMF_SHUTDOWN_SUBTYPE_SYSTEM, +}; + #endif /* _PM_DEFS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index d635583401..c062392e48 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -152,7 +152,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, SMC_RET1(handle, (uint64_t)ret); case PM_SYSTEM_SHUTDOWN: - ret = pm_system_shutdown(pm_arg[0]); + ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_REQ_NODE: From 79c96f8afe0b8595b395cf74a7edb758fa98b03e Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 27 May 2016 08:56:53 -0700 Subject: [PATCH 6/9] zynqmp: Fix UART1 base address Cc: Michal Simek Reported-by: Jonas Karlsson Signed-off-by: Soren Brinkmann Acked-by: Michal Simek --- plat/xilinx/zynqmp/zynqmp_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h index 1f1bf0f4c9..37951e03d8 100644 --- a/plat/xilinx/zynqmp/zynqmp_def.h +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -140,7 +140,7 @@ * UART related constants ******************************************************************************/ #define ZYNQMP_UART0_BASE 0xFF000000 -#define ZYNQMP_UART1_BASE 0xFF001000 +#define ZYNQMP_UART1_BASE 0xFF010000 #if ZYNQMP_CONSOLE_IS(cadence) # define ZYNQMP_UART_BASE ZYNQMP_UART0_BASE From 9f8a2e242592f184822192af463dd4bb90fa202c Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Wed, 16 Nov 2016 15:50:14 -0800 Subject: [PATCH 7/9] zynqmp: Remove dead code Remove dead code pieces and stale comments. Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/include/platform_def.h | 1 - plat/xilinx/zynqmp/pm_service/pm_client.c | 1 - plat/xilinx/zynqmp/pm_service/pm_ipi.c | 1 - plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 1 - plat/xilinx/zynqmp/zynqmp_def.h | 1 - 5 files changed, 5 deletions(-) diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h index 3c1a9e5c8a..047aeaa16d 100644 --- a/plat/xilinx/zynqmp/include/platform_def.h +++ b/plat/xilinx/zynqmp/include/platform_def.h @@ -113,7 +113,6 @@ * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \ - IRQ_SEC_IPI_APU, \ ARM_IRQ_SEC_SGI_0, \ ARM_IRQ_SEC_SGI_1, \ ARM_IRQ_SEC_SGI_2, \ diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c index b77a1cf091..e102b4f2cc 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_client.c +++ b/plat/xilinx/zynqmp/pm_service/pm_client.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "pm_api_sys.h" #include "pm_client.h" #include "pm_ipi.h" diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c index 6648fec732..5fd9d550d1 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -96,7 +96,6 @@ const struct pm_ipi apu_ipi = { * Any other return value will cause the framework to ignore * the service * - * Enable interrupts at registered entrance in IPI peripheral * Called from pm_setup initialization function */ int pm_ipi_init(void) diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index c062392e48..34823757ad 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -68,7 +68,6 @@ static struct { * * Called from sip_svc_setup initialization function with the * rt_svc_init signature. - * */ int pm_setup(void) { diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h index 37951e03d8..bdca3b490e 100644 --- a/plat/xilinx/zynqmp/zynqmp_def.h +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -122,7 +122,6 @@ #define BASE_GICH_BASE 0xF9040000 #define BASE_GICV_BASE 0xF9060000 -#define IRQ_SEC_IPI_APU 67 #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 From a76c3697a0e898c5d135194f7f31afd13b72ef81 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 30 Sep 2016 11:30:21 -0700 Subject: [PATCH 8/9] zynqmp: pm: Enable IPI IRQ when API version is probed The IPI hardware is secure and managed by ATF, nevertheless we deliver the IRQ to the rich OS. The IRQ is needed to receive PM callbacks. Enable the IPI interrupt when the rich OS probes the API version. Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 2 +- plat/xilinx/zynqmp/pm_service/pm_ipi.c | 10 ++++++++++ plat/xilinx/zynqmp/pm_service/pm_ipi.h | 2 ++ plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 10 +++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index 9416016922..c7b8b9a7de 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -396,7 +396,7 @@ enum pm_ret_status pm_register_notifier(enum pm_node_id nid, PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER, nid, event, wake, enable); - return pm_ipi_send(primary_proc, payload); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c index 5fd9d550d1..df3b854d83 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -248,3 +248,13 @@ unlock: return ret; } + +void pm_ipi_irq_enable(void) +{ + mmio_write_32(IPI_APU_IER, IPI_APU_IXR_PMU_0_MASK); +} + +void pm_ipi_irq_disable(void) +{ + mmio_write_32(IPI_APU_IDR, 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 108aef4961..fefe89ab7c 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.h +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.h @@ -40,5 +40,7 @@ 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_irq_enable(void); +void pm_ipi_irq_disable(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 34823757ad..8a4bba617b 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -173,11 +173,19 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, case PM_GET_API_VERSION: /* Check is PM API version already verified */ - if (pm_ctx.api_version == PM_VERSION) + if (pm_ctx.api_version == PM_VERSION) { SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | ((uint64_t)PM_VERSION << 32)); + } ret = pm_get_api_version(&pm_ctx.api_version); + /* + * 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(); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)pm_ctx.api_version << 32)); From 300cbb0bdb762dbbf716acc9606529535fd6c038 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 30 Sep 2016 14:24:25 -0700 Subject: [PATCH 9/9] zynqmp: pm: Add SiP call to obtain PM callback data The callback IRQ is delivered to the NS OS. Provide an interface to allow the NS OS to obtain the callback data from the secure HW. Signed-off-by: Soren Brinkmann --- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 13 +++++++++ plat/xilinx/zynqmp/pm_service/pm_api_sys.h | 1 + plat/xilinx/zynqmp/pm_service/pm_ipi.c | 30 +++++++++++++++++++++ plat/xilinx/zynqmp/pm_service/pm_ipi.h | 2 ++ plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 12 +++++++++ 5 files changed, 58 insertions(+) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index c7b8b9a7de..15e12fa8e7 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 8cbd13b2f5..7e229488fd 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 df3b854d83..9148f90942 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 fefe89ab7c..b314b80aee 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 8a4bba617b..036ed8a202 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);