diff options
Diffstat (limited to 'drivers/firmware/xilinx/zynqmp.c')
-rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 9a1c72a9280f..98f936125643 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -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 @@ -187,6 +194,29 @@ static int zynqmp_pm_get_api_version(u32 *version) } /** + * 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; |