feat(versal): add common interfaces to handle EEMI commands

This change adds common interfaces to handle commands from firmware driver
to power management controller. It removes big chunk of source line of code
that was handling each command separately and doing same repetitive work.

EEMI - Embedded Energy Management Interface is Xilinx proprietary
protocol to allow communication between power management controller
and different processing clusters.

As of now, Each EEMI command has its own implementation in TF-A.
This is redundant. Essentially most EEMI command implementation
in TF-A  does same work. It prepares payload received from kernel, sends
payload to firmware, receives response from firmware and send response
back to kernel.

The same functionality can be achieved if common interface is used among
multiple EEMI commands. This change divides platform management related
SMCCC requests into 4 categories.

1) EEMI commands required for backward compatibility.

Some EEMI commands are still required for backward compatibility
until removed completely or its use is changed to accommodate
common interface

2) EEMI commands that require for PSCI interface and accessed from debugfs

For example EEMI calls related to CPU suspend/resume

3) TF-A specific requests

Functionality such as getting TF-A version and getting callback
data for platform management is handled by this interface

4) Common interface for rest of EEMI commands

This handlers performs payload and firmware response transaction job for
rest of EEMI commands. Also it parses module ID from SMC payload and inserts
in IPI request. If not module ID is found, then default is LIBPM_MODULE_ID.
This helps in making common path in TF-A for all the modules in PLM firmware

Change-Id: I57a2787c7fff9f2e1d1f9003b3daab092632d57e
Signed-off-by: Tanmay Shah <tanmay.shah@xilinx.com>
This commit is contained in:
Tanmay Shah 2021-08-09 11:00:41 -07:00
parent 2fe9d05853
commit 1397967490
4 changed files with 278 additions and 930 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -25,6 +25,8 @@
#define LOADER_MODULE_ID 0x7U
#define MODE 0x80000000U
#define MODULE_ID_MASK 0x0000ff00
/* default shutdown/reboot scope is system(2) */
static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
@ -73,38 +75,29 @@ unsigned int pm_get_shutdown_scope(void)
/* 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
* 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 to x5 Arguments received per SMC64 standard
* @result Payload received from firmware
*
* @return Returns status, either success or error+reason
* @return PM_RET_SUCCESS on success or error code
*/
enum pm_ret_status pm_get_api_version(unsigned int *version, uint32_t flag)
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];
uint32_t payload[PAYLOAD_ARG_CNT] = {0};
uint32_t module_id;
/* Send request to the PMC */
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, flag, PM_GET_API_VERSION);
return pm_ipi_send_sync(primary_proc, payload, version, 1);
}
module_id = (x0 & MODULE_ID_MASK) >> 8;
/**
* pm_init_finalize() - Call to notify PMC PM firmware that master has power
* management enabled and that it has finished its
* initialization
* @flag 0 - Call from secure source
* 1 - Call from non-secure source
*
* @return Status returned by the PMU firmware
*/
enum pm_ret_status pm_init_finalize(uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
//default module id is for LIBPM
if (module_id == 0)
module_id = LIBPM_MODULE_ID;
/* Send request to the PMU */
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, flag, PM_INIT_FINALIZE);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
}
/**
@ -234,134 +227,6 @@ enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
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
* @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_request_device(uint32_t device_id, uint32_t capabilities,
uint32_t qos, uint32_t ack, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, 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
* @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_release_device(uint32_t device_id, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
* @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_requirement(uint32_t device_id, uint32_t capabilities,
uint32_t latency, uint32_t qos,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, 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
* @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_get_device_status(uint32_t device_id, uint32_t *response,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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)
* @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_reset_assert(uint32_t reset, bool assert, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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
* @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_reset_get_status(uint32_t reset, uint32_t *status,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
@ -381,295 +246,13 @@ void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag)
pm_ipi_irq_clear(primary_proc);
}
/**
* pm_pinctrl_request() - Request a pin
* @pin Pin ID
* @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_pinctrl_request(uint32_t pin, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_PINCTRL_REQUEST,
pin);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_pinctrl_release() - Release a pin
* @pin Pin ID
* @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_pinctrl_release(uint32_t pin, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
* @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_pinctrl_set_function(uint32_t pin, uint32_t function,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag,
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
* @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_pinctrl_get_function(uint32_t pin, uint32_t *function,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
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
* @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_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
uint32_t value, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag,
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
* @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_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
uint32_t *value, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag,
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
* @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_clock_enable(uint32_t clk_id, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
* @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_clock_disable(uint32_t clk_id, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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)
* @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_clock_get_state(uint32_t clk_id, uint32_t *state,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
* @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_clock_set_divider(uint32_t clk_id, uint32_t divider,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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
* @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_clock_get_divider(uint32_t clk_id, uint32_t *divider,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
* @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_clock_set_parent(uint32_t clk_id, uint32_t parent,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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
* @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_clock_get_parent(uint32_t clk_id, uint32_t *parent,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_CLOCK_GETPARENT,
clk_id);
return pm_ipi_send_sync(primary_proc, payload, parent, 1);
}
/**
* pm_clock_get_rate() - Get the rate value for the clock
* @clk_id Clock ID
* @rate: Buffer to store clock rate value
* @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_clock_get_rate(uint32_t clk_id, uint32_t *clk_rate,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_CLOCK_GETRATE,
clk_id);
return pm_ipi_send_sync(primary_proc, payload, clk_rate, 2);
}
/**
* pm_pll_set_param() - Set PLL parameter
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @clk_id PLL clock ID
* @param PLL parameter ID
* @value Value to set for PLL parameter
@ -692,6 +275,11 @@ enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
/**
* pm_pll_get_param() - Get PLL parameter value
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @clk_id PLL clock ID
* @param PLL parameter ID
* @value: Buffer to store PLL parameter value
@ -714,6 +302,11 @@ enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
/**
* pm_pll_set_mode() - Set PLL mode
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @clk_id PLL clock ID
* @mode PLL mode
* @flag 0 - Call from secure source
@ -735,6 +328,11 @@ enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode,
/**
* pm_pll_get_mode() - Get PLL mode
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @clk_id PLL clock ID
* @mode: Buffer to store PLL mode
* @flag 0 - Call from secure source
@ -808,22 +406,28 @@ enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
}
/**
* 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
* @flag 0 - Call from secure source
* 1 - Call from non-secure source
*
* This function returns requested data.
*/
* pm_query_data() - PM API for querying firmware data
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @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
* @flag 0 - Call from secure source
* 1 - Call from non-secure source
*
* @retur - 0 if success else non-zero error code of type
* enum pm_ret_status
*/
enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
uint32_t arg3, uint32_t *data, uint32_t flag)
{
uint32_t ret;
uint32_t version;
uint32_t version[PAYLOAD_ARG_CNT] = {0};
uint32_t payload[PAYLOAD_ARG_CNT];
uint32_t fw_api_version;
@ -831,25 +435,32 @@ enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid,
arg1, arg2, arg3);
ret = pm_feature_check(PM_QUERY_DATA, &version, flag);
if (PM_RET_SUCCESS == ret) {
fw_api_version = version & 0xFFFFU;
if ((2U == fw_api_version) &&
((XPM_QID_CLOCK_GET_NAME == qid) ||
(XPM_QID_PINCTRL_GET_FUNCTION_NAME == qid))) {
ret = pm_ipi_send_sync(primary_proc, payload, data, 8);
ret = data[0];
data[0] = data[1];
data[1] = data[2];
data[2] = data[3];
ret = pm_feature_check(PM_QUERY_DATA, &version[0], flag);
if (ret == PM_RET_SUCCESS) {
fw_api_version = version[0] & 0xFFFF;
if ((fw_api_version == 2U) &&
((qid == XPM_QID_CLOCK_GET_NAME) ||
(qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) {
ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
if (ret == PM_RET_SUCCESS) {
ret = data[0];
data[0] = data[1];
data[1] = data[2];
data[2] = data[3];
}
} else {
ret = pm_ipi_send_sync(primary_proc, payload, data, 4);
ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
}
}
return ret;
}
/**
* pm_api_ioctl() - PM IOCTL API for device control and configs
*
* This API is deprecated and maintained here for backward compatibility.
* New use of this API should be avoided for versal platform.
* This API and its use cases will be removed for versal platform.
*
* @device_id Device ID
* @ioctl_id ID of the requested IOCTL
* @arg1 Argument 1 to requested IOCTL call
@ -860,13 +471,13 @@ enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
*
* This function calls IOCTL to firmware for device control and configuration.
*
* @return Returns status, either success or error+reason
* @return Returns status, either 0 on success or non-zero error code
* of type enum pm_ret_status
*/
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 flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
enum pm_ret_status ret;
switch (ioctl_id) {
@ -892,11 +503,7 @@ enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
ret = PM_RET_SUCCESS;
break;
default:
/* Send request to the PMC */
PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_IOCTL,
device_id, ioctl_id, arg1, arg2);
ret = pm_ipi_send_sync(primary_proc, payload, value, 1);
break;
return PM_RET_ERROR_NOTSUPPORTED;
}
return ret;
@ -922,25 +529,6 @@ enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device,
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* pm_get_chipid() - Read silicon ID registers
* @value Buffer for return values. Must be large enough
* to hold 8 bytes.
* @flag 0 - Call from secure source
* 1 - Call from non-secure source
*
* @return Returns silicon ID registers
*/
enum pm_ret_status pm_get_chipid(uint32_t *value, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, flag, 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
@ -954,71 +542,32 @@ enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
enum pm_ret_status status = PM_RET_ERROR_NOFEATURE;
enum pm_ret_status status;
uint32_t module_id;
module_id = (api_id & MODULE_ID_MASK) >> 8;
/* 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 > 0) && (module_id != LIBPM_MODULE_ID)) {
return PM_RET_SUCCESS;
}
switch (api_id) {
case PM_GET_CALLBACK_DATA:
case PM_GET_TRUSTZONE_VERSION:
case PM_LOAD_PDI:
*version = (PM_API_BASE_VERSION << 16);
status = PM_RET_SUCCESS;
break;
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_GET_CHIPID:
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_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_CLOCK_GETRATE:
case PM_PLL_SET_PARAMETER:
case PM_PLL_GET_PARAMETER:
case PM_PLL_SET_MODE:
case PM_PLL_GET_MODE:
case PM_FEATURE_CHECK:
case PM_INIT_FINALIZE:
case PM_SET_MAX_LATENCY:
case PM_REGISTER_NOTIFIER:
*version = (PM_API_BASE_VERSION << 16);
status = PM_RET_SUCCESS;
break;
return PM_RET_SUCCESS;
case PM_QUERY_DATA:
*version = (PM_API_QUERY_DATA_VERSION << 16);
status = PM_RET_SUCCESS;
break;
default:
*version = 0U;
status = PM_RET_ERROR_NOFEATURE;
*version = (PM_API_BASE_VERSION << 16);
break;
}
if (status != PM_RET_SUCCESS) {
goto done;
}
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
PM_FEATURE_CHECK, api_id);
@ -1059,54 +608,6 @@ enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t 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
* @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_get_op_characteristic(uint32_t device_id,
enum pm_opchar_type type,
uint32_t *result, uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag,
PM_GET_OP_CHARACTERISTIC, device_id, type);
return pm_ipi_send_sync(primary_proc, payload, result, 1);
}
/**
* pm_set_max_latency() - PM call to change in the maximum wake-up latency
* requirements for a specific device currently
* used by that CPU.
* @device_id Device ID
* @latency Latency value
* @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_max_latency(uint32_t device_id, uint32_t latency,
uint32_t flag)
{
uint32_t payload[PAYLOAD_ARG_CNT];
/* Send request to the PMC */
PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_SET_MAX_LATENCY,
device_id, latency);
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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020, Xilinx, Inc. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -14,8 +14,9 @@
* PM API function declarations
**********************************************************/
enum pm_ret_status pm_get_api_version(unsigned int *version, uint32_t flag);
enum pm_ret_status pm_init_finalize(uint32_t flag);
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);
enum pm_ret_status pm_self_suspend(uint32_t nid,
unsigned int latency,
unsigned int state,
@ -29,42 +30,7 @@ enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
uintptr_t address, uint8_t ack, uint32_t flag);
enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
uint8_t enable, uint32_t flag);
enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
uint32_t qos, uint32_t ack, uint32_t flag);
enum pm_ret_status pm_release_device(uint32_t device_id, uint32_t flag);
enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
uint32_t latency, uint32_t qos,
uint32_t flag);
enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response,
uint32_t flag);
enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert, uint32_t flag);
enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status,
uint32_t flag);
void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag);
enum pm_ret_status pm_pinctrl_request(uint32_t pin, uint32_t flag);
enum pm_ret_status pm_pinctrl_release(uint32_t pin, uint32_t flag);
enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function,
uint32_t flag);
enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function,
uint32_t flag);
enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
uint32_t value, uint32_t flag);
enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
uint32_t *value, uint32_t flag);
enum pm_ret_status pm_clock_enable(uint32_t clk_id, uint32_t flag);
enum pm_ret_status pm_clock_disable(uint32_t clk_id, uint32_t flag);
enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state,
uint32_t flag);
enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider,
uint32_t flag);
enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider,
uint32_t flag);
enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent,
uint32_t flag);
enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent,
uint32_t flag);
enum pm_ret_status pm_clock_get_rate(uint32_t clk_id, uint32_t *clk_rate,
uint32_t flag);
enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
uint32_t value, uint32_t flag);
enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
@ -83,16 +49,10 @@ enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
uint32_t arg3, uint32_t *data, uint32_t flag);
unsigned int pm_get_shutdown_scope(void);
enum pm_ret_status pm_get_chipid(uint32_t *value, uint32_t flag);
enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version,
uint32_t flag);
enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
uint32_t address_high, uint32_t flag);
enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
enum pm_opchar_type type,
uint32_t *result, uint32_t flag);
enum pm_ret_status pm_set_max_latency(uint32_t device_id, uint32_t latency,
uint32_t flag);
enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
uint32_t wake, uint32_t enable,
uint32_t flag);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -42,9 +42,6 @@
#define PM_API_QUERY_DATA_VERSION 2U
/* PM API ids */
#define PM_GET_API_VERSION 1U
#define PM_GET_DEVICE_STATUS 3U
#define PM_GET_OP_CHARACTERISTIC 4U
#define PM_REGISTER_NOTIFIER 5U
#define PM_REQ_SUSPEND 6U
#define PM_SELF_SUSPEND 7U
@ -53,31 +50,8 @@
#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_SET_MAX_LATENCY 16U
#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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -114,49 +114,82 @@ int pm_setup(void)
}
/**
* 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
* eemi_for_compatibility() - EEMI calls handler for deprecated calls
*
* @return - Unused
* @return - If EEMI API found then, uintptr_t type address, else 0
*
* 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
* Some EEMI API's use case needs to be changed in Linux driver, so they
* can take advantage of common EEMI handler in TF-A. As of now the old
* implementation of these APIs are required to maintain backward compatibility
* until their use case in linux driver changes.
*/
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)
static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
uint32_t pm_arg[4];
uint32_t security_flag = SECURE_FLAG;
switch (api_id) {
/* Handle case where PM wasn't initialized properly */
if (pm_up == false) {
SMC_RET1(handle, SMC_UNK);
case PM_IOCTL:
{
uint32_t value;
ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], &value, security_flag);
if (ret == PM_RET_ERROR_NOTSUPPORTED)
return (uintptr_t)0;
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
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);
case PM_QUERY_DATA:
{
uint32_t data[PAYLOAD_ARG_CNT] = { 0 };
/*
* Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1)
* if smc called is non secure
*/
if (is_caller_non_secure(flags) != 0) {
security_flag = NON_SECURE_FLAG;
ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], data, security_flag);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32),
(uint64_t)data[1] | ((uint64_t)data[2] << 32));
}
switch (smc_fid & FUNCID_NUM_MASK) {
/* PM API Functions */
case PM_FEATURE_CHECK:
{
uint32_t version;
ret = pm_feature_check(pm_arg[0], &version, security_flag);
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],
security_flag);
SMC_RET1(handle, (uint64_t)ret);
}
default:
return (uintptr_t)0;
}
}
/**
* eemi_psci_debugfs_handler() - EEMI API invoked from PSCI
*
* These EEMI APIs performs CPU specific power management tasks.
* These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
* These calls require CPU specific processing before sending IPI request to
* Platform Management Controller. For example enable/disable CPU specific
* interrupts. This requires separate handler for these calls and may not be
* handled using common eemi handler
*/
static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
switch (api_id) {
case PM_SELF_SUSPEND:
ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], security_flag);
@ -179,65 +212,22 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
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],
security_flag);
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],
security_flag);
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], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_RELEASE_DEVICE:
ret = pm_release_device(pm_arg[0], security_flag);
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], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_API_VERSION:
{
uint32_t api_version;
ret = pm_get_api_version(&api_version, security_flag);
SMC_RET1(handle, (u_register_t)PM_RET_SUCCESS |
((u_register_t)api_version << 32));
default:
return (uintptr_t)0;
}
}
case PM_GET_DEVICE_STATUS:
{
uint32_t buff[3];
ret = pm_get_device_status(pm_arg[0], buff, security_flag);
SMC_RET2(handle, (u_register_t)ret | ((u_register_t)buff[0] << 32),
(u_register_t)buff[1] | ((u_register_t)buff[2] << 32));
}
case PM_RESET_ASSERT:
ret = pm_reset_assert(pm_arg[0], pm_arg[1], security_flag);
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,
security_flag);
SMC_RET1(handle, (u_register_t)ret |
((u_register_t)reset_status << 32));
}
case PM_INIT_FINALIZE:
ret = pm_init_finalize(security_flag);
SMC_RET1(handle, (uint64_t)ret);
/**
* TF_A_specific_handler() - SMC handler for TF-A specific functionality
*
* These EEMI calls performs functionality that does not require
* IPI transaction. The handler ends in TF-A and returns requested data to
* kernel from TF-A
*/
static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
switch (api_id) {
case PM_GET_CALLBACK_DATA:
{
@ -245,192 +235,115 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag);
SMC_RET2(handle,
(u_register_t)result[0] | ((u_register_t)result[1] << 32),
(u_register_t)result[2] | ((u_register_t)result[3] << 32));
}
case PM_PINCTRL_REQUEST:
ret = pm_pinctrl_request(pm_arg[0], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_PINCTRL_RELEASE:
ret = pm_pinctrl_release(pm_arg[0], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_PINCTRL_GET_FUNCTION:
{
uint32_t value = 0;
ret = pm_pinctrl_get_function(pm_arg[0], &value, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_PINCTRL_SET_FUNCTION:
ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1],
security_flag);
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,
security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_PINCTRL_CONFIG_PARAM_SET:
ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2],
security_flag);
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, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_QUERY_DATA:
{
uint32_t data[8] = { 0 };
ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], data, security_flag);
SMC_RET2(handle, (u_register_t)ret | ((u_register_t)data[0] << 32),
(u_register_t)data[1] | ((u_register_t)data[2] << 32));
}
case PM_CLOCK_ENABLE:
ret = pm_clock_enable(pm_arg[0], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_DISABLE:
ret = pm_clock_disable(pm_arg[0], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETSTATE:
{
uint32_t value;
ret = pm_clock_get_state(pm_arg[0], &value, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_CLOCK_SETDIVIDER:
ret = pm_clock_set_divider(pm_arg[0], pm_arg[1], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETDIVIDER:
{
uint32_t value;
ret = pm_clock_get_divider(pm_arg[0], &value, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_CLOCK_SETPARENT:
ret = pm_clock_set_parent(pm_arg[0], pm_arg[1], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_CLOCK_GETPARENT:
{
uint32_t value;
ret = pm_clock_get_parent(pm_arg[0], &value, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
}
case PM_CLOCK_GETRATE:
{
uint32_t rate[2] = { 0 };
ret = pm_clock_get_rate(pm_arg[0], rate, security_flag);
SMC_RET2(handle, (u_register_t)ret | ((u_register_t)rate[0] << 32),
(u_register_t)rate[1] | ((u_register_t)0U << 32));
}
case PM_PLL_SET_PARAMETER:
ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2],
security_flag);
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,
security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value << 32));
}
case PM_PLL_SET_MODE:
ret = pm_pll_set_mode(pm_arg[0], pm_arg[1], security_flag);
SMC_RET1(handle, (uint64_t)ret);
case PM_PLL_GET_MODE:
{
uint32_t mode;
ret = pm_pll_get_mode(pm_arg[0], &mode, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)mode << 32));
(uint64_t)result[0] | ((uint64_t)result[1] << 32),
(uint64_t)result[2] | ((uint64_t)result[3] << 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, security_flag);
SMC_RET2(handle, (u_register_t)ret | ((u_register_t)result[0] << 32),
(u_register_t)result[1] | ((u_register_t)0U << 32));
}
case PM_FEATURE_CHECK:
{
uint32_t version;
ret = pm_feature_check(pm_arg[0], &version, security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)version << 32));
}
case PM_LOAD_PDI:
{
ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2],
security_flag);
SMC_RET1(handle, (u_register_t)ret);
}
case PM_GET_OP_CHARACTERISTIC:
{
uint32_t result;
ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result,
security_flag);
SMC_RET1(handle, (u_register_t)ret | ((u_register_t)result << 32));
}
case PM_SET_MAX_LATENCY:
{
ret = pm_set_max_latency(pm_arg[0], pm_arg[1], security_flag);
SMC_RET1(handle, (u_register_t)ret);
}
case PM_REGISTER_NOTIFIER:
{
ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3], security_flag);
SMC_RET1(handle, (u_register_t)ret);
}
default:
WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
return (uintptr_t)0;
}
}
/**
* eemi_handler() - Prepare EEMI payload and perform IPI transaction
*
* EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol
* to allow communication between power management controller and different
* processing clusters.
*
* This handler prepares EEMI protocol payload received from kernel and performs
* IPI transaction.
*/
static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
uint32_t buf[PAYLOAD_ARG_CNT] = {0};
ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
pm_arg[2], pm_arg[3], pm_arg[4],
(uint64_t *)buf);
/*
* Two IOCTLs, to get clock name and pinctrl name of pm_query_data API
* receives 5 words of respoonse from firmware. Currently linux driver can
* receive only 4 words from TF-A. So, this needs to be handled separately
* than other eemi calls.
*/
if (api_id == PM_QUERY_DATA) {
if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME ||
pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) &&
ret == PM_RET_SUCCESS) {
SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32),
(uint64_t)buf[2] | ((uint64_t)buf[3] << 32));
}
}
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32),
(uint64_t)buf[1] | ((uint64_t)buf[2] << 32));
}
/**
* pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
* @smc_fid - Function Identifier
* @x1 - x4 - SMC64 Arguments from kernel
* x3 and x4 are Unused
* @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)
{
uintptr_t ret;
uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
uint32_t security_flag = SECURE_FLAG;
uint32_t api_id;
/* Handle case where PM wasn't initialized properly */
if (!pm_up)
SMC_RET1(handle, SMC_UNK);
/*
* Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1)
* if smc called is non secure
*/
if (is_caller_non_secure(flags)) {
security_flag = NON_SECURE_FLAG;
}
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);
(void)(x3);
(void)(x4);
api_id = smc_fid & FUNCID_NUM_MASK;
ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag);
if (ret != (uintptr_t)0)
return ret;
ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags);
if (ret != (uintptr_t)0)
return ret;
ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
if (ret != (uintptr_t)0)
return ret;
ret = eemi_handler(api_id, pm_arg, handle, security_flag);
return ret;
}