From c8284409e13ea72d08a9d858f8bcbddfb2f4df42 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Sun, 6 Mar 2016 20:16:27 -0800 Subject: [PATCH] Add support for Xilinx Zynq UltraScale+ MPSOC The Xilinx Zynq UltraScale+ MPSOC containes a quad A53 cluster. This patch adds the platform port for that SoC. Signed-off-by: Soren Brinkmann --- docs/plat/xilinx-zynqmp.md | 49 ++ plat/xilinx/zynqmp/aarch64/zynqmp_common.c | 308 +++++++++++++ plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S | 73 +++ plat/xilinx/zynqmp/bl31_zynqmp_setup.c | 164 +++++++ plat/xilinx/zynqmp/include/plat_macros.S | 51 ++ plat/xilinx/zynqmp/include/platform_def.h | 135 ++++++ plat/xilinx/zynqmp/plat_psci.c | 374 +++++++++++++++ plat/xilinx/zynqmp/plat_topology.c | 39 ++ plat/xilinx/zynqmp/plat_zynqmp.c | 42 ++ plat/xilinx/zynqmp/platform.mk | 95 ++++ plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 485 ++++++++++++++++++++ plat/xilinx/zynqmp/pm_service/pm_api_sys.h | 111 +++++ plat/xilinx/zynqmp/pm_service/pm_client.c | 202 ++++++++ plat/xilinx/zynqmp/pm_service/pm_client.h | 56 +++ plat/xilinx/zynqmp/pm_service/pm_common.h | 74 +++ plat/xilinx/zynqmp/pm_service/pm_defs.h | 213 +++++++++ plat/xilinx/zynqmp/pm_service/pm_ipi.c | 247 ++++++++++ plat/xilinx/zynqmp/pm_service/pm_ipi.h | 44 ++ plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 231 ++++++++++ plat/xilinx/zynqmp/pm_service/pm_svc_main.h | 41 ++ plat/xilinx/zynqmp/sip_svc_setup.c | 114 +++++ plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk | 31 ++ plat/xilinx/zynqmp/tsp/tsp_plat_setup.c | 104 +++++ plat/xilinx/zynqmp/zynqmp_def.h | 207 +++++++++ plat/xilinx/zynqmp/zynqmp_private.h | 42 ++ 25 files changed, 3532 insertions(+) create mode 100644 docs/plat/xilinx-zynqmp.md create mode 100644 plat/xilinx/zynqmp/aarch64/zynqmp_common.c create mode 100644 plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S create mode 100644 plat/xilinx/zynqmp/bl31_zynqmp_setup.c create mode 100644 plat/xilinx/zynqmp/include/plat_macros.S create mode 100644 plat/xilinx/zynqmp/include/platform_def.h create mode 100644 plat/xilinx/zynqmp/plat_psci.c create mode 100644 plat/xilinx/zynqmp/plat_topology.c create mode 100644 plat/xilinx/zynqmp/plat_zynqmp.c create mode 100644 plat/xilinx/zynqmp/platform.mk create mode 100644 plat/xilinx/zynqmp/pm_service/pm_api_sys.c create mode 100644 plat/xilinx/zynqmp/pm_service/pm_api_sys.h create mode 100644 plat/xilinx/zynqmp/pm_service/pm_client.c create mode 100644 plat/xilinx/zynqmp/pm_service/pm_client.h create mode 100644 plat/xilinx/zynqmp/pm_service/pm_common.h create mode 100644 plat/xilinx/zynqmp/pm_service/pm_defs.h create mode 100644 plat/xilinx/zynqmp/pm_service/pm_ipi.c create mode 100644 plat/xilinx/zynqmp/pm_service/pm_ipi.h create mode 100644 plat/xilinx/zynqmp/pm_service/pm_svc_main.c create mode 100644 plat/xilinx/zynqmp/pm_service/pm_svc_main.h create mode 100644 plat/xilinx/zynqmp/sip_svc_setup.c create mode 100644 plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk create mode 100644 plat/xilinx/zynqmp/tsp/tsp_plat_setup.c create mode 100644 plat/xilinx/zynqmp/zynqmp_def.h create mode 100644 plat/xilinx/zynqmp/zynqmp_private.h diff --git a/docs/plat/xilinx-zynqmp.md b/docs/plat/xilinx-zynqmp.md new file mode 100644 index 000000000..997d9a9a3 --- /dev/null +++ b/docs/plat/xilinx-zynqmp.md @@ -0,0 +1,49 @@ +ARM Trusted Firmware for Xilinx Zynq UltraScale+ MPSoC +================================ + +ARM Trusted Firmware implements the EL3 firmware layer for Xilinx Zynq +UltraScale + MPSoC. +The platform only uses the runtime part of ATF as ZynqMP already has a +BootROM (BL1) and FSBL (BL2). + +BL31 is ATF. +BL32 is an optional Secure Payload. +BL33 is the non-secure world software (U-Boot, Linux etc). + +To build: +```bash +make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31 +``` + +To build bl32 TSP you have to rebuild bl31 too: +```bash +make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32 +``` + +# ZynqMP platform specific build options +* `ZYNQMP_ATF_LOCATION`: Specifies the location of the bl31 binary. Options: + - `tsram` : bl31 will be located in OCM (default) + - `tdram` : bl31 will be located in DRAM (address: 0x30000000) + +* `ZYNQMP_TSP_RAM_LOCATION`: Specifies the location of the bl32 binary and + secure payload dispatcher. Options: + - `tsram` : bl32/spd will be located in OCM (default) + - `tdram` : bl32/spd will be located in DRAM (address: 0x30000000) + +# Power Domain Tree +The following power domain tree represents the power domain model used by the +ATF for ZynqMP: +``` + +-+ + |0| + +-+ + +-------+---+---+-------+ + | | | | + | | | | + v v v v + +-+ +-+ +-+ +-+ + |0| |1| |2| |3| + +-+ +-+ +-+ +-+ +``` +The 4 leaf power domains represent the individual A53 cores, while resources +common to the cluster are grouped in the power domain on the top. diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c new file mode 100644 index 000000000..0a878c30e --- /dev/null +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../zynqmp_private.h" + +/* + * Table of regions to map using the MMU. + * This doesn't include TZRAM as the 'mem_layout' argument passed to + * configure_mmu_elx() will give the available subset of that, + */ +const mmap_region_t plat_arm_mmap[] = { + { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + {0} +}; + +static unsigned int zynqmp_get_silicon_ver(void) +{ + unsigned int ver; + + ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); + ver &= ZYNQMP_SILICON_VER_MASK; + ver >>= ZYNQMP_SILICON_VER_SHIFT; + + return ver; +} + +unsigned int zynqmp_get_uart_clk(void) +{ + unsigned int ver = zynqmp_get_silicon_ver(); + + switch (ver) { + case ZYNQMP_CSU_VERSION_VELOCE: + return 48000; + case ZYNQMP_CSU_VERSION_EP108: + return 25000000; + case ZYNQMP_CSU_VERSION_QEMU: + return 133000000; + } + + return 100000000; +} + +static unsigned int zynqmp_get_system_timer_freq(void) +{ + unsigned int ver = zynqmp_get_silicon_ver(); + + switch (ver) { + case ZYNQMP_CSU_VERSION_VELOCE: + return 10000; + case ZYNQMP_CSU_VERSION_EP108: + return 4000000; + case ZYNQMP_CSU_VERSION_QEMU: + return 50000000; + } + + return 100000000; +} + +#if LOG_LEVEL >= LOG_LEVEL_NOTICE +static const struct { + unsigned int id; + char *name; +} zynqmp_devices[] = { + { + .id = 0x10, + .name = "3EG", + }, + { + .id = 0x11, + .name = "2EG", + }, + { + .id = 0x20, + .name = "5EV", + }, + { + .id = 0x21, + .name = "4EV", + }, + { + .id = 0x30, + .name = "7EV", + }, + { + .id = 0x38, + .name = "9EG", + }, + { + .id = 0x39, + .name = "6EG", + }, + { + .id = 0x40, + .name = "11EG", + }, + { + .id = 0x50, + .name = "15EG", + }, + { + .id = 0x58, + .name = "19EG", + }, + { + .id = 0x59, + .name = "17EG", + }, +}; + +static unsigned int zynqmp_get_silicon_id(void) +{ + uint32_t id; + + id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); + + id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK; + id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; + + return id; +} + +static char *zynqmp_get_silicon_idcode_name(void) +{ + unsigned int id; + + id = zynqmp_get_silicon_id(); + for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { + if (zynqmp_devices[i].id == id) + return zynqmp_devices[i].name; + } + return "UNKN"; +} + +static unsigned int zynqmp_get_rtl_ver(void) +{ + uint32_t ver; + + ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); + ver &= ZYNQMP_RTL_VER_MASK; + ver >>= ZYNQMP_RTL_VER_SHIFT; + + return ver; +} + +static char *zynqmp_print_silicon_idcode(void) +{ + uint32_t id, maskid, tmp; + + id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); + + tmp = id; + tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK | + ZYNQMP_CSU_IDCODE_FAMILY_MASK | + ZYNQMP_CSU_IDCODE_REVISION_MASK; + maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT | + ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT | + ZYNQMP_CSU_IDCODE_REVISION << ZYNQMP_CSU_IDCODE_REVISION_SHIFT; + if (tmp != maskid) { + ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid); + return "UNKN"; + } + VERBOSE("Xilinx IDCODE 0x%x\n", id); + return zynqmp_get_silicon_idcode_name(); +} + +static unsigned int zynqmp_get_ps_ver(void) +{ + uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); + + ver &= ZYNQMP_PS_VER_MASK; + ver >>= ZYNQMP_PS_VER_SHIFT; + + return ver + 1; +} + +static void zynqmp_print_platform_name(void) +{ + unsigned int ver = zynqmp_get_silicon_ver(); + unsigned int rtl = zynqmp_get_rtl_ver(); + char *label = "Unknown"; + + switch (ver) { + case ZYNQMP_CSU_VERSION_VELOCE: + label = "VELOCE"; + break; + case ZYNQMP_CSU_VERSION_EP108: + label = "EP108"; + break; + case ZYNQMP_CSU_VERSION_QEMU: + label = "QEMU"; + break; + case ZYNQMP_CSU_VERSION_SILICON: + label = "silicon"; + break; + } + + NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n", + zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(), + (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE, + zynqmp_is_pmu_up() ? ", with PMU firmware" : ""); +} +#else +static inline void zynqmp_print_platform_name(void) { } +#endif + +/* + * Indicator for PMUFW discovery: + * 0 = No FW found + * non-zero = FW is present + */ +static int zynqmp_pmufw_present; + +/* + * zynqmp_discover_pmufw - Discover presence of PMUFW + * + * Discover the presence of PMUFW and store it for later run-time queries + * through zynqmp_is_pmu_up. + * NOTE: This discovery method is fragile and will break if: + * - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW + * (be it by error or intentionally) + * - XPPU/XMPU may restrict ATF's access to the PMU address space + */ +static int zynqmp_discover_pmufw(void) +{ + zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL); + zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT; + + return !!zynqmp_pmufw_present; +} + +/* + * zynqmp_is_pmu_up - Find if PMU firmware is up and running + * + * Return 0 if firmware is not available, non 0 otherwise + */ +int zynqmp_is_pmu_up(void) +{ + return zynqmp_pmufw_present; +} + +/* + * A single boot loader stack is expected to work on both the Foundation ZYNQMP + * models and the two flavours of the Base ZYNQMP models (AEMv8 & Cortex). The + * SYS_ID register provides a mechanism for detecting the differences between + * these platforms. This information is stored in a per-BL array to allow the + * code to take the correct path.Per BL platform configuration. + */ +void zynqmp_config_setup(void) +{ + zynqmp_discover_pmufw(); + zynqmp_print_platform_name(); + + /* Global timer init - Program time stamp reference clk */ + uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL); + val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; + mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val); + + /* Program freq register in System counter and enable system counter. */ + mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq()); + mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN); +} + +uint64_t plat_get_syscnt_freq(void) +{ + uint64_t counter_base_frequency; + + /* FIXME: Read the frequency from Frequency modes table */ + counter_base_frequency = zynqmp_get_system_timer_freq(); + + return counter_base_frequency; +} diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S new file mode 100644 index 000000000..0afed47c8 --- /dev/null +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + + .globl plat_secondary_cold_boot_setup + .globl plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset e.g + * mark the cpu's presence, mechanism to place it in a + * holding pen etc. + * TODO: Should we read the PSYS register to make sure + * that the request has gone through. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + mrs x0, mpidr_el1 + + /* Deactivate the gic cpu interface */ + ldr x1, =BASE_GICC_BASE + mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1) + orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0) + str w0, [x1, #GICC_CTLR] + + /* + * There is no sane reason to come out of this wfi. This + * cpu will be powered on and reset by the cpu_on pm api + */ + dsb sy +1: + bl plat_panic_handler +endfunc plat_secondary_cold_boot_setup + +func plat_is_my_cpu_primary + mov x9, x30 + bl plat_my_core_pos + cmp x0, #ZYNQMP_PRIMARY_CPU + cset x0, eq + ret x9 +endfunc plat_is_my_cpu_primary diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c new file mode 100644 index 000000000..9c9d18d14 --- /dev/null +++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "zynqmp_private.h" + +/* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + */ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL31_RO_BASE (unsigned long)(&__RO_START__) +#define BL31_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols + * refer to page-aligned addresses. + */ +#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + */ +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + assert(sec_state_is_valid(type)); + + if (type == NON_SECURE) + return &bl33_image_ep_info; + + return &bl32_image_ep_info; +} + +/* + * Perform any BL31 specific platform actions. Here is an opportunity to copy + * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they + * are lost (potentially). This needs to be done before the MMU is initialized + * so that the memory layout can be used while creating page tables. + */ +void bl31_early_platform_setup(bl31_params_t *from_bl2, + void *plat_params_from_bl2) +{ + /* Initialize the console to provide early debug support */ + console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(), + ZYNQMP_UART_BAUDRATE); + + /* Initialize the platform config for future decision making */ + zynqmp_config_setup(); + + /* There are no parameters from BL2 if BL31 is a reset vector */ + assert(from_bl2 == NULL); + assert(plat_params_from_bl2 == NULL); + + /* + * Do initial security configuration to allow DRAM/device access. On + * Base ZYNQMP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + + /* Populate entry point information for BL32 and BL33 */ + SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); + + NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); + + SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); + + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + + NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); +} + +void bl31_platform_setup(void) +{ + /* Initialize the gic cpu and distributor interfaces */ + plat_arm_gic_driver_init(); + plat_arm_gic_init(); +} + +void bl31_plat_runtime_setup(void) +{ +} + +/* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the MMU in a quick and dirty way. + */ +void bl31_plat_arch_setup(void) +{ + plat_arm_interconnect_init(); + plat_arm_interconnect_enter_coherency(); + + arm_configure_mmu_el3(BL31_RO_BASE, + BL31_COHERENT_RAM_LIMIT - BL31_RO_BASE, + BL31_RO_BASE, + BL31_RO_LIMIT, + BL31_COHERENT_RAM_BASE, + BL31_COHERENT_RAM_LIMIT); +} diff --git a/plat/xilinx/zynqmp/include/plat_macros.S b/plat/xilinx/zynqmp/include/plat_macros.S new file mode 100644 index 000000000..e6c39bb51 --- /dev/null +++ b/plat/xilinx/zynqmp/include/plat_macros.S @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __PLAT_MACROS_S__ +#define __PLAT_MACROS_S__ + +#include +#include +#include "../zynqmp_def.h" + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant GIC registers whenever an + * unhandled exception is taken in BL31. + * Clobbers: x0 - x10, x16, sp + * --------------------------------------------- + */ + .macro plat_print_gic_regs + mov_imm x17, BASE_GICC_BASE + mov_imm x16, BASE_GICD_BASE + arm_print_gic_regs + mov x0, x1 + .endm + +#endif /* __PLAT_MACROS_S__ */ diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h new file mode 100644 index 000000000..947a0f3bc --- /dev/null +++ b/plat/xilinx/zynqmp/include/platform_def.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +#include +#include "../zynqmp_def.h" + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#define PLATFORM_STACK_SIZE 0x440 + +#define PLATFORM_CORE_COUNT 4 +#define PLAT_NUM_POWER_DOMAINS 5 +#define PLAT_MAX_PWR_LVL 1 +#define PLAT_MAX_RET_STATE 1 +#define PLAT_MAX_OFF_STATE 2 + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ + +#define ZYNQMP_BL31_SIZE 0x1b000 +/* + * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if + * present). BL31_BASE is calculated using the current BL31 debug size plus a + * little space for growth. + */ +#if ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM +# define BL31_BASE (ZYNQMP_TRUSTED_SRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +# define BL31_PROGBITS_LIMIT (ZYNQMP_TRUSTED_SRAM_LIMIT - 0x6000) +# define BL31_LIMIT ZYNQMP_TRUSTED_SRAM_LIMIT +#elif ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM +# define BL31_BASE (ZYNQMP_TRUSTED_DRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +# define BL31_PROGBITS_LIMIT (ZYNQMP_TRUSTED_DRAM_LIMIT - 0x6000) +# define BL31_LIMIT (ZYNQMP_TRUSTED_DRAM_BASE + \ + ZYNQMP_TRUSTED_DRAM_SIZE) +#else +# error "Unsupported ZYNQMP_ATF_LOCATION_ID value" +#endif + +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +/* + * On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM. + */ +#if ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM +# define TSP_SEC_MEM_BASE ZYNQMP_TRUSTED_SRAM_BASE +# define TSP_SEC_MEM_SIZE ZYNQMP_TRUSTED_SRAM_SIZE +# define TSP_PROGBITS_LIMIT (ZYNQMP_TRUSTED_SRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +# define BL32_BASE ZYNQMP_TRUSTED_SRAM_BASE +# define BL32_LIMIT (ZYNQMP_TRUSTED_SRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +#elif ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM +# define TSP_SEC_MEM_BASE ZYNQMP_TRUSTED_DRAM_BASE +# define TSP_SEC_MEM_SIZE (ZYNQMP_TRUSTED_DRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +# define BL32_BASE ZYNQMP_TRUSTED_DRAM_BASE +# define BL32_LIMIT (ZYNQMP_TRUSTED_DRAM_LIMIT - \ + ZYNQMP_BL31_SIZE) +#else +# error "Unsupported ZYNQMP_TSP_RAM_LOCATION_ID value" +#endif + +/* + * ID of the secure physical generic timer interrupt used by the TSP. + */ +#define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define ADDR_SPACE_SIZE (1ull << 32) +#define MAX_XLAT_TABLES 5 +#define MAX_MMAP_REGIONS 7 + +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + +#define PLAT_ARM_GICD_BASE BASE_GICD_BASE +#define PLAT_ARM_GICC_BASE BASE_GICC_BASE +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLAT_ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \ + IRQ_SEC_IPI_APU, \ + ARM_IRQ_SEC_SGI_0, \ + ARM_IRQ_SEC_SGI_1, \ + ARM_IRQ_SEC_SGI_2, \ + ARM_IRQ_SEC_SGI_3, \ + ARM_IRQ_SEC_SGI_4, \ + ARM_IRQ_SEC_SGI_5, \ + ARM_IRQ_SEC_SGI_6, \ + ARM_IRQ_SEC_SGI_7 + +#define PLAT_ARM_G0_IRQS + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c new file mode 100644 index 000000000..d693a2dbf --- /dev/null +++ b/plat/xilinx/zynqmp/plat_psci.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" +#include "zynqmp_private.h" + +uintptr_t zynqmp_sec_entry; + +void zynqmp_cpu_standby(plat_local_state_t cpu_state) +{ + VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); + + dsb(); + wfi(); +} + +static int zynqmp_nopmu_pwr_domain_on(u_register_t mpidr) +{ + uint32_t r; + unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); + + VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); + + if (cpu_id == -1) + return PSCI_E_INTERN_FAIL; + + /* program RVBAR */ + mmio_write_32(APU_RVBAR_L_0 + (cpu_id << 3), zynqmp_sec_entry); + mmio_write_32(APU_RVBAR_H_0 + (cpu_id << 3), zynqmp_sec_entry >> 32); + + /* clear VINITHI */ + r = mmio_read_32(APU_CONFIG_0); + r &= ~(1 << APU_CONFIG_0_VINITHI_SHIFT << cpu_id); + mmio_write_32(APU_CONFIG_0, r); + + /* clear power down request */ + r = mmio_read_32(APU_PWRCTL); + r &= ~(1 << cpu_id); + mmio_write_32(APU_PWRCTL, r); + + /* power up island */ + mmio_write_32(PMU_GLOBAL_REQ_PWRUP_EN, 1 << cpu_id); + mmio_write_32(PMU_GLOBAL_REQ_PWRUP_TRIG, 1 << cpu_id); + /* FIXME: we should have a way to break out */ + while (mmio_read_32(PMU_GLOBAL_REQ_PWRUP_STATUS) & (1 << cpu_id)) + ; + + /* release core reset */ + r = mmio_read_32(CRF_APB_RST_FPD_APU); + r &= ~((CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET | + CRF_APB_RST_FPD_APU_ACPU_RESET) << cpu_id); + mmio_write_32(CRF_APB_RST_FPD_APU, r); + + return PSCI_E_SUCCESS; +} + +static int zynqmp_pwr_domain_on(u_register_t mpidr) +{ + 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; + + proc = pm_get_proc(cpu_id); + + /* Send request to PMU to wake up selected APU CPU core */ + pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_NO); + + return PSCI_E_SUCCESS; +} + +static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state) +{ + uint32_t r; + unsigned int cpu_id = plat_my_core_pos(); + + 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 */ + gicv2_cpuif_disable(); + + /* set power down request */ + r = mmio_read_32(APU_PWRCTL); + r |= (1 << cpu_id); + mmio_write_32(APU_PWRCTL, r); +} + +static void zynqmp_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 */ + gicv2_cpuif_disable(); + + /* + * Send request to PMU 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, 0, 0); +} + +static void zynqmp_nopmu_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + uint32_t r; + unsigned int cpu_id = plat_my_core_pos(); + + 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]); + + /* set power down request */ + r = mmio_read_32(APU_PWRCTL); + r |= (1 << cpu_id); + mmio_write_32(APU_PWRCTL, r); + + /* program RVBAR */ + mmio_write_32(APU_RVBAR_L_0 + (cpu_id << 3), zynqmp_sec_entry); + mmio_write_32(APU_RVBAR_H_0 + (cpu_id << 3), zynqmp_sec_entry >> 32); + + /* clear VINITHI */ + r = mmio_read_32(APU_CONFIG_0); + r &= ~(1 << APU_CONFIG_0_VINITHI_SHIFT << cpu_id); + mmio_write_32(APU_CONFIG_0, r); + + /* enable power up on IRQ */ + mmio_write_32(PMU_GLOBAL_REQ_PWRUP_EN, 1 << cpu_id); +} + +static void zynqmp_pwr_domain_suspend(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]); + + /* Send request to PMU to suspend this core */ + pm_self_suspend(proc->node_id, MAX_LATENCY, 0, zynqmp_sec_entry); + + /* APU is to be turned off */ + if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { + /* Power down L2 cache */ + pm_set_requirement(NODE_L2, 0, 0, REQ_ACK_NO); + /* Send request for OCM retention state */ + set_ocm_retention(); + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + } +} + +static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + 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]); + + gicv2_cpuif_enable(); + gicv2_pcpu_distif_init(); +} + +static void zynqmp_nopmu_pwr_domain_suspend_finish(const psci_power_state_t *target_state) +{ + uint32_t r; + unsigned int cpu_id = plat_my_core_pos(); + + 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]); + + /* disable power up on IRQ */ + mmio_write_32(PMU_GLOBAL_REQ_PWRUP_DIS, 1 << cpu_id); + + /* clear powerdown bit */ + r = mmio_read_32(APU_PWRCTL); + r &= ~(1 << cpu_id); + mmio_write_32(APU_PWRCTL, r); +} + +static void zynqmp_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(); +} + +/******************************************************************************* + * ZynqMP handlers to shutdown/reboot the system + ******************************************************************************/ +static void __dead2 zynqmp_nopmu_system_off(void) +{ + ERROR("ZynqMP System Off: operation not handled.\n"); + + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + + panic(); +} + +static void __dead2 zynqmp_system_off(void) +{ + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + + /* Send the power down request to the PMU */ + pm_system_shutdown(0); + + while (1) + wfi(); +} + +static void __dead2 zynqmp_nopmu_system_reset(void) +{ + /* + * This currently triggers a system reset. I.e. the whole + * system will be reset! Including RPUs, PMU, PL, etc. + */ + + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + + /* bypass RPLL (needed on 1.0 silicon) */ + uint32_t reg = mmio_read_32(CRL_APB_RPLL_CTRL); + reg |= CRL_APB_RPLL_CTRL_BYPASS; + mmio_write_32(CRL_APB_RPLL_CTRL, reg); + + /* trigger system reset */ + mmio_write_32(CRL_APB_RESET_CTRL, CRL_APB_RESET_CTRL_SOFT_RESET); + + while (1) + wfi(); +} + +static void __dead2 zynqmp_system_reset(void) +{ + /* disable coherency */ + plat_arm_interconnect_exit_coherency(); + + /* Send the system reset request to the PMU */ + pm_system_shutdown(1); + + while (1) + wfi(); +} + +int zynqmp_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); + + /* FIXME: populate req_state */ + return PSCI_E_SUCCESS; +} + +int zynqmp_validate_ns_entrypoint(unsigned long ns_entrypoint) +{ + VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); + + /* FIXME: Actually validate */ + return PSCI_E_SUCCESS; +} + +void zynqmp_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; +} + +/******************************************************************************* + * Export the platform handlers to enable psci to invoke them + ******************************************************************************/ +static const struct plat_psci_ops zynqmp_psci_ops = { + .cpu_standby = zynqmp_cpu_standby, + .pwr_domain_on = zynqmp_pwr_domain_on, + .pwr_domain_off = zynqmp_pwr_domain_off, + .pwr_domain_suspend = zynqmp_pwr_domain_suspend, + .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish, + .pwr_domain_suspend_finish = zynqmp_pwr_domain_suspend_finish, + .system_off = zynqmp_system_off, + .system_reset = zynqmp_system_reset, + .validate_power_state = zynqmp_validate_power_state, + .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint, + .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state, +}; + +static const struct plat_psci_ops zynqmp_nopmu_psci_ops = { + .cpu_standby = zynqmp_cpu_standby, + .pwr_domain_on = zynqmp_nopmu_pwr_domain_on, + .pwr_domain_off = zynqmp_nopmu_pwr_domain_off, + .pwr_domain_suspend = zynqmp_nopmu_pwr_domain_suspend, + .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish, + .pwr_domain_suspend_finish = zynqmp_nopmu_pwr_domain_suspend_finish, + .system_off = zynqmp_nopmu_system_off, + .system_reset = zynqmp_nopmu_system_reset, + .validate_power_state = zynqmp_validate_power_state, + .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint, + .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state, +}; + +/******************************************************************************* + * Export the platform specific power ops. + ******************************************************************************/ +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const struct plat_psci_ops **psci_ops) +{ + zynqmp_sec_entry = sec_entrypoint; + + if (zynqmp_is_pmu_up()) + *psci_ops = &zynqmp_psci_ops; + else + *psci_ops = &zynqmp_nopmu_psci_ops; + + return 0; +} diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c new file mode 100644 index 000000000..34e7b53b6 --- /dev/null +++ b/plat/xilinx/zynqmp/plat_topology.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +static const unsigned char plat_power_domain_tree_desc[] = {1, 4}; + +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return plat_power_domain_tree_desc; +} diff --git a/plat/xilinx/zynqmp/plat_zynqmp.c b/plat/xilinx/zynqmp/plat_zynqmp.c new file mode 100644 index 000000000..38fa20f86 --- /dev/null +++ b/plat/xilinx/zynqmp/plat_zynqmp.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + if (mpidr & MPIDR_CLUSTER_MASK) + return -1; + + if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) + return -1; + + return plat_arm_calc_core_pos(mpidr); +} diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk new file mode 100644 index 000000000..0ffc0a9ca --- /dev/null +++ b/plat/xilinx/zynqmp/platform.mk @@ -0,0 +1,95 @@ +# Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# Neither the name of ARM nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +ENABLE_PLAT_COMPAT := 0 +PROGRAMMABLE_RESET_ADDRESS := 1 +PSCI_EXTENDED_STATE_ID := 1 +A53_DISABLE_NON_TEMPORAL_HINT := 0 + +ZYNQMP_ATF_LOCATION ?= tsram +ifeq (${ZYNQMP_ATF_LOCATION}, tsram) + ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM +else ifeq (${ZYNQMP_ATF_LOCATION}, tdram) + ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM +else + $(error "Unsupported ZYNQMP_ATF_LOCATION value") +endif + +# On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM. +# Trusted SRAM is the default. +ZYNQMP_TSP_RAM_LOCATION ?= tsram +ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tsram) + ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM +else ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tdram) + ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM +else + $(error "Unsupported ZYNQMP_TSP_RAM_LOCATION value") +endif + +# Process flags +$(eval $(call add_define,ZYNQMP_ATF_LOCATION_ID)) +$(eval $(call add_define,ZYNQMP_TSP_RAM_LOCATION_ID)) + +PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ + -Iinclude/plat/arm/common/aarch64/ \ + -Iplat/xilinx/zynqmp/include/ \ + -Iplat/xilinx/zynqmp/pm_service/ + +PLAT_BL_COMMON_SOURCES := lib/aarch64/xlat_tables.c \ + drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v2/gicv2_main.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + drivers/cadence/uart/cdns_console.S \ + drivers/console/console.S \ + plat/arm/common/aarch64/arm_common.c \ + plat/arm/common/aarch64/arm_helpers.S \ + plat/arm/common/arm_cci.c \ + plat/arm/common/arm_gicv2.c \ + plat/common/plat_gicv2.c \ + plat/common/aarch64/plat_common.c \ + plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S \ + plat/xilinx/zynqmp/aarch64/zynqmp_common.c + +BL31_SOURCES += drivers/arm/cci/cci.c \ + lib/cpus/aarch64/aem_generic.S \ + lib/cpus/aarch64/cortex_a53.S \ + plat/common/aarch64/plat_psci_common.c \ + plat/common/aarch64/platform_mp_stack.S \ + plat/xilinx/zynqmp/bl31_zynqmp_setup.c \ + plat/xilinx/zynqmp/plat_psci.c \ + plat/xilinx/zynqmp/plat_zynqmp.c \ + plat/xilinx/zynqmp/plat_topology.c \ + plat/xilinx/zynqmp/sip_svc_setup.c \ + plat/xilinx/zynqmp/pm_service/pm_svc_main.c \ + plat/xilinx/zynqmp/pm_service/pm_api_sys.c \ + plat/xilinx/zynqmp/pm_service/pm_ipi.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_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c new file mode 100644 index 000000000..2f2e2edfe --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ZynqMP system level PM-API functions and communication with PMU via + * IPI interrupts + */ + +#include +#include +#include "pm_client.h" +#include "pm_common.h" +#include "pm_api_sys.h" + +/** + * Assigning of argument values into array elements. + */ +#define PM_PACK_PAYLOAD1(pl, arg0) { \ + pl[0] = (uint32_t)(arg0); \ +} + +#define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \ + pl[1] = (uint32_t)(arg1); \ + PM_PACK_PAYLOAD1(pl, arg0); \ +} + +#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \ + pl[2] = (uint32_t)(arg2); \ + PM_PACK_PAYLOAD2(pl, arg0, arg1); \ +} + +#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \ + pl[3] = (uint32_t)(arg3); \ + PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \ +} + +#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \ + pl[4] = (uint32_t)(arg4); \ + PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \ +} + +#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \ + pl[5] = (uint32_t)(arg5); \ + PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \ +} + +/** + * 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 (not supported) + * @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(enum pm_node_id 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); + + /* + * Do client specific suspend operations + * (e.g. set powerdown request bit) + */ + pm_client_suspend(proc); + /* Send request to the PMU */ + PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, + state, address, (address >> 32)); + return pm_ipi_send_sync(proc, payload, NULL); +} + +/** + * 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(enum pm_node_id target, + enum pm_request_ack ack, + unsigned int latency, unsigned int state) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state); + if (ack == REQ_ACK_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_req_wakeup() - PM call for processor to wake up selected processor + * or subsystem + * @target Node id of the processor or subsystem to wake up + * @ack Flag to specify whether acknowledge requested + * @set_address Resume address presence indicator + * 1 resume address specified, 0 otherwise + * @address Resume address + * + * 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 PMU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_wakeup(enum pm_node_id target, + unsigned int set_address, + uintptr_t address, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + uint64_t encoded_address; + const struct pm_proc *proc = pm_get_proc_by_node(target); + + /* invoke APU-specific code for waking up another APU core */ + pm_client_wakeup(proc); + + /* encode set Address into 1st bit of address */ + encoded_address = address; + encoded_address |= !!set_address; + + /* Send request to the PMU to perform the wake of the PU */ + PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address, + encoded_address >> 32, ack); + + if (ack == REQ_ACK_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_force_powerdown() - PM call to request for another PU or subsystem to + * be powered down forcefully + * @target Node id of the targeted PU or subsystem + * @ack Flag to specify whether acknowledge is requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_force_powerdown(enum pm_node_id target, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack); + + if (ack == REQ_ACK_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * 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 PMU */ + /* TODO: allow passing the node ID of the affected CPU */ + PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason, + primary_proc->node_id); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended + * @target Node id of the targeted PU or subsystem + * @wkup_node Node 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(enum pm_node_id target, + enum pm_node_id wkup_node, + unsigned int enable) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node, + enable); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_system_shutdown() - PM call to request a system shutdown or restart + * @restart Shutdown or restart? 0 for shutdown, 1 for restart + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_system_shutdown(unsigned int restart) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD2(payload, PM_SYSTEM_SHUTDOWN, restart); + return pm_ipi_send(primary_proc, payload); +} + +/* APIs for managing PM slaves: */ + +/** + * pm_req_node() - PM call to request a node with specific capabilities + * @nid Node id of the slave + * @capabilities Requested capabilities of the slave + * @qos Quality of service (not supported) + * @ack Flag to specify whether acknowledge is requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_node(enum pm_node_id nid, + unsigned int capabilities, + unsigned int qos, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack); + + if (ack == REQ_ACK_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_set_requirement() - PM call to set requirement for PM slaves + * @nid Node id of the slave + * @capabilities Requested capabilities of the slave + * @qos Quality of service (not supported) + * @ack Flag to specify whether acknowledge is requested + * + * This API function is to be used for slaves a PU already has requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_requirement(enum pm_node_id nid, + unsigned int capabilities, + unsigned int qos, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos, + ack); + + if (ack == REQ_ACK_BLOCKING) + return pm_ipi_send_sync(primary_proc, payload, NULL); + else + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_release_node() - PM call to release a node + * @nid Node id of the slave + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_release_node(enum pm_node_id nid) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_set_max_latency() - PM call to set wakeup latency requirements + * @nid Node id of the slave + * @latency Requested maximum wakeup latency + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_max_latency(enum pm_node_id nid, + unsigned int latency) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency); + return pm_ipi_send(primary_proc, payload); +} + +/* Miscellaneous API functions */ + +/** + * pm_get_api_version() - Get version number of PMU PM firmware + * @version Returns 32-bit version number of PMU 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 PMU */ + PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION); + return pm_ipi_send_sync(primary_proc, payload, version); +} + +/** + * pm_set_configuration() - PM call to set system configuration + * @phys_addr Physical 32-bit address of data structure in memory + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_configuration(unsigned int phys_addr) +{ + return PM_RET_ERROR_NOTSUPPORTED; +} + +/** + * pm_get_node_status() - PM call to request a node's current power state + * @nid Node id of the slave + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_node_status(enum pm_node_id nid) +{ + /* TODO: Add power state argument!! */ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_register_notifier() - Register the PU to be notified of PM events + * @nid Node id of the slave + * @event The event to be notified about + * @wake Wake up on event + * @enable Enable or disable the notifier + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_register_notifier(enum pm_node_id nid, + unsigned int event, + unsigned int wake, + unsigned int enable) +{ + return PM_RET_ERROR_NOTSUPPORTED; +} + +/** + * pm_get_op_characteristic() - PM call to get a particular operating + * characteristic of a node + * @nid Node ID + * @type Operating characterstic type to be returned + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid, + enum pm_opchar_type type) +{ + return PM_RET_ERROR_NOTSUPPORTED; +} + +/* Direct-Control API functions */ + +/** + * pm_reset_assert() - 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(unsigned int reset, + unsigned int assert) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_reset_get_status() - Get current status of a reset line + * @reset Reset ID + * @reset_status Returns current status of selected reset line + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_reset_get_status(unsigned int reset, + unsigned int *reset_status) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset); + return pm_ipi_send_sync(primary_proc, payload, reset_status); +} + +/** + * pm_mmio_write() - Perform write to protected mmio + * @address Address to write to + * @mask Mask to apply + * @value Value to write + * + * This function provides access to PM-related control registers + * that may not be directly accessible by a particular PU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_mmio_write(uintptr_t address, + unsigned int mask, + unsigned int value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value); + return pm_ipi_send(primary_proc, payload); +} + +/** + * pm_mmio_read() - Read value from protected mmio + * @address Address to write to + * @value Value to write + * + * This function provides access to PM-related control registers + * that may not be directly accessible by a particular PU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address); + return pm_ipi_send_sync(primary_proc, payload, value); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h new file mode 100644 index 000000000..f0365cd99 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PM_API_SYS_H_ +#define _PM_API_SYS_H_ + +#include +#include "pm_defs.h" + +/********************************************************** + * System-level API function declarations + **********************************************************/ +enum pm_ret_status pm_req_suspend(enum pm_node_id nid, + enum pm_request_ack ack, + unsigned int latency, + unsigned int state); + +enum pm_ret_status pm_self_suspend(enum pm_node_id nid, + unsigned int latency, + unsigned int state, + uintptr_t address); + +enum pm_ret_status pm_force_powerdown(enum pm_node_id nid, + enum pm_request_ack ack); + +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason); + +enum pm_ret_status pm_req_wakeup(enum pm_node_id nid, + unsigned int set_address, + uintptr_t address, + enum pm_request_ack ack); + +enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, + enum pm_node_id wkup_node, + unsigned int enable); + +enum pm_ret_status pm_system_shutdown(unsigned int restart); + +enum pm_ret_status pm_init_suspend_cb(enum pm_suspend_reason reason, + unsigned int latency, + unsigned int state, + unsigned int timeout); + +/* API functions for managing PM Slaves */ +enum pm_ret_status pm_req_node(enum pm_node_id nid, + unsigned int capabilities, + unsigned int qos, + enum pm_request_ack ack); +enum pm_ret_status pm_release_node(enum pm_node_id nid); + +enum pm_ret_status pm_set_requirement(enum pm_node_id nid, + unsigned int capabilities, + unsigned int qos, + enum pm_request_ack ack); +enum pm_ret_status pm_set_max_latency(enum pm_node_id nid, + unsigned int latency); + +/* Miscellaneous API functions */ +enum pm_ret_status pm_get_api_version(unsigned int *version); +enum pm_ret_status pm_set_configuration(unsigned int phys_addr); +enum pm_ret_status pm_get_node_status(enum pm_node_id node); +enum pm_ret_status pm_register_notifier(enum pm_node_id nid, + unsigned int event, + unsigned int wake, + unsigned int enable); +enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid, + enum pm_opchar_type type); +enum pm_ret_status pm_acknowledge_cb(enum pm_node_id nid, + enum pm_ret_status status, + unsigned int oppoint); +enum pm_ret_status pm_notify_cb(enum pm_node_id nid, + unsigned int event, + unsigned int oppoint); + +/* Direct-Control API functions */ +enum pm_ret_status pm_reset_assert(unsigned int reset_id, + unsigned int assert); +enum pm_ret_status pm_reset_get_status(unsigned int reset_id, + unsigned int *reset_status); +enum pm_ret_status pm_mmio_write(uintptr_t address, + unsigned int mask, + unsigned int value); +enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value); +#endif /* _PM_API_SYS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c new file mode 100644 index 000000000..eb986bca4 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_client.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * 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 "pm_api_sys.h" +#include "pm_client.h" +#include "pm_ipi.h" +#include "../zynqmp_def.h" + +#define OCM_BANK_0 0xFFFC0000 +#define OCM_BANK_1 (OCM_BANK_0 + 0x10000) +#define OCM_BANK_2 (OCM_BANK_1 + 0x10000) +#define OCM_BANK_3 (OCM_BANK_2 + 0x10000) + +#define UNDEFINED_CPUID (~0) + +/* Declaration of linker defined symbol */ +extern unsigned long __BL31_END__; +extern const struct pm_ipi apu_ipi; + +/* Order in pm_procs_all array must match cpu ids */ +static const struct pm_proc const pm_procs_all[] = { + { + .node_id = NODE_APU_0, + .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, + .ipi = &apu_ipi, + }, + { + .node_id = NODE_APU_1, + .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, + .ipi = &apu_ipi, + }, + { + .node_id = NODE_APU_2, + .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK, + .ipi = &apu_ipi, + }, + { + .node_id = NODE_APU_3, + .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK, + .ipi = &apu_ipi, + }, +}; + +/** + * set_ocm_retention() - Configure OCM memory banks for retention + * + * APU specific requirements for suspend action: + * OCM has to enter retention state in order to preserve saved + * context after suspend request. OCM banks are determined by + * __BL31_END__ linker symbol. + * + * Return: Returns status, either success or error+reason + */ +enum pm_ret_status set_ocm_retention(void) +{ + enum pm_ret_status ret; + + /* OCM_BANK_0 will always be occupied */ + ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0, + REQ_ACK_NO); + + /* Check for other OCM banks */ + if ((unsigned long)&__BL31_END__ >= OCM_BANK_1) + ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0, + REQ_ACK_NO); + if ((unsigned long)&__BL31_END__ >= OCM_BANK_2) + ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0, + REQ_ACK_NO); + if ((unsigned long)&__BL31_END__ >= OCM_BANK_3) + ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0, + REQ_ACK_NO); + + return ret; +} + +/** + * 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; +} + +/** + * pm_get_proc_by_node() - returns pointer to the proc structure + * @nid: node id of the processor + * + * Return: pointer to a proc structure if proc is found, otherwise NULL + */ +const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid) +{ + for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { + if (nid == pm_procs_all[i].node_id) + return &pm_procs_all[i]; + } + return NULL; +} + +/** + * 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(enum pm_node_id 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; +} + +const struct pm_proc *primary_proc = &pm_procs_all[0]; + +/** + * pm_client_suspend() - Client-specific suspend actions + * + * This function should contain any PU-specific actions + * required prior to sending suspend request to PMU + */ +void pm_client_suspend(const struct pm_proc *proc) +{ + /* Set powerdown request */ + mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask); +} + + +/** + * 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) */ + gicv2_cpuif_enable(); + /* Clear powerdown request */ + mmio_write_32(APU_PWRCTL, + mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask); +} + +/** + * 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; + + /* clear powerdown bit for affected cpu */ + uint32_t val = mmio_read_32(APU_PWRCTL); + val &= ~(proc->pwrdn_mask); + mmio_write_32(APU_PWRCTL, val); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h new file mode 100644 index 000000000..b9f196d77 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_client.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Contains APU specific macros and macros to be defined depending on + * the execution environment. + */ + +#ifndef _PM_CLIENT_H_ +#define _PM_CLIENT_H_ + +#include "pm_defs.h" +#include "pm_common.h" + +/* Functions to be implemented by each PU */ +enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]); +enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + uint32_t *val); +void pm_client_suspend(const struct pm_proc *proc); +void pm_client_abort_suspend(void); +void pm_client_wakeup(const struct pm_proc *proc); +enum pm_ret_status set_ocm_retention(void); + +/* 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_common.h b/plat/xilinx/zynqmp/pm_service/pm_common.h new file mode 100644 index 000000000..b432a8367 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_common.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Contains definitions of commonly used macros and data types needed + * for PU Power Management. This file should be common for all PU's. + */ + +#ifndef _PM_COMMON_H_ +#define _PM_COMMON_H_ + +#include +#include +#include "pm_defs.h" + +#define PAYLOAD_ARG_CNT 6U +#define PAYLOAD_ARG_SIZE 4U /* size in bytes */ + +/** + * pm_ipi - struct for capturing IPI-channel specific info + * @mask mask for enabling/disabling and triggering the IPI + * @base base address for IPI + * @buffer_base base address for payload buffer + */ +struct pm_ipi { + const unsigned int mask; + const uintptr_t base; + const uintptr_t buffer_base; +}; + +/** + * pm_proc - struct for capturing processor related info + * @node_id node-ID of the processor + * @pwrdn_mask cpu-specific mask to be used for power control register + * @ipi pointer to IPI channel structure + * (in APU all processors share one IPI channel) + */ +struct pm_proc { + const enum pm_node_id node_id; + const unsigned int pwrdn_mask; + const struct pm_ipi *ipi; +}; + +const struct pm_proc *pm_get_proc(unsigned int cpuid); +const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid); + +#endif /* _PM_COMMON_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h new file mode 100644 index 000000000..08f4aab79 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* ZynqMP power management enums and defines */ + +#ifndef _PM_DEFS_H_ +#define _PM_DEFS_H_ + +/********************************************************************* + * Macro definitions + ********************************************************************/ + +/* + * Version number is a 32bit value, like: + * (PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR + */ +#define PM_VERSION_MAJOR 0 +#define PM_VERSION_MINOR 2 + +#define PM_VERSION ((PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR) + +/* Capabilities for RAM */ +#define PM_CAP_ACCESS 0x1U +#define PM_CAP_CONTEXT 0x2U + +#define MAX_LATENCY (~0U) +#define MAX_QOS 100U + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +enum pm_api_id { + /* Miscellaneous API functions: */ + PM_GET_API_VERSION = 1, /* Do not change or move */ + PM_SET_CONFIGURATION, + PM_GET_NODE_STATUS, + PM_GET_OP_CHARACTERISTIC, + PM_REGISTER_NOTIFIER, + /* API for suspending of PUs: */ + PM_REQ_SUSPEND, + PM_SELF_SUSPEND, + PM_FORCE_POWERDOWN, + PM_ABORT_SUSPEND, + PM_REQ_WAKEUP, + PM_SET_WAKEUP_SOURCE, + PM_SYSTEM_SHUTDOWN, + /* API for managing PM slaves: */ + PM_REQ_NODE, + PM_RELEASE_NODE, + PM_SET_REQUIREMENT, + PM_SET_MAX_LATENCY, + /* Direct control API functions: */ + PM_RESET_ASSERT, + PM_RESET_GET_STATUS, + PM_MMIO_WRITE, + PM_MMIO_READ, + PM_API_MAX +}; + +enum pm_node_id { + NODE_UNKNOWN = 0, + NODE_APU, + NODE_APU_0, + NODE_APU_1, + NODE_APU_2, + NODE_APU_3, + NODE_RPU, + NODE_RPU_0, + NODE_RPU_1, + NODE_PL, + NODE_FPD, + NODE_OCM_BANK_0, + NODE_OCM_BANK_1, + NODE_OCM_BANK_2, + NODE_OCM_BANK_3, + NODE_TCM_0_A, + NODE_TCM_0_B, + NODE_TCM_1_A, + NODE_TCM_1_B, + NODE_L2, + NODE_GPU_PP_0, + NODE_GPU_PP_1, + NODE_USB_0, + NODE_USB_1, + NODE_TTC_0, + NODE_TTC_1, + NODE_TTC_2, + NODE_TTC_3, + NODE_SATA, + NODE_ETH_0, + NODE_ETH_1, + NODE_ETH_2, + NODE_ETH_3, + NODE_UART_0, + NODE_UART_1, + NODE_SPI_0, + NODE_SPI_1, + NODE_I2C_0, + NODE_I2C_1, + NODE_SD_0, + NODE_SD_1, + NODE_DP, + NODE_GDMA, + NODE_ADMA, + NODE_NAND, + NODE_QSPI, + NODE_GPIO, + NODE_CAN_0, + NODE_CAN_1, + NODE_AFI, + NODE_APLL, + NODE_VPLL, + NODE_DPLL, + NODE_RPLL, + NODE_IOPLL, + NODE_DDR, +}; + +enum pm_request_ack { + REQ_ACK_NO = 1, + REQ_ACK_BLOCKING, + REQ_ACK_NON_BLOCKING, +}; + +enum pm_abort_reason { + ABORT_REASON_WKUP_EVENT = 100, + ABORT_REASON_PU_BUSY, + ABORT_REASON_NO_PWRDN, + ABORT_REASON_UNKNOWN, +}; + +enum pm_suspend_reason { + SUSPEND_REASON_PU_REQ = 201, + SUSPEND_REASON_ALERT, + SUSPEND_REASON_SYS_SHUTDOWN, +}; + +enum pm_ram_state { + PM_RAM_STATE_OFF = 1, + PM_RAM_STATE_RETENTION, + PM_RAM_STATE_ON, +}; + +enum pm_opchar_type { + PM_OPCHAR_TYPE_POWER = 1, + PM_OPCHAR_TYPE_ENERGY, + PM_OPCHAR_TYPE_TEMP, +}; + +/** + * @PM_RET_SUCCESS: success + * @PM_RET_ERROR_ARGS: illegal arguments provided + * @PM_RET_ERROR_ACCESS: access rights violation + * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU + * @PM_RET_ERROR_NOTSUPPORTED: feature not supported + * @PM_RET_ERROR_PROC: node is not a processor node + * @PM_RET_ERROR_API_ID: illegal API ID + * @PM_RET_ERROR_OTHER: other error + */ +enum pm_ret_status { + PM_RET_SUCCESS, + PM_RET_ERROR_ARGS, + PM_RET_ERROR_ACCESS, + PM_RET_ERROR_TIMEOUT, + PM_RET_ERROR_NOTSUPPORTED, + PM_RET_ERROR_PROC, + PM_RET_ERROR_API_ID, + PM_RET_ERROR_FAILURE, + PM_RET_ERROR_COMMUNIC, + PM_RET_ERROR_DOUBLEREQ, + PM_RET_ERROR_OTHER, +}; + +/** + * @PM_INITIAL_BOOT: boot is a fresh system startup + * @PM_RESUME: boot is a resume + * @PM_BOOT_ERROR: error, boot cause cannot be identified + */ +enum pm_boot_status { + PM_INITIAL_BOOT, + PM_RESUME, + PM_BOOT_ERROR, +}; + +#endif /* _PM_DEFS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c new file mode 100644 index 000000000..ef2b4fe6b --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "pm_ipi.h" +#include "../zynqmp_private.h" + +/* IPI message buffers */ +#define IPI_BUFFER_BASEADDR 0xFF990000U + +#define IPI_BUFFER_RPU_0_BASE (IPI_BUFFER_BASEADDR + 0x0U) +#define IPI_BUFFER_RPU_1_BASE (IPI_BUFFER_BASEADDR + 0x200U) +#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U) +#define IPI_BUFFER_PL_0_BASE (IPI_BUFFER_BASEADDR + 0x600U) +#define IPI_BUFFER_PL_1_BASE (IPI_BUFFER_BASEADDR + 0x800U) +#define IPI_BUFFER_PL_2_BASE (IPI_BUFFER_BASEADDR + 0xA00U) +#define IPI_BUFFER_PL_3_BASE (IPI_BUFFER_BASEADDR + 0xC00U) +#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U) + +#define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U +#define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U +#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U +#define IPI_BUFFER_TARGET_PL_0_OFFSET 0xC0U +#define IPI_BUFFER_TARGET_PL_1_OFFSET 0x100U +#define IPI_BUFFER_TARGET_PL_2_OFFSET 0x140U +#define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U +#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U + +#define IPI_BUFFER_REQ_OFFSET 0x0U +#define IPI_BUFFER_RESP_OFFSET 0x20U + +/* IPI Base Address */ +#define IPI_BASEADDR 0XFF300000 + +/* APU's IPI registers */ +#define IPI_APU_ISR (IPI_BASEADDR + 0X00000010) +#define IPI_APU_IER (IPI_BASEADDR + 0X00000018) +#define IPI_APU_IDR (IPI_BASEADDR + 0X0000001C) +#define IPI_APU_ISR_PMU_0_MASK 0X00010000 +#define IPI_APU_IER_PMU_0_MASK 0X00010000 + +#define IPI_TRIG_OFFSET 0 +#define IPI_OBS_OFFSET 4 + +/* Power Management IPI interrupt number */ +#define PM_INT_NUM 0 +#define IPI_PMU_PM_INT_BASE (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000)) +#define IPI_PMU_PM_INT_MASK (IPI_APU_ISR_PMU_0_MASK << PM_INT_NUM) +#if (PM_INT_NUM < 0 || PM_INT_NUM > 3) + #error PM_INT_NUM value out of range +#endif + +#define IPI_APU_MASK 1U + +static bakery_lock_t pm_secure_lock; + +const struct pm_ipi apu_ipi = { + .mask = IPI_APU_MASK, + .base = IPI_BASEADDR, + .buffer_base = IPI_BUFFER_APU_BASE, +}; + +/** + * pm_ipi_init() - Initialize IPI peripheral for communication with PMU + * + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Enable interrupts at registered entrance in IPI peripheral + * Called from pm_setup initialization function + */ +int pm_ipi_init(void) +{ + bakery_lock_init(&pm_secure_lock); + + /* IPI Interrupts Clear & Disable */ + mmio_write_32(IPI_APU_ISR, 0xffffffff); + mmio_write_32(IPI_APU_IDR, 0xffffffff); + + return 0; +} + +/** + * pm_ipi_wait() - wait for pmu to handle request + * @proc proc which is waiting for PMU to handle request + */ +static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc) +{ + int status; + + /* Wait until previous interrupt is handled by PMU */ + do { + status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) & + IPI_PMU_PM_INT_MASK; + /* TODO: 1) Use timer to add delay between read attempts */ + /* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */ + } while (status); + + return PM_RET_SUCCESS; +} + +/** + * pm_ipi_send_common() - Sends IPI request to the PMU + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * + * Send an IPI request to the power controller. Caller needs to hold + * the 'pm_secure_lock' lock. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]) +{ + unsigned int offset = 0; + uintptr_t buffer_base = proc->ipi->buffer_base + + IPI_BUFFER_TARGET_PMU_OFFSET + + IPI_BUFFER_REQ_OFFSET; + + /* Wait until previous interrupt is handled by PMU */ + pm_ipi_wait(proc); + + /* Write payload into IPI buffer */ + for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { + mmio_write_32(buffer_base + offset, payload[i]); + offset += PAYLOAD_ARG_SIZE; + } + /* Generate IPI to PMU */ + mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK); + + return PM_RET_SUCCESS; +} + +/** + * pm_ipi_send() - Sends IPI request to the PMU + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * + * Send an IPI request to the power controller. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]) +{ + enum pm_ret_status ret; + + bakery_lock_get(&pm_secure_lock); + + ret = pm_ipi_send_common(proc, payload); + + bakery_lock_release(&pm_secure_lock); + + return ret; +} + + +/** + * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt + * @proc Pointer to the processor who is waiting and reading response + * @value Used to return value from 2nd IPI buffer element (optional) + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, + unsigned int *value) +{ + uintptr_t buffer_base = proc->ipi->buffer_base + + IPI_BUFFER_TARGET_PMU_OFFSET + + IPI_BUFFER_RESP_OFFSET; + + pm_ipi_wait(proc); + + /* + * Read response from IPI buffer + * buf-0: success or error+reason + * buf-1: value + * buf-2: unused + * buf-3: unused + */ + if (value != NULL) + *value = mmio_read_32(buffer_base + PAYLOAD_ARG_SIZE); + + return mmio_read_32(buffer_base); +} + +/** + * pm_ipi_send_sync() - Sends IPI request to the PMU + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * @value Used to return value from 2nd IPI buffer element (optional) + * + * Send an IPI request to the power controller and wait for it to be handled. + * + * @return Returns status, either success or error+reason and, optionally, + * @value + */ +enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + unsigned int *value) +{ + enum pm_ret_status ret; + + bakery_lock_get(&pm_secure_lock); + + ret = pm_ipi_send_common(proc, payload); + if (ret != PM_RET_SUCCESS) + goto unlock; + + ret = pm_ipi_buff_read(proc, value); + +unlock: + bakery_lock_release(&pm_secure_lock); + + return ret; +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.h b/plat/xilinx/zynqmp/pm_service/pm_ipi.h new file mode 100644 index 000000000..d92e648c8 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PM_IPI_H_ +#define _PM_IPI_H_ + +#include "pm_common.h" + +int pm_ipi_init(void); + +enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]); +enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + unsigned int *value); + +#endif /* _PM_IPI_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c new file mode 100644 index 000000000..67440650b --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Top-level SMC handler for ZynqMP power management calls and + * IPI setup functions for communication with PMU. + */ + +#include +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" +#include "pm_ipi.h" +#include "../zynqmp_private.h" + +/* 0 - UP, !0 - DOWN */ +static int32_t pm_down = !0; + +/** + * pm_context - Structure which contains data for power management + * @api_version version of PM API, must match with one on PMU side + * @payload payload array used to store received + * data from ipi buffer registers + */ +static struct { + uint32_t api_version; + uint32_t payload[PAYLOAD_ARG_CNT]; +} pm_ctx; + +/** + * 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 ZynqMP power management for + * communicaton with PMU. + * + * Called from sip_svc_setup initialization function with the + * rt_svc_init signature. + * + */ +int pm_setup(void) +{ + int status; + + if (!zynqmp_is_pmu_up()) + return -ENODEV; + + status = pm_ipi_init(); + + if (status == 0) + INFO("BL31: PM Service Init Complete: API v%d.%d\n", + PM_VERSION_MAJOR, PM_VERSION_MINOR); + else + INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); + + pm_down = status; + + return status; +} + +/** + * 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_down) + 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_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_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_FORCE_POWERDOWN: + ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); + 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_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_SYSTEM_SHUTDOWN: + ret = pm_system_shutdown(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_NODE: + ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_RELEASE_NODE: + ret = pm_release_node(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_SET_MAX_LATENCY: + ret = pm_set_max_latency(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_API_VERSION: + /* Check is PM API version already verified */ + if (pm_ctx.api_version == PM_VERSION) + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)PM_VERSION << 32)); + + ret = pm_get_api_version(&pm_ctx.api_version); + SMC_RET1(handle, (uint64_t)ret | + ((uint64_t)pm_ctx.api_version << 32)); + + case PM_SET_CONFIGURATION: + ret = pm_set_configuration(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_NODE_STATUS: + ret = pm_get_node_status(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_OP_CHARACTERISTIC: + ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REGISTER_NOTIFIER: + ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + 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)); + } + + /* PM memory access functions */ + case PM_MMIO_WRITE: + ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_MMIO_READ: + { + uint32_t value; + + ret = pm_mmio_read(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + default: + WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h new file mode 100644 index 000000000..26985a2ac --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PM_SVC_MAIN_H_ +#define _PM_SVC_MAIN_H_ + +#include "pm_common.h" + +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/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c new file mode 100644 index 000000000..8bcfa6e3c --- /dev/null +++ b/plat/xilinx/zynqmp/sip_svc_setup.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */ + +#include +#include +#include "pm_svc_main.h" + +/* SMC function IDs for SiP Service queries */ +#define ZYNQMP_SIP_SVC_CALL_COUNT 0x8200ff00 +#define ZYNQMP_SIP_SVC_UID 0x8200ff01 +#define ZYNQMP_SIP_SVC_VERSION 0x8200ff03 + +/* SiP Service Calls version numbers */ +#define SIP_SVC_VERSION_MAJOR 0 +#define SIP_SVC_VERSION_MINOR 1 + +/* These macros are used to identify PM calls from the SMC function ID */ +#define PM_FID_MASK 0xf000u +#define PM_FID_VALUE 0u +#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) + +/* SiP Service UUID */ +DEFINE_SVC_UUID(zynqmp_sip_uuid, + 0x2a1d9b5c, 0x8605, 0x4023, 0xa6, 0x1b, + 0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5); + +/** + * sip_svc_setup() - Setup SiP Service + * + * Invokes PM setup + */ +static int32_t sip_svc_setup(void) +{ + /* PM implementation as SiP Service */ + pm_setup(); + + return 0; +} + +/** + * sip_svc_smc_handler() - Top-level SiP Service SMC handler + * + * Handler for all SiP SMC calls. Handles standard SIP requests + * and calls PM SMC handler if the call is for a PM-API function. + */ +uint64_t sip_svc_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) +{ + /* 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); + } + + switch (smc_fid) { + case ZYNQMP_SIP_SVC_CALL_COUNT: + /* PM functions + default functions */ + SMC_RET1(handle, PM_API_MAX + 2); + + case ZYNQMP_SIP_SVC_UID: + SMC_UUID_RET(handle, zynqmp_sip_uuid); + + case ZYNQMP_SIP_SVC_VERSION: + SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR); + + default: + WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} + +/* Register PM Service Calls as runtime service */ +DECLARE_RT_SVC( + sip_svc, + OEN_SIP_START, + OEN_SIP_END, + SMC_TYPE_FAST, + sip_svc_setup, + sip_svc_smc_handler); diff --git a/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk new file mode 100644 index 000000000..a9ebe602e --- /dev/null +++ b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk @@ -0,0 +1,31 @@ +# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# Neither the name of ARM nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# TSP source files specific to ZynqMP platform +BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \ + plat/xilinx/zynqmp/tsp/tsp_plat_setup.c diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c new file mode 100644 index 000000000..291ccbac0 --- /dev/null +++ b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "../zynqmp_def.h" +#include "../zynqmp_private.h" + +/* + * The next 3 constants identify the extents of the code & RO data region and + * the limit of the BL32 image. These addresses are used by the MMU setup code + * and therefore they must be page-aligned. It is the responsibility of the + * linker script to ensure that __RO_START__, __RO_END__ & & __BL32_END__ + * linker symbols refer to page-aligned addresses. + */ +#define BL32_RO_BASE (unsigned long)(&__RO_START__) +#define BL32_RO_LIMIT (unsigned long)(&__RO_END__) +#define BL32_END (unsigned long)(&__BL32_END__) + + +#if USE_COHERENT_MEM +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL32_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL32_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) +#endif + +/******************************************************************************* + * Initialize the UART + ******************************************************************************/ +void tsp_early_platform_setup(void) +{ + /* + * Initialize a different console than already in use to display + * messages from TSP + */ + console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(), + ZYNQMP_UART_BAUDRATE); + + /* Initialize the platform config for future decision making */ + zynqmp_config_setup(); +} + +/******************************************************************************* + * Perform platform specific setup placeholder + ******************************************************************************/ +void tsp_platform_setup(void) +{ + plat_arm_gic_driver_init(); + plat_arm_gic_init(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the MMU + ******************************************************************************/ +void tsp_plat_arch_setup(void) +{ + arm_configure_mmu_el1(BL32_RO_BASE, + (BL32_END - BL32_RO_BASE), + BL32_RO_BASE, + BL32_RO_LIMIT +#if USE_COHERENT_MEM + , BL32_COHERENT_RAM_BASE, + BL32_COHERENT_RAM_LIMIT +#endif + ); +} diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h new file mode 100644 index 000000000..32190e41f --- /dev/null +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ZYNQMP_DEF_H__ +#define __ZYNQMP_DEF_H__ + +#include + +/* Firmware Image Package */ +#define ZYNQMP_PRIMARY_CPU 0 + +/* Memory location options for Shared data and TSP in ZYNQMP */ +#define ZYNQMP_IN_TRUSTED_SRAM 0 +#define ZYNQMP_IN_TRUSTED_DRAM 1 + +/******************************************************************************* + * ZYNQMP memory map related constants + ******************************************************************************/ + +#define ZYNQMP_TRUSTED_SRAM_BASE 0xFFFC0000 +#define ZYNQMP_TRUSTED_SRAM_SIZE 0x00040000 +#define ZYNQMP_TRUSTED_SRAM_LIMIT (ZYNQMP_TRUSTED_SRAM_BASE + \ + ZYNQMP_TRUSTED_SRAM_SIZE) + + +/* Location of trusted dram on the base zynqmp */ +#define ZYNQMP_TRUSTED_DRAM_BASE 0x30000000 /* Can't overlap TZROM area */ +#define ZYNQMP_TRUSTED_DRAM_SIZE 0x10000000 +#define ZYNQMP_TRUSTED_DRAM_LIMIT (ZYNQMP_TRUSTED_DRAM_BASE + \ + ZYNQMP_TRUSTED_DRAM_SIZE) + +/* Aggregate of all devices in the first GB */ +#define DEVICE0_BASE 0xFF000000 +#define DEVICE0_SIZE 0x00E00000 +#define DEVICE1_BASE 0xF9000000 +#define DEVICE1_SIZE 0x01000000 + +/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/ +#define CRF_APB_BASE 0xFD1A0000 +#define CRF_APB_SIZE 0x00600000 + +/* CRF registers and bitfields */ +#define CRF_APB_RST_FPD_APU (CRF_APB_BASE + 0X00000104) + +#define CRF_APB_RST_FPD_APU_ACPU_RESET (1 << 0) +#define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET (1 << 10) + +/* CRL registers and bitfields */ +#define CRL_APB_BASE 0xFF5E0000 +#define CRL_APB_RPLL_CTRL (CRL_APB_BASE + 0x30) +#define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_BASE + 0x128) +#define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218) + +#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 24) + +#define CRL_APB_RPLL_CTRL_BYPASS (1 << 3) + +#define CRL_APB_RESET_CTRL_SOFT_RESET (1 << 4) + +/* system counter registers and bitfields */ +#define IOU_SCNTRS_BASE 0xFF260000 +#define IOU_SCNTRS_CONTROL (IOU_SCNTRS_BASE + 0) +#define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20) + +#define IOU_SCNTRS_CONTROL_EN (1 << 0) + +/* APU registers and bitfields */ +#define APU_BASE 0xFD5C0000 +#define APU_CONFIG_0 (APU_BASE + 0x20) +#define APU_RVBAR_L_0 (APU_BASE + 0x40) +#define APU_RVBAR_H_0 (APU_BASE + 0x44) +#define APU_PWRCTL (APU_BASE + 0x90) + +#define APU_CONFIG_0_VINITHI_SHIFT 8 +#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1 +#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2 +#define APU_2_PWRCTL_CPUPWRDWNREQ_MASK 4 +#define APU_3_PWRCTL_CPUPWRDWNREQ_MASK 8 + +/* PMU registers and bitfields */ +#define PMU_GLOBAL_BASE 0xFFD80000 +#define PMU_GLOBAL_CNTRL (PMU_GLOBAL_BASE + 0) +#define PMU_GLOBAL_REQ_PWRUP_STATUS (PMU_GLOBAL_BASE + 0x110) +#define PMU_GLOBAL_REQ_PWRUP_EN (PMU_GLOBAL_BASE + 0x118) +#define PMU_GLOBAL_REQ_PWRUP_DIS (PMU_GLOBAL_BASE + 0x11c) +#define PMU_GLOBAL_REQ_PWRUP_TRIG (PMU_GLOBAL_BASE + 0x120) + +#define PMU_GLOBAL_CNTRL_FW_IS_PRESENT (1 << 4) + +#define DRAM1_BASE 0x00000000ull +#define DRAM1_SIZE 0x10000000ull +#define DRAM1_END (DRAM1_BASE + DRAM1_SIZE - 1) + +#define DRAM_BASE DRAM1_BASE +#define DRAM_SIZE DRAM1_SIZE + +/* Load address of BL33 in the ZYNQMP port */ +#define PLAT_ARM_NS_IMAGE_OFFSET (DRAM1_BASE + 0x8000000) /* DRAM + 128MB */ + +/******************************************************************************* + * CCI-400 related constants + ******************************************************************************/ +#define PLAT_ARM_CCI_BASE 0xFD6E0000 +#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 3 +#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 4 + +/******************************************************************************* + * GIC-400 & interrupt handling related constants + ******************************************************************************/ +#define BASE_GICD_BASE 0xF9010000 +#define BASE_GICC_BASE 0xF9020000 +#define BASE_GICH_BASE 0xF9040000 +#define BASE_GICV_BASE 0xF9060000 + +#define IRQ_SEC_IPI_APU 67 +#define ARM_IRQ_SEC_PHY_TIMER 29 + +#define ARM_IRQ_SEC_SGI_0 8 +#define ARM_IRQ_SEC_SGI_1 9 +#define ARM_IRQ_SEC_SGI_2 10 +#define ARM_IRQ_SEC_SGI_3 11 +#define ARM_IRQ_SEC_SGI_4 12 +#define ARM_IRQ_SEC_SGI_5 13 +#define ARM_IRQ_SEC_SGI_6 14 +#define ARM_IRQ_SEC_SGI_7 15 + +#define MAX_INTR_EL3 128 + +/******************************************************************************* + * UART related constants + ******************************************************************************/ +#define ZYNQMP_UART0_BASE 0xFF000000 +#define ZYNQMP_UART1_BASE 0xFF001000 + +#define PLAT_ARM_CRASH_UART_BASE ZYNQMP_UART0_BASE +/* impossible to call C routine how it is done now - hardcode any value */ +#define PLAT_ARM_CRASH_UART_CLK_IN_HZ 100000000 /* FIXME */ + +/* Must be non zero */ +#define ZYNQMP_UART_BAUDRATE 115200 +#define ARM_CONSOLE_BAUDRATE ZYNQMP_UART_BAUDRATE + +/* Silicon version detection */ +#define ZYNQMP_SILICON_VER_MASK 0xF000 +#define ZYNQMP_SILICON_VER_SHIFT 12 +#define ZYNQMP_CSU_VERSION_SILICON 0 +#define ZYNQMP_CSU_VERSION_EP108 1 +#define ZYNQMP_CSU_VERSION_VELOCE 2 +#define ZYNQMP_CSU_VERSION_QEMU 3 + +#define ZYNQMP_RTL_VER_MASK 0xFF0 +#define ZYNQMP_RTL_VER_SHIFT 4 + +#define ZYNQMP_PS_VER_MASK 0xF +#define ZYNQMP_PS_VER_SHIFT 0 + +#define ZYNQMP_CSU_BASEADDR 0xFFCA0000 +#define ZYNQMP_CSU_IDCODE_OFFSET 0x40 + +#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT 0 +#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK (0xFFF << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT) +#define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093 + +#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12 +#define ZYNQMP_CSU_IDCODE_SVD_MASK (0xE << ZYNQMP_CSU_IDCODE_SVD_SHIFT) +#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15 +#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xF << ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT) +#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19 +#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK (0x3 << ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT) +#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT 21 +#define ZYNQMP_CSU_IDCODE_FAMILY_MASK (0x7F << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT) +#define ZYNQMP_CSU_IDCODE_FAMILY 0x23 + +#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT 28 +#define ZYNQMP_CSU_IDCODE_REVISION_MASK (0xF << ZYNQMP_CSU_IDCODE_REVISION_SHIFT) +#define ZYNQMP_CSU_IDCODE_REVISION 0 + +#define ZYNQMP_CSU_VERSION_OFFSET 0x44 + +#endif /* __ZYNQMP_DEF_H__ */ diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h new file mode 100644 index 000000000..1f5be39ba --- /dev/null +++ b/plat/xilinx/zynqmp/zynqmp_private.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ZYNQMP_PRIVATE_H__ +#define __ZYNQMP_PRIVATE_H__ + +#include + +void zynqmp_config_setup(void); + +/* ZynqMP specific functions */ +unsigned int zynqmp_get_uart_clk(void); +int zynqmp_is_pmu_up(void); + +#endif /* __ZYNQMP_PRIVATE_H__ */