[PATCH v2 00/12] firmware: scmi: add SCMI base protocol support

This patch series allows users to access SCMI base protocol provided by SCMI server (platform). It will also be utilized in separate patches in the future to add sanity/validity checks for other protocols. See SCMI specification document v3.2 beta[1] for more details about SCMI base protocol.
What is currently not implemented is - SCMI_BASE_NOTIFY_ERRORS command and notification callback mechanism
This feature won't be very useful in the current U-Boot environment.
[1] https://developer.arm.com/documentation/den0056/e/?lang=en
Test ==== The patch series was tested on the following platforms: * sandbox * qemu-arm64 with OPTEE as SCMI server
Prerequisite: ============= * This patch series is based on v2023.07-rc and relies on the following patch:
[2] https://lists.denx.de/pipermail/u-boot/2023-June/520083.html
Patches: ======== Patch#1-#5: Add SCMI base protocol driver Patch#6-#9: Add SCMI base protocol device unit test Patch#10-#12: Add scmi command
Change history: =============== v2 (Jul, 26, 2023) * refactor devm_scmi_of_get_channel()/process_msg(), removing uses of ops (patch#1) * use helper functions, removing uses of ops (patch#2,#9,#10) * add more descriptions in scmi command doc (patch#11) * remove 'scmi base' sub-command (patch#10,#12)
v1 (Jun, 28, 2023) * initial release
AKASHI Takahiro (12): scmi: refactor the code to hide a channel from devices firmware: scmi: implement SCMI base protocol firmware: scmi: move scmi_bind_protocols() backward firmware: scmi: framework for installing additional protocols firmware: scmi: install base protocol to SCMI agent sandbox: remove SCMI base node definition from test.dts firmware: scmi: fake base protocol commands on sandbox test: dm: simplify SCMI unit test on sandbox test: dm: add SCMI base protocol test cmd: add scmi command for SCMI firmware doc: cmd: add documentation for scmi test: dm: add scmi command test
arch/sandbox/dts/test.dts | 4 - arch/sandbox/include/asm/scmi_test.h | 7 +- cmd/Kconfig | 9 + cmd/Makefile | 1 + cmd/scmi.c | 334 +++++++++++ doc/usage/cmd/scmi.rst | 126 ++++ drivers/clk/clk_scmi.c | 27 +- drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/base.c | 637 +++++++++++++++++++++ drivers/firmware/scmi/sandbox-scmi_agent.c | 379 +++++++++++- drivers/firmware/scmi/scmi_agent-uclass.c | 367 ++++++++++-- drivers/power/regulator/scmi_regulator.c | 27 +- drivers/reset/reset-scmi.c | 19 +- include/dm/uclass-id.h | 1 + include/scmi_agent-uclass.h | 81 ++- include/scmi_agent.h | 29 +- include/scmi_protocols.h | 345 +++++++++++ test/dm/scmi.c | 226 ++++++-- 18 files changed, 2430 insertions(+), 190 deletions(-) create mode 100644 cmd/scmi.c create mode 100644 doc/usage/cmd/scmi.rst create mode 100644 drivers/firmware/scmi/base.c

The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * new patch --- drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index d172fed24c9d..34a49363a51a 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -13,17 +13,8 @@ #include <asm/types.h> #include <linux/clk-provider.h>
-/** - * struct scmi_clk_priv - Private data for SCMI clocks - * @channel: Reference to the SCMI channel to use - */ -struct scmi_clk_priv { - struct scmi_channel *channel; -}; - static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) { - struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_protocol_attr_out out; struct scmi_msg msg = { .protocol_id = SCMI_PROTOCOL_ID_CLOCK, @@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) { - struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_attribute_in in = { .clock_id = clkid, }; @@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -70,7 +60,6 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_gate(struct clk *clk, int enable) { - struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_state_in in = { .clock_id = clk->id, .attributes = enable, @@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg); + ret = devm_scmi_process_msg(clk->dev, &msg); if (ret) return ret;
@@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk) { - struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_get_in in = { .clock_id = clk->id, }; @@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg); + ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) { - struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_set_in in = { .clock_id = clk->id, .flags = SCMI_CLK_RATE_ROUND_CLOSEST, @@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg); + ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev) { - struct scmi_clk_priv *priv = dev_get_priv(dev); struct clk *clk; size_t num_clocks, i; int ret;
- ret = devm_scmi_of_get_channel(dev, &priv->channel); + ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
@@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = { .id = UCLASS_CLK, .ops = &scmi_clk_ops, .probe = scmi_clk_probe, - .priv_auto = sizeof(struct scmi_clk_priv *), }; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 02de692d66f3..39cf15c88f75 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <dm/device_compat.h> @@ -129,43 +130,88 @@ static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) return (const struct scmi_agent_ops *)dev->driver->ops; }
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +/** + * scmi_of_get_channel() - Get SCMI channel handle + * + * @dev: SCMI agent device + * @channel: Output reference to the SCMI channel upon success + * + * On return, @channel will be set. + * Return 0 on success and a negative errno on failure + */ +static int scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +{ + const struct scmi_agent_ops *ops; + + ops = transport_dev_ops(dev); + if (ops->of_get_channel) + return ops->of_get_channel(dev, channel); + else + return -EPROTONOSUPPORT; +} + +int devm_scmi_of_get_channel(struct udevice *dev) { struct udevice *parent; + struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev); + int ret;
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- if (transport_dev_ops(parent)->of_get_channel) - return transport_dev_ops(parent)->of_get_channel(parent, channel); + ret = scmi_of_get_channel(parent, &priv->channel); + if (ret == -EPROTONOSUPPORT) { + /* Drivers without a get_channel operator don't need a channel ref */ + priv->channel = NULL;
- /* Drivers without a get_channel operator don't need a channel ref */ - *channel = NULL; + return 0; + }
- return 0; + return ret; }
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel, - struct scmi_msg *msg) +/** + * scmi_process_msg() - Send and process an SCMI message + * + * Send a message to an SCMI server. + * Caller sets scmi_msg::out_msg_sz to the output message buffer size. + * + * @dev: SCMI agent device + * @channel: Communication channel for the device + * @msg: Message structure reference + * + * On return, scmi_msg::out_msg_sz stores the response payload size. + * Return: 0 on success and a negative errno on failure + */ +static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel, + struct scmi_msg *msg) { const struct scmi_agent_ops *ops; + + ops = transport_dev_ops(dev); + if (ops->process_msg) + return ops->process_msg(dev, channel, msg); + else + return -EPROTONOSUPPORT; +} + +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ struct udevice *parent; + struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- ops = transport_dev_ops(parent); - - if (ops->process_msg) - return ops->process_msg(parent, channel, msg); - - return -EPROTONOSUPPORT; + return scmi_process_msg(parent, priv->channel, msg); }
UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent", .post_bind = scmi_bind_protocols, + .per_device_plat_auto = sizeof(struct scmi_agent_priv), + .per_child_auto = sizeof(struct scmi_agent_proto_priv *), }; diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 801148036ff6..08918b20872c 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -25,18 +25,9 @@ struct scmi_regulator_platdata { u32 domain_id; };
-/** - * struct scmi_regulator_priv - Private data for SCMI voltage regulator - * @channel: Reference to the SCMI channel to use - */ -struct scmi_regulator_priv { - struct scmi_channel *channel; -}; - static int scmi_voltd_set_enable(struct udevice *dev, bool enable) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev); - struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_set_in in = { .domain_id = pdata->domain_id, .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF, @@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) static int scmi_voltd_get_enable(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev); - struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_get_in in = { .domain_id = pdata->domain_id, }; @@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) { - struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_set_in in = { .domain_id = pdata->domain_id, @@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev) { - struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_get_in in = { .domain_id = pdata->domain_id, @@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg); + ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev) static int scmi_regulator_probe(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev); - struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_attr_in in = { 0 }; struct scmi_voltd_attr_out out = { 0 }; struct scmi_msg scmi_msg = { @@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev) }; int ret;
- ret = devm_scmi_of_get_channel(dev->parent, &priv->channel); + ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
/* Check voltage domain is known from SCMI server */ in.domain_id = pdata->domain_id;
- ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg); + ret = devm_scmi_process_msg(dev, &scmi_msg); if (ret) { dev_err(dev, "Failed to query voltage domain %u: %d\n", pdata->domain_id, ret); @@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = { .probe = scmi_regulator_probe, .of_to_plat = scmi_regulator_of_to_plat, .plat_auto = sizeof(struct scmi_regulator_platdata), - .priv_auto = sizeof(struct scmi_regulator_priv *), };
static int scmi_regulator_bind(struct udevice *dev) @@ -209,4 +195,5 @@ U_BOOT_DRIVER(scmi_voltage_domain) = { .name = "scmi_voltage_domain", .id = UCLASS_NOP, .bind = scmi_regulator_bind, + .per_child_auto = sizeof(struct scmi_agent_proto_priv *), }; diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 122556162ec3..b76711f0a8fb 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -13,17 +13,8 @@ #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, @@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) in, out); int ret;
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg); + ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
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, }; @@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst) * We don't really care about the attribute, just check * the reset domain exists. */ - ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg); + ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
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); + return devm_scmi_of_get_channel(dev); }
U_BOOT_DRIVER(scmi_reset_domain) = { @@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = { .id = UCLASS_RESET, .ops = &scmi_reset_domain_ops, .probe = scmi_reset_probe, - .priv_auto = sizeof(struct scmi_reset_priv *), }; diff --git a/include/scmi_agent.h b/include/scmi_agent.h index ee6286366df7..577892029ff8 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -15,6 +15,14 @@ struct udevice; struct scmi_channel;
+/** + * struct scmi_agent_proto_priv - Private data in device for SCMI agent + * @channel: Reference to the SCMI channel to use + */ +struct scmi_agent_proto_priv { + struct scmi_channel *channel; +}; + /* * struct scmi_msg - Context of a SCMI message sent and the response received * @@ -49,10 +57,9 @@ struct scmi_msg { * devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node * * @dev: Device requesting a channel - * @channel: Output reference to the SCMI channel upon success * @return 0 on success and a negative errno on failure */ -int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel); +int devm_scmi_of_get_channel(struct udevice *dev);
/** * devm_scmi_process_msg() - Send and process an SCMI message @@ -62,12 +69,10 @@ int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) * On return, scmi_msg::out_msg_sz stores the response payload size. * * @dev: SCMI device - * @channel: Communication channel for the device * @msg: Message structure reference * Return: 0 on success and a negative errno on failure */ -int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel, - struct scmi_msg *msg); +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
/** * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code

On Wed, 26 Jul 2023 at 02:38, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- new patch
drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Hello Takahiro-san,
From: U-Boot u-boot-bounces@lists.denx.de on behalf of Simon Glass sjg@chromium.org Sent: Thursday, July 27, 2023 2:50 AM
On Wed, 26 Jul 2023 at 02:38, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- new patch
drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Sorry for this late feedback. I initially saw no issues with this patch series but testing the series against stm32mp135f-dk board which is using SCMI resources, I saw the board failed to boot. The issue is related to udevice parent tree and common clock framework. I'll post comments on patch 01/12.
Best regards, Etienne

Hello Takahiro-san,
Sorry again for this late feedback. Testing the series against stm32mp135f-dk board which is using SCMI resources, I see the board fails to boot.
From: AKASHI Takahiro takahiro.akashi@linaro.org To: trini@konsulko.com, sjg@chromium.org Cc: etienne.carriere@st.com, u-boot@lists.denx.de, AKASHI Takahiro takahiro.akashi@linaro.org Subject: [PATCH v2 01/12] scmi: refactor the code to hide a channel from devices Date: Wed, 26 Jul 2023 17:37:57 +0900 [thread overview] Message-ID: 20230726083808.140780-2-takahiro.akashi@linaro.org (raw) In-Reply-To: 20230726083808.140780-1-takahiro.akashi@linaro.org
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- new patch
drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index d172fed24c9d..34a49363a51a 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -13,17 +13,8 @@ #include <asm/types.h> #include <linux/clk-provider.h>
-/**
- struct scmi_clk_priv - Private data for SCMI clocks
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_clk_priv {
- struct scmi_channel *channel;
-};
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_protocol_attr_out out; struct scmi_msg msg = { .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_attribute_in in = { .clock_id = clkid, };
@@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -70,7 +60,6 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_gate(struct clk *clk, int enable) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_state_in in = { .clock_id = clk->id, .attributes = enable,
@@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret) return ret;
@@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_get_in in = { .clock_id = clk->id, };
@@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_set_in in = { .clock_id = clk->id, .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev) {
struct scmi_clk_priv *priv = dev_get_priv(dev); struct clk *clk; size_t num_clocks, i; int ret;
ret = devm_scmi_of_get_channel(dev, &priv->channel);
- ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
@@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = { .id = UCLASS_CLK, .ops = &scmi_clk_ops, .probe = scmi_clk_probe,
- .priv_auto = sizeof(struct scmi_clk_priv *),
}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 02de692d66f3..39cf15c88f75 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <dm/device_compat.h> @@ -129,43 +130,88 @@ static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) return (const struct scmi_agent_ops *)dev->driver->ops; }
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +/**
- scmi_of_get_channel() - Get SCMI channel handle
- @dev: SCMI agent device
- @channel: Output reference to the SCMI channel upon success
- On return, @channel will be set.
- Return 0 on success and a negative errno on failure
- */
+static int scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +{
- const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->of_get_channel)
return ops->of_get_channel(dev, channel);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_of_get_channel(struct udevice *dev) { struct udevice *parent;
- struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
This parent lookup does not match when CONFIG_CLK_CCF is enabled. When so, the scmi clock device is on the clock itself but a child udevice of some udevice held by the common clock framework (CCF). Platforms from the stm32mp13 family do enable SCMI clock and CCF.
It can propose a way to go, using find_scmi_transport_device() to provide the agent's 1st child private data as an output argument: //patch-start -static struct udevice *find_scmi_transport_device(struct udevice *dev) +static struct udevice * +find_scmi_transport_device(struct udevice *dev, + struct scmi_agent_proto_priv **priv) { struct udevice *parent = dev; + struct scmi_agent_proto_priv *parent_priv;
do { + parent_priv = dev_get_parent_priv(parent); parent = dev_get_parent(parent); } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
if (!parent) dev_err(dev, "Invalid SCMI device, agent not found\n"); + else if (priv) + *priv = parent_priv;
return parent; } //end patch
Tested OK on stm32mp13 with the remaining patch series applied (minor conflics).
BR, etienne
int ret;
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- if (transport_dev_ops(parent)->of_get_channel)
return transport_dev_ops(parent)->of_get_channel(parent, channel);
- ret = scmi_of_get_channel(parent, &priv->channel);
- if (ret == -EPROTONOSUPPORT) {
/* Drivers without a get_channel operator don't need a channel ref */
priv->channel = NULL;
- /* Drivers without a get_channel operator don't need a channel ref */
- *channel = NULL;
return 0;
- }
- return 0;
- return ret;
}
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
+/**
- scmi_process_msg() - Send and process an SCMI message
- Send a message to an SCMI server.
- Caller sets scmi_msg::out_msg_sz to the output message buffer size.
- @dev: SCMI agent device
- @channel: Communication channel for the device
- @msg: Message structure reference
- On return, scmi_msg::out_msg_sz stores the response payload size.
- Return: 0 on success and a negative errno on failure
- */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
{ const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->process_msg)
return ops->process_msg(dev, channel, msg);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ struct udevice *parent;
struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- ops = transport_dev_ops(parent);
- if (ops->process_msg)
return ops->process_msg(parent, channel, msg);
- return -EPROTONOSUPPORT;
- return scmi_process_msg(parent, priv->channel, msg);
}
UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent", .post_bind = scmi_bind_protocols,
- .per_device_plat_auto = sizeof(struct scmi_agent_priv),
Typo: this added line belong to patch 04/12.
Regards, Etienne
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 801148036ff6..08918b20872c 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -25,18 +25,9 @@ struct scmi_regulator_platdata { u32 domain_id; };
-/**
- struct scmi_regulator_priv - Private data for SCMI voltage regulator
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_regulator_priv {
- struct scmi_channel *channel;
-};
static int scmi_voltd_set_enable(struct udevice *dev, bool enable) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_set_in in = { .domain_id = pdata->domain_id, .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) static int scmi_voltd_get_enable(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_get_in in = { .domain_id = pdata->domain_id, };
@@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_set_in in = { .domain_id = pdata->domain_id,
@@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_get_in in = { .domain_id = pdata->domain_id,
@@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev) static int scmi_regulator_probe(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_attr_in in = { 0 }; struct scmi_voltd_attr_out out = { 0 }; struct scmi_msg scmi_msg = {
@@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev) }; int ret;
- ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
/* Check voltage domain is known from SCMI server */ in.domain_id = pdata->domain_id;
- ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
- ret = devm_scmi_process_msg(dev, &scmi_msg); if (ret) { dev_err(dev, "Failed to query voltage domain %u: %d\n", pdata->domain_id, ret);
@@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = { .probe = scmi_regulator_probe, .of_to_plat = scmi_regulator_of_to_plat, .plat_auto = sizeof(struct scmi_regulator_platdata),
- .priv_auto = sizeof(struct scmi_regulator_priv *),
};
static int scmi_regulator_bind(struct udevice *dev) @@ -209,4 +195,5 @@ U_BOOT_DRIVER(scmi_voltage_domain) = { .name = "scmi_voltage_domain", .id = UCLASS_NOP, .bind = scmi_regulator_bind,
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 122556162ec3..b76711f0a8fb 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -13,17 +13,8 @@ #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,
@@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) in, out); int ret;
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
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, };
@@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst) * We don't really care about the attribute, just check * the reset domain exists. */
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
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);
- return devm_scmi_of_get_channel(dev);
}
U_BOOT_DRIVER(scmi_reset_domain) = { @@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = { .id = UCLASS_RESET, .ops = &scmi_reset_domain_ops, .probe = scmi_reset_probe,
- .priv_auto = sizeof(struct scmi_reset_priv *),
}; diff --git a/include/scmi_agent.h b/include/scmi_agent.h index ee6286366df7..577892029ff8 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -15,6 +15,14 @@ struct udevice; struct scmi_channel;
+/**
- struct scmi_agent_proto_priv - Private data in device for SCMI agent
- @channel: Reference to the SCMI channel to use
- */
+struct scmi_agent_proto_priv {
- struct scmi_channel *channel;
+};
/*
- struct scmi_msg - Context of a SCMI message sent and the response received
@@ -49,10 +57,9 @@ struct scmi_msg {
- devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node
- @dev: Device requesting a channel
*/
- @channel: Output reference to the SCMI channel upon success
- @return 0 on success and a negative errno on failure
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel); +int devm_scmi_of_get_channel(struct udevice *dev);
/**
- devm_scmi_process_msg() - Send and process an SCMI message
@@ -62,12 +69,10 @@ int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
- On return, scmi_msg::out_msg_sz stores the response payload size.
- @dev: SCMI device
*/
- @channel: Communication channel for the device
- @msg: Message structure reference
- Return: 0 on success and a negative errno on failure
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg);
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
/**
- scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
-- 2.41.0

Hi Etienne,
On Thu, Aug 03, 2023 at 09:24:51AM +0000, Etienne CARRIERE wrote:
Hello Takahiro-san,
Sorry again for this late feedback. Testing the series against stm32mp135f-dk board which is using SCMI resources, I see the board fails to boot.
From: AKASHI Takahiro takahiro.akashi@linaro.org To: trini@konsulko.com, sjg@chromium.org Cc: etienne.carriere@st.com, u-boot@lists.denx.de, AKASHI Takahiro takahiro.akashi@linaro.org Subject: [PATCH v2 01/12] scmi: refactor the code to hide a channel from devices Date: Wed, 26 Jul 2023 17:37:57 +0900 [thread overview] Message-ID: 20230726083808.140780-2-takahiro.akashi@linaro.org (raw) In-Reply-To: 20230726083808.140780-1-takahiro.akashi@linaro.org
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- new patch
drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index d172fed24c9d..34a49363a51a 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -13,17 +13,8 @@ #include <asm/types.h> #include <linux/clk-provider.h>
-/**
- struct scmi_clk_priv - Private data for SCMI clocks
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_clk_priv {
- struct scmi_channel *channel;
-};
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_protocol_attr_out out; struct scmi_msg msg = { .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_attribute_in in = { .clock_id = clkid, };
@@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -70,7 +60,6 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_gate(struct clk *clk, int enable) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_state_in in = { .clock_id = clk->id, .attributes = enable,
@@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret) return ret;
@@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_get_in in = { .clock_id = clk->id, };
@@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_set_in in = { .clock_id = clk->id, .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev) {
struct scmi_clk_priv *priv = dev_get_priv(dev); struct clk *clk; size_t num_clocks, i; int ret;
ret = devm_scmi_of_get_channel(dev, &priv->channel);
- ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
@@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = { .id = UCLASS_CLK, .ops = &scmi_clk_ops, .probe = scmi_clk_probe,
- .priv_auto = sizeof(struct scmi_clk_priv *),
}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 02de692d66f3..39cf15c88f75 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <dm/device_compat.h> @@ -129,43 +130,88 @@ static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) return (const struct scmi_agent_ops *)dev->driver->ops; }
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +/**
- scmi_of_get_channel() - Get SCMI channel handle
- @dev: SCMI agent device
- @channel: Output reference to the SCMI channel upon success
- On return, @channel will be set.
- Return 0 on success and a negative errno on failure
- */
+static int scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +{
- const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->of_get_channel)
return ops->of_get_channel(dev, channel);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_of_get_channel(struct udevice *dev) { struct udevice *parent;
- struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
This parent lookup does not match when CONFIG_CLK_CCF is enabled. When so, the scmi clock device is on the clock itself but a child udevice of some udevice held by the common clock framework (CCF). Platforms from the stm32mp13 family do enable SCMI clock and CCF.
I tested my patch on sandbox, where CCF is also enabled, and "ut dm scmi_clocks" is passed without any error. So I'm not sure if the point you mentioned above is a root cause.
-Takahiro Akashi
It can propose a way to go, using find_scmi_transport_device() to provide the agent's 1st child private data as an output argument: //patch-start -static struct udevice *find_scmi_transport_device(struct udevice *dev) +static struct udevice * +find_scmi_transport_device(struct udevice *dev,
struct scmi_agent_proto_priv **priv)
{ struct udevice *parent = dev;
struct scmi_agent_proto_priv *parent_priv; do {
parent_priv = dev_get_parent_priv(parent); parent = dev_get_parent(parent); } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT); if (!parent) dev_err(dev, "Invalid SCMI device, agent not found\n");
else if (priv)
*priv = parent_priv; return parent;
} //end patch
Tested OK on stm32mp13 with the remaining patch series applied (minor conflics).
BR, etienne
int ret;
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- if (transport_dev_ops(parent)->of_get_channel)
return transport_dev_ops(parent)->of_get_channel(parent, channel);
- ret = scmi_of_get_channel(parent, &priv->channel);
- if (ret == -EPROTONOSUPPORT) {
/* Drivers without a get_channel operator don't need a channel ref */
priv->channel = NULL;
- /* Drivers without a get_channel operator don't need a channel ref */
- *channel = NULL;
return 0;
- }
- return 0;
- return ret;
}
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
+/**
- scmi_process_msg() - Send and process an SCMI message
- Send a message to an SCMI server.
- Caller sets scmi_msg::out_msg_sz to the output message buffer size.
- @dev: SCMI agent device
- @channel: Communication channel for the device
- @msg: Message structure reference
- On return, scmi_msg::out_msg_sz stores the response payload size.
- Return: 0 on success and a negative errno on failure
- */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
{ const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->process_msg)
return ops->process_msg(dev, channel, msg);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ struct udevice *parent;
struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- ops = transport_dev_ops(parent);
- if (ops->process_msg)
return ops->process_msg(parent, channel, msg);
- return -EPROTONOSUPPORT;
- return scmi_process_msg(parent, priv->channel, msg);
}
UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent", .post_bind = scmi_bind_protocols,
- .per_device_plat_auto = sizeof(struct scmi_agent_priv),
Typo: this added line belong to patch 04/12.
Regards, Etienne
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 801148036ff6..08918b20872c 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -25,18 +25,9 @@ struct scmi_regulator_platdata { u32 domain_id; };
-/**
- struct scmi_regulator_priv - Private data for SCMI voltage regulator
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_regulator_priv {
- struct scmi_channel *channel;
-};
static int scmi_voltd_set_enable(struct udevice *dev, bool enable) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_set_in in = { .domain_id = pdata->domain_id, .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) static int scmi_voltd_get_enable(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_get_in in = { .domain_id = pdata->domain_id, };
@@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_set_in in = { .domain_id = pdata->domain_id,
@@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_get_in in = { .domain_id = pdata->domain_id,
@@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev) static int scmi_regulator_probe(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_attr_in in = { 0 }; struct scmi_voltd_attr_out out = { 0 }; struct scmi_msg scmi_msg = {
@@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev) }; int ret;
- ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
/* Check voltage domain is known from SCMI server */ in.domain_id = pdata->domain_id;
- ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
- ret = devm_scmi_process_msg(dev, &scmi_msg); if (ret) { dev_err(dev, "Failed to query voltage domain %u: %d\n", pdata->domain_id, ret);
@@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = { .probe = scmi_regulator_probe, .of_to_plat = scmi_regulator_of_to_plat, .plat_auto = sizeof(struct scmi_regulator_platdata),
- .priv_auto = sizeof(struct scmi_regulator_priv *),
};
static int scmi_regulator_bind(struct udevice *dev) @@ -209,4 +195,5 @@ U_BOOT_DRIVER(scmi_voltage_domain) = { .name = "scmi_voltage_domain", .id = UCLASS_NOP, .bind = scmi_regulator_bind,
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 122556162ec3..b76711f0a8fb 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -13,17 +13,8 @@ #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,
@@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) in, out); int ret;
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
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, };
@@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst) * We don't really care about the attribute, just check * the reset domain exists. */
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
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);
- return devm_scmi_of_get_channel(dev);
}
U_BOOT_DRIVER(scmi_reset_domain) = { @@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = { .id = UCLASS_RESET, .ops = &scmi_reset_domain_ops, .probe = scmi_reset_probe,
- .priv_auto = sizeof(struct scmi_reset_priv *),
}; diff --git a/include/scmi_agent.h b/include/scmi_agent.h index ee6286366df7..577892029ff8 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -15,6 +15,14 @@ struct udevice; struct scmi_channel;
+/**
- struct scmi_agent_proto_priv - Private data in device for SCMI agent
- @channel: Reference to the SCMI channel to use
- */
+struct scmi_agent_proto_priv {
- struct scmi_channel *channel;
+};
/*
- struct scmi_msg - Context of a SCMI message sent and the response received
@@ -49,10 +57,9 @@ struct scmi_msg {
- devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node
- @dev: Device requesting a channel
*/
- @channel: Output reference to the SCMI channel upon success
- @return 0 on success and a negative errno on failure
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel); +int devm_scmi_of_get_channel(struct udevice *dev);
/**
- devm_scmi_process_msg() - Send and process an SCMI message
@@ -62,12 +69,10 @@ int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
- On return, scmi_msg::out_msg_sz stores the response payload size.
- @dev: SCMI device
*/
- @channel: Communication channel for the device
- @msg: Message structure reference
- Return: 0 on success and a negative errno on failure
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg);
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
/**
- scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
-- 2.41.0

Hello Akashi-san,
From: AKASHI Takahiro Sent: Monday, August 7, 2023 12:03 PM
Hi Etienne,
On Thu, Aug 03, 2023 at 09:24:51AM +0000, Etienne CARRIERE wrote:
Hello Takahiro-san,
Sorry again for this late feedback. Testing the series against stm32mp135f-dk board which is using SCMI resources, I see the board fails to boot.
From: AKASHI Takahiro takahiro.akashi@linaro.org To: trini@konsulko.com, sjg@chromium.org Cc: etienne.carriere@st.com, u-boot@lists.denx.de, AKASHI Takahiro takahiro.akashi@linaro.org Subject: [PATCH v2 01/12] scmi: refactor the code to hide a channel from devices Date: Wed, 26 Jul 2023 17:37:57 +0900 [thread overview] Message-ID: 20230726083808.140780-2-takahiro.akashi@linaro.org (raw) In-Reply-To: 20230726083808.140780-1-takahiro.akashi@linaro.org
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex.
Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- new patch
drivers/clk/clk_scmi.c | 27 ++------- drivers/firmware/scmi/scmi_agent-uclass.c | 74 ++++++++++++++++++----- drivers/power/regulator/scmi_regulator.c | 27 +++------ drivers/reset/reset-scmi.c | 19 +----- include/scmi_agent.h | 15 +++-- 5 files changed, 86 insertions(+), 76 deletions(-)
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index d172fed24c9d..34a49363a51a 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -13,17 +13,8 @@ #include <asm/types.h> #include <linux/clk-provider.h>
-/**
- struct scmi_clk_priv - Private data for SCMI clocks
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_clk_priv {
- struct scmi_channel *channel;
-};
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_protocol_attr_out out; struct scmi_msg msg = { .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) {
- struct scmi_clk_priv *priv = dev_get_priv(dev); struct scmi_clk_attribute_in in = { .clock_id = clkid, };
@@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) }; int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -70,7 +60,6 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_gate(struct clk *clk, int enable) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_state_in in = { .clock_id = clk->id, .attributes = enable,
@@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret) return ret;
@@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_get_in in = { .clock_id = clk->id, };
@@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) {
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev); struct scmi_clk_rate_set_in in = { .clock_id = clk->id, .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) in, out); int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(clk->dev, &msg); if (ret < 0) return ret;
@@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev) {
struct scmi_clk_priv *priv = dev_get_priv(dev); struct clk *clk; size_t num_clocks, i; int ret;
ret = devm_scmi_of_get_channel(dev, &priv->channel);
- ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
@@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = { .id = UCLASS_CLK, .ops = &scmi_clk_ops, .probe = scmi_clk_probe,
- .priv_auto = sizeof(struct scmi_clk_priv *),
}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 02de692d66f3..39cf15c88f75 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <dm/device_compat.h> @@ -129,43 +130,88 @@ static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) return (const struct scmi_agent_ops *)dev->driver->ops; }
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +/**
- scmi_of_get_channel() - Get SCMI channel handle
- @dev: SCMI agent device
- @channel: Output reference to the SCMI channel upon success
- On return, @channel will be set.
- Return 0 on success and a negative errno on failure
- */
+static int scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel) +{
- const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->of_get_channel)
return ops->of_get_channel(dev, channel);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_of_get_channel(struct udevice *dev) { struct udevice *parent;
- struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
This parent lookup does not match when CONFIG_CLK_CCF is enabled. When so, the scmi clock device is on the clock itself but a child udevice of some udevice held by the common clock framework (CCF). Platforms from the stm32mp13 family do enable SCMI clock and CCF.
I tested my patch on sandbox, where CCF is also enabled, and "ut dm scmi_clocks" is passed without any error. So I'm not sure if the point you mentioned above is a root cause.
Ok, i'll better investigate where stm32mp13 gets lost. and why sandbox passes wher I would expect it to fail.
Best regards, etienne
-Takahiro Akashi
It can propose a way to go, using find_scmi_transport_device() to provide the agent's 1st child private data as an output argument: //patch-start -static struct udevice *find_scmi_transport_device(struct udevice *dev) +static struct udevice * +find_scmi_transport_device(struct udevice *dev,
struct scmi_agent_proto_priv **priv)
{ struct udevice *parent = dev;
struct scmi_agent_proto_priv *parent_priv; do {
parent_priv = dev_get_parent_priv(parent); parent = dev_get_parent(parent); } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT); if (!parent) dev_err(dev, "Invalid SCMI device, agent not found\n");
else if (priv)
*priv = parent_priv; return parent;
} //end patch
Tested OK on stm32mp13 with the remaining patch series applied (minor conflics).
BR, etienne
int ret;
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- if (transport_dev_ops(parent)->of_get_channel)
return transport_dev_ops(parent)->of_get_channel(parent, channel);
- ret = scmi_of_get_channel(parent, &priv->channel);
- if (ret == -EPROTONOSUPPORT) {
/* Drivers without a get_channel operator don't need a channel ref */
priv->channel = NULL;
- /* Drivers without a get_channel operator don't need a channel ref */
- *channel = NULL;
return 0;
- }
- return 0;
- return ret;
}
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
+/**
- scmi_process_msg() - Send and process an SCMI message
- Send a message to an SCMI server.
- Caller sets scmi_msg::out_msg_sz to the output message buffer size.
- @dev: SCMI agent device
- @channel: Communication channel for the device
- @msg: Message structure reference
- On return, scmi_msg::out_msg_sz stores the response payload size.
- Return: 0 on success and a negative errno on failure
- */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
{ const struct scmi_agent_ops *ops;
- ops = transport_dev_ops(dev);
- if (ops->process_msg)
return ops->process_msg(dev, channel, msg);
- else
return -EPROTONOSUPPORT;
+}
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ struct udevice *parent;
struct scmi_agent_proto_priv *priv = dev_get_parent_priv(dev);
parent = find_scmi_transport_device(dev); if (!parent) return -ENODEV;
- ops = transport_dev_ops(parent);
- if (ops->process_msg)
return ops->process_msg(parent, channel, msg);
- return -EPROTONOSUPPORT;
- return scmi_process_msg(parent, priv->channel, msg);
}
UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent", .post_bind = scmi_bind_protocols,
- .per_device_plat_auto = sizeof(struct scmi_agent_priv),
Typo: this added line belong to patch 04/12.
Regards, Etienne
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 801148036ff6..08918b20872c 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -25,18 +25,9 @@ struct scmi_regulator_platdata { u32 domain_id; };
-/**
- struct scmi_regulator_priv - Private data for SCMI voltage regulator
- @channel: Reference to the SCMI channel to use
- */
-struct scmi_regulator_priv {
- struct scmi_channel *channel;
-};
static int scmi_voltd_set_enable(struct udevice *dev, bool enable) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_set_in in = { .domain_id = pdata->domain_id, .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret) return ret;
@@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable) static int scmi_voltd_get_enable(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_config_get_in in = { .domain_id = pdata->domain_id, };
@@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_set_in in = { .domain_id = pdata->domain_id,
@@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev) {
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_regulator_platdata *pdata = dev_get_plat(dev); struct scmi_voltd_level_get_in in = { .domain_id = pdata->domain_id,
@@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev) in, out); int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(dev, &msg); if (ret < 0) return ret;
@@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev) static int scmi_regulator_probe(struct udevice *dev) { struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev); struct scmi_voltd_attr_in in = { 0 }; struct scmi_voltd_attr_out out = { 0 }; struct scmi_msg scmi_msg = {
@@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev) }; int ret;
- ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
ret = devm_scmi_of_get_channel(dev); if (ret) return ret;
/* Check voltage domain is known from SCMI server */ in.domain_id = pdata->domain_id;
- ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
- ret = devm_scmi_process_msg(dev, &scmi_msg); if (ret) { dev_err(dev, "Failed to query voltage domain %u: %d\n", pdata->domain_id, ret);
@@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = { .probe = scmi_regulator_probe, .of_to_plat = scmi_regulator_of_to_plat, .plat_auto = sizeof(struct scmi_regulator_platdata),
- .priv_auto = sizeof(struct scmi_regulator_priv *),
};
static int scmi_regulator_bind(struct udevice *dev) @@ -209,4 +195,5 @@ U_BOOT_DRIVER(scmi_voltage_domain) = { .name = "scmi_voltage_domain", .id = UCLASS_NOP, .bind = scmi_regulator_bind,
- .per_child_auto = sizeof(struct scmi_agent_proto_priv *),
}; diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 122556162ec3..b76711f0a8fb 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -13,17 +13,8 @@ #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,
@@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) in, out); int ret;
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
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, };
@@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst) * We don't really care about the attribute, just check * the reset domain exists. */
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
- ret = devm_scmi_process_msg(rst->dev, &msg); if (ret) return ret;
@@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
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);
- return devm_scmi_of_get_channel(dev);
}
U_BOOT_DRIVER(scmi_reset_domain) = { @@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = { .id = UCLASS_RESET, .ops = &scmi_reset_domain_ops, .probe = scmi_reset_probe,
- .priv_auto = sizeof(struct scmi_reset_priv *),
}; diff --git a/include/scmi_agent.h b/include/scmi_agent.h index ee6286366df7..577892029ff8 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -15,6 +15,14 @@ struct udevice; struct scmi_channel;
+/**
- struct scmi_agent_proto_priv - Private data in device for SCMI agent
- @channel: Reference to the SCMI channel to use
- */
+struct scmi_agent_proto_priv {
- struct scmi_channel *channel;
+};
/*
- struct scmi_msg - Context of a SCMI message sent and the response received
@@ -49,10 +57,9 @@ struct scmi_msg {
- devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node
- @dev: Device requesting a channel
*/
- @channel: Output reference to the SCMI channel upon success
- @return 0 on success and a negative errno on failure
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel); +int devm_scmi_of_get_channel(struct udevice *dev);
/**
- devm_scmi_process_msg() - Send and process an SCMI message
@@ -62,12 +69,10 @@ int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
- On return, scmi_msg::out_msg_sz stores the response payload size.
- @dev: SCMI device
*/
- @channel: Communication channel for the device
- @msg: Message structure reference
- Return: 0 on success and a negative errno on failure
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg);
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
/**
- scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
-- 2.41.0

SCMI base protocol is mandatory according to the SCMI specification.
With this patch, SCMI base protocol can be accessed via SCMI transport layers. All the commands, except SCMI_BASE_NOTIFY_ERRORS, are supported. This is because U-Boot doesn't support interrupts and the current transport layers are not able to handle asynchronous messages properly.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * add helper functions, removing direct uses of ops * add function descriptions for each of functions in ops --- drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/base.c | 637 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_protocols.h | 345 ++++++++++++++++++ 4 files changed, 984 insertions(+) create mode 100644 drivers/firmware/scmi/base.c
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index b2ff483c75a1..1a23d4981709 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -1,4 +1,5 @@ obj-y += scmi_agent-uclass.o +obj-y += base.o obj-y += smt.o obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c new file mode 100644 index 000000000000..2b61fa650d15 --- /dev/null +++ b/drivers/firmware/scmi/base.c @@ -0,0 +1,637 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SCMI Base protocol as U-Boot device + * + * Copyright (C) 2023 Linaro Limited + * author: AKASHI Takahiro takahiro.akashi@linaro.org + */ + +#include <common.h> +#include <dm.h> +#include <scmi_agent.h> +#include <scmi_protocols.h> +#include <stdlib.h> +#include <asm/types.h> +#include <dm/device_compat.h> +#include <linux/kernel.h> + +/** + * scmi_generic_protocol_version - get protocol version + * @dev: SCMI device + * @id: SCMI protocol ID + * @version: Pointer to SCMI protocol version + * + * Obtain the protocol version number in @version. + * + * Return: 0 on success, error code otherwise + */ +int scmi_generic_protocol_version(struct udevice *dev, + enum scmi_std_protocol id, u32 *version) +{ + struct scmi_protocol_version_out out; + struct scmi_msg msg = { + .protocol_id = id, + .message_id = SCMI_PROTOCOL_VERSION, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *version = out.version; + + return 0; +} + +/** + * scmi_base_protocol_version_int - get Base protocol version + * @dev: SCMI device + * @version: Pointer to SCMI protocol version + * + * Obtain the protocol version number in @version for Base protocol. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version) +{ + return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE, + version); +} + +/** + * scmi_protocol_attrs_int - get protocol attributes + * @dev: SCMI device + * @num_agents: Number of SCMI agents + * @num_protocols: Number of SCMI protocols + * + * Obtain the protocol attributes, the number of agents and the number + * of protocols, in @num_agents and @num_protocols respectively, that + * the device provides. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents, + u32 *num_protocols) +{ + struct scmi_protocol_attrs_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_PROTOCOL_ATTRIBUTES, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes); + *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes); + + return 0; +} + +/** + * scmi_protocol_message_attrs_int - get message-specific attributes + * @dev: SCMI device + * @message_id: SCMI message ID + * @attributes: Message-specific attributes + * + * Obtain the message-specific attributes in @attributes. + * This command succeeds if the message is implemented and available. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id, + u32 *attributes) +{ + struct scmi_protocol_msg_attrs_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES, + .in_msg = (u8 *)&message_id, + .in_msg_sz = sizeof(message_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *attributes = out.attributes; + + return 0; +} + +/** + * scmi_base_discover_vendor_int - get vendor name + * @dev: SCMI device + * @vendor: Vendor name + * + * Obtain the vendor's name in @vendor. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_discover_vendor_int(struct udevice *dev, u8 *vendor) +{ + struct scmi_base_discover_vendor_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_DISCOVER_VENDOR, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + strcpy(vendor, out.vendor_identifier); + + return 0; +} + +/** + * scmi_base_discover_sub_vendor_int - get sub-vendor name + * @dev: SCMI device + * @sub_vendor: Sub-vendor name + * + * Obtain the sub-vendor's name in @sub_vendor. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_discover_sub_vendor_int(struct udevice *dev, + u8 *sub_vendor) +{ + struct scmi_base_discover_vendor_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + strcpy(sub_vendor, out.vendor_identifier); + + return 0; +} + +/** + * scmi_base_discover_impl_version_int - get implementation version + * @dev: SCMI device + * @impl_version: Pointer to implementation version + * + * Obtain the implementation version number in @impl_version. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_discover_impl_version_int(struct udevice *dev, + u32 *impl_version) +{ + struct scmi_base_discover_impl_version_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *impl_version = out.impl_version; + + return 0; +} + +/** + * scmi_base_discover_list_protocols_int - get list of protocols + * @dev: SCMI device + * @protocols: Pointer to array of SCMI protocols + * + * Obtain the list of protocols provided in @protocols. + * The number of elements in @protocols always match to the number of + * protocols returned by smci_protocol_attrs() when this function succeeds. + * It is a caller's responsibility to free @protocols. + * + * Return: the number of protocols in @protocols on success, error code otherwise + */ +static int scmi_base_discover_list_protocols_int(struct udevice *dev, + u8 **protocols) +{ + struct scmi_base_discover_list_protocols_out out; + int cur; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS, + .in_msg = (u8 *)&cur, + .in_msg_sz = sizeof(cur), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + u32 num_agents, num_protocols; + u8 *buf; + int i, ret; + + ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols); + if (ret) + return ret; + + buf = calloc(sizeof(u8), num_protocols); + if (!buf) + return -ENOMEM; + + cur = 0; + do { + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + goto err; + if (out.status) { + ret = scmi_to_linux_errno(out.status); + goto err; + } + + for (i = 0; i < out.num_protocols; i++, cur++) + buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8); + } while (cur < num_protocols); + + *protocols = buf; + + return num_protocols; +err: + free(buf); + + return ret; +} + +/** + * scmi_base_discover_agent_int - identify agent + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @ret_agent_id: Pointer to SCMI agent ID + * @name: SCMI agent name + * + * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff, + * this function returns the caller's agent id in @ret_agent_id. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id, + u32 *ret_agent_id, u8 *name) +{ + struct scmi_base_discover_agent_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_DISCOVER_AGENT, + .in_msg = (u8 *)&agent_id, + .in_msg_sz = sizeof(agent_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + strcpy(name, out.name); + *ret_agent_id = out.agent_id; + + return 0; +} + +/** + * scmi_base_set_device_permissions_int - configure access permission to device + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @device_id: ID of device to access + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id, + u32 device_id, u32 flags) +{ + struct scmi_base_set_device_permissions_in in = { + .agent_id = agent_id, + .device_id = device_id, + .flags = flags, + }; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +/** + * scmi_base_set_protocol_permissions_int - configure access permission to + protocol on device + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @device_id: ID of device to access + * @command_id: SCMI command ID + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the protocol, @command_id, + * on the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_set_protocol_permissions_int(struct udevice *dev, + u32 agent_id, u32 device_id, + u32 command_id, u32 flags) +{ + struct scmi_base_set_protocol_permissions_in in = { + .agent_id = agent_id, + .device_id = device_id, + .command_id = command_id, + .flags = flags, + }; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +/** + * scmi_base_reset_agent_configuration_int - reset resource settings + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the protocol, @command_id, + * on the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_reset_agent_configuration_int(struct udevice *dev, + u32 agent_id, u32 flags) +{ + struct scmi_base_reset_agent_configuration_in in = { + .agent_id = agent_id, + .flags = flags, + }; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_BASE, + .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +/** + * scmi_base_probe - probe base protocol device + * @dev: SCMI device + * + * Probe the device for SCMI base protocol and initialize the private data. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_base_probe(struct udevice *dev) +{ + int ret; + + ret = devm_scmi_of_get_channel(dev); + if (ret) { + dev_err(dev, "get_channel failed\n"); + return ret; + } + + return ret; +} + +struct scmi_base_ops scmi_base_ops = { + /* Commands */ + .protocol_version = scmi_base_protocol_version_int, + .protocol_attrs = scmi_protocol_attrs_int, + .protocol_message_attrs = scmi_protocol_message_attrs_int, + .base_discover_vendor = scmi_base_discover_vendor_int, + .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int, + .base_discover_impl_version = scmi_base_discover_impl_version_int, + .base_discover_list_protocols = scmi_base_discover_list_protocols_int, + .base_discover_agent = scmi_base_discover_agent_int, + .base_notify_errors = NULL, + .base_set_device_permissions = scmi_base_set_device_permissions_int, + .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int, + .base_reset_agent_configuration = + scmi_base_reset_agent_configuration_int, +}; + +int scmi_base_protocol_version(struct udevice *dev, u32 *version) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->protocol_version) + return (*ops->protocol_version)(dev, version); + + return -EOPNOTSUPP; +} + +int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents, + u32 *num_protocols) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->protocol_attrs) + return (*ops->protocol_attrs)(dev, num_agents, num_protocols); + + return -EOPNOTSUPP; +} + +int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id, + u32 *attributes) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->protocol_message_attrs) + return (*ops->protocol_message_attrs)(dev, message_id, + attributes); + + return -EOPNOTSUPP; +} + +int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_discover_vendor) + return (*ops->base_discover_vendor)(dev, vendor); + + return -EOPNOTSUPP; +} + +int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_discover_sub_vendor) + return (*ops->base_discover_sub_vendor)(dev, sub_vendor); + + return -EOPNOTSUPP; +} + +int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_discover_impl_version) + return (*ops->base_discover_impl_version)(dev, impl_version); + + return -EOPNOTSUPP; +} + +int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_discover_list_protocols) + return (*ops->base_discover_list_protocols)(dev, protocols); + + return -EOPNOTSUPP; +} + +int scmi_base_discover_agent(struct udevice *dev, u32 agent_id, + u32 *ret_agent_id, u8 *name) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_discover_agent) + return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id, + name); + + return -EOPNOTSUPP; +} + +int scmi_base_notify_errors(struct udevice *dev, u32 enable) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_notify_errors) + return (*ops->base_notify_errors)(dev, enable); + + return -EOPNOTSUPP; +} + +int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id, + u32 device_id, u32 flags) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_set_device_permissions) + return (*ops->base_set_device_permissions)(dev, agent_id, + device_id, flags); + + return -EOPNOTSUPP; +} + +int scmi_base_set_protocol_permissions(struct udevice *dev, + u32 agent_id, u32 device_id, + u32 command_id, u32 flags) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_set_protocol_permissions) + return (*ops->base_set_protocol_permissions)(dev, agent_id, + device_id, + command_id, + flags); + + return -EOPNOTSUPP; +} + +int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id, + u32 flags) +{ + const struct scmi_base_ops *ops = device_get_ops(dev); + + if (ops->base_reset_agent_configuration) + return (*ops->base_reset_agent_configuration)(dev, agent_id, + flags); + + return -EOPNOTSUPP; +} + +U_BOOT_DRIVER(scmi_base_drv) = { + .id = UCLASS_SCMI_BASE, + .name = "scmi_base_drv", + .ops = &scmi_base_ops, + .probe = scmi_base_probe, +}; + +UCLASS_DRIVER(scmi_base) = { + .id = UCLASS_SCMI_BASE, + .name = "scmi_base", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931ca7..f7a110852321 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -116,6 +116,7 @@ enum uclass_id { UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */ + UCLASS_SCMI_BASE, /* Interface for SCMI Base protocol */ UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index a220cb2a91ad..64fd740472b5 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -49,6 +49,351 @@ enum scmi_discovery_id { SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2, };
+/* + * SCMI Base Protocol + */ +#define SCMI_BASE_PROTOCOL_VERSION 0x20000 + +enum scmi_base_message_id { + SCMI_BASE_DISCOVER_VENDOR = 0x3, + SCMI_BASE_DISCOVER_SUB_VENDOR = 0x4, + SCMI_BASE_DISCOVER_IMPL_VERSION = 0x5, + SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x6, + SCMI_BASE_DISCOVER_AGENT = 0x7, + SCMI_BASE_NOTIFY_ERRORS = 0x8, + SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x9, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0xa, + SCMI_BASE_RESET_AGENT_CONFIGURATION = 0xb, +}; + +#define SCMI_BASE_NAME_LENGTH_MAX 16 + +/** + * struct scmi_protocol_version_out - Response for SCMI_PROTOCOL_VERSION + * command + * @status: SCMI command status + * @version: Protocol version + */ +struct scmi_protocol_version_out { + s32 status; + u32 version; +}; + +/** + * struct scmi_protocol_attrs_out - Response for SCMI_PROTOCOL_ATTRIBUTES + * command + * @status: SCMI command status + * @attributes: Protocol attributes or implementation details + */ +struct scmi_protocol_attrs_out { + s32 status; + u32 attributes; +}; + +#define SCMI_PROTOCOL_ATTRS_NUM_AGENTS(attributes) \ + (((attributes) & GENMASK(15, 8)) >> 8) +#define SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(attributes) \ + ((attributes) & GENMASK(7, 0)) + +/** + * struct scmi_protocol_msg_attrs_out - Response for + * SCMI_PROTOCOL_MESSAGE_ATTRIBUTES command + * @status: SCMI command status + * @attributes: Message-specific attributes + */ +struct scmi_protocol_msg_attrs_out { + s32 status; + u32 attributes; +}; + +/** + * struct scmi_base_discover_vendor_out - Response for + * SCMI_BASE_DISCOVER_VENDOR or + * SCMI_BASE_DISCOVER_SUB_VENDOR command + * @status: SCMI command status + * @vendor_identifier: Name of vendor or sub-vendor in string + */ +struct scmi_base_discover_vendor_out { + s32 status; + u8 vendor_identifier[SCMI_BASE_NAME_LENGTH_MAX]; +}; + +/** + * struct scmi_base_discover_impl_version_out - Response for + * SCMI_BASE_DISCOVER_IMPL_VERSION command + * @status: SCMI command status + * @impl_version: Vendor-specific implementation version + */ +struct scmi_base_discover_impl_version_out { + s32 status; + u32 impl_version; +}; + +/** + * struct scmi_base_discover_list_protocols_out - Response for + * SCMI_BASE_DISCOVER_LIST_PROTOCOLS command + * @status: SCMI command status + * @num_protocols: Number of SCMI protocols in @protocol + * @protocols: Array of packed SCMI protocol ID's + */ +struct scmi_base_discover_list_protocols_out { + s32 status; + u32 num_protocols; + u32 protocols[3]; +}; + +/** + * struct scmi_base_discover_agent_out - Response for + * SCMI_BASE_DISCOVER_AGENT command + * @status: SCMI command status + * @agent_id: SCMI agent ID + * @name: Name of agent in string + */ +struct scmi_base_discover_agent_out { + s32 status; + u32 agent_id; + u8 name[SCMI_BASE_NAME_LENGTH_MAX]; +}; + +#define SCMI_BASE_NOTIFY_ERRORS_ENABLE BIT(0) + +/** + * struct scmi_base_set_device_permissions_in - Parameters for + * SCMI_BASE_SET_DEVICE_PERMISSIONS command + * @agent_id: SCMI agent ID + * @device_id: device ID + * @flags: A set of flags + */ +struct scmi_base_set_device_permissions_in { + u32 agent_id; + u32 device_id; + u32 flags; +}; + +#define SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS BIT(0) + +/** + * struct scmi_base_set_protocol_permissions_in - Parameters for + * SCMI_BASE_SET_PROTOCOL_PERMISSIONS command + * @agent_id: SCMI agent ID + * @device_id: device ID + * @command_id: command ID + * @flags: A set of flags + */ +struct scmi_base_set_protocol_permissions_in { + u32 agent_id; + u32 device_id; + u32 command_id; + u32 flags; +}; + +#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_COMMAND GENMASK(7, 0) +#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS BIT(0) + +/** + * struct scmi_base_reset_agent_configuration_in - Parameters for + * SCMI_BASE_RESET_AGENT_CONFIGURATION command + * @agent_id: SCMI agent ID + * @flags: A set of flags + */ +struct scmi_base_reset_agent_configuration_in { + u32 agent_id; + u32 flags; +}; + +#define SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS BIT(0) + +/** + * struct scmi_base_ops - SCMI base protocol interfaces + */ +struct scmi_base_ops { + /** + * protocol_version - get Base protocol version + * @dev: SCMI device + * @version: Pointer to SCMI protocol version + * + * Obtain the protocol version number in @version for Base protocol. + * + * Return: 0 on success, error code otherwise + */ + int (*protocol_version)(struct udevice *dev, u32 *version); + /** + * protocol_attrs - get protocol attributes + * @dev: SCMI device + * @num_agents: Number of SCMI agents + * @num_protocols: Number of SCMI protocols + * + * Obtain the protocol attributes, the number of agents and the number + * of protocols, in @num_agents and @num_protocols respectively, that + * the device provides. + * + * Return: 0 on success, error code otherwise + */ + int (*protocol_attrs)(struct udevice *dev, u32 *num_agents, + u32 *num_protocols); + /** + * protocol_message_attrs - get message-specific attributes + * @dev: SCMI device + * @message_id: SCMI message ID + * @attributes: Message-specific attributes + * + * Obtain the message-specific attributes in @attributes. + * This command succeeds if the message is implemented and available. + * + * Return: 0 on success, error code otherwise + */ + int (*protocol_message_attrs)(struct udevice *dev, u32 message_id, + u32 *attributes); + /** + * base_discover_vendor - get vendor name + * @dev: SCMI device + * @vendor: Vendor name + * + * Obtain the vendor's name in @vendor. + * + * Return: 0 on success, error code otherwise + */ + int (*base_discover_vendor)(struct udevice *dev, u8 *vendor); + /** + * base_discover_sub_vendor - get sub-vendor name + * @dev: SCMI device + * @sub_vendor: Sub-vendor name + * + * Obtain the sub-vendor's name in @sub_vendor. + * + * Return: 0 on success, error code otherwise + */ + int (*base_discover_sub_vendor)(struct udevice *dev, u8 *sub_vendor); + /** + * base_discover_impl_version - get implementation version + * @dev: SCMI device + * @impl_version: Pointer to implementation version + * + * Obtain the implementation version number in @impl_version. + * + * Return: 0 on success, error code otherwise + */ + int (*base_discover_impl_version)(struct udevice *dev, u32 *impl_version); + /** + * base_discover_list_protocols - get list of protocols + * @dev: SCMI device + * @protocols: Pointer to array of SCMI protocols + * + * Obtain the list of protocols provided in @protocols. + * The number of elements in @protocols always match to the number of + * protocols returned by smci_protocol_attrs() when this function succeeds. + * It is a caller's responsibility to free @protocols. + * + * Return: the number of protocols in @protocols on success, error code otherwise + */ + int (*base_discover_list_protocols)(struct udevice *dev, u8 **protocols); + /** + * base_discover_agent - identify agent + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @ret_agent_id: Pointer to SCMI agent ID + * @name: SCMI agent name + * + * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff, + * this function returns the caller's agent id in @ret_agent_id. + * + * Return: 0 on success, error code otherwise + */ + int (*base_discover_agent)(struct udevice *dev, u32 agent_id, + u32 *ret_agent_id, u8 *name); + /** + * base_notify_errors - configure error notification + * @dev: SCMI device + * @enable: Operation + * + * This function is not yet implemented. + * + * Return: always -EOPNOTSUPP + */ + int (*base_notify_errors)(struct udevice *dev, u32 enable); + /** + * base_set_device_permissions - configure access permission to device + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @device_id: ID of device to access + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ + int (*base_set_device_permissions)(struct udevice *dev, u32 agent_id, + u32 device_id, u32 flags); + /** + * base_set_protocol_permissions - configure access permission to + * protocol on device + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @device_id: ID of device to access + * @command_id: command ID + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the protocol, @command_id, + * on the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ + int (*base_set_protocol_permissions)(struct udevice *dev, u32 agent_id, + u32 device_id, u32 command_id, + u32 flags); + /** + * base_reset_agent_configuration - reset resource settings + * @dev: SCMI device + * @agent_id: SCMI agent ID + * @flags: A set of flags + * + * Ask for allowing or denying access permission to the protocol, @command_id, + * on the device, @device_id. + * The meaning of @flags is defined in SCMI specification. + * + * Return: 0 on success, error code otherwise + */ + int (*base_reset_agent_configuration)(struct udevice *dev, u32 agent_id, + u32 flags); +}; + +int scmi_base_protocol_version(struct udevice *dev, u32 *version); +int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents, + u32 *num_protocols); +int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id, + u32 *attributes); +int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor); +int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor); +int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version); +int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols); +int scmi_base_discover_agent(struct udevice *dev, u32 agent_id, + u32 *ret_agent_id, u8 *name); +int scmi_base_notify_errors(struct udevice *dev, u32 enable); +int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id, + u32 device_id, u32 flags); +int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id, + u32 device_id, u32 flags); +int scmi_base_set_protocol_permissions(struct udevice *dev, + u32 agent_id, u32 device_id, + u32 command_id, u32 flags); +int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id, + u32 flags); + +/** + * scmi_generic_protocol_version - get protocol version + * @dev: SCMI device + * @id: SCMI protocol ID + * @version: Pointer to SCMI protocol version + * + * Obtain the protocol version number in @version. + * + * Return: 0 on success, error code otherwise + */ +int scmi_generic_protocol_version(struct udevice *dev, + enum scmi_std_protocol id, u32 *version); + /* * SCMI Clock Protocol */

On Wed, 26 Jul 2023 at 02:38, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
SCMI base protocol is mandatory according to the SCMI specification.
With this patch, SCMI base protocol can be accessed via SCMI transport layers. All the commands, except SCMI_BASE_NOTIFY_ERRORS, are supported. This is because U-Boot doesn't support interrupts and the current transport layers are not able to handle asynchronous messages properly.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- add helper functions, removing direct uses of ops
- add function descriptions for each of functions in ops
drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/base.c | 637 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_protocols.h | 345 ++++++++++++++++++ 4 files changed, 984 insertions(+) create mode 100644 drivers/firmware/scmi/base.c
Reviewed-by: Simon Glass sjg@chromium.org

Hello Takahiro-san,
From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:37 SCMI base protocol is mandatory according to the SCMI specification.
With this patch, SCMI base protocol can be accessed via SCMI transport layers. All the commands, except SCMI_BASE_NOTIFY_ERRORS, are supported. This is because U-Boot doesn't support interrupts and the current transport layers are not able to handle asynchronous messages properly.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- add helper functions, removing direct uses of ops
- add function descriptions for each of functions in ops
A reported typo and a question on use of strcpy(). Otherwise the patch look to me. If you strongly feel strcpy() is safe, please get my R-b tag: Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/base.c | 637 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_protocols.h | 345 ++++++++++++++++++ 4 files changed, 984 insertions(+) create mode 100644 drivers/firmware/scmi/base.c
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index b2ff483c75a1..1a23d4981709 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -1,4 +1,5 @@ obj-y += scmi_agent-uclass.o +obj-y += base.o obj-y += smt.o obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c new file mode 100644 index 000000000000..2b61fa650d15 --- /dev/null +++ b/drivers/firmware/scmi/base.c @@ -0,0 +1,637 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- SCMI Base protocol as U-Boot device
- Copyright (C) 2023 Linaro Limited
- author: AKASHI Takahiro takahiro.akashi@linaro.org
- */
+#include <common.h> +#include <dm.h> +#include <scmi_agent.h> +#include <scmi_protocols.h> +#include <stdlib.h> +#include <asm/types.h> +#include <dm/device_compat.h> +#include <linux/kernel.h>
+/**
- scmi_generic_protocol_version - get protocol version
- @dev: SCMI device
- @id: SCMI protocol ID
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version.
- Return: 0 on success, error code otherwise
- */
+int scmi_generic_protocol_version(struct udevice *dev,
- enum scmi_std_protocol id, u32 *version)
+{
- struct scmi_protocol_version_out out;
- struct scmi_msg msg = {
- .protocol_id = id,
- .message_id = SCMI_PROTOCOL_VERSION,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *version = out.version;
- return 0;
+}
+/**
- scmi_base_protocol_version_int - get Base protocol version
- @dev: SCMI device
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version for Base protocol.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version) +{
- return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
- version);
+}
+/**
- scmi_protocol_attrs_int - get protocol attributes
- @dev: SCMI device
- @num_agents: Number of SCMI agents
- @num_protocols: Number of SCMI protocols
- Obtain the protocol attributes, the number of agents and the number
- of protocols, in @num_agents and @num_protocols respectively, that
- the device provides.
- Return: 0 on success, error code otherwise
- */
+static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols)
+{
- struct scmi_protocol_attrs_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_PROTOCOL_ATTRIBUTES,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
- *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
- return 0;
+}
+/**
- scmi_protocol_message_attrs_int - get message-specific attributes
- @dev: SCMI device
- @message_id: SCMI message ID
- @attributes: Message-specific attributes
- Obtain the message-specific attributes in @attributes.
- This command succeeds if the message is implemented and available.
- Return: 0 on success, error code otherwise
- */
+static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
- u32 *attributes)
+{
- struct scmi_protocol_msg_attrs_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
- .in_msg = (u8 *)&message_id,
- .in_msg_sz = sizeof(message_id),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *attributes = out.attributes;
- return 0;
+}
+/**
- scmi_base_discover_vendor_int - get vendor name
- @dev: SCMI device
- @vendor: Vendor name
- Obtain the vendor's name in @vendor.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_vendor_int(struct udevice *dev, u8 *vendor) +{
- struct scmi_base_discover_vendor_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_VENDOR,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(vendor, out.vendor_identifier);
Nitpicking: there are no check on output string buffer size.
The implementation looks good as we expect SCMI platform firmware complies with the specification. However I wonder if here it's better to either use strncpy() or to explicit vendor[] argument size:
-static int scmi_base_discover_vendor_int(struct udevice *dev, u8 *vendor) +static int scmi_base_discover_vendor_int(struct udevice *dev, u8 vendor[SCMI_BASE_NAME_LENGTH_MAX])
Ditto in scmi_base_discover_sub_vendor_int() and scmi_base_discover_agent_int().
- return 0;
+}
+/**
- scmi_base_discover_sub_vendor_int - get sub-vendor name
- @dev: SCMI device
- @sub_vendor: Sub-vendor name
- Obtain the sub-vendor's name in @sub_vendor.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
- u8 *sub_vendor)
+{
- struct scmi_base_discover_vendor_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(sub_vendor, out.vendor_identifier);
- return 0;
+}
+/**
- scmi_base_discover_impl_version_int - get implementation version
- @dev: SCMI device
- @impl_version: Pointer to implementation version
- Obtain the implementation version number in @impl_version.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_impl_version_int(struct udevice *dev,
- u32 *impl_version)
+{
- struct scmi_base_discover_impl_version_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *impl_version = out.impl_version;
- return 0;
+}
+/**
- scmi_base_discover_list_protocols_int - get list of protocols
- @dev: SCMI device
- @protocols: Pointer to array of SCMI protocols
- Obtain the list of protocols provided in @protocols.
- The number of elements in @protocols always match to the number of
- protocols returned by smci_protocol_attrs() when this function succeeds.
- It is a caller's responsibility to free @protocols.
- Return: the number of protocols in @protocols on success, error code otherwise
- */
+static int scmi_base_discover_list_protocols_int(struct udevice *dev,
- u8 **protocols)
+{
- struct scmi_base_discover_list_protocols_out out;
- int cur;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
- .in_msg = (u8 *)&cur,
- .in_msg_sz = sizeof(cur),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- u32 num_agents, num_protocols;
- u8 *buf;
- int i, ret;
- ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
- if (ret)
- return ret;
- buf = calloc(sizeof(u8), num_protocols);
- if (!buf)
- return -ENOMEM;
- cur = 0;
- do {
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- goto err;
- if (out.status) {
- ret = scmi_to_linux_errno(out.status);
- goto err;
- }
- for (i = 0; i < out.num_protocols; i++, cur++)
- buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
- } while (cur < num_protocols);
- *protocols = buf;
- return num_protocols;
+err:
- free(buf);
- return ret;
+}
+/**
- scmi_base_discover_agent_int - identify agent
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @ret_agent_id: Pointer to SCMI agent ID
- @name: SCMI agent name
- Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
- this function returns the caller's agent id in @ret_agent_id.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name)
+{
- struct scmi_base_discover_agent_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_AGENT,
- .in_msg = (u8 *)&agent_id,
- .in_msg_sz = sizeof(agent_id),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(name, out.name);
- *ret_agent_id = out.agent_id;
- return 0;
+}
+/**
- scmi_base_set_device_permissions_int - configure access permission to device
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @device_id: ID of device to access
- @flags: A set of flags
- Ask for allowing or denying access permission to the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags)
+{
- struct scmi_base_set_device_permissions_in in = {
- .agent_id = agent_id,
- .device_id = device_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_set_protocol_permissions_int - configure access permission to
- protocol on device
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @device_id: ID of device to access
- @command_id: SCMI command ID
- @flags: A set of flags
- Ask for allowing or denying access permission to the protocol, @command_id,
- on the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags)
+{
- struct scmi_base_set_protocol_permissions_in in = {
- .agent_id = agent_id,
- .device_id = device_id,
- .command_id = command_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_reset_agent_configuration_int - reset resource settings
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @flags: A set of flags
- Ask for allowing or denying access permission to the protocol, @command_id,
- on the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
- u32 agent_id, u32 flags)
+{
- struct scmi_base_reset_agent_configuration_in in = {
- .agent_id = agent_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_probe - probe base protocol device
- @dev: SCMI device
- Probe the device for SCMI base protocol and initialize the private data.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_probe(struct udevice *dev) +{
- int ret;
- ret = devm_scmi_of_get_channel(dev);
- if (ret) {
- dev_err(dev, "get_channel failed\n");
- return ret;
- }
- return ret;
+}
+struct scmi_base_ops scmi_base_ops = {
- /* Commands */
- .protocol_version = scmi_base_protocol_version_int,
- .protocol_attrs = scmi_protocol_attrs_int,
- .protocol_message_attrs = scmi_protocol_message_attrs_int,
- .base_discover_vendor = scmi_base_discover_vendor_int,
- .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
- .base_discover_impl_version = scmi_base_discover_impl_version_int,
- .base_discover_list_protocols = scmi_base_discover_list_protocols_int,
- .base_discover_agent = scmi_base_discover_agent_int,
- .base_notify_errors = NULL,
- .base_set_device_permissions = scmi_base_set_device_permissions_int,
- .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
- .base_reset_agent_configuration =
- scmi_base_reset_agent_configuration_int,
+};
+int scmi_base_protocol_version(struct udevice *dev, u32 *version) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_version)
- return (*ops->protocol_version)(dev, version);
- return -EOPNOTSUPP;
+}
+int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_attrs)
- return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
- return -EOPNOTSUPP;
+}
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
- u32 *attributes)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_message_attrs)
- return (*ops->protocol_message_attrs)(dev, message_id,
- attributes);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_vendor)
- return (*ops->base_discover_vendor)(dev, vendor);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_sub_vendor)
- return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_impl_version)
- return (*ops->base_discover_impl_version)(dev, impl_version);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_list_protocols)
- return (*ops->base_discover_list_protocols)(dev, protocols);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_agent)
- return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
- name);
- return -EOPNOTSUPP;
+}
+int scmi_base_notify_errors(struct udevice *dev, u32 enable) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_notify_errors)
- return (*ops->base_notify_errors)(dev, enable);
- return -EOPNOTSUPP;
+}
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_set_device_permissions)
- return (*ops->base_set_device_permissions)(dev, agent_id,
- device_id, flags);
- return -EOPNOTSUPP;
+}
+int scmi_base_set_protocol_permissions(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_set_protocol_permissions)
- return (*ops->base_set_protocol_permissions)(dev, agent_id,
- device_id,
- command_id,
- flags);
- return -EOPNOTSUPP;
+}
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
- u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_reset_agent_configuration)
- return (*ops->base_reset_agent_configuration)(dev, agent_id,
- flags);
- return -EOPNOTSUPP;
+}
+U_BOOT_DRIVER(scmi_base_drv) = {
- .id = UCLASS_SCMI_BASE,
- .name = "scmi_base_drv",
- .ops = &scmi_base_ops,
- .probe = scmi_base_probe,
+};
+UCLASS_DRIVER(scmi_base) = {
- .id = UCLASS_SCMI_BASE,
- .name = "scmi_base",
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931ca7..f7a110852321 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -116,6 +116,7 @@ enum uclass_id { UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */
- UCLASS_SCMI_BASE, /* Interface for SCMI Base protocol */
UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index a220cb2a91ad..64fd740472b5 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -49,6 +49,351 @@ enum scmi_discovery_id { SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2, }; +/*
- SCMI Base Protocol
- */
+#define SCMI_BASE_PROTOCOL_VERSION 0x20000
+enum scmi_base_message_id {
- SCMI_BASE_DISCOVER_VENDOR = 0x3,
- SCMI_BASE_DISCOVER_SUB_VENDOR = 0x4,
- SCMI_BASE_DISCOVER_IMPL_VERSION = 0x5,
- SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
- SCMI_BASE_DISCOVER_AGENT = 0x7,
- SCMI_BASE_NOTIFY_ERRORS = 0x8,
- SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x9,
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
- SCMI_BASE_RESET_AGENT_CONFIGURATION = 0xb,
+};
+#define SCMI_BASE_NAME_LENGTH_MAX 16
+/**
- struct scmi_protocol_version_out - Response for SCMI_PROTOCOL_VERSION
- command
- @status: SCMI command status
- @version: Protocol version
- */
+struct scmi_protocol_version_out {
- s32 status;
- u32 version;
+};
+/**
- struct scmi_protocol_attrs_out - Response for SCMI_PROTOCOL_ATTRIBUTES
- command
- @status: SCMI command status
- @attributes: Protocol attributes or implementation details
- */
+struct scmi_protocol_attrs_out {
- s32 status;
- u32 attributes;
+};
+#define SCMI_PROTOCOL_ATTRS_NUM_AGENTS(attributes) \
- (((attributes) & GENMASK(15, 8)) >> 8)
+#define SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(attributes) \
- ((attributes) & GENMASK(7, 0))
+/**
- struct scmi_protocol_msg_attrs_out - Response for
- SCMI_PROTOCOL_MESSAGE_ATTRIBUTES command
- @status: SCMI command status
- @attributes: Message-specific attributes
- */
+struct scmi_protocol_msg_attrs_out {
- s32 status;
- u32 attributes;
+};
+/**
- struct scmi_base_discover_vendor_out - Response for
- SCMI_BASE_DISCOVER_VENDOR or
- SCMI_BASE_DISCOVER_SUB_VENDOR command
- @status: SCMI command status
- @vendor_identifier: Name of vendor or sub-vendor in string
- */
+struct scmi_base_discover_vendor_out {
- s32 status;
- u8 vendor_identifier[SCMI_BASE_NAME_LENGTH_MAX];
+};
+/**
- struct scmi_base_discover_impl_version_out - Response for
- SCMI_BASE_DISCOVER_IMPL_VERSION command
- @status: SCMI command status
- @impl_version: Vendor-specific implementation version
- */
+struct scmi_base_discover_impl_version_out {
- s32 status;
- u32 impl_version;
+};
+/**
- struct scmi_base_discover_list_protocols_out - Response for
- SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
- @status: SCMI command status
- @num_protocols: Number of SCMI protocols in @protocol
- @protocols: Array of packed SCMI protocol ID's
- */
+struct scmi_base_discover_list_protocols_out {
- s32 status;
- u32 num_protocols;
- u32 protocols[3];
+};
+/**
- struct scmi_base_discover_agent_out - Response for
- SCMI_BASE_DISCOVER_AGENT command
- @status: SCMI command status
- @agent_id: SCMI agent ID
- @name: Name of agent in string
- */
+struct scmi_base_discover_agent_out {
- s32 status;
- u32 agent_id;
- u8 name[SCMI_BASE_NAME_LENGTH_MAX];
+};
+#define SCMI_BASE_NOTIFY_ERRORS_ENABLE BIT(0)
+/**
- struct scmi_base_set_device_permissions_in - Parameters for
- SCMI_BASE_SET_DEVICE_PERMISSIONS command
- @agent_id: SCMI agent ID
- @device_id: device ID
- @flags: A set of flags
- */
+struct scmi_base_set_device_permissions_in {
- u32 agent_id;
- u32 device_id;
- u32 flags;
+};
+#define SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS BIT(0)
+/**
- struct scmi_base_set_protocol_permissions_in - Parameters for
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
- @agent_id: SCMI agent ID
- @device_id: device ID
- @command_id: command ID
- @flags: A set of flags
- */
+struct scmi_base_set_protocol_permissions_in {
- u32 agent_id;
- u32 device_id;
- u32 command_id;
- u32 flags;
+};
+#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_COMMAND GENMASK(7, 0) +#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS BIT(0)
+/**
- struct scmi_base_reset_agent_configuration_in - Parameters for
- SCMI_BASE_RESET_AGENT_CONFIGURATION command
- @agent_id: SCMI agent ID
- @flags: A set of flags
- */
+struct scmi_base_reset_agent_configuration_in {
- u32 agent_id;
- u32 flags;
+};
+#define SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS BIT(0)
+/**
- struct scmi_base_ops - SCMI base protocol interfaces
- */
+struct scmi_base_ops {
- /**
- * protocol_version - get Base protocol version
- * @dev: SCMI device
- * @version: Pointer to SCMI protocol version
- *
- * Obtain the protocol version number in @version for Base protocol.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_version)(struct udevice *dev, u32 *version);
- /**
- * protocol_attrs - get protocol attributes
- * @dev: SCMI device
- * @num_agents: Number of SCMI agents
- * @num_protocols: Number of SCMI protocols
- *
- * Obtain the protocol attributes, the number of agents and the number
- * of protocols, in @num_agents and @num_protocols respectively, that
- * the device provides.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_attrs)(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols);
- /**
- * protocol_message_attrs - get message-specific attributes
- * @dev: SCMI device
- * @message_id: SCMI message ID
- * @attributes: Message-specific attributes
- *
- * Obtain the message-specific attributes in @attributes.
- * This command succeeds if the message is implemented and available.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_message_attrs)(struct udevice *dev, u32 message_id,
- u32 *attributes);
- /**
- * base_discover_vendor - get vendor name
- * @dev: SCMI device
- * @vendor: Vendor name
- *
- * Obtain the vendor's name in @vendor.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_vendor)(struct udevice *dev, u8 *vendor);
- /**
- * base_discover_sub_vendor - get sub-vendor name
- * @dev: SCMI device
- * @sub_vendor: Sub-vendor name
- *
- * Obtain the sub-vendor's name in @sub_vendor.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_sub_vendor)(struct udevice *dev, u8 *sub_vendor);
- /**
- * base_discover_impl_version - get implementation version
- * @dev: SCMI device
- * @impl_version: Pointer to implementation version
- *
- * Obtain the implementation version number in @impl_version.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_impl_version)(struct udevice *dev, u32 *impl_version);
- /**
- * base_discover_list_protocols - get list of protocols
- * @dev: SCMI device
- * @protocols: Pointer to array of SCMI protocols
- *
- * Obtain the list of protocols provided in @protocols.
- * The number of elements in @protocols always match to the number of
- * protocols returned by smci_protocol_attrs() when this function succeeds.
- * It is a caller's responsibility to free @protocols.
- *
- * Return: the number of protocols in @protocols on success, error code otherwise
- */
- int (*base_discover_list_protocols)(struct udevice *dev, u8 **protocols);
- /**
- * base_discover_agent - identify agent
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @ret_agent_id: Pointer to SCMI agent ID
- * @name: SCMI agent name
- *
- * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
- * this function returns the caller's agent id in @ret_agent_id.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_agent)(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name);
- /**
- * base_notify_errors - configure error notification
- * @dev: SCMI device
- * @enable: Operation
- *
- * This function is not yet implemented.
- *
- * Return: always -EOPNOTSUPP
- */
- int (*base_notify_errors)(struct udevice *dev, u32 enable);
- /**
- * base_set_device_permissions - configure access permission to device
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @device_id: ID of device to access
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_set_device_permissions)(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
- /**
- * base_set_protocol_permissions - configure access permission to
- * protocol on device
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @device_id: ID of device to access
- * @command_id: command ID
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the protocol, @command_id,
- * on the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_set_protocol_permissions)(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 command_id,
- u32 flags);
- /**
- * base_reset_agent_configuration - reset resource settings
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the protocol, @command_id,
- * on the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_reset_agent_configuration)(struct udevice *dev, u32 agent_id,
- u32 flags);
+};
+int scmi_base_protocol_version(struct udevice *dev, u32 *version); +int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols);
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
- u32 *attributes);
+int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor); +int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor); +int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version); +int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols); +int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name);
+int scmi_base_notify_errors(struct udevice *dev, u32 enable); +int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
typo: duplicated declaration.
BR, Etienne
+int scmi_base_set_protocol_permissions(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags);
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
- u32 flags);
+/**
- scmi_generic_protocol_version - get protocol version
- @dev: SCMI device
- @id: SCMI protocol ID
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version.
- Return: 0 on success, error code otherwise
- */
+int scmi_generic_protocol_version(struct udevice *dev,
- enum scmi_std_protocol id, u32 *version);
/* * SCMI Clock Protocol */ -- 2.41.0

Hi Etienne,
On Thu, Aug 03, 2023 at 09:35:57AM +0000, Etienne CARRIERE wrote:
Hello Takahiro-san,
From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:37 SCMI base protocol is mandatory according to the SCMI specification.
With this patch, SCMI base protocol can be accessed via SCMI transport layers. All the commands, except SCMI_BASE_NOTIFY_ERRORS, are supported. This is because U-Boot doesn't support interrupts and the current transport layers are not able to handle asynchronous messages properly.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- add helper functions, removing direct uses of ops
- add function descriptions for each of functions in ops
A reported typo and a question on use of strcpy().
Thank you for pointing out typos not only in this file, but also others. While I won't reply each time, I will fix all those typos.
Otherwise the patch look to me. If you strongly feel strcpy() is safe, please get my R-b tag:
My initial thought was that commands in Base protocol are expected to be used mostly internally so the string size check can be superfluous. But for more safety, I will change the code so that data for returned strings are dynamically allocated by helper functions.
This approach will also be helpful and consistent, in the future, when "exntended name" is supported in other protocols as well so people don't have to worry about the maximum length in any case.
-Takahiro Akashi
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/base.c | 637 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_protocols.h | 345 ++++++++++++++++++ 4 files changed, 984 insertions(+) create mode 100644 drivers/firmware/scmi/base.c
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index b2ff483c75a1..1a23d4981709 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -1,4 +1,5 @@ obj-y += scmi_agent-uclass.o +obj-y += base.o obj-y += smt.o obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c new file mode 100644 index 000000000000..2b61fa650d15 --- /dev/null +++ b/drivers/firmware/scmi/base.c @@ -0,0 +1,637 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- SCMI Base protocol as U-Boot device
- Copyright (C) 2023 Linaro Limited
- author: AKASHI Takahiro takahiro.akashi@linaro.org
- */
+#include <common.h> +#include <dm.h> +#include <scmi_agent.h> +#include <scmi_protocols.h> +#include <stdlib.h> +#include <asm/types.h> +#include <dm/device_compat.h> +#include <linux/kernel.h>
+/**
- scmi_generic_protocol_version - get protocol version
- @dev: SCMI device
- @id: SCMI protocol ID
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version.
- Return: 0 on success, error code otherwise
- */
+int scmi_generic_protocol_version(struct udevice *dev,
- enum scmi_std_protocol id, u32 *version)
+{
- struct scmi_protocol_version_out out;
- struct scmi_msg msg = {
- .protocol_id = id,
- .message_id = SCMI_PROTOCOL_VERSION,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *version = out.version;
- return 0;
+}
+/**
- scmi_base_protocol_version_int - get Base protocol version
- @dev: SCMI device
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version for Base protocol.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version) +{
- return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
- version);
+}
+/**
- scmi_protocol_attrs_int - get protocol attributes
- @dev: SCMI device
- @num_agents: Number of SCMI agents
- @num_protocols: Number of SCMI protocols
- Obtain the protocol attributes, the number of agents and the number
- of protocols, in @num_agents and @num_protocols respectively, that
- the device provides.
- Return: 0 on success, error code otherwise
- */
+static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols)
+{
- struct scmi_protocol_attrs_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_PROTOCOL_ATTRIBUTES,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
- *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
- return 0;
+}
+/**
- scmi_protocol_message_attrs_int - get message-specific attributes
- @dev: SCMI device
- @message_id: SCMI message ID
- @attributes: Message-specific attributes
- Obtain the message-specific attributes in @attributes.
- This command succeeds if the message is implemented and available.
- Return: 0 on success, error code otherwise
- */
+static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
- u32 *attributes)
+{
- struct scmi_protocol_msg_attrs_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
- .in_msg = (u8 *)&message_id,
- .in_msg_sz = sizeof(message_id),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *attributes = out.attributes;
- return 0;
+}
+/**
- scmi_base_discover_vendor_int - get vendor name
- @dev: SCMI device
- @vendor: Vendor name
- Obtain the vendor's name in @vendor.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_vendor_int(struct udevice *dev, u8 *vendor) +{
- struct scmi_base_discover_vendor_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_VENDOR,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(vendor, out.vendor_identifier);
Nitpicking: there are no check on output string buffer size.
The implementation looks good as we expect SCMI platform firmware complies with the specification. However I wonder if here it's better to either use strncpy() or to explicit vendor[] argument size:
-static int scmi_base_discover_vendor_int(struct udevice *dev, u8 *vendor) +static int scmi_base_discover_vendor_int(struct udevice *dev, u8 vendor[SCMI_BASE_NAME_LENGTH_MAX])
Ditto in scmi_base_discover_sub_vendor_int() and scmi_base_discover_agent_int().
- return 0;
+}
+/**
- scmi_base_discover_sub_vendor_int - get sub-vendor name
- @dev: SCMI device
- @sub_vendor: Sub-vendor name
- Obtain the sub-vendor's name in @sub_vendor.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
- u8 *sub_vendor)
+{
- struct scmi_base_discover_vendor_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(sub_vendor, out.vendor_identifier);
- return 0;
+}
+/**
- scmi_base_discover_impl_version_int - get implementation version
- @dev: SCMI device
- @impl_version: Pointer to implementation version
- Obtain the implementation version number in @impl_version.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_impl_version_int(struct udevice *dev,
- u32 *impl_version)
+{
- struct scmi_base_discover_impl_version_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- *impl_version = out.impl_version;
- return 0;
+}
+/**
- scmi_base_discover_list_protocols_int - get list of protocols
- @dev: SCMI device
- @protocols: Pointer to array of SCMI protocols
- Obtain the list of protocols provided in @protocols.
- The number of elements in @protocols always match to the number of
- protocols returned by smci_protocol_attrs() when this function succeeds.
- It is a caller's responsibility to free @protocols.
- Return: the number of protocols in @protocols on success, error code otherwise
- */
+static int scmi_base_discover_list_protocols_int(struct udevice *dev,
- u8 **protocols)
+{
- struct scmi_base_discover_list_protocols_out out;
- int cur;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
- .in_msg = (u8 *)&cur,
- .in_msg_sz = sizeof(cur),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- u32 num_agents, num_protocols;
- u8 *buf;
- int i, ret;
- ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
- if (ret)
- return ret;
- buf = calloc(sizeof(u8), num_protocols);
- if (!buf)
- return -ENOMEM;
- cur = 0;
- do {
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- goto err;
- if (out.status) {
- ret = scmi_to_linux_errno(out.status);
- goto err;
- }
- for (i = 0; i < out.num_protocols; i++, cur++)
- buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
- } while (cur < num_protocols);
- *protocols = buf;
- return num_protocols;
+err:
- free(buf);
- return ret;
+}
+/**
- scmi_base_discover_agent_int - identify agent
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @ret_agent_id: Pointer to SCMI agent ID
- @name: SCMI agent name
- Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
- this function returns the caller's agent id in @ret_agent_id.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name)
+{
- struct scmi_base_discover_agent_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_DISCOVER_AGENT,
- .in_msg = (u8 *)&agent_id,
- .in_msg_sz = sizeof(agent_id),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (out.status)
- return scmi_to_linux_errno(out.status);
- strcpy(name, out.name);
- *ret_agent_id = out.agent_id;
- return 0;
+}
+/**
- scmi_base_set_device_permissions_int - configure access permission to device
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @device_id: ID of device to access
- @flags: A set of flags
- Ask for allowing or denying access permission to the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags)
+{
- struct scmi_base_set_device_permissions_in in = {
- .agent_id = agent_id,
- .device_id = device_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_set_protocol_permissions_int - configure access permission to
- protocol on device
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @device_id: ID of device to access
- @command_id: SCMI command ID
- @flags: A set of flags
- Ask for allowing or denying access permission to the protocol, @command_id,
- on the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags)
+{
- struct scmi_base_set_protocol_permissions_in in = {
- .agent_id = agent_id,
- .device_id = device_id,
- .command_id = command_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_reset_agent_configuration_int - reset resource settings
- @dev: SCMI device
- @agent_id: SCMI agent ID
- @flags: A set of flags
- Ask for allowing or denying access permission to the protocol, @command_id,
- on the device, @device_id.
- The meaning of @flags is defined in SCMI specification.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
- u32 agent_id, u32 flags)
+{
- struct scmi_base_reset_agent_configuration_in in = {
- .agent_id = agent_id,
- .flags = flags,
- };
- s32 status;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_BASE,
- .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&status,
- .out_msg_sz = sizeof(status),
- };
- int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
- if (status)
- return scmi_to_linux_errno(status);
- return 0;
+}
+/**
- scmi_base_probe - probe base protocol device
- @dev: SCMI device
- Probe the device for SCMI base protocol and initialize the private data.
- Return: 0 on success, error code otherwise
- */
+static int scmi_base_probe(struct udevice *dev) +{
- int ret;
- ret = devm_scmi_of_get_channel(dev);
- if (ret) {
- dev_err(dev, "get_channel failed\n");
- return ret;
- }
- return ret;
+}
+struct scmi_base_ops scmi_base_ops = {
- /* Commands */
- .protocol_version = scmi_base_protocol_version_int,
- .protocol_attrs = scmi_protocol_attrs_int,
- .protocol_message_attrs = scmi_protocol_message_attrs_int,
- .base_discover_vendor = scmi_base_discover_vendor_int,
- .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
- .base_discover_impl_version = scmi_base_discover_impl_version_int,
- .base_discover_list_protocols = scmi_base_discover_list_protocols_int,
- .base_discover_agent = scmi_base_discover_agent_int,
- .base_notify_errors = NULL,
- .base_set_device_permissions = scmi_base_set_device_permissions_int,
- .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
- .base_reset_agent_configuration =
- scmi_base_reset_agent_configuration_int,
+};
+int scmi_base_protocol_version(struct udevice *dev, u32 *version) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_version)
- return (*ops->protocol_version)(dev, version);
- return -EOPNOTSUPP;
+}
+int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_attrs)
- return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
- return -EOPNOTSUPP;
+}
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
- u32 *attributes)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->protocol_message_attrs)
- return (*ops->protocol_message_attrs)(dev, message_id,
- attributes);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_vendor)
- return (*ops->base_discover_vendor)(dev, vendor);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_sub_vendor)
- return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_impl_version)
- return (*ops->base_discover_impl_version)(dev, impl_version);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_list_protocols)
- return (*ops->base_discover_list_protocols)(dev, protocols);
- return -EOPNOTSUPP;
+}
+int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_discover_agent)
- return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
- name);
- return -EOPNOTSUPP;
+}
+int scmi_base_notify_errors(struct udevice *dev, u32 enable) +{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_notify_errors)
- return (*ops->base_notify_errors)(dev, enable);
- return -EOPNOTSUPP;
+}
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_set_device_permissions)
- return (*ops->base_set_device_permissions)(dev, agent_id,
- device_id, flags);
- return -EOPNOTSUPP;
+}
+int scmi_base_set_protocol_permissions(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_set_protocol_permissions)
- return (*ops->base_set_protocol_permissions)(dev, agent_id,
- device_id,
- command_id,
- flags);
- return -EOPNOTSUPP;
+}
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
- u32 flags)
+{
- const struct scmi_base_ops *ops = device_get_ops(dev);
- if (ops->base_reset_agent_configuration)
- return (*ops->base_reset_agent_configuration)(dev, agent_id,
- flags);
- return -EOPNOTSUPP;
+}
+U_BOOT_DRIVER(scmi_base_drv) = {
- .id = UCLASS_SCMI_BASE,
- .name = "scmi_base_drv",
- .ops = &scmi_base_ops,
- .probe = scmi_base_probe,
+};
+UCLASS_DRIVER(scmi_base) = {
- .id = UCLASS_SCMI_BASE,
- .name = "scmi_base",
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931ca7..f7a110852321 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -116,6 +116,7 @@ enum uclass_id { UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */
- UCLASS_SCMI_BASE, /* Interface for SCMI Base protocol */
UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index a220cb2a91ad..64fd740472b5 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -49,6 +49,351 @@ enum scmi_discovery_id { SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2, }; +/*
- SCMI Base Protocol
- */
+#define SCMI_BASE_PROTOCOL_VERSION 0x20000
+enum scmi_base_message_id {
- SCMI_BASE_DISCOVER_VENDOR = 0x3,
- SCMI_BASE_DISCOVER_SUB_VENDOR = 0x4,
- SCMI_BASE_DISCOVER_IMPL_VERSION = 0x5,
- SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
- SCMI_BASE_DISCOVER_AGENT = 0x7,
- SCMI_BASE_NOTIFY_ERRORS = 0x8,
- SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x9,
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
- SCMI_BASE_RESET_AGENT_CONFIGURATION = 0xb,
+};
+#define SCMI_BASE_NAME_LENGTH_MAX 16
+/**
- struct scmi_protocol_version_out - Response for SCMI_PROTOCOL_VERSION
- command
- @status: SCMI command status
- @version: Protocol version
- */
+struct scmi_protocol_version_out {
- s32 status;
- u32 version;
+};
+/**
- struct scmi_protocol_attrs_out - Response for SCMI_PROTOCOL_ATTRIBUTES
- command
- @status: SCMI command status
- @attributes: Protocol attributes or implementation details
- */
+struct scmi_protocol_attrs_out {
- s32 status;
- u32 attributes;
+};
+#define SCMI_PROTOCOL_ATTRS_NUM_AGENTS(attributes) \
- (((attributes) & GENMASK(15, 8)) >> 8)
+#define SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(attributes) \
- ((attributes) & GENMASK(7, 0))
+/**
- struct scmi_protocol_msg_attrs_out - Response for
- SCMI_PROTOCOL_MESSAGE_ATTRIBUTES command
- @status: SCMI command status
- @attributes: Message-specific attributes
- */
+struct scmi_protocol_msg_attrs_out {
- s32 status;
- u32 attributes;
+};
+/**
- struct scmi_base_discover_vendor_out - Response for
- SCMI_BASE_DISCOVER_VENDOR or
- SCMI_BASE_DISCOVER_SUB_VENDOR command
- @status: SCMI command status
- @vendor_identifier: Name of vendor or sub-vendor in string
- */
+struct scmi_base_discover_vendor_out {
- s32 status;
- u8 vendor_identifier[SCMI_BASE_NAME_LENGTH_MAX];
+};
+/**
- struct scmi_base_discover_impl_version_out - Response for
- SCMI_BASE_DISCOVER_IMPL_VERSION command
- @status: SCMI command status
- @impl_version: Vendor-specific implementation version
- */
+struct scmi_base_discover_impl_version_out {
- s32 status;
- u32 impl_version;
+};
+/**
- struct scmi_base_discover_list_protocols_out - Response for
- SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
- @status: SCMI command status
- @num_protocols: Number of SCMI protocols in @protocol
- @protocols: Array of packed SCMI protocol ID's
- */
+struct scmi_base_discover_list_protocols_out {
- s32 status;
- u32 num_protocols;
- u32 protocols[3];
+};
+/**
- struct scmi_base_discover_agent_out - Response for
- SCMI_BASE_DISCOVER_AGENT command
- @status: SCMI command status
- @agent_id: SCMI agent ID
- @name: Name of agent in string
- */
+struct scmi_base_discover_agent_out {
- s32 status;
- u32 agent_id;
- u8 name[SCMI_BASE_NAME_LENGTH_MAX];
+};
+#define SCMI_BASE_NOTIFY_ERRORS_ENABLE BIT(0)
+/**
- struct scmi_base_set_device_permissions_in - Parameters for
- SCMI_BASE_SET_DEVICE_PERMISSIONS command
- @agent_id: SCMI agent ID
- @device_id: device ID
- @flags: A set of flags
- */
+struct scmi_base_set_device_permissions_in {
- u32 agent_id;
- u32 device_id;
- u32 flags;
+};
+#define SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS BIT(0)
+/**
- struct scmi_base_set_protocol_permissions_in - Parameters for
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
- @agent_id: SCMI agent ID
- @device_id: device ID
- @command_id: command ID
- @flags: A set of flags
- */
+struct scmi_base_set_protocol_permissions_in {
- u32 agent_id;
- u32 device_id;
- u32 command_id;
- u32 flags;
+};
+#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_COMMAND GENMASK(7, 0) +#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS BIT(0)
+/**
- struct scmi_base_reset_agent_configuration_in - Parameters for
- SCMI_BASE_RESET_AGENT_CONFIGURATION command
- @agent_id: SCMI agent ID
- @flags: A set of flags
- */
+struct scmi_base_reset_agent_configuration_in {
- u32 agent_id;
- u32 flags;
+};
+#define SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS BIT(0)
+/**
- struct scmi_base_ops - SCMI base protocol interfaces
- */
+struct scmi_base_ops {
- /**
- * protocol_version - get Base protocol version
- * @dev: SCMI device
- * @version: Pointer to SCMI protocol version
- *
- * Obtain the protocol version number in @version for Base protocol.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_version)(struct udevice *dev, u32 *version);
- /**
- * protocol_attrs - get protocol attributes
- * @dev: SCMI device
- * @num_agents: Number of SCMI agents
- * @num_protocols: Number of SCMI protocols
- *
- * Obtain the protocol attributes, the number of agents and the number
- * of protocols, in @num_agents and @num_protocols respectively, that
- * the device provides.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_attrs)(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols);
- /**
- * protocol_message_attrs - get message-specific attributes
- * @dev: SCMI device
- * @message_id: SCMI message ID
- * @attributes: Message-specific attributes
- *
- * Obtain the message-specific attributes in @attributes.
- * This command succeeds if the message is implemented and available.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*protocol_message_attrs)(struct udevice *dev, u32 message_id,
- u32 *attributes);
- /**
- * base_discover_vendor - get vendor name
- * @dev: SCMI device
- * @vendor: Vendor name
- *
- * Obtain the vendor's name in @vendor.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_vendor)(struct udevice *dev, u8 *vendor);
- /**
- * base_discover_sub_vendor - get sub-vendor name
- * @dev: SCMI device
- * @sub_vendor: Sub-vendor name
- *
- * Obtain the sub-vendor's name in @sub_vendor.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_sub_vendor)(struct udevice *dev, u8 *sub_vendor);
- /**
- * base_discover_impl_version - get implementation version
- * @dev: SCMI device
- * @impl_version: Pointer to implementation version
- *
- * Obtain the implementation version number in @impl_version.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_impl_version)(struct udevice *dev, u32 *impl_version);
- /**
- * base_discover_list_protocols - get list of protocols
- * @dev: SCMI device
- * @protocols: Pointer to array of SCMI protocols
- *
- * Obtain the list of protocols provided in @protocols.
- * The number of elements in @protocols always match to the number of
- * protocols returned by smci_protocol_attrs() when this function succeeds.
- * It is a caller's responsibility to free @protocols.
- *
- * Return: the number of protocols in @protocols on success, error code otherwise
- */
- int (*base_discover_list_protocols)(struct udevice *dev, u8 **protocols);
- /**
- * base_discover_agent - identify agent
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @ret_agent_id: Pointer to SCMI agent ID
- * @name: SCMI agent name
- *
- * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
- * this function returns the caller's agent id in @ret_agent_id.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_discover_agent)(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name);
- /**
- * base_notify_errors - configure error notification
- * @dev: SCMI device
- * @enable: Operation
- *
- * This function is not yet implemented.
- *
- * Return: always -EOPNOTSUPP
- */
- int (*base_notify_errors)(struct udevice *dev, u32 enable);
- /**
- * base_set_device_permissions - configure access permission to device
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @device_id: ID of device to access
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_set_device_permissions)(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
- /**
- * base_set_protocol_permissions - configure access permission to
- * protocol on device
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @device_id: ID of device to access
- * @command_id: command ID
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the protocol, @command_id,
- * on the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_set_protocol_permissions)(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 command_id,
- u32 flags);
- /**
- * base_reset_agent_configuration - reset resource settings
- * @dev: SCMI device
- * @agent_id: SCMI agent ID
- * @flags: A set of flags
- *
- * Ask for allowing or denying access permission to the protocol, @command_id,
- * on the device, @device_id.
- * The meaning of @flags is defined in SCMI specification.
- *
- * Return: 0 on success, error code otherwise
- */
- int (*base_reset_agent_configuration)(struct udevice *dev, u32 agent_id,
- u32 flags);
+};
+int scmi_base_protocol_version(struct udevice *dev, u32 *version); +int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
- u32 *num_protocols);
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
- u32 *attributes);
+int scmi_base_discover_vendor(struct udevice *dev, u8 *vendor); +int scmi_base_discover_sub_vendor(struct udevice *dev, u8 *sub_vendor); +int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version); +int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols); +int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
- u32 *ret_agent_id, u8 *name);
+int scmi_base_notify_errors(struct udevice *dev, u32 enable); +int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
- u32 device_id, u32 flags);
typo: duplicated declaration.
BR, Etienne
+int scmi_base_set_protocol_permissions(struct udevice *dev,
- u32 agent_id, u32 device_id,
- u32 command_id, u32 flags);
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
- u32 flags);
+/**
- scmi_generic_protocol_version - get protocol version
- @dev: SCMI device
- @id: SCMI protocol ID
- @version: Pointer to SCMI protocol version
- Obtain the protocol version number in @version.
- Return: 0 on success, error code otherwise
- */
+int scmi_generic_protocol_version(struct udevice *dev,
- enum scmi_std_protocol id, u32 *version);
/* * SCMI Clock Protocol */ -- 2.41.0

Move the location of scmi_bind_protocols() backward for changes in later patches. There is no change in functionality.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- drivers/firmware/scmi/scmi_agent-uclass.c | 118 +++++++++++----------- 1 file changed, 59 insertions(+), 59 deletions(-)
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 39cf15c88f75..8693e4c447b7 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -52,65 +52,6 @@ int scmi_to_linux_errno(s32 scmi_code) return -EPROTO; }
-/* - * SCMI agent devices binds devices of various uclasses depeding on - * the FDT description. scmi_bind_protocol() is a generic bind sequence - * called by the uclass at bind stage, that is uclass post_bind. - */ -static int scmi_bind_protocols(struct udevice *dev) -{ - int ret = 0; - ofnode node; - const char *name; - - dev_for_each_subnode(node, dev) { - struct driver *drv = NULL; - u32 protocol_id; - - if (!ofnode_is_enabled(node)) - continue; - - if (ofnode_read_u32(node, "reg", &protocol_id)) - continue; - - name = ofnode_get_name(node); - switch (protocol_id) { - case SCMI_PROTOCOL_ID_CLOCK: - if (CONFIG_IS_ENABLED(CLK_SCMI)) - drv = DM_DRIVER_GET(scmi_clock); - break; - case SCMI_PROTOCOL_ID_RESET_DOMAIN: - if (IS_ENABLED(CONFIG_RESET_SCMI)) - drv = DM_DRIVER_GET(scmi_reset_domain); - break; - case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: - if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) { - node = ofnode_find_subnode(node, "regulators"); - if (!ofnode_valid(node)) { - dev_err(dev, "no regulators node\n"); - return -ENXIO; - } - drv = DM_DRIVER_GET(scmi_voltage_domain); - } - break; - default: - break; - } - - if (!drv) { - dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", - protocol_id); - continue; - } - - ret = device_bind(dev, drv, name, NULL, node, NULL); - if (ret) - break; - } - - return ret; -} - static struct udevice *find_scmi_transport_device(struct udevice *dev) { struct udevice *parent = dev; @@ -208,6 +149,65 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); }
+/* + * SCMI agent devices binds devices of various uclasses depeding on + * the FDT description. scmi_bind_protocol() is a generic bind sequence + * called by the uclass at bind stage, that is uclass post_bind. + */ +static int scmi_bind_protocols(struct udevice *dev) +{ + int ret = 0; + ofnode node; + const char *name; + + dev_for_each_subnode(node, dev) { + struct driver *drv = NULL; + u32 protocol_id; + + if (!ofnode_is_enabled(node)) + continue; + + if (ofnode_read_u32(node, "reg", &protocol_id)) + continue; + + name = ofnode_get_name(node); + switch (protocol_id) { + case SCMI_PROTOCOL_ID_CLOCK: + if (CONFIG_IS_ENABLED(CLK_SCMI)) + drv = DM_DRIVER_GET(scmi_clock); + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + if (IS_ENABLED(CONFIG_RESET_SCMI)) + drv = DM_DRIVER_GET(scmi_reset_domain); + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) { + node = ofnode_find_subnode(node, "regulators"); + if (!ofnode_valid(node)) { + dev_err(dev, "no regulators node\n"); + return -ENXIO; + } + drv = DM_DRIVER_GET(scmi_voltage_domain); + } + break; + default: + break; + } + + if (!drv) { + dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", + protocol_id); + continue; + } + + ret = device_bind(dev, drv, name, NULL, node, NULL); + if (ret) + break; + } + + return ret; +} + UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent",

On Wed, 26 Jul 2023 at 02:38, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Move the location of scmi_bind_protocols() backward for changes in later patches. There is no change in functionality.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
drivers/firmware/scmi/scmi_agent-uclass.c | 118 +++++++++++----------- 1 file changed, 59 insertions(+), 59 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:37 Move the location of scmi_bind_protocols() backward for changes in later patches. There is no change in functionality.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
drivers/firmware/scmi/scmi_agent-uclass.c | 118 +++++++++++----------- 1 file changed, 59 insertions(+), 59 deletions(-)
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 39cf15c88f75..8693e4c447b7 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -52,65 +52,6 @@ int scmi_to_linux_errno(s32 scmi_code) return -EPROTO; } -/*
- SCMI agent devices binds devices of various uclasses depeding on
- the FDT description. scmi_bind_protocol() is a generic bind sequence
- called by the uclass at bind stage, that is uclass post_bind.
- */
-static int scmi_bind_protocols(struct udevice *dev) -{ - int ret = 0; - ofnode node; - const char *name;
- dev_for_each_subnode(node, dev) { - struct driver *drv = NULL; - u32 protocol_id;
- if (!ofnode_is_enabled(node)) - continue;
- if (ofnode_read_u32(node, "reg", &protocol_id)) - continue;
- name = ofnode_get_name(node); - switch (protocol_id) { - case SCMI_PROTOCOL_ID_CLOCK: - if (CONFIG_IS_ENABLED(CLK_SCMI)) - drv = DM_DRIVER_GET(scmi_clock); - break; - case SCMI_PROTOCOL_ID_RESET_DOMAIN: - if (IS_ENABLED(CONFIG_RESET_SCMI)) - drv = DM_DRIVER_GET(scmi_reset_domain); - break; - case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: - if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) { - node = ofnode_find_subnode(node, "regulators"); - if (!ofnode_valid(node)) { - dev_err(dev, "no regulators node\n"); - return -ENXIO; - } - drv = DM_DRIVER_GET(scmi_voltage_domain); - } - break; - default: - break; - }
- if (!drv) { - dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", - protocol_id); - continue; - }
- ret = device_bind(dev, drv, name, NULL, node, NULL); - if (ret) - break; - }
- return ret; -}
static struct udevice *find_scmi_transport_device(struct udevice *dev) { struct udevice *parent = dev; @@ -208,6 +149,65 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); } +/*
- SCMI agent devices binds devices of various uclasses depeding on
- the FDT description. scmi_bind_protocol() is a generic bind sequence
- called by the uclass at bind stage, that is uclass post_bind.
- */
+static int scmi_bind_protocols(struct udevice *dev) +{ + int ret = 0; + ofnode node; + const char *name;
+ dev_for_each_subnode(node, dev) { + struct driver *drv = NULL; + u32 protocol_id;
+ if (!ofnode_is_enabled(node)) + continue;
+ if (ofnode_read_u32(node, "reg", &protocol_id)) + continue;
+ name = ofnode_get_name(node); + switch (protocol_id) { + case SCMI_PROTOCOL_ID_CLOCK: + if (CONFIG_IS_ENABLED(CLK_SCMI)) + drv = DM_DRIVER_GET(scmi_clock); + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + if (IS_ENABLED(CONFIG_RESET_SCMI)) + drv = DM_DRIVER_GET(scmi_reset_domain); + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) { + node = ofnode_find_subnode(node, "regulators"); + if (!ofnode_valid(node)) { + dev_err(dev, "no regulators node\n"); + return -ENXIO; + } + drv = DM_DRIVER_GET(scmi_voltage_domain); + } + break; + default: + break; + }
+ if (!drv) { + dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", + protocol_id); + continue; + }
+ ret = device_bind(dev, drv, name, NULL, node, NULL); + if (ret) + break; + }
+ return ret; +}
UCLASS_DRIVER(scmi_agent) = { .id = UCLASS_SCMI_AGENT, .name = "scmi_agent", -- 2.41.0

This framework allows SCMI protocols to be installed and bound to the agent so that the agent can manage and utilize them later.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * check for availability of protocols --- drivers/firmware/scmi/scmi_agent-uclass.c | 100 +++++++++++++++++++++- include/scmi_agent-uclass.h | 15 +++- include/scmi_agent.h | 14 +++ 3 files changed, 125 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 8693e4c447b7..2244fcf487e8 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -38,6 +38,86 @@ static const struct error_code scmi_linux_errmap[] = { { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, };
+/* + * NOTE: The only one instance should exist according to + * the current specification and device tree bindings. + */ +struct udevice *scmi_agent; + +struct udevice *scmi_get_protocol(struct udevice *dev, + enum scmi_std_protocol id) +{ + struct scmi_agent_priv *priv; + struct udevice *proto; + + priv = dev_get_uclass_plat(dev); + if (!priv) { + dev_err(dev, "No priv data found\n"); + return NULL; + } + + switch (id) { + case SCMI_PROTOCOL_ID_CLOCK: + proto = priv->clock_dev; + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + proto = priv->resetdom_dev; + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + proto = priv->voltagedom_dev; + break; + default: + dev_err(dev, "Protocol not supported\n"); + proto = NULL; + break; + } + if (proto && device_probe(proto)) + dev_err(dev, "Probe failed\n"); + + return proto; +} + +/** + * scmi_add_protocol - add protocol to agent + * @dev: SCMI agent device + * @proto_id: SCMI protocol ID + * @proto: SCMI protocol device + * + * Associate the protocol instance, @proto, to the agent, @dev, + * for later use. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_add_protocol(struct udevice *dev, + enum scmi_std_protocol proto_id, + struct udevice *proto) +{ + struct scmi_agent_priv *priv; + + priv = dev_get_uclass_plat(dev); + if (!priv) { + dev_err(dev, "No priv data found\n"); + return -ENODEV; + } + + switch (proto_id) { + case SCMI_PROTOCOL_ID_CLOCK: + priv->clock_dev = proto; + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + priv->resetdom_dev = proto; + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + priv->voltagedom_dev = proto; + break; + default: + dev_err(dev, "Protocol not supported\n"); + return -EPROTO; + } + + return 0; +} + int scmi_to_linux_errno(s32 scmi_code) { int n; @@ -156,12 +236,14 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) */ static int scmi_bind_protocols(struct udevice *dev) { + struct udevice *agent; int ret = 0; ofnode node; const char *name; + struct driver *drv; + struct udevice *proto;
dev_for_each_subnode(node, dev) { - struct driver *drv = NULL; u32 protocol_id;
if (!ofnode_is_enabled(node)) @@ -170,6 +252,7 @@ static int scmi_bind_protocols(struct udevice *dev) if (ofnode_read_u32(node, "reg", &protocol_id)) continue;
+ drv = NULL; name = ofnode_get_name(node); switch (protocol_id) { case SCMI_PROTOCOL_ID_CLOCK: @@ -200,11 +283,22 @@ static int scmi_bind_protocols(struct udevice *dev) continue; }
- ret = device_bind(dev, drv, name, NULL, node, NULL); - if (ret) + ret = device_bind(dev, drv, name, NULL, node, &proto); + if (ret) { + dev_err(dev, "failed to bind %s protocol\n", drv->name); break; + } + ret = scmi_add_protocol(dev, protocol_id, proto); + if (ret) { + dev_err(dev, "failed to add protocol: %s, ret: %d\n", + proto->name, ret); + break; + } }
+ if (!ret) + scmi_agent = dev; + return ret; }
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index b1c93532c0ea..f9e7d3f51de1 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,10 +5,23 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H
-struct udevice; +#include <dm/device.h> + struct scmi_msg; struct scmi_channel;
+/** + * struct scmi_agent_priv - private data maintained by agent instance + * @clock_dev: SCMI clock protocol device + * @clock_dev: SCMI reset domain protocol device + * @clock_dev: SCMI voltage domain protocol device + */ +struct scmi_agent_priv { + struct udevice *clock_dev; + struct udevice *resetdom_dev; + struct udevice *voltagedom_dev; +}; + /** * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. */ diff --git a/include/scmi_agent.h b/include/scmi_agent.h index 577892029ff8..a5e7cf0592bc 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -11,6 +11,7 @@ #define SCMI_AGENT_H
#include <asm/types.h> +#include <scmi_protocols.h>
struct udevice; struct scmi_channel; @@ -74,6 +75,19 @@ int devm_scmi_of_get_channel(struct udevice *dev); */ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
+/** + * scmi_get_protocol() - get protocol instance + * + * @dev: SCMI agent device + * @id: SCMI protocol ID + * + * Obtain the device instance for given protocol ID, @id. + * + * Return: Pointer to the device if found, null otherwise + */ +struct udevice *scmi_get_protocol(struct udevice *dev, + enum scmi_std_protocol id); + /** * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code *

On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This framework allows SCMI protocols to be installed and bound to the agent so that the agent can manage and utilize them later.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- check for availability of protocols
drivers/firmware/scmi/scmi_agent-uclass.c | 100 +++++++++++++++++++++- include/scmi_agent-uclass.h | 15 +++- include/scmi_agent.h | 14 +++ 3 files changed, 125 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 This framework allows SCMI protocols to be installed and bound to the agent so that the agent can manage and utilize them later.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- check for availability of protocols
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com with 2 minor comments and with .per_device_plat_auto value set by this patch instead of from patch v2 01/12.
drivers/firmware/scmi/scmi_agent-uclass.c | 100 +++++++++++++++++++++- include/scmi_agent-uclass.h | 15 +++- include/scmi_agent.h | 14 +++ 3 files changed, 125 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 8693e4c447b7..2244fcf487e8 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -38,6 +38,86 @@ static const struct error_code scmi_linux_errmap[] = { { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, }; +/*
- NOTE: The only one instance should exist according to
- the current specification and device tree bindings.
- */
+struct udevice *scmi_agent;
+struct udevice *scmi_get_protocol(struct udevice *dev, + enum scmi_std_protocol id) +{ + struct scmi_agent_priv *priv; + struct udevice *proto;
+ priv = dev_get_uclass_plat(dev); + if (!priv) { + dev_err(dev, "No priv data found\n"); + return NULL; + }
+ switch (id) { + case SCMI_PROTOCOL_ID_CLOCK: + proto = priv->clock_dev; + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + proto = priv->resetdom_dev; + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + proto = priv->voltagedom_dev; + break; + default: + dev_err(dev, "Protocol not supported\n"); + proto = NULL; + break; + } + if (proto && device_probe(proto)) + dev_err(dev, "Probe failed\n");
+ return proto; +}
+/**
- scmi_add_protocol - add protocol to agent
- @dev: SCMI agent device
- @proto_id: SCMI protocol ID
- @proto: SCMI protocol device
- Associate the protocol instance, @proto, to the agent, @dev,
- for later use.
- Return: 0 on success, error code otherwise
- */
+static int scmi_add_protocol(struct udevice *dev, + enum scmi_std_protocol proto_id, + struct udevice *proto) +{ + struct scmi_agent_priv *priv;
+ priv = dev_get_uclass_plat(dev); + if (!priv) { + dev_err(dev, "No priv data found\n"); + return -ENODEV; + }
+ switch (proto_id) { + case SCMI_PROTOCOL_ID_CLOCK: + priv->clock_dev = proto; + break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + priv->resetdom_dev = proto; + break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + priv->voltagedom_dev = proto; + break; + default: + dev_err(dev, "Protocol not supported\n"); + return -EPROTO; + }
+ return 0; +}
int scmi_to_linux_errno(s32 scmi_code) { int n; @@ -156,12 +236,14 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) */ static int scmi_bind_protocols(struct udevice *dev) { + struct udevice *agent; int ret = 0; ofnode node; const char *name; + struct driver *drv; + struct udevice *proto; dev_for_each_subnode(node, dev) { - struct driver *drv = NULL; u32 protocol_id; if (!ofnode_is_enabled(node)) @@ -170,6 +252,7 @@ static int scmi_bind_protocols(struct udevice *dev) if (ofnode_read_u32(node, "reg", &protocol_id)) continue; + drv = NULL; name = ofnode_get_name(node); switch (protocol_id) { case SCMI_PROTOCOL_ID_CLOCK: @@ -200,11 +283,22 @@ static int scmi_bind_protocols(struct udevice *dev) continue; } - ret = device_bind(dev, drv, name, NULL, node, NULL); - if (ret) + ret = device_bind(dev, drv, name, NULL, node, &proto); + if (ret) { + dev_err(dev, "failed to bind %s protocol\n", drv->name); break; + } + ret = scmi_add_protocol(dev, protocol_id, proto); + if (ret) { + dev_err(dev, "failed to add protocol: %s, ret: %d\n", + proto->name, ret); + break; + } } + if (!ret) + scmi_agent = dev;
return ret; } diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index b1c93532c0ea..f9e7d3f51de1 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,10 +5,23 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H -struct udevice; +#include <dm/device.h>
struct scmi_msg; struct scmi_channel; +/**
- struct scmi_agent_priv - private data maintained by agent instance
- @clock_dev: SCMI clock protocol device
- @clock_dev: SCMI reset domain protocol device
- @clock_dev: SCMI voltage domain protocol device
- */
+struct scmi_agent_priv { + struct udevice *clock_dev; + struct udevice *resetdom_dev; + struct udevice *voltagedom_dev;
Nitpicking: typo on @clock_dev, fixed in next patch v2 05/12 of the series. Could be squashed here.
+};
/** * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. */ diff --git a/include/scmi_agent.h b/include/scmi_agent.h index 577892029ff8..a5e7cf0592bc 100644 --- a/include/scmi_agent.h +++ b/include/scmi_agent.h @@ -11,6 +11,7 @@ #define SCMI_AGENT_H #include <asm/types.h> +#include <scmi_protocols.h>
Should swap the 2 lines.
BR, Etienne
struct udevice; struct scmi_channel; @@ -74,6 +75,19 @@ int devm_scmi_of_get_channel(struct udevice *dev); */ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg); +/**
- scmi_get_protocol() - get protocol instance
- @dev: SCMI agent device
- @id: SCMI protocol ID
- Obtain the device instance for given protocol ID, @id.
- Return: Pointer to the device if found, null otherwise
- */
+struct udevice *scmi_get_protocol(struct udevice *dev, + enum scmi_std_protocol id);
/** * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code * -- 2.41.0

SCMI base protocol is mandatory, and once SCMI node is found in a device tree, the protocol handle (udevice) is unconditionally installed to the agent. Then basic information will be retrieved from SCMI server via the protocol and saved into the agent instance's local storage.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * use helper functions, removing direct uses of ops --- drivers/firmware/scmi/scmi_agent-uclass.c | 116 ++++++++++++++++++++++ include/scmi_agent-uclass.h | 70 ++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 2244fcf487e8..279c2c218913 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -57,6 +57,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev, }
switch (id) { + case SCMI_PROTOCOL_ID_BASE: + proto = priv->base_dev; + break; case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break; @@ -101,6 +104,9 @@ static int scmi_add_protocol(struct udevice *dev, }
switch (proto_id) { + case SCMI_PROTOCOL_ID_BASE: + priv->base_dev = proto; + break; case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break; @@ -229,6 +235,83 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); }
+/** + * scmi_fill_base_info - get base information about SCMI server + * @agent: SCMI agent device + * @dev: SCMI protocol device + * + * By using Base protocol commands, collect the base information + * about SCMI server. + * + * Return: 0 on success, error code otherwise + */ +static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev) +{ + struct scmi_agent_priv *priv = dev_get_uclass_plat(agent); + int ret; + + ret = scmi_base_protocol_version(dev, &priv->version); + if (ret) { + dev_err(dev, "protocol_version() failed (%d)\n", ret); + return ret; + } + /* check for required version */ + if (priv->version < SCMI_BASE_PROTOCOL_VERSION) { + dev_err(dev, "base protocol version (%d) lower than expected\n", + priv->version); + return -EPROTO; + } + + ret = scmi_base_protocol_attrs(dev, &priv->num_agents, + &priv->num_protocols); + if (ret) { + dev_err(dev, "protocol_attrs() failed (%d)\n", ret); + return ret; + } + ret = scmi_base_discover_vendor(dev, priv->vendor); + if (ret) { + dev_err(dev, "base_discover_vendor() failed (%d)\n", ret); + return ret; + } + ret = scmi_base_discover_sub_vendor(dev, priv->sub_vendor); + if (ret) { + if (ret != -EOPNOTSUPP) { + dev_err(dev, "base_discover_sub_vendor() failed (%d)\n", + ret); + return ret; + } + strcpy(priv->sub_vendor, "NA"); + } + ret = scmi_base_discover_impl_version(dev, &priv->impl_version); + if (ret) { + dev_err(dev, "base_discover_impl_version() failed (%d)\n", + ret); + return ret; + } + + priv->agent_id = 0xffffffff; /* to avoid false claim */ + ret = scmi_base_discover_agent(dev, 0xffffffff, + &priv->agent_id, priv->agent_name); + if (ret) { + if (ret != -EOPNOTSUPP) { + dev_err(dev, + "base_discover_agent() failed for myself (%d)\n", + ret); + return ret; + } + priv->agent_name[0] = '\0'; + } + + ret = scmi_base_discover_list_protocols(dev, &priv->protocols); + if (ret != priv->num_protocols) { + dev_err(dev, "base_discover_list_protocols() failed (%d)\n", + ret); + return ret; + } + + return 0; +} + /* * SCMI agent devices binds devices of various uclasses depeding on * the FDT description. scmi_bind_protocol() is a generic bind sequence @@ -243,6 +326,39 @@ static int scmi_bind_protocols(struct udevice *dev) struct driver *drv; struct udevice *proto;
+ if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) { + /* This is a second SCMI agent */ + dev_err(dev, "Cannot have more than one SCMI agent\n"); + return -EEXIST; + } + + /* initialize the device from device tree */ + drv = DM_DRIVER_GET(scmi_base_drv); + name = "scmi-base.0"; + ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto); + if (ret) { + dev_err(dev, "failed to bind base protocol\n"); + return ret; + } + ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto); + if (ret) { + dev_err(dev, "failed to add protocol: %s, ret: %d\n", + proto->name, ret); + return ret; + } + + ret = device_probe(proto); + if (ret) { + dev_err(dev, "failed to probe base protocol\n"); + return ret; + } + + ret = scmi_fill_base_info(dev, proto); + if (ret) { + dev_err(dev, "failed to get base information\n"); + return ret; + } + dev_for_each_subnode(node, dev) { u32 protocol_id;
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index f9e7d3f51de1..0043a93c8d90 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,6 +5,7 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H
+#include <scmi_protocols.h> #include <dm/device.h>
struct scmi_msg; @@ -12,16 +13,81 @@ struct scmi_channel;
/** * struct scmi_agent_priv - private data maintained by agent instance + * @version: Version + * @num_agents: Number of agents + * @num_protocols: Number of protocols + * @impl_version: Implementation version + * @protocols: Array of protocol IDs + * @vendor: Vendor name + * @sub_vendor: Sub-vendor name + * @agent_name: Agent name + * agent_id: Identifier of agent + * @base_dev: SCMI base protocol device * @clock_dev: SCMI clock protocol device - * @clock_dev: SCMI reset domain protocol device - * @clock_dev: SCMI voltage domain protocol device + * @resetdom_dev: SCMI reset domain protocol device + * @voltagedom_dev: SCMI voltage domain protocol device */ struct scmi_agent_priv { + u32 version; + u32 num_agents; + u32 num_protocols; + u32 impl_version; + u8 *protocols; + u8 vendor[SCMI_BASE_NAME_LENGTH_MAX]; + u8 sub_vendor[SCMI_BASE_NAME_LENGTH_MAX]; + u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX]; + u32 agent_id; + struct udevice *base_dev; struct udevice *clock_dev; struct udevice *resetdom_dev; struct udevice *voltagedom_dev; };
+static inline u32 scmi_version(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version; +} + +static inline u32 scmi_num_agents(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents; +} + +static inline u32 scmi_num_protocols(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols; +} + +static inline u32 scmi_impl_version(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version; +} + +static inline u8 *scmi_protocols(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols; +} + +static inline u8 *scmi_vendor(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor; +} + +static inline u8 *scmi_sub_vendor(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor; +} + +static inline u8 *scmi_agent_name(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name; +} + +static inline u32 scmi_agent_id(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id; +} + /** * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. */

Hi,
On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
SCMI base protocol is mandatory, and once SCMI node is found in a device tree, the protocol handle (udevice) is unconditionally installed to the agent. Then basic information will be retrieved from SCMI server via the protocol and saved into the agent instance's local storage.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
drivers/firmware/scmi/scmi_agent-uclass.c | 116 ++++++++++++++++++++++ include/scmi_agent-uclass.h | 70 ++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 2244fcf487e8..279c2c218913 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -57,6 +57,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev, }
switch (id) {
case SCMI_PROTOCOL_ID_BASE:
proto = priv->base_dev;
break; case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break;
@@ -101,6 +104,9 @@ static int scmi_add_protocol(struct udevice *dev, }
switch (proto_id) {
case SCMI_PROTOCOL_ID_BASE:
priv->base_dev = proto;
break; case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break;
@@ -229,6 +235,83 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); }
+/**
- scmi_fill_base_info - get base information about SCMI server
- @agent: SCMI agent device
- @dev: SCMI protocol device
- By using Base protocol commands, collect the base information
- about SCMI server.
- Return: 0 on success, error code otherwise
- */
+static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev) +{
struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
int ret;
ret = scmi_base_protocol_version(dev, &priv->version);
if (ret) {
dev_err(dev, "protocol_version() failed (%d)\n", ret);
return ret;
}
/* check for required version */
if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
dev_err(dev, "base protocol version (%d) lower than expected\n",
priv->version);
return -EPROTO;
}
ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
&priv->num_protocols);
if (ret) {
dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_vendor(dev, priv->vendor);
if (ret) {
dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_sub_vendor(dev, priv->sub_vendor);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
ret);
return ret;
}
strcpy(priv->sub_vendor, "NA");
}
ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
if (ret) {
dev_err(dev, "base_discover_impl_version() failed (%d)\n",
ret);
return ret;
}
priv->agent_id = 0xffffffff; /* to avoid false claim */
ret = scmi_base_discover_agent(dev, 0xffffffff,
&priv->agent_id, priv->agent_name);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev,
"base_discover_agent() failed for myself (%d)\n",
ret);
return ret;
}
priv->agent_name[0] = '\0';
}
ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
if (ret != priv->num_protocols) {
dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
ret);
return ret;
}
return 0;
+}
/*
- SCMI agent devices binds devices of various uclasses depeding on
- the FDT description. scmi_bind_protocol() is a generic bind sequence
@@ -243,6 +326,39 @@ static int scmi_bind_protocols(struct udevice *dev) struct driver *drv; struct udevice *proto;
if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
/* This is a second SCMI agent */
dev_err(dev, "Cannot have more than one SCMI agent\n");
return -EEXIST;
}
/* initialize the device from device tree */
drv = DM_DRIVER_GET(scmi_base_drv);
name = "scmi-base.0";
ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
Why is this not in the devicetree too?
if (ret) {
dev_err(dev, "failed to bind base protocol\n");
return ret;
}
ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
if (ret) {
dev_err(dev, "failed to add protocol: %s, ret: %d\n",
proto->name, ret);
return ret;
}
ret = device_probe(proto);
if (ret) {
dev_err(dev, "failed to probe base protocol\n");
return ret;
}
ret = scmi_fill_base_info(dev, proto);
if (ret) {
dev_err(dev, "failed to get base information\n");
return ret;
}
dev_for_each_subnode(node, dev) { u32 protocol_id;
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index f9e7d3f51de1..0043a93c8d90 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,6 +5,7 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H
+#include <scmi_protocols.h> #include <dm/device.h>
struct scmi_msg; @@ -12,16 +13,81 @@ struct scmi_channel;
/**
- struct scmi_agent_priv - private data maintained by agent instance
- @version: Version
- @num_agents: Number of agents
- @num_protocols: Number of protocols
- @impl_version: Implementation version
- @protocols: Array of protocol IDs
- @vendor: Vendor name
- @sub_vendor: Sub-vendor name
- @agent_name: Agent name
- agent_id: Identifier of agent
- @base_dev: SCMI base protocol device
- @clock_dev: SCMI clock protocol device
- @clock_dev: SCMI reset domain protocol device
- @clock_dev: SCMI voltage domain protocol device
- @resetdom_dev: SCMI reset domain protocol device
*/
- @voltagedom_dev: SCMI voltage domain protocol device
struct scmi_agent_priv {
u32 version;
u32 num_agents;
u32 num_protocols;
u32 impl_version;
u8 *protocols;
u8 vendor[SCMI_BASE_NAME_LENGTH_MAX];
u8 sub_vendor[SCMI_BASE_NAME_LENGTH_MAX];
u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX];
u32 agent_id;
struct udevice *base_dev; struct udevice *clock_dev; struct udevice *resetdom_dev; struct udevice *voltagedom_dev;
};
+static inline u32 scmi_version(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version;
+}
+static inline u32 scmi_num_agents(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents;
+}
+static inline u32 scmi_num_protocols(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols;
+}
+static inline u32 scmi_impl_version(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version;
+}
+static inline u8 *scmi_protocols(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols;
+}
+static inline u8 *scmi_vendor(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor;
+}
+static inline u8 *scmi_sub_vendor(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor;
+}
+static inline u8 *scmi_agent_name(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name;
+}
+static inline u32 scmi_agent_id(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
+}
Why these helper functions? It seems better to avoid inlining access to dev_get_uclass_plat(). Are you worried about exposing the priv struct to clients?
/**
- struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
*/
2.41.0
Regards, Simon

Hi Simon,
Thank you for your extensive review.
On Wed, Jul 26, 2023 at 06:50:23PM -0600, Simon Glass wrote:
Hi,
On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
SCMI base protocol is mandatory, and once SCMI node is found in a device tree, the protocol handle (udevice) is unconditionally installed to the agent. Then basic information will be retrieved from SCMI server via the protocol and saved into the agent instance's local storage.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
drivers/firmware/scmi/scmi_agent-uclass.c | 116 ++++++++++++++++++++++ include/scmi_agent-uclass.h | 70 ++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 2244fcf487e8..279c2c218913 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -57,6 +57,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev, }
switch (id) {
case SCMI_PROTOCOL_ID_BASE:
proto = priv->base_dev;
break; case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break;
@@ -101,6 +104,9 @@ static int scmi_add_protocol(struct udevice *dev, }
switch (proto_id) {
case SCMI_PROTOCOL_ID_BASE:
priv->base_dev = proto;
break; case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break;
@@ -229,6 +235,83 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); }
+/**
- scmi_fill_base_info - get base information about SCMI server
- @agent: SCMI agent device
- @dev: SCMI protocol device
- By using Base protocol commands, collect the base information
- about SCMI server.
- Return: 0 on success, error code otherwise
- */
+static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev) +{
struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
int ret;
ret = scmi_base_protocol_version(dev, &priv->version);
if (ret) {
dev_err(dev, "protocol_version() failed (%d)\n", ret);
return ret;
}
/* check for required version */
if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
dev_err(dev, "base protocol version (%d) lower than expected\n",
priv->version);
return -EPROTO;
}
ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
&priv->num_protocols);
if (ret) {
dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_vendor(dev, priv->vendor);
if (ret) {
dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_sub_vendor(dev, priv->sub_vendor);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
ret);
return ret;
}
strcpy(priv->sub_vendor, "NA");
}
ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
if (ret) {
dev_err(dev, "base_discover_impl_version() failed (%d)\n",
ret);
return ret;
}
priv->agent_id = 0xffffffff; /* to avoid false claim */
ret = scmi_base_discover_agent(dev, 0xffffffff,
&priv->agent_id, priv->agent_name);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev,
"base_discover_agent() failed for myself (%d)\n",
ret);
return ret;
}
priv->agent_name[0] = '\0';
}
ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
if (ret != priv->num_protocols) {
dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
ret);
return ret;
}
return 0;
+}
/*
- SCMI agent devices binds devices of various uclasses depeding on
- the FDT description. scmi_bind_protocol() is a generic bind sequence
@@ -243,6 +326,39 @@ static int scmi_bind_protocols(struct udevice *dev) struct driver *drv; struct udevice *proto;
if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
/* This is a second SCMI agent */
dev_err(dev, "Cannot have more than one SCMI agent\n");
return -EEXIST;
}
/* initialize the device from device tree */
drv = DM_DRIVER_GET(scmi_base_drv);
name = "scmi-base.0";
ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
Why is this not in the devicetree too?
I don't know the history of discussions, but it is because no binding for the base protocol is necessary, I guess, as it is a mandatory protocol without any customisable parameters. Please see kernel's Documentation/devicetree/bindings/firmware/arm,scmi.yaml.
if (ret) {
dev_err(dev, "failed to bind base protocol\n");
return ret;
}
ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
if (ret) {
dev_err(dev, "failed to add protocol: %s, ret: %d\n",
proto->name, ret);
return ret;
}
ret = device_probe(proto);
if (ret) {
dev_err(dev, "failed to probe base protocol\n");
return ret;
}
ret = scmi_fill_base_info(dev, proto);
if (ret) {
dev_err(dev, "failed to get base information\n");
return ret;
}
dev_for_each_subnode(node, dev) { u32 protocol_id;
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index f9e7d3f51de1..0043a93c8d90 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,6 +5,7 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H
+#include <scmi_protocols.h> #include <dm/device.h>
struct scmi_msg; @@ -12,16 +13,81 @@ struct scmi_channel;
/**
- struct scmi_agent_priv - private data maintained by agent instance
- @version: Version
- @num_agents: Number of agents
- @num_protocols: Number of protocols
- @impl_version: Implementation version
- @protocols: Array of protocol IDs
- @vendor: Vendor name
- @sub_vendor: Sub-vendor name
- @agent_name: Agent name
- agent_id: Identifier of agent
- @base_dev: SCMI base protocol device
- @clock_dev: SCMI clock protocol device
- @clock_dev: SCMI reset domain protocol device
- @clock_dev: SCMI voltage domain protocol device
- @resetdom_dev: SCMI reset domain protocol device
*/
- @voltagedom_dev: SCMI voltage domain protocol device
struct scmi_agent_priv {
u32 version;
u32 num_agents;
u32 num_protocols;
u32 impl_version;
u8 *protocols;
u8 vendor[SCMI_BASE_NAME_LENGTH_MAX];
u8 sub_vendor[SCMI_BASE_NAME_LENGTH_MAX];
u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX];
u32 agent_id;
struct udevice *base_dev; struct udevice *clock_dev; struct udevice *resetdom_dev; struct udevice *voltagedom_dev;
};
+static inline u32 scmi_version(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version;
+}
+static inline u32 scmi_num_agents(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents;
+}
+static inline u32 scmi_num_protocols(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols;
+}
+static inline u32 scmi_impl_version(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version;
+}
+static inline u8 *scmi_protocols(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols;
+}
+static inline u8 *scmi_vendor(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor;
+}
+static inline u8 *scmi_sub_vendor(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor;
+}
+static inline u8 *scmi_agent_name(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name;
+}
+static inline u32 scmi_agent_id(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
+}
Why these helper functions? It seems better to avoid inlining access to dev_get_uclass_plat(). Are you worried about exposing the priv struct to clients?
Well, simply wanted to avoid repeating "((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->)" in the code.
Thanks, -Takahiro Akashi
/**
- struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
*/
2.41.0
Regards, Simon

Hi,
On Wed, 26 Jul 2023 at 19:07, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Simon,
Thank you for your extensive review.
Cheers.
On Wed, Jul 26, 2023 at 06:50:23PM -0600, Simon Glass wrote:
Hi,
On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
SCMI base protocol is mandatory, and once SCMI node is found in a device tree, the protocol handle (udevice) is unconditionally installed to the agent. Then basic information will be retrieved from SCMI server via the protocol and saved into the agent instance's local storage.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
drivers/firmware/scmi/scmi_agent-uclass.c | 116 ++++++++++++++++++++++ include/scmi_agent-uclass.h | 70 ++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
[..]
+static inline u32 scmi_agent_id(struct udevice *dev) +{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
+}
Why these helper functions? It seems better to avoid inlining access to dev_get_uclass_plat(). Are you worried about exposing the priv struct to clients?
Well, simply wanted to avoid repeating "((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->)" in the code.
That's fine, so long as it would not be better for the caller to obtain the priv pointer and just access the fields in the struct,
Regards, Simon

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Thursday, July 27, 2023 03:07 Hi Simon,
Thank you for your extensive review.
On Wed, Jul 26, 2023 at 06:50:23PM -0600, Simon Glass wrote:
Hi,
On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
SCMI base protocol is mandatory, and once SCMI node is found in a device tree, the protocol handle (udevice) is unconditionally installed to the agent. Then basic information will be retrieved from SCMI server via the protocol and saved into the agent instance's local storage.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
drivers/firmware/scmi/scmi_agent-uclass.c | 116 ++++++++++++++++++++++ include/scmi_agent-uclass.h | 70 ++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com with below reported typo preferrably addressed.
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 2244fcf487e8..279c2c218913 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -57,6 +57,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev, }
switch (id) { + case SCMI_PROTOCOL_ID_BASE: + proto = priv->base_dev; + break; case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break; @@ -101,6 +104,9 @@ static int scmi_add_protocol(struct udevice *dev, }
switch (proto_id) { + case SCMI_PROTOCOL_ID_BASE: + priv->base_dev = proto; + break; case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break; @@ -229,6 +235,83 @@ int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) return scmi_process_msg(parent, priv->channel, msg); }
+/**
- scmi_fill_base_info - get base information about SCMI server
- @agent: SCMI agent device
- @dev: SCMI protocol device
- By using Base protocol commands, collect the base information
- about SCMI server.
- Return: 0 on success, error code otherwise
- */
+static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev) +{ + struct scmi_agent_priv *priv = dev_get_uclass_plat(agent); + int ret;
+ ret = scmi_base_protocol_version(dev, &priv->version); + if (ret) { + dev_err(dev, "protocol_version() failed (%d)\n", ret); + return ret; + } + /* check for required version */ + if (priv->version < SCMI_BASE_PROTOCOL_VERSION) { + dev_err(dev, "base protocol version (%d) lower than expected\n", + priv->version); + return -EPROTO; + }
+ ret = scmi_base_protocol_attrs(dev, &priv->num_agents, + &priv->num_protocols); + if (ret) { + dev_err(dev, "protocol_attrs() failed (%d)\n", ret); + return ret; + } + ret = scmi_base_discover_vendor(dev, priv->vendor); + if (ret) { + dev_err(dev, "base_discover_vendor() failed (%d)\n", ret); + return ret; + } + ret = scmi_base_discover_sub_vendor(dev, priv->sub_vendor); + if (ret) { + if (ret != -EOPNOTSUPP) { + dev_err(dev, "base_discover_sub_vendor() failed (%d)\n", + ret); + return ret; + } + strcpy(priv->sub_vendor, "NA"); + } + ret = scmi_base_discover_impl_version(dev, &priv->impl_version); + if (ret) { + dev_err(dev, "base_discover_impl_version() failed (%d)\n", + ret); + return ret; + }
+ priv->agent_id = 0xffffffff; /* to avoid false claim */ + ret = scmi_base_discover_agent(dev, 0xffffffff, + &priv->agent_id, priv->agent_name); + if (ret) { + if (ret != -EOPNOTSUPP) { + dev_err(dev, + "base_discover_agent() failed for myself (%d)\n", + ret); + return ret; + } + priv->agent_name[0] = '\0'; + }
+ ret = scmi_base_discover_list_protocols(dev, &priv->protocols); + if (ret != priv->num_protocols) { + dev_err(dev, "base_discover_list_protocols() failed (%d)\n", + ret); + return ret; + }
+ return 0; +}
/* * SCMI agent devices binds devices of various uclasses depeding on * the FDT description. scmi_bind_protocol() is a generic bind sequence @@ -243,6 +326,39 @@ static int scmi_bind_protocols(struct udevice *dev) struct driver *drv; struct udevice *proto;
+ if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) { + /* This is a second SCMI agent */ + dev_err(dev, "Cannot have more than one SCMI agent\n"); + return -EEXIST; + }
+ /* initialize the device from device tree */ + drv = DM_DRIVER_GET(scmi_base_drv); + name = "scmi-base.0"; + ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
Why is this not in the devicetree too?
I don't know the history of discussions, but it is because no binding for the base protocol is necessary, I guess, as it is a mandatory protocol without any customisable parameters. Please see kernel's Documentation/devicetree/bindings/firmware/arm,scmi.yaml.
+ if (ret) { + dev_err(dev, "failed to bind base protocol\n"); + return ret; + } + ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto); + if (ret) { + dev_err(dev, "failed to add protocol: %s, ret: %d\n", + proto->name, ret); + return ret; + }
+ ret = device_probe(proto); + if (ret) { + dev_err(dev, "failed to probe base protocol\n"); + return ret; + }
+ ret = scmi_fill_base_info(dev, proto); + if (ret) { + dev_err(dev, "failed to get base information\n"); + return ret; + }
dev_for_each_subnode(node, dev) { u32 protocol_id;
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h index f9e7d3f51de1..0043a93c8d90 100644 --- a/include/scmi_agent-uclass.h +++ b/include/scmi_agent-uclass.h @@ -5,6 +5,7 @@ #ifndef _SCMI_AGENT_UCLASS_H #define _SCMI_AGENT_UCLASS_H
+#include <scmi_protocols.h> #include <dm/device.h>
struct scmi_msg; @@ -12,16 +13,81 @@ struct scmi_channel;
/** * struct scmi_agent_priv - private data maintained by agent instance
- @version: Version
- @num_agents: Number of agents
- @num_protocols: Number of protocols
- @impl_version: Implementation version
- @protocols: Array of protocol IDs
- @vendor: Vendor name
- @sub_vendor: Sub-vendor name
- @agent_name: Agent name
- agent_id: Identifier of agent
typo: s/agent_id/@agent_id/
- @base_dev: SCMI base protocol device
* @clock_dev: SCMI clock protocol device
- @clock_dev: SCMI reset domain protocol device
- @clock_dev: SCMI voltage domain protocol device
- @resetdom_dev: SCMI reset domain protocol device
- @voltagedom_dev: SCMI voltage domain protocol device
*/ struct scmi_agent_priv { + u32 version; + u32 num_agents; + u32 num_protocols; + u32 impl_version; + u8 *protocols; + u8 vendor[SCMI_BASE_NAME_LENGTH_MAX]; + u8 sub_vendor[SCMI_BASE_NAME_LENGTH_MAX]; + u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX]; + u32 agent_id; + struct udevice *base_dev; struct udevice *clock_dev; struct udevice *resetdom_dev; struct udevice *voltagedom_dev; };
+static inline u32 scmi_version(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version; +}
+static inline u32 scmi_num_agents(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents; +}
+static inline u32 scmi_num_protocols(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols; +}
+static inline u32 scmi_impl_version(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version; +}
+static inline u8 *scmi_protocols(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols; +}
+static inline u8 *scmi_vendor(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor; +}
+static inline u8 *scmi_sub_vendor(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor; +}
+static inline u8 *scmi_agent_name(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name; +}
+static inline u32 scmi_agent_id(struct udevice *dev) +{ + return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id; +}
Why these helper functions? It seems better to avoid inlining access to dev_get_uclass_plat(). Are you worried about exposing the priv struct to clients?
Well, simply wanted to avoid repeating "((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->)" in the code.
Thanks, -Takahiro Akashi
/** * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. */ -- 2.41.0
Regards, Simon

SCMI base protocol is mandatory and doesn't need to be listed in a device tree.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- arch/sandbox/dts/test.dts | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index ff9f9222e6f9..2aad94681148 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -682,10 +682,6 @@ #address-cells = <1>; #size-cells = <0>;
- protocol@10 { - reg = <0x10>; - }; - clk_scmi: protocol@14 { reg = <0x14>; #clock-cells = <1>;

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 SCMI base protocol is mandatory and doesn't need to be listed in a device tree.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
arch/sandbox/dts/test.dts | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index ff9f9222e6f9..2aad94681148 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -682,10 +682,6 @@ #address-cells = <1>; #size-cells = <0>; - protocol@10 { - reg = <0x10>; - };
clk_scmi: protocol@14 { reg = <0x14>; #clock-cells = <1>; -- 2.41.0

This is a simple implementation of SCMI base protocol for sandbox. The main use is in SCMI unit test.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- drivers/firmware/scmi/sandbox-scmi_agent.c | 359 ++++++++++++++++++++- 1 file changed, 358 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 031882998dfa..1f0261ea5c94 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -14,11 +14,14 @@ #include <asm/io.h> #include <asm/scmi_test.h> #include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/kernel.h>
/* * The sandbox SCMI agent driver simulates to some extend a SCMI message * processing. It simulates few of the SCMI services for some of the * SCMI protocols embedded in U-Boot. Currently: + * - SCMI base protocol * - SCMI clock protocol emulates an agent exposing 2 clocks * - SCMI reset protocol emulates an agent exposing a reset controller * - SCMI voltage domain protocol emulates an agent exposing 2 regulators @@ -33,6 +36,21 @@ * various uclass devices, as clocks and reset controllers. */
+#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION +#define SANDBOX_SCMI_VENDOR "U-Boot" +#define SANDBOX_SCMI_SUB_VENDOR "Sandbox" +#define SANDBOX_SCMI_IMPL_VERSION 0x1 +#define SANDBOX_SCMI_AGENT_NAME "OSPM" +#define SANDBOX_SCMI_PLATFORM_NAME "platform" + +static u8 protocols[] = { + SCMI_PROTOCOL_ID_CLOCK, + SCMI_PROTOCOL_ID_RESET_DOMAIN, + SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, +}; + +#define NUM_PROTOCOLS ARRAY_SIZE(protocols) + static struct sandbox_scmi_clk scmi_clk[] = { { .rate = 333 }, { .rate = 200 }, @@ -114,6 +132,316 @@ static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id) * Sandbox SCMI agent ops */
+/* Base Protocol */ + +/** + * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_PROTOCOL_VERSION command. + */ +static int sandbox_scmi_base_protocol_version(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_protocol_version_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_protocol_version_out *)msg->out_msg; + out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION; + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command. + */ +static int sandbox_scmi_base_protocol_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_protocol_attrs_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_protocol_attrs_out *)msg->out_msg; + out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS; + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_message_attrs - implement + * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command. + */ +static int sandbox_scmi_base_message_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + u32 message_id; + struct scmi_protocol_msg_attrs_out *out = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + message_id = *(u32 *)msg->in_msg; + out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg; + + if (message_id >= SCMI_PROTOCOL_VERSION && + message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION && + message_id != SCMI_BASE_NOTIFY_ERRORS) { + out->attributes = 0; + out->status = SCMI_SUCCESS; + } else { + out->status = SCMI_NOT_FOUND; + } + + return 0; +} + +/** + * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_DISCOVER_VENDOR command + */ +static int sandbox_scmi_base_discover_vendor(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_vendor_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_base_discover_vendor_out *)msg->out_msg; + strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR); + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_discover_sub_vendor - implement + * SCMI_BASE_DISCOVER_SUB_VENDOR + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command + */ +static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_vendor_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_base_discover_vendor_out *)msg->out_msg; + strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR); + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_discover_impl_version - implement + * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command + */ +static int sandbox_scmi_base_discover_impl_version(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_impl_version_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_base_discover_impl_version_out *)msg->out_msg; + out->impl_version = SANDBOX_SCMI_IMPL_VERSION; + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_discover_list_protocols - implement + * SCMI_BASE_DISCOVER_LIST_PROTOCOLS + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command + */ +static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_list_protocols_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg; + memcpy(out->protocols, protocols, sizeof(protocols)); + out->num_protocols = NUM_PROTOCOLS; + out->status = SCMI_SUCCESS; + + return 0; +} + +/** + * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_DISCOVER_AGENT command + */ +static int sandbox_scmi_base_discover_agent(struct udevice *dev, + struct scmi_msg *msg) +{ + u32 agent_id; + struct scmi_base_discover_agent_out *out = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + agent_id = *(u32 *)msg->in_msg; + out = (struct scmi_base_discover_agent_out *)msg->out_msg; + out->status = SCMI_SUCCESS; + if (agent_id == 0xffffffff || agent_id == 1) { + out->agent_id = 1; + strcpy(out->name, SANDBOX_SCMI_AGENT_NAME); + } else if (!agent_id) { + out->agent_id = agent_id; + strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME); + } else { + out->status = SCMI_NOT_FOUND; + } + + return 0; +} + +/** + * sandbox_scmi_base_set_device_permissions - implement + * SCMI_BASE_SET_DEVICE_PERMISSIONS + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command + */ +static int sandbox_scmi_base_set_device_permissions(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_set_device_permissions_in *in = NULL; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_base_set_device_permissions_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + if (in->agent_id != 1 || in->device_id != 0) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS) + *status = SCMI_INVALID_PARAMETERS; + else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED; + + return 0; +} + +/** + * sandbox_scmi_base_set_protocol_permissions - implement + * SCMI_BASE_SET_PROTOCOL_PERMISSIONS + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command + */ +static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_set_protocol_permissions_in *in = NULL; + u32 *status; + int i; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + for (i = 0; i < ARRAY_SIZE(protocols); i++) + if (protocols[i] == in->command_id) + break; + if (in->agent_id != 1 || in->device_id != 0 || + i == ARRAY_SIZE(protocols)) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS) + *status = SCMI_INVALID_PARAMETERS; + else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED; + + return 0; +} + +/** + * sandbox_scmi_base_reset_agent_configuration - implement + * SCMI_BASE_RESET_AGENT_CONFIGURATION + * @udevice: SCMI device + * @msg: SCMI message + * + * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command + */ +static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_reset_agent_configuration_in *in = NULL; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + if (in->agent_id != 1) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS) + *status = SCMI_INVALID_PARAMETERS; + else + *status = SCMI_DENIED; + + return 0; +} + +/* Clock Protocol */ + static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev, struct scmi_msg *msg) { @@ -475,6 +803,36 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_msg *msg) { switch (msg->protocol_id) { + case SCMI_PROTOCOL_ID_BASE: + switch (msg->message_id) { + case SCMI_PROTOCOL_VERSION: + return sandbox_scmi_base_protocol_version(dev, msg); + case SCMI_PROTOCOL_ATTRIBUTES: + return sandbox_scmi_base_protocol_attrs(dev, msg); + case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES: + return sandbox_scmi_base_message_attrs(dev, msg); + case SCMI_BASE_DISCOVER_VENDOR: + return sandbox_scmi_base_discover_vendor(dev, msg); + case SCMI_BASE_DISCOVER_SUB_VENDOR: + return sandbox_scmi_base_discover_sub_vendor(dev, msg); + case SCMI_BASE_DISCOVER_IMPL_VERSION: + return sandbox_scmi_base_discover_impl_version(dev, msg); + case SCMI_BASE_DISCOVER_LIST_PROTOCOLS: + return sandbox_scmi_base_discover_list_protocols(dev, msg); + case SCMI_BASE_DISCOVER_AGENT: + return sandbox_scmi_base_discover_agent(dev, msg); + case SCMI_BASE_NOTIFY_ERRORS: + break; + case SCMI_BASE_SET_DEVICE_PERMISSIONS: + return sandbox_scmi_base_set_device_permissions(dev, msg); + case SCMI_BASE_SET_PROTOCOL_PERMISSIONS: + return sandbox_scmi_base_set_protocol_permissions(dev, msg); + case SCMI_BASE_RESET_AGENT_CONFIGURATION: + return sandbox_scmi_base_reset_agent_configuration(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_CLOCK: switch (msg->message_id) { case SCMI_PROTOCOL_ATTRIBUTES: @@ -517,7 +875,6 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, break; } break; - case SCMI_PROTOCOL_ID_BASE: case SCMI_PROTOCOL_ID_POWER_DOMAIN: case SCMI_PROTOCOL_ID_SYSTEM: case SCMI_PROTOCOL_ID_PERF:

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 This is a simple implementation of SCMI base protocol for sandbox. The main use is in SCMI unit test.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com with reported typo addressed.
drivers/firmware/scmi/sandbox-scmi_agent.c | 359 ++++++++++++++++++++- 1 file changed, 358 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 031882998dfa..1f0261ea5c94 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -14,11 +14,14 @@ #include <asm/io.h> #include <asm/scmi_test.h> #include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/kernel.h> /* * The sandbox SCMI agent driver simulates to some extend a SCMI message * processing. It simulates few of the SCMI services for some of the * SCMI protocols embedded in U-Boot. Currently:
- SCMI base protocol
* - SCMI clock protocol emulates an agent exposing 2 clocks * - SCMI reset protocol emulates an agent exposing a reset controller * - SCMI voltage domain protocol emulates an agent exposing 2 regulators @@ -33,6 +36,21 @@ * various uclass devices, as clocks and reset controllers. */ +#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION +#define SANDBOX_SCMI_VENDOR "U-Boot" +#define SANDBOX_SCMI_SUB_VENDOR "Sandbox" +#define SANDBOX_SCMI_IMPL_VERSION 0x1 +#define SANDBOX_SCMI_AGENT_NAME "OSPM" +#define SANDBOX_SCMI_PLATFORM_NAME "platform"
+static u8 protocols[] = { + SCMI_PROTOCOL_ID_CLOCK, + SCMI_PROTOCOL_ID_RESET_DOMAIN, + SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, +};
+#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
static struct sandbox_scmi_clk scmi_clk[] = { { .rate = 333 }, { .rate = 200 }, @@ -114,6 +132,316 @@ static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id) * Sandbox SCMI agent ops */ +/* Base Protocol */
+/**
- sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
- @udevice: SCMI device
typo: s/udevice/dev/g here and in the other function inline descripion comments below.
BR, etienne
- @msg: SCMI message
- Implement SCMI_BASE_PROTOCOL_VERSION command.
- */
+static int sandbox_scmi_base_protocol_version(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_protocol_version_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_protocol_version_out *)msg->out_msg; + out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION; + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
- */
+static int sandbox_scmi_base_protocol_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_protocol_attrs_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_protocol_attrs_out *)msg->out_msg; + out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS; + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_message_attrs - implement
- * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
- */
+static int sandbox_scmi_base_message_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + u32 message_id; + struct scmi_protocol_msg_attrs_out *out = NULL;
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ message_id = *(u32 *)msg->in_msg; + out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
+ if (message_id >= SCMI_PROTOCOL_VERSION && + message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION && + message_id != SCMI_BASE_NOTIFY_ERRORS) { + out->attributes = 0; + out->status = SCMI_SUCCESS; + } else { + out->status = SCMI_NOT_FOUND; + }
+ return 0; +}
+/**
- sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_DISCOVER_VENDOR command
- */
+static int sandbox_scmi_base_discover_vendor(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_vendor_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_base_discover_vendor_out *)msg->out_msg; + strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR); + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_discover_sub_vendor - implement
- * SCMI_BASE_DISCOVER_SUB_VENDOR
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
- */
+static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_vendor_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_base_discover_vendor_out *)msg->out_msg; + strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR); + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_discover_impl_version - implement
- * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
- */
+static int sandbox_scmi_base_discover_impl_version(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_impl_version_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_base_discover_impl_version_out *)msg->out_msg; + out->impl_version = SANDBOX_SCMI_IMPL_VERSION; + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_discover_list_protocols - implement
- * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
- */
+static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_discover_list_protocols_out *out = NULL;
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg; + memcpy(out->protocols, protocols, sizeof(protocols)); + out->num_protocols = NUM_PROTOCOLS; + out->status = SCMI_SUCCESS;
+ return 0; +}
+/**
- sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_DISCOVER_AGENT command
- */
+static int sandbox_scmi_base_discover_agent(struct udevice *dev, + struct scmi_msg *msg) +{ + u32 agent_id; + struct scmi_base_discover_agent_out *out = NULL;
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL;
+ agent_id = *(u32 *)msg->in_msg; + out = (struct scmi_base_discover_agent_out *)msg->out_msg; + out->status = SCMI_SUCCESS; + if (agent_id == 0xffffffff || agent_id == 1) { + out->agent_id = 1; + strcpy(out->name, SANDBOX_SCMI_AGENT_NAME); + } else if (!agent_id) { + out->agent_id = agent_id; + strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME); + } else { + out->status = SCMI_NOT_FOUND; + }
+ return 0; +}
+/**
- sandbox_scmi_base_set_device_permissions - implement
- * SCMI_BASE_SET_DEVICE_PERMISSIONS
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
- */
+static int sandbox_scmi_base_set_device_permissions(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_set_device_permissions_in *in = NULL; + u32 *status;
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL;
+ in = (struct scmi_base_set_device_permissions_in *)msg->in_msg; + status = (u32 *)msg->out_msg;
+ if (in->agent_id != 1 || in->device_id != 0) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS) + *status = SCMI_INVALID_PARAMETERS; + else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED;
+ return 0; +}
+/**
- sandbox_scmi_base_set_protocol_permissions - implement
- * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
- */
+static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_set_protocol_permissions_in *in = NULL; + u32 *status; + int i;
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL;
+ in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg; + status = (u32 *)msg->out_msg;
+ for (i = 0; i < ARRAY_SIZE(protocols); i++) + if (protocols[i] == in->command_id) + break; + if (in->agent_id != 1 || in->device_id != 0 || + i == ARRAY_SIZE(protocols)) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS) + *status = SCMI_INVALID_PARAMETERS; + else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED;
+ return 0; +}
+/**
- sandbox_scmi_base_reset_agent_configuration - implement
- * SCMI_BASE_RESET_AGENT_CONFIGURATION
- @udevice: SCMI device
- @msg: SCMI message
- Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
- */
+static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_base_reset_agent_configuration_in *in = NULL; + u32 *status;
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL;
+ in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg; + status = (u32 *)msg->out_msg;
+ if (in->agent_id != 1) + *status = SCMI_NOT_FOUND; + else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS) + *status = SCMI_INVALID_PARAMETERS; + else + *status = SCMI_DENIED;
+ return 0; +}
+/* Clock Protocol */
static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev, struct scmi_msg *msg) { @@ -475,6 +803,36 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_msg *msg) { switch (msg->protocol_id) { + case SCMI_PROTOCOL_ID_BASE: + switch (msg->message_id) { + case SCMI_PROTOCOL_VERSION: + return sandbox_scmi_base_protocol_version(dev, msg); + case SCMI_PROTOCOL_ATTRIBUTES: + return sandbox_scmi_base_protocol_attrs(dev, msg); + case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES: + return sandbox_scmi_base_message_attrs(dev, msg); + case SCMI_BASE_DISCOVER_VENDOR: + return sandbox_scmi_base_discover_vendor(dev, msg); + case SCMI_BASE_DISCOVER_SUB_VENDOR: + return sandbox_scmi_base_discover_sub_vendor(dev, msg); + case SCMI_BASE_DISCOVER_IMPL_VERSION: + return sandbox_scmi_base_discover_impl_version(dev, msg); + case SCMI_BASE_DISCOVER_LIST_PROTOCOLS: + return sandbox_scmi_base_discover_list_protocols(dev, msg); + case SCMI_BASE_DISCOVER_AGENT: + return sandbox_scmi_base_discover_agent(dev, msg); + case SCMI_BASE_NOTIFY_ERRORS: + break; + case SCMI_BASE_SET_DEVICE_PERMISSIONS: + return sandbox_scmi_base_set_device_permissions(dev, msg); + case SCMI_BASE_SET_PROTOCOL_PERMISSIONS: + return sandbox_scmi_base_set_protocol_permissions(dev, msg); + case SCMI_BASE_RESET_AGENT_CONFIGURATION: + return sandbox_scmi_base_reset_agent_configuration(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_CLOCK: switch (msg->message_id) { case SCMI_PROTOCOL_ATTRIBUTES: @@ -517,7 +875,6 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, break; } break; - case SCMI_PROTOCOL_ID_BASE: case SCMI_PROTOCOL_ID_POWER_DOMAIN: case SCMI_PROTOCOL_ID_SYSTEM: case SCMI_PROTOCOL_ID_PERF: -- 2.41.0

Adding SCMI base protocol makes it inconvenient to hold the agent instance (udevice) locally since the agent device will be re-created per each test. Just remove it and simplify the test flows. The test scenario is not changed at all.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- arch/sandbox/include/asm/scmi_test.h | 7 ++- drivers/firmware/scmi/sandbox-scmi_agent.c | 20 +------ drivers/firmware/scmi/scmi_agent-uclass.c | 3 - test/dm/scmi.c | 64 +++++++--------------- 4 files changed, 26 insertions(+), 68 deletions(-)
diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h index c72ec1e1cb25..2718336a9a50 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -89,10 +89,11 @@ struct sandbox_scmi_devices {
#ifdef CONFIG_SCMI_FIRMWARE /** - * sandbox_scmi_service_ctx - Get the simulated SCMI services context + * sandbox_scmi_agent_ctx - Get the simulated SCMI agent context + * @dev: Reference to the test agent * @return: Reference to backend simulated resources state */ -struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); +struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev);
/** * sandbox_scmi_devices_ctx - Get references to devices accessed through SCMI @@ -101,7 +102,7 @@ struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); */ struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev); #else -static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +static struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev) { return NULL; } diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 1f0261ea5c94..ab8afb01de40 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -66,11 +66,9 @@ static struct sandbox_scmi_voltd scmi_voltd[] = { { .id = 1, .voltage_uv = 1800000 }, };
-static struct sandbox_scmi_service sandbox_scmi_service_state; - -struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev) { - return &sandbox_scmi_service_state; + return dev_get_priv(dev); }
static void debug_print_agent_state(struct udevice *dev, char *str) @@ -898,16 +896,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
static int sandbox_scmi_test_remove(struct udevice *dev) { - struct sandbox_scmi_agent *agent = dev_get_priv(dev); - - if (agent != sandbox_scmi_service_ctx()->agent) - return -EINVAL; - debug_print_agent_state(dev, "removed");
- /* We only need to dereference the agent in the context */ - sandbox_scmi_service_ctx()->agent = NULL; - return 0; }
@@ -915,9 +905,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev) { struct sandbox_scmi_agent *agent = dev_get_priv(dev);
- if (sandbox_scmi_service_ctx()->agent) - return -EINVAL; - *agent = (struct sandbox_scmi_agent){ .clk = scmi_clk, .clk_count = ARRAY_SIZE(scmi_clk), @@ -929,9 +916,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
debug_print_agent_state(dev, "probed");
- /* Save reference for tests purpose */ - sandbox_scmi_service_ctx()->agent = agent; - return 0; };
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 279c2c218913..91cb172f3005 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -412,9 +412,6 @@ static int scmi_bind_protocols(struct udevice *dev) } }
- if (!ret) - scmi_agent = dev; - return ret; }
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index d87e2731ce42..881be3171b7c 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -23,22 +23,11 @@ #include <power/regulator.h> #include <test/ut.h>
-static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts) -{ - struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); - - ut_assertnonnull(scmi_ctx); - ut_assertnull(scmi_ctx->agent); - - return 0; -} - static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, + struct sandbox_scmi_agent *agent, struct udevice *dev) { struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent;
/* Device references to check context against test sequence */ scmi_devices = sandbox_scmi_devices_ctx(dev); @@ -48,10 +37,6 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, ut_asserteq(2, scmi_devices->regul_count);
/* State of the simulated SCMI server exposed */ - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); ut_asserteq(3, agent->clk_count); ut_assertnonnull(agent->clk); ut_asserteq(1, agent->reset_count); @@ -63,27 +48,32 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, }
static int load_sandbox_scmi_test_devices(struct unit_test_state *uts, + struct sandbox_scmi_agent **ctx, struct udevice **dev) { - int ret; + struct udevice *agent_dev;
- ret = ut_assert_scmi_state_preprobe(uts); - if (ret) - return ret; + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + + *ctx = sandbox_scmi_agent_ctx(agent_dev); + ut_assertnonnull(*ctx);
+ /* probe */ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi", dev)); ut_assertnonnull(*dev);
- return ut_assert_scmi_state_postprobe(uts, *dev); + return ut_assert_scmi_state_postprobe(uts, *ctx, *dev); }
static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, struct udevice *dev) { + /* un-probe */ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
- /* Not sure test devices are fully removed, agent may not be visible */ return 0; }
@@ -93,10 +83,11 @@ static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, */ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) { + struct sandbox_scmi_agent *ctx; struct udevice *dev = NULL; int ret;
- ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &ctx, &dev); if (!ret) ret = release_sandbox_scmi_test_devices(uts, dev);
@@ -106,23 +97,18 @@ DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_clocks(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct udevice *dev; int ret_dev; int ret;
- ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret;
scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent);
/* Test SCMI clocks rate manipulation */ ut_asserteq(333, agent->clk[0].rate); @@ -169,22 +155,17 @@ DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_resets(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct udevice *dev = NULL; int ret;
- ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret;
scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent);
/* Test SCMI resect controller manipulation */ ut_assert(!agent->reset[0].asserted); @@ -201,21 +182,16 @@ DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct dm_regulator_uclass_plat *uc_pdata; struct udevice *dev; struct udevice *regul0_dev;
- ut_assertok(load_sandbox_scmi_test_devices(uts, &dev)); + ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev));
scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent);
/* Set/Get an SCMI voltage domain level */ regul0_dev = scmi_devices->regul[0];

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 Adding SCMI base protocol makes it inconvenient to hold the agent instance (udevice) locally since the agent device will be re-created per each test. Just remove it and simplify the test flows. The test scenario is not changed at all.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
arch/sandbox/include/asm/scmi_test.h | 7 ++- drivers/firmware/scmi/sandbox-scmi_agent.c | 20 +------ drivers/firmware/scmi/scmi_agent-uclass.c | 3 - test/dm/scmi.c | 64 +++++++--------------- 4 files changed, 26 insertions(+), 68 deletions(-)
diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h index c72ec1e1cb25..2718336a9a50 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -89,10 +89,11 @@ struct sandbox_scmi_devices { #ifdef CONFIG_SCMI_FIRMWARE /**
- sandbox_scmi_service_ctx - Get the simulated SCMI services context
- sandbox_scmi_agent_ctx - Get the simulated SCMI agent context
- @dev: Reference to the test agent
* @return: Reference to backend simulated resources state */ -struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); +struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev); /** * sandbox_scmi_devices_ctx - Get references to devices accessed through SCMI @@ -101,7 +102,7 @@ struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); */ struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev); #else -static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +static struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev) { return NULL; } diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 1f0261ea5c94..ab8afb01de40 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -66,11 +66,9 @@ static struct sandbox_scmi_voltd scmi_voltd[] = { { .id = 1, .voltage_uv = 1800000 }, }; -static struct sandbox_scmi_service sandbox_scmi_service_state;
-struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev) { - return &sandbox_scmi_service_state; + return dev_get_priv(dev); } static void debug_print_agent_state(struct udevice *dev, char *str) @@ -898,16 +896,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, static int sandbox_scmi_test_remove(struct udevice *dev) { - struct sandbox_scmi_agent *agent = dev_get_priv(dev);
- if (agent != sandbox_scmi_service_ctx()->agent) - return -EINVAL;
debug_print_agent_state(dev, "removed"); - /* We only need to dereference the agent in the context */ - sandbox_scmi_service_ctx()->agent = NULL;
return 0; } @@ -915,9 +905,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev) { struct sandbox_scmi_agent *agent = dev_get_priv(dev); - if (sandbox_scmi_service_ctx()->agent) - return -EINVAL;
*agent = (struct sandbox_scmi_agent){ .clk = scmi_clk, .clk_count = ARRAY_SIZE(scmi_clk), @@ -929,9 +916,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev) debug_print_agent_state(dev, "probed"); - /* Save reference for tests purpose */ - sandbox_scmi_service_ctx()->agent = agent;
return 0; }; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 279c2c218913..91cb172f3005 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -412,9 +412,6 @@ static int scmi_bind_protocols(struct udevice *dev) } } - if (!ret) - scmi_agent = dev;
return ret; } diff --git a/test/dm/scmi.c b/test/dm/scmi.c index d87e2731ce42..881be3171b7c 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -23,22 +23,11 @@ #include <power/regulator.h> #include <test/ut.h> -static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts) -{ - struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx();
- ut_assertnonnull(scmi_ctx); - ut_assertnull(scmi_ctx->agent);
- return 0; -}
static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, + struct sandbox_scmi_agent *agent, struct udevice *dev) { struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent; /* Device references to check context against test sequence */ scmi_devices = sandbox_scmi_devices_ctx(dev); @@ -48,10 +37,6 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, ut_asserteq(2, scmi_devices->regul_count); /* State of the simulated SCMI server exposed */ - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); ut_asserteq(3, agent->clk_count); ut_assertnonnull(agent->clk); ut_asserteq(1, agent->reset_count); @@ -63,27 +48,32 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, } static int load_sandbox_scmi_test_devices(struct unit_test_state *uts, + struct sandbox_scmi_agent **ctx, struct udevice **dev) { - int ret; + struct udevice *agent_dev; - ret = ut_assert_scmi_state_preprobe(uts); - if (ret) - return ret; + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev);
+ *ctx = sandbox_scmi_agent_ctx(agent_dev); + ut_assertnonnull(*ctx); + /* probe */ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi", dev)); ut_assertnonnull(*dev); - return ut_assert_scmi_state_postprobe(uts, *dev); + return ut_assert_scmi_state_postprobe(uts, *ctx, *dev); } static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, struct udevice *dev) { + /* un-probe */ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); - /* Not sure test devices are fully removed, agent may not be visible */ return 0; } @@ -93,10 +83,11 @@ static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, */ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) { + struct sandbox_scmi_agent *ctx; struct udevice *dev = NULL; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &ctx, &dev); if (!ret) ret = release_sandbox_scmi_test_devices(uts, dev); @@ -106,23 +97,18 @@ DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT); static int dm_test_scmi_clocks(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct udevice *dev; int ret_dev; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); /* Test SCMI clocks rate manipulation */ ut_asserteq(333, agent->clk[0].rate); @@ -169,22 +155,17 @@ DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT); static int dm_test_scmi_resets(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct udevice *dev = NULL; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); /* Test SCMI resect controller manipulation */ ut_assert(!agent->reset[0].asserted); @@ -201,21 +182,16 @@ DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT); static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct dm_regulator_uclass_plat *uc_pdata; struct udevice *dev; struct udevice *regul0_dev; - ut_assertok(load_sandbox_scmi_test_devices(uts, &dev)); + ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev)); scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); /* Set/Get an SCMI voltage domain level */ regul0_dev = scmi_devices->regul[0]; -- 2.41.0

Added is a new unit test for SCMI base protocol, which will exercise all the commands provided by the protocol, except SCMI_BASE_NOTIFY_ERRORS. $ ut dm scmi_base It is assumed that test.dtb is used as sandbox's device tree.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * use helper functions, removing direct uses of ops --- test/dm/scmi.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index 881be3171b7c..41d46548f7fd 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -16,6 +16,9 @@ #include <clk.h> #include <dm.h> #include <reset.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> #include <asm/scmi_test.h> #include <dm/device-internal.h> #include <dm/test.h> @@ -95,6 +98,112 @@ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) } DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);
+static int dm_test_scmi_base(struct unit_test_state *uts) +{ + struct udevice *agent_dev, *base; + struct scmi_agent_priv *priv; + u32 version, num_agents, num_protocols, impl_version; + u32 attributes, agent_id; + char vendor[SCMI_BASE_NAME_LENGTH_MAX], + agent_name[SCMI_BASE_NAME_LENGTH_MAX]; + u8 *protocols; + int ret; + + /* preparation */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + ut_assertnonnull(priv = dev_get_uclass_plat(agent_dev)); + ut_assertnonnull(base = scmi_get_protocol(agent_dev, + SCMI_PROTOCOL_ID_BASE)); + + /* version */ + ret = scmi_base_protocol_version(base, &version); + ut_assertok(ret); + ut_asserteq(priv->version, version); + + /* protocol attributes */ + ret = scmi_base_protocol_attrs(base, &num_agents, &num_protocols); + ut_assertok(ret); + ut_asserteq(priv->num_agents, num_agents); + ut_asserteq(priv->num_protocols, num_protocols); + + /* discover vendor */ + ret = scmi_base_discover_vendor(base, vendor); + ut_assertok(ret); + ut_asserteq_str(priv->vendor, vendor); + + /* message attributes */ + ret = scmi_protocol_message_attrs(base, + SCMI_BASE_DISCOVER_SUB_VENDOR, + &attributes); + ut_assertok(ret); + ut_assertok(attributes); + + /* discover sub vendor */ + ret = scmi_base_discover_sub_vendor(base, vendor); + ut_assertok(ret); + ut_asserteq_str(priv->sub_vendor, vendor); + + /* impl version */ + ret = scmi_base_discover_impl_version(base, &impl_version); + ut_assertok(ret); + ut_asserteq(priv->impl_version, impl_version); + + /* discover agent (my self) */ + ret = scmi_base_discover_agent(base, 0xffffffff, &agent_id, agent_name); + ut_assertok(ret); + ut_asserteq(priv->agent_id, agent_id); + ut_asserteq_str(priv->agent_name, agent_name); + + /* discover protocols */ + ret = scmi_base_discover_list_protocols(base, &protocols); + ut_asserteq(num_protocols, ret); + ut_asserteq_mem(priv->protocols, protocols, sizeof(u8) * num_protocols); + free(protocols); + + /* + * NOTE: Sandbox SCMI driver handles device-0 only. It supports setting + * access and protocol permissions, but doesn't allow unsetting them nor + * resetting the configurations. + */ + /* set device permissions */ + ret = scmi_base_set_device_permissions(base, agent_id, 0, + SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS); + ut_assertok(ret); /* SCMI_SUCCESS */ + ret = scmi_base_set_device_permissions(base, agent_id, 1, + SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS); + ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */ + ret = scmi_base_set_device_permissions(base, agent_id, 0, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + /* set protocol permissions */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 0, + SCMI_PROTOCOL_ID_CLOCK, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS); + ut_assertok(ret); /* SCMI_SUCCESS */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 1, + SCMI_PROTOCOL_ID_CLOCK, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS); + ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 0, + SCMI_PROTOCOL_ID_CLOCK, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + /* reset agent configuration */ + ret = scmi_base_reset_agent_configuration(base, agent_id, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + ret = scmi_base_reset_agent_configuration(base, agent_id, + SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + ret = scmi_base_reset_agent_configuration(base, agent_id, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + return 0; +} + +DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT); + static int dm_test_scmi_clocks(struct unit_test_state *uts) { struct sandbox_scmi_agent *agent;

\On Wed, 26 Jul 2023 at 02:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Added is a new unit test for SCMI base protocol, which will exercise all the commands provided by the protocol, except SCMI_BASE_NOTIFY_ERRORS. $ ut dm scmi_base It is assumed that test.dtb is used as sandbox's device tree.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
test/dm/scmi.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 Added is a new unit test for SCMI base protocol, which will exercise all the commands provided by the protocol, except SCMI_BASE_NOTIFY_ERRORS. $ ut dm scmi_base It is assumed that test.dtb is used as sandbox's device tree.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- use helper functions, removing direct uses of ops
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com with reported issue fixed.
test/dm/scmi.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index 881be3171b7c..41d46548f7fd 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -16,6 +16,9 @@ #include <clk.h> #include <dm.h> #include <reset.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> #include <asm/scmi_test.h> #include <dm/device-internal.h> #include <dm/test.h> @@ -95,6 +98,112 @@ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) } DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT); +static int dm_test_scmi_base(struct unit_test_state *uts) +{
- struct udevice *agent_dev, *base;
- struct scmi_agent_priv *priv;
- u32 version, num_agents, num_protocols, impl_version;
- u32 attributes, agent_id;
- char vendor[SCMI_BASE_NAME_LENGTH_MAX],
- agent_name[SCMI_BASE_NAME_LENGTH_MAX];
- u8 *protocols;
- int ret;
- /* preparation */
- ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
- &agent_dev));
- ut_assertnonnull(agent_dev);
- ut_assertnonnull(priv = dev_get_uclass_plat(agent_dev));
- ut_assertnonnull(base = scmi_get_protocol(agent_dev,
- SCMI_PROTOCOL_ID_BASE));
- /* version */
- ret = scmi_base_protocol_version(base, &version);
- ut_assertok(ret);
- ut_asserteq(priv->version, version);
- /* protocol attributes */
- ret = scmi_base_protocol_attrs(base, &num_agents, &num_protocols);
Typo: s/scmi_base_protocol_attrs/scmi_base_protocol_message_attrs/
This issue is fixed in patch 12/12 but should be squashed here to prevent a build error.
BR, etienne
- ut_assertok(ret);
- ut_asserteq(priv->num_agents, num_agents);
- ut_asserteq(priv->num_protocols, num_protocols);
- /* discover vendor */
- ret = scmi_base_discover_vendor(base, vendor);
- ut_assertok(ret);
- ut_asserteq_str(priv->vendor, vendor);
- /* message attributes */
- ret = scmi_protocol_message_attrs(base,
- SCMI_BASE_DISCOVER_SUB_VENDOR,
- &attributes);
- ut_assertok(ret);
- ut_assertok(attributes);
- /* discover sub vendor */
- ret = scmi_base_discover_sub_vendor(base, vendor);
- ut_assertok(ret);
- ut_asserteq_str(priv->sub_vendor, vendor);
- /* impl version */
- ret = scmi_base_discover_impl_version(base, &impl_version);
- ut_assertok(ret);
- ut_asserteq(priv->impl_version, impl_version);
- /* discover agent (my self) */
- ret = scmi_base_discover_agent(base, 0xffffffff, &agent_id, agent_name);
- ut_assertok(ret);
- ut_asserteq(priv->agent_id, agent_id);
- ut_asserteq_str(priv->agent_name, agent_name);
- /* discover protocols */
- ret = scmi_base_discover_list_protocols(base, &protocols);
- ut_asserteq(num_protocols, ret);
- ut_asserteq_mem(priv->protocols, protocols, sizeof(u8) * num_protocols);
- free(protocols);
- /*
- * NOTE: Sandbox SCMI driver handles device-0 only. It supports setting
- * access and protocol permissions, but doesn't allow unsetting them nor
- * resetting the configurations.
- */
- /* set device permissions */
- ret = scmi_base_set_device_permissions(base, agent_id, 0,
- SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
- ut_assertok(ret); /* SCMI_SUCCESS */
- ret = scmi_base_set_device_permissions(base, agent_id, 1,
- SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
- ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
- ret = scmi_base_set_device_permissions(base, agent_id, 0, 0);
- ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
- /* set protocol permissions */
- ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
- SCMI_PROTOCOL_ID_CLOCK,
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
- ut_assertok(ret); /* SCMI_SUCCESS */
- ret = scmi_base_set_protocol_permissions(base, agent_id, 1,
- SCMI_PROTOCOL_ID_CLOCK,
- SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
- ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
- ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
- SCMI_PROTOCOL_ID_CLOCK, 0);
- ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
- /* reset agent configuration */
- ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
- ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
- ret = scmi_base_reset_agent_configuration(base, agent_id,
- SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS);
- ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
- ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
- ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
- return 0;
+}
+DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_clocks(struct unit_test_state *uts) { struct sandbox_scmi_agent *agent; -- 2.41.0

This command, "scmi", may provide a command line interface to various SCMI protocols. It supports at least initially SCMI base protocol and is intended mainly for debug purpose.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * remove sub command category, 'scmi base', for simplicity --- cmd/Kconfig | 9 ++ cmd/Makefile | 1 + cmd/scmi.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 cmd/scmi.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 02e54f1e50fe..15d1d7b9863f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2504,6 +2504,15 @@ config CMD_CROS_EC a number of sub-commands for performing EC tasks such as updating its flash, accessing a small saved context area and talking to the I2C bus behind the EC (if there is one). + +config CMD_SCMI + bool "Enable scmi command" + depends on SCMI_FIRMWARE + default n + help + This command provides user interfaces to several SCMI (System + Control and Management Interface) protocols available on Arm + platforms to manage system resources. endmenu
menu "Filesystem commands" diff --git a/cmd/Makefile b/cmd/Makefile index 6c37521b4e2b..826e0b74b587 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_CMD_SATA) += sata.o obj-$(CONFIG_CMD_NVME) += nvme.o obj-$(CONFIG_SANDBOX) += sb.o obj-$(CONFIG_CMD_SF) += sf.o +obj-$(CONFIG_CMD_SCMI) += scmi.o obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o obj-$(CONFIG_CMD_SEAMA) += seama.o diff --git a/cmd/scmi.c b/cmd/scmi.c new file mode 100644 index 000000000000..5ecd9051b48d --- /dev/null +++ b/cmd/scmi.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SCMI (System Control and Management Interface) utility command + * + * Copyright (c) 2023 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include <common.h> +#include <command.h> +#include <exports.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <asm/types.h> +#include <dm/device.h> +#include <dm/uclass.h> /* uclass_get_device */ +#include <linux/bitfield.h> +#include <linux/bitops.h> + +static struct udevice *agent; +static struct udevice *base_proto; + +struct { + enum scmi_std_protocol id; + const char *name; +} protocol_name[] = { + {SCMI_PROTOCOL_ID_BASE, "Base"}, + {SCMI_PROTOCOL_ID_POWER_DOMAIN, "Power domain management"}, + {SCMI_PROTOCOL_ID_SYSTEM, "System power management"}, + {SCMI_PROTOCOL_ID_PERF, "Performance domain management"}, + {SCMI_PROTOCOL_ID_CLOCK, "Clock management"}, + {SCMI_PROTOCOL_ID_SENSOR, "Sensor management"}, + {SCMI_PROTOCOL_ID_RESET_DOMAIN, "Reset domain management"}, + {SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, "Voltage domain management"}, +}; + +/** + * get_proto_name() - get the name of SCMI protocol + * + * @id: SCMI Protocol ID + * + * Get the printable name of the protocol, @id + * + * Return: Name string on success, NULL on failure + */ +static const char *get_proto_name(enum scmi_std_protocol id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(protocol_name); i++) + if (id == protocol_name[i].id) + return protocol_name[i].name; + + return NULL; +} + +/** + * do_scmi_info() - get the information of SCMI services + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * + * Get the information of SCMI services using various interfaces + * provided by the Base protocol. + * + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + */ +static int do_scmi_info(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, num_protocols; + u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX], *protocols; + int i, ret; + + if (argc != 1) + return CMD_RET_USAGE; + + printf("SCMI device: %s\n", agent->name); + printf(" protocol version: 0x%x\n", scmi_version(agent)); + printf(" # of agents: %d\n", scmi_num_agents(agent)); + for (i = 0; i < scmi_num_agents(agent); i++) { + ret = scmi_base_discover_agent(base_proto, i, &agent_id, + agent_name); + if (ret) { + if (ret != -EOPNOTSUPP) + printf("base_discover_agent() failed for id: %d (%d)\n", + i, ret); + break; + } + printf(" %c%2d: %s\n", i == scmi_agent_id(agent) ? '>' : ' ', + i, agent_name); + } + printf(" # of protocols: %d\n", scmi_num_protocols(agent)); + num_protocols = scmi_num_protocols(agent); + protocols = scmi_protocols(agent); + if (protocols) + for (i = 0; i < num_protocols; i++) + printf(" %s\n", get_proto_name(protocols[i])); + printf(" vendor: %s\n", scmi_vendor(agent)); + printf(" sub vendor: %s\n", scmi_sub_vendor(agent)); + printf(" impl version: 0x%x\n", scmi_impl_version(agent)); + + return CMD_RET_SUCCESS; +} + +/** + * do_scmi_set_dev() - set access permission to device + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * + * Set access permission to device with SCMI_BASE_SET_DEVICE_PERMISSIONS + * + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + */ +static int do_scmi_set_dev(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, device_id, flags, attributes; + char *end; + int ret; + + if (argc != 4) + return CMD_RET_USAGE; + + agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + device_id = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + flags = simple_strtoul(argv[3], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_SET_DEVICE_PERMISSIONS, + &attributes); + if (ret) { + printf("This operation is not supported\n"); + return CMD_RET_FAILURE; + } + + ret = scmi_base_set_device_permissions(base_proto, agent_id, + device_id, flags); + if (ret) { + printf("%s access to device:%u failed (%d)\n", + flags ? "Allowing" : "Denying", device_id, ret); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +/** + * do_scmi_set_proto() - set protocol permission to device + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * + * Set protocol permission to device with SCMI_BASE_SET_PROTOCOL_PERMISSIONS + * + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + */ +static int do_scmi_set_proto(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, device_id, protocol_id, flags, attributes; + char *end; + int ret; + + if (argc != 5) + return CMD_RET_USAGE; + + agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + device_id = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + protocol_id = simple_strtoul(argv[3], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + flags = simple_strtoul(argv[4], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS, + &attributes); + if (ret) { + printf("This operation is not supported\n"); + return CMD_RET_FAILURE; + } + + ret = scmi_base_set_protocol_permissions(base_proto, agent_id, + device_id, protocol_id, + flags); + if (ret) { + printf("%s access to protocol:0x%x on device:%u failed (%d)\n", + flags ? "Allowing" : "Denying", protocol_id, device_id, + ret); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +/** + * do_scmi_reset() - reset platform resource settings + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * + * Reset platform resource settings with BASE_RESET_AGENT_CONFIGURATION + * + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + */ +static int do_scmi_reset(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, flags, attributes; + char *end; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + flags = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE; + + ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_RESET_AGENT_CONFIGURATION, + &attributes); + if (ret) { + printf("Reset is not supported\n"); + return CMD_RET_FAILURE; + } + + ret = scmi_base_reset_agent_configuration(base_proto, agent_id, flags); + if (ret) { + printf("Reset failed (%d)\n", ret); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static struct cmd_tbl cmd_scmi_sub[] = { + U_BOOT_CMD_MKENT(info, CONFIG_SYS_MAXARGS, 1, + do_scmi_info, "", ""), + U_BOOT_CMD_MKENT(perm_dev, CONFIG_SYS_MAXARGS, 1, + do_scmi_set_dev, "", ""), + U_BOOT_CMD_MKENT(perm_proto, CONFIG_SYS_MAXARGS, 1, + do_scmi_set_proto, "", ""), + U_BOOT_CMD_MKENT(reset, CONFIG_SYS_MAXARGS, 1, + do_scmi_reset, "", ""), +}; + +/** + * do_scmi() - SCMI utility + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * + * Provide user interfaces to SCMI protocols. + * + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + */ +static int do_scmi(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + struct cmd_tbl *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + if (!agent) { + if (uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent)) { + printf("Cannot find any SCMI agent\n"); + return CMD_RET_FAILURE; + } + } + + if (!base_proto) + base_proto = scmi_get_protocol(agent, SCMI_PROTOCOL_ID_BASE); + if (!base_proto) { + printf("SCMI base protocol not found\n"); + return CMD_RET_FAILURE; + } + + cp = find_cmd_tbl(argv[0], cmd_scmi_sub, ARRAY_SIZE(cmd_scmi_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +static char scmi_help_text[] = + " - SCMI utility\n" + " info - get the info of SCMI services\n" + " perm_dev <agent id> <device id> <flags>\n" + " - set access permission to device\n" + " perm_proto <agent id> <device id> <protocol id> <flags>\n" + " - set protocol permission to device\n" + " reset <agent id> <flags>\n" + " - reset platform resource settings\n" + ""; + +U_BOOT_CMD(scmi, CONFIG_SYS_MAXARGS, 0, do_scmi, "SCMI utility", + scmi_help_text);

On Wed, 26 Jul 2023 at 02:40, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This command, "scmi", may provide a command line interface to various SCMI protocols. It supports at least initially SCMI base protocol and is intended mainly for debug purpose.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- remove sub command category, 'scmi base', for simplicity
cmd/Kconfig | 9 ++ cmd/Makefile | 1 + cmd/scmi.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 cmd/scmi.c
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 This command, "scmi", may provide a command line interface to various SCMI protocols. It supports at least initially SCMI base protocol and is intended mainly for debug purpose.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- remove sub command category, 'scmi base', for simplicity
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
cmd/Kconfig | 9 ++ cmd/Makefile | 1 + cmd/scmi.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 cmd/scmi.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 02e54f1e50fe..15d1d7b9863f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2504,6 +2504,15 @@ config CMD_CROS_EC a number of sub-commands for performing EC tasks such as updating its flash, accessing a small saved context area and talking to the I2C bus behind the EC (if there is one).
+config CMD_SCMI + bool "Enable scmi command" + depends on SCMI_FIRMWARE + default n + help + This command provides user interfaces to several SCMI (System + Control and Management Interface) protocols available on Arm + platforms to manage system resources. endmenu menu "Filesystem commands" diff --git a/cmd/Makefile b/cmd/Makefile index 6c37521b4e2b..826e0b74b587 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_CMD_SATA) += sata.o obj-$(CONFIG_CMD_NVME) += nvme.o obj-$(CONFIG_SANDBOX) += sb.o obj-$(CONFIG_CMD_SF) += sf.o +obj-$(CONFIG_CMD_SCMI) += scmi.o obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o obj-$(CONFIG_CMD_SEAMA) += seama.o diff --git a/cmd/scmi.c b/cmd/scmi.c new file mode 100644 index 000000000000..5ecd9051b48d --- /dev/null +++ b/cmd/scmi.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- * SCMI (System Control and Management Interface) utility command
- * Copyright (c) 2023 Linaro Limited
- * Author: AKASHI Takahiro
- */
+#include <common.h> +#include <command.h> +#include <exports.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <asm/types.h> +#include <dm/device.h> +#include <dm/uclass.h> /* uclass_get_device */ +#include <linux/bitfield.h> +#include <linux/bitops.h>
+static struct udevice *agent; +static struct udevice *base_proto;
+struct { + enum scmi_std_protocol id; + const char *name; +} protocol_name[] = { + {SCMI_PROTOCOL_ID_BASE, "Base"}, + {SCMI_PROTOCOL_ID_POWER_DOMAIN, "Power domain management"}, + {SCMI_PROTOCOL_ID_SYSTEM, "System power management"}, + {SCMI_PROTOCOL_ID_PERF, "Performance domain management"}, + {SCMI_PROTOCOL_ID_CLOCK, "Clock management"}, + {SCMI_PROTOCOL_ID_SENSOR, "Sensor management"}, + {SCMI_PROTOCOL_ID_RESET_DOMAIN, "Reset domain management"}, + {SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, "Voltage domain management"}, +};
+/**
- get_proto_name() - get the name of SCMI protocol
- @id: SCMI Protocol ID
- Get the printable name of the protocol, @id
- Return: Name string on success, NULL on failure
- */
+static const char *get_proto_name(enum scmi_std_protocol id) +{ + int i;
+ for (i = 0; i < ARRAY_SIZE(protocol_name); i++) + if (id == protocol_name[i].id) + return protocol_name[i].name;
+ return NULL; +}
+/**
- do_scmi_info() - get the information of SCMI services
- @cmdtp: Command table
- @flag: Command flag
- @argc: Number of arguments
- @argv: Argument array
- Get the information of SCMI services using various interfaces
- provided by the Base protocol.
- Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
- */
+static int do_scmi_info(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, num_protocols; + u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX], *protocols; + int i, ret;
+ if (argc != 1) + return CMD_RET_USAGE;
+ printf("SCMI device: %s\n", agent->name); + printf(" protocol version: 0x%x\n", scmi_version(agent)); + printf(" # of agents: %d\n", scmi_num_agents(agent)); + for (i = 0; i < scmi_num_agents(agent); i++) { + ret = scmi_base_discover_agent(base_proto, i, &agent_id, + agent_name); + if (ret) { + if (ret != -EOPNOTSUPP) + printf("base_discover_agent() failed for id: %d (%d)\n", + i, ret); + break; + } + printf(" %c%2d: %s\n", i == scmi_agent_id(agent) ? '>' : ' ', + i, agent_name); + } + printf(" # of protocols: %d\n", scmi_num_protocols(agent)); + num_protocols = scmi_num_protocols(agent); + protocols = scmi_protocols(agent); + if (protocols) + for (i = 0; i < num_protocols; i++) + printf(" %s\n", get_proto_name(protocols[i])); + printf(" vendor: %s\n", scmi_vendor(agent)); + printf(" sub vendor: %s\n", scmi_sub_vendor(agent)); + printf(" impl version: 0x%x\n", scmi_impl_version(agent));
+ return CMD_RET_SUCCESS; +}
+/**
- do_scmi_set_dev() - set access permission to device
- @cmdtp: Command table
- @flag: Command flag
- @argc: Number of arguments
- @argv: Argument array
- Set access permission to device with SCMI_BASE_SET_DEVICE_PERMISSIONS
- Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
- */
+static int do_scmi_set_dev(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, device_id, flags, attributes; + char *end; + int ret;
+ if (argc != 4) + return CMD_RET_USAGE;
+ agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ device_id = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ flags = simple_strtoul(argv[3], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_SET_DEVICE_PERMISSIONS, + &attributes); + if (ret) { + printf("This operation is not supported\n"); + return CMD_RET_FAILURE; + }
+ ret = scmi_base_set_device_permissions(base_proto, agent_id, + device_id, flags); + if (ret) { + printf("%s access to device:%u failed (%d)\n", + flags ? "Allowing" : "Denying", device_id, ret); + return CMD_RET_FAILURE; + }
+ return CMD_RET_SUCCESS; +}
+/**
- do_scmi_set_proto() - set protocol permission to device
- @cmdtp: Command table
- @flag: Command flag
- @argc: Number of arguments
- @argv: Argument array
- Set protocol permission to device with SCMI_BASE_SET_PROTOCOL_PERMISSIONS
- Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
- */
+static int do_scmi_set_proto(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, device_id, protocol_id, flags, attributes; + char *end; + int ret;
+ if (argc != 5) + return CMD_RET_USAGE;
+ agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ device_id = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ protocol_id = simple_strtoul(argv[3], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ flags = simple_strtoul(argv[4], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS, + &attributes); + if (ret) { + printf("This operation is not supported\n"); + return CMD_RET_FAILURE; + }
+ ret = scmi_base_set_protocol_permissions(base_proto, agent_id, + device_id, protocol_id, + flags); + if (ret) { + printf("%s access to protocol:0x%x on device:%u failed (%d)\n", + flags ? "Allowing" : "Denying", protocol_id, device_id, + ret); + return CMD_RET_FAILURE; + }
+ return CMD_RET_SUCCESS; +}
+/**
- do_scmi_reset() - reset platform resource settings
- @cmdtp: Command table
- @flag: Command flag
- @argc: Number of arguments
- @argv: Argument array
- Reset platform resource settings with BASE_RESET_AGENT_CONFIGURATION
- Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
- */
+static int do_scmi_reset(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 agent_id, flags, attributes; + char *end; + int ret;
+ if (argc != 3) + return CMD_RET_USAGE;
+ agent_id = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ flags = simple_strtoul(argv[2], &end, 16); + if (*end != '\0') + return CMD_RET_USAGE;
+ ret = scmi_base_protocol_message_attrs(base_proto, + SCMI_BASE_RESET_AGENT_CONFIGURATION, + &attributes); + if (ret) { + printf("Reset is not supported\n"); + return CMD_RET_FAILURE; + }
+ ret = scmi_base_reset_agent_configuration(base_proto, agent_id, flags); + if (ret) { + printf("Reset failed (%d)\n", ret); + return CMD_RET_FAILURE; + }
+ return CMD_RET_SUCCESS; +}
+static struct cmd_tbl cmd_scmi_sub[] = { + U_BOOT_CMD_MKENT(info, CONFIG_SYS_MAXARGS, 1, + do_scmi_info, "", ""), + U_BOOT_CMD_MKENT(perm_dev, CONFIG_SYS_MAXARGS, 1, + do_scmi_set_dev, "", ""), + U_BOOT_CMD_MKENT(perm_proto, CONFIG_SYS_MAXARGS, 1, + do_scmi_set_proto, "", ""), + U_BOOT_CMD_MKENT(reset, CONFIG_SYS_MAXARGS, 1, + do_scmi_reset, "", ""), +};
+/**
- do_scmi() - SCMI utility
- @cmdtp: Command table
- @flag: Command flag
- @argc: Number of arguments
- @argv: Argument array
- Provide user interfaces to SCMI protocols.
- Return: CMD_RET_SUCCESS on success,
- * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
- */
+static int do_scmi(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + struct cmd_tbl *cp;
+ if (argc < 2) + return CMD_RET_USAGE;
+ argc--; argv++;
+ if (!agent) { + if (uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent)) { + printf("Cannot find any SCMI agent\n"); + return CMD_RET_FAILURE; + } + }
+ if (!base_proto) + base_proto = scmi_get_protocol(agent, SCMI_PROTOCOL_ID_BASE); + if (!base_proto) { + printf("SCMI base protocol not found\n"); + return CMD_RET_FAILURE; + }
+ cp = find_cmd_tbl(argv[0], cmd_scmi_sub, ARRAY_SIZE(cmd_scmi_sub)); + if (!cp) + return CMD_RET_USAGE;
+ return cp->cmd(cmdtp, flag, argc, argv); +}
+static char scmi_help_text[] = + " - SCMI utility\n" + " info - get the info of SCMI services\n" + " perm_dev <agent id> <device id> <flags>\n" + " - set access permission to device\n" + " perm_proto <agent id> <device id> <protocol id> <flags>\n" + " - set protocol permission to device\n" + " reset <agent id> <flags>\n" + " - reset platform resource settings\n" + "";
+U_BOOT_CMD(scmi, CONFIG_SYS_MAXARGS, 0, do_scmi, "SCMI utility",
+ scmi_help_text);
2.41.0

This is a help text for scmi command.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- v2 * add more descriptions about SCMI --- doc/usage/cmd/scmi.rst | 126 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 doc/usage/cmd/scmi.rst
diff --git a/doc/usage/cmd/scmi.rst b/doc/usage/cmd/scmi.rst new file mode 100644 index 000000000000..aebcfe95101d --- /dev/null +++ b/doc/usage/cmd/scmi.rst @@ -0,0 +1,126 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +scmi command +============ + +Synopsis +-------- + +:: + + scmi info + scmi perm_dev <agent id> <device id> <flags> + scmi perm_proto <agent id> <device id> <protocol id> <flags> + scmi reset <agent id> <flags> + +Description +----------- + +Arm System Control and Management Interface (SCMI hereafter) is a set of +standardised interfaces to manage system resources, like clocks, power +domains, pin controls, reset and so on, in a system-wide manner. + +An entity which provides those services is called a SCMI firmware (or +SCMI server if you like) may be placed/implemented by EL3 software or +by a dedicated system control processor (SCP) or else. + +A user of SCMI interfaces, including U-Boot, is called a SCMI agent and +may issues commands, which are defined in each protocol for specific system +resources, to SCMI server via a communication channel, called a transport. +Those interfaces are independent from the server's implementation thanks to +a tranport layer. + +For more details, see the `SCMI specification`_. + +While most of system resources managed under SCMI protocols are implemented +and handled as standard U-Boot devices, for example clk_scmi, scmi command +provides additional management functionality against SCMI server. + +scmi info +~~~~~~~~~ + Show base information about SCMI server and supported protocols + +scmi perm_dev +~~~~~~~~~~~~~ + Allow or deny access permission to the device + +scmi perm_proto +~~~~~~~~~~~~~~~ + Allow or deny access to the protocol on the device + +scmi reset +~~~~~~~~~~ + Reset the already-configured permissions against the device + +Parameters are used as follows: + +<agent id> + SCMI Agent ID, hex value + +<device id> + SCMI Device ID, hex value + + Please note that what a device means is not defined + in the specification. + +<protocol id> + SCMI Protocol ID, hex value + + It must not be 0x10 (base protocol) + +<flags> + Flags to control the action, hex value + + 0 to deny, 1 to allow. The other values are reserved and allowed + values may depend on the implemented version of SCMI server in + the future. See SCMI specification for more details. + +Example +------- + +Obtain basic information about SCMI server: + +:: + + => scmi info + SCMI device: scmi + protocol version: 0x20000 + # of agents: 3 + 0: platform + > 1: OSPM + 2: PSCI + # of protocols: 4 + Power domain management + Performance domain management + Clock management + Sensor management + vendor: Linaro + sub vendor: PMWG + impl version: 0x20b0000 + +Ask for access permission to device#0: + +:: + + => scmi perm_dev 1 0 1 + +Reset configurations with all access permission settings retained: + +:: + + => scmi reset 1 0 + +Configuration +------------- + +The scmi command is only available if CONFIG_CMD_SCMI=y. +Default n because this command is mainly for debug purpose. + +Return value +------------ + +The return value ($?) is set to 0 if the operation succeeded, +1 if the operation failed or -1 if the operation failed due to +a syntax error. + +.. _`SCMI specification`: https://developer.arm.com/documentation/den0056/e/?lang=en

On Wed, 26 Jul 2023 at 02:40, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This is a help text for scmi command.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- add more descriptions about SCMI
doc/usage/cmd/scmi.rst | 126 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 doc/usage/cmd/scmi.rst
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 This is a help text for scmi command.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
v2
- add more descriptions about SCMI
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com
doc/usage/cmd/scmi.rst | 126 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 doc/usage/cmd/scmi.rst
diff --git a/doc/usage/cmd/scmi.rst b/doc/usage/cmd/scmi.rst new file mode 100644 index 000000000000..aebcfe95101d --- /dev/null +++ b/doc/usage/cmd/scmi.rst @@ -0,0 +1,126 @@ +.. SPDX-License-Identifier: GPL-2.0+:
+scmi command +============
+Synopsis +--------
+::
+ scmi info + scmi perm_dev <agent id> <device id> <flags> + scmi perm_proto <agent id> <device id> <protocol id> <flags> + scmi reset <agent id> <flags>
+Description +-----------
+Arm System Control and Management Interface (SCMI hereafter) is a set of +standardised interfaces to manage system resources, like clocks, power +domains, pin controls, reset and so on, in a system-wide manner.
+An entity which provides those services is called a SCMI firmware (or +SCMI server if you like) may be placed/implemented by EL3 software or +by a dedicated system control processor (SCP) or else.
+A user of SCMI interfaces, including U-Boot, is called a SCMI agent and +may issues commands, which are defined in each protocol for specific system +resources, to SCMI server via a communication channel, called a transport. +Those interfaces are independent from the server's implementation thanks to +a tranport layer.
+For more details, see the `SCMI specification`_.
+While most of system resources managed under SCMI protocols are implemented +and handled as standard U-Boot devices, for example clk_scmi, scmi command +provides additional management functionality against SCMI server.
+scmi info +~~~~~~~~~ + Show base information about SCMI server and supported protocols
+scmi perm_dev +~~~~~~~~~~~~~ + Allow or deny access permission to the device
+scmi perm_proto +~~~~~~~~~~~~~~~ + Allow or deny access to the protocol on the device
+scmi reset +~~~~~~~~~~ + Reset the already-configured permissions against the device
+Parameters are used as follows:
+<agent id> + SCMI Agent ID, hex value
By the way, this documentation states hexadecimal value are awaited but not the embedded doc (patch v2 10/12). Would it be worth it?
+<device id> + SCMI Device ID, hex value
+ Please note that what a device means is not defined + in the specification.
+<protocol id> + SCMI Protocol ID, hex value
+ It must not be 0x10 (base protocol)
+<flags> + Flags to control the action, hex value
+ 0 to deny, 1 to allow. The other values are reserved and allowed + values may depend on the implemented version of SCMI server in + the future. See SCMI specification for more details.
+Example +-------
+Obtain basic information about SCMI server:
+::
+ => scmi info + SCMI device: scmi + protocol version: 0x20000 + # of agents: 3 + 0: platform + > 1: OSPM + 2: PSCI + # of protocols: 4 + Power domain management + Performance domain management + Clock management + Sensor management + vendor: Linaro + sub vendor: PMWG + impl version: 0x20b0000
+Ask for access permission to device#0:
+::
+ => scmi perm_dev 1 0 1
+Reset configurations with all access permission settings retained:
+::
+ => scmi reset 1 0
+Configuration +-------------
+The scmi command is only available if CONFIG_CMD_SCMI=y. +Default n because this command is mainly for debug purpose.
+Return value +------------
+The return value ($?) is set to 0 if the operation succeeded, +1 if the operation failed or -1 if the operation failed due to +a syntax error.
+.. _`SCMI specification`: https://developer.arm.com/documentation/den0056/e/?lang=en
2.41.0

In this test, "scmi" command is tested against different sub-commands. Please note that scmi command is for debug purpose and is not intended in production system.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- v2 * use helper functions, removing direct uses of ops --- test/dm/scmi.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-)
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index 41d46548f7fd..a3e61355088a 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -134,9 +134,9 @@ static int dm_test_scmi_base(struct unit_test_state *uts) ut_asserteq_str(priv->vendor, vendor);
/* message attributes */ - ret = scmi_protocol_message_attrs(base, - SCMI_BASE_DISCOVER_SUB_VENDOR, - &attributes); + ret = scmi_base_protocol_message_attrs(base, + SCMI_BASE_DISCOVER_SUB_VENDOR, + &attributes); ut_assertok(ret); ut_assertok(attributes);
@@ -204,6 +204,59 @@ static int dm_test_scmi_base(struct unit_test_state *uts)
DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT);
+static int dm_test_scmi_cmd(struct unit_test_state *uts) +{ + struct udevice *agent_dev; + + /* preparation */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + + /* scmi info */ + ut_assertok(run_command("scmi info", 0)); + + ut_assert_nextline("SCMI device: scmi"); + ut_assert_nextline(" protocol version: 0x20000"); + ut_assert_nextline(" # of agents: 2"); + ut_assert_nextline(" 0: platform"); + ut_assert_nextline(" > 1: OSPM"); + ut_assert_nextline(" # of protocols: 3"); + ut_assert_nextline(" Clock management"); + ut_assert_nextline(" Reset domain management"); + ut_assert_nextline(" Voltage domain management"); + ut_assert_nextline(" vendor: U-Boot"); + ut_assert_nextline(" sub vendor: Sandbox"); + ut_assert_nextline(" impl version: 0x1"); + + ut_assert_console_end(); + + /* scmi perm_dev */ + ut_assertok(run_command("scmi perm_dev 1 0 1", 0)); + ut_assert_console_end(); + + ut_assert(run_command("scmi perm_dev 1 0 0", 0)); + ut_assert_nextline("Denying access to device:0 failed (-13)"); + ut_assert_console_end(); + + /* scmi perm_proto */ + ut_assertok(run_command("scmi perm_proto 1 0 14 1", 0)); + ut_assert_console_end(); + + ut_assert(run_command("scmi perm_proto 1 0 14 0", 0)); + ut_assert_nextline("Denying access to protocol:0x14 on device:0 failed (-13)"); + ut_assert_console_end(); + + /* scmi reset */ + ut_assert(run_command("scmi reset 1 1", 0)); + ut_assert_nextline("Reset failed (-13)"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_scmi_cmd, UT_TESTF_SCAN_FDT); + static int dm_test_scmi_clocks(struct unit_test_state *uts) { struct sandbox_scmi_agent *agent;

On Wed, 26 Jul 2023 at 02:40, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
In this test, "scmi" command is tested against different sub-commands. Please note that scmi command is for debug purpose and is not intended in production system.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
v2
- use helper functions, removing direct uses of ops
test/dm/scmi.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

From: AKASHI Takahiro takahiro.akashi@linaro.org Sent: Wednesday, July 26, 2023 10:38 In this test, "scmi" command is tested against different sub-commands. Please note that scmi command is for debug purpose and is not intended in production system.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
v2
- use helper functions, removing direct uses of ops
Reviewed-by: Etienne Carriere etienne.carriere@foss.st.com with patch on dm_test_scmi_base() squashed in patch 9/12.
test/dm/scmi.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-)
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index 41d46548f7fd..a3e61355088a 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -134,9 +134,9 @@ static int dm_test_scmi_base(struct unit_test_state *uts) ut_asserteq_str(priv->vendor, vendor); /* message attributes */ - ret = scmi_protocol_message_attrs(base, - SCMI_BASE_DISCOVER_SUB_VENDOR, - &attributes); + ret = scmi_base_protocol_message_attrs(base, + SCMI_BASE_DISCOVER_SUB_VENDOR, + &attributes); ut_assertok(ret); ut_assertok(attributes); @@ -204,6 +204,59 @@ static int dm_test_scmi_base(struct unit_test_state *uts) DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT); +static int dm_test_scmi_cmd(struct unit_test_state *uts) +{ + struct udevice *agent_dev;
+ /* preparation */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev);
+ /* scmi info */ + ut_assertok(run_command("scmi info", 0));
+ ut_assert_nextline("SCMI device: scmi"); + ut_assert_nextline(" protocol version: 0x20000"); + ut_assert_nextline(" # of agents: 2"); + ut_assert_nextline(" 0: platform"); + ut_assert_nextline(" > 1: OSPM"); + ut_assert_nextline(" # of protocols: 3"); + ut_assert_nextline(" Clock management"); + ut_assert_nextline(" Reset domain management"); + ut_assert_nextline(" Voltage domain management"); + ut_assert_nextline(" vendor: U-Boot"); + ut_assert_nextline(" sub vendor: Sandbox"); + ut_assert_nextline(" impl version: 0x1");
+ ut_assert_console_end();
+ /* scmi perm_dev */ + ut_assertok(run_command("scmi perm_dev 1 0 1", 0)); + ut_assert_console_end();
+ ut_assert(run_command("scmi perm_dev 1 0 0", 0)); + ut_assert_nextline("Denying access to device:0 failed (-13)"); + ut_assert_console_end();
+ /* scmi perm_proto */ + ut_assertok(run_command("scmi perm_proto 1 0 14 1", 0)); + ut_assert_console_end();
+ ut_assert(run_command("scmi perm_proto 1 0 14 0", 0)); + ut_assert_nextline("Denying access to protocol:0x14 on device:0 failed (-13)"); + ut_assert_console_end();
+ /* scmi reset */ + ut_assert(run_command("scmi reset 1 1", 0)); + ut_assert_nextline("Reset failed (-13)"); + ut_assert_console_end();
+ return 0; +}
+DM_TEST(dm_test_scmi_cmd, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_clocks(struct unit_test_state *uts) { struct sandbox_scmi_agent *agent; -- 2.41.0
participants (4)
-
AKASHI Takahiro
-
Etienne CARRIERE
-
Etienne CARRIERE - foss
-
Simon Glass