| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (C) 2019-2022 Linaro Limited |
| */ |
| |
| #define LOG_CATEGORY UCLASS_RESET |
| |
| #include <common.h> |
| #include <dm.h> |
| #include <errno.h> |
| #include <reset-uclass.h> |
| #include <scmi_agent.h> |
| #include <scmi_protocols.h> |
| #include <asm/types.h> |
| |
| /** |
| * struct scmi_reset_priv - Private data for SCMI reset controller |
| * @channel: Reference to the SCMI channel to use |
| */ |
| struct scmi_reset_priv { |
| struct scmi_channel *channel; |
| }; |
| |
| static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) |
| { |
| struct scmi_reset_priv *priv = dev_get_priv(rst->dev); |
| struct scmi_rd_reset_in in = { |
| .domain_id = rst->id, |
| .flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0, |
| .reset_state = 0, |
| }; |
| struct scmi_rd_reset_out out; |
| struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN, |
| SCMI_RESET_DOMAIN_RESET, |
| in, out); |
| int ret; |
| |
| ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg); |
| if (ret) |
| return ret; |
| |
| return scmi_to_linux_errno(out.status); |
| } |
| |
| static int scmi_reset_assert(struct reset_ctl *rst) |
| { |
| return scmi_reset_set_level(rst, true); |
| } |
| |
| static int scmi_reset_deassert(struct reset_ctl *rst) |
| { |
| return scmi_reset_set_level(rst, false); |
| } |
| |
| static int scmi_reset_request(struct reset_ctl *rst) |
| { |
| struct scmi_reset_priv *priv = dev_get_priv(rst->dev); |
| struct scmi_rd_attr_in in = { |
| .domain_id = rst->id, |
| }; |
| struct scmi_rd_attr_out out; |
| struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN, |
| SCMI_RESET_DOMAIN_ATTRIBUTES, |
| in, out); |
| int ret; |
| |
| /* |
| * We don't really care about the attribute, just check |
| * the reset domain exists. |
| */ |
| ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg); |
| if (ret) |
| return ret; |
| |
| return scmi_to_linux_errno(out.status); |
| } |
| |
| static const struct reset_ops scmi_reset_domain_ops = { |
| .request = scmi_reset_request, |
| .rst_assert = scmi_reset_assert, |
| .rst_deassert = scmi_reset_deassert, |
| }; |
| |
| static int scmi_reset_probe(struct udevice *dev) |
| { |
| struct scmi_reset_priv *priv = dev_get_priv(dev); |
| |
| return devm_scmi_of_get_channel(dev, &priv->channel); |
| } |
| |
| U_BOOT_DRIVER(scmi_reset_domain) = { |
| .name = "scmi_reset_domain", |
| .id = UCLASS_RESET, |
| .ops = &scmi_reset_domain_ops, |
| .probe = scmi_reset_probe, |
| .priv_auto = sizeof(struct scmi_reset_priv *), |
| }; |