Merge changes from topic "add-versal-soc-support" into integration

* changes:
  plat: xilinx: Move pm_client.h to common directory
  plat: xilinx: versal: Make silicon default build target
  xilinx: versal: Wire silicon default setup
  versal: Increase OCM memory size for DEBUG builds
  plat: xilinx: versal: Dont set IOU switch clock
  arm64: versal: Adjust cpu clock for versal virtual
  xilinx: versal: Add support for PM_GET_OPERATING_CHARACTERISTIC EEMI call
  plat: versal: Add Get_ChipID API
  plat: xilinx: versal: Add load Pdi API support
  xilinx: versal: Add feature check API
  xilinx: versal: Implement set wakeup source for client
  plat: xilinx: versal: Add GET_CALLBACK_DATA function
  xilinx: versal: Add PSCI APIs for system shutdown & reset
  xilinx: versal: Add PSCI APIs for suspend/resume
  xilinx: versal: Remove no_pmc ops to ON power domain
  xilinx: versal: Add set wakeup source API
  xilinx: versal: Add client wakeup API
  xilinx: versal: Add query data API
  xilinx: versal: Add request wakeup API
  xilinx: versal: Add PM_INIT_FINALIZE API for versal
  xilinx: versal: Add support of PM_GET_TRUSTZONE_VERSION API
  xilinx: versal: enable ipi mailbox service
  xilinx: move ipi mailbox svc to xilinx common
  plat: xilinx: versal: Implement PM IOCTL API
  xilinx: versal: Implement power down/restart related EEMI API
  xilinx: versal: Add SMC handler for EEMI API
  xilinx: versal: Implement PLL related PM APIs
  xilinx: versal: Implement clock related PM APIs
  xilinx: versal: Implement pin control related PM APIs
  xilinx: versal: Implement reset related PM APIs
  xilinx: versal: Implement device related PM APIs
  xilinx: versal: Add support for suspend related APIs
  xilinx: versal: Add get_api_version support
  xilinx: Add support to send PM API to PMC using IPI for versal
  plat: xilinx: versal: Move versal_def.h to include directory
  plat: xilinx: versal: Move versal_private.h to include directory
  plat: xilinx: zynqmp: Use GIC framework for warm restart
This commit is contained in:
Soby Mathew 2020-01-22 11:12:07 +00:00 committed by TrustedFirmware Code Review
commit f44d291f23
27 changed files with 2395 additions and 88 deletions

View File

@ -14,7 +14,7 @@ To build:
make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
```
To build ATF for different platform (for now its just versal virtual "versal_virt")
To build ATF for different platform (supported are "silicon"(default) and "versal_virt")
```bash
make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
```

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -19,11 +19,14 @@
void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
void pm_client_abort_suspend(void);
void pm_client_wakeup(const struct pm_proc *proc);
enum pm_ret_status set_ocm_retention(void);
enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
/* Global variables to be set in pm_client.c */
extern const struct pm_proc *primary_proc;
#ifndef VERSAL_PLATFORM
enum pm_ret_status set_ocm_retention(void);
enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
#endif
#endif /* PM_CLIENT_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

View File

@ -1,18 +1,18 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <plat_ipi.h>
#include <versal_def.h>
#include <plat_private.h>
#include <common/debug.h>
#include <drivers/generic_delay_timer.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables.h>
#include <plat/common/platform.h>
#include "../versal_def.h"
#include "../versal_private.h"
/*
* Table of regions to map using the MMU.
* This doesn't include TZRAM as the 'mem_layout' argument passed to
@ -22,6 +22,8 @@ const mmap_region_t plat_versal_mmap[] = {
MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(FPD_MAINCCI_BASE, FPD_MAINCCI_SIZE, MT_DEVICE | MT_RW |
MT_SECURE),
{ 0 }
};
@ -39,11 +41,10 @@ void versal_config_setup(void)
{
uint32_t val;
versal_print_platform_name();
/* Configure IPI data for versal */
versal_ipi_config_table_init();
mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL,
VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT |
(0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT));
versal_print_platform_name();
/* Global timer init - Program time stamp reference clk */
val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL);

View File

@ -1,12 +1,13 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <plat_arm.h>
#include <plat_private.h>
#include <bl31/bl31.h>
#include <common/bl_common.h>
#include <common/debug.h>
@ -15,8 +16,6 @@
#include <lib/xlat_tables/xlat_tables.h>
#include <plat/common/platform.h>
#include "versal_private.h"
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
static console_pl011_t versal_runtime_console;
@ -104,6 +103,9 @@ void bl31_plat_runtime_setup(void)
*/
void bl31_plat_arch_setup(void)
{
plat_arm_interconnect_init();
plat_arm_interconnect_enter_coherency();
const mmap_region_t bl_regions[] = {
MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
MT_MEMORY | MT_RW | MT_SECURE),

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* Versal IPI management enums and defines */
#ifndef PLAT_IPI_H
#define PLAT_IPI_H
#include <ipi.h>
#include <stdint.h>
/*********************************************************************
* IPI agent IDs macros
********************************************************************/
#define IPI_ID_PMC 1U
#define IPI_ID_APU 2U
#define IPI_ID_RPU0 3U
#define IPI_ID_RPU1 4U
#define IPI_ID_3 5U
#define IPI_ID_4 6U
#define IPI_ID_5 7U
/*********************************************************************
* IPI message buffers
********************************************************************/
#define IPI_BUFFER_BASEADDR 0xFF3F0000U
#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U)
#define IPI_BUFFER_TARGET_APU_OFFSET 0x0U
#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U
#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE
#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET
#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET
#define IPI_BUFFER_MAX_WORDS 8
#define IPI_BUFFER_REQ_OFFSET 0x0U
#define IPI_BUFFER_RESP_OFFSET 0x20U
/*********************************************************************
* Platform specific IPI API declarations
********************************************************************/
/* Configure IPI table for versal */
void versal_ipi_config_table_init(void);
#endif /* PLAT_IPI_H */

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Contains platform specific definitions of commonly used macros data types
* for PU Power Management. This file should be common for all PU's.
*/
#ifndef PLAT_PM_COMMON_H
#define PLAT_PM_COMMON_H
#include <common/debug.h>
#include <stdint.h>
#include "pm_defs.h"
#define PAYLOAD_ARG_CNT 6U
#define PAYLOAD_ARG_SIZE 4U /* size in bytes */
#define VERSAL_TZ_VERSION_MAJOR 1
#define VERSAL_TZ_VERSION_MINOR 0
#define VERSAL_TZ_VERSION ((VERSAL_TZ_VERSION_MAJOR << 16) | \
VERSAL_TZ_VERSION_MINOR)
#endif /* PLAT_PM_COMMON_H */

View File

@ -1,11 +1,11 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef VERSAL_PRIVATE_H
#define VERSAL_PRIVATE_H
#ifndef PLAT_PRIVATE_H
#define PLAT_PRIVATE_H
#include <lib/xlat_tables/xlat_tables.h>
@ -18,7 +18,9 @@ void plat_versal_gic_init(void);
void plat_versal_gic_cpuif_enable(void);
void plat_versal_gic_cpuif_disable(void);
void plat_versal_gic_pcpu_init(void);
void plat_versal_gic_save(void);
void plat_versal_gic_resume(void);
unsigned int versal_calc_core_pos(u_register_t mpidr);
#endif /* VERSAL_PRIVATE_H */
#endif /* PLAT_PRIVATE_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -8,8 +8,7 @@
#define PLATFORM_DEF_H
#include <arch.h>
#include "../versal_def.h"
#include "versal_def.h"
/*******************************************************************************
* Generic platform constants
@ -32,7 +31,7 @@
* little space for growth.
*/
#ifndef VERSAL_ATF_MEM_BASE
# define BL31_BASE 0xfffea000
# define BL31_BASE 0xfffe0000
# define BL31_LIMIT 0xffffffff
#else
# define BL31_BASE (VERSAL_ATF_MEM_BASE)
@ -76,7 +75,7 @@
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
#define MAX_MMAP_REGIONS 7
#define MAX_MMAP_REGIONS 8
#define MAX_XLAT_TABLES 5
#define CACHE_WRITEBACK_SHIFT 6

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -19,6 +19,7 @@
/* List all supported platforms */
#define VERSAL_PLATFORM_ID_versal_virt 1
#define VERSAL_PLATFORM_ID_silicon 4
#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
@ -35,13 +36,10 @@
/* CRL */
#define VERSAL_CRL 0xFF5E0000
#define VERSAL_CRL_IOU_SWITCH_CTRL (VERSAL_CRL + 0x114)
#define VERSAL_CRL_TIMESTAMP_REF_CTRL (VERSAL_CRL + 0x14C)
#define VERSAL_CRL_RST_TIMESTAMP_OFFSET (VERSAL_CRL + 0x348)
#define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 25)
#define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT (1 << 25)
#define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT 8
/* IOU SCNTRS */
#define VERSAL_IOU_SCNTRS 0xFF140000
@ -55,6 +53,13 @@
******************************************************************************/
#define VERSAL_IRQ_SEC_PHY_TIMER 29
/*******************************************************************************
* CCI-400 related constants
******************************************************************************/
#define PLAT_ARM_CCI_BASE 0xFD000000
#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 4
#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 5
/*******************************************************************************
* UART related constants
******************************************************************************/
@ -80,7 +85,12 @@
# define PLATFORM_NAME "Versal Virt"
# define VERSAL_UART_CLOCK 25000000
# define VERSAL_UART_BAUDRATE 115200
# define VERSAL_CPU_CLOCK 62500000
# define VERSAL_CPU_CLOCK 2720000
#elif VERSAL_PLATFORM_IS(silicon)
# define PLATFORM_NAME "Versal Silicon"
# define VERSAL_UART_CLOCK 100000000
# define VERSAL_UART_BAUDRATE 115200
# define VERSAL_CPU_CLOCK 100000000
#endif
/* Access control register defines */
@ -97,6 +107,9 @@
#define CRF_RST_APU_ACPU_RESET (1 << 0)
#define CRF_RST_APU_ACPU_PWRON_RESET (1 << 10)
#define FPD_MAINCCI_BASE 0xFD000000
#define FPD_MAINCCI_SIZE 0x00100000
/* APU registers and bitfields */
#define FPD_APU_BASE 0xFD5C0000
#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20)
@ -105,5 +118,22 @@
#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90)
#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8
#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1
#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2
/* IPI registers and bitfields */
#define IPI0_REG_BASE 0xFF330000
#define IPI0_TRIG_BIT (1 << 2)
#define PMC_IPI_TRIG_BIT (1 << 1)
#define IPI1_REG_BASE 0xFF340000
#define IPI1_TRIG_BIT (1 << 3)
#define IPI2_REG_BASE 0xFF350000
#define IPI2_TRIG_BIT (1 << 4)
#define IPI3_REG_BASE 0xFF360000
#define IPI3_TRIG_BIT (1 << 5)
#define IPI4_REG_BASE 0xFF370000
#define IPI4_TRIG_BIT (1 << 5)
#define IPI5_REG_BASE 0xFF380000
#define IPI5_TRIG_BIT (1 << 6)
#endif /* VERSAL_DEF_H */

View File

@ -1,65 +1,111 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <plat_arm.h>
#include <plat_private.h>
#include <pm_common.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
#include <plat/arm/common/plat_arm.h>
#include "versal_private.h"
#include "pm_api_sys.h"
#include "pm_client.h"
static uintptr_t versal_sec_entry;
static int versal_nopmc_pwr_domain_on(u_register_t mpidr)
static int versal_pwr_domain_on(u_register_t mpidr)
{
uint32_t r;
unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
const struct pm_proc *proc;
VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
if (cpu_id == -1)
return PSCI_E_INTERN_FAIL;
/*
* program RVBAR
*/
mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry);
mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32);
proc = pm_get_proc(cpu_id);
/*
* clear VINITHI
*/
r = mmio_read_32(FPD_APU_CONFIG_0);
r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
mmio_write_32(FPD_APU_CONFIG_0, r);
/* Send request to PMC to wake up selected ACPU core */
pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFF) | 0x1,
versal_sec_entry >> 32, 0);
/*
* FIXME: Add power up sequence, By default it works
* now without the need of it as it was powered up by
* default.
*/
/*
* clear power down request
*/
r = mmio_read_32(FPD_APU_PWRCTL);
r &= ~(1 << cpu_id);
mmio_write_32(FPD_APU_PWRCTL, r);
/*
* release core reset
*/
r = mmio_read_32(CRF_RST_APU);
r &= ~((CRF_RST_APU_ACPU_PWRON_RESET |
CRF_RST_APU_ACPU_RESET) << cpu_id);
mmio_write_32(CRF_RST_APU, r);
/* Clear power down request */
pm_client_wakeup(proc);
return PSCI_E_SUCCESS;
}
/**
* versal_pwr_domain_suspend() - This function sends request to PMC to suspend
* core.
*
* @target_state Targated state
*/
static void versal_pwr_domain_suspend(const psci_power_state_t *target_state)
{
unsigned int state;
unsigned int cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
__func__, i, target_state->pwr_domain_state[i]);
plat_versal_gic_cpuif_disable();
plat_versal_gic_save();
state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
/* Send request to PMC to suspend this core */
pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry);
/* APU is to be turned off */
if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
/* disable coherency */
plat_arm_interconnect_exit_coherency();
}
}
/**
* versal_pwr_domain_suspend_finish() - This function performs actions to finish
* suspend procedure.
*
* @target_state Targated state
*/
static void versal_pwr_domain_suspend_finish(
const psci_power_state_t *target_state)
{
unsigned int cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
__func__, i, target_state->pwr_domain_state[i]);
/* Clear the APU power control register for this cpu */
pm_client_wakeup(proc);
/* enable coherency */
plat_arm_interconnect_enter_coherency();
/* APU was turned off, so restore GIC context */
if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
plat_versal_gic_resume();
plat_versal_gic_cpuif_enable();
} else {
plat_versal_gic_cpuif_enable();
plat_versal_gic_pcpu_init();
}
}
void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
/* Enable the gic cpu interface */
@ -69,9 +115,114 @@ void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
plat_versal_gic_cpuif_enable();
}
/**
* versal_system_off() - This function sends the system off request
* to firmware. This function does not return.
*/
static void __dead2 versal_system_off(void)
{
/* Send the power down request to the PMC */
pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
pm_get_shutdown_scope());
while (1)
wfi();
}
/**
* versal_system_reset() - This function sends the reset request
* to firmware for the system to reset. This function does not return.
*/
static void __dead2 versal_system_reset(void)
{
/* Send the system reset request to the PMC */
pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
pm_get_shutdown_scope());
while (1)
wfi();
}
/**
* versal_pwr_domain_off() - This function performs actions to turn off core
*
* @target_state Targated state
*/
static void versal_pwr_domain_off(const psci_power_state_t *target_state)
{
unsigned int cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
__func__, i, target_state->pwr_domain_state[i]);
/* Prevent interrupts from spuriously waking up this cpu */
plat_versal_gic_cpuif_disable();
/*
* Send request to PMC to power down the appropriate APU CPU
* core.
* According to PSCI specification, CPU_off function does not
* have resume address and CPU core can only be woken up
* invoking CPU_on function, during which resume address will
* be set.
*/
pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
}
/**
* versal_validate_power_state() - This function ensures that the power state
* parameter in request is valid.
*
* @power_state Power state of core
* @req_state Requested state
*
* @return Returns status, either success or reason
*/
static int versal_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
int pstate = psci_get_pstate_type(power_state);
assert(req_state);
/* Sanity check the requested state */
if (pstate == PSTATE_TYPE_STANDBY)
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
else
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
/* We expect the 'state id' to be zero */
if (psci_get_pstate_id(power_state))
return PSCI_E_INVALID_PARAMS;
return PSCI_E_SUCCESS;
}
/**
* versal_get_sys_suspend_power_state() - Get power state for system suspend
*
* @req_state Requested state
*/
static void versal_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
}
static const struct plat_psci_ops versal_nopmc_psci_ops = {
.pwr_domain_on = versal_nopmc_pwr_domain_on,
.pwr_domain_on = versal_pwr_domain_on,
.pwr_domain_off = versal_pwr_domain_off,
.pwr_domain_on_finish = versal_pwr_domain_on_finish,
.pwr_domain_suspend = versal_pwr_domain_suspend,
.pwr_domain_suspend_finish = versal_pwr_domain_suspend_finish,
.system_off = versal_system_off,
.system_reset = versal_system_reset,
.validate_power_state = versal_validate_power_state,
.get_sys_suspend_power_state = versal_get_sys_suspend_power_state,
};
/*******************************************************************************

View File

@ -1,13 +1,12 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <plat_private.h>
#include <plat/common/platform.h>
#include "versal_private.h"
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
if (mpidr & MPIDR_CLUSTER_MASK)

View File

@ -31,33 +31,48 @@ ifdef VERSAL_BL32_MEM_BASE
$(eval $(call add_define,VERSAL_BL32_MEM_SIZE))
endif
VERSAL_PLATFORM ?= versal_virt
VERSAL_PLATFORM ?= silicon
$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
VERSAL_CONSOLE ?= pl011
$(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
PLAT_INCLUDES := -Iplat/xilinx/versal/include/
PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
-Iplat/xilinx/common/include/ \
-Iplat/xilinx/common/ipi_mailbox_service/ \
-Iplat/xilinx/versal/include/ \
-Iplat/xilinx/versal/pm_service/
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/arm_gicv3_common.c \
drivers/arm/gic/v3/gic500.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
drivers/arm/pl011/aarch64/pl011_console.S \
plat/common/aarch64/crash_console_helpers.S \
plat/arm/common/arm_cci.c \
plat/common/plat_gicv3.c \
plat/xilinx/versal/aarch64/versal_helpers.S \
plat/xilinx/versal/aarch64/versal_common.c
BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
BL31_SOURCES += drivers/arm/cci/cci.c \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
plat/common/plat_psci_common.c \
plat/xilinx/common/ipi.c \
plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
plat/xilinx/common/pm_service/pm_ipi.c \
plat/xilinx/versal/bl31_versal_setup.c \
plat/xilinx/versal/plat_psci.c \
plat/xilinx/versal/plat_versal.c \
plat/xilinx/versal/plat_topology.c \
plat/xilinx/versal/sip_svc_setup.c \
plat/xilinx/versal/versal_gicv3.c
plat/xilinx/versal/versal_gicv3.c \
plat/xilinx/versal/versal_ipi.c \
plat/xilinx/versal/pm_service/pm_svc_main.c \
plat/xilinx/versal/pm_service/pm_api_sys.c \
plat/xilinx/versal/pm_service/pm_client.c

View File

@ -0,0 +1,885 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Versal system level PM-API functions and communication with PMC via
* IPI interrupts
*/
#include <pm_common.h>
#include <pm_ipi.h>
#include <plat/common/platform.h>
#include "pm_api_sys.h"
#include "pm_client.h"
/*********************************************************************
* Target module IDs macros
********************************************************************/
#define LIBPM_MODULE_ID 0x2
#define LOADER_MODULE_ID 0x7
/* default shutdown/reboot scope is system(2) */
static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
/**
* pm_get_shutdown_scope() - Get the currently set shutdown scope
*
* @return Shutdown scope value
*/
unsigned int pm_get_shutdown_scope(void)
{
return pm_shutdown_scope;
}
/**
* Assigning of argument values into array elements.
*/
#define PM_PACK_PAYLOAD1(pl, mid, arg0) { \
pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \
}
#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) { \
pl[1] = (uint32_t)(arg1); \
PM_PACK_PAYLOAD1(pl, mid, arg0); \
}
#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) { \
pl[2] = (uint32_t)(arg2); \
PM_PACK_PAYLOAD2(pl, mid, arg0, arg1); \
}
#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) { \
pl[3] = (uint32_t)(arg3); \
PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2); \
}
#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) { \
pl[4] = (uint32_t)(arg4); \
PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3); \
}
#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) { \
pl[5] = (uint32_t)(arg5); \
PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4); \
}
/* PM API functions */
/**
* pm_get_api_version() - Get version number of PMC PM firmware
* @version Returns 32-bit version number of PMC Power Management Firmware
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_get_api_version(unsigned int *version)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION);
return pm_ipi_send_sync(primary_proc, payload, version, 1);
}
/**
* pm_self_suspend() - PM call for processor to suspend itself
* @nid Node id of the processor or subsystem
* @latency Requested maximum wakeup latency (not supported)
* @state Requested state
* @address Resume address
*
* This is a blocking call, it will return only once PMU has responded.
* On a wakeup, resume address will be automatically set by PMU.
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_self_suspend(uint32_t nid,
unsigned int latency,
unsigned int state,
uintptr_t address)
{
uint32_t payload[PAYLOAD_ARG_CNT];
unsigned int cpuid = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpuid);
if (!proc) {
WARN("Failed to get proc %d\n", cpuid);
return PM_RET_ERROR_INTERNAL;
}
/*
* Do client specific suspend operations
* (e.g. set powerdown request bit)
*/
pm_client_suspend(proc, state);
/* Send request to the PLM */
PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, PM_SELF_SUSPEND,
proc->node_id, latency, state, address,
(address >> 32));
return pm_ipi_send_sync(proc, payload, NULL, 0);
}
/**
* pm_abort_suspend() - PM call to announce that a prior suspend request
* is to be aborted.
* @reason Reason for the abort
*
* Calling PU expects the PMU to abort the initiated suspend procedure.
* This is a non-blocking call without any acknowledge.
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/*
* Do client specific abort suspend operations
* (e.g. enable interrupts and clear powerdown request bit)
*/
pm_client_abort_suspend();
/* Send request to the PLM */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason,
primary_proc->node_id);
return pm_ipi_send(primary_proc, payload);
}
/**
* pm_req_suspend() - PM call to request for another PU or subsystem to
* be suspended gracefully.
* @target Node id of the targeted PU or subsystem
* @ack Flag to specify whether acknowledge is requested
* @latency Requested wakeup latency (not supported)
* @state Requested state (not supported)
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
unsigned int latency, unsigned int state)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_REQ_SUSPEND, target,
latency, state);
if (ack == IPI_BLOCKING)
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
else
return pm_ipi_send(primary_proc, payload);
}
/**
* pm_req_wakeup() - PM call for processor to wake up selected processor
* or subsystem
* @target Device ID of the processor or subsystem to wake up
* @set_address Resume address presence indicator
* 1 - resume address specified, 0 - otherwise
* @address Resume address
* @ack Flag to specify whether acknowledge requested
*
* This API function is either used to power up another APU core for SMP
* (by PSCI) or to power up an entirely different PU or subsystem, such
* as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
* automatically set by PMC.
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
uintptr_t address, uint8_t ack)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC to perform the wake of the PU */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQ_WAKEUP, target,
set_address, address, ack);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_request_device() - Request a device
* @device_id Device ID
* @capabilities Requested capabilities for the device
* @qos Required Quality of Service
* @ack Flag to specify whether acknowledge requested
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
uint32_t qos, uint32_t ack)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQUEST_DEVICE,
device_id, capabilities, qos, ack);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_release_device() - Release a device
* @device_id Device ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_release_device(uint32_t device_id)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RELEASE_DEVICE,
device_id);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_set_requirement() - Set requirement for the device
* @device_id Device ID
* @capabilities Requested capabilities for the device
* @latency Requested maximum latency
* @qos Required Quality of Service
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
uint32_t latency, uint32_t qos)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_SET_REQUIREMENT,
device_id, capabilities, latency, qos);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_get_device_status() - Get device's status
* @device_id Device ID
* @response Buffer to store device status response
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_GET_DEVICE_STATUS,
device_id);
return pm_ipi_send_sync(primary_proc, payload, response, 3);
}
/**
* pm_reset_assert() - Assert/De-assert reset
* @reset Reset ID
* @assert Assert (1) or de-assert (0)
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset,
assert);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_reset_get_status() - Get current status of a reset line
* @reset Reset ID
* @status Returns current status of selected reset ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset);
return pm_ipi_send_sync(primary_proc, payload, status, 1);
}
/**
* pm_get_callbackdata() - Read from IPI response buffer
* @data - array of PAYLOAD_ARG_CNT elements
*
* Read value from ipi buffer response buffer.
*/
void pm_get_callbackdata(uint32_t *data, size_t count)
{
/* Return if interrupt is not from PMU */
if (!pm_ipi_irq_status(primary_proc))
return;
pm_ipi_buff_read_callb(data, count);
pm_ipi_irq_clear(primary_proc);
}
/**
* pm_pinctrl_request() - Request a pin
* @pin Pin ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_request(uint32_t pin)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_REQUEST, pin);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pinctrl_release() - Release a pin
* @pin Pin ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_release(uint32_t pin)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_RELEASE, pin);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pinctrl_set_function() - Set pin function
* @pin Pin ID
* @function Function ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, pin,
function)
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pinctrl_get_function() - Get function set on the pin
* @pin Pin ID
* @function Function set on the pin
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION,
pin);
return pm_ipi_send_sync(primary_proc, payload, function, 1);
}
/**
* pm_pinctrl_set_pin_param() - Set configuration parameter for the pin
* @pin Pin ID
* @param Parameter ID
* @value Parameter value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
uint32_t value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_SET,
pin, param, value);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pinctrl_get_pin_param() - Get configuration parameter value for the pin
* @pin Pin ID
* @param Parameter ID
* @value Buffer to store parameter value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
uint32_t *value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_GET,
pin, param);
return pm_ipi_send_sync(primary_proc, payload, value, 1);
}
/**
* pm_clock_enable() - Enable the clock
* @clk_id Clock ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_enable(uint32_t clk_id)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_ENABLE, clk_id);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_clock_disable() - Disable the clock
* @clk_id Clock ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_disable(uint32_t clk_id)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_DISABLE, clk_id);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_clock_get_state() - Get clock status
* @clk_id Clock ID
* @state: Buffer to store clock status (1: Enabled, 0:Disabled)
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETSTATE, clk_id);
return pm_ipi_send_sync(primary_proc, payload, state, 1);
}
/**
* pm_clock_set_divider() - Set divider for the clock
* @clk_id Clock ID
* @divider Divider value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETDIVIDER, clk_id,
divider);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_clock_get_divider() - Get divider value for the clock
* @clk_id Clock ID
* @divider: Buffer to store clock divider value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETDIVIDER, clk_id);
return pm_ipi_send_sync(primary_proc, payload, divider, 1);
}
/**
* pm_clock_set_parent() - Set parent for the clock
* @clk_id Clock ID
* @parent Parent ID
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETPARENT, clk_id,
parent);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_clock_get_parent() - Get parent value for the clock
* @clk_id Clock ID
* @parent: Buffer to store clock parent value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETPARENT, clk_id);
return pm_ipi_send_sync(primary_proc, payload, parent, 1);
}
/**
* pm_pll_set_param() - Set PLL parameter
* @clk_id PLL clock ID
* @param PLL parameter ID
* @value Value to set for PLL parameter
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
uint32_t value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PLL_SET_PARAMETER, clk_id,
param, value);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pll_get_param() - Get PLL parameter value
* @clk_id PLL clock ID
* @param PLL parameter ID
* @value: Buffer to store PLL parameter value
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
uint32_t *value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_GET_PARAMETER, clk_id,
param);
return pm_ipi_send_sync(primary_proc, payload, value, 1);
}
/**
* pm_pll_set_mode() - Set PLL mode
* @clk_id PLL clock ID
* @mode PLL mode
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_SET_MODE, clk_id,
mode);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pll_get_mode() - Get PLL mode
* @clk_id PLL clock ID
* @mode: Buffer to store PLL mode
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PLL_GET_MODE, clk_id);
return pm_ipi_send_sync(primary_proc, payload, mode, 1);
}
/**
* pm_force_powerdown() - PM call to request for another PU or subsystem to
* be powered down forcefully
* @target Device ID of the PU node to be forced powered down.
* @ack Flag to specify whether acknowledge is requested
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_FORCE_POWERDOWN, target,
ack);
if (ack == IPI_BLOCKING)
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
else
return pm_ipi_send(primary_proc, payload);
}
/**
* pm_system_shutdown() - PM call to request a system shutdown or restart
* @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope
* @subtype Scope: 0=APU-subsystem, 1=PS, 2=system
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype)
{
uint32_t payload[PAYLOAD_ARG_CNT];
if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) {
/* Setting scope for subsequent PSCI reboot or shutdown */
pm_shutdown_scope = subtype;
return PM_RET_SUCCESS;
}
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_SYSTEM_SHUTDOWN, type,
subtype);
return pm_ipi_send_non_blocking(primary_proc, payload);
}
/**
* pm_query_data() - PM API for querying firmware data
* @qid The type of data to query
* @arg1 Argument 1 to requested query data call
* @arg2 Argument 2 to requested query data call
* @arg3 Argument 3 to requested query data call
* @data Returned output data
*
* This function returns requested data.
*/
enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
uint32_t arg3, uint32_t *data)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_QUERY_DATA, qid, arg1,
arg2, arg3);
return pm_ipi_send_sync(primary_proc, payload, data, 4);
}
/**
* pm_api_ioctl() - PM IOCTL API for device control and configs
* @device_id Device ID
* @ioctl_id ID of the requested IOCTL
* @arg1 Argument 1 to requested IOCTL call
* @arg2 Argument 2 to requested IOCTL call
* @value Returned output value
*
* This function calls IOCTL to firmware for device control and configuration.
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
uint32_t arg1, uint32_t arg2, uint32_t *value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
switch (ioctl_id) {
case IOCTL_SET_PLL_FRAC_MODE:
return pm_pll_set_mode(arg1, arg2);
case IOCTL_GET_PLL_FRAC_MODE:
return pm_pll_get_mode(arg1, value);
case IOCTL_SET_PLL_FRAC_DATA:
return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2);
case IOCTL_GET_PLL_FRAC_DATA:
return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value);
default:
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_IOCTL, device_id,
ioctl_id, arg1, arg2);
return pm_ipi_send_sync(primary_proc, payload, value, 1);
}
}
/**
* pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
* @target Device id of the targeted PU or subsystem
* @wkup_node Device id of the wakeup peripheral
* @enable Enable or disable the specified peripheral as wake source
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device,
uint8_t enable)
{
uint32_t payload[PAYLOAD_ARG_CNT];
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_SET_WAKEUP_SOURCE, target,
wkup_device, enable);
return pm_ipi_send(primary_proc, payload);
}
/**
* pm_get_chipid() - Read silicon ID registers
* @value Buffer for return values. Must be large enough
* to hold 8 bytes.
*
* @return Returns silicon ID registers
*/
enum pm_ret_status pm_get_chipid(uint32_t *value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_CHIPID);
return pm_ipi_send_sync(primary_proc, payload, value, 2);
}
/**
* pm_feature_check() - Returns the supported API version if supported
* @api_id API ID to check
* @value Returned supported API version
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version)
{
uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
uint32_t status;
switch (api_id) {
case PM_GET_CALLBACK_DATA:
case PM_GET_TRUSTZONE_VERSION:
case PM_INIT_FINALIZE:
*version = (PM_API_BASE_VERSION << 16);
return PM_RET_SUCCESS;
case PM_GET_API_VERSION:
case PM_GET_DEVICE_STATUS:
case PM_GET_OP_CHARACTERISTIC:
case PM_REQ_SUSPEND:
case PM_SELF_SUSPEND:
case PM_FORCE_POWERDOWN:
case PM_ABORT_SUSPEND:
case PM_REQ_WAKEUP:
case PM_SET_WAKEUP_SOURCE:
case PM_SYSTEM_SHUTDOWN:
case PM_REQUEST_DEVICE:
case PM_RELEASE_DEVICE:
case PM_SET_REQUIREMENT:
case PM_RESET_ASSERT:
case PM_RESET_GET_STATUS:
case PM_PINCTRL_REQUEST:
case PM_PINCTRL_RELEASE:
case PM_PINCTRL_GET_FUNCTION:
case PM_PINCTRL_SET_FUNCTION:
case PM_PINCTRL_CONFIG_PARAM_GET:
case PM_PINCTRL_CONFIG_PARAM_SET:
case PM_IOCTL:
case PM_QUERY_DATA:
case PM_CLOCK_ENABLE:
case PM_CLOCK_DISABLE:
case PM_CLOCK_GETSTATE:
case PM_CLOCK_SETDIVIDER:
case PM_CLOCK_GETDIVIDER:
case PM_CLOCK_SETPARENT:
case PM_CLOCK_GETPARENT:
case PM_PLL_SET_PARAMETER:
case PM_PLL_GET_PARAMETER:
case PM_PLL_SET_MODE:
case PM_PLL_GET_MODE:
case PM_FEATURE_CHECK:
*version = (PM_API_BASE_VERSION << 16);
break;
case PM_LOAD_PDI:
*version = (PM_API_BASE_VERSION << 16);
return PM_RET_SUCCESS;
default:
*version = 0U;
return PM_RET_ERROR_NOFEATURE;
}
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_FEATURE_CHECK, api_id);
status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1);
if (status != PM_RET_SUCCESS)
return status;
*version |= fw_api_version;
return PM_RET_SUCCESS;
}
/**
* pm_load_pdi() - Load the PDI
*
* This function provides support to load PDI from linux
*
* src: Source device of pdi(DDR, OCM, SD etc)
* address_low: lower 32-bit Linear memory space address
* address_high: higher 32-bit Linear memory space address
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_load_pdi(uint32_t src,
uint32_t address_low, uint32_t address_high)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, PM_LOAD_PDI, src,
address_high, address_low);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_get_op_characteristic() - PM call to request operating characteristics
* of a device
* @device_id Device id
* @type Type of the operating characteristic
* (power, temperature and latency)
* @result Returns the operating characteristic for the requested device,
* specified by the type
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
enum pm_opchar_type type,
uint32_t *result)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_GET_OP_CHARACTERISTIC,
device_id, type);
return pm_ipi_send_sync(primary_proc, payload, result, 1);
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PM_API_SYS_H
#define PM_API_SYS_H
#include <stdint.h>
#include "pm_defs.h"
/**********************************************************
* PM API function declarations
**********************************************************/
enum pm_ret_status pm_get_api_version(unsigned int *version);
enum pm_ret_status pm_self_suspend(uint32_t nid,
unsigned int latency,
unsigned int state,
uintptr_t address);
enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
enum pm_ret_status pm_req_suspend(uint32_t target,
uint8_t ack,
unsigned int latency,
unsigned int state);
enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
uintptr_t address, uint8_t ack);
enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
uint8_t enable);
enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
uint32_t qos, uint32_t ack);
enum pm_ret_status pm_release_device(uint32_t device_id);
enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
uint32_t latency, uint32_t qos);
enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response);
enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert);
enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status);
void pm_get_callbackdata(uint32_t *data, size_t count);
enum pm_ret_status pm_pinctrl_request(uint32_t pin);
enum pm_ret_status pm_pinctrl_release(uint32_t pin);
enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function);
enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function);
enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
uint32_t value);
enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
uint32_t *value);
enum pm_ret_status pm_clock_enable(uint32_t clk_id);
enum pm_ret_status pm_clock_disable(uint32_t clk_id);
enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state);
enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider);
enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider);
enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent);
enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent);
enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
uint32_t value);
enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
uint32_t *value);
enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode);
enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode);
enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack);
enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype);
enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
uint32_t arg1, uint32_t arg2, uint32_t *value);
enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
uint32_t arg3, uint32_t *data);
unsigned int pm_get_shutdown_scope(void);
enum pm_ret_status pm_get_chipid(uint32_t *value);
enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version);
enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
uint32_t address_high);
enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
enum pm_opchar_type type,
uint32_t *result);
#endif /* PM_API_SYS_H */

View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* APU specific definition of processors in the subsystem as well as functions
* for getting information about and changing state of the APU.
*/
#include <assert.h>
#include <plat_ipi.h>
#include <platform_def.h>
#include <versal_def.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <drivers/arm/gicv3.h>
#include <drivers/arm/gic_common.h>
#include <plat/common/platform.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#define UNDEFINED_CPUID (~0)
#define IRQ_MAX 142
#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1)
DEFINE_BAKERY_LOCK(pm_client_secure_lock);
static const struct pm_ipi apu_ipi = {
.local_ipi_id = IPI_ID_APU,
.remote_ipi_id = IPI_ID_PMC,
.buffer_base = IPI_BUFFER_APU_BASE,
};
/* Order in pm_procs_all array must match cpu ids */
static const struct pm_proc pm_procs_all[] = {
{
.node_id = XPM_DEVID_ACPU_0,
.ipi = &apu_ipi,
.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
},
{
.node_id = XPM_DEVID_ACPU_1,
.ipi = &apu_ipi,
.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
}
};
const struct pm_proc *primary_proc = &pm_procs_all[0];
/* Interrupt to PM node index map */
static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
[13] = XPM_NODEIDX_DEV_GPIO,
[14] = XPM_NODEIDX_DEV_I2C_0,
[15] = XPM_NODEIDX_DEV_I2C_1,
[16] = XPM_NODEIDX_DEV_SPI_0,
[17] = XPM_NODEIDX_DEV_SPI_1,
[18] = XPM_NODEIDX_DEV_UART_0,
[19] = XPM_NODEIDX_DEV_UART_1,
[20] = XPM_NODEIDX_DEV_CAN_FD_0,
[21] = XPM_NODEIDX_DEV_CAN_FD_1,
[22] = XPM_NODEIDX_DEV_USB_0,
[23] = XPM_NODEIDX_DEV_USB_0,
[24] = XPM_NODEIDX_DEV_USB_0,
[25] = XPM_NODEIDX_DEV_USB_0,
[26] = XPM_NODEIDX_DEV_USB_0,
[37] = XPM_NODEIDX_DEV_TTC_0,
[38] = XPM_NODEIDX_DEV_TTC_0,
[39] = XPM_NODEIDX_DEV_TTC_0,
[40] = XPM_NODEIDX_DEV_TTC_1,
[41] = XPM_NODEIDX_DEV_TTC_1,
[42] = XPM_NODEIDX_DEV_TTC_1,
[43] = XPM_NODEIDX_DEV_TTC_2,
[44] = XPM_NODEIDX_DEV_TTC_2,
[45] = XPM_NODEIDX_DEV_TTC_2,
[46] = XPM_NODEIDX_DEV_TTC_3,
[47] = XPM_NODEIDX_DEV_TTC_3,
[48] = XPM_NODEIDX_DEV_TTC_3,
[56] = XPM_NODEIDX_DEV_GEM_0,
[57] = XPM_NODEIDX_DEV_GEM_0,
[58] = XPM_NODEIDX_DEV_GEM_1,
[59] = XPM_NODEIDX_DEV_GEM_1,
[60] = XPM_NODEIDX_DEV_ADMA_0,
[61] = XPM_NODEIDX_DEV_ADMA_1,
[62] = XPM_NODEIDX_DEV_ADMA_2,
[63] = XPM_NODEIDX_DEV_ADMA_3,
[64] = XPM_NODEIDX_DEV_ADMA_4,
[65] = XPM_NODEIDX_DEV_ADMA_5,
[66] = XPM_NODEIDX_DEV_ADMA_6,
[67] = XPM_NODEIDX_DEV_ADMA_7,
[74] = XPM_NODEIDX_DEV_USB_0,
[126] = XPM_NODEIDX_DEV_SDIO_0,
[127] = XPM_NODEIDX_DEV_SDIO_0,
[128] = XPM_NODEIDX_DEV_SDIO_1,
[129] = XPM_NODEIDX_DEV_SDIO_1,
[142] = XPM_NODEIDX_DEV_RTC,
};
/**
* irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
* @irq: Interrupt number
*
* Return: PM node index corresponding to the specified interrupt
*/
static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq)
{
assert(irq <= IRQ_MAX);
return irq_node_map[irq];
}
/**
* pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
* wake sources in the LibPM.
*/
static void pm_client_set_wakeup_sources(void)
{
uint32_t reg_num;
uint32_t device_id;
uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
uint32_t base_irq = reg_num << ISENABLER_SHIFT;
uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
if (!reg)
continue;
while (reg) {
enum pm_device_node_idx node_idx;
uint32_t idx, ret, irq, lowest_set = reg & (-reg);
idx = __builtin_ctz(lowest_set);
irq = base_irq + idx;
if (irq > IRQ_MAX)
break;
node_idx = irq_to_pm_node_idx(irq);
reg &= ~lowest_set;
if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
(!pm_wakeup_nodes_set[node_idx])) {
/* Get device ID from node index */
device_id = PERIPH_DEVID(node_idx);
ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0,
device_id, 1);
pm_wakeup_nodes_set[node_idx] = !ret;
}
}
}
}
/**
* pm_client_suspend() - Client-specific suspend actions
*
* This function should contain any PU-specific actions
* required prior to sending suspend request to PMU
* Actions taken depend on the state system is suspending to.
*/
void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
{
bakery_lock_get(&pm_client_secure_lock);
if (state == PM_STATE_SUSPEND_TO_RAM)
pm_client_set_wakeup_sources();
/* Set powerdown request */
mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
proc->pwrdn_mask);
bakery_lock_release(&pm_client_secure_lock);
}
/**
* pm_client_abort_suspend() - Client-specific abort-suspend actions
*
* This function should contain any PU-specific actions
* required for aborting a prior suspend request
*/
void pm_client_abort_suspend(void)
{
/* Enable interrupts at processor level (for current cpu) */
gicv3_cpuif_enable(plat_my_core_pos());
bakery_lock_get(&pm_client_secure_lock);
/* Clear powerdown request */
mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
~primary_proc->pwrdn_mask);
bakery_lock_release(&pm_client_secure_lock);
}
/**
* pm_get_cpuid() - get the local cpu ID for a global node ID
* @nid: node id of the processor
*
* Return: the cpu ID (starting from 0) for the subsystem
*/
static unsigned int pm_get_cpuid(uint32_t nid)
{
for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
if (pm_procs_all[i].node_id == nid)
return i;
}
return UNDEFINED_CPUID;
}
/**
* pm_client_wakeup() - Client-specific wakeup actions
*
* This function should contain any PU-specific actions
* required for waking up another APU core
*/
void pm_client_wakeup(const struct pm_proc *proc)
{
unsigned int cpuid = pm_get_cpuid(proc->node_id);
if (cpuid == UNDEFINED_CPUID)
return;
bakery_lock_get(&pm_client_secure_lock);
/* clear powerdown bit for affected cpu */
uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
val &= ~(proc->pwrdn_mask);
mmio_write_32(FPD_APU_PWRCTL, val);
bakery_lock_release(&pm_client_secure_lock);
}
/**
* pm_get_proc() - returns pointer to the proc structure
* @cpuid: id of the cpu whose proc struct pointer should be returned
*
* Return: pointer to a proc structure if proc is found, otherwise NULL
*/
const struct pm_proc *pm_get_proc(unsigned int cpuid)
{
if (cpuid < ARRAY_SIZE(pm_procs_all))
return &pm_procs_all[cpuid];
return NULL;
}

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* Versal power management enums and defines */
#ifndef PM_DEFS_H
#define PM_DEFS_H
#include "pm_node.h"
/*********************************************************************
* Macro definitions
********************************************************************/
/* State arguments of the self suspend */
#define PM_STATE_CPU_IDLE 0x0U
#define PM_STATE_SUSPEND_TO_RAM 0xFU
#define MAX_LATENCY (~0U)
#define MAX_QOS 100U
/* Processor core device IDs */
#define APU_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, XPM_NODESUBCL_DEV_CORE, \
XPM_NODETYPE_DEV_CORE_APU, (IDX))
#define XPM_DEVID_ACPU_0 APU_DEVID(XPM_NODEIDX_DEV_ACPU_0)
#define XPM_DEVID_ACPU_1 APU_DEVID(XPM_NODEIDX_DEV_ACPU_1)
#define PERIPH_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, \
XPM_NODESUBCL_DEV_PERIPH, \
XPM_NODETYPE_DEV_PERIPH, (IDX))
#define PM_GET_CALLBACK_DATA 0xa01
#define PM_GET_TRUSTZONE_VERSION 0xa03
/* PM API Versions */
#define PM_API_BASE_VERSION 1U
/* PM API ids */
#define PM_GET_API_VERSION 1U
#define PM_GET_DEVICE_STATUS 3U
#define PM_GET_OP_CHARACTERISTIC 4U
#define PM_REQ_SUSPEND 6U
#define PM_SELF_SUSPEND 7U
#define PM_FORCE_POWERDOWN 8U
#define PM_ABORT_SUSPEND 9U
#define PM_REQ_WAKEUP 10U
#define PM_SET_WAKEUP_SOURCE 11U
#define PM_SYSTEM_SHUTDOWN 12U
#define PM_REQUEST_DEVICE 13U
#define PM_RELEASE_DEVICE 14U
#define PM_SET_REQUIREMENT 15U
#define PM_RESET_ASSERT 17U
#define PM_RESET_GET_STATUS 18U
#define PM_INIT_FINALIZE 21U
#define PM_GET_CHIPID 24U
#define PM_PINCTRL_REQUEST 28U
#define PM_PINCTRL_RELEASE 29U
#define PM_PINCTRL_GET_FUNCTION 30U
#define PM_PINCTRL_SET_FUNCTION 31U
#define PM_PINCTRL_CONFIG_PARAM_GET 32U
#define PM_PINCTRL_CONFIG_PARAM_SET 33U
#define PM_IOCTL 34U
#define PM_QUERY_DATA 35U
#define PM_CLOCK_ENABLE 36U
#define PM_CLOCK_DISABLE 37U
#define PM_CLOCK_GETSTATE 38U
#define PM_CLOCK_SETDIVIDER 39U
#define PM_CLOCK_GETDIVIDER 40U
#define PM_CLOCK_SETRATE 41U
#define PM_CLOCK_GETRATE 42U
#define PM_CLOCK_SETPARENT 43U
#define PM_CLOCK_GETPARENT 44U
#define PM_PLL_SET_PARAMETER 48U
#define PM_PLL_GET_PARAMETER 49U
#define PM_PLL_SET_MODE 50U
#define PM_PLL_GET_MODE 51U
#define PM_FEATURE_CHECK 63U
/* Loader API ids */
#define PM_LOAD_PDI 0x701U
/* IOCTL IDs for clock driver */
#define IOCTL_SET_PLL_FRAC_MODE 8
#define IOCTL_GET_PLL_FRAC_MODE 9
#define IOCTL_SET_PLL_FRAC_DATA 10
#define IOCTL_GET_PLL_FRAC_DATA 11
/* Parameter ID for PLL IOCTLs */
/* Fractional data portion for PLL */
#define PM_PLL_PARAM_DATA 2
/* System shutdown macros */
#define XPM_SHUTDOWN_TYPE_SHUTDOWN 0U
#define XPM_SHUTDOWN_TYPE_RESET 1U
#define XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY 2U
#define XPM_SHUTDOWN_SUBTYPE_RST_SUBSYSTEM 0U
#define XPM_SHUTDOWN_SUBTYPE_RST_PS_ONLY 1U
#define XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM 2U
/*********************************************************************
* Enum definitions
********************************************************************/
enum pm_abort_reason {
ABORT_REASON_WKUP_EVENT = 100,
ABORT_REASON_PU_BUSY,
ABORT_REASON_NO_PWRDN,
ABORT_REASON_UNKNOWN,
};
enum pm_opchar_type {
PM_OPCHAR_TYPE_POWER = 1,
PM_OPCHAR_TYPE_TEMP,
PM_OPCHAR_TYPE_LATENCY,
};
/**
* Subsystem IDs
*/
typedef enum {
XPM_SUBSYSID_PMC,
XPM_SUBSYSID_PSM,
XPM_SUBSYSID_APU,
XPM_SUBSYSID_RPU0_LOCK,
XPM_SUBSYSID_RPU0_0,
XPM_SUBSYSID_RPU0_1,
XPM_SUBSYSID_DDR0,
XPM_SUBSYSID_ME,
XPM_SUBSYSID_PL,
XPM_SUBSYSID_MAX,
} XPm_SubsystemId;
/**
* @PM_RET_SUCCESS: success
* @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
* @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
* @PM_RET_ERROR_NOFEATURE: feature is not available
* @PM_RET_ERROR_INTERNAL: internal error
* @PM_RET_ERROR_CONFLICT: conflict
* @PM_RET_ERROR_ACCESS: access rights violation
* @PM_RET_ERROR_INVALID_NODE: invalid node
* @PM_RET_ERROR_DOUBLE_REQ: duplicate request for same node
* @PM_RET_ERROR_ABORT_SUSPEND: suspend procedure has been aborted
* @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU
* @PM_RET_ERROR_NODE_USED: node is already in use
*/
enum pm_ret_status {
PM_RET_SUCCESS,
PM_RET_ERROR_ARGS = 1,
PM_RET_ERROR_NOTSUPPORTED = 4,
PM_RET_ERROR_NOFEATURE = 19,
PM_RET_ERROR_INTERNAL = 2000,
PM_RET_ERROR_CONFLICT = 2001,
PM_RET_ERROR_ACCESS = 2002,
PM_RET_ERROR_INVALID_NODE = 2003,
PM_RET_ERROR_DOUBLE_REQ = 2004,
PM_RET_ERROR_ABORT_SUSPEND = 2005,
PM_RET_ERROR_TIMEOUT = 2006,
PM_RET_ERROR_NODE_USED = 2007
};
#endif /* PM_DEFS_H */

View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* Versal PM nodes enums and defines */
#ifndef PM_NODE_H
#define PM_NODE_H
/*********************************************************************
* Macro definitions
********************************************************************/
#define NODE_CLASS_SHIFT 26U
#define NODE_SUBCLASS_SHIFT 20U
#define NODE_TYPE_SHIFT 14U
#define NODE_INDEX_SHIFT 0U
#define NODE_CLASS_MASK_BITS 0x3F
#define NODE_SUBCLASS_MASK_BITS 0x3F
#define NODE_TYPE_MASK_BITS 0x3F
#define NODE_INDEX_MASK_BITS 0x3FFF
#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT)
#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT)
#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT)
#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT)
#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \
((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \
(((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \
(((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \
(((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT))
#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT)
#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \
NODE_SUBCLASS_SHIFT)
#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT)
#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT)
/*********************************************************************
* Enum definitions
********************************************************************/
/* Node class types */
enum pm_node_class {
XPM_NODECLASS_MIN,
XPM_NODECLASS_POWER,
XPM_NODECLASS_CLOCK,
XPM_NODECLASS_RESET,
XPM_NODECLASS_MEMIC,
XPM_NODECLASS_STMIC,
XPM_NODECLASS_DEVICE,
XPM_NODECLASS_MAX
};
enum pm_device_node_subclass {
/* Device types */
XPM_NODESUBCL_DEV_CORE = 1,
XPM_NODESUBCL_DEV_PERIPH,
XPM_NODESUBCL_DEV_MEM,
XPM_NODESUBCL_DEV_SOC,
XPM_NODESUBCL_DEV_MEM_CTRLR,
XPM_NODESUBCL_DEV_PHY,
};
enum pm_device_node_type {
/* Device types */
XPM_NODETYPE_DEV_CORE_PMC = 1,
XPM_NODETYPE_DEV_CORE_PSM,
XPM_NODETYPE_DEV_CORE_APU,
XPM_NODETYPE_DEV_CORE_RPU,
XPM_NODETYPE_DEV_OCM,
XPM_NODETYPE_DEV_TCM,
XPM_NODETYPE_DEV_L2CACHE,
XPM_NODETYPE_DEV_DDR,
XPM_NODETYPE_DEV_PERIPH,
XPM_NODETYPE_DEV_SOC,
XPM_NODETYPE_DEV_GT,
};
/* Device node Indexes */
enum pm_device_node_idx {
/* Device nodes */
XPM_NODEIDX_DEV_MIN,
/* Processor devices */
XPM_NODEIDX_DEV_PMC_PROC,
XPM_NODEIDX_DEV_PSM_PROC,
XPM_NODEIDX_DEV_ACPU_0,
XPM_NODEIDX_DEV_ACPU_1,
XPM_NODEIDX_DEV_RPU0_0,
XPM_NODEIDX_DEV_RPU0_1,
/* Memory devices */
XPM_NODEIDX_DEV_OCM_0,
XPM_NODEIDX_DEV_OCM_1,
XPM_NODEIDX_DEV_OCM_2,
XPM_NODEIDX_DEV_OCM_3,
XPM_NODEIDX_DEV_TCM_0_A,
XPM_NODEIDX_DEV_TCM_0_B,
XPM_NODEIDX_DEV_TCM_1_A,
XPM_NODEIDX_DEV_TCM_1_B,
XPM_NODEIDX_DEV_L2_BANK_0,
XPM_NODEIDX_DEV_DDR_0,
XPM_NODEIDX_DEV_DDR_1,
XPM_NODEIDX_DEV_DDR_2,
XPM_NODEIDX_DEV_DDR_3,
XPM_NODEIDX_DEV_DDR_4,
XPM_NODEIDX_DEV_DDR_5,
XPM_NODEIDX_DEV_DDR_6,
XPM_NODEIDX_DEV_DDR_7,
/* LPD Peripheral devices */
XPM_NODEIDX_DEV_USB_0,
XPM_NODEIDX_DEV_GEM_0,
XPM_NODEIDX_DEV_GEM_1,
XPM_NODEIDX_DEV_SPI_0,
XPM_NODEIDX_DEV_SPI_1,
XPM_NODEIDX_DEV_I2C_0,
XPM_NODEIDX_DEV_I2C_1,
XPM_NODEIDX_DEV_CAN_FD_0,
XPM_NODEIDX_DEV_CAN_FD_1,
XPM_NODEIDX_DEV_UART_0,
XPM_NODEIDX_DEV_UART_1,
XPM_NODEIDX_DEV_GPIO,
XPM_NODEIDX_DEV_TTC_0,
XPM_NODEIDX_DEV_TTC_1,
XPM_NODEIDX_DEV_TTC_2,
XPM_NODEIDX_DEV_TTC_3,
XPM_NODEIDX_DEV_SWDT_LPD,
/* FPD Peripheral devices */
XPM_NODEIDX_DEV_SWDT_FPD,
/* PMC Peripheral devices */
XPM_NODEIDX_DEV_OSPI,
XPM_NODEIDX_DEV_QSPI,
XPM_NODEIDX_DEV_GPIO_PMC,
XPM_NODEIDX_DEV_I2C_PMC,
XPM_NODEIDX_DEV_SDIO_0,
XPM_NODEIDX_DEV_SDIO_1,
XPM_NODEIDX_DEV_PL_0,
XPM_NODEIDX_DEV_PL_1,
XPM_NODEIDX_DEV_PL_2,
XPM_NODEIDX_DEV_PL_3,
XPM_NODEIDX_DEV_RTC,
XPM_NODEIDX_DEV_ADMA_0,
XPM_NODEIDX_DEV_ADMA_1,
XPM_NODEIDX_DEV_ADMA_2,
XPM_NODEIDX_DEV_ADMA_3,
XPM_NODEIDX_DEV_ADMA_4,
XPM_NODEIDX_DEV_ADMA_5,
XPM_NODEIDX_DEV_ADMA_6,
XPM_NODEIDX_DEV_ADMA_7,
XPM_NODEIDX_DEV_IPI_0,
XPM_NODEIDX_DEV_IPI_1,
XPM_NODEIDX_DEV_IPI_2,
XPM_NODEIDX_DEV_IPI_3,
XPM_NODEIDX_DEV_IPI_4,
XPM_NODEIDX_DEV_IPI_5,
XPM_NODEIDX_DEV_IPI_6,
/* Entire SoC */
XPM_NODEIDX_DEV_SOC,
/* DDR memory controllers */
XPM_NODEIDX_DEV_DDRMC_0,
XPM_NODEIDX_DEV_DDRMC_1,
XPM_NODEIDX_DEV_DDRMC_2,
XPM_NODEIDX_DEV_DDRMC_3,
/* GT devices */
XPM_NODEIDX_DEV_GT_0,
XPM_NODEIDX_DEV_GT_1,
XPM_NODEIDX_DEV_GT_2,
XPM_NODEIDX_DEV_GT_3,
XPM_NODEIDX_DEV_GT_4,
XPM_NODEIDX_DEV_GT_5,
XPM_NODEIDX_DEV_GT_6,
XPM_NODEIDX_DEV_GT_7,
XPM_NODEIDX_DEV_GT_8,
XPM_NODEIDX_DEV_GT_9,
XPM_NODEIDX_DEV_GT_10,
XPM_NODEIDX_DEV_MAX
};
#endif /* PM_NODE_H */

View File

@ -0,0 +1,328 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Top-level SMC handler for Versal power management calls and
* IPI setup functions for communication with PMC.
*/
#include <errno.h>
#include <plat_private.h>
#include <stdbool.h>
#include <common/runtime_svc.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#include "pm_ipi.h"
/* pm_up = true - UP, pm_up = false - DOWN */
static bool pm_up;
/**
* pm_setup() - PM service setup
*
* @return On success, the initialization function must return 0.
* Any other return value will cause the framework to ignore
* the service
*
* Initialization functions for Versal power management for
* communicaton with PMC.
*
* Called from sip_svc_setup initialization function with the
* rt_svc_init signature.
*/
int pm_setup(void)
{
int status, ret = 0;
status = pm_ipi_init(primary_proc);
if (status < 0) {
INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
ret = status;
} else {
pm_up = true;
}
return ret;
}
/**
* pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
* @smc_fid - Function Identifier
* @x1 - x4 - Arguments
* @cookie - Unused
* @handler - Pointer to caller's context structure
*
* @return - Unused
*
* Determines that smc_fid is valid and supported PM SMC Function ID from the
* list of pm_api_ids, otherwise completes the request with
* the unknown SMC Function ID
*
* The SMC calls for PM service are forwarded from SIP Service SMC handler
* function with rt_svc_handle signature
*/
uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie, void *handle, uint64_t flags)
{
enum pm_ret_status ret;
uint32_t pm_arg[4];
/* Handle case where PM wasn't initialized properly */
if (!pm_up)
SMC_RET1(handle, SMC_UNK);
pm_arg[0] = (uint32_t)x1;
pm_arg[1] = (uint32_t)(x1 >> 32);
pm_arg[2] = (uint32_t)x2;
pm_arg[3] = (uint32_t)(x2 >> 32);
switch (smc_fid & FUNCID_NUM_MASK) {
/* PM API Functions */
case PM_SELF_SUSPEND:
ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_FORCE_POWERDOWN:
ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQ_SUSPEND:
ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_ABORT_SUSPEND:
ret = pm_abort_suspend(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SYSTEM_SHUTDOWN:
ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQ_WAKEUP:
ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SET_WAKEUP_SOURCE:
ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQUEST_DEVICE:
ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_RELEASE_DEVICE:
ret = pm_release_device(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SET_REQUIREMENT:
ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_API_VERSION:
{
uint32_t api_version;
ret = pm_get_api_version(&api_version);
SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
((uint64_t)api_version << 32));
}
case PM_GET_DEVICE_STATUS:
{
uint32_t buff[3];
ret = pm_get_device_status(pm_arg[0], buff);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
(uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
}
case PM_RESET_ASSERT:
ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_RESET_GET_STATUS:
{
uint32_t reset_status;
ret = pm_reset_get_status(pm_arg[0], &reset_status);
SMC_RET1(handle, (uint64_t)ret |
((uint64_t)reset_status << 32));
}
case PM_INIT_FINALIZE:
SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS);
case PM_GET_CALLBACK_DATA:
{
uint32_t result[4] = {0};
pm_get_callbackdata(result, sizeof(result));
SMC_RET2(handle,
(uint64_t)result[0] | ((uint64_t)result[1] << 32),
(uint64_t)result[2] | ((uint64_t)result[3] << 32));
}
case PM_PINCTRL_REQUEST:
ret = pm_pinctrl_request(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_PINCTRL_RELEASE:
ret = pm_pinctrl_release(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_PINCTRL_GET_FUNCTION:
{
uint32_t value = 0;
ret = pm_pinctrl_get_function(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_PINCTRL_SET_FUNCTION:
ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_PINCTRL_CONFIG_PARAM_GET:
{
uint32_t value;
ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_PINCTRL_CONFIG_PARAM_SET:
ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
case PM_IOCTL:
{
uint32_t value;
ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_QUERY_DATA:
{
uint32_t data[4] = { 0 };
ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], data);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32),
(uint64_t)data[1] | ((uint64_t)data[2] << 32));
}
case PM_CLOCK_ENABLE:
ret = pm_clock_enable(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_DISABLE:
ret = pm_clock_disable(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETSTATE:
{
uint32_t value;
ret = pm_clock_get_state(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_CLOCK_SETDIVIDER:
ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETDIVIDER:
{
uint32_t value;
ret = pm_clock_get_divider(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_CLOCK_SETPARENT:
ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETPARENT:
{
uint32_t value;
ret = pm_clock_get_parent(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
case PM_PLL_SET_PARAMETER:
ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
case PM_PLL_GET_PARAMETER:
{
uint32_t value;
ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
}
case PM_PLL_SET_MODE:
ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_PLL_GET_MODE:
{
uint32_t mode;
ret = pm_pll_get_mode(pm_arg[0], &mode);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
}
case PM_GET_TRUSTZONE_VERSION:
SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
((uint64_t)VERSAL_TZ_VERSION << 32));
case PM_GET_CHIPID:
{
uint32_t result[2];
ret = pm_get_chipid(result);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
result[1]);
}
case PM_FEATURE_CHECK:
{
uint32_t version;
ret = pm_feature_check(pm_arg[0], &version);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
}
case PM_LOAD_PDI:
{
ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
}
case PM_GET_OP_CHARACTERISTIC:
{
uint32_t result;
ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
}
default:
WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PM_SVC_MAIN_H
#define PM_SVC_MAIN_H
#include <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 */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -10,6 +10,9 @@
#include <common/runtime_svc.h>
#include <tools_share/uuid.h>
#include "ipi_mailbox_svc.h"
#include "pm_svc_main.h"
/* SMC function IDs for SiP Service queries */
#define VERSAL_SIP_SVC_CALL_COUNT 0x8200ff00
#define VERSAL_SIP_SVC_UID 0x8200ff01
@ -22,7 +25,9 @@
/* These macros are used to identify PM calls from the SMC function ID */
#define PM_FID_MASK 0xf000u
#define PM_FID_VALUE 0u
#define IPI_FID_VALUE 0x1000u
#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
/* SiP Service UUID */
DEFINE_SVC_UUID2(versal_sip_uuid,
@ -36,6 +41,9 @@ DEFINE_SVC_UUID2(versal_sip_uuid,
*/
static int32_t sip_svc_setup(void)
{
/* PM implementation as SiP Service */
pm_setup();
return 0;
}
@ -54,6 +62,18 @@ uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
void *handle,
u_register_t flags)
{
/* Let PM SMC handler deal with PM-related requests */
if (is_pm_fid(smc_fid)) {
return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
flags);
}
/* Let IPI SMC handler deal with IPI-related requests */
if (is_ipi_fid(smc_fid)) {
return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
flags);
}
/* Let PM SMC handler deal with PM-related requests */
switch (smc_fid) {
case VERSAL_SIP_SVC_CALL_COUNT:

View File

@ -1,9 +1,10 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <plat_private.h>
#include <platform_def.h>
#include <common/interrupt_props.h>
@ -11,8 +12,6 @@
#include <lib/utils.h>
#include <plat/common/platform.h>
#include "versal_private.h"
/******************************************************************************
* The following functions are defined as weak to allow a platform to override
* the way the GICv3 driver is initialised and used.

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Versal IPI agent registers access management
*/
#include <errno.h>
#include <ipi.h>
#include <plat_ipi.h>
#include <plat_private.h>
#include <string.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
/* versal ipi configuration table */
const static struct ipi_config versal_ipi_table[] = {
/* A72 IPI */
[IPI_ID_APU] = {
.ipi_bit_mask = IPI0_TRIG_BIT,
.ipi_reg_base = IPI0_REG_BASE,
.secure_only = 0,
},
/* PMC IPI */
[IPI_ID_PMC] = {
.ipi_bit_mask = PMC_IPI_TRIG_BIT,
.ipi_reg_base = IPI0_REG_BASE,
.secure_only = 0,
},
/* RPU0 IPI */
[IPI_ID_RPU0] = {
.ipi_bit_mask = IPI1_TRIG_BIT,
.ipi_reg_base = IPI1_REG_BASE,
.secure_only = 0,
},
/* RPU1 IPI */
[IPI_ID_RPU1] = {
.ipi_bit_mask = IPI2_TRIG_BIT,
.ipi_reg_base = IPI2_REG_BASE,
.secure_only = 0,
},
/* IPI3 IPI */
[IPI_ID_3] = {
.ipi_bit_mask = IPI3_TRIG_BIT,
.ipi_reg_base = IPI3_REG_BASE,
.secure_only = 0,
},
/* IPI4 IPI */
[IPI_ID_4] = {
.ipi_bit_mask = IPI4_TRIG_BIT,
.ipi_reg_base = IPI4_REG_BASE,
.secure_only = 0,
},
/* IPI5 IPI */
[IPI_ID_5] = {
.ipi_bit_mask = IPI5_TRIG_BIT,
.ipi_reg_base = IPI5_REG_BASE,
.secure_only = 0,
},
};
/* versal_ipi_config_table_init() - Initialize versal IPI configuration data
*
* @ipi_config_table - IPI configuration table
* @ipi_total - Total number of IPI available
*
*/
void versal_ipi_config_table_init(void)
{
ipi_config_table_init(versal_ipi_table, ARRAY_SIZE(versal_ipi_table));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -100,9 +100,8 @@ 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]);
plat_arm_gic_pcpu_init();
gicv2_cpuif_enable();
gicv2_pcpu_distif_init();
}
static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)

View File

@ -11,6 +11,8 @@ SEPARATE_CODE_AND_RODATA := 1
ZYNQMP_WDT_RESTART := 0
ZYNQMP_IPI_CRC_CHECK := 0
override RESET_TO_BL31 := 1
override GICV2_G0_FOR_EL3 := 1
override WARMBOOT_ENABLE_DCACHE_EARLY := 1
# Do not enable SVE
ENABLE_SVE_FOR_NS := 0
@ -53,9 +55,9 @@ endif
PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
-Iinclude/plat/arm/common/aarch64/ \
-Iplat/xilinx/common/include/ \
-Iplat/xilinx/common/ipi_mailbox_service/ \
-Iplat/xilinx/zynqmp/include/ \
-Iplat/xilinx/zynqmp/pm_service/ \
-Iplat/xilinx/zynqmp/ipi_mailbox_service/
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
@ -78,6 +80,7 @@ BL31_SOURCES += drivers/arm/cci/cci.c \
lib/cpus/aarch64/aem_generic.S \
lib/cpus/aarch64/cortex_a53.S \
plat/common/plat_psci_common.c \
plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
plat/xilinx/common/pm_service/pm_ipi.c \
plat/xilinx/zynqmp/bl31_zynqmp_setup.c \
plat/xilinx/zynqmp/plat_psci.c \
@ -90,5 +93,8 @@ BL31_SOURCES += drivers/arm/cci/cci.c \
plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \
plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \
plat/xilinx/zynqmp/pm_service/pm_api_clock.c \
plat/xilinx/zynqmp/pm_service/pm_client.c \
plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
plat/xilinx/zynqmp/pm_service/pm_client.c
ifneq (${RESET_TO_BL31},1)
$(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.")
endif

View File

@ -77,8 +77,12 @@ static void trigger_wdt_restart(void)
INFO("Active Cores: %d\n", active_cores);
/* trigger SGI to active cores */
gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list);
for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) {
if (target_cpu_list & (1 << i)) {
/* trigger SGI to active cores */
plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i);
}
}
}
/**
@ -106,6 +110,8 @@ static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle,
{
INFO("BL31: Got TTC FIQ\n");
plat_ic_end_of_interrupt(id);
/* Clear TTC interrupt by reading interrupt register */
mmio_read_32(TTC3_INTR_REGISTER_1);