diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk_scmi.c | 204 | ||||
-rw-r--r-- | drivers/cpu/imx8_cpu.c | 2 | ||||
-rw-r--r-- | drivers/firmware/scmi/base.c | 24 | ||||
-rw-r--r-- | drivers/firmware/scmi/sandbox-scmi_agent.c | 56 | ||||
-rw-r--r-- | drivers/firmware/scmi/scmi_agent-uclass.c | 50 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/Kconfig | 13 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx-scmi.c | 165 | ||||
-rw-r--r-- | drivers/power/domain/scmi-power-domain.c | 8 | ||||
-rw-r--r-- | drivers/power/regulator/scmi_regulator.c | 8 | ||||
-rw-r--r-- | drivers/reset/reset-scmi.c | 8 |
11 files changed, 494 insertions, 45 deletions
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index e42d2032d45..af69850cdd8 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -8,10 +8,59 @@ #include <clk-uclass.h> #include <dm.h> #include <scmi_agent.h> +#include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <asm/types.h> #include <linux/clk-provider.h> +struct clk_scmi { + struct clk clk; + u32 ctrl_flags; +}; + +struct scmi_clock_priv { + u32 version; +}; + +static int scmi_clk_get_permissions(struct udevice *dev, int clkid, u32 *perm) +{ + struct scmi_clock_priv *priv = dev_get_priv(dev); + int ret; + + struct scmi_clk_get_permissions_in in = { + .clock_id = clkid, + }; + struct scmi_clk_get_permissions_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_CLOCK, + .message_id = SCMI_CLOCK_GET_PERMISSIONS, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + + if (priv->version < CLOCK_PROTOCOL_VERSION_3_0) { + log_debug("%s: SCMI clock management protocol version is less than 3.0.\n", __func__); + return -EINVAL; + } + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) { + log_debug("%s: get SCMI clock management protocol permissions failed\n", __func__); + return ret; + } + + ret = scmi_to_linux_errno(out.status); + if (ret < 0) { + log_debug("%s: the status code of getting permissions: %d\n", __func__, ret); + return ret; + } + + *perm = out.permissions; + return 0; +} + static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) { struct scmi_clk_protocol_attr_out out; @@ -32,7 +81,8 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) return 0; } -static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) +static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, + u32 *attr) { struct scmi_clk_attribute_in in = { .clock_id = clkid, @@ -53,6 +103,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name) return ret; *name = strdup(out.clock_name); + *attr = out.attributes; return 0; } @@ -78,12 +129,48 @@ static int scmi_clk_gate(struct clk *clk, int enable) static int scmi_clk_enable(struct clk *clk) { - return scmi_clk_gate(clk, 1); + struct clk_scmi *clkscmi; + struct clk *c; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return scmi_clk_gate(clk, 1); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + clkscmi = container_of(c, struct clk_scmi, clk); + + if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + return scmi_clk_gate(clk, 1); + + /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ + log_debug("%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__); + return 0; } static int scmi_clk_disable(struct clk *clk) { - return scmi_clk_gate(clk, 0); + struct clk_scmi *clkscmi; + struct clk *c; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return scmi_clk_gate(clk, 0); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + clkscmi = container_of(c, struct clk_scmi, clk); + + if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + return scmi_clk_gate(clk, 0); + + /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ + log_debug("%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__); + return 0; } static ulong scmi_clk_get_rate(struct clk *clk) @@ -108,7 +195,7 @@ static ulong scmi_clk_get_rate(struct clk *clk) return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb); } -static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) +static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate) { struct scmi_clk_rate_set_in in = { .clock_id = clk->id, @@ -133,9 +220,33 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) return scmi_clk_get_rate(clk); } +static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk_scmi *clkscmi; + struct clk *c; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return __scmi_clk_set_rate(clk, rate); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + clkscmi = container_of(c, struct clk_scmi, clk); + + if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL) + return __scmi_clk_set_rate(clk, rate); + + /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ + log_debug("%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__); + return 0; +} + static int scmi_clk_probe(struct udevice *dev) { - struct clk *clk; + struct clk_scmi *clk_scmi; + struct scmi_clock_priv *priv = dev_get_priv(dev); size_t num_clocks, i; int ret; @@ -154,35 +265,98 @@ static int scmi_clk_probe(struct udevice *dev) if (ret) return ret; + ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK, &priv->version); + if (ret) { + log_debug("%s: get SCMI clock management protocol version failed\n", __func__); + return ret; + } + for (i = 0; i < num_clocks; i++) { char *clock_name; + u32 attributes; - if (!scmi_clk_get_attibute(dev, i, &clock_name)) { - clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk || !clock_name) + if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { + clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL); + if (!clk_scmi || !clock_name) ret = -ENOMEM; else - ret = clk_register(clk, dev->driver->name, + ret = clk_register(&clk_scmi->clk, dev->driver->name, clock_name, dev->name); if (ret) { - free(clk); + free(clk_scmi); free(clock_name); return ret; } - clk_dm(i, clk); + clk_dm(i, &clk_scmi->clk); + + if (CLK_HAS_RESTRICTIONS(attributes)) { + u32 perm; + + ret = scmi_clk_get_permissions(dev, i, &perm); + if (ret < 0) + clk_scmi->ctrl_flags = 0; + else + clk_scmi->ctrl_flags = perm; + } else { + clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL | + SUPPORT_CLK_RATE_CONTROL; + } } } return 0; } +static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct scmi_clk_parent_set_in in = { + .clock_id = clk->id, + .parent_clk = parent->id, + }; + struct scmi_clk_parent_set_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_PARENT_SET, + in, out); + int ret; + + ret = devm_scmi_process_msg(clk->dev, &msg); + if (ret < 0) + return ret; + + return scmi_to_linux_errno(out.status); +} + +static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_scmi *clkscmi; + struct clk *c; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return -ENOTSUPP; + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + clkscmi = container_of(c, struct clk_scmi, clk); + + if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) + return __scmi_clk_set_parent(clk, parent); + + /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ + log_debug("%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__); + return 0; +} + static const struct clk_ops scmi_clk_ops = { .enable = scmi_clk_enable, .disable = scmi_clk_disable, .get_rate = scmi_clk_get_rate, .set_rate = scmi_clk_set_rate, + .set_parent = scmi_clk_set_parent, }; U_BOOT_DRIVER(scmi_clock) = { @@ -190,4 +364,12 @@ U_BOOT_DRIVER(scmi_clock) = { .id = UCLASS_CLK, .ops = &scmi_clk_ops, .probe = scmi_clk_probe, + .priv_auto = sizeof(struct scmi_clock_priv), }; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_CLOCK }, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_clock, match); diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 4e1eccaa5b0..4836bddd93b 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -111,6 +111,8 @@ static const char *get_imx_type_str(u32 imxtype) return "91(11)";/* iMX91 9x9 Reduced feature */ case MXC_CPU_IMX9101: return "91(01)";/* iMX91 9x9 Specific feature */ + case MXC_CPU_IMX95: + return "95"; default: return "??"; } diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c index f4e3974ff5b..78ee2ffd2da 100644 --- a/drivers/firmware/scmi/base.c +++ b/drivers/firmware/scmi/base.c @@ -258,7 +258,7 @@ static int scmi_base_discover_impl_version_int(struct udevice *dev, static int scmi_base_discover_list_protocols_int(struct udevice *dev, u8 **protocols) { - struct scmi_base_discover_list_protocols_out out; + struct scmi_base_discover_list_protocols_out *out; int cur; struct scmi_msg msg = { .protocol_id = SCMI_PROTOCOL_ID_BASE, @@ -268,7 +268,7 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev, .out_msg = (u8 *)&out, .out_msg_sz = sizeof(out), }; - u32 num_agents, num_protocols; + u32 num_agents, num_protocols, out_size; u8 *buf; int i, ret; @@ -276,22 +276,31 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev, if (ret) return ret; + out_size = sizeof(*out) + sizeof(u32) * (1 + num_protocols / 4); + out = calloc(1, out_size); + if (!out) + return -ENOMEM; + msg.out_msg = (u8 *)out; + msg.out_msg_sz = out_size; + buf = calloc(sizeof(u8), num_protocols); - if (!buf) + if (!buf) { + free(out); 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); + 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); + for (i = 0; i < out->num_protocols; i++, cur++) + buf[cur] = out->protocols[i / 4] >> ((i % 4) * 8); } while (cur < num_protocols); *protocols = buf; @@ -299,6 +308,7 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev, return num_protocols; err: free(buf); + free(out); return ret; } diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 19be280ec44..74a87832dcb 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -80,9 +80,9 @@ static struct sandbox_scmi_pwd scmi_pwdom[] = { }; static struct sandbox_scmi_clk scmi_clk[] = { - { .rate = 333 }, - { .rate = 200 }, - { .rate = 1000 }, + { .rate = 333, .perm = 0xE0000000 }, + { .rate = 200, .perm = 0xE0000000 }, + { .rate = 1000, .perm = 0xE0000000 }, }; static struct sandbox_scmi_reset scmi_reset[] = { @@ -700,6 +700,21 @@ static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg) /* Clock Protocol */ +static int sandbox_scmi_clock_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 = 0x30000; + out->status = SCMI_SUCCESS; + + return 0; +} + static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev, struct scmi_msg *msg) { @@ -740,6 +755,9 @@ static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg) if (clk_state->enabled) out->attributes = 1; + /* Restricted clock */ + out->attributes |= BIT(1); + ret = snprintf(out->clock_name, sizeof(out->clock_name), "clk%u", in->clock_id); assert(ret > 0 && ret < sizeof(out->clock_name)); @@ -837,6 +855,34 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) return 0; } +static int sandbox_scmi_clock_permissions_get(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_clk_get_permissions_in *in = NULL; + struct scmi_clk_get_permissions_out *out = NULL; + struct sandbox_scmi_clk *clk_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_clk_get_permissions_in *)msg->in_msg; + out = (struct scmi_clk_get_permissions_out *)msg->out_msg; + + clk_state = get_scmi_clk_state(in->clock_id); + if (!clk_state) { + dev_err(dev, "Unexpected clock ID %u\n", in->clock_id); + + out->status = SCMI_NOT_FOUND; + } else { + out->permissions = clk_state->perm; + + out->status = SCMI_SUCCESS; + } + + return 0; +} + static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg) { struct scmi_rd_attr_in *in = NULL; @@ -1193,6 +1239,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, return sandbox_proto_not_supported(msg); switch (msg->message_id) { + case SCMI_PROTOCOL_VERSION: + return sandbox_scmi_clock_protocol_version(dev, msg); case SCMI_PROTOCOL_ATTRIBUTES: return sandbox_scmi_clock_protocol_attribs(dev, msg); case SCMI_CLOCK_ATTRIBUTES: @@ -1203,6 +1251,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, return sandbox_scmi_clock_rate_get(dev, msg); case SCMI_CLOCK_CONFIG_SET: return sandbox_scmi_clock_gate(dev, msg); + case SCMI_CLOCK_GET_PERMISSIONS: + return sandbox_scmi_clock_permissions_get(dev, msg); default: break; } diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index e6e43ae936a..e7ec2c108e6 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -97,6 +97,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: proto = priv->voltagedom_dev; break; + case SCMI_PROTOCOL_ID_PINCTRL: + proto = priv->pinctrl_dev; + break; default: dev_err(dev, "Protocol not supported\n"); proto = NULL; @@ -147,6 +150,9 @@ static int scmi_add_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: priv->voltagedom_dev = proto; break; + case SCMI_PROTOCOL_ID_PINCTRL: + priv->pinctrl_dev = proto; + break; default: dev_err(dev, "Protocol not supported\n"); return -EPROTO; @@ -352,6 +358,22 @@ static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev) return 0; } +static struct driver *scmi_proto_driver_get(unsigned int proto_id) +{ + struct scmi_proto_driver *start, *entry; + int n_ents; + + start = ll_entry_start(struct scmi_proto_driver, scmi_proto_driver); + n_ents = ll_entry_count(struct scmi_proto_driver, scmi_proto_driver); + + for (entry = start; entry != start + n_ents; entry++) { + if (entry->match->proto_id == proto_id) + return entry->driver; + } + + return NULL; +} + /* * SCMI agent devices binds devices of various uclasses depending on * the FDT description. scmi_bind_protocol() is a generic bind sequence @@ -409,31 +431,11 @@ static int scmi_bind_protocols(struct udevice *dev) drv = NULL; name = ofnode_get_name(node); - switch (protocol_id) { - case SCMI_PROTOCOL_ID_POWER_DOMAIN: - if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) && - scmi_protocol_is_supported(dev, protocol_id)) - drv = DM_DRIVER_GET(scmi_power_domain); - break; - case SCMI_PROTOCOL_ID_CLOCK: - if (CONFIG_IS_ENABLED(CLK_SCMI) && - scmi_protocol_is_supported(dev, protocol_id)) - drv = DM_DRIVER_GET(scmi_clock); - break; - case SCMI_PROTOCOL_ID_RESET_DOMAIN: - if (IS_ENABLED(CONFIG_RESET_SCMI) && - scmi_protocol_is_supported(dev, protocol_id)) - drv = DM_DRIVER_GET(scmi_reset_domain); - break; - case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: - if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) && - scmi_protocol_is_supported(dev, protocol_id)) - drv = DM_DRIVER_GET(scmi_voltage_domain); - break; - default: - break; - } + if (!scmi_protocol_is_supported(dev, protocol_id)) + continue; + + drv = scmi_proto_driver_get(protocol_id); if (!drv) { dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", protocol_id); diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig index d13c5f2a6d5..84d9a3641ff 100644 --- a/drivers/pinctrl/nxp/Kconfig +++ b/drivers/pinctrl/nxp/Kconfig @@ -139,6 +139,19 @@ config PINCTRL_IMXRT only parses the 'fsl,pins' property and configure related registers. +config PINCTRL_IMX_SCMI + bool "IMX pinctrl SCMI driver" + depends on ARCH_IMX9 && PINCTRL_FULL + select PINCTRL_IMX + help + This provides a simple pinctrl driver for i.MX SoC which supports + SCMI. This feature depends on device tree configuration. This driver + is different from the linux one, this is a simple implementation, + only parses the 'fsl,pins' property and configure related + registers. + + Say Y here to enable the imx pinctrl SCMI driver + config PINCTRL_VYBRID bool "Vybrid (vf610) pinctrl driver" depends on ARCH_VF610 && PINCTRL_FULL diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile index 44e37c631e5..7d861ae52c1 100644 --- a/drivers/pinctrl/nxp/Makefile +++ b/drivers/pinctrl/nxp/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_PINCTRL_IMX93) += pinctrl-imx93.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_IMXRT) += pinctrl-imxrt.o +obj-$(CONFIG_PINCTRL_IMX_SCMI) += pinctrl-imx-scmi.o diff --git a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c new file mode 100644 index 00000000000..aed47be337d --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2025 NXP + */ + +#include <asm/io.h> +#include <asm/mach-imx/sys_proto.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <dm/pinctrl.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> + +#include "pinctrl-imx.h" + +#define DAISY_OFFSET_IMX95 0x408 + +/* SCMI pin control types */ +#define PINCTRL_TYPE_MUX 192 +#define PINCTRL_TYPE_CONFIG 193 +#define PINCTRL_TYPE_DAISY_ID 194 +#define PINCTRL_TYPE_DAISY_CFG 195 +#define PINCTRL_NUM_CFGS_SHIFT 2 + +struct imx_scmi_pinctrl_priv { + u16 daisy_offset; +}; + +static int imx_pinconf_scmi_set(struct udevice *dev, u32 mux_ofs, u32 mux, u32 config_val, + u32 input_ofs, u32 input_val) +{ + struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev); + int ret, num_cfgs = 0; + struct scmi_msg msg; + + /* Call SCMI API to set the pin mux and configuration. */ + struct scmi_pinctrl_config_set_out out; + struct scmi_pinctrl_config_set_in in = { + .identifier = mux_ofs / 4, + .function_id = 0xFFFFFFFF, + .attributes = 0, + }; + + if (mux_ofs) { + in.configs[num_cfgs].type = PINCTRL_TYPE_MUX; + in.configs[num_cfgs].val = mux; + num_cfgs++; + } + + if (config_val) { + in.configs[num_cfgs].type = PINCTRL_TYPE_CONFIG; + in.configs[num_cfgs].val = config_val; + num_cfgs++; + } + + if (input_ofs) { + in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_ID; + in.configs[num_cfgs].val = (input_ofs - priv->daisy_offset) / 4; + num_cfgs++; + in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_CFG; + in.configs[num_cfgs].val = input_val; + num_cfgs++; + } + + /* Update the number of configs sent in this call. */ + in.attributes = num_cfgs << PINCTRL_NUM_CFGS_SHIFT; + + msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_PINCTRL, + SCMI_MSG_PINCTRL_CONFIG_SET, in, out); + + ret = devm_scmi_process_msg(dev, &msg); + if (ret || out.status) { + dev_err(dev, "Failed to set PAD = %d, daisy = %d, scmi_err = %d, ret = %d\n", + mux_ofs / 4, input_ofs / 4, out.status, ret); + } + + return ret; +} + +static int imx_pinctrl_set_state_scmi(struct udevice *dev, struct udevice *config) +{ + int mux_ofs, mux, config_val, input_reg, input_val; + u32 *pin_data; + int i, j = 0; + int npins; + int ret; + + ret = imx_pinctrl_set_state_common(dev, config, FSL_PIN_SIZE, + &pin_data, &npins); + if (ret) + return ret; + + /* + * Refer to linux documentation for details: + * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt + */ + for (i = 0; i < npins; i++) { + mux_ofs = pin_data[j++]; + /* Skip config_reg */ + j++; + input_reg = pin_data[j++]; + + mux = pin_data[j++]; + input_val = pin_data[j++]; + config_val = pin_data[j++]; + + if (config_val & IMX_PAD_SION) + mux |= IOMUXC_CONFIG_SION; + + config_val &= ~IMX_PAD_SION; + + ret = imx_pinconf_scmi_set(dev, mux_ofs, mux, config_val, input_reg, input_val); + if (ret && ret != -EPERM) { + dev_err(dev, "Set pin %d, mux %d, val %d, error\n", + mux_ofs, mux, config_val); + } + } + + devm_kfree(dev, pin_data); + + return ret; +} + +static const struct pinctrl_ops imx_scmi_pinctrl_ops = { + .set_state = imx_pinctrl_set_state_scmi, +}; + +static int imx_scmi_pinctrl_probe(struct udevice *dev) +{ + struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev); + + if (IS_ENABLED(CONFIG_IMX95)) + priv->daisy_offset = DAISY_OFFSET_IMX95; + else + return -EINVAL; + + return devm_scmi_of_get_channel(dev); +} + +static int imx_scmi_pinctrl_bind(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_IMX95)) + return 0; + + return -ENODEV; +} + +U_BOOT_DRIVER(scmi_pinctrl_imx) = { + .name = "scmi_pinctrl_imx", + .id = UCLASS_PINCTRL, + .bind = imx_scmi_pinctrl_bind, + .probe = imx_scmi_pinctrl_probe, + .priv_auto = sizeof(struct imx_scmi_pinctrl_priv), + .ops = &imx_scmi_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_PINCTRL }, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_pinctrl_imx, match); diff --git a/drivers/power/domain/scmi-power-domain.c b/drivers/power/domain/scmi-power-domain.c index 3cd0f075d95..e8c0ba8878e 100644 --- a/drivers/power/domain/scmi-power-domain.c +++ b/drivers/power/domain/scmi-power-domain.c @@ -11,6 +11,7 @@ #include <power-domain.h> #include <power-domain-uclass.h> #include <scmi_agent.h> +#include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <dm/device_compat.h> @@ -190,3 +191,10 @@ U_BOOT_DRIVER(scmi_power_domain) = { .probe = scmi_power_domain_probe, .priv_auto = sizeof(struct scmi_power_domain_priv), }; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_POWER_DOMAIN }, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_power_domain, match); diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 79db1a6a8aa..7d2db1e2bee 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <scmi_agent.h> +#include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <asm/types.h> #include <dm/device.h> @@ -202,3 +203,10 @@ U_BOOT_DRIVER(scmi_voltage_domain) = { .id = UCLASS_NOP, .bind = scmi_regulator_bind, }; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN }, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_voltage_domain, match); diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c index 6dc1fcb3365..f92a9e35579 100644 --- a/drivers/reset/reset-scmi.c +++ b/drivers/reset/reset-scmi.c @@ -9,6 +9,7 @@ #include <errno.h> #include <reset-uclass.h> #include <scmi_agent.h> +#include <scmi_agent-uclass.h> #include <scmi_protocols.h> #include <asm/types.h> @@ -81,3 +82,10 @@ U_BOOT_DRIVER(scmi_reset_domain) = { .ops = &scmi_reset_domain_ops, .probe = scmi_reset_probe, }; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_RESET_DOMAIN }, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_reset_domain, match); |