From 0ddcc08a28053c7969180857d350331bf40f12f6 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 7 Aug 2024 09:47:02 +0300 Subject: [PATCH] drivers: reset: arm_scmi: add shell interface Add ARM SCMI Reset shell interface for demo and testing purposes, which is defined as sub-command of *arm_scmi* command. It's optional and can be enabled by CONFIG_ARM_SCMI_RESET_SHELL option. The ARM SCMI Reset shell interface defined as following: $arm_scmi reset reset - SCMI Reset proto commands. Subcommands: revision : SCMI Reset proto show revision information Usage: arm_scmi reset revision list : SCMI Reset domains list Usage: arm_scmi reset list info : SCMI Reset domain show info Usage: arm_scmi reset info assert : SCMI Reset domain assert Usage: arm_scmi reset assert deassert : SCMI Reset domain de-assert Usage: arm_scmi reset deassert autoreset : SCMI Reset domain Autonomous reset Usage: arm_scmi reset autoreset Signed-off-by: Grygorii Strashko --- drivers/reset/Kconfig.arm_scmi | 7 ++ drivers/reset/reset_arm_scmi.c | 174 +++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) diff --git a/drivers/reset/Kconfig.arm_scmi b/drivers/reset/Kconfig.arm_scmi index 80e4b6a09a9f961..bc6d2199f4e25a7 100644 --- a/drivers/reset/Kconfig.arm_scmi +++ b/drivers/reset/Kconfig.arm_scmi @@ -7,3 +7,10 @@ config ARM_SCMI_RESET default y help Enable ARM SCMI reset driver based on Reset domain management protocol. + +config ARM_SCMI_RESET_SHELL + bool "ARM SCMI reset shell interface" + depends on ARM_SCMI_SHELL + default y + help + Enable ARM SCMI reset shell interface used for testing/demo purposes. \ No newline at end of file diff --git a/drivers/reset/reset_arm_scmi.c b/drivers/reset/reset_arm_scmi.c index 456f3fb4732e952..f09b5fe2f309cbf 100644 --- a/drivers/reset/reset_arm_scmi.c +++ b/drivers/reset/reset_arm_scmi.c @@ -86,6 +86,30 @@ static int scmi_reset_proto_attr_get(const struct device *scmi_dev, uint16_t *nu return 0; } +#if defined(CONFIG_ARM_SCMI_RESET_SHELL) +static int scmi_reset_domain_attr_get(const struct device *scmi_dev, uint32_t id, + struct scmi_msg_reset_domain_attr_resp *dom_attr) +{ + struct scmi_msg_reset_domain_attr_req dom_attr_req = {0}; + int ret; + + dom_attr_req.domain_id = sys_cpu_to_le32(id); + + ret = scmi_xfer(scmi_dev, SCMI_PROTOCOL_RESET, SCMI_RESET_DOMAIN_ATTRIBUTES, + (uint8_t *)&dom_attr_req, sizeof(struct scmi_msg_reset_domain_attr_req), + (uint8_t *)dom_attr, sizeof(struct scmi_msg_reset_domain_attr_resp)); + if (ret) { + LOG_ERR("reset domain get attributes failed (%d)", ret); + return ret; + } + + dom_attr->attr = sys_le32_to_cpu(dom_attr->attr); + dom_attr->latency = sys_le32_to_cpu(dom_attr->latency); + + return 0; +} +#endif /* CONFIG_ARM_SCMI_RESET_SHELL */ + static int scmi_reset_line_assert(const struct device *dev, uint32_t id) { const struct scmi_reset_config *cfg = dev->config; @@ -191,3 +215,153 @@ static const struct scmi_reset_config scmi_reset_config = { DEVICE_DT_INST_DEFINE(0, scmi_reset_init, NULL, &scmi_reset_data, &scmi_reset_config, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &scmi_reset_driver_api); +#if defined(CONFIG_ARM_SCMI_RESET_SHELL) +#include + +#if defined(CONFIG_DT_HAS_ARM_SCMI_RESET_ENABLED) +static const struct device *reset_dev = DEVICE_DT_GET_ANY(DT_DRV_COMPAT); +#else +BUILD_ASSERT(1, "unsupported scmi reset interface"); +#endif + +static int scmi_shell_reset_revision(const struct shell *sh, size_t argc, char **argv) +{ + struct scmi_reset_data *data = reset_dev->data; + + shell_print(sh, "ARM SCMI Reset protocol version 0x%04x.%04x num_domains:%u", + data->version.ver.major, data->version.ver.minor, data->num_domains); + + return 0; +} + +static int scmi_shell_reset_dom_list(const struct shell *sh, size_t argc, char **argv) +{ + const struct scmi_reset_config *cfg = reset_dev->config; + struct scmi_msg_reset_domain_attr_resp dom_attr = {0}; + struct scmi_reset_data *data = reset_dev->data; + uint16_t i; + int ret; + + shell_print(sh, "domain_id,name,latency,attributes"); + + for (i = 0; i < data->num_domains; i++) { + ret = scmi_reset_domain_attr_get(cfg->scmi_dev, i, &dom_attr); + if (ret) { + shell_error(sh, "reset domain:%u get attributes failed (%d)", ret, i); + return ret; + } + + shell_print(sh, "%u,%s,0x%08x,0x%08x", i, dom_attr.name, dom_attr.latency, + dom_attr.attr); + } + + return 0; +} + +static int scmi_shell_reset_info(const struct shell *sh, size_t argc, char **argv) +{ + const struct scmi_reset_config *cfg = reset_dev->config; + struct scmi_msg_reset_domain_attr_resp dom_attr = {0}; + struct scmi_reset_data *data = reset_dev->data; + uint32_t domain_id; + int ret; + + domain_id = atoi(argv[1]); + if (domain_id >= data->num_domains) { + shell_error(sh, "invalid reset domain index %s\n", argv[1]); + return -ENOENT; + } + + ret = scmi_reset_domain_attr_get(cfg->scmi_dev, domain_id, &dom_attr); + if (ret) { + shell_error(sh, "reset domain get attributes failed (%d)", ret); + return ret; + } + + shell_print(sh, "ARM SCMI reset domain: %u", domain_id); + shell_print(sh, " name\t\t: %s", dom_attr.name); + if (dom_attr.latency == SCMI_RESET_ATTR_LATENCY_UNK1 || + dom_attr.latency == SCMI_RESET_ATTR_LATENCY_UNK1) { + shell_print(sh, " latency\t: unk"); + } else { + shell_print(sh, " latency\t: %u", dom_attr.latency); + } + shell_print(sh, " attr\t\t: 0x%08x", dom_attr.attr); + + return 0; +} + +static int scmi_shell_reset_assert(const struct shell *sh, size_t argc, char **argv) +{ + struct scmi_reset_data *data = reset_dev->data; + uint32_t domain_id; + + domain_id = atoi(argv[1]); + if (domain_id >= data->num_domains) { + shell_error(sh, "invalid reset domain index %s\n", argv[1]); + return -ENOENT; + } + + return scmi_reset_line_assert(reset_dev, domain_id); +} + +static int scmi_shell_reset_deassert(const struct shell *sh, size_t argc, char **argv) +{ + struct scmi_reset_data *data = reset_dev->data; + uint32_t domain_id; + + domain_id = atoi(argv[1]); + if (domain_id >= data->num_domains) { + shell_error(sh, "invalid reset domain index %s\n", argv[1]); + return -ENOENT; + } + + return scmi_reset_line_deassert(reset_dev, domain_id); +} + +static int scmi_shell_reset_toggle(const struct shell *sh, size_t argc, char **argv) +{ + struct scmi_reset_data *data = reset_dev->data; + uint32_t domain_id; + + domain_id = atoi(argv[1]); + if (domain_id >= data->num_domains) { + shell_error(sh, "invalid reset domain index %s\n", argv[1]); + return -ENOENT; + } + + return scmi_reset_line_toggle(reset_dev, domain_id); +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_scmi_reset_cmds, + SHELL_CMD_ARG(revision, NULL, + "SCMI Reset proto show revision information\n" + "Usage: arm_scmi reset revision\n", + scmi_shell_reset_revision, 1, 0), + SHELL_CMD_ARG(list, NULL, + "SCMI Reset domains list\n" + "Usage: arm_scmi reset list\n", + scmi_shell_reset_dom_list, 1, 0), + SHELL_CMD_ARG(info, NULL, + "SCMI Reset domain show info\n" + "Usage: arm_scmi reset info \n", + scmi_shell_reset_info, 2, 0), + SHELL_CMD_ARG(assert, NULL, + "SCMI Reset domain assert\n" + "Usage: arm_scmi reset assert \n", + scmi_shell_reset_assert, 2, 0), + SHELL_CMD_ARG(deassert, NULL, + "SCMI Reset domain de-assert\n" + "Usage: arm_scmi reset deassert \n", + scmi_shell_reset_deassert, 2, 0), + SHELL_CMD_ARG(autoreset, NULL, + "SCMI Reset domain Autonomous reset\n" + "Usage: arm_scmi reset autoreset \n", + scmi_shell_reset_toggle, 2, 0), + SHELL_SUBCMD_SET_END); + +SHELL_SUBCMD_ADD((arm_scmi), reset, &sub_scmi_reset_cmds, + "SCMI Reset proto commands.", + NULL, 1, 1); + +#endif /* CONFIG_ARM_SCMI_RESET_SHELL */