From c0dd177a9986b97dab42f07b3db0ed1d2fe6e540 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:07 +0200 Subject: [PATCH] firmware: smci: sandbox test for SCMI reset controllers 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 Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- 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 | 40 ++++++++- test/dm/scmi.c | 36 +++++++++ 6 files changed, 211 insertions(+), 6 deletions(-) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5ed364f..e6da47d 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -376,6 +376,11 @@ reg = <0x14>; #clock-cells = <1>; }; + + reset_scmi0: protocol@16 { + reg = <0x16>; + #reset-cells = <1>; + }; }; sandbox-scmi-agent@1 { @@ -1082,6 +1087,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 63093fd..3e8b006 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -23,15 +23,28 @@ struct sandbox_scmi_clk { }; /** + * 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 7d71c80..a2ebb3c 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 ff59098..5b6a423 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 }, }; @@ -71,6 +76,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) @@ -99,6 +109,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 */ @@ -194,6 +218,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 = dev_get_priv(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 = dev_get_priv(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) { @@ -210,12 +306,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: @@ -260,6 +365,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 b3e411c..c69967b 100644 --- a/drivers/firmware/scmi/sandbox-scmi_devices.c +++ b/drivers/firmware/scmi/sandbox-scmi_devices.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,18 +15,22 @@ /* * Simulate to some extent a SCMI exchange. * This drivers gets SCMI resources and offers API function to the - * SCMI test sequence manipulate the resources, currently clocks. + * SCMI test sequence manipulate the resources, currently clock + * and reset controllers. */ #define SCMI_TEST_DEVICES_CLK_COUNT 3 +#define SCMI_TEST_DEVICES_RD_COUNT 1 /* * struct sandbox_scmi_device_priv - Storage for device handles used by test * @clk: Array of clock instances used by tests + * @reset_clt: Array of the reset controller instances used by tests * @devices: Resources exposed by sandbox_scmi_devices_ctx() */ struct sandbox_scmi_device_priv { struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT]; + struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT]; struct sandbox_scmi_devices devices; }; @@ -39,6 +44,22 @@ struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev) return NULL; } +static int sandbox_scmi_devices_remove(struct udevice *dev) +{ + struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev); + int ret = 0; + size_t n; + + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + int ret2 = reset_free(devices->reset + n); + + if (ret2 && !ret) + ret = ret2; + } + + return ret; +} + static int sandbox_scmi_devices_probe(struct udevice *dev) { struct sandbox_scmi_device_priv *priv = dev_get_priv(dev); @@ -48,6 +69,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) priv->devices = (struct sandbox_scmi_devices){ .clk = priv->clk, .clk_count = SCMI_TEST_DEVICES_CLK_COUNT, + .reset = priv->reset_ctl, + .reset_count = SCMI_TEST_DEVICES_RD_COUNT, }; for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) { @@ -58,7 +81,21 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) } } + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + ret = reset_get_by_index(dev, n, priv->devices.reset + n); + if (ret) { + dev_err(dev, "%s: Failed on reset %zu\n", __func__, n); + goto err_reset; + } + } + return 0; + +err_reset: + for (; n > 0; n--) + reset_free(priv->devices.reset + n - 1); + + return ret; } static const struct udevice_id sandbox_scmi_devices_ids[] = { @@ -71,5 +108,6 @@ U_BOOT_DRIVER(sandbox_scmi_devices) = { .id = UCLASS_MISC, .of_match = sandbox_scmi_devices_ids, .priv_auto_alloc_size = sizeof(struct sandbox_scmi_device_priv), + .remove = sandbox_scmi_devices_remove, .probe = sandbox_scmi_devices_probe, }; diff --git a/test/dm/scmi.c b/test/dm/scmi.c index aa46f31..be60b44 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,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 */ scmi_ctx = sandbox_scmi_service_ctx(); @@ -53,6 +56,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); @@ -165,3 +170,34 @@ 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_devices *scmi_devices; + struct sandbox_scmi_service *scmi_ctx; + struct udevice *dev = NULL; + int ret; + + if (!IS_ENABLED(CONFIG_RESET_SCMI)) + return 0; + + ret = load_sandbox_scmi_test_devices(uts, &dev); + if (ret) + return ret; + + scmi_devices = sandbox_scmi_devices_ctx(dev); + scmi_ctx = sandbox_scmi_service_ctx(); + + /* 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); -- 2.7.4