diff options
author | Etienne Carriere | 2020-09-09 18:44:07 +0200 |
---|---|---|
committer | Tom Rini | 2020-09-30 11:55:24 -0400 |
commit | c0dd177a9986b97dab42f07b3db0ed1d2fe6e540 (patch) | |
tree | ae4db71e77556f34f9fa7023205e4284c1d72c38 /drivers | |
parent | 34d76fefb2667d0ca138ff4fcf8bc8443032449f (diff) |
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 <etienne.carriere@linaro.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firmware/scmi/sandbox-scmi_agent.c | 117 | ||||
-rw-r--r-- | drivers/firmware/scmi/sandbox-scmi_devices.c | 40 |
2 files changed, 151 insertions, 6 deletions
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index ff590988a68..5b6a4232af4 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 b3e411c5ac7..c69967bf693 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> @@ -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, }; |