arm-trusted-firmware/plat/xilinx/common/pm_service/pm_api_sys.c
Maheedhar Bollapalli 83bcef3f50 fix(xilinx): typecast expressions to match data type
This corrects the MISRA violation C2012-10.4:
Both operands of an operator in which the usual arithmetic conversions
are performed shall have the same essential type category.
The condition is explicitly checked against 0U, appending 'U' and
typecasting for unsigned comparison.

Change-Id: I9110ea86f5ee49af0b21be78fd0890742ef95ddf
Signed-off-by: Nithin G <nithing@amd.com>
Signed-off-by: Maheedhar Bollapalli <maheedharsai.bollapalli@amd.com>
2024-12-20 11:00:53 +00:00

508 lines
15 KiB
C

/*
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Versal system level PM-API functions and communication with PMC via
* IPI interrupts
*/
#include <drivers/arm/gic_common.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <pm_api_sys.h>
#include <pm_client.h>
#include <pm_common.h>
#include <pm_defs.h>
#include <pm_ipi.h>
#include "pm_svc_main.h"
#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
/* default shutdown/reboot scope is system(2) */
static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
/**
* pm_get_shutdown_scope() - Get the currently set shutdown scope.
*
* Return: Shutdown scope value.
*
*/
uint32_t pm_get_shutdown_scope(void)
{
return pm_shutdown_scope;
}
/* PM API functions */
/**
* pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
* wake sources in the XilPM.
* @node_id: Node id of processor.
*
*/
void pm_client_set_wakeup_sources(uint32_t node_id)
{
uint32_t reg_num, device_id;
uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX] = {0U};
uint32_t isenabler1 = PLAT_ARM_GICD_BASE + GICD_ISENABLER + 4U;
zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
for (reg_num = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) {
uint32_t base_irq = reg_num << ISENABLER_SHIFT;
isenabler1 += (reg_num << 2);
uint32_t reg = mmio_read_32((uint64_t)isenabler1);
if (reg == 0U) {
continue;
}
while (reg != 0U) {
enum pm_device_node_idx node_idx;
uint32_t idx, irq, lowest_set = reg & (-reg);
enum pm_ret_status ret;
idx = (uint32_t)__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) {
if (pm_wakeup_nodes_set[node_idx] == 0U) {
/* Get device ID from node index */
device_id = PERIPH_DEVID((uint32_t)node_idx);
ret = pm_set_wakeup_source(node_id,
device_id, 1U,
SECURE_FLAG);
pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
1U : 0U;
}
}
}
}
}
/**
* pm_handle_eemi_call() - PM call for processor to send eemi payload.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
* @x0: Arguments received per SMC64 standard.
* @x1: Arguments received per SMC64 standard.
* @x2: Arguments received per SMC64 standard.
* @x3: Arguments received per SMC64 standard.
* @x4: Arguments received per SMC64 standard.
* @x5: Arguments received per SMC64 standard.
* @result: Payload received from firmware.
*
* Return: PM_RET_SUCCESS on success or error code.
*
*/
enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
uint32_t x2, uint32_t x3, uint32_t x4,
uint32_t x5, uint64_t *result)
{
uint32_t payload[PAYLOAD_ARG_CNT] = {0};
uint32_t module_id;
module_id = (x0 & MODULE_ID_MASK) >> 8U;
//default module id is for LIBPM
if (module_id == 0U) {
module_id = LIBPM_MODULE_ID;
}
PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, RET_PAYLOAD_ARG_CNT);
}
/**
* 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.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* 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,
uint32_t latency,
uint32_t state,
uintptr_t address, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
uint32_t cpuid = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpuid);
if (proc == NULL) {
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, flag, 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.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* 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 flag)
{
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, flag, PM_ABORT_SUSPEND,
reason, primary_proc->node_id);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* 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).
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* Return: Returns status, either success or error+reason.
*
*/
enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
uint32_t latency, uint32_t state,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target,
latency, state);
if (ack == (uint32_t)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.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* 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 flag)
{
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, flag, PM_REQ_WAKEUP, target,
set_address, address, ack);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_get_callbackdata() - Read from IPI response buffer.
* @data: array of PAYLOAD_ARG_CNT elements.
* @count: Number of values to return.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
* @ack: 0 - Do not ack IPI after reading payload.
* 1 - Ack IPI after reading payload.
*
* Read value from ipi buffer response buffer.
* Return: Returns status, either success or error.
*
*/
enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
{
enum pm_ret_status ret = PM_RET_SUCCESS;
/* Return if interrupt is not from PMU */
if (pm_ipi_irq_status(primary_proc) == 0U) {
return ret;
}
ret = pm_ipi_buff_read_callb(data, count);
if (ack != 0U) {
pm_ipi_irq_clear(primary_proc);
}
return ret;
}
/**
* 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
* @flag: 0 - Call from secure source
* 1 - Call from non-secure source
*
* Return: Returns status, either success or error+reason.
*
*/
enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN,
target, ack);
if (ack == (uint32_t)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.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* Return: Returns status, either success or error+reason.
*
*/
enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
uint32_t flag)
{
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, flag, PM_SYSTEM_SHUTDOWN,
type, subtype);
return pm_ipi_send_non_blocking(primary_proc, payload);
}
/**
* pm_set_wakeup_source() - PM call to specify the wakeup source while
* suspended.
* @target: Device id of the targeted PU or subsystem
* @wkup_device: Device id of the wakeup peripheral
* @enable: Enable or disable the specified peripheral as wake source
* @flag: 0 - Call from secure source
* 1 - Call from non-secure 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 flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE,
target, wkup_device, enable);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* eemi_feature_check() - Returns the supported API version if supported.
* @api_id: API ID to check.
* @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
* words Returned supported API version
*
* Return: Returns status, either success or error+reason.
*/
enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload)
{
enum pm_ret_status ret;
/* Return version of API which are implemented in TF-A only */
switch (api_id) {
case PM_GET_CALLBACK_DATA:
case PM_GET_TRUSTZONE_VERSION:
ret_payload[0] = PM_API_VERSION_2;
ret = PM_RET_SUCCESS;
break;
case TF_A_PM_REGISTER_SGI:
case TF_A_FEATURE_CHECK:
ret_payload[0] = PM_API_BASE_VERSION;
ret = PM_RET_SUCCESS;
break;
default:
ret = PM_RET_ERROR_NO_FEATURE;
}
return ret;
}
/**
* pm_feature_check() - Returns the supported API version if supported.
* @api_id: API ID to check.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
* @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
* words Returned supported API version and bitmasks
* for IOCTL and QUERY ID
*
* Return: Returns status, either success or error+reason.
*
*/
enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
uint32_t module_id;
/* Return version of API which are implemented in TF-A only */
switch (api_id) {
case PM_GET_CALLBACK_DATA:
case PM_GET_TRUSTZONE_VERSION:
ret_payload[0] = PM_API_VERSION_2;
return PM_RET_SUCCESS;
case TF_A_PM_REGISTER_SGI:
ret_payload[0] = PM_API_BASE_VERSION;
return PM_RET_SUCCESS;
default:
break;
}
module_id = (api_id & MODULE_ID_MASK) >> 8U;
/*
* feature check should be done only for LIBPM module
* If module_id is 0, then we consider it LIBPM module as default id
*/
if ((module_id > 0U) && (module_id != LIBPM_MODULE_ID)) {
return PM_RET_SUCCESS;
}
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
PM_FEATURE_CHECK, api_id);
return pm_ipi_send_sync(primary_proc, payload, ret_payload, RET_PAYLOAD_ARG_CNT);
}
/**
* 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.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* 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 flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src,
address_high, address_low);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_register_notifier() - PM call to register a subsystem to be notified
* about the device event.
* @device_id: Device ID for the Node to which the event is related.
* @event: Event in question.
* @wake: Wake subsystem upon capturing the event if value 1.
* @enable: Enable the registration for value 1, disable for value 0.
* @flag: 0 - Call from secure source.
* 1 - Call from non-secure source.
*
* Return: Returns status, either success or error+reason.
*
*/
enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
uint32_t wake, uint32_t enable,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER,
device_id, event, wake, enable);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_get_chipid() - Read silicon ID registers.
* @value: Buffer for two 32bit words.
*
* Return: Returns status, either success or error+reason and,
* optionally, @value.
*/
enum pm_ret_status pm_get_chipid(uint32_t *value)
{
uint32_t payload[PAYLOAD_ARG_CNT];
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, SECURE_FLAG, PM_GET_CHIPID);
return pm_ipi_send_sync(primary_proc, payload, value, 2);
}