diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst index 231286e..95c89a8 100644 --- a/docs/plat/xilinx-versal.rst +++ b/docs/plat/xilinx-versal.rst @@ -14,7 +14,7 @@ make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31 ``` -To build ATF for different platform (for now its just versal virtual "versal_virt") +To build ATF for different platform (supported are "silicon"(default) and "versal_virt") ```bash make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31 ``` diff --git a/plat/xilinx/common/include/pm_client.h b/plat/xilinx/common/include/pm_client.h new file mode 100644 index 0000000..e91bb8f --- /dev/null +++ b/plat/xilinx/common/include/pm_client.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Contains APU specific macros and macros to be defined depending on + * the execution environment. + */ + +#ifndef PM_CLIENT_H +#define PM_CLIENT_H + +#include "pm_common.h" +#include "pm_defs.h" + +/* Functions to be implemented by each PU */ +void pm_client_suspend(const struct pm_proc *proc, unsigned int state); +void pm_client_abort_suspend(void); +void pm_client_wakeup(const struct pm_proc *proc); + +/* Global variables to be set in pm_client.c */ +extern const struct pm_proc *primary_proc; + +#ifndef VERSAL_PLATFORM +enum pm_ret_status set_ocm_retention(void); +enum pm_ret_status pm_set_suspend_mode(uint32_t mode); +const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid); +#endif + +#endif /* PM_CLIENT_H */ diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c new file mode 100644 index 0000000..f531158 --- /dev/null +++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "ipi_mailbox_svc.h" +#include "../../../services/spd/trusty/smcall.h" + +/********************************************************************* + * Macros definitions + ********************************************************************/ + +/* IPI SMC calls macros: */ +#define IPI_SMC_OPEN_IRQ_MASK 0x00000001U /* IRQ enable bit in IPI + * open SMC call + */ +#define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001U /* Flag to indicate if + * IPI notification needs + * to be blocking. + */ +#define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001U /* Flag to indicate if + * notification interrupt + * to be disabled. + */ +#define IPI_SMC_ACK_EIRQ_MASK 0x00000001U /* Flag to indicate if + * notification interrupt + * to be enable. + */ + +#define UNSIGNED32_MASK 0xFFFFFFFFU /* 32bit mask */ + +/** + * ipi_smc_handler() - SMC handler for IPI SMC calls + * + * @smc_fid - Function identifier + * @x1 - x4 - Arguments + * @cookie - Unused + * @handler - Pointer to caller's context structure + * + * @return - Unused + * + * Determines that smc_fid is valid and supported PM SMC Function ID from the + * list of pm_api_ids, otherwise completes the request with + * the unknown SMC Function ID + * + * The SMC calls for PM service are forwarded from SIP Service SMC handler + * function with rt_svc_handle signature + */ +uint64_t ipi_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 ret; + uint32_t ipi_local_id; + uint32_t ipi_remote_id; + unsigned int is_secure; + + ipi_local_id = x1 & UNSIGNED32_MASK; + ipi_remote_id = x2 & UNSIGNED32_MASK; + + if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP) + is_secure = 1; + else + is_secure = 0; + + /* Validate IPI mailbox access */ + ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure); + if (ret) + SMC_RET1(handle, ret); + + switch (SMC_FUNCTION(smc_fid)) { + case IPI_MAILBOX_OPEN: + ipi_mb_open(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_RELEASE: + ipi_mb_release(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_STATUS_ENQUIRY: + { + int disable_irq; + + disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0; + ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id); + if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq) + ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, ret); + } + case IPI_MAILBOX_NOTIFY: + { + uint32_t is_blocking; + + is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0; + ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking); + SMC_RET1(handle, 0); + } + case IPI_MAILBOX_ACK: + { + int enable_irq; + + enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0; + ipi_mb_ack(ipi_local_id, ipi_remote_id); + if (enable_irq) + ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + } + case IPI_MAILBOX_ENABLE_IRQ: + ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_DISABLE_IRQ: + ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + default: + WARN("Unimplemented IPI service call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h new file mode 100644 index 0000000..10682d8 --- /dev/null +++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* ZynqMP IPI mailbox doorbell service enums and defines */ + +#ifndef IPI_MAILBOX_SVC_H +#define IPI_MAILBOX_SVC_H + +#include + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +/* IPI SMC function numbers enum definition */ +enum ipi_api_id { + /* IPI mailbox operations functions: */ + IPI_MAILBOX_OPEN = 0x1000, + IPI_MAILBOX_RELEASE, + IPI_MAILBOX_STATUS_ENQUIRY, + IPI_MAILBOX_NOTIFY, + IPI_MAILBOX_ACK, + IPI_MAILBOX_ENABLE_IRQ, + IPI_MAILBOX_DISABLE_IRQ +}; + +/********************************************************************* + * IPI mailbox service APIs declarations + ********************************************************************/ + +/* IPI SMC handler */ +uint64_t ipi_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); + +#endif /* IPI_MAILBOX_SVC_H */ diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c index 587b797..825421e 100644 --- a/plat/xilinx/versal/aarch64/versal_common.c +++ b/plat/xilinx/versal/aarch64/versal_common.c @@ -1,18 +1,18 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include #include #include #include #include #include -#include "../versal_def.h" -#include "../versal_private.h" - /* * Table of regions to map using the MMU. * This doesn't include TZRAM as the 'mem_layout' argument passed to @@ -22,6 +22,8 @@ MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(FPD_MAINCCI_BASE, FPD_MAINCCI_SIZE, MT_DEVICE | MT_RW | + MT_SECURE), { 0 } }; @@ -39,11 +41,10 @@ { uint32_t val; - versal_print_platform_name(); + /* Configure IPI data for versal */ + versal_ipi_config_table_init(); - mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL, - VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT | - (0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT)); + versal_print_platform_name(); /* Global timer init - Program time stamp reference clk */ val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL); diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c index d7e07e0..6b56307 100644 --- a/plat/xilinx/versal/bl31_versal_setup.c +++ b/plat/xilinx/versal/bl31_versal_setup.c @@ -1,12 +1,13 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include - +#include +#include #include #include #include @@ -15,8 +16,6 @@ #include #include -#include "versal_private.h" - static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static console_pl011_t versal_runtime_console; @@ -104,6 +103,9 @@ */ void bl31_plat_arch_setup(void) { + plat_arm_interconnect_init(); + plat_arm_interconnect_enter_coherency(); + const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE), diff --git a/plat/xilinx/versal/include/plat_ipi.h b/plat/xilinx/versal/include/plat_ipi.h new file mode 100644 index 0000000..6b08f32 --- /dev/null +++ b/plat/xilinx/versal/include/plat_ipi.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Versal IPI management enums and defines */ + +#ifndef PLAT_IPI_H +#define PLAT_IPI_H + +#include +#include + +/********************************************************************* + * IPI agent IDs macros + ********************************************************************/ +#define IPI_ID_PMC 1U +#define IPI_ID_APU 2U +#define IPI_ID_RPU0 3U +#define IPI_ID_RPU1 4U +#define IPI_ID_3 5U +#define IPI_ID_4 6U +#define IPI_ID_5 7U + +/********************************************************************* + * IPI message buffers + ********************************************************************/ +#define IPI_BUFFER_BASEADDR 0xFF3F0000U + +#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U) +#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U) + +#define IPI_BUFFER_TARGET_APU_OFFSET 0x0U +#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U + +#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE +#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE + +#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET +#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET + +#define IPI_BUFFER_MAX_WORDS 8 + +#define IPI_BUFFER_REQ_OFFSET 0x0U +#define IPI_BUFFER_RESP_OFFSET 0x20U + +/********************************************************************* + * Platform specific IPI API declarations + ********************************************************************/ + +/* Configure IPI table for versal */ +void versal_ipi_config_table_init(void); + +#endif /* PLAT_IPI_H */ diff --git a/plat/xilinx/versal/include/plat_pm_common.h b/plat/xilinx/versal/include/plat_pm_common.h new file mode 100644 index 0000000..2d00801 --- /dev/null +++ b/plat/xilinx/versal/include/plat_pm_common.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Contains platform specific definitions of commonly used macros data types + * for PU Power Management. This file should be common for all PU's. + */ + +#ifndef PLAT_PM_COMMON_H +#define PLAT_PM_COMMON_H + +#include +#include +#include "pm_defs.h" + +#define PAYLOAD_ARG_CNT 6U +#define PAYLOAD_ARG_SIZE 4U /* size in bytes */ + +#define VERSAL_TZ_VERSION_MAJOR 1 +#define VERSAL_TZ_VERSION_MINOR 0 +#define VERSAL_TZ_VERSION ((VERSAL_TZ_VERSION_MAJOR << 16) | \ + VERSAL_TZ_VERSION_MINOR) +#endif /* PLAT_PM_COMMON_H */ diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h new file mode 100644 index 0000000..e302096 --- /dev/null +++ b/plat/xilinx/versal/include/plat_private.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_PRIVATE_H +#define PLAT_PRIVATE_H + +#include + +void versal_config_setup(void); + +const mmap_region_t *plat_versal_get_mmap(void); + +void plat_versal_gic_driver_init(void); +void plat_versal_gic_init(void); +void plat_versal_gic_cpuif_enable(void); +void plat_versal_gic_cpuif_disable(void); +void plat_versal_gic_pcpu_init(void); +void plat_versal_gic_save(void); +void plat_versal_gic_resume(void); + +unsigned int versal_calc_core_pos(u_register_t mpidr); + +#endif /* PLAT_PRIVATE_H */ diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h index 0c4b954..bcc7a93 100644 --- a/plat/xilinx/versal/include/platform_def.h +++ b/plat/xilinx/versal/include/platform_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,8 +8,7 @@ #define PLATFORM_DEF_H #include - -#include "../versal_def.h" +#include "versal_def.h" /******************************************************************************* * Generic platform constants @@ -32,7 +31,7 @@ * little space for growth. */ #ifndef VERSAL_ATF_MEM_BASE -# define BL31_BASE 0xfffea000 +# define BL31_BASE 0xfffe0000 # define BL31_LIMIT 0xffffffff #else # define BL31_BASE (VERSAL_ATF_MEM_BASE) @@ -76,7 +75,7 @@ ******************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) -#define MAX_MMAP_REGIONS 7 +#define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 5 #define CACHE_WRITEBACK_SHIFT 6 diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h new file mode 100644 index 0000000..94bd321 --- /dev/null +++ b/plat/xilinx/versal/include/versal_def.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef VERSAL_DEF_H +#define VERSAL_DEF_H + +#include + +/* List all consoles */ +#define VERSAL_CONSOLE_ID_pl011 1 +#define VERSAL_CONSOLE_ID_pl011_0 1 +#define VERSAL_CONSOLE_ID_pl011_1 2 +#define VERSAL_CONSOLE_ID_dcc 3 + +#define VERSAL_CONSOLE_IS(con) (VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE) + +/* List all supported platforms */ +#define VERSAL_PLATFORM_ID_versal_virt 1 +#define VERSAL_PLATFORM_ID_silicon 4 + +#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM) + +/* Firmware Image Package */ +#define VERSAL_PRIMARY_CPU 0 + +/******************************************************************************* + * memory map related constants + ******************************************************************************/ +#define DEVICE0_BASE 0xFF000000 +#define DEVICE0_SIZE 0x00E00000 +#define DEVICE1_BASE 0xF9000000 +#define DEVICE1_SIZE 0x00800000 + +/* CRL */ +#define VERSAL_CRL 0xFF5E0000 +#define VERSAL_CRL_TIMESTAMP_REF_CTRL (VERSAL_CRL + 0x14C) +#define VERSAL_CRL_RST_TIMESTAMP_OFFSET (VERSAL_CRL + 0x348) + +#define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 25) + +/* IOU SCNTRS */ +#define VERSAL_IOU_SCNTRS 0xFF140000 +#define VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG (VERSAL_IOU_SCNTRS + 0x0) +#define VERSAL_IOU_SCNTRS_BASE_FREQ (VERSAL_IOU_SCNTRS + 0x20) + +#define VERSAL_IOU_SCNTRS_CONTROL_EN 1 + +/******************************************************************************* + * IRQ constants + ******************************************************************************/ +#define VERSAL_IRQ_SEC_PHY_TIMER 29 + +/******************************************************************************* + * CCI-400 related constants + ******************************************************************************/ +#define PLAT_ARM_CCI_BASE 0xFD000000 +#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 4 +#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 5 + +/******************************************************************************* + * UART related constants + ******************************************************************************/ +#define VERSAL_UART0_BASE 0xFF000000 +#define VERSAL_UART1_BASE 0xFF010000 + +#if VERSAL_CONSOLE_IS(pl011) +# define VERSAL_UART_BASE VERSAL_UART0_BASE +#elif VERSAL_CONSOLE_IS(pl011_1) +# define VERSAL_UART_BASE VERSAL_UART1_BASE +#else +# error "invalid VERSAL_CONSOLE" +#endif + +#define PLAT_VERSAL_CRASH_UART_BASE VERSAL_UART_BASE +#define PLAT_VERSAL_CRASH_UART_CLK_IN_HZ VERSAL_UART_CLOCK +#define VERSAL_CONSOLE_BAUDRATE VERSAL_UART_BAUDRATE + +/******************************************************************************* + * Platform related constants + ******************************************************************************/ +#if VERSAL_PLATFORM_IS(versal_virt) +# define PLATFORM_NAME "Versal Virt" +# define VERSAL_UART_CLOCK 25000000 +# define VERSAL_UART_BAUDRATE 115200 +# define VERSAL_CPU_CLOCK 2720000 +#elif VERSAL_PLATFORM_IS(silicon) +# define PLATFORM_NAME "Versal Silicon" +# define VERSAL_UART_CLOCK 100000000 +# define VERSAL_UART_BAUDRATE 115200 +# define VERSAL_CPU_CLOCK 100000000 +#endif + +/* Access control register defines */ +#define ACTLR_EL3_L2ACTLR_BIT (1 << 6) +#define ACTLR_EL3_CPUACTLR_BIT (1 << 0) + +/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/ +#define CRF_BASE 0xFD1A0000 +#define CRF_SIZE 0x00600000 + +/* CRF registers and bitfields */ +#define CRF_RST_APU (CRF_BASE + 0X00000300) + +#define CRF_RST_APU_ACPU_RESET (1 << 0) +#define CRF_RST_APU_ACPU_PWRON_RESET (1 << 10) + +#define FPD_MAINCCI_BASE 0xFD000000 +#define FPD_MAINCCI_SIZE 0x00100000 + +/* APU registers and bitfields */ +#define FPD_APU_BASE 0xFD5C0000 +#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20) +#define FPD_APU_RVBAR_L_0 (FPD_APU_BASE + 0x40) +#define FPD_APU_RVBAR_H_0 (FPD_APU_BASE + 0x44) +#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90) + +#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8 +#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1 +#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2 + +/* IPI registers and bitfields */ +#define IPI0_REG_BASE 0xFF330000 +#define IPI0_TRIG_BIT (1 << 2) +#define PMC_IPI_TRIG_BIT (1 << 1) +#define IPI1_REG_BASE 0xFF340000 +#define IPI1_TRIG_BIT (1 << 3) +#define IPI2_REG_BASE 0xFF350000 +#define IPI2_TRIG_BIT (1 << 4) +#define IPI3_REG_BASE 0xFF360000 +#define IPI3_TRIG_BIT (1 << 5) +#define IPI4_REG_BASE 0xFF370000 +#define IPI4_TRIG_BIT (1 << 5) +#define IPI5_REG_BASE 0xFF380000 +#define IPI5_TRIG_BIT (1 << 6) + +#endif /* VERSAL_DEF_H */ diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c index 4a44369..3955085 100644 --- a/plat/xilinx/versal/plat_psci.c +++ b/plat/xilinx/versal/plat_psci.c @@ -1,65 +1,111 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include +#include #include #include #include #include +#include -#include "versal_private.h" +#include "pm_api_sys.h" +#include "pm_client.h" static uintptr_t versal_sec_entry; -static int versal_nopmc_pwr_domain_on(u_register_t mpidr) +static int versal_pwr_domain_on(u_register_t mpidr) { - uint32_t r; unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); + const struct pm_proc *proc; VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; - /* - * program RVBAR - */ - mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry); - mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32); + proc = pm_get_proc(cpu_id); - /* - * clear VINITHI - */ - r = mmio_read_32(FPD_APU_CONFIG_0); - r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id); - mmio_write_32(FPD_APU_CONFIG_0, r); + /* Send request to PMC to wake up selected ACPU core */ + pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFF) | 0x1, + versal_sec_entry >> 32, 0); - /* - * FIXME: Add power up sequence, By default it works - * now without the need of it as it was powered up by - * default. - */ - - /* - * clear power down request - */ - r = mmio_read_32(FPD_APU_PWRCTL); - r &= ~(1 << cpu_id); - mmio_write_32(FPD_APU_PWRCTL, r); - - /* - * release core reset - */ - r = mmio_read_32(CRF_RST_APU); - r &= ~((CRF_RST_APU_ACPU_PWRON_RESET | - CRF_RST_APU_ACPU_RESET) << cpu_id); - mmio_write_32(CRF_RST_APU, r); + /* Clear power down request */ + pm_client_wakeup(proc); return PSCI_E_SUCCESS; } +/** + * versal_pwr_domain_suspend() - This function sends request to PMC to suspend + * core. + * + * @target_state Targated state + */ +static void versal_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + unsigned int state; + unsigned int cpu_id = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpu_id); + + for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) + VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + + plat_versal_gic_cpuif_disable(); + + plat_versal_gic_save(); + + state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ? + PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE; + + /* Send request to PMC to suspend this core */ + pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry); + + /* APU is to be turned off */ + if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + } +} + +/** + * versal_pwr_domain_suspend_finish() - This function performs actions to finish + * suspend procedure. + * + * @target_state Targated state + */ +static void versal_pwr_domain_suspend_finish( + const psci_power_state_t *target_state) +{ + unsigned int cpu_id = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpu_id); + + for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) + VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + + /* Clear the APU power control register for this cpu */ + pm_client_wakeup(proc); + + /* enable coherency */ + plat_arm_interconnect_enter_coherency(); + + /* APU was turned off, so restore GIC context */ + if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { + plat_versal_gic_resume(); + plat_versal_gic_cpuif_enable(); + } else { + plat_versal_gic_cpuif_enable(); + plat_versal_gic_pcpu_init(); + } +} + void versal_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* Enable the gic cpu interface */ @@ -69,9 +115,114 @@ plat_versal_gic_cpuif_enable(); } +/** + * versal_system_off() - This function sends the system off request + * to firmware. This function does not return. + */ +static void __dead2 versal_system_off(void) +{ + /* Send the power down request to the PMC */ + pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN, + pm_get_shutdown_scope()); + + while (1) + wfi(); +} + +/** + * versal_system_reset() - This function sends the reset request + * to firmware for the system to reset. This function does not return. + */ +static void __dead2 versal_system_reset(void) +{ + /* Send the system reset request to the PMC */ + pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, + pm_get_shutdown_scope()); + + while (1) + wfi(); +} + +/** + * versal_pwr_domain_off() - This function performs actions to turn off core + * + * @target_state Targated state + */ +static void versal_pwr_domain_off(const psci_power_state_t *target_state) +{ + unsigned int cpu_id = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpu_id); + + for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) + VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + + /* Prevent interrupts from spuriously waking up this cpu */ + plat_versal_gic_cpuif_disable(); + + /* + * Send request to PMC to power down the appropriate APU CPU + * core. + * According to PSCI specification, CPU_off function does not + * have resume address and CPU core can only be woken up + * invoking CPU_on function, during which resume address will + * be set. + */ + pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0); +} + +/** + * versal_validate_power_state() - This function ensures that the power state + * parameter in request is valid. + * + * @power_state Power state of core + * @req_state Requested state + * + * @return Returns status, either success or reason + */ +static int versal_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); + + int pstate = psci_get_pstate_type(power_state); + + assert(req_state); + + /* Sanity check the requested state */ + if (pstate == PSTATE_TYPE_STANDBY) + req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; + else + req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; + + /* We expect the 'state id' to be zero */ + if (psci_get_pstate_id(power_state)) + return PSCI_E_INVALID_PARAMS; + + return PSCI_E_SUCCESS; +} + +/** + * versal_get_sys_suspend_power_state() - Get power state for system suspend + * + * @req_state Requested state + */ +static void versal_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; + req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; +} + static const struct plat_psci_ops versal_nopmc_psci_ops = { - .pwr_domain_on = versal_nopmc_pwr_domain_on, + .pwr_domain_on = versal_pwr_domain_on, + .pwr_domain_off = versal_pwr_domain_off, .pwr_domain_on_finish = versal_pwr_domain_on_finish, + .pwr_domain_suspend = versal_pwr_domain_suspend, + .pwr_domain_suspend_finish = versal_pwr_domain_suspend_finish, + .system_off = versal_system_off, + .system_reset = versal_system_reset, + .validate_power_state = versal_validate_power_state, + .get_sys_suspend_power_state = versal_get_sys_suspend_power_state, }; /******************************************************************************* diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c index 642867d..a080a76 100644 --- a/plat/xilinx/versal/plat_versal.c +++ b/plat/xilinx/versal/plat_versal.c @@ -1,13 +1,12 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include #include -#include "versal_private.h" - int plat_core_pos_by_mpidr(u_register_t mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk index 1c56364..7a8bfa3 100644 --- a/plat/xilinx/versal/platform.mk +++ b/plat/xilinx/versal/platform.mk @@ -31,33 +31,48 @@ $(eval $(call add_define,VERSAL_BL32_MEM_SIZE)) endif -VERSAL_PLATFORM ?= versal_virt +VERSAL_PLATFORM ?= silicon $(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM})) VERSAL_CONSOLE ?= pl011 $(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE})) -PLAT_INCLUDES := -Iplat/xilinx/versal/include/ +PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ + -Iplat/xilinx/common/include/ \ + -Iplat/xilinx/common/ipi_mailbox_service/ \ + -Iplat/xilinx/versal/include/ \ + -Iplat/xilinx/versal/pm_service/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v3/arm_gicv3_common.c \ + drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/pl011/aarch64/pl011_console.S \ plat/common/aarch64/crash_console_helpers.S \ + plat/arm/common/arm_cci.c \ plat/common/plat_gicv3.c \ plat/xilinx/versal/aarch64/versal_helpers.S \ plat/xilinx/versal/aarch64/versal_common.c -BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ +BL31_SOURCES += drivers/arm/cci/cci.c \ + lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ plat/common/plat_psci_common.c \ + plat/xilinx/common/ipi.c \ + plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \ + plat/xilinx/common/pm_service/pm_ipi.c \ plat/xilinx/versal/bl31_versal_setup.c \ plat/xilinx/versal/plat_psci.c \ plat/xilinx/versal/plat_versal.c \ plat/xilinx/versal/plat_topology.c \ plat/xilinx/versal/sip_svc_setup.c \ - plat/xilinx/versal/versal_gicv3.c + plat/xilinx/versal/versal_gicv3.c \ + plat/xilinx/versal/versal_ipi.c \ + plat/xilinx/versal/pm_service/pm_svc_main.c \ + plat/xilinx/versal/pm_service/pm_api_sys.c \ + plat/xilinx/versal/pm_service/pm_client.c diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c new file mode 100644 index 0000000..dbe94e6 --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_api_sys.c @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Versal system level PM-API functions and communication with PMC via + * IPI interrupts + */ + +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" + +/********************************************************************* + * Target module IDs macros + ********************************************************************/ +#define LIBPM_MODULE_ID 0x2 +#define LOADER_MODULE_ID 0x7 + +/* default shutdown/reboot scope is system(2) */ +static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM; + +/** + * pm_get_shutdown_scope() - Get the currently set shutdown scope + * + * @return Shutdown scope value + */ +unsigned int pm_get_shutdown_scope(void) +{ + return pm_shutdown_scope; +} + +/** + * Assigning of argument values into array elements. + */ +#define PM_PACK_PAYLOAD1(pl, mid, arg0) { \ + pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \ +} + +#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) { \ + pl[1] = (uint32_t)(arg1); \ + PM_PACK_PAYLOAD1(pl, mid, arg0); \ +} + +#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) { \ + pl[2] = (uint32_t)(arg2); \ + PM_PACK_PAYLOAD2(pl, mid, arg0, arg1); \ +} + +#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) { \ + pl[3] = (uint32_t)(arg3); \ + PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2); \ +} + +#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) { \ + pl[4] = (uint32_t)(arg4); \ + PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3); \ +} + +#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) { \ + pl[5] = (uint32_t)(arg5); \ + PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4); \ +} + +/* PM API functions */ + +/** + * pm_get_api_version() - Get version number of PMC PM firmware + * @version Returns 32-bit version number of PMC Power Management Firmware + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_api_version(unsigned int *version) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION); + return pm_ipi_send_sync(primary_proc, payload, version, 1); +} + +/** + * pm_self_suspend() - PM call for processor to suspend itself + * @nid Node id of the processor or subsystem + * @latency Requested maximum wakeup latency (not supported) + * @state Requested state + * @address Resume address + * + * This is a blocking call, it will return only once PMU has responded. + * On a wakeup, resume address will be automatically set by PMU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_self_suspend(uint32_t nid, + unsigned int latency, + unsigned int state, + uintptr_t address) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + unsigned int cpuid = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpuid); + + if (!proc) { + WARN("Failed to get proc %d\n", cpuid); + return PM_RET_ERROR_INTERNAL; + } + + /* + * Do client specific suspend operations + * (e.g. set powerdown request bit) + */ + pm_client_suspend(proc, state); + + /* Send request to the PLM */ + PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, PM_SELF_SUSPEND, + proc->node_id, latency, state, address, + (address >> 32)); + return pm_ipi_send_sync(proc, payload, NULL, 0); +} + +/** + * pm_abort_suspend() - PM call to announce that a prior suspend request + * is to be aborted. + * @reason Reason for the abort + * + * Calling PU expects the PMU to abort the initiated suspend procedure. + * This is a non-blocking call without any acknowledge. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* + * Do client specific abort suspend operations + * (e.g. enable interrupts and clear powerdown request bit) + */ + pm_client_abort_suspend(); + + /* Send request to the PLM */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason, + primary_proc->node_id); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_req_suspend() - PM call to request for another PU or subsystem to + * be suspended gracefully. + * @target Node id of the targeted PU or subsystem + * @ack Flag to specify whether acknowledge is requested + * @latency Requested wakeup latency (not supported) + * @state Requested state (not supported) + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack, + unsigned int latency, unsigned int state) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_REQ_SUSPEND, target, + latency, state); + if (ack == IPI_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_req_wakeup() - PM call for processor to wake up selected processor + * or subsystem + * @target Device ID of the processor or subsystem to wake up + * @set_address Resume address presence indicator + * 1 - resume address specified, 0 - otherwise + * @address Resume address + * @ack Flag to specify whether acknowledge requested + * + * This API function is either used to power up another APU core for SMP + * (by PSCI) or to power up an entirely different PU or subsystem, such + * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be + * automatically set by PMC. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, + uintptr_t address, uint8_t ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC to perform the wake of the PU */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQ_WAKEUP, target, + set_address, address, ack); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_request_device() - Request a device + * @device_id Device ID + * @capabilities Requested capabilities for the device + * @qos Required Quality of Service + * @ack Flag to specify whether acknowledge requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities, + uint32_t qos, uint32_t ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQUEST_DEVICE, + device_id, capabilities, qos, ack); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_release_device() - Release a device + * @device_id Device ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_release_device(uint32_t device_id) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RELEASE_DEVICE, + device_id); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_set_requirement() - Set requirement for the device + * @device_id Device ID + * @capabilities Requested capabilities for the device + * @latency Requested maximum latency + * @qos Required Quality of Service + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities, + uint32_t latency, uint32_t qos) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_SET_REQUIREMENT, + device_id, capabilities, latency, qos); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_get_device_status() - Get device's status + * @device_id Device ID + * @response Buffer to store device status response + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_GET_DEVICE_STATUS, + device_id); + + return pm_ipi_send_sync(primary_proc, payload, response, 3); +} + +/** + * pm_reset_assert() - Assert/De-assert reset + * @reset Reset ID + * @assert Assert (1) or de-assert (0) + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset, + assert); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_reset_get_status() - Get current status of a reset line + * @reset Reset ID + * @status Returns current status of selected reset ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset); + + return pm_ipi_send_sync(primary_proc, payload, status, 1); +} + +/** + * 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) +{ + /* Return if interrupt is not from PMU */ + if (!pm_ipi_irq_status(primary_proc)) + return; + + pm_ipi_buff_read_callb(data, count); + pm_ipi_irq_clear(primary_proc); +} + +/** + * pm_pinctrl_request() - Request a pin + * @pin Pin ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_request(uint32_t pin) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_REQUEST, pin); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pinctrl_release() - Release a pin + * @pin Pin ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_release(uint32_t pin) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_RELEASE, pin); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pinctrl_set_function() - Set pin function + * @pin Pin ID + * @function Function ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, pin, + function) + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pinctrl_get_function() - Get function set on the pin + * @pin Pin ID + * @function Function set on the pin + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, + pin); + + return pm_ipi_send_sync(primary_proc, payload, function, 1); +} + +/** + * pm_pinctrl_set_pin_param() - Set configuration parameter for the pin + * @pin Pin ID + * @param Parameter ID + * @value Parameter value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param, + uint32_t value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_SET, + pin, param, value); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pinctrl_get_pin_param() - Get configuration parameter value for the pin + * @pin Pin ID + * @param Parameter ID + * @value Buffer to store parameter value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_GET, + pin, param); + + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_clock_enable() - Enable the clock + * @clk_id Clock ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_enable(uint32_t clk_id) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_ENABLE, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_disable() - Disable the clock + * @clk_id Clock ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_disable(uint32_t clk_id) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_DISABLE, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_get_state() - Get clock status + * @clk_id Clock ID + * @state: Buffer to store clock status (1: Enabled, 0:Disabled) + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETSTATE, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, state, 1); +} + +/** + * pm_clock_set_divider() - Set divider for the clock + * @clk_id Clock ID + * @divider Divider value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETDIVIDER, clk_id, + divider); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_get_divider() - Get divider value for the clock + * @clk_id Clock ID + * @divider: Buffer to store clock divider value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETDIVIDER, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, divider, 1); +} + +/** + * pm_clock_set_parent() - Set parent for the clock + * @clk_id Clock ID + * @parent Parent ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETPARENT, clk_id, + parent); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_get_parent() - Get parent value for the clock + * @clk_id Clock ID + * @parent: Buffer to store clock parent value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETPARENT, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, parent, 1); +} + +/** + * pm_pll_set_param() - Set PLL parameter + * @clk_id PLL clock ID + * @param PLL parameter ID + * @value Value to set for PLL parameter + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, + uint32_t value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PLL_SET_PARAMETER, clk_id, + param, value); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_param() - Get PLL parameter value + * @clk_id PLL clock ID + * @param PLL parameter ID + * @value: Buffer to store PLL parameter value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_GET_PARAMETER, clk_id, + param); + + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_pll_set_mode() - Set PLL mode + * @clk_id PLL clock ID + * @mode PLL mode + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_SET_MODE, clk_id, + mode); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_mode() - Get PLL mode + * @clk_id PLL clock ID + * @mode: Buffer to store PLL mode + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PLL_GET_MODE, clk_id); + + return pm_ipi_send_sync(primary_proc, payload, mode, 1); +} + +/** + * pm_force_powerdown() - PM call to request for another PU or subsystem to + * be powered down forcefully + * @target Device ID of the PU node to be forced powered down. + * @ack Flag to specify whether acknowledge is requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_FORCE_POWERDOWN, target, + ack); + + if (ack == IPI_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_system_shutdown() - PM call to request a system shutdown or restart + * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope + * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) { + /* Setting scope for subsequent PSCI reboot or shutdown */ + pm_shutdown_scope = subtype; + return PM_RET_SUCCESS; + } + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_SYSTEM_SHUTDOWN, type, + subtype); + + return pm_ipi_send_non_blocking(primary_proc, payload); +} + +/** +* pm_query_data() - PM API for querying firmware data +* @qid The type of data to query +* @arg1 Argument 1 to requested query data call +* @arg2 Argument 2 to requested query data call +* @arg3 Argument 3 to requested query data call +* @data Returned output data +* +* This function returns requested data. +*/ +enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_QUERY_DATA, qid, arg1, + arg2, arg3); + return pm_ipi_send_sync(primary_proc, payload, data, 4); +} +/** + * pm_api_ioctl() - PM IOCTL API for device control and configs + * @device_id Device ID + * @ioctl_id ID of the requested IOCTL + * @arg1 Argument 1 to requested IOCTL call + * @arg2 Argument 2 to requested IOCTL call + * @value Returned output value + * + * This function calls IOCTL to firmware for device control and configuration. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, + uint32_t arg1, uint32_t arg2, uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + switch (ioctl_id) { + case IOCTL_SET_PLL_FRAC_MODE: + return pm_pll_set_mode(arg1, arg2); + case IOCTL_GET_PLL_FRAC_MODE: + return pm_pll_get_mode(arg1, value); + case IOCTL_SET_PLL_FRAC_DATA: + return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2); + case IOCTL_GET_PLL_FRAC_DATA: + return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value); + default: + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_IOCTL, device_id, + ioctl_id, arg1, arg2); + return pm_ipi_send_sync(primary_proc, payload, value, 1); + } +} + +/** + * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended + * @target Device id of the targeted PU or subsystem + * @wkup_node Device id of the wakeup peripheral + * @enable Enable or disable the specified peripheral as wake source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device, + uint8_t enable) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_SET_WAKEUP_SOURCE, target, + wkup_device, enable); + return pm_ipi_send(primary_proc, payload); +} + +/** + * 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 PMC */ + PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_CHIPID); + + return pm_ipi_send_sync(primary_proc, payload, value, 2); +} + +/** + * pm_feature_check() - Returns the supported API version if supported + * @api_id API ID to check + * @value Returned supported API version + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version) +{ + uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version; + uint32_t status; + + switch (api_id) { + case PM_GET_CALLBACK_DATA: + case PM_GET_TRUSTZONE_VERSION: + case PM_INIT_FINALIZE: + *version = (PM_API_BASE_VERSION << 16); + return PM_RET_SUCCESS; + case PM_GET_API_VERSION: + case PM_GET_DEVICE_STATUS: + case PM_GET_OP_CHARACTERISTIC: + case PM_REQ_SUSPEND: + case PM_SELF_SUSPEND: + case PM_FORCE_POWERDOWN: + case PM_ABORT_SUSPEND: + case PM_REQ_WAKEUP: + case PM_SET_WAKEUP_SOURCE: + case PM_SYSTEM_SHUTDOWN: + case PM_REQUEST_DEVICE: + case PM_RELEASE_DEVICE: + case PM_SET_REQUIREMENT: + case PM_RESET_ASSERT: + case PM_RESET_GET_STATUS: + case PM_PINCTRL_REQUEST: + case PM_PINCTRL_RELEASE: + case PM_PINCTRL_GET_FUNCTION: + case PM_PINCTRL_SET_FUNCTION: + case PM_PINCTRL_CONFIG_PARAM_GET: + case PM_PINCTRL_CONFIG_PARAM_SET: + case PM_IOCTL: + case PM_QUERY_DATA: + case PM_CLOCK_ENABLE: + case PM_CLOCK_DISABLE: + case PM_CLOCK_GETSTATE: + case PM_CLOCK_SETDIVIDER: + case PM_CLOCK_GETDIVIDER: + case PM_CLOCK_SETPARENT: + case PM_CLOCK_GETPARENT: + case PM_PLL_SET_PARAMETER: + case PM_PLL_GET_PARAMETER: + case PM_PLL_SET_MODE: + case PM_PLL_GET_MODE: + case PM_FEATURE_CHECK: + *version = (PM_API_BASE_VERSION << 16); + break; + case PM_LOAD_PDI: + *version = (PM_API_BASE_VERSION << 16); + return PM_RET_SUCCESS; + default: + *version = 0U; + return PM_RET_ERROR_NOFEATURE; + } + + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_FEATURE_CHECK, api_id); + + status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1); + if (status != PM_RET_SUCCESS) + return status; + + *version |= fw_api_version; + + return PM_RET_SUCCESS; +} + +/** + * pm_load_pdi() - Load the PDI + * + * This function provides support to load PDI from linux + * + * src: Source device of pdi(DDR, OCM, SD etc) + * address_low: lower 32-bit Linear memory space address + * address_high: higher 32-bit Linear memory space address + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_load_pdi(uint32_t src, + uint32_t address_low, uint32_t address_high) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, PM_LOAD_PDI, src, + address_high, address_low); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_get_op_characteristic() - PM call to request operating characteristics + * of a device + * @device_id Device id + * @type Type of the operating characteristic + * (power, temperature and latency) + * @result Returns the operating characteristic for the requested device, + * specified by the type + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_op_characteristic(uint32_t device_id, + enum pm_opchar_type type, + uint32_t *result) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_GET_OP_CHARACTERISTIC, + device_id, type); + return pm_ipi_send_sync(primary_proc, payload, result, 1); +} diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h new file mode 100644 index 0000000..4de592a --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_api_sys.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PM_API_SYS_H +#define PM_API_SYS_H + +#include +#include "pm_defs.h" + +/********************************************************** + * PM API function declarations + **********************************************************/ + +enum pm_ret_status pm_get_api_version(unsigned int *version); +enum pm_ret_status pm_self_suspend(uint32_t nid, + unsigned int latency, + unsigned int state, + uintptr_t address); +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason); +enum pm_ret_status pm_req_suspend(uint32_t target, + uint8_t ack, + unsigned int latency, + unsigned int state); +enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, + uintptr_t address, uint8_t ack); +enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id, + uint8_t enable); +enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities, + uint32_t qos, uint32_t ack); +enum pm_ret_status pm_release_device(uint32_t device_id); +enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities, + uint32_t latency, uint32_t qos); +enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response); +enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert); +enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status); +void pm_get_callbackdata(uint32_t *data, size_t count); +enum pm_ret_status pm_pinctrl_request(uint32_t pin); +enum pm_ret_status pm_pinctrl_release(uint32_t pin); +enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function); +enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function); +enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param, + uint32_t value); +enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param, + uint32_t *value); +enum pm_ret_status pm_clock_enable(uint32_t clk_id); +enum pm_ret_status pm_clock_disable(uint32_t clk_id); +enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state); +enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider); +enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider); +enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent); +enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent); +enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, + uint32_t value); +enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, + uint32_t *value); +enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode); +enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode); +enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack); +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype); +enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, + uint32_t arg1, uint32_t arg2, uint32_t *value); +enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data); +unsigned int pm_get_shutdown_scope(void); +enum pm_ret_status pm_get_chipid(uint32_t *value); +enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version); +enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, + uint32_t address_high); +enum pm_ret_status pm_get_op_characteristic(uint32_t device_id, + enum pm_opchar_type type, + uint32_t *result); +#endif /* PM_API_SYS_H */ diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c new file mode 100644 index 0000000..5b47838 --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_client.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * APU specific definition of processors in the subsystem as well as functions + * for getting information about and changing state of the APU. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" + +#define UNDEFINED_CPUID (~0) +#define IRQ_MAX 142 +#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1) + +DEFINE_BAKERY_LOCK(pm_client_secure_lock); + +static const struct pm_ipi apu_ipi = { + .local_ipi_id = IPI_ID_APU, + .remote_ipi_id = IPI_ID_PMC, + .buffer_base = IPI_BUFFER_APU_BASE, +}; + +/* Order in pm_procs_all array must match cpu ids */ +static const struct pm_proc pm_procs_all[] = { + { + .node_id = XPM_DEVID_ACPU_0, + .ipi = &apu_ipi, + .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, + }, + { + .node_id = XPM_DEVID_ACPU_1, + .ipi = &apu_ipi, + .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, + } +}; + +const struct pm_proc *primary_proc = &pm_procs_all[0]; + +/* Interrupt to PM node index map */ +static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = { + [13] = XPM_NODEIDX_DEV_GPIO, + [14] = XPM_NODEIDX_DEV_I2C_0, + [15] = XPM_NODEIDX_DEV_I2C_1, + [16] = XPM_NODEIDX_DEV_SPI_0, + [17] = XPM_NODEIDX_DEV_SPI_1, + [18] = XPM_NODEIDX_DEV_UART_0, + [19] = XPM_NODEIDX_DEV_UART_1, + [20] = XPM_NODEIDX_DEV_CAN_FD_0, + [21] = XPM_NODEIDX_DEV_CAN_FD_1, + [22] = XPM_NODEIDX_DEV_USB_0, + [23] = XPM_NODEIDX_DEV_USB_0, + [24] = XPM_NODEIDX_DEV_USB_0, + [25] = XPM_NODEIDX_DEV_USB_0, + [26] = XPM_NODEIDX_DEV_USB_0, + [37] = XPM_NODEIDX_DEV_TTC_0, + [38] = XPM_NODEIDX_DEV_TTC_0, + [39] = XPM_NODEIDX_DEV_TTC_0, + [40] = XPM_NODEIDX_DEV_TTC_1, + [41] = XPM_NODEIDX_DEV_TTC_1, + [42] = XPM_NODEIDX_DEV_TTC_1, + [43] = XPM_NODEIDX_DEV_TTC_2, + [44] = XPM_NODEIDX_DEV_TTC_2, + [45] = XPM_NODEIDX_DEV_TTC_2, + [46] = XPM_NODEIDX_DEV_TTC_3, + [47] = XPM_NODEIDX_DEV_TTC_3, + [48] = XPM_NODEIDX_DEV_TTC_3, + [56] = XPM_NODEIDX_DEV_GEM_0, + [57] = XPM_NODEIDX_DEV_GEM_0, + [58] = XPM_NODEIDX_DEV_GEM_1, + [59] = XPM_NODEIDX_DEV_GEM_1, + [60] = XPM_NODEIDX_DEV_ADMA_0, + [61] = XPM_NODEIDX_DEV_ADMA_1, + [62] = XPM_NODEIDX_DEV_ADMA_2, + [63] = XPM_NODEIDX_DEV_ADMA_3, + [64] = XPM_NODEIDX_DEV_ADMA_4, + [65] = XPM_NODEIDX_DEV_ADMA_5, + [66] = XPM_NODEIDX_DEV_ADMA_6, + [67] = XPM_NODEIDX_DEV_ADMA_7, + [74] = XPM_NODEIDX_DEV_USB_0, + [126] = XPM_NODEIDX_DEV_SDIO_0, + [127] = XPM_NODEIDX_DEV_SDIO_0, + [128] = XPM_NODEIDX_DEV_SDIO_1, + [129] = XPM_NODEIDX_DEV_SDIO_1, + [142] = XPM_NODEIDX_DEV_RTC, +}; + +/** + * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number + * @irq: Interrupt number + * + * Return: PM node index corresponding to the specified interrupt + */ +static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq) +{ + assert(irq <= IRQ_MAX); + return irq_node_map[irq]; +} + +/** + * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as + * wake sources in the LibPM. + */ +static void pm_client_set_wakeup_sources(void) +{ + uint32_t reg_num; + uint32_t device_id; + uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX]; + uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4; + + zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set)); + + for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) { + uint32_t base_irq = reg_num << ISENABLER_SHIFT; + uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2)); + + if (!reg) + continue; + + while (reg) { + enum pm_device_node_idx node_idx; + uint32_t idx, ret, irq, lowest_set = reg & (-reg); + + idx = __builtin_ctz(lowest_set); + irq = base_irq + idx; + + if (irq > IRQ_MAX) + break; + + node_idx = irq_to_pm_node_idx(irq); + reg &= ~lowest_set; + + if ((node_idx != XPM_NODEIDX_DEV_MIN) && + (!pm_wakeup_nodes_set[node_idx])) { + /* Get device ID from node index */ + device_id = PERIPH_DEVID(node_idx); + ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0, + device_id, 1); + pm_wakeup_nodes_set[node_idx] = !ret; + } + } + } +} + +/** + * pm_client_suspend() - Client-specific suspend actions + * + * This function should contain any PU-specific actions + * required prior to sending suspend request to PMU + * Actions taken depend on the state system is suspending to. + */ +void pm_client_suspend(const struct pm_proc *proc, unsigned int state) +{ + bakery_lock_get(&pm_client_secure_lock); + + if (state == PM_STATE_SUSPEND_TO_RAM) + pm_client_set_wakeup_sources(); + + /* Set powerdown request */ + mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) | + proc->pwrdn_mask); + + bakery_lock_release(&pm_client_secure_lock); +} + +/** + * pm_client_abort_suspend() - Client-specific abort-suspend actions + * + * This function should contain any PU-specific actions + * required for aborting a prior suspend request + */ +void pm_client_abort_suspend(void) +{ + /* Enable interrupts at processor level (for current cpu) */ + gicv3_cpuif_enable(plat_my_core_pos()); + + bakery_lock_get(&pm_client_secure_lock); + + /* Clear powerdown request */ + mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) & + ~primary_proc->pwrdn_mask); + + bakery_lock_release(&pm_client_secure_lock); +} + +/** + * pm_get_cpuid() - get the local cpu ID for a global node ID + * @nid: node id of the processor + * + * Return: the cpu ID (starting from 0) for the subsystem + */ +static unsigned int pm_get_cpuid(uint32_t nid) +{ + for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { + if (pm_procs_all[i].node_id == nid) + return i; + } + return UNDEFINED_CPUID; +} + +/** + * pm_client_wakeup() - Client-specific wakeup actions + * + * This function should contain any PU-specific actions + * required for waking up another APU core + */ +void pm_client_wakeup(const struct pm_proc *proc) +{ + unsigned int cpuid = pm_get_cpuid(proc->node_id); + + if (cpuid == UNDEFINED_CPUID) + return; + + bakery_lock_get(&pm_client_secure_lock); + + /* clear powerdown bit for affected cpu */ + uint32_t val = mmio_read_32(FPD_APU_PWRCTL); + val &= ~(proc->pwrdn_mask); + mmio_write_32(FPD_APU_PWRCTL, val); + + bakery_lock_release(&pm_client_secure_lock); +} + +/** + * pm_get_proc() - returns pointer to the proc structure + * @cpuid: id of the cpu whose proc struct pointer should be returned + * + * Return: pointer to a proc structure if proc is found, otherwise NULL + */ +const struct pm_proc *pm_get_proc(unsigned int cpuid) +{ + if (cpuid < ARRAY_SIZE(pm_procs_all)) + return &pm_procs_all[cpuid]; + + return NULL; +} diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h new file mode 100644 index 0000000..966b00b --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_defs.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Versal power management enums and defines */ + +#ifndef PM_DEFS_H +#define PM_DEFS_H + +#include "pm_node.h" + +/********************************************************************* + * Macro definitions + ********************************************************************/ + +/* State arguments of the self suspend */ +#define PM_STATE_CPU_IDLE 0x0U +#define PM_STATE_SUSPEND_TO_RAM 0xFU + +#define MAX_LATENCY (~0U) +#define MAX_QOS 100U + +/* Processor core device IDs */ +#define APU_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, XPM_NODESUBCL_DEV_CORE, \ + XPM_NODETYPE_DEV_CORE_APU, (IDX)) + +#define XPM_DEVID_ACPU_0 APU_DEVID(XPM_NODEIDX_DEV_ACPU_0) +#define XPM_DEVID_ACPU_1 APU_DEVID(XPM_NODEIDX_DEV_ACPU_1) + +#define PERIPH_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, \ + XPM_NODESUBCL_DEV_PERIPH, \ + XPM_NODETYPE_DEV_PERIPH, (IDX)) + +#define PM_GET_CALLBACK_DATA 0xa01 +#define PM_GET_TRUSTZONE_VERSION 0xa03 + +/* PM API Versions */ +#define PM_API_BASE_VERSION 1U + +/* PM API ids */ +#define PM_GET_API_VERSION 1U +#define PM_GET_DEVICE_STATUS 3U +#define PM_GET_OP_CHARACTERISTIC 4U +#define PM_REQ_SUSPEND 6U +#define PM_SELF_SUSPEND 7U +#define PM_FORCE_POWERDOWN 8U +#define PM_ABORT_SUSPEND 9U +#define PM_REQ_WAKEUP 10U +#define PM_SET_WAKEUP_SOURCE 11U +#define PM_SYSTEM_SHUTDOWN 12U +#define PM_REQUEST_DEVICE 13U +#define PM_RELEASE_DEVICE 14U +#define PM_SET_REQUIREMENT 15U +#define PM_RESET_ASSERT 17U +#define PM_RESET_GET_STATUS 18U +#define PM_INIT_FINALIZE 21U +#define PM_GET_CHIPID 24U +#define PM_PINCTRL_REQUEST 28U +#define PM_PINCTRL_RELEASE 29U +#define PM_PINCTRL_GET_FUNCTION 30U +#define PM_PINCTRL_SET_FUNCTION 31U +#define PM_PINCTRL_CONFIG_PARAM_GET 32U +#define PM_PINCTRL_CONFIG_PARAM_SET 33U +#define PM_IOCTL 34U +#define PM_QUERY_DATA 35U +#define PM_CLOCK_ENABLE 36U +#define PM_CLOCK_DISABLE 37U +#define PM_CLOCK_GETSTATE 38U +#define PM_CLOCK_SETDIVIDER 39U +#define PM_CLOCK_GETDIVIDER 40U +#define PM_CLOCK_SETRATE 41U +#define PM_CLOCK_GETRATE 42U +#define PM_CLOCK_SETPARENT 43U +#define PM_CLOCK_GETPARENT 44U +#define PM_PLL_SET_PARAMETER 48U +#define PM_PLL_GET_PARAMETER 49U +#define PM_PLL_SET_MODE 50U +#define PM_PLL_GET_MODE 51U +#define PM_FEATURE_CHECK 63U + +/* Loader API ids */ +#define PM_LOAD_PDI 0x701U + +/* IOCTL IDs for clock driver */ +#define IOCTL_SET_PLL_FRAC_MODE 8 +#define IOCTL_GET_PLL_FRAC_MODE 9 +#define IOCTL_SET_PLL_FRAC_DATA 10 +#define IOCTL_GET_PLL_FRAC_DATA 11 + +/* Parameter ID for PLL IOCTLs */ +/* Fractional data portion for PLL */ +#define PM_PLL_PARAM_DATA 2 + +/* System shutdown macros */ +#define XPM_SHUTDOWN_TYPE_SHUTDOWN 0U +#define XPM_SHUTDOWN_TYPE_RESET 1U +#define XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY 2U + +#define XPM_SHUTDOWN_SUBTYPE_RST_SUBSYSTEM 0U +#define XPM_SHUTDOWN_SUBTYPE_RST_PS_ONLY 1U +#define XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM 2U + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +enum pm_abort_reason { + ABORT_REASON_WKUP_EVENT = 100, + ABORT_REASON_PU_BUSY, + ABORT_REASON_NO_PWRDN, + ABORT_REASON_UNKNOWN, +}; + +enum pm_opchar_type { + PM_OPCHAR_TYPE_POWER = 1, + PM_OPCHAR_TYPE_TEMP, + PM_OPCHAR_TYPE_LATENCY, +}; + +/** + * Subsystem IDs + */ +typedef enum { + XPM_SUBSYSID_PMC, + XPM_SUBSYSID_PSM, + XPM_SUBSYSID_APU, + XPM_SUBSYSID_RPU0_LOCK, + XPM_SUBSYSID_RPU0_0, + XPM_SUBSYSID_RPU0_1, + XPM_SUBSYSID_DDR0, + XPM_SUBSYSID_ME, + XPM_SUBSYSID_PL, + XPM_SUBSYSID_MAX, +} XPm_SubsystemId; + +/** + * @PM_RET_SUCCESS: success + * @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated) + * @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated) + * @PM_RET_ERROR_NOFEATURE: feature is not available + * @PM_RET_ERROR_INTERNAL: internal error + * @PM_RET_ERROR_CONFLICT: conflict + * @PM_RET_ERROR_ACCESS: access rights violation + * @PM_RET_ERROR_INVALID_NODE: invalid node + * @PM_RET_ERROR_DOUBLE_REQ: duplicate request for same node + * @PM_RET_ERROR_ABORT_SUSPEND: suspend procedure has been aborted + * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU + * @PM_RET_ERROR_NODE_USED: node is already in use + */ +enum pm_ret_status { + PM_RET_SUCCESS, + PM_RET_ERROR_ARGS = 1, + PM_RET_ERROR_NOTSUPPORTED = 4, + PM_RET_ERROR_NOFEATURE = 19, + PM_RET_ERROR_INTERNAL = 2000, + PM_RET_ERROR_CONFLICT = 2001, + PM_RET_ERROR_ACCESS = 2002, + PM_RET_ERROR_INVALID_NODE = 2003, + PM_RET_ERROR_DOUBLE_REQ = 2004, + PM_RET_ERROR_ABORT_SUSPEND = 2005, + PM_RET_ERROR_TIMEOUT = 2006, + PM_RET_ERROR_NODE_USED = 2007 +}; +#endif /* PM_DEFS_H */ diff --git a/plat/xilinx/versal/pm_service/pm_node.h b/plat/xilinx/versal/pm_service/pm_node.h new file mode 100644 index 0000000..1b82ec7 --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_node.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Versal PM nodes enums and defines */ + +#ifndef PM_NODE_H +#define PM_NODE_H + +/********************************************************************* + * Macro definitions + ********************************************************************/ + +#define NODE_CLASS_SHIFT 26U +#define NODE_SUBCLASS_SHIFT 20U +#define NODE_TYPE_SHIFT 14U +#define NODE_INDEX_SHIFT 0U +#define NODE_CLASS_MASK_BITS 0x3F +#define NODE_SUBCLASS_MASK_BITS 0x3F +#define NODE_TYPE_MASK_BITS 0x3F +#define NODE_INDEX_MASK_BITS 0x3FFF +#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT) +#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT) +#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT) +#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT) + +#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \ + ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \ + (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \ + (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \ + (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT)) + +#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT) +#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \ + NODE_SUBCLASS_SHIFT) +#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT) +#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT) + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +/* Node class types */ +enum pm_node_class { + XPM_NODECLASS_MIN, + + XPM_NODECLASS_POWER, + XPM_NODECLASS_CLOCK, + XPM_NODECLASS_RESET, + XPM_NODECLASS_MEMIC, + XPM_NODECLASS_STMIC, + XPM_NODECLASS_DEVICE, + + XPM_NODECLASS_MAX +}; + +enum pm_device_node_subclass { + /* Device types */ + XPM_NODESUBCL_DEV_CORE = 1, + XPM_NODESUBCL_DEV_PERIPH, + XPM_NODESUBCL_DEV_MEM, + XPM_NODESUBCL_DEV_SOC, + XPM_NODESUBCL_DEV_MEM_CTRLR, + XPM_NODESUBCL_DEV_PHY, +}; + +enum pm_device_node_type { + /* Device types */ + XPM_NODETYPE_DEV_CORE_PMC = 1, + XPM_NODETYPE_DEV_CORE_PSM, + XPM_NODETYPE_DEV_CORE_APU, + XPM_NODETYPE_DEV_CORE_RPU, + XPM_NODETYPE_DEV_OCM, + XPM_NODETYPE_DEV_TCM, + XPM_NODETYPE_DEV_L2CACHE, + XPM_NODETYPE_DEV_DDR, + XPM_NODETYPE_DEV_PERIPH, + XPM_NODETYPE_DEV_SOC, + XPM_NODETYPE_DEV_GT, +}; + +/* Device node Indexes */ +enum pm_device_node_idx { + /* Device nodes */ + XPM_NODEIDX_DEV_MIN, + + /* Processor devices */ + XPM_NODEIDX_DEV_PMC_PROC, + XPM_NODEIDX_DEV_PSM_PROC, + XPM_NODEIDX_DEV_ACPU_0, + XPM_NODEIDX_DEV_ACPU_1, + XPM_NODEIDX_DEV_RPU0_0, + XPM_NODEIDX_DEV_RPU0_1, + + /* Memory devices */ + XPM_NODEIDX_DEV_OCM_0, + XPM_NODEIDX_DEV_OCM_1, + XPM_NODEIDX_DEV_OCM_2, + XPM_NODEIDX_DEV_OCM_3, + XPM_NODEIDX_DEV_TCM_0_A, + XPM_NODEIDX_DEV_TCM_0_B, + XPM_NODEIDX_DEV_TCM_1_A, + XPM_NODEIDX_DEV_TCM_1_B, + XPM_NODEIDX_DEV_L2_BANK_0, + XPM_NODEIDX_DEV_DDR_0, + XPM_NODEIDX_DEV_DDR_1, + XPM_NODEIDX_DEV_DDR_2, + XPM_NODEIDX_DEV_DDR_3, + XPM_NODEIDX_DEV_DDR_4, + XPM_NODEIDX_DEV_DDR_5, + XPM_NODEIDX_DEV_DDR_6, + XPM_NODEIDX_DEV_DDR_7, + + /* LPD Peripheral devices */ + XPM_NODEIDX_DEV_USB_0, + XPM_NODEIDX_DEV_GEM_0, + XPM_NODEIDX_DEV_GEM_1, + XPM_NODEIDX_DEV_SPI_0, + XPM_NODEIDX_DEV_SPI_1, + XPM_NODEIDX_DEV_I2C_0, + XPM_NODEIDX_DEV_I2C_1, + XPM_NODEIDX_DEV_CAN_FD_0, + XPM_NODEIDX_DEV_CAN_FD_1, + XPM_NODEIDX_DEV_UART_0, + XPM_NODEIDX_DEV_UART_1, + XPM_NODEIDX_DEV_GPIO, + XPM_NODEIDX_DEV_TTC_0, + XPM_NODEIDX_DEV_TTC_1, + XPM_NODEIDX_DEV_TTC_2, + XPM_NODEIDX_DEV_TTC_3, + XPM_NODEIDX_DEV_SWDT_LPD, + + /* FPD Peripheral devices */ + XPM_NODEIDX_DEV_SWDT_FPD, + + /* PMC Peripheral devices */ + XPM_NODEIDX_DEV_OSPI, + XPM_NODEIDX_DEV_QSPI, + XPM_NODEIDX_DEV_GPIO_PMC, + XPM_NODEIDX_DEV_I2C_PMC, + XPM_NODEIDX_DEV_SDIO_0, + XPM_NODEIDX_DEV_SDIO_1, + + XPM_NODEIDX_DEV_PL_0, + XPM_NODEIDX_DEV_PL_1, + XPM_NODEIDX_DEV_PL_2, + XPM_NODEIDX_DEV_PL_3, + XPM_NODEIDX_DEV_RTC, + XPM_NODEIDX_DEV_ADMA_0, + XPM_NODEIDX_DEV_ADMA_1, + XPM_NODEIDX_DEV_ADMA_2, + XPM_NODEIDX_DEV_ADMA_3, + XPM_NODEIDX_DEV_ADMA_4, + XPM_NODEIDX_DEV_ADMA_5, + XPM_NODEIDX_DEV_ADMA_6, + XPM_NODEIDX_DEV_ADMA_7, + XPM_NODEIDX_DEV_IPI_0, + XPM_NODEIDX_DEV_IPI_1, + XPM_NODEIDX_DEV_IPI_2, + XPM_NODEIDX_DEV_IPI_3, + XPM_NODEIDX_DEV_IPI_4, + XPM_NODEIDX_DEV_IPI_5, + XPM_NODEIDX_DEV_IPI_6, + + /* Entire SoC */ + XPM_NODEIDX_DEV_SOC, + + /* DDR memory controllers */ + XPM_NODEIDX_DEV_DDRMC_0, + XPM_NODEIDX_DEV_DDRMC_1, + XPM_NODEIDX_DEV_DDRMC_2, + XPM_NODEIDX_DEV_DDRMC_3, + + /* GT devices */ + XPM_NODEIDX_DEV_GT_0, + XPM_NODEIDX_DEV_GT_1, + XPM_NODEIDX_DEV_GT_2, + XPM_NODEIDX_DEV_GT_3, + XPM_NODEIDX_DEV_GT_4, + XPM_NODEIDX_DEV_GT_5, + XPM_NODEIDX_DEV_GT_6, + XPM_NODEIDX_DEV_GT_7, + XPM_NODEIDX_DEV_GT_8, + XPM_NODEIDX_DEV_GT_9, + XPM_NODEIDX_DEV_GT_10, + + XPM_NODEIDX_DEV_MAX +}; + +#endif /* PM_NODE_H */ diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c new file mode 100644 index 0000000..a3a9f43 --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_svc_main.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for Versal power management calls and + * IPI setup functions for communication with PMC. + */ + +#include +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" +#include "pm_ipi.h" + +/* pm_up = true - UP, pm_up = false - DOWN */ +static bool pm_up; + +/** + * pm_setup() - PM service setup + * + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Initialization functions for Versal power management for + * communicaton with PMC. + * + * Called from sip_svc_setup initialization function with the + * rt_svc_init signature. + */ +int pm_setup(void) +{ + int status, ret = 0; + + status = pm_ipi_init(primary_proc); + + if (status < 0) { + INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); + ret = status; + } else { + pm_up = true; + } + + return ret; +} + +/** + * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. + * @smc_fid - Function Identifier + * @x1 - x4 - Arguments + * @cookie - Unused + * @handler - Pointer to caller's context structure + * + * @return - Unused + * + * Determines that smc_fid is valid and supported PM SMC Function ID from the + * list of pm_api_ids, otherwise completes the request with + * the unknown SMC Function ID + * + * The SMC calls for PM service are forwarded from SIP Service SMC handler + * function with rt_svc_handle signature + */ +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) +{ + enum pm_ret_status ret; + + uint32_t pm_arg[4]; + + /* Handle case where PM wasn't initialized properly */ + if (!pm_up) + SMC_RET1(handle, SMC_UNK); + + pm_arg[0] = (uint32_t)x1; + pm_arg[1] = (uint32_t)(x1 >> 32); + pm_arg[2] = (uint32_t)x2; + pm_arg[3] = (uint32_t)(x2 >> 32); + + switch (smc_fid & FUNCID_NUM_MASK) { + /* PM API Functions */ + case PM_SELF_SUSPEND: + ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_FORCE_POWERDOWN: + ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_SUSPEND: + ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_ABORT_SUSPEND: + ret = pm_abort_suspend(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SYSTEM_SHUTDOWN: + ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_WAKEUP: + ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SET_WAKEUP_SOURCE: + ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQUEST_DEVICE: + ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_RELEASE_DEVICE: + ret = pm_release_device(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SET_REQUIREMENT: + ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_API_VERSION: + { + uint32_t api_version; + + ret = pm_get_api_version(&api_version); + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)api_version << 32)); + } + + case PM_GET_DEVICE_STATUS: + { + uint32_t buff[3]; + + ret = pm_get_device_status(pm_arg[0], buff); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32), + (uint64_t)buff[1] | ((uint64_t)buff[2] << 32)); + } + + case PM_RESET_ASSERT: + ret = pm_reset_assert(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_RESET_GET_STATUS: + { + uint32_t reset_status; + + ret = pm_reset_get_status(pm_arg[0], &reset_status); + SMC_RET1(handle, (uint64_t)ret | + ((uint64_t)reset_status << 32)); + } + + case PM_INIT_FINALIZE: + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS); + + case PM_GET_CALLBACK_DATA: + { + uint32_t result[4] = {0}; + + 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)); + } + + case PM_PINCTRL_REQUEST: + ret = pm_pinctrl_request(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PINCTRL_RELEASE: + ret = pm_pinctrl_release(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PINCTRL_GET_FUNCTION: + { + uint32_t value = 0; + + ret = pm_pinctrl_get_function(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_PINCTRL_SET_FUNCTION: + ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PINCTRL_CONFIG_PARAM_GET: + { + uint32_t value; + + ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_PINCTRL_CONFIG_PARAM_SET: + ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_IOCTL: + { + uint32_t value; + + ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_QUERY_DATA: + { + uint32_t data[4] = { 0 }; + + ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], data); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32), + (uint64_t)data[1] | ((uint64_t)data[2] << 32)); + } + + case PM_CLOCK_ENABLE: + ret = pm_clock_enable(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_DISABLE: + ret = pm_clock_disable(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETSTATE: + { + uint32_t value; + + ret = pm_clock_get_state(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_CLOCK_SETDIVIDER: + ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETDIVIDER: + { + uint32_t value; + + ret = pm_clock_get_divider(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_CLOCK_SETPARENT: + ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETPARENT: + { + uint32_t value; + + ret = pm_clock_get_parent(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_PLL_SET_PARAMETER: + ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PLL_GET_PARAMETER: + { + uint32_t value; + + ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32)); + } + + case PM_PLL_SET_MODE: + ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PLL_GET_MODE: + { + uint32_t mode; + + ret = pm_pll_get_mode(pm_arg[0], &mode); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32)); + } + + case PM_GET_TRUSTZONE_VERSION: + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)VERSAL_TZ_VERSION << 32)); + + case PM_GET_CHIPID: + { + uint32_t result[2]; + + ret = pm_get_chipid(result); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32), + result[1]); + } + + case PM_FEATURE_CHECK: + { + uint32_t version; + + ret = pm_feature_check(pm_arg[0], &version); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32)); + } + + case PM_LOAD_PDI: + { + ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + } + + case PM_GET_OP_CHARACTERISTIC: + { + uint32_t result; + + ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32)); + } + + default: + WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h new file mode 100644 index 0000000..71329ca --- /dev/null +++ b/plat/xilinx/versal/pm_service/pm_svc_main.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PM_SVC_MAIN_H +#define PM_SVC_MAIN_H + +#include + +int pm_setup(void); +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); + +#endif /* PM_SVC_MAIN_H */ diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c index 8f2180b..bc7d8b7 100644 --- a/plat/xilinx/versal/sip_svc_setup.c +++ b/plat/xilinx/versal/sip_svc_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,6 +10,9 @@ #include #include +#include "ipi_mailbox_svc.h" +#include "pm_svc_main.h" + /* SMC function IDs for SiP Service queries */ #define VERSAL_SIP_SVC_CALL_COUNT 0x8200ff00 #define VERSAL_SIP_SVC_UID 0x8200ff01 @@ -22,7 +25,9 @@ /* These macros are used to identify PM calls from the SMC function ID */ #define PM_FID_MASK 0xf000u #define PM_FID_VALUE 0u +#define IPI_FID_VALUE 0x1000u #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) +#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE) /* SiP Service UUID */ DEFINE_SVC_UUID2(versal_sip_uuid, @@ -36,6 +41,9 @@ */ static int32_t sip_svc_setup(void) { + /* PM implementation as SiP Service */ + pm_setup(); + return 0; } @@ -55,6 +63,18 @@ u_register_t flags) { /* Let PM SMC handler deal with PM-related requests */ + if (is_pm_fid(smc_fid)) { + return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, + flags); + } + + /* Let IPI SMC handler deal with IPI-related requests */ + if (is_ipi_fid(smc_fid)) { + return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, + flags); + } + + /* Let PM SMC handler deal with PM-related requests */ switch (smc_fid) { case VERSAL_SIP_SVC_CALL_COUNT: /* PM functions + default functions */ diff --git a/plat/xilinx/versal/versal_def.h b/plat/xilinx/versal/versal_def.h deleted file mode 100644 index 41c65b9..0000000 --- a/plat/xilinx/versal/versal_def.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef VERSAL_DEF_H -#define VERSAL_DEF_H - -#include - -/* List all consoles */ -#define VERSAL_CONSOLE_ID_pl011 1 -#define VERSAL_CONSOLE_ID_pl011_0 1 -#define VERSAL_CONSOLE_ID_pl011_1 2 -#define VERSAL_CONSOLE_ID_dcc 3 - -#define VERSAL_CONSOLE_IS(con) (VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE) - -/* List all supported platforms */ -#define VERSAL_PLATFORM_ID_versal_virt 1 - -#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM) - -/* Firmware Image Package */ -#define VERSAL_PRIMARY_CPU 0 - -/******************************************************************************* - * memory map related constants - ******************************************************************************/ -#define DEVICE0_BASE 0xFF000000 -#define DEVICE0_SIZE 0x00E00000 -#define DEVICE1_BASE 0xF9000000 -#define DEVICE1_SIZE 0x00800000 - -/* CRL */ -#define VERSAL_CRL 0xFF5E0000 -#define VERSAL_CRL_IOU_SWITCH_CTRL (VERSAL_CRL + 0x114) -#define VERSAL_CRL_TIMESTAMP_REF_CTRL (VERSAL_CRL + 0x14C) -#define VERSAL_CRL_RST_TIMESTAMP_OFFSET (VERSAL_CRL + 0x348) - -#define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 25) -#define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT (1 << 25) -#define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT 8 - -/* IOU SCNTRS */ -#define VERSAL_IOU_SCNTRS 0xFF140000 -#define VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG (VERSAL_IOU_SCNTRS + 0x0) -#define VERSAL_IOU_SCNTRS_BASE_FREQ (VERSAL_IOU_SCNTRS + 0x20) - -#define VERSAL_IOU_SCNTRS_CONTROL_EN 1 - -/******************************************************************************* - * IRQ constants - ******************************************************************************/ -#define VERSAL_IRQ_SEC_PHY_TIMER 29 - -/******************************************************************************* - * UART related constants - ******************************************************************************/ -#define VERSAL_UART0_BASE 0xFF000000 -#define VERSAL_UART1_BASE 0xFF010000 - -#if VERSAL_CONSOLE_IS(pl011) -# define VERSAL_UART_BASE VERSAL_UART0_BASE -#elif VERSAL_CONSOLE_IS(pl011_1) -# define VERSAL_UART_BASE VERSAL_UART1_BASE -#else -# error "invalid VERSAL_CONSOLE" -#endif - -#define PLAT_VERSAL_CRASH_UART_BASE VERSAL_UART_BASE -#define PLAT_VERSAL_CRASH_UART_CLK_IN_HZ VERSAL_UART_CLOCK -#define VERSAL_CONSOLE_BAUDRATE VERSAL_UART_BAUDRATE - -/******************************************************************************* - * Platform related constants - ******************************************************************************/ -#if VERSAL_PLATFORM_IS(versal_virt) -# define PLATFORM_NAME "Versal Virt" -# define VERSAL_UART_CLOCK 25000000 -# define VERSAL_UART_BAUDRATE 115200 -# define VERSAL_CPU_CLOCK 62500000 -#endif - -/* Access control register defines */ -#define ACTLR_EL3_L2ACTLR_BIT (1 << 6) -#define ACTLR_EL3_CPUACTLR_BIT (1 << 0) - -/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/ -#define CRF_BASE 0xFD1A0000 -#define CRF_SIZE 0x00600000 - -/* CRF registers and bitfields */ -#define CRF_RST_APU (CRF_BASE + 0X00000300) - -#define CRF_RST_APU_ACPU_RESET (1 << 0) -#define CRF_RST_APU_ACPU_PWRON_RESET (1 << 10) - -/* APU registers and bitfields */ -#define FPD_APU_BASE 0xFD5C0000 -#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20) -#define FPD_APU_RVBAR_L_0 (FPD_APU_BASE + 0x40) -#define FPD_APU_RVBAR_H_0 (FPD_APU_BASE + 0x44) -#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90) - -#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8 - -#endif /* VERSAL_DEF_H */ diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c index dcf23b4..08e7cf9 100644 --- a/plat/xilinx/versal/versal_gicv3.c +++ b/plat/xilinx/versal/versal_gicv3.c @@ -1,9 +1,10 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include #include #include @@ -11,8 +12,6 @@ #include #include -#include "versal_private.h" - /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv3 driver is initialised and used. diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c new file mode 100644 index 0000000..27541ff --- /dev/null +++ b/plat/xilinx/versal/versal_ipi.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Versal IPI agent registers access management + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* versal ipi configuration table */ +const static struct ipi_config versal_ipi_table[] = { + /* A72 IPI */ + [IPI_ID_APU] = { + .ipi_bit_mask = IPI0_TRIG_BIT, + .ipi_reg_base = IPI0_REG_BASE, + .secure_only = 0, + }, + + /* PMC IPI */ + [IPI_ID_PMC] = { + .ipi_bit_mask = PMC_IPI_TRIG_BIT, + .ipi_reg_base = IPI0_REG_BASE, + .secure_only = 0, + }, + + /* RPU0 IPI */ + [IPI_ID_RPU0] = { + .ipi_bit_mask = IPI1_TRIG_BIT, + .ipi_reg_base = IPI1_REG_BASE, + .secure_only = 0, + }, + + /* RPU1 IPI */ + [IPI_ID_RPU1] = { + .ipi_bit_mask = IPI2_TRIG_BIT, + .ipi_reg_base = IPI2_REG_BASE, + .secure_only = 0, + }, + + /* IPI3 IPI */ + [IPI_ID_3] = { + .ipi_bit_mask = IPI3_TRIG_BIT, + .ipi_reg_base = IPI3_REG_BASE, + .secure_only = 0, + }, + + /* IPI4 IPI */ + [IPI_ID_4] = { + .ipi_bit_mask = IPI4_TRIG_BIT, + .ipi_reg_base = IPI4_REG_BASE, + .secure_only = 0, + }, + + /* IPI5 IPI */ + [IPI_ID_5] = { + .ipi_bit_mask = IPI5_TRIG_BIT, + .ipi_reg_base = IPI5_REG_BASE, + .secure_only = 0, + }, +}; + +/* versal_ipi_config_table_init() - Initialize versal IPI configuration data + * + * @ipi_config_table - IPI configuration table + * @ipi_total - Total number of IPI available + * + */ +void versal_ipi_config_table_init(void) +{ + ipi_config_table_init(versal_ipi_table, ARRAY_SIZE(versal_ipi_table)); +} diff --git a/plat/xilinx/versal/versal_private.h b/plat/xilinx/versal/versal_private.h deleted file mode 100644 index 5d98d08..0000000 --- a/plat/xilinx/versal/versal_private.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef VERSAL_PRIVATE_H -#define VERSAL_PRIVATE_H - -#include - -void versal_config_setup(void); - -const mmap_region_t *plat_versal_get_mmap(void); - -void plat_versal_gic_driver_init(void); -void plat_versal_gic_init(void); -void plat_versal_gic_cpuif_enable(void); -void plat_versal_gic_cpuif_disable(void); -void plat_versal_gic_pcpu_init(void); - -unsigned int versal_calc_core_pos(u_register_t mpidr); - -#endif /* VERSAL_PRIVATE_H */ diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c deleted file mode 100644 index c499d78..0000000 --- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions. - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "ipi_mailbox_svc.h" -#include "../../../services/spd/trusty/smcall.h" - -/********************************************************************* - * Macros definitions - ********************************************************************/ - -/* IPI SMC calls macros: */ -#define IPI_SMC_OPEN_IRQ_MASK 0x00000001U /* IRQ enable bit in IPI - * open SMC call - */ -#define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001U /* Flag to indicate if - * IPI notification needs - * to be blocking. - */ -#define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001U /* Flag to indicate if - * notification interrupt - * to be disabled. - */ -#define IPI_SMC_ACK_EIRQ_MASK 0x00000001U /* Flag to indicate if - * notification interrupt - * to be enable. - */ - -#define UNSIGNED32_MASK 0xFFFFFFFFU /* 32bit mask */ - -/** - * ipi_smc_handler() - SMC handler for IPI SMC calls - * - * @smc_fid - Function identifier - * @x1 - x4 - Arguments - * @cookie - Unused - * @handler - Pointer to caller's context structure - * - * @return - Unused - * - * Determines that smc_fid is valid and supported PM SMC Function ID from the - * list of pm_api_ids, otherwise completes the request with - * the unknown SMC Function ID - * - * The SMC calls for PM service are forwarded from SIP Service SMC handler - * function with rt_svc_handle signature - */ -uint64_t ipi_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 ret; - uint32_t ipi_local_id; - uint32_t ipi_remote_id; - unsigned int is_secure; - - ipi_local_id = x1 & UNSIGNED32_MASK; - ipi_remote_id = x2 & UNSIGNED32_MASK; - - if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP) - is_secure = 1; - else - is_secure = 0; - - /* Validate IPI mailbox access */ - ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure); - if (ret) - SMC_RET1(handle, ret); - - switch (SMC_FUNCTION(smc_fid)) { - case IPI_MAILBOX_OPEN: - ipi_mb_open(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, 0); - case IPI_MAILBOX_RELEASE: - ipi_mb_release(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, 0); - case IPI_MAILBOX_STATUS_ENQUIRY: - { - int disable_irq; - - disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0; - ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id); - if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq) - ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, ret); - } - case IPI_MAILBOX_NOTIFY: - { - uint32_t is_blocking; - - is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0; - ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking); - SMC_RET1(handle, 0); - } - case IPI_MAILBOX_ACK: - { - int enable_irq; - - enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0; - ipi_mb_ack(ipi_local_id, ipi_remote_id); - if (enable_irq) - ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, 0); - } - case IPI_MAILBOX_ENABLE_IRQ: - ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, 0); - case IPI_MAILBOX_DISABLE_IRQ: - ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); - SMC_RET1(handle, 0); - default: - WARN("Unimplemented IPI service call: 0x%x\n", smc_fid); - SMC_RET1(handle, SMC_UNK); - } -} diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h deleted file mode 100644 index 197c788..0000000 --- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* ZynqMP IPI mailbox doorbell service enums and defines */ - -#ifndef IPI_MAILBOX_SVC_H -#define IPI_MAILBOX_SVC_H - -#include - -/********************************************************************* - * Enum definitions - ********************************************************************/ - -/* IPI SMC function numbers enum definition */ -enum ipi_api_id { - /* IPI mailbox operations functions: */ - IPI_MAILBOX_OPEN = 0x1000, - IPI_MAILBOX_RELEASE, - IPI_MAILBOX_STATUS_ENQUIRY, - IPI_MAILBOX_NOTIFY, - IPI_MAILBOX_ACK, - IPI_MAILBOX_ENABLE_IRQ, - IPI_MAILBOX_DISABLE_IRQ -}; - -/********************************************************************* - * IPI mailbox service APIs declarations - ********************************************************************/ - -/* IPI SMC handler */ -uint64_t ipi_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); - -#endif /* IPI_MAILBOX_SVC_H */ diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c index a32e089..f579f79 100644 --- a/plat/xilinx/zynqmp/plat_psci.c +++ b/plat/xilinx/zynqmp/plat_psci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -100,9 +100,8 @@ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); - + plat_arm_gic_pcpu_init(); gicv2_cpuif_enable(); - gicv2_pcpu_distif_init(); } static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk index 1039e27..de4bf3a 100644 --- a/plat/xilinx/zynqmp/platform.mk +++ b/plat/xilinx/zynqmp/platform.mk @@ -11,6 +11,8 @@ ZYNQMP_WDT_RESTART := 0 ZYNQMP_IPI_CRC_CHECK := 0 override RESET_TO_BL31 := 1 +override GICV2_G0_FOR_EL3 := 1 +override WARMBOOT_ENABLE_DCACHE_EARLY := 1 # Do not enable SVE ENABLE_SVE_FOR_NS := 0 @@ -53,9 +55,9 @@ PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ -Iinclude/plat/arm/common/aarch64/ \ -Iplat/xilinx/common/include/ \ + -Iplat/xilinx/common/ipi_mailbox_service/ \ -Iplat/xilinx/zynqmp/include/ \ -Iplat/xilinx/zynqmp/pm_service/ \ - -Iplat/xilinx/zynqmp/ipi_mailbox_service/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ @@ -78,6 +80,7 @@ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ + plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \ plat/xilinx/common/pm_service/pm_ipi.c \ plat/xilinx/zynqmp/bl31_zynqmp_setup.c \ plat/xilinx/zynqmp/plat_psci.c \ @@ -90,5 +93,8 @@ plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \ plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \ plat/xilinx/zynqmp/pm_service/pm_api_clock.c \ - plat/xilinx/zynqmp/pm_service/pm_client.c \ - plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c + plat/xilinx/zynqmp/pm_service/pm_client.c + +ifneq (${RESET_TO_BL31},1) + $(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.") +endif diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h deleted file mode 100644 index adbb76f..0000000 --- a/plat/xilinx/zynqmp/pm_service/pm_client.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * Contains APU specific macros and macros to be defined depending on - * the execution environment. - */ - -#ifndef PM_CLIENT_H -#define PM_CLIENT_H - -#include "pm_common.h" -#include "pm_defs.h" - -/* Functions to be implemented by each PU */ -void pm_client_suspend(const struct pm_proc *proc, unsigned int state); -void pm_client_abort_suspend(void); -void pm_client_wakeup(const struct pm_proc *proc); -enum pm_ret_status set_ocm_retention(void); -enum pm_ret_status pm_set_suspend_mode(uint32_t mode); -const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid); - -/* Global variables to be set in pm_client.c */ -extern const struct pm_proc *primary_proc; - -#endif /* PM_CLIENT_H */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index 5a320f1..98dbe7d 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -77,8 +77,12 @@ INFO("Active Cores: %d\n", active_cores); - /* trigger SGI to active cores */ - gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list); + for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) { + if (target_cpu_list & (1 << i)) { + /* trigger SGI to active cores */ + plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i); + } + } } /** @@ -106,6 +110,8 @@ { INFO("BL31: Got TTC FIQ\n"); + plat_ic_end_of_interrupt(id); + /* Clear TTC interrupt by reading interrupt register */ mmio_read_32(TTC3_INTR_REGISTER_1);