
Add tests for SCMI reset controllers. A test device driver sandbox-scmi_devices.c is used to get reset resources, allowing further resets manipulation.
Change sandbox-smci_agent to emulate 1 reset controller exposed through an agent. Add DM test scmi_resets to test this reset controller.
Signed-off-by: Etienne Carriere etienne.carriere@linaro.org Cc: Simon Glass sjg@chromium.org Cc: Peng Fan peng.fan@nxp.com Cc: Sudeep Holla sudeep.holla@arm.com ---
Changes in v3: - New commit in the series, addresses review comments on test support. ut_dm_scmi_resets() tests SCMI resources are found and behave as expected for the implemented reset uclass methods. --- arch/sandbox/dts/test.dts | 6 + arch/sandbox/include/asm/scmi_test.h | 17 +++ configs/sandbox_defconfig | 1 + drivers/firmware/scmi/sandbox-scmi_agent.c | 117 ++++++++++++++++++- drivers/firmware/scmi/sandbox-scmi_devices.c | 30 ++++- test/dm/scmi.c | 35 ++++++ 6 files changed, 200 insertions(+), 6 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 61acd8d79f..7023f33a67 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -366,6 +366,11 @@ reg = <0x14>; #clock-cells = <1>; }; + + reset_scmi0: protocol@16 { + reg = <0x16>; + #reset-cells = <1>; + }; };
sandbox-scmi-agent@1 { @@ -1065,6 +1070,7 @@ sandbox_scmi { compatible = "sandbox,scmi-devices"; clocks = <&clk_scmi0 7>, <&clk_scmi0 3>, <&clk_scmi1 1>; + resets = <&reset_scmi0 3>; };
pinctrl { diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h index 4e09957bc7..de3b2bbcc2 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -22,16 +22,29 @@ struct sandbox_scmi_clk { ulong rate; };
+/** + * struct sandbox_scmi_reset - Simulated reset controller exposed by SCMI + * @asserted: Reset control state: true if asserted, false if desasserted + */ +struct sandbox_scmi_reset { + uint id; + bool asserted; +}; + /** * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent * @idx: Identifier for the SCMI agent, its index * @clk: Simulated clocks * @clk_count: Simulated clocks array size + * @clk: Simulated reset domains + * @clk_count: Simulated reset domains array size */ struct sandbox_scmi_agent { uint idx; struct sandbox_scmi_clk *clk; size_t clk_count; + struct sandbox_scmi_reset *reset; + size_t reset_count; };
/** @@ -48,10 +61,14 @@ struct sandbox_scmi_service { * struct sandbox_scmi_devices - Reference to devices probed through SCMI * @clk: Array the clock devices * @clk_count: Number of clock devices probed + * @reset: Array the reset controller devices + * @reset_count: Number of reset controller devices probed */ struct sandbox_scmi_devices { struct clk *clk; size_t clk_count; + struct reset_ctl *reset; + size_t reset_count; };
#ifdef CONFIG_SCMI_FIRMWARE diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 7d71c805dc..a2ebb3c971 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -220,6 +220,7 @@ CONFIG_REMOTEPROC_SANDBOX=y CONFIG_DM_RESET=y CONFIG_SANDBOX_RESET=y CONFIG_RESET_SYSCON=y +CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y CONFIG_DM_RTC=y CONFIG_RTC_RV8803=y diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 262efbd12c..01843a9827 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -18,19 +18,20 @@ * processing. It simulates few of the SCMI services for some of the * SCMI protocols embedded in U-Boot. Currently: * - SCMI clock protocol: emulate 2 agents each exposing few clocks + * - SCMI reset protocol: emulate 1 agents each exposing a reset * - * Agent #0 simulates 2 clocks. - * See IDs in scmi0_clk[] and "sandbox-scmi-agent@0" in test.dts. + * Agent #0 simulates 2 clocks and 1 reset domain. + * See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts. * * Agent #1 simulates 1 clock. * See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts. * - * All clocks are default disabled. + * All clocks are default disabled and reset levels down. * * This Driver exports sandbox_scmi_service_ct() for the test sequence to * get the state of the simulated services (clock state, rate, ...) and * check back-end device state reflects the request send through the - * various uclass devices, currently only clock controllers. + * various uclass devices, as clocks and reset controllers. */
#define SANDBOX_SCMI_AGENT_COUNT 2 @@ -40,6 +41,10 @@ static struct sandbox_scmi_clk scmi0_clk[] = { { .id = 3, .rate = 333 }, };
+static struct sandbox_scmi_reset scmi0_reset[] = { + { .id = 3 }, +}; + static struct sandbox_scmi_clk scmi1_clk[] = { { .id = 1, .rate = 44 }, }; @@ -76,6 +81,11 @@ static void debug_print_agent_state(struct udevice *dev, char *str) agent->clk_count > 1 ? agent->clk[1].rate : -1, agent->clk_count > 2 ? agent->clk[2].enabled : -1, agent->clk_count > 2 ? agent->clk[2].rate : -1); + dev_dbg(dev, " scmi%u_reset (%zu): %d, %d, ...\n", + agent->idx, + agent->reset_count, + agent->reset_count ? agent->reset[0].asserted : -1, + agent->reset_count > 1 ? agent->reset[1].asserted : -1); };
static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id) @@ -104,6 +114,20 @@ static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id) return NULL; }
+static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id, + uint reset_id) +{ + size_t n; + + if (agent_id == 0) { + for (n = 0; n < ARRAY_SIZE(scmi0_reset); n++) + if (scmi0_reset[n].id == reset_id) + return scmi0_reset + n; + } + + return NULL; +} + /* * Sandbox SCMI agent ops */ @@ -199,6 +223,78 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) return 0; }
+static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev2agent(dev); + struct scmi_rd_attr_in *in = NULL; + struct scmi_rd_attr_out *out = NULL; + struct sandbox_scmi_reset *reset_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_rd_attr_in *)msg->in_msg; + out = (struct scmi_rd_attr_out *)msg->out_msg; + + reset_state = get_scmi_reset_state(agent->idx, in->domain_id); + if (!reset_state) { + dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id); + + out->status = SCMI_NOT_FOUND; + } else { + memset(out, 0, sizeof(*out)); + snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id); + + out->status = SCMI_SUCCESS; + } + + return 0; +} + +static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev2agent(dev); + struct scmi_rd_reset_in *in = NULL; + struct scmi_rd_reset_out *out = NULL; + struct sandbox_scmi_reset *reset_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_rd_reset_in *)msg->in_msg; + out = (struct scmi_rd_reset_out *)msg->out_msg; + + reset_state = get_scmi_reset_state(agent->idx, in->domain_id); + if (!reset_state) { + dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id); + + out->status = SCMI_NOT_FOUND; + } else if (in->reset_state > 1) { + dev_err(dev, "Invalid reset domain input attribute value\n"); + + out->status = SCMI_INVALID_PARAMETERS; + } else { + if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) { + if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) { + out->status = SCMI_NOT_SUPPORTED; + } else { + /* Ends deasserted whatever current state */ + reset_state->asserted = false; + out->status = SCMI_SUCCESS; + } + } else { + reset_state->asserted = in->flags & + SCMI_RD_RESET_FLAG_ASSERT; + + out->status = SCMI_SUCCESS; + } + } + + return 0; +} + static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_msg *msg) { @@ -215,12 +311,21 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, break; } break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + switch (msg->message_id) { + case SCMI_RESET_DOMAIN_ATTRIBUTES: + return sandbox_scmi_rd_attribs(dev, msg); + case SCMI_RESET_DOMAIN_RESET: + return sandbox_scmi_rd_reset(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_BASE: case SCMI_PROTOCOL_ID_POWER_DOMAIN: case SCMI_PROTOCOL_ID_SYSTEM: case SCMI_PROTOCOL_ID_PERF: case SCMI_PROTOCOL_ID_SENSOR: - case SCMI_PROTOCOL_ID_RESET_DOMAIN: *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED; return 0; default: @@ -265,6 +370,8 @@ static int sandbox_scmi_test_probe(struct udevice *dev) .idx = 0, .clk = scmi0_clk, .clk_count = ARRAY_SIZE(scmi0_clk), + .reset = scmi0_reset, + .reset_count = ARRAY_SIZE(scmi0_reset), }; break; case '1': diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c index 2ce8e664df..001ccbd87e 100644 --- a/drivers/firmware/scmi/sandbox-scmi_devices.c +++ b/drivers/firmware/scmi/sandbox-scmi_devices.c @@ -7,6 +7,7 @@ #include <clk.h> #include <dm.h> #include <malloc.h> +#include <reset.h> #include <asm/io.h> #include <asm/scmi_test.h> #include <dm/device_compat.h> @@ -18,6 +19,7 @@ */
#define SCMI_TEST_DEVICES_CLK_COUNT 3 +#define SCMI_TEST_DEVICES_RD_COUNT 1
/* * These tables store de handles used in the various uclasses device function @@ -25,6 +27,7 @@ * memory allocation to ease sharing with test sequence implementation. */ static struct clk sandbox_scmi_clk_device[SCMI_TEST_DEVICES_CLK_COUNT]; +static struct reset_ctl sandbox_scmi_reset_device[SCMI_TEST_DEVICES_RD_COUNT]; static struct sandbox_scmi_devices sandbox_scmi_devhld;
struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(void) @@ -36,15 +39,26 @@ static void dereference_device_handles(struct sandbox_scmi_devices *devices) { devices->clk = NULL; devices->clk_count = 0; + devices->reset = NULL; + devices->reset_count = 0; }
static int sandbox_scmi_devices_remove(struct udevice *dev) { struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(); + int rc = 0; + size_t n; + + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + int rc2 = reset_free(devices->reset + n); + + if (rc2 && !rc) + rc = rc2; + }
dereference_device_handles(devices);
- return 0; + return rc; }
static int sandbox_scmi_devices_probe(struct udevice *dev) @@ -54,7 +68,9 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) size_t n;
devices->clk = sandbox_scmi_clk_device; + devices->reset = sandbox_scmi_reset_device; devices->clk_count = SCMI_TEST_DEVICES_CLK_COUNT; + devices->reset_count = SCMI_TEST_DEVICES_RD_COUNT;
for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) { rc = clk_get_by_index(dev, n, devices->clk + n); @@ -64,8 +80,20 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) } }
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + rc = reset_get_by_index(dev, n, devices->reset + n); + if (rc) { + dev_err(dev, "%s: Failed on reset %zu\n", __func__, n); + goto err_reset; + } + } + return 0;
+err_reset: + for (; n > 0; n--) + reset_free(devices->reset + n - 1); + err_clk: dereference_device_handles(devices);
diff --git a/test/dm/scmi.c b/test/dm/scmi.c index e652dbf52b..aa6ddf883f 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -15,6 +15,7 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <reset.h> #include <asm/scmi_test.h> #include <dm/device-internal.h> #include <dm/test.h> @@ -35,6 +36,8 @@ static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts)
if (scmi_devices->clk_count) ut_asserteq(3, scmi_devices->clk_count); + if (scmi_devices->reset_count) + ut_asserteq(1, scmi_devices->reset_count);
return 0; } @@ -48,6 +51,8 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts) ut_assertnonnull(scmi_devices); if (IS_ENABLED(CONFIG_CLK_SCMI)) ut_asserteq(3, scmi_devices->clk_count); + if (IS_ENABLED(CONFIG_RESET_SCMI)) + ut_asserteq(1, scmi_devices->reset_count);
/* State of the simulated SCMI server exposed */ ut_asserteq(2, scmi_ctx->agent_count); @@ -55,6 +60,8 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts) ut_assertnonnull(scmi_ctx->agent[0]); ut_asserteq(2, scmi_ctx->agent[0]->clk_count); ut_assertnonnull(scmi_ctx->agent[0]->clk); + ut_asserteq(1, scmi_ctx->agent[0]->reset_count); + ut_assertnonnull(scmi_ctx->agent[0]->reset);
ut_assertnonnull(scmi_ctx->agent[1]); ut_assertnonnull(scmi_ctx->agent[1]->clk); @@ -163,3 +170,31 @@ static int dm_test_scmi_clocks(struct unit_test_state *uts) }
DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_resets(struct unit_test_state *uts) +{ + struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); + struct sandbox_scmi_devices *scmi_devices = sandbox_scmi_devices_ctx(); + struct udevice *dev = NULL; + int rc; + + if (!IS_ENABLED(CONFIG_RESET_SCMI)) + return 0; + + rc = load_sandbox_scmi_test_devices(uts, &dev); + if (rc) + return rc; + + /* Test SCMI resect controller manipulation */ + ut_assert(!scmi_ctx->agent[0]->reset[0].asserted) + + ut_assertok(reset_assert(&scmi_devices->reset[0])); + ut_assert(scmi_ctx->agent[0]->reset[0].asserted) + + ut_assertok(reset_deassert(&scmi_devices->reset[0])); + ut_assert(!scmi_ctx->agent[0]->reset[0].asserted); + + return release_sandbox_scmi_test_devices(uts, dev); +} + +DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT);