mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 10:34:19 +00:00
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:
commit
f44d291f23
27 changed files with 2395 additions and 88 deletions
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
*/
|
|
@ -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
|
||||
*/
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
55
plat/xilinx/versal/include/plat_ipi.h
Normal file
55
plat/xilinx/versal/include/plat_ipi.h
Normal 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 */
|
26
plat/xilinx/versal/include/plat_pm_common.h
Normal file
26
plat/xilinx/versal/include/plat_pm_common.h
Normal 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 */
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
885
plat/xilinx/versal/pm_service/pm_api_sys.c
Normal file
885
plat/xilinx/versal/pm_service/pm_api_sys.c
Normal 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);
|
||||
}
|
75
plat/xilinx/versal/pm_service/pm_api_sys.h
Normal file
75
plat/xilinx/versal/pm_service/pm_api_sys.h
Normal 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 */
|
249
plat/xilinx/versal/pm_service/pm_client.c
Normal file
249
plat/xilinx/versal/pm_service/pm_client.c
Normal 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;
|
||||
}
|
166
plat/xilinx/versal/pm_service/pm_defs.h
Normal file
166
plat/xilinx/versal/pm_service/pm_defs.h
Normal 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 */
|
192
plat/xilinx/versal/pm_service/pm_node.h
Normal file
192
plat/xilinx/versal/pm_service/pm_node.h
Normal 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 */
|
328
plat/xilinx/versal/pm_service/pm_svc_main.c
Normal file
328
plat/xilinx/versal/pm_service/pm_svc_main.c
Normal 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);
|
||||
}
|
||||
}
|
17
plat/xilinx/versal/pm_service/pm_svc_main.h
Normal file
17
plat/xilinx/versal/pm_service/pm_svc_main.h
Normal 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 */
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
82
plat/xilinx/versal/versal_ipi.c
Normal file
82
plat/xilinx/versal/versal_ipi.c
Normal 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));
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue