diff options
Diffstat (limited to 'drivers/firmware/arm_scmi/reset.c')
-rw-r--r-- | drivers/firmware/arm_scmi/reset.c | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index 94baab99e1..98a7dd0afa 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -2,30 +2,29 @@ /* * System Control and Management Interface (SCMI) Reset Protocol * - * Copyright (C) 2019-2021 ARM Ltd. + * Copyright (C) 2019-2022 ARM Ltd. */ -#define pr_fmt(fmt) "SCMI RESET - " fmt +#define pr_fmt(fmt) "SCMI Notifications RESET - " fmt #include <common.h> #include <linux/scmi_protocol.h> -#include "common.h" +#include "protocols.h" enum scmi_reset_protocol_cmd { RESET_DOMAIN_ATTRIBUTES = 0x3, RESET = 0x4, - RESET_NOTIFY = 0x5, + RESET_DOMAIN_NAME_GET = 0x6, }; #define NUM_RESET_DOMAIN_MASK 0xffff struct scmi_msg_resp_reset_domain_attributes { __le32 attributes; -#define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31)) -#define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30)) +#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) __le32 latency; - u8 name[SCMI_MAX_STR_SIZE]; + u8 name[SCMI_SHORT_NAME_MAX_SIZE]; }; struct scmi_msg_reset_domain_reset { @@ -33,13 +32,11 @@ struct scmi_msg_reset_domain_reset { __le32 flags; #define AUTONOMOUS_RESET BIT(0) #define EXPLICIT_RESET_ASSERT BIT(1) -#define ASYNCHRONOUS_RESET BIT(2) __le32 reset_state; #define ARCH_COLD_RESET 0 }; struct reset_dom_info { - bool async_reset; u32 latency_us; char name[SCMI_MAX_STR_SIZE]; }; @@ -74,9 +71,11 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph, static int scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, - u32 domain, struct reset_dom_info *dom_info) + u32 domain, struct reset_dom_info *dom_info, + u32 version) { int ret; + u32 attributes; struct scmi_xfer *t; struct scmi_msg_resp_reset_domain_attributes *attr; @@ -90,16 +89,25 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, ret = ph->xops->do_xfer(ph, t); if (!ret) { - u32 attributes = le32_to_cpu(attr->attributes); + attributes = le32_to_cpu(attr->attributes); - dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes); dom_info->latency_us = le32_to_cpu(attr->latency); if (dom_info->latency_us == U32_MAX) dom_info->latency_us = 0; - strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); } ph->xops->xfer_put(ph, t); + + /* + * If supported overwrite short name with the extended one; + * on error just carry on and use already provided short name. + */ + if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && + SUPPORTS_EXTENDED_NAMES(attributes)) + ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain, + dom_info->name, SCMI_MAX_STR_SIZE); + return ret; } @@ -110,8 +118,8 @@ static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph) return pi->num_domains; } -static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph, - u32 domain) +static const char * +scmi_reset_name_get(const struct scmi_protocol_handle *ph, u32 domain) { struct scmi_reset_info *pi = ph->get_priv(ph); @@ -136,10 +144,12 @@ static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain, struct scmi_xfer *t; struct scmi_msg_reset_domain_reset *dom; struct scmi_reset_info *pi = ph->get_priv(ph); - struct reset_dom_info *rdom = pi->dom_info + domain; + struct reset_dom_info *rdom; - if (rdom->async_reset) - flags |= ASYNCHRONOUS_RESET; + if (domain >= pi->num_domains) + return -EINVAL; + + rdom = pi->dom_info + domain; ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t); if (ret) @@ -150,10 +160,7 @@ static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain, dom->flags = cpu_to_le32(flags); dom->reset_state = cpu_to_le32(state); - if (rdom->async_reset) - ret = ph->xops->do_xfer_with_response(ph, t); - else - ret = ph->xops->do_xfer(ph, t); + ret = ph->xops->do_xfer(ph, t); ph->xops->xfer_put(ph, t); return ret; @@ -190,22 +197,26 @@ static const struct scmi_reset_proto_ops reset_proto_ops = { static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) { - int domain; + int domain, ret; u32 version; struct scmi_reset_info *pinfo; - ph->xops->version_get(ph, &version); + ret = ph->xops->version_get(ph, &version); + if (ret) + return ret; dev_dbg(ph->dev, "Reset Version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; - scmi_reset_attributes_get(ph, pinfo); + ret = scmi_reset_attributes_get(ph, pinfo); + if (ret) + return ret; - pinfo->dom_info = kcalloc(pinfo->num_domains, + pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, sizeof(*pinfo->dom_info), GFP_KERNEL); if (!pinfo->dom_info) return -ENOMEM; @@ -213,7 +224,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) for (domain = 0; domain < pinfo->num_domains; domain++) { struct reset_dom_info *dom = pinfo->dom_info + domain; - scmi_reset_domain_attributes_get(ph, domain, dom); + scmi_reset_domain_attributes_get(ph, domain, dom, version); } pinfo->version = version; |