Commit 5d787dd9 authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #569 from Xilinx/zynqmp-v1

Support for Xilinx Zynq UltraScale+ MPSoC
parents af984eef 498256ed
...@@ -7,5 +7,7 @@ Linaro Limited ...@@ -7,5 +7,7 @@ Linaro Limited
NVIDIA Corporation NVIDIA Corporation
Xilinx, Inc.
Individuals Individuals
----------- -----------
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.
/*
* Copyright (c) 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 <arch.h>
#include <asm_macros.S>
#include <cadence/cdns_uart.h>
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* We assume that the bootloader already set up
* the HW (baud, ...) and only enable the trans-
* mitter and receiver here.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success else 0 on error
* Clobber list : x1, x2, x3
* -----------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, core_init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, core_init_fail
cbz w2, core_init_fail
/* RX/TX enabled & reset */
mov w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST)
str w3, [x0, #R_UART_CR]
mov w0, #1
ret
core_init_fail:
mov w0, wzr
ret
endfunc console_core_init
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned long base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
1:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #R_UART_SR]
tbnz w2, #UART_SR_INTR_TFUL_BIT, 1b
mov w2, #0xD
str w2, [x1, #R_UART_TX]
2:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #R_UART_SR]
tbnz w2, #UART_SR_INTR_TFUL_BIT, 2b
str w0, [x1, #R_UART_TX]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
/* ---------------------------------------------
* int console_core_getc(unsigned long base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* In : x0 - console base address
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
cbz x0, getc_error
1:
/* Check if the receive FIFO is empty */
ldr w1, [x0, #R_UART_SR]
tbnz w1, #UART_SR_INTR_REMPTY_BIT, 1b
ldr w1, [x0, #R_UART_RX]
mov w0, w1
ret
getc_error:
mov w0, #-1
ret
endfunc console_core_getc
/*
* Copyright (c) 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 __CADENCE_UART_H__
#define __CADENCE_UART_H__
/* This is very minimalistic and will only work in QEMU. */
/* CADENCE Registers */
#define R_UART_CR 0
#define R_UART_CR_RXRST (1 << 0) /* RX logic reset */
#define R_UART_CR_TXRST (1 << 1) /* TX logic reset */
#define R_UART_CR_RX_EN (1 << 2) /* RX enabled */
#define R_UART_CR_TX_EN (1 << 4) /* TX enabled */
#define R_UART_SR 0x2C
#define UART_SR_INTR_REMPTY_BIT 1
#define UART_SR_INTR_TFUL_BIT 4
#define R_UART_TX 0x30
#define R_UART_RX 0x30
#endif
...@@ -137,6 +137,7 @@ uint32_t arm_get_spsr_for_bl33_entry(void) ...@@ -137,6 +137,7 @@ uint32_t arm_get_spsr_for_bl33_entry(void)
/******************************************************************************* /*******************************************************************************
* Configures access to the system counter timer module. * Configures access to the system counter timer module.
******************************************************************************/ ******************************************************************************/
#ifdef ARM_SYS_TIMCTL_BASE
void arm_configure_sys_timer(void) void arm_configure_sys_timer(void)
{ {
unsigned int reg_val; unsigned int reg_val;
...@@ -151,6 +152,7 @@ void arm_configure_sys_timer(void) ...@@ -151,6 +152,7 @@ void arm_configure_sys_timer(void)
reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID)); reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID));
mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val); mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
} }
#endif /* ARM_SYS_TIMCTL_BASE */
/******************************************************************************* /*******************************************************************************
* Returns ARM platform specific memory map regions. * Returns ARM platform specific memory map regions.
......
/*
* 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 <arch_helpers.h>
#include <cci.h>
#include <debug.h>
#include <gicv2.h>
#include <mmio.h>
#include <plat_arm.h>
#include <platform.h>
#include <xlat_tables.h>
#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;
}
/*
* 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 <asm_macros.S>
#include <gicv2.h>
#include <platform_def.h>
.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
/*
* 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 <assert.h>
#include <bl_common.h>
#include <bl31.h>
#include <console.h>
#include <debug.h>
#include <errno.h>
#include <plat_arm.h>
#include <platform.h>
#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);
}
/*
* 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 <arm_macros.S>
#include <cci_macros.S>
#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__ */
/*
* 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 <arch.h>
#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__ */
/*
* 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 <arch_helpers.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <gicv2.h>
#include <mmio.h>
#include <plat_arm.h>
#include <platform.h>
#include <psci.h>
#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;
}
/*
* 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 <platform_def.h>
#include <psci.h>
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;
}
/*
* 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 <plat_arm.h>
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);
}
# 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
/*
* 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 <arch_helpers.h>
#include <platform.h>
#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);
}
/*
* 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 <stdint.h>
#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_ */
/*
* 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 <gicv2.h>
#include <bl_common.h>
#include <mmio.h>
#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);
}
/*
* 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_ */
/*
* 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 <debug.h>
#include <stdint.h>
#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_ */
/*
* 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_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment