mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
arm64: zynqmp: SoC changes for v5.1
- Extend firmware interface with reset, nvmem, power management and power domain support - Add reset, nvmem driver, power management and power domain drivers - -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlxixLEACgkQykllyylKDCEduwCeLkIFr48uJ/5Fv1X16gitcrOk F38An2wbsk21xkWQpfzCFdUrpPbT0u4t =GOP8 -----END PGP SIGNATURE----- Merge tag 'zynqmp-soc-for-v5.1' of https://github.com/Xilinx/linux-xlnx into arm/drivers arm64: zynqmp: SoC changes for v5.1 - Extend firmware interface with reset, nvmem, power management and power domain support - Add reset, nvmem driver, power management and power domain drivers - * tag 'zynqmp-soc-for-v5.1' of https://github.com/Xilinx/linux-xlnx: drivers: soc: xilinx: Add ZynqMP power domain driver firmware: xilinx: Add APIs to control node status/power dt-bindings: power: Add ZynqMP power domain bindings drivers: soc: xilinx: Add ZynqMP PM driver firmware: xilinx: Implement ZynqMP power management APIs dt-bindings: soc: Add ZynqMP PM bindings nvmem: zynqmp: Added zynqmp nvmem firmware driver dt-bindings: nvmem: Add bindings for ZynqMP nvmem driver firmware: xilinx: Add zynqmp_pm_get_chipid() API reset: reset-zynqmp: Adding support for Xilinx zynqmp reset controller. dt-bindings: reset: Add bindings for ZynqMP reset driver firmware: xilinx: Add reset API's Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
59f527dd7a
@ -0,0 +1,46 @@
|
||||
--------------------------------------------------------------------------
|
||||
= Zynq UltraScale+ MPSoC nvmem firmware driver binding =
|
||||
--------------------------------------------------------------------------
|
||||
The nvmem_firmware node provides access to the hardware related data
|
||||
like soc revision, IDCODE... etc, By using the firmware interface.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "xlnx,zynqmp-nvmem-fw"
|
||||
|
||||
= Data cells =
|
||||
Are child nodes of silicon id, bindings of which as described in
|
||||
bindings/nvmem/nvmem.txt
|
||||
|
||||
-------
|
||||
Example
|
||||
-------
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
method = "smc";
|
||||
|
||||
nvmem_firmware {
|
||||
compatible = "xlnx,zynqmp-nvmem-fw";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* Data cells */
|
||||
soc_revision: soc_revision {
|
||||
reg = <0x0 0x4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
= Data consumers =
|
||||
Are device nodes which consume nvmem data cells.
|
||||
|
||||
For example:
|
||||
pcap {
|
||||
...
|
||||
|
||||
nvmem-cells = <&soc_revision>;
|
||||
nvmem-cell-names = "soc_revision";
|
||||
|
||||
...
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
--------------------------------------------------------------------
|
||||
Device Tree Bindings for the Xilinx Zynq MPSoC Power Management
|
||||
--------------------------------------------------------------------
|
||||
The zynqmp-power node describes the power management configurations.
|
||||
It will control remote suspend/shutdown interfaces.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain: "xlnx,zynqmp-power"
|
||||
- interrupts: Interrupt specifier
|
||||
|
||||
-------
|
||||
Example
|
||||
-------
|
||||
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
method = "smc";
|
||||
|
||||
zynqmp_power: zynqmp-power {
|
||||
compatible = "xlnx,zynqmp-power";
|
||||
interrupts = <0 35 4>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
-----------------------------------------------------------
|
||||
Device Tree Bindings for the Xilinx Zynq MPSoC PM domains
|
||||
-----------------------------------------------------------
|
||||
The binding for zynqmp-power-controller follow the common
|
||||
generic PM domain binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/power/power_domain.txt
|
||||
|
||||
== Zynq MPSoC Generic PM Domain Node ==
|
||||
|
||||
Required property:
|
||||
- Below property should be in zynqmp-firmware node.
|
||||
- #power-domain-cells: Number of cells in a PM domain specifier. Must be 1.
|
||||
|
||||
Power domain ID indexes are mentioned in
|
||||
include/dt-bindings/power/xlnx-zynqmp-power.h.
|
||||
|
||||
-------
|
||||
Example
|
||||
-------
|
||||
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
...
|
||||
#power-domain-cells = <1>;
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
sata {
|
||||
...
|
||||
power-domains = <&zynqmp_firmware 28>;
|
||||
...
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
--------------------------------------------------------------------------
|
||||
= Zynq UltraScale+ MPSoC reset driver binding =
|
||||
--------------------------------------------------------------------------
|
||||
The Zynq UltraScale+ MPSoC has several different resets.
|
||||
|
||||
See Chapter 36 of the Zynq UltraScale+ MPSoC TRM (UG) for more information
|
||||
about zynqmp resets.
|
||||
|
||||
Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
Required Properties:
|
||||
- compatible: "xlnx,zynqmp-reset"
|
||||
- #reset-cells: Specifies the number of cells needed to encode reset
|
||||
line, should be 1
|
||||
|
||||
-------
|
||||
Example
|
||||
-------
|
||||
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
method = "smc";
|
||||
|
||||
zynqmp_reset: reset-controller {
|
||||
compatible = "xlnx,zynqmp-reset";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Specifying reset lines connected to IP modules
|
||||
==============================================
|
||||
|
||||
Device nodes that need access to reset lines should
|
||||
specify them as a reset phandle in their corresponding node as
|
||||
specified in reset.txt.
|
||||
|
||||
For list of all valid reset indicies see
|
||||
<dt-bindings/reset/xlnx-zynqmp-resets.h>
|
||||
|
||||
Example:
|
||||
|
||||
serdes: zynqmp_phy@fd400000 {
|
||||
...
|
||||
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_SATA>;
|
||||
reset-names = "sata_rst";
|
||||
|
||||
...
|
||||
};
|
@ -6,6 +6,7 @@ menu "Zynq MPSoC Firmware Drivers"
|
||||
|
||||
config ZYNQMP_FIRMWARE
|
||||
bool "Enable Xilinx Zynq MPSoC firmware interface"
|
||||
select MFD_CORE
|
||||
help
|
||||
Firmware interface driver is used by different
|
||||
drivers to communicate with the firmware for
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
@ -23,6 +24,12 @@
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include "zynqmp-debug.h"
|
||||
|
||||
static const struct mfd_cell firmware_devs[] = {
|
||||
{
|
||||
.name = "zynqmp_power_controller",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
|
||||
* @ret_status: PMUFW return code
|
||||
@ -186,6 +193,29 @@ static int zynqmp_pm_get_api_version(u32 *version)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_get_chipid - Get silicon ID registers
|
||||
* @idcode: IDCODE register
|
||||
* @version: version register
|
||||
*
|
||||
* Return: Returns the status of the operation and the idcode and version
|
||||
* registers in @idcode and @version.
|
||||
*/
|
||||
static int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
|
||||
{
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
int ret;
|
||||
|
||||
if (!idcode || !version)
|
||||
return -EINVAL;
|
||||
|
||||
ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
|
||||
*idcode = ret_payload[1];
|
||||
*version = ret_payload[2];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
|
||||
* @version: Returned version value
|
||||
@ -469,8 +499,129 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
|
||||
arg1, arg2, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
|
||||
* @reset: Reset to be configured
|
||||
* @assert_flag: Flag stating should reset be asserted (1) or
|
||||
* released (0)
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
|
||||
const enum zynqmp_pm_reset_action assert_flag)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag,
|
||||
0, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_reset_get_status - Get status of the reset
|
||||
* @reset: Reset whose status should be returned
|
||||
* @status: Returned status
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
|
||||
u32 *status)
|
||||
{
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
int ret;
|
||||
|
||||
if (!status)
|
||||
return -EINVAL;
|
||||
|
||||
ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0,
|
||||
0, 0, ret_payload);
|
||||
*status = ret_payload[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
|
||||
* master has initialized its own power management
|
||||
*
|
||||
* This API function is to be used for notify the power management controller
|
||||
* about the completed power management initialization.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_init_finalize(void)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_set_suspend_mode() - Set system suspend mode
|
||||
* @mode: Mode to set for system suspend
|
||||
*
|
||||
* This API function is used to set mode of system suspend.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_set_suspend_mode(u32 mode)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_request_node() - Request a node with specific capabilities
|
||||
* @node: Node ID of the slave
|
||||
* @capabilities: Requested capabilities of the slave
|
||||
* @qos: Quality of service (not supported)
|
||||
* @ack: Flag to specify whether acknowledge is requested
|
||||
*
|
||||
* This function is used by master to request particular node from firmware.
|
||||
* Every master must request node before using it.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
|
||||
const u32 qos,
|
||||
const enum zynqmp_pm_request_ack ack)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities,
|
||||
qos, ack, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_release_node() - Release a node
|
||||
* @node: Node ID of the slave
|
||||
*
|
||||
* This function is used by master to inform firmware that master
|
||||
* has released node. Once released, master must not use that node
|
||||
* without re-request.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_release_node(const u32 node)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves
|
||||
* @node: Node ID of the slave
|
||||
* @capabilities: Requested capabilities of the slave
|
||||
* @qos: Quality of service (not supported)
|
||||
* @ack: Flag to specify whether acknowledge is requested
|
||||
*
|
||||
* This API function is to be used for slaves a PU already has requested
|
||||
* to change its capabilities.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
|
||||
const u32 qos,
|
||||
const enum zynqmp_pm_request_ack ack)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities,
|
||||
qos, ack, NULL);
|
||||
}
|
||||
|
||||
static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
.get_api_version = zynqmp_pm_get_api_version,
|
||||
.get_chipid = zynqmp_pm_get_chipid,
|
||||
.query_data = zynqmp_pm_query_data,
|
||||
.clock_enable = zynqmp_pm_clock_enable,
|
||||
.clock_disable = zynqmp_pm_clock_disable,
|
||||
@ -482,6 +633,13 @@ static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
.clock_setparent = zynqmp_pm_clock_setparent,
|
||||
.clock_getparent = zynqmp_pm_clock_getparent,
|
||||
.ioctl = zynqmp_pm_ioctl,
|
||||
.reset_assert = zynqmp_pm_reset_assert,
|
||||
.reset_get_status = zynqmp_pm_reset_get_status,
|
||||
.init_finalize = zynqmp_pm_init_finalize,
|
||||
.set_suspend_mode = zynqmp_pm_set_suspend_mode,
|
||||
.request_node = zynqmp_pm_request_node,
|
||||
.release_node = zynqmp_pm_release_node,
|
||||
.set_requirement = zynqmp_pm_set_requirement,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -538,11 +696,19 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
||||
|
||||
zynqmp_pm_api_debugfs_init();
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
|
||||
ARRAY_SIZE(firmware_devs), NULL, 0, NULL);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add MFD devices %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
static int zynqmp_firmware_remove(struct platform_device *pdev)
|
||||
{
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
zynqmp_pm_api_debugfs_exit();
|
||||
|
||||
return 0;
|
||||
|
@ -192,4 +192,14 @@ config SC27XX_EFUSE
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called nvmem-sc27xx-efuse.
|
||||
|
||||
config NVMEM_ZYNQMP
|
||||
bool "Xilinx ZYNQMP SoC nvmem firmware support"
|
||||
depends on ARCH_ZYNQMP
|
||||
help
|
||||
This is a driver to access hardware related data like
|
||||
soc revision, IDCODE... etc by using the firmware
|
||||
interface.
|
||||
|
||||
If sure, say yes. If unsure, say no.
|
||||
|
||||
endif
|
||||
|
@ -41,3 +41,5 @@ obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o
|
||||
nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o
|
||||
obj-$(CONFIG_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o
|
||||
nvmem-sc27xx-efuse-y := sc27xx-efuse.o
|
||||
obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o
|
||||
nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o
|
||||
|
86
drivers/nvmem/zynqmp_nvmem.c
Normal file
86
drivers/nvmem/zynqmp_nvmem.c
Normal file
@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
#define SILICON_REVISION_MASK 0xF
|
||||
|
||||
struct zynqmp_nvmem_data {
|
||||
struct device *dev;
|
||||
struct nvmem_device *nvmem;
|
||||
};
|
||||
|
||||
static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
int ret;
|
||||
int idcode, version;
|
||||
struct zynqmp_nvmem_data *priv = context;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_chipid)
|
||||
return -ENXIO;
|
||||
|
||||
ret = eemi_ops->get_chipid(&idcode, &version);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
|
||||
*(int *)val = version & SILICON_REVISION_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nvmem_config econfig = {
|
||||
.name = "zynqmp-nvmem",
|
||||
.owner = THIS_MODULE,
|
||||
.word_size = 1,
|
||||
.size = 1,
|
||||
.read_only = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id zynqmp_nvmem_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-nvmem-fw", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynqmp_nvmem_match);
|
||||
|
||||
static int zynqmp_nvmem_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct zynqmp_nvmem_data *priv;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
econfig.dev = dev;
|
||||
econfig.reg_read = zynqmp_nvmem_read;
|
||||
econfig.priv = priv;
|
||||
|
||||
priv->nvmem = devm_nvmem_register(dev, &econfig);
|
||||
|
||||
return PTR_ERR_OR_ZERO(priv->nvmem);
|
||||
}
|
||||
|
||||
static struct platform_driver zynqmp_nvmem_driver = {
|
||||
.probe = zynqmp_nvmem_probe,
|
||||
.driver = {
|
||||
.name = "zynqmp-nvmem",
|
||||
.of_match_table = zynqmp_nvmem_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(zynqmp_nvmem_driver);
|
||||
|
||||
MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>, Nava kishore Manne <navam@xilinx.com>");
|
||||
MODULE_DESCRIPTION("ZynqMP NVMEM driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -26,4 +26,5 @@ obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
|
||||
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
|
||||
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
|
||||
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
|
||||
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
|
||||
|
||||
|
114
drivers/reset/reset-zynqmp.c
Normal file
114
drivers/reset/reset-zynqmp.c
Normal file
@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2018 Xilinx, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
|
||||
#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
|
||||
|
||||
struct zynqmp_reset_data {
|
||||
struct reset_controller_dev rcdev;
|
||||
const struct zynqmp_eemi_ops *eemi_ops;
|
||||
};
|
||||
|
||||
static inline struct zynqmp_reset_data *
|
||||
to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
|
||||
{
|
||||
return container_of(rcdev, struct zynqmp_reset_data, rcdev);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return priv->eemi_ops->reset_assert(ZYNQMP_RESET_ID + id,
|
||||
PM_RESET_ACTION_ASSERT);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return priv->eemi_ops->reset_assert(ZYNQMP_RESET_ID + id,
|
||||
PM_RESET_ACTION_RELEASE);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
int val, err;
|
||||
|
||||
err = priv->eemi_ops->reset_get_status(ZYNQMP_RESET_ID + id, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return priv->eemi_ops->reset_assert(ZYNQMP_RESET_ID + id,
|
||||
PM_RESET_ACTION_PULSE);
|
||||
}
|
||||
|
||||
static struct reset_control_ops zynqmp_reset_ops = {
|
||||
.reset = zynqmp_reset_reset,
|
||||
.assert = zynqmp_reset_assert,
|
||||
.deassert = zynqmp_reset_deassert,
|
||||
.status = zynqmp_reset_status,
|
||||
};
|
||||
|
||||
static int zynqmp_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct zynqmp_reset_data *priv;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!priv->eemi_ops)
|
||||
return -ENXIO;
|
||||
|
||||
priv->rcdev.ops = &zynqmp_reset_ops;
|
||||
priv->rcdev.owner = THIS_MODULE;
|
||||
priv->rcdev.of_node = pdev->dev.of_node;
|
||||
priv->rcdev.nr_resets = ZYNQMP_NR_RESETS;
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id zynqmp_reset_dt_ids[] = {
|
||||
{ .compatible = "xlnx,zynqmp-reset", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver zynqmp_reset_driver = {
|
||||
.probe = zynqmp_reset_probe,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = zynqmp_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init zynqmp_reset_init(void)
|
||||
{
|
||||
return platform_driver_register(&zynqmp_reset_driver);
|
||||
}
|
||||
|
||||
arch_initcall(zynqmp_reset_init);
|
@ -17,4 +17,24 @@ config XILINX_VCU
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called xlnx_vcu.
|
||||
|
||||
config ZYNQMP_POWER
|
||||
bool "Enable Xilinx Zynq MPSoC Power Management driver"
|
||||
depends on PM && ARCH_ZYNQMP
|
||||
default y
|
||||
help
|
||||
Say yes to enable power management support for ZyqnMP SoC.
|
||||
This driver uses firmware driver as an interface for power
|
||||
management request to firmware. It registers isr to handle
|
||||
power management callbacks from firmware.
|
||||
If in doubt, say N.
|
||||
|
||||
config ZYNQMP_PM_DOMAINS
|
||||
bool "Enable Zynq MPSoC generic PM domains"
|
||||
default y
|
||||
depends on PM && ARCH_ZYNQMP && ZYNQMP_FIRMWARE
|
||||
select PM_GENERIC_DOMAINS
|
||||
help
|
||||
Say yes to enable device power management through PM domains
|
||||
If in doubt, say N.
|
||||
|
||||
endmenu
|
||||
|
@ -1,2 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_XILINX_VCU) += xlnx_vcu.o
|
||||
obj-$(CONFIG_ZYNQMP_POWER) += zynqmp_power.o
|
||||
obj-$(CONFIG_ZYNQMP_PM_DOMAINS) += zynqmp_pm_domains.o
|
||||
|
321
drivers/soc/xilinx/zynqmp_pm_domains.c
Normal file
321
drivers/soc/xilinx/zynqmp_pm_domains.c
Normal file
@ -0,0 +1,321 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ZynqMP Generic PM domain support
|
||||
*
|
||||
* Copyright (C) 2015-2018 Xilinx, Inc.
|
||||
*
|
||||
* Davorin Mista <davorin.mista@aggios.com>
|
||||
* Jolly Shah <jollys@xilinx.com>
|
||||
* Rajan Vaja <rajan.vaja@xilinx.com>
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
#define ZYNQMP_NUM_DOMAINS (100)
|
||||
/* Flag stating if PM nodes mapped to the PM domain has been requested */
|
||||
#define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0)
|
||||
|
||||
/**
|
||||
* struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
|
||||
* @gpd: Generic power domain
|
||||
* @node_id: PM node ID corresponding to device inside PM domain
|
||||
* @flags: ZynqMP PM domain flags
|
||||
*/
|
||||
struct zynqmp_pm_domain {
|
||||
struct generic_pm_domain gpd;
|
||||
u32 node_id;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* zynqmp_gpd_is_active_wakeup_path() - Check if device is in wakeup source
|
||||
* path
|
||||
* @dev: Device to check for wakeup source path
|
||||
* @not_used: Data member (not required)
|
||||
*
|
||||
* This function is checks device's child hierarchy and checks if any device is
|
||||
* set as wakeup source.
|
||||
*
|
||||
* Return: 1 if device is in wakeup source path else 0
|
||||
*/
|
||||
static int zynqmp_gpd_is_active_wakeup_path(struct device *dev, void *not_used)
|
||||
{
|
||||
int may_wakeup;
|
||||
|
||||
may_wakeup = device_may_wakeup(dev);
|
||||
if (may_wakeup)
|
||||
return may_wakeup;
|
||||
|
||||
return device_for_each_child(dev, NULL,
|
||||
zynqmp_gpd_is_active_wakeup_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_gpd_power_on() - Power on PM domain
|
||||
* @domain: Generic PM domain
|
||||
*
|
||||
* This function is called before devices inside a PM domain are resumed, to
|
||||
* power on PM domain.
|
||||
*
|
||||
* Return: 0 on success, error code otherwise
|
||||
*/
|
||||
static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
ret = eemi_ops->set_requirement(pd->node_id,
|
||||
ZYNQMP_PM_CAPABILITY_ACCESS,
|
||||
ZYNQMP_PM_MAX_QOS,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
if (ret) {
|
||||
pr_err("%s() %s set requirement for node %d failed: %d\n",
|
||||
__func__, domain->name, pd->node_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("%s() Powered on %s domain\n", __func__, domain->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_gpd_power_off() - Power off PM domain
|
||||
* @domain: Generic PM domain
|
||||
*
|
||||
* This function is called after devices inside a PM domain are suspended, to
|
||||
* power off PM domain.
|
||||
*
|
||||
* Return: 0 on success, error code otherwise
|
||||
*/
|
||||
static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
int ret;
|
||||
struct pm_domain_data *pdd, *tmp;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
u32 capabilities = 0;
|
||||
bool may_wakeup;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
|
||||
/* If domain is already released there is nothing to be done */
|
||||
if (!(pd->flags & ZYNQMP_PM_DOMAIN_REQUESTED)) {
|
||||
pr_debug("%s() %s domain is already released\n",
|
||||
__func__, domain->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(pdd, tmp, &domain->dev_list, list_node) {
|
||||
/* If device is in wakeup path, set capability to WAKEUP */
|
||||
may_wakeup = zynqmp_gpd_is_active_wakeup_path(pdd->dev, NULL);
|
||||
if (may_wakeup) {
|
||||
dev_dbg(pdd->dev, "device is in wakeup path in %s\n",
|
||||
domain->name);
|
||||
capabilities = ZYNQMP_PM_CAPABILITY_WAKEUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = eemi_ops->set_requirement(pd->node_id, capabilities, 0,
|
||||
ZYNQMP_PM_REQUEST_ACK_NO);
|
||||
/**
|
||||
* If powering down of any node inside this domain fails,
|
||||
* report and return the error
|
||||
*/
|
||||
if (ret) {
|
||||
pr_err("%s() %s set requirement for node %d failed: %d\n",
|
||||
__func__, domain->name, pd->node_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("%s() Powered off %s domain\n", __func__, domain->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_gpd_attach_dev() - Attach device to the PM domain
|
||||
* @domain: Generic PM domain
|
||||
* @dev: Device to attach
|
||||
*
|
||||
* Return: 0 on success, error code otherwise
|
||||
*/
|
||||
static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->request_node)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
|
||||
/* If this is not the first device to attach there is nothing to do */
|
||||
if (domain->device_count)
|
||||
return 0;
|
||||
|
||||
ret = eemi_ops->request_node(pd->node_id, 0, 0,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
/* If requesting a node fails print and return the error */
|
||||
if (ret) {
|
||||
pr_err("%s() %s request failed for node %d: %d\n",
|
||||
__func__, domain->name, pd->node_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pd->flags |= ZYNQMP_PM_DOMAIN_REQUESTED;
|
||||
|
||||
pr_debug("%s() %s attached to %s domain\n", __func__,
|
||||
dev_name(dev), domain->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_gpd_detach_dev() - Detach device from the PM domain
|
||||
* @domain: Generic PM domain
|
||||
* @dev: Device to detach
|
||||
*/
|
||||
static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->release_node)
|
||||
return;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
|
||||
/* If this is not the last device to detach there is nothing to do */
|
||||
if (domain->device_count)
|
||||
return;
|
||||
|
||||
ret = eemi_ops->release_node(pd->node_id);
|
||||
/* If releasing a node fails print the error and return */
|
||||
if (ret) {
|
||||
pr_err("%s() %s release failed for node %d: %d\n",
|
||||
__func__, domain->name, pd->node_id, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
pd->flags &= ~ZYNQMP_PM_DOMAIN_REQUESTED;
|
||||
|
||||
pr_debug("%s() %s detached from %s domain\n", __func__,
|
||||
dev_name(dev), domain->name);
|
||||
}
|
||||
|
||||
static struct generic_pm_domain *zynqmp_gpd_xlate
|
||||
(struct of_phandle_args *genpdspec, void *data)
|
||||
{
|
||||
struct genpd_onecell_data *genpd_data = data;
|
||||
unsigned int i, idx = genpdspec->args[0];
|
||||
struct zynqmp_pm_domain *pd;
|
||||
|
||||
pd = container_of(genpd_data->domains[0], struct zynqmp_pm_domain, gpd);
|
||||
|
||||
if (genpdspec->args_count != 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Check for existing pm domains */
|
||||
for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
|
||||
if (pd[i].node_id == idx)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add index in empty node_id of power domain list as no existing
|
||||
* power domain found for current index.
|
||||
*/
|
||||
for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
|
||||
if (pd[i].node_id == 0) {
|
||||
pd[i].node_id = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (!genpd_data->domains[i] || i == ZYNQMP_NUM_DOMAINS)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return genpd_data->domains[i];
|
||||
}
|
||||
|
||||
static int zynqmp_gpd_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct genpd_onecell_data *zynqmp_pd_data;
|
||||
struct generic_pm_domain **domains;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
zynqmp_pd_data = devm_kzalloc(dev, sizeof(*zynqmp_pd_data), GFP_KERNEL);
|
||||
if (!zynqmp_pd_data)
|
||||
return -ENOMEM;
|
||||
|
||||
zynqmp_pd_data->xlate = zynqmp_gpd_xlate;
|
||||
|
||||
domains = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*domains),
|
||||
GFP_KERNEL);
|
||||
if (!domains)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++, pd++) {
|
||||
pd->node_id = 0;
|
||||
pd->gpd.name = kasprintf(GFP_KERNEL, "domain%d", i);
|
||||
pd->gpd.power_off = zynqmp_gpd_power_off;
|
||||
pd->gpd.power_on = zynqmp_gpd_power_on;
|
||||
pd->gpd.attach_dev = zynqmp_gpd_attach_dev;
|
||||
pd->gpd.detach_dev = zynqmp_gpd_detach_dev;
|
||||
|
||||
domains[i] = &pd->gpd;
|
||||
|
||||
/* Mark all PM domains as initially powered off */
|
||||
pm_genpd_init(&pd->gpd, NULL, true);
|
||||
}
|
||||
|
||||
zynqmp_pd_data->domains = domains;
|
||||
zynqmp_pd_data->num_domains = ZYNQMP_NUM_DOMAINS;
|
||||
of_genpd_add_provider_onecell(dev->parent->of_node, zynqmp_pd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_gpd_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_genpd_del_provider(pdev->dev.parent->of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver zynqmp_power_domain_driver = {
|
||||
.driver = {
|
||||
.name = "zynqmp_power_controller",
|
||||
},
|
||||
.probe = zynqmp_gpd_probe,
|
||||
.remove = zynqmp_gpd_remove,
|
||||
};
|
||||
module_platform_driver(zynqmp_power_domain_driver);
|
||||
|
||||
MODULE_ALIAS("platform:zynqmp_power_controller");
|
178
drivers/soc/xilinx/zynqmp_power.c
Normal file
178
drivers/soc/xilinx/zynqmp_power.c
Normal file
@ -0,0 +1,178 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Xilinx Zynq MPSoC Power Management
|
||||
*
|
||||
* Copyright (C) 2014-2018 Xilinx, Inc.
|
||||
*
|
||||
* Davorin Mista <davorin.mista@aggios.com>
|
||||
* Jolly Shah <jollys@xilinx.com>
|
||||
* Rajan Vaja <rajan.vaja@xilinx.com>
|
||||
*/
|
||||
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
enum pm_suspend_mode {
|
||||
PM_SUSPEND_MODE_FIRST = 0,
|
||||
PM_SUSPEND_MODE_STD = PM_SUSPEND_MODE_FIRST,
|
||||
PM_SUSPEND_MODE_POWER_OFF,
|
||||
};
|
||||
|
||||
#define PM_SUSPEND_MODE_FIRST PM_SUSPEND_MODE_STD
|
||||
|
||||
static const char *const suspend_modes[] = {
|
||||
[PM_SUSPEND_MODE_STD] = "standard",
|
||||
[PM_SUSPEND_MODE_POWER_OFF] = "power-off",
|
||||
};
|
||||
|
||||
static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
|
||||
|
||||
enum pm_api_cb_id {
|
||||
PM_INIT_SUSPEND_CB = 30,
|
||||
PM_ACKNOWLEDGE_CB,
|
||||
PM_NOTIFY_CB,
|
||||
};
|
||||
|
||||
static void zynqmp_pm_get_callback_data(u32 *buf)
|
||||
{
|
||||
zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
|
||||
}
|
||||
|
||||
static irqreturn_t zynqmp_pm_isr(int irq, void *data)
|
||||
{
|
||||
u32 payload[CB_PAYLOAD_SIZE];
|
||||
|
||||
zynqmp_pm_get_callback_data(payload);
|
||||
|
||||
/* First element is callback API ID, others are callback arguments */
|
||||
if (payload[0] == PM_INIT_SUSPEND_CB) {
|
||||
switch (payload[1]) {
|
||||
case SUSPEND_SYSTEM_SHUTDOWN:
|
||||
orderly_poweroff(true);
|
||||
break;
|
||||
case SUSPEND_POWER_REQUEST:
|
||||
pm_suspend(PM_SUSPEND_MEM);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s Unsupported InitSuspendCb reason "
|
||||
"code %d\n", __func__, payload[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static ssize_t suspend_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
char *s = buf;
|
||||
int md;
|
||||
|
||||
for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
|
||||
if (suspend_modes[md]) {
|
||||
if (md == suspend_mode)
|
||||
s += sprintf(s, "[%s] ", suspend_modes[md]);
|
||||
else
|
||||
s += sprintf(s, "%s ", suspend_modes[md]);
|
||||
}
|
||||
|
||||
/* Convert last space to newline */
|
||||
if (s != buf)
|
||||
*(s - 1) = '\n';
|
||||
return (s - buf);
|
||||
}
|
||||
|
||||
static ssize_t suspend_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int md, ret = -EINVAL;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_suspend_mode)
|
||||
return ret;
|
||||
|
||||
for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
|
||||
if (suspend_modes[md] &&
|
||||
sysfs_streq(suspend_modes[md], buf)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret && md != suspend_mode) {
|
||||
ret = eemi_ops->set_suspend_mode(md);
|
||||
if (likely(!ret))
|
||||
suspend_mode = md;
|
||||
}
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(suspend_mode);
|
||||
|
||||
static int zynqmp_pm_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, irq;
|
||||
u32 pm_api_version;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize)
|
||||
return -ENXIO;
|
||||
|
||||
eemi_ops->init_finalize();
|
||||
eemi_ops->get_api_version(&pm_api_version);
|
||||
|
||||
/* Check PM API version number */
|
||||
if (pm_api_version < ZYNQMP_PM_VERSION)
|
||||
return -ENODEV;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0)
|
||||
return -ENXIO;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, zynqmp_pm_isr,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), &pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "devm_request_threaded_irq '%d' failed "
|
||||
"with %d\n", irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to create sysfs interface\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_pm_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pm_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-power", },
|
||||
{ /* end of table */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm_of_match);
|
||||
|
||||
static struct platform_driver zynqmp_pm_platform_driver = {
|
||||
.probe = zynqmp_pm_probe,
|
||||
.remove = zynqmp_pm_remove,
|
||||
.driver = {
|
||||
.name = "zynqmp_power",
|
||||
.of_match_table = pm_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(zynqmp_pm_platform_driver);
|
39
include/dt-bindings/power/xlnx-zynqmp-power.h
Normal file
39
include/dt-bindings/power/xlnx-zynqmp-power.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_ZYNQMP_POWER_H
|
||||
#define _DT_BINDINGS_ZYNQMP_POWER_H
|
||||
|
||||
#define PD_USB_0 22
|
||||
#define PD_USB_1 23
|
||||
#define PD_TTC_0 24
|
||||
#define PD_TTC_1 25
|
||||
#define PD_TTC_2 26
|
||||
#define PD_TTC_3 27
|
||||
#define PD_SATA 28
|
||||
#define PD_ETH_0 29
|
||||
#define PD_ETH_1 30
|
||||
#define PD_ETH_2 31
|
||||
#define PD_ETH_3 32
|
||||
#define PD_UART_0 33
|
||||
#define PD_UART_1 34
|
||||
#define PD_SPI_0 35
|
||||
#define PD_SPI_1 36
|
||||
#define PD_I2C_0 37
|
||||
#define PD_I2C_1 38
|
||||
#define PD_SD_0 39
|
||||
#define PD_SD_1 40
|
||||
#define PD_DP 41
|
||||
#define PD_GDMA 42
|
||||
#define PD_ADMA 43
|
||||
#define PD_NAND 44
|
||||
#define PD_QSPI 45
|
||||
#define PD_GPIO 46
|
||||
#define PD_CAN_0 47
|
||||
#define PD_CAN_1 48
|
||||
#define PD_GPU 58
|
||||
#define PD_PCIE 59
|
||||
|
||||
#endif
|
130
include/dt-bindings/reset/xlnx-zynqmp-resets.h
Normal file
130
include/dt-bindings/reset/xlnx-zynqmp-resets.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_ZYNQMP_RESETS_H
|
||||
#define _DT_BINDINGS_ZYNQMP_RESETS_H
|
||||
|
||||
#define ZYNQMP_RESET_PCIE_CFG 0
|
||||
#define ZYNQMP_RESET_PCIE_BRIDGE 1
|
||||
#define ZYNQMP_RESET_PCIE_CTRL 2
|
||||
#define ZYNQMP_RESET_DP 3
|
||||
#define ZYNQMP_RESET_SWDT_CRF 4
|
||||
#define ZYNQMP_RESET_AFI_FM5 5
|
||||
#define ZYNQMP_RESET_AFI_FM4 6
|
||||
#define ZYNQMP_RESET_AFI_FM3 7
|
||||
#define ZYNQMP_RESET_AFI_FM2 8
|
||||
#define ZYNQMP_RESET_AFI_FM1 9
|
||||
#define ZYNQMP_RESET_AFI_FM0 10
|
||||
#define ZYNQMP_RESET_GDMA 11
|
||||
#define ZYNQMP_RESET_GPU_PP1 12
|
||||
#define ZYNQMP_RESET_GPU_PP0 13
|
||||
#define ZYNQMP_RESET_GPU 14
|
||||
#define ZYNQMP_RESET_GT 15
|
||||
#define ZYNQMP_RESET_SATA 16
|
||||
#define ZYNQMP_RESET_ACPU3_PWRON 17
|
||||
#define ZYNQMP_RESET_ACPU2_PWRON 18
|
||||
#define ZYNQMP_RESET_ACPU1_PWRON 19
|
||||
#define ZYNQMP_RESET_ACPU0_PWRON 20
|
||||
#define ZYNQMP_RESET_APU_L2 21
|
||||
#define ZYNQMP_RESET_ACPU3 22
|
||||
#define ZYNQMP_RESET_ACPU2 23
|
||||
#define ZYNQMP_RESET_ACPU1 24
|
||||
#define ZYNQMP_RESET_ACPU0 25
|
||||
#define ZYNQMP_RESET_DDR 26
|
||||
#define ZYNQMP_RESET_APM_FPD 27
|
||||
#define ZYNQMP_RESET_SOFT 28
|
||||
#define ZYNQMP_RESET_GEM0 29
|
||||
#define ZYNQMP_RESET_GEM1 30
|
||||
#define ZYNQMP_RESET_GEM2 31
|
||||
#define ZYNQMP_RESET_GEM3 32
|
||||
#define ZYNQMP_RESET_QSPI 33
|
||||
#define ZYNQMP_RESET_UART0 34
|
||||
#define ZYNQMP_RESET_UART1 35
|
||||
#define ZYNQMP_RESET_SPI0 36
|
||||
#define ZYNQMP_RESET_SPI1 37
|
||||
#define ZYNQMP_RESET_SDIO0 38
|
||||
#define ZYNQMP_RESET_SDIO1 39
|
||||
#define ZYNQMP_RESET_CAN0 40
|
||||
#define ZYNQMP_RESET_CAN1 41
|
||||
#define ZYNQMP_RESET_I2C0 42
|
||||
#define ZYNQMP_RESET_I2C1 43
|
||||
#define ZYNQMP_RESET_TTC0 44
|
||||
#define ZYNQMP_RESET_TTC1 45
|
||||
#define ZYNQMP_RESET_TTC2 46
|
||||
#define ZYNQMP_RESET_TTC3 47
|
||||
#define ZYNQMP_RESET_SWDT_CRL 48
|
||||
#define ZYNQMP_RESET_NAND 49
|
||||
#define ZYNQMP_RESET_ADMA 50
|
||||
#define ZYNQMP_RESET_GPIO 51
|
||||
#define ZYNQMP_RESET_IOU_CC 52
|
||||
#define ZYNQMP_RESET_TIMESTAMP 53
|
||||
#define ZYNQMP_RESET_RPU_R50 54
|
||||
#define ZYNQMP_RESET_RPU_R51 55
|
||||
#define ZYNQMP_RESET_RPU_AMBA 56
|
||||
#define ZYNQMP_RESET_OCM 57
|
||||
#define ZYNQMP_RESET_RPU_PGE 58
|
||||
#define ZYNQMP_RESET_USB0_CORERESET 59
|
||||
#define ZYNQMP_RESET_USB1_CORERESET 60
|
||||
#define ZYNQMP_RESET_USB0_HIBERRESET 61
|
||||
#define ZYNQMP_RESET_USB1_HIBERRESET 62
|
||||
#define ZYNQMP_RESET_USB0_APB 63
|
||||
#define ZYNQMP_RESET_USB1_APB 64
|
||||
#define ZYNQMP_RESET_IPI 65
|
||||
#define ZYNQMP_RESET_APM_LPD 66
|
||||
#define ZYNQMP_RESET_RTC 67
|
||||
#define ZYNQMP_RESET_SYSMON 68
|
||||
#define ZYNQMP_RESET_AFI_FM6 69
|
||||
#define ZYNQMP_RESET_LPD_SWDT 70
|
||||
#define ZYNQMP_RESET_FPD 71
|
||||
#define ZYNQMP_RESET_RPU_DBG1 72
|
||||
#define ZYNQMP_RESET_RPU_DBG0 73
|
||||
#define ZYNQMP_RESET_DBG_LPD 74
|
||||
#define ZYNQMP_RESET_DBG_FPD 75
|
||||
#define ZYNQMP_RESET_APLL 76
|
||||
#define ZYNQMP_RESET_DPLL 77
|
||||
#define ZYNQMP_RESET_VPLL 78
|
||||
#define ZYNQMP_RESET_IOPLL 79
|
||||
#define ZYNQMP_RESET_RPLL 80
|
||||
#define ZYNQMP_RESET_GPO3_PL_0 81
|
||||
#define ZYNQMP_RESET_GPO3_PL_1 82
|
||||
#define ZYNQMP_RESET_GPO3_PL_2 83
|
||||
#define ZYNQMP_RESET_GPO3_PL_3 84
|
||||
#define ZYNQMP_RESET_GPO3_PL_4 85
|
||||
#define ZYNQMP_RESET_GPO3_PL_5 86
|
||||
#define ZYNQMP_RESET_GPO3_PL_6 87
|
||||
#define ZYNQMP_RESET_GPO3_PL_7 88
|
||||
#define ZYNQMP_RESET_GPO3_PL_8 89
|
||||
#define ZYNQMP_RESET_GPO3_PL_9 90
|
||||
#define ZYNQMP_RESET_GPO3_PL_10 91
|
||||
#define ZYNQMP_RESET_GPO3_PL_11 92
|
||||
#define ZYNQMP_RESET_GPO3_PL_12 93
|
||||
#define ZYNQMP_RESET_GPO3_PL_13 94
|
||||
#define ZYNQMP_RESET_GPO3_PL_14 95
|
||||
#define ZYNQMP_RESET_GPO3_PL_15 96
|
||||
#define ZYNQMP_RESET_GPO3_PL_16 97
|
||||
#define ZYNQMP_RESET_GPO3_PL_17 98
|
||||
#define ZYNQMP_RESET_GPO3_PL_18 99
|
||||
#define ZYNQMP_RESET_GPO3_PL_19 100
|
||||
#define ZYNQMP_RESET_GPO3_PL_20 101
|
||||
#define ZYNQMP_RESET_GPO3_PL_21 102
|
||||
#define ZYNQMP_RESET_GPO3_PL_22 103
|
||||
#define ZYNQMP_RESET_GPO3_PL_23 104
|
||||
#define ZYNQMP_RESET_GPO3_PL_24 105
|
||||
#define ZYNQMP_RESET_GPO3_PL_25 106
|
||||
#define ZYNQMP_RESET_GPO3_PL_26 107
|
||||
#define ZYNQMP_RESET_GPO3_PL_27 108
|
||||
#define ZYNQMP_RESET_GPO3_PL_28 109
|
||||
#define ZYNQMP_RESET_GPO3_PL_29 110
|
||||
#define ZYNQMP_RESET_GPO3_PL_30 111
|
||||
#define ZYNQMP_RESET_GPO3_PL_31 112
|
||||
#define ZYNQMP_RESET_RPU_LS 113
|
||||
#define ZYNQMP_RESET_PS_ONLY 114
|
||||
#define ZYNQMP_RESET_PL 115
|
||||
#define ZYNQMP_RESET_PS_PL0 116
|
||||
#define ZYNQMP_RESET_PS_PL1 117
|
||||
#define ZYNQMP_RESET_PS_PL2 118
|
||||
#define ZYNQMP_RESET_PS_PL3 119
|
||||
|
||||
#endif
|
@ -28,12 +28,35 @@
|
||||
/* SMC SIP service Call Function Identifier Prefix */
|
||||
#define PM_SIP_SVC 0xC2000000
|
||||
#define PM_GET_TRUSTZONE_VERSION 0xa03
|
||||
#define PM_SET_SUSPEND_MODE 0xa02
|
||||
#define GET_CALLBACK_DATA 0xa01
|
||||
|
||||
/* Number of 32bits values in payload */
|
||||
#define PAYLOAD_ARG_CNT 4U
|
||||
|
||||
/* Number of arguments for a callback */
|
||||
#define CB_ARG_CNT 4
|
||||
|
||||
/* Payload size (consists of callback API ID + arguments) */
|
||||
#define CB_PAYLOAD_SIZE (CB_ARG_CNT + 1)
|
||||
|
||||
#define ZYNQMP_PM_MAX_QOS 100U
|
||||
|
||||
/* Node capabilities */
|
||||
#define ZYNQMP_PM_CAPABILITY_ACCESS 0x1U
|
||||
#define ZYNQMP_PM_CAPABILITY_CONTEXT 0x2U
|
||||
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
|
||||
#define ZYNQMP_PM_CAPABILITY_POWER 0x8U
|
||||
|
||||
enum pm_api_id {
|
||||
PM_GET_API_VERSION = 1,
|
||||
PM_REQUEST_NODE = 13,
|
||||
PM_RELEASE_NODE,
|
||||
PM_SET_REQUIREMENT,
|
||||
PM_RESET_ASSERT = 17,
|
||||
PM_RESET_GET_STATUS,
|
||||
PM_PM_INIT_FINALIZE = 21,
|
||||
PM_GET_CHIPID = 24,
|
||||
PM_IOCTL = 34,
|
||||
PM_QUERY_DATA,
|
||||
PM_CLOCK_ENABLE,
|
||||
@ -75,6 +98,149 @@ enum pm_query_id {
|
||||
PM_QID_CLOCK_GET_NUM_CLOCKS = 12,
|
||||
};
|
||||
|
||||
enum zynqmp_pm_reset_action {
|
||||
PM_RESET_ACTION_RELEASE,
|
||||
PM_RESET_ACTION_ASSERT,
|
||||
PM_RESET_ACTION_PULSE,
|
||||
};
|
||||
|
||||
enum zynqmp_pm_reset {
|
||||
ZYNQMP_PM_RESET_START = 1000,
|
||||
ZYNQMP_PM_RESET_PCIE_CFG = ZYNQMP_PM_RESET_START,
|
||||
ZYNQMP_PM_RESET_PCIE_BRIDGE,
|
||||
ZYNQMP_PM_RESET_PCIE_CTRL,
|
||||
ZYNQMP_PM_RESET_DP,
|
||||
ZYNQMP_PM_RESET_SWDT_CRF,
|
||||
ZYNQMP_PM_RESET_AFI_FM5,
|
||||
ZYNQMP_PM_RESET_AFI_FM4,
|
||||
ZYNQMP_PM_RESET_AFI_FM3,
|
||||
ZYNQMP_PM_RESET_AFI_FM2,
|
||||
ZYNQMP_PM_RESET_AFI_FM1,
|
||||
ZYNQMP_PM_RESET_AFI_FM0,
|
||||
ZYNQMP_PM_RESET_GDMA,
|
||||
ZYNQMP_PM_RESET_GPU_PP1,
|
||||
ZYNQMP_PM_RESET_GPU_PP0,
|
||||
ZYNQMP_PM_RESET_GPU,
|
||||
ZYNQMP_PM_RESET_GT,
|
||||
ZYNQMP_PM_RESET_SATA,
|
||||
ZYNQMP_PM_RESET_ACPU3_PWRON,
|
||||
ZYNQMP_PM_RESET_ACPU2_PWRON,
|
||||
ZYNQMP_PM_RESET_ACPU1_PWRON,
|
||||
ZYNQMP_PM_RESET_ACPU0_PWRON,
|
||||
ZYNQMP_PM_RESET_APU_L2,
|
||||
ZYNQMP_PM_RESET_ACPU3,
|
||||
ZYNQMP_PM_RESET_ACPU2,
|
||||
ZYNQMP_PM_RESET_ACPU1,
|
||||
ZYNQMP_PM_RESET_ACPU0,
|
||||
ZYNQMP_PM_RESET_DDR,
|
||||
ZYNQMP_PM_RESET_APM_FPD,
|
||||
ZYNQMP_PM_RESET_SOFT,
|
||||
ZYNQMP_PM_RESET_GEM0,
|
||||
ZYNQMP_PM_RESET_GEM1,
|
||||
ZYNQMP_PM_RESET_GEM2,
|
||||
ZYNQMP_PM_RESET_GEM3,
|
||||
ZYNQMP_PM_RESET_QSPI,
|
||||
ZYNQMP_PM_RESET_UART0,
|
||||
ZYNQMP_PM_RESET_UART1,
|
||||
ZYNQMP_PM_RESET_SPI0,
|
||||
ZYNQMP_PM_RESET_SPI1,
|
||||
ZYNQMP_PM_RESET_SDIO0,
|
||||
ZYNQMP_PM_RESET_SDIO1,
|
||||
ZYNQMP_PM_RESET_CAN0,
|
||||
ZYNQMP_PM_RESET_CAN1,
|
||||
ZYNQMP_PM_RESET_I2C0,
|
||||
ZYNQMP_PM_RESET_I2C1,
|
||||
ZYNQMP_PM_RESET_TTC0,
|
||||
ZYNQMP_PM_RESET_TTC1,
|
||||
ZYNQMP_PM_RESET_TTC2,
|
||||
ZYNQMP_PM_RESET_TTC3,
|
||||
ZYNQMP_PM_RESET_SWDT_CRL,
|
||||
ZYNQMP_PM_RESET_NAND,
|
||||
ZYNQMP_PM_RESET_ADMA,
|
||||
ZYNQMP_PM_RESET_GPIO,
|
||||
ZYNQMP_PM_RESET_IOU_CC,
|
||||
ZYNQMP_PM_RESET_TIMESTAMP,
|
||||
ZYNQMP_PM_RESET_RPU_R50,
|
||||
ZYNQMP_PM_RESET_RPU_R51,
|
||||
ZYNQMP_PM_RESET_RPU_AMBA,
|
||||
ZYNQMP_PM_RESET_OCM,
|
||||
ZYNQMP_PM_RESET_RPU_PGE,
|
||||
ZYNQMP_PM_RESET_USB0_CORERESET,
|
||||
ZYNQMP_PM_RESET_USB1_CORERESET,
|
||||
ZYNQMP_PM_RESET_USB0_HIBERRESET,
|
||||
ZYNQMP_PM_RESET_USB1_HIBERRESET,
|
||||
ZYNQMP_PM_RESET_USB0_APB,
|
||||
ZYNQMP_PM_RESET_USB1_APB,
|
||||
ZYNQMP_PM_RESET_IPI,
|
||||
ZYNQMP_PM_RESET_APM_LPD,
|
||||
ZYNQMP_PM_RESET_RTC,
|
||||
ZYNQMP_PM_RESET_SYSMON,
|
||||
ZYNQMP_PM_RESET_AFI_FM6,
|
||||
ZYNQMP_PM_RESET_LPD_SWDT,
|
||||
ZYNQMP_PM_RESET_FPD,
|
||||
ZYNQMP_PM_RESET_RPU_DBG1,
|
||||
ZYNQMP_PM_RESET_RPU_DBG0,
|
||||
ZYNQMP_PM_RESET_DBG_LPD,
|
||||
ZYNQMP_PM_RESET_DBG_FPD,
|
||||
ZYNQMP_PM_RESET_APLL,
|
||||
ZYNQMP_PM_RESET_DPLL,
|
||||
ZYNQMP_PM_RESET_VPLL,
|
||||
ZYNQMP_PM_RESET_IOPLL,
|
||||
ZYNQMP_PM_RESET_RPLL,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_0,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_1,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_2,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_3,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_4,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_5,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_6,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_7,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_8,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_9,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_10,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_11,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_12,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_13,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_14,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_15,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_16,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_17,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_18,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_19,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_20,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_21,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_22,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_23,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_24,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_25,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_26,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_27,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_28,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_29,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_30,
|
||||
ZYNQMP_PM_RESET_GPO3_PL_31,
|
||||
ZYNQMP_PM_RESET_RPU_LS,
|
||||
ZYNQMP_PM_RESET_PS_ONLY,
|
||||
ZYNQMP_PM_RESET_PL,
|
||||
ZYNQMP_PM_RESET_PS_PL0,
|
||||
ZYNQMP_PM_RESET_PS_PL1,
|
||||
ZYNQMP_PM_RESET_PS_PL2,
|
||||
ZYNQMP_PM_RESET_PS_PL3,
|
||||
ZYNQMP_PM_RESET_END = ZYNQMP_PM_RESET_PS_PL3
|
||||
};
|
||||
|
||||
enum zynqmp_pm_suspend_reason {
|
||||
SUSPEND_POWER_REQUEST = 201,
|
||||
SUSPEND_ALERT,
|
||||
SUSPEND_SYSTEM_SHUTDOWN,
|
||||
};
|
||||
|
||||
enum zynqmp_pm_request_ack {
|
||||
ZYNQMP_PM_REQUEST_ACK_NO = 1,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING,
|
||||
ZYNQMP_PM_REQUEST_ACK_NON_BLOCKING,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zynqmp_pm_query_data - PM query data
|
||||
* @qid: query ID
|
||||
@ -91,6 +257,7 @@ struct zynqmp_pm_query_data {
|
||||
|
||||
struct zynqmp_eemi_ops {
|
||||
int (*get_api_version)(u32 *version);
|
||||
int (*get_chipid)(u32 *idcode, u32 *version);
|
||||
int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
|
||||
int (*clock_enable)(u32 clock_id);
|
||||
int (*clock_disable)(u32 clock_id);
|
||||
@ -102,8 +269,25 @@ struct zynqmp_eemi_ops {
|
||||
int (*clock_setparent)(u32 clock_id, u32 parent_id);
|
||||
int (*clock_getparent)(u32 clock_id, u32 *parent_id);
|
||||
int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out);
|
||||
int (*reset_assert)(const enum zynqmp_pm_reset reset,
|
||||
const enum zynqmp_pm_reset_action assert_flag);
|
||||
int (*reset_get_status)(const enum zynqmp_pm_reset reset, u32 *status);
|
||||
int (*init_finalize)(void);
|
||||
int (*set_suspend_mode)(u32 mode);
|
||||
int (*request_node)(const u32 node,
|
||||
const u32 capabilities,
|
||||
const u32 qos,
|
||||
const enum zynqmp_pm_request_ack ack);
|
||||
int (*release_node)(const u32 node);
|
||||
int (*set_requirement)(const u32 node,
|
||||
const u32 capabilities,
|
||||
const u32 qos,
|
||||
const enum zynqmp_pm_request_ack ack);
|
||||
};
|
||||
|
||||
int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
|
||||
u32 arg2, u32 arg3, u32 *ret_payload);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_ARCH_ZYNQMP)
|
||||
const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user