summaryrefslogtreecommitdiff
path: root/components/drivers
diff options
context:
space:
mode:
authorGUI <[email protected]>2025-12-19 21:20:17 +0800
committerGitHub <[email protected]>2025-12-19 21:20:17 +0800
commit43733268c1e22f65c67c796f9e3fe8908267aefd (patch)
treefb98d71f46e640f57fc5756f026746ed24e1cc02 /components/drivers
parent77fbed5744872a825ce71222796b9bdcee30526c (diff)
[dm][firmware][scmi] support ARM-SCMI interface #11069
Diffstat (limited to 'components/drivers')
-rwxr-xr-xcomponents/drivers/Kconfig1
-rwxr-xr-xcomponents/drivers/clk/Kconfig6
-rw-r--r--components/drivers/clk/SConscript2
-rwxr-xr-xcomponents/drivers/clk/clk-scmi.c411
-rwxr-xr-xcomponents/drivers/firmware/Kconfig9
-rwxr-xr-xcomponents/drivers/firmware/SConscript15
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/Kconfig23
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/SConscript21
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/agent-mailbox.c176
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/agent-smc.c200
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/agent.c177
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/agent.h36
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/bus.c84
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/shmem.c110
-rwxr-xr-xcomponents/drivers/firmware/arm_scmi/shmem.h23
-rwxr-xr-xcomponents/drivers/include/drivers/scmi.h1092
-rw-r--r--components/drivers/include/rtdevice.h6
-rw-r--r--components/drivers/pinctrl/Kconfig6
-rw-r--r--components/drivers/pinctrl/SConscript3
-rwxr-xr-xcomponents/drivers/pinctrl/pinctrl-scmi.c485
-rw-r--r--components/drivers/pmdomain/Kconfig5
-rw-r--r--components/drivers/pmdomain/SConscript3
-rwxr-xr-xcomponents/drivers/pmdomain/pm-domain-scmi.c134
-rw-r--r--components/drivers/regulator/Kconfig7
-rwxr-xr-xcomponents/drivers/regulator/SConscript3
-rwxr-xr-xcomponents/drivers/regulator/regulator-scmi.c206
-rw-r--r--components/drivers/reset/Kconfig6
-rwxr-xr-xcomponents/drivers/reset/SConscript3
-rwxr-xr-xcomponents/drivers/reset/reset-scmi.c129
-rw-r--r--components/drivers/thermal/Kconfig6
-rw-r--r--components/drivers/thermal/SConscript3
-rwxr-xr-xcomponents/drivers/thermal/thermal-scmi.c170
32 files changed, 3561 insertions, 0 deletions
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index a2a6dc9ef6..f803469d64 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -30,6 +30,7 @@ rsource "ata/Kconfig"
rsource "nvme/Kconfig"
rsource "block/Kconfig"
rsource "scsi/Kconfig"
+rsource "firmware/Kconfig"
rsource "hwcache/Kconfig"
rsource "regulator/Kconfig"
rsource "reset/Kconfig"
diff --git a/components/drivers/clk/Kconfig b/components/drivers/clk/Kconfig
index c13ccbf259..6cc65c3c2f 100755
--- a/components/drivers/clk/Kconfig
+++ b/components/drivers/clk/Kconfig
@@ -4,6 +4,12 @@ menuconfig RT_USING_CLK
select RT_USING_ADT_REF
default y
+config RT_CLK_SCMI
+ bool "Clock driver controlled via SCMI interface"
+ depends on RT_USING_CLK
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
if RT_USING_CLK
osource "$(SOC_DM_CLK_DIR)/Kconfig"
endif
diff --git a/components/drivers/clk/SConscript b/components/drivers/clk/SConscript
index 928697863d..09c1e27c76 100644
--- a/components/drivers/clk/SConscript
+++ b/components/drivers/clk/SConscript
@@ -14,6 +14,8 @@ src = ['clk.c']
if GetDepend(['RT_USING_OFW']):
src += ['clk-fixed-rate.c']
+if GetDepend(['RT_CLK_SCMI']):
+ src += ['clk-scmi.c']
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
diff --git a/components/drivers/clk/clk-scmi.c b/components/drivers/clk/clk-scmi.c
new file mode 100755
index 0000000000..ca51ee1ddc
--- /dev/null
+++ b/components/drivers/clk/clk-scmi.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "clk.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct scmi_clk
+{
+ struct rt_clk_node parent;
+
+ struct rt_scmi_device *sdev;
+};
+
+#define raw_to_scmi_clk(raw) rt_container_of(raw, struct scmi_clk, parent)
+
+struct scmi_clk_data
+{
+ struct rt_clk_cell cell;
+
+ int id;
+ rt_bool_t rate_discrete;
+
+ union
+ {
+ struct
+ {
+ int rates_nr;
+ rt_uint64_t rates[];
+ } list;
+ struct
+ {
+ rt_uint64_t min_rate;
+ rt_uint64_t max_rate;
+ rt_uint64_t step_size;
+ } range;
+ } info;
+};
+
+#define cell_to_scmi_clk_data(cell) rt_container_of(cell, struct scmi_clk_data, cell)
+
+static rt_err_t scmi_clk_op_gate(struct scmi_clk *sclk, int clk_id, rt_bool_t enable)
+{
+ struct scmi_clk_state_in in =
+ {
+ .clock_id = rt_cpu_to_le32(clk_id),
+ .attributes = rt_cpu_to_le32(enable),
+ };
+ struct scmi_clk_state_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_CLOCK_CONFIG_SET, &in, &out);
+
+ return rt_scmi_process_msg(sclk->sdev, &msg);
+}
+
+static rt_base_t scmi_clk_op_get_rate(struct scmi_clk *sclk, int clk_id)
+{
+ rt_ubase_t res;
+ struct scmi_clk_rate_get_in in =
+ {
+ .clock_id = rt_cpu_to_le32(clk_id),
+ };
+ struct scmi_clk_rate_get_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_CLOCK_RATE_GET, &in, &out);
+
+ res = rt_scmi_process_msg(sclk->sdev, &msg);
+
+ if ((rt_base_t)res >= 0)
+ {
+ res = (rt_ubase_t)(((rt_uint64_t)out.rate_msb << 32) | out.rate_lsb);
+ }
+
+ return res;
+}
+
+static rt_base_t scmi_clk_op_set_rate(struct scmi_clk *sclk, int clk_id, rt_ubase_t rate)
+{
+ struct scmi_clk_rate_set_in in =
+ {
+ .clock_id = rt_cpu_to_le32(clk_id),
+ .flags = rt_cpu_to_le32(SCMI_CLK_RATE_ROUND_CLOSEST),
+ .rate_lsb = rt_cpu_to_le32((rt_uint32_t)rate),
+ .rate_msb = rt_cpu_to_le32((rt_uint32_t)((rt_uint64_t)rate >> 32)),
+ };
+ struct scmi_clk_rate_set_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_CLOCK_RATE_SET, &in, &out);
+
+ return rt_scmi_process_msg(sclk->sdev, &msg);
+}
+
+static rt_err_t scmi_clk_enable(struct rt_clk_cell *cell)
+{
+ struct scmi_clk *sclk = raw_to_scmi_clk(cell->clk_np);
+ struct scmi_clk_data *clk_data = cell_to_scmi_clk_data(cell);
+
+ return scmi_clk_op_gate(sclk, clk_data->id, RT_TRUE);
+}
+
+static void scmi_clk_disable(struct rt_clk_cell *cell)
+{
+ struct scmi_clk *sclk = raw_to_scmi_clk(cell->clk_np);
+ struct scmi_clk_data *clk_data = cell_to_scmi_clk_data(cell);
+
+ scmi_clk_op_gate(sclk, clk_data->id, RT_FALSE);
+}
+
+static rt_ubase_t scmi_clk_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
+{
+ struct scmi_clk *sclk = raw_to_scmi_clk(cell->clk_np);
+ struct scmi_clk_data *clk_data = cell_to_scmi_clk_data(cell);
+
+ return scmi_clk_op_get_rate(sclk, clk_data->id);
+}
+
+static rt_base_t scmi_clk_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate)
+{
+ rt_uint64_t fmin, fmax, ftmp;
+ struct scmi_clk_data *clk_data = cell_to_scmi_clk_data(cell);
+
+ if (clk_data->rate_discrete)
+ {
+ return rate;
+ }
+
+ fmin = clk_data->info.range.min_rate;
+ fmax = clk_data->info.range.max_rate;
+
+ if (drate <= fmin)
+ {
+ return fmin;
+ }
+
+ if (drate >= fmax)
+ {
+ return fmax;
+ }
+
+ ftmp = drate - fmin;
+ ftmp += clk_data->info.range.step_size - 1;
+ rt_do_div(ftmp, clk_data->info.range.step_size);
+
+ return ftmp * clk_data->info.range.step_size + fmin;
+}
+
+static rt_err_t scmi_clk_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate)
+{
+ rt_err_t err;
+ rt_ubase_t res_rate;
+ struct scmi_clk *sclk = raw_to_scmi_clk(cell->clk_np);
+ struct scmi_clk_data *clk_data = cell_to_scmi_clk_data(cell);
+
+ if (!(err = scmi_clk_op_set_rate(sclk, clk_data->id, rate)))
+ {
+ res_rate = scmi_clk_op_get_rate(sclk, clk_data->id);
+
+ if ((rt_err_t)res_rate < 0)
+ {
+ err = (rt_err_t)res_rate;
+ }
+ }
+
+ return err;
+}
+
+static const struct rt_clk_ops scmi_clk_ops =
+{
+ .enable = scmi_clk_enable,
+ .disable = scmi_clk_disable,
+ .recalc_rate = scmi_clk_recalc_rate,
+ .round_rate = scmi_clk_round_rate,
+ .set_rate = scmi_clk_set_rate,
+};
+
+static rt_err_t scmi_clk_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ rt_size_t cell_count, out_size;
+ struct rt_scmi_msg msg;
+ struct rt_device *dev = &sdev->parent;
+ struct rt_clk_cell **cells_list = RT_NULL, *cell;
+ struct scmi_clk_data *clk_data;
+ struct scmi_clk_describe_rates_out *out = RT_NULL;
+ struct scmi_clk_describe_rates_in in;
+ struct scmi_clk_attributes attr;
+ struct scmi_clk_name_in name_in;
+ struct scmi_clk_name_out name_out;
+ struct scmi_clk_describe_attributes_in clk_attr_in;
+ struct scmi_clk_describe_attributes_out clk_attr_out;
+ struct scmi_clk *sclk = rt_calloc(1, sizeof(*sclk));
+
+ if (!sclk)
+ {
+ return -RT_ENOMEM;
+ }
+
+ sclk->sdev = sdev;
+
+ msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
+
+ if ((err = rt_scmi_process_msg(sclk->sdev, &msg)))
+ {
+ goto _fail;
+ }
+
+ cell_count = rt_le16_to_cpu(attr.num_clocks);
+
+ if (!(cells_list = rt_calloc(cell_count, sizeof(*cells_list))))
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ out_size = rt_offsetof(struct scmi_clk_describe_rates_out, rate[SCMI_MAX_NUM_RATES]);
+
+ if (!(out = rt_malloc(out_size)))
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ for (int id = 0; id < cell_count; ++id)
+ {
+ const char *clk_name;
+ rt_uint32_t flags, rates_nr, rate_discrete;
+
+ in.id = rt_cpu_to_le32(id);
+ in.rate_index = rt_cpu_to_le32(0);
+ msg = RT_SCMI_MSG_RAW(SCMI_CLOCK_DESCRIBE_RATES, &in, sizeof(in), out, out_size);
+
+ if ((err = rt_scmi_process_msg(sclk->sdev, &msg)))
+ {
+ goto _fail;
+ }
+
+ flags = rt_le32_to_cpu(out->num_rates_flags);
+ rates_nr = SCMI_NUM_REMAINING(flags);
+ rate_discrete = SCMI_RATE_DISCRETE(flags);
+
+ if (rate_discrete)
+ {
+ clk_data = rt_malloc(rt_offsetof(struct scmi_clk_data,
+ info.list.rates[SCMI_MAX_NUM_RATES]));
+ }
+ else
+ {
+ clk_data = rt_malloc(sizeof(*clk_data));
+ }
+
+ if (!clk_data)
+ {
+ err = -RT_ENOMEM;
+ break;
+ }
+
+ if (rate_discrete)
+ {
+ for (int i = 0; i < rates_nr; ++i)
+ {
+ clk_data->info.list.rates[i] = SCMI_RATE_TO_U64(out->rate[i]);
+ }
+
+ clk_data->info.list.rates_nr = rates_nr;
+ }
+ else
+ {
+ clk_data->info.range.min_rate = SCMI_RATE_TO_U64(out->rate[0]);
+ clk_data->info.range.max_rate = SCMI_RATE_TO_U64(out->rate[1]);
+ clk_data->info.range.step_size = SCMI_RATE_TO_U64(out->rate[2]);
+ }
+
+ clk_data->rate_discrete = rate_discrete;
+ clk_data->id = id;
+
+ cell = &clk_data->cell;
+ rt_memset(cell, 0, sizeof(*cell));
+
+ clk_attr_in.clock_id = rt_cpu_to_le32(id);
+ msg = RT_SCMI_MSG_IN_OUT(SCMI_CLOCK_ATTRIBUTES, &clk_attr_in, &clk_attr_out);
+
+ if ((err = rt_scmi_process_msg(sclk->sdev, &msg)))
+ {
+ rt_free(clk_data);
+ goto _fail;
+ }
+
+ if (SUPPORTS_EXTENDED_NAMES(clk_attr_out.attributes))
+ {
+ name_in.clock_id = rt_cpu_to_le32(id);
+ msg = RT_SCMI_MSG_IN_OUT(SCMI_CLOCK_NAME_GET, &name_in, &name_out);
+
+ if ((err = rt_scmi_process_msg(sclk->sdev, &msg)))
+ {
+ rt_free(clk_data);
+ goto _fail;
+ }
+
+ clk_name = (const char *)name_out.name;
+ }
+ else
+ {
+ clk_name = (const char *)clk_attr_out.name;
+ }
+
+ if (!(cell->name = rt_strdup(clk_name)))
+ {
+ rt_free(clk_data);
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ cell->ops = &scmi_clk_ops;
+ cell->flags = RT_CLK_F_GET_RATE_NOCACHE;
+
+ cells_list[id] = cell;
+ }
+
+ sclk->parent.dev = dev;
+ sclk->parent.cells = cells_list;
+ sclk->parent.cells_nr = cell_count;
+
+ if ((err = rt_clk_register(&sclk->parent)))
+ {
+ goto _fail;
+ }
+
+ for (int id = 0; id < cell_count; ++id)
+ {
+ struct rt_clk *clk = rt_clk_cell_get_clk(cells_list[id], RT_NULL);
+
+ if (clk)
+ {
+ rt_ubase_t min_rate, max_rate;
+
+ clk_data = cell_to_scmi_clk_data(cells_list[id]);
+
+ if (clk_data->rate_discrete)
+ {
+ min_rate = clk_data->info.list.rates[0];
+ max_rate = clk_data->info.list.rates[clk_data->info.list.rates_nr - 1];
+ }
+ else
+ {
+ min_rate = clk_data->info.range.min_rate;
+ max_rate = clk_data->info.range.max_rate;
+ }
+
+ rt_clk_set_rate_range(clk, min_rate, max_rate);
+ }
+ }
+
+ return RT_EOK;
+
+_fail:
+ if (out)
+ {
+ rt_free(out);
+ }
+
+ if (cells_list)
+ {
+ for (int id = 0; id < cell_count; ++id)
+ {
+ if (!cells_list[id])
+ {
+ break;
+ }
+
+ cell = cells_list[id];
+ clk_data = cell_to_scmi_clk_data(cell);
+
+ rt_free(clk_data);
+ }
+
+ rt_free(cells_list);
+ }
+
+ rt_free(sclk);
+
+ return err;
+}
+
+static const struct rt_scmi_device_id scmi_clk_ids[] =
+{
+ { SCMI_PROTOCOL_ID_CLOCK, "clocks" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_clk_driver =
+{
+ .name = "clk-scmi",
+ .ids = scmi_clk_ids,
+
+ .probe = scmi_clk_probe,
+};
+
+static int scmi_clk_drv_register(void)
+{
+ rt_scmi_driver_register(&scmi_clk_driver);
+
+ return 0;
+}
+INIT_SUBSYS_EXPORT(scmi_clk_drv_register);
diff --git a/components/drivers/firmware/Kconfig b/components/drivers/firmware/Kconfig
new file mode 100755
index 0000000000..4261e6157e
--- /dev/null
+++ b/components/drivers/firmware/Kconfig
@@ -0,0 +1,9 @@
+menuconfig RT_USING_FIRMWARE
+ bool "Using Firmware"
+ depends on RT_USING_DM
+ default n
+
+if RT_USING_FIRMWARE
+ rsource "arm_scmi/Kconfig"
+ osource "$(SOC_DM_FIRMWARE_DIR)/Kconfig"
+endif
diff --git a/components/drivers/firmware/SConscript b/components/drivers/firmware/SConscript
new file mode 100755
index 0000000000..77728612f6
--- /dev/null
+++ b/components/drivers/firmware/SConscript
@@ -0,0 +1,15 @@
+from building import *
+
+cwd = GetCurrentDir()
+list = os.listdir(cwd)
+objs = []
+
+if not GetDepend('RT_USING_FIRMWARE'):
+ Return('objs')
+
+for d in list:
+ path = os.path.join(cwd, d)
+ if os.path.isfile(os.path.join(path, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')
diff --git a/components/drivers/firmware/arm_scmi/Kconfig b/components/drivers/firmware/arm_scmi/Kconfig
new file mode 100755
index 0000000000..e83cc78b4d
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/Kconfig
@@ -0,0 +1,23 @@
+menuconfig RT_FIRMWARE_ARM_SCMI
+ bool "ARM System Control and Management Interface Protocol (SCMI)"
+ depends on RT_USING_FIRMWARE
+ depends on ARCH_ARM_CORTEX_A || ARCH_ARMV8
+ depends on RT_USING_OFW
+ default n
+
+config RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX
+ bool "SCMI transport based on mailbox"
+ depends on RT_FIRMWARE_ARM_SCMI
+ depends on RT_USING_MBOX
+ default y
+
+config RT_FIRMWARE_ARM_SCMI_TRANSPORT_SMC
+ bool "SCMI transport based on SMC"
+ depends on RT_FIRMWARE_ARM_SCMI
+ default y
+
+if RT_VIRTIO_SCMI
+ config RT_FIRMWARE_ARM_SCMI_TRANSPORT_VIRTIO
+ bool
+ default y
+endif
diff --git a/components/drivers/firmware/arm_scmi/SConscript b/components/drivers/firmware/arm_scmi/SConscript
new file mode 100755
index 0000000000..6415bc52b1
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/SConscript
@@ -0,0 +1,21 @@
+from building import *
+
+group = []
+
+if not GetDepend(['RT_FIRMWARE_ARM_SCMI']):
+ Return('group')
+
+cwd = GetCurrentDir()
+CPPPATH = [cwd + '/../../include']
+
+src = ['agent.c', 'bus.c', 'shmem.c']
+
+if GetDepend(['RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX']):
+ src += ['agent-mailbox.c']
+
+if GetDepend(['RT_FIRMWARE_ARM_SCMI_TRANSPORT_SMC']):
+ src += ['agent-smc.c']
+
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/firmware/arm_scmi/agent-mailbox.c b/components/drivers/firmware/arm_scmi/agent-mailbox.c
new file mode 100755
index 0000000000..4a25860560
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/agent-mailbox.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rthw.h>
+
+#include <drivers/mailbox.h>
+#include <dt-bindings/size.h>
+
+#define DBG_TAG "scmi.agent.mailbox"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "agent.h"
+
+struct scmi_agent_mailbox
+{
+ struct rt_mbox_client mbox_client;
+
+ struct rt_mbox_chan *chan;
+ struct scmi_shared_mem *shmem;
+
+ struct rt_spinlock lock;
+};
+#define raw_to_scmi_mailbox(raw) rt_container_of(raw, struct scmi_agent_mailbox, mbox_client)
+
+static void scmi_mailbox_rx_callback(struct rt_mbox_client *client, void *data)
+{
+ struct rt_scmi_msg *msg = data;
+
+ if (msg->rx_callback)
+ {
+ msg->rx_callback(msg->sdev, msg->out_msg, msg->out_msg_size);
+ }
+}
+
+static void scmi_mailbox_tx_prepare(struct rt_mbox_client *client, const void *data)
+{
+ struct rt_scmi_msg *msg = (void *)data;
+ struct scmi_agent_mailbox *ambox = raw_to_scmi_mailbox(client);
+
+ scmi_shmem_msg_write(ambox->shmem, msg);
+}
+
+static void scmi_mailbox_tx_done(struct rt_mbox_client *client, const void *data,
+ rt_err_t err)
+{
+ struct scmi_agent_mailbox *ambox = raw_to_scmi_mailbox(client);
+
+ if (!err)
+ {
+ scmi_shmem_clear_channel(ambox->shmem);
+ }
+}
+
+static rt_err_t scmi_agent_mailbox_setup(struct scmi_agent *agent,
+ struct rt_device *dev)
+{
+ rt_err_t err;
+ rt_uint64_t shm_addr, shm_size;
+ int mbox_chan, mbox_count, shmem_count;
+ struct rt_ofw_node *np = dev->ofw_node, *shmem_np;
+ struct scmi_agent_mailbox *ambox = rt_calloc(1, sizeof(*ambox));
+
+ if (!ambox)
+ {
+ return -RT_ENOMEM;
+ }
+
+ mbox_count = rt_ofw_count_phandle_cells(np, "mboxes", "#mbox-cells");
+ shmem_count = rt_ofw_count_phandle_cells(np, "shmem", RT_NULL);
+
+ if (mbox_count < 0)
+ {
+ err = mbox_count;
+ goto _fail;
+ }
+
+ if (shmem_count < 0)
+ {
+ err = shmem_count;
+ goto _fail;
+ }
+
+ mbox_chan = 0;
+ if (mbox_count == 2 && shmem_count == 2)
+ {
+ mbox_chan = 1;
+ }
+ else if (mbox_count == 3)
+ {
+ mbox_chan = 2;
+ }
+
+ ambox->mbox_client.dev = dev;
+ ambox->mbox_client.rx_callback = scmi_mailbox_rx_callback;
+ ambox->mbox_client.tx_prepare = scmi_mailbox_tx_prepare;
+ ambox->mbox_client.tx_done = scmi_mailbox_tx_done;
+
+ ambox->chan = rt_mbox_request_by_index(&ambox->mbox_client, mbox_chan);
+ if (rt_is_err_or_null(ambox->chan))
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+
+ shmem_np = rt_ofw_parse_phandle(np, "shmem", 0);
+
+ if (!rt_ofw_node_is_compatible(shmem_np, "arm,scmi-shmem"))
+ {
+ err = -RT_EINVAL;
+ rt_ofw_node_put(shmem_np);
+
+ goto _fail;
+ }
+
+ if ((err = rt_ofw_get_address(shmem_np, 0, &shm_addr, &shm_size)))
+ {
+ rt_ofw_node_put(shmem_np);
+ goto _fail;
+ }
+ rt_ofw_node_put(shmem_np);
+
+ ambox->shmem = rt_ioremap((void *)shm_addr, shm_size);
+
+ if (!ambox->shmem)
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+
+ agent->priv = ambox;
+
+ return RT_EOK;
+
+_fail:
+ if (!rt_is_err_or_null(ambox->chan))
+ {
+ rt_mbox_release(ambox->chan);
+ }
+ if (ambox->shmem)
+ {
+ rt_iounmap(ambox->shmem);
+ }
+ rt_free(ambox);
+
+ return err;
+}
+
+static rt_err_t scmi_agent_mailbox_process_msg(struct scmi_agent *agent,
+ struct rt_scmi_msg *msg)
+{
+ rt_err_t err;
+ struct scmi_agent_mailbox *ambox = agent->priv;
+
+ rt_hw_spin_lock(&ambox->lock.lock);
+
+ err = rt_mbox_send(ambox->chan, (const void *)msg, 30);
+
+ rt_hw_spin_unlock(&ambox->lock.lock);
+
+ return err;
+}
+
+struct scmi_agent_ops scmi_agent_mailbox_ops =
+{
+ .name = "mailbox",
+ .setup = scmi_agent_mailbox_setup,
+ .process_msg = scmi_agent_mailbox_process_msg,
+};
diff --git a/components/drivers/firmware/arm_scmi/agent-smc.c b/components/drivers/firmware/arm_scmi/agent-smc.c
new file mode 100755
index 0000000000..8bff749f98
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/agent-smc.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rthw.h>
+
+#include <mmu.h>
+#include <smccc.h>
+#include <cpuport.h>
+#include <dt-bindings/size.h>
+
+#define DBG_TAG "scmi.agent.smc"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "agent.h"
+
+struct scmi_agent_smc
+{
+ int irq;
+ rt_uint32_t func_id;
+
+#define SHMEM_SIZE (4 * SIZE_KB)
+#define SHMEM_SHIFT 12
+#define SHMEM_PAGE(x) (((rt_ubase_t)(x) >> SHMEM_SHIFT))
+#define SHMEM_OFFSET(x) ((x) & (SHMEM_SIZE - 1))
+ rt_uint32_t param_page;
+ rt_uint32_t param_offset;
+ rt_ubase_t cap_id;
+
+ rt_bool_t done;
+
+ struct rt_spinlock lock;
+ struct scmi_shared_mem *shmem;
+};
+
+static void scmi_agent_smc_isr(int irqno, void *param)
+{
+ struct scmi_agent_smc *asmc = param;
+
+ HWREG32(&asmc->done) = RT_TRUE;
+ rt_hw_dmb();
+}
+
+static rt_err_t scmi_agent_smc_setup(struct scmi_agent *agent,
+ struct rt_device *dev)
+{
+ rt_err_t err;
+ rt_uint64_t shm_addr, shm_size;
+ struct rt_ofw_node *np = dev->ofw_node, *shmem_np;
+ struct scmi_agent_smc *asmc = rt_calloc(1, sizeof(*asmc));
+
+ if (!asmc)
+ {
+ return -RT_ENOMEM;
+ }
+
+ if ((err = rt_ofw_prop_read_u32(np, "arm,smc-id", &asmc->func_id)))
+ {
+ goto _fail;
+ }
+
+ shmem_np = rt_ofw_parse_phandle(np, "shmem", 0);
+
+ if (!rt_ofw_node_is_compatible(shmem_np, "arm,scmi-shmem"))
+ {
+ err = -RT_EINVAL;
+ rt_ofw_node_put(shmem_np);
+
+ goto _fail;
+ }
+
+ if ((err = rt_ofw_get_address(shmem_np, 0, &shm_addr, &shm_size)))
+ {
+ rt_ofw_node_put(shmem_np);
+ goto _fail;
+ }
+ rt_ofw_node_put(shmem_np);
+
+ asmc->shmem = rt_ioremap((void *)shm_addr, shm_size);
+
+ if (!asmc->shmem)
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+
+ if (rt_ofw_node_is_compatible(np, "qcom,scmi-smc"))
+ {
+ void *cap_id_map = (void *)asmc->shmem + (shm_size - 8);
+
+ rt_memcpy(&asmc->cap_id, cap_id_map, sizeof(asmc->cap_id));
+ }
+ else
+ {
+ asmc->cap_id = ~0UL;
+ }
+
+ if (rt_ofw_node_is_compatible(np, "arm,scmi-smc-param"))
+ {
+ rt_ubase_t base = (rt_ubase_t)rt_kmem_v2p(asmc->shmem);
+
+ asmc->param_page = SHMEM_PAGE(base);
+ asmc->param_offset = SHMEM_OFFSET(base);
+ }
+
+ asmc->irq = rt_ofw_get_irq_by_name(np, "a2p");
+
+ if (asmc->irq >= 0)
+ {
+ rt_hw_interrupt_install(asmc->irq, scmi_agent_smc_isr, asmc, "scmi");
+ rt_hw_interrupt_umask(asmc->irq);
+ }
+
+ rt_spin_lock_init(&asmc->lock);
+
+ agent->priv = asmc;
+
+ return RT_EOK;
+
+_fail:
+ if (asmc->shmem)
+ {
+ rt_iounmap(asmc->shmem);
+ }
+ rt_free(asmc);
+
+ return err;
+}
+
+static rt_err_t scmi_agent_smc_process_msg(struct scmi_agent *agent,
+ struct rt_scmi_msg *msg)
+{
+ rt_err_t err;
+ struct arm_smccc_res_t res;
+ struct scmi_shared_mem *shmem;
+ struct scmi_agent_smc *asmc = agent->priv;
+
+ rt_spin_lock(&asmc->lock);
+
+ if (asmc->irq >= 0)
+ {
+ while (HWREG32(&asmc->done))
+ {
+ rt_hw_cpu_relax();
+ }
+ }
+
+ shmem = asmc->shmem;
+
+ if ((err = scmi_shmem_msg_write(shmem, msg)))
+ {
+ goto _out_lock;
+ }
+
+ if (asmc->irq >= 0)
+ {
+ HWREG32(&asmc->done) = RT_FALSE;
+ }
+
+ if (asmc->cap_id == ~0UL)
+ {
+ arm_smccc_smc(asmc->func_id, asmc->param_page, asmc->param_offset,
+ 0, 0, 0, 0, 0, &res, RT_NULL);
+ }
+ else
+ {
+ arm_smccc_smc(asmc->func_id, asmc->cap_id,
+ 0, 0, 0, 0, 0, 0, &res, RT_NULL);
+ }
+
+ if (res.a0)
+ {
+ err = -RT_EIO;
+ }
+ else
+ {
+ err = scmi_shmem_msg_read(shmem, msg);
+ }
+
+ scmi_shmem_clear_channel(shmem);
+
+_out_lock:
+ rt_spin_unlock(&asmc->lock);
+
+ return err;
+}
+
+struct scmi_agent_ops scmi_agent_smc_ops =
+{
+ .name = "smc",
+ .setup = scmi_agent_smc_setup,
+ .process_msg = scmi_agent_smc_process_msg,
+};
diff --git a/components/drivers/firmware/arm_scmi/agent.c b/components/drivers/firmware/arm_scmi/agent.c
new file mode 100755
index 0000000000..2ff38de4bc
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/agent.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include "agent.h"
+
+#define DBG_TAG "scmi.agent"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+rt_err_t rt_scmi_process_msg(struct rt_scmi_device *sdev, struct rt_scmi_msg *msg)
+{
+ struct scmi_agent *agent;
+
+ if (!sdev || !msg)
+ {
+ return -RT_EINVAL;
+ }
+
+ agent = sdev->agent;
+ msg->sdev = sdev;
+
+ return agent->ops->process_msg(agent, msg);
+}
+
+static const char * const _scmi_error_table[] =
+{
+ [-SCMI_SUCCESS] = "SUCCESS",
+ [-SCMI_ERR_SUPPORT] = "SUPPORT",
+ [-SCMI_ERR_PARAMS] = "PARAMS",
+ [-SCMI_ERR_ACCESS] = "ACCESS",
+ [-SCMI_ERR_ENTRY] = "ENTRY",
+ [-SCMI_ERR_RANGE] = "RANGE",
+ [-SCMI_ERR_BUSY] = "BUSY",
+ [-SCMI_ERR_COMMS] = "COMMS",
+ [-SCMI_ERR_GENERIC] = "GENERIC",
+ [-SCMI_ERR_HARDWARE] = "HARDWARE",
+ [-SCMI_ERR_PROTOCOL] = "PROTOCOL",
+};
+
+const char *rt_scmi_strerror(rt_base_t err)
+{
+ const char *str;
+
+ err = err < 0 ? -err : err;
+
+ if (err < RT_ARRAY_SIZE(_scmi_error_table))
+ {
+ str = _scmi_error_table[err];
+ }
+ else
+ {
+ str = "UNKNOWN";
+ }
+
+ return str;
+}
+
+static rt_err_t scmi_channels_setup(struct scmi_agent *agent,
+ struct rt_platform_device *pdev)
+{
+ struct rt_ofw_node *np = pdev->parent.ofw_node, *chn;
+
+ rt_ofw_foreach_available_child_node(np, chn)
+ {
+ rt_uint32_t prot_id;
+ struct rt_scmi_device *sdev;
+
+ if (rt_ofw_prop_read_u32(chn, "reg", &prot_id))
+ {
+ continue;
+ }
+
+ sdev = rt_calloc(1, sizeof(*sdev));
+
+ if (!sdev)
+ {
+ rt_ofw_node_put(chn);
+ return -RT_ENOMEM;
+ }
+
+ sdev->parent.ofw_node = chn;
+ sdev->protocol_id = prot_id;
+ sdev->agent = agent;
+
+ rt_scmi_device_register(sdev);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t scmi_probe(struct rt_platform_device *pdev)
+{
+ rt_err_t err;
+ struct rt_scmi_device *base_sdev;
+ struct scmi_agent *agent = rt_malloc(sizeof(*agent) + sizeof(*base_sdev));
+ const struct scmi_agent_ops *agent_ops;
+
+ if (!agent)
+ {
+ return -RT_ENOMEM;
+ }
+
+ agent_ops = pdev->id->data;
+ agent->ops = agent_ops;
+
+ if ((err = agent_ops->setup(agent, &pdev->parent)))
+ {
+ LOG_E("Setup interface %s error = %s", agent_ops->name, rt_strerror(err));
+ goto _fail;
+ }
+
+ if ((err = scmi_channels_setup(agent, pdev)))
+ {
+ goto _fail;
+ }
+
+ base_sdev = (void *)&agent[1];
+ rt_memset(base_sdev, 0, sizeof(*base_sdev));
+
+ base_sdev->protocol_id = SCMI_PROTOCOL_ID_BASE;
+ base_sdev->agent = agent;
+
+ if ((err = rt_scmi_device_register(base_sdev)))
+ {
+ LOG_W("Base protocol register error = %s", rt_strerror(err));
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_free(agent);
+
+ return err;
+}
+
+extern struct rt_scmi_agent_ops scmi_agent_mailbox_ops;
+extern struct rt_scmi_agent_ops scmi_agent_smc_ops;
+extern struct rt_scmi_agent_ops scmi_agent_virtio_ops;
+
+static const struct rt_ofw_node_id scmi_ofw_ids[] =
+{
+#ifdef RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX
+ { .compatible = "arm,scmi", .data = &scmi_agent_mailbox_ops },
+#endif
+#ifdef RT_FIRMWARE_ARM_SCMI_TRANSPORT_SMC
+ { .compatible = "arm,scmi-smc", .data = &scmi_agent_smc_ops },
+ { .compatible = "arm,scmi-smc-param", .data = &scmi_agent_smc_ops },
+ { .compatible = "qcom,scmi-smc", .data = &scmi_agent_smc_ops},
+#endif
+#ifdef RT_FIRMWARE_ARM_SCMI_TRANSPORT_VIRTIO
+ { .compatible = "arm,scmi-virtio", .data = &scmi_agent_virtio_ops },
+#endif
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver scmi_driver =
+{
+ .name = "arm-scmi",
+ .ids = scmi_ofw_ids,
+
+ .probe = scmi_probe,
+};
+
+static int scmi_drv_register(void)
+{
+ rt_platform_driver_register(&scmi_driver);
+
+ return 0;
+}
+INIT_SUBSYS_EXPORT(scmi_drv_register);
diff --git a/components/drivers/firmware/arm_scmi/agent.h b/components/drivers/firmware/arm_scmi/agent.h
new file mode 100755
index 0000000000..a28572f43e
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/agent.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#ifndef __SCMI_AGENT_H__
+#define __SCMI_AGENT_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "shmem.h"
+
+struct scmi_agent;
+
+struct scmi_agent_ops
+{
+ const char *name;
+
+ rt_err_t (*setup)(struct scmi_agent *agent, struct rt_device *dev);
+ rt_err_t (*process_msg)(struct scmi_agent *agent, struct rt_scmi_msg *msg);
+};
+
+struct scmi_agent
+{
+ const struct scmi_agent_ops *ops;
+
+ void *priv;
+};
+
+#endif /* __SCMI_AGENT_H__ */
diff --git a/components/drivers/firmware/arm_scmi/bus.c b/components/drivers/firmware/arm_scmi/bus.c
new file mode 100755
index 0000000000..e4e9c7e12a
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/bus.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "scmi.bus"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct rt_bus scmi_bus;
+
+rt_err_t rt_scmi_driver_register(struct rt_scmi_driver *driver)
+{
+ RT_ASSERT(driver != RT_NULL);
+
+ driver->parent.bus = &scmi_bus;
+
+ return rt_driver_register(&driver->parent);
+}
+
+rt_err_t rt_scmi_device_register(struct rt_scmi_device *device)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ return rt_bus_add_device(&scmi_bus, &device->parent);
+}
+static rt_bool_t scmi_match(rt_driver_t drv, rt_device_t dev)
+{
+ const struct rt_scmi_device_id *id;
+ struct rt_scmi_driver *driver = rt_container_of(drv, struct rt_scmi_driver, parent);
+ struct rt_scmi_device *device = rt_container_of(dev, struct rt_scmi_device, parent);
+
+ for (id = driver->ids; id->protocol_id; ++id)
+ {
+ if (id->protocol_id == device->protocol_id)
+ {
+ if (!id->name || !device->name || !rt_strcmp(id->name, device->name))
+ {
+ return RT_TRUE;
+ }
+ }
+ }
+
+ return RT_FALSE;
+}
+
+static rt_err_t scmi_probe(rt_device_t dev)
+{
+ rt_err_t err;
+ struct rt_scmi_driver *driver = rt_container_of(dev->drv, struct rt_scmi_driver, parent);
+ struct rt_scmi_device *device = rt_container_of(dev, struct rt_scmi_device, parent);
+
+ if (!device->agent)
+ {
+ return -RT_EINVAL;
+ }
+
+ err = driver->probe(device);
+
+ return err;
+}
+
+static struct rt_bus scmi_bus =
+{
+ .name = "scmi",
+ .match = scmi_match,
+ .probe = scmi_probe,
+};
+
+static int scmi_bus_init(void)
+{
+ rt_bus_register(&scmi_bus);
+
+ return 0;
+}
+INIT_CORE_EXPORT(scmi_bus_init);
diff --git a/components/drivers/firmware/arm_scmi/shmem.c b/components/drivers/firmware/arm_scmi/shmem.c
new file mode 100755
index 0000000000..876398471e
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/shmem.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#define DBG_TAG "scmi.shmem"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "shmem.h"
+
+struct scmi_shared_mem
+{
+ rt_le32_t reserved;
+ rt_le32_t channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR rt_cpu_to_le32(RT_BIT(1))
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE rt_cpu_to_le32(RT_BIT(0))
+ rt_le32_t reserved1[2];
+ rt_le32_t flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED rt_cpu_to_le32(RT_BIT(0))
+ rt_le32_t length;
+ rt_le32_t msg_header;
+ rt_uint8_t msg_payload[];
+};
+
+rt_err_t scmi_shmem_msg_write(struct scmi_shared_mem *shmem,
+ struct rt_scmi_msg *msg)
+{
+ if (!shmem || !msg)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((!msg->in_msg && msg->in_msg_size) || (!msg->out_msg && msg->out_msg_size))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!(shmem->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE))
+ {
+ LOG_E("Channel busy");
+
+ return -RT_EBUSY;
+ }
+
+ /* Load message in shared memory */
+ shmem->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ shmem->length = rt_cpu_to_le32(msg->in_msg_size + sizeof(shmem->msg_header));
+ shmem->msg_header = rt_cpu_to_le32(scmi_header(
+ msg->message_id, 0, msg->sdev->protocol_id, 0));
+
+ if (msg->in_msg)
+ {
+ rt_memcpy(shmem->msg_payload, msg->in_msg, msg->in_msg_size);
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t scmi_shmem_msg_read(struct scmi_shared_mem *shmem, struct rt_scmi_msg *msg)
+{
+ rt_size_t length;
+
+ if (!shmem || !msg)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!(shmem->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE))
+ {
+ LOG_E("Channel unexpectedly busy");
+
+ return -RT_EBUSY;
+ }
+
+ if (shmem->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR)
+ {
+ LOG_E("Channel error reported, reset channel");
+
+ return -RT_EIO;
+ }
+
+ length = rt_le32_to_cpu(shmem->length);
+
+ if (length > msg->out_msg_size + sizeof(shmem->msg_header))
+ {
+ LOG_E("Buffer < %u too small", length);
+
+ return -RT_EINVAL;
+ }
+
+ msg->out_msg_size = length - sizeof(shmem->msg_header);
+
+ rt_memcpy(msg->out_msg, shmem->msg_payload, msg->out_msg_size);
+
+ return RT_EOK;
+}
+
+void scmi_shmem_clear_channel(struct scmi_shared_mem *shmem)
+{
+ if (shmem)
+ {
+ shmem->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+ }
+}
diff --git a/components/drivers/firmware/arm_scmi/shmem.h b/components/drivers/firmware/arm_scmi/shmem.h
new file mode 100755
index 0000000000..fd30213add
--- /dev/null
+++ b/components/drivers/firmware/arm_scmi/shmem.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#ifndef __SCMI_SHMEM_H__
+#define __SCMI_SHMEM_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+struct scmi_shared_mem;
+
+rt_err_t scmi_shmem_msg_write(struct scmi_shared_mem *shmem, struct rt_scmi_msg *msg);
+rt_err_t scmi_shmem_msg_read(struct scmi_shared_mem *shmem, struct rt_scmi_msg *msg);
+void scmi_shmem_clear_channel(struct scmi_shared_mem *shmem);
+
+#endif /* __SCMI_SHMEM_H__ */
diff --git a/components/drivers/include/drivers/scmi.h b/components/drivers/include/drivers/scmi.h
new file mode 100755
index 0000000000..0605ce3ca7
--- /dev/null
+++ b/components/drivers/include/drivers/scmi.h
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#ifndef __SCMI_H__
+#define __SCMI_H__
+
+#include <rtdef.h>
+#include <drivers/misc.h>
+#include <drivers/byteorder.h>
+
+#define SCMI_PROTOCOL_ID_BASE 0x10
+#define SCMI_PROTOCOL_ID_POWER 0x11
+#define SCMI_PROTOCOL_ID_SYSTEM 0x12
+#define SCMI_PROTOCOL_ID_PERF 0x13
+#define SCMI_PROTOCOL_ID_CLOCK 0x14
+#define SCMI_PROTOCOL_ID_SENSOR 0x15
+#define SCMI_PROTOCOL_ID_RESET 0x16
+#define SCMI_PROTOCOL_ID_VOLTAGE 0x17
+#define SCMI_PROTOCOL_ID_POWERCAP 0x18
+#define SCMI_PROTOCOL_ID_PINCTRL 0x19
+
+#define SCMI_SUCCESS 0 /* Success */
+#define SCMI_ERR_SUPPORT (-1) /* Not supported */
+#define SCMI_ERR_PARAMS (-2) /* Invalid Parameters */
+#define SCMI_ERR_ACCESS (-3) /* Invalid access/permission denied */
+#define SCMI_ERR_ENTRY (-4) /* Not found */
+#define SCMI_ERR_RANGE (-5) /* Value out of range */
+#define SCMI_ERR_BUSY (-6) /* Device busy */
+#define SCMI_ERR_COMMS (-7) /* Communication Error */
+#define SCMI_ERR_GENERIC (-8) /* Generic Error */
+#define SCMI_ERR_HARDWARE (-9) /* Hardware Error */
+#define SCMI_ERR_PROTOCOL (-10) /* Protocol Error */
+
+#define SCMI_MAX_STR_SIZE 64
+#define SCMI_SHORT_NAME_MAX_SIZE 16
+#define SCMI_MAX_NUM_RATES 16
+
+struct rt_scmi_device;
+
+typedef void (*rt_scmi_msg_callback)(struct rt_scmi_device *sdev, rt_uint8_t *msg, rt_size_t size);
+
+/*
+ * struct rt_scmi_msg - Context of a SCMI message sent and the response received
+ *
+ */
+struct rt_scmi_msg
+{
+ struct rt_scmi_device *sdev;
+
+ rt_scmi_msg_callback rx_callback;
+
+ rt_uint32_t message_id;
+
+ rt_uint8_t *in_msg;
+ rt_size_t in_msg_size;
+
+ rt_uint8_t *out_msg;
+ rt_size_t out_msg_size;
+};
+
+/* Helper macro to match a message on input/output array references */
+#define RT_SCMI_MSG_RAW(MSG_ID, IN, IN_SIZE, OUT, OUT_SIZE) \
+(struct rt_scmi_msg) { \
+ .message_id = MSG_ID, \
+ .in_msg = (rt_uint8_t *)(IN), \
+ .in_msg_size = IN_SIZE, \
+ .out_msg = (rt_uint8_t *)(OUT), \
+ .out_msg_size = OUT_SIZE, \
+}
+
+#define RT_SCMI_MSG_IN_OUT(MSG_ID, IN, OUT) \
+ RT_SCMI_MSG_RAW(MSG_ID, IN, sizeof(*(IN)), OUT, sizeof(*(OUT)))
+
+#define RT_SCMI_MSG_IN(MSG_ID, IN) \
+ RT_SCMI_MSG_RAW(MSG_ID, IN, sizeof(*(IN)), RT_NULL, 0)
+
+#define RT_SCMI_MSG_OUT(MSG_ID, OUT) \
+ RT_SCMI_MSG_RAW(MSG_ID, RT_NULL, 0, OUT, sizeof(*(OUT)))
+
+#define SCMI_HDR_TOKEN(token) (((token) << 18) & RT_GENMASK(31, 18))
+#define SCMI_HDR_PROTOCOL_ID(proto) (((proto) << 10) & RT_GENMASK(17, 10))
+#define SCMI_HDR_MESSAGE_TYPE(type) (((type) << 18) & RT_GENMASK(9, 8))
+#define SCMI_HDR_MESSAGE_ID(id) ((id) & RT_GENMASK(7, 0))
+
+rt_inline rt_uint32_t scmi_header(unsigned msg_id, unsigned msg_type,
+ unsigned protocol_id, unsigned token)
+{
+ return SCMI_HDR_TOKEN(token) |
+ SCMI_HDR_MESSAGE_TYPE(msg_type) |
+ SCMI_HDR_PROTOCOL_ID(protocol_id) |
+ SCMI_HDR_MESSAGE_ID(msg_id);
+}
+
+enum scmi_common_message_id
+{
+ SCMI_COM_MSG_VERSION = 0x0,
+ SCMI_COM_MSG_ATTRIBUTES = 0x1,
+ SCMI_COM_MSG_MESSAGE_ATTRIBUTES = 0x2,
+};
+
+/*
+ * SCMI Power Protocol
+ */
+enum scmi_power_protocol_cmd
+{
+ SCMI_POWER_DOMAIN_ATTRIBUTES = 0x3,
+ SCMI_POWER_STATE_SET = 0x4,
+ SCMI_POWER_STATE_GET = 0x5,
+ SCMI_POWER_STATE_NOTIFY = 0x6,
+ SCMI_POWER_DOMAIN_NAME_GET = 0x8,
+};
+
+/**
+ * struct scmi_power_attributes - Response payload for SCMI_COM_MSG_ATTRIBUTES command
+ */
+struct scmi_power_attributes
+{
+ rt_le32_t state;
+ rt_le16_t num_domains;
+ rt_le16_t reserved;
+ rt_le32_t stats_addr_low;
+ rt_le32_t stats_addr_high;
+ rt_le32_t stats_size;
+};
+
+/**
+ * struct scmi_power_state_set_in - Message payload for SCMI_POWER_STATE_SET command
+ */
+struct scmi_power_state_set_in
+{
+ rt_le32_t flags;
+ rt_le32_t domain;
+#define SCMI_POWER_STATE_TYPE_SHIFT 30
+#define SCMI_POWER_STATE_ID_MASK (RT_BIT(28) - 1)
+#define SCMI_POWER_STATE_PARAM(type, id) ((((type) & RT_BIT(0)) << SCMI_POWER_STATE_TYPE_SHIFT) | ((id) & SCMI_POWER_STATE_ID_MASK))
+#define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0)
+#define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0)
+ rt_le32_t state;
+};
+
+/**
+ * struct scmi_power_state_set_out - Response payload for SCMI_POWER_STATE_SET command
+ */
+struct scmi_power_state_set_out
+{
+ rt_le32_t state;
+};
+
+/*
+ * SCMI Clock Protocol
+ */
+enum scmi_clock_message_id
+{
+ SCMI_CLOCK_ATTRIBUTES = 0x3,
+ SCMI_CLOCK_DESCRIBE_RATES = 0x4,
+ SCMI_CLOCK_RATE_SET = 0x5,
+ SCMI_CLOCK_RATE_GET = 0x6,
+ SCMI_CLOCK_CONFIG_SET = 0x7,
+ SCMI_CLOCK_NAME_GET = 0x8,
+};
+
+/**
+ * struct scmi_clk_attributes - Response payload for SCMI_COM_MSG_ATTRIBUTES command
+ */
+struct scmi_clk_attributes
+{
+ rt_le32_t status;
+ rt_le16_t num_clocks;
+ rt_uint8_t max_async_req;
+ rt_uint8_t reserved;
+};
+
+/**
+ * struct scmi_clk_describe_attributes_in - Message payload for SCMI_CLOCK_ATTRIBUTES command
+ */
+struct scmi_clk_describe_attributes_in
+{
+ rt_le32_t clock_id;
+};
+
+/**
+ * struct scmi_clk_describe_attributes_out - Response payload for SCMI_CLOCK_ATTRIBUTES command
+ * clock in response to a clock enable request from an agent
+ */
+struct scmi_clk_describe_attributes_out
+{
+ rt_le32_t status;
+ rt_le32_t attributes;
+#define CLOCK_ENABLE RT_BIT(0)
+#define SUPPORTS_RATE_CHANGED_NOTIF(x) ((x) & RT_BIT(31))
+#define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & RT_BIT(30))
+#define SUPPORTS_EXTENDED_NAMES(x) ((x) & RT_BIT(29))
+ rt_uint8_t name[SCMI_SHORT_NAME_MAX_SIZE];
+ rt_le32_t clock_enable_latency;
+};
+
+/**
+ * struct scmi_clk_describe_rates_in - Message payload for SCMI_CLOCK_DESCRIBE_RATES command
+ */
+struct scmi_clk_describe_rates_in
+{
+ rt_le32_t id;
+ rt_le32_t rate_index;
+};
+
+/**
+ * struct scmi_clk_describe_rates_out - Response payload for SCMI_CLOCK_DESCRIBE_RATES command
+ */
+struct scmi_clk_describe_rates_out
+{
+ rt_le32_t status;
+ rt_le32_t num_rates_flags;
+#define SCMI_NUM_RETURNED(x) ((x) & 0xfff)
+#define SCMI_RATE_DISCRETE(x) !((x) & RT_BIT(12))
+#define SCMI_NUM_REMAINING(x) ((x) >> 16)
+ struct
+ {
+ rt_le32_t value_low;
+ rt_le32_t value_high;
+ } rate[];
+#define SCMI_RATE_TO_U64(X) \
+({ \
+ typeof(X) x = (X); \
+ rt_le32_to_cpu((x).value_low) | (rt_uint64_t)rt_le32_to_cpu((x).value_high) << 32; \
+})
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for SCMI_CLOCK_RATE_SET command
+ */
+struct scmi_clk_rate_set_in
+{
+#define SCMI_CLK_RATE_ASYNC_NOTIFY RT_BIT(0)
+#define SCMI_CLK_RATE_ASYNC_NORESP (RT_BIT(0) | RT_BIT(1))
+#define SCMI_CLK_RATE_ROUND_DOWN 0
+#define SCMI_CLK_RATE_ROUND_UP RT_BIT(2)
+#define SCMI_CLK_RATE_ROUND_CLOSEST RT_BIT(3)
+ rt_le32_t flags;
+ rt_le32_t clock_id;
+ rt_le32_t rate_lsb;
+ rt_le32_t rate_msb;
+};
+
+/**
+ * struct scmi_clk_rate_set_out - Response payload for SCMI_CLOCK_RATE_SET command
+ */
+struct scmi_clk_rate_set_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for SCMI_CLOCK_RATE_GET command
+ */
+struct scmi_clk_rate_get_in
+{
+ rt_le32_t clock_id;
+};
+
+/**
+ * struct scmi_clk_rate_get_out - Response payload for SCMI_CLOCK_RATE_GET command
+ */
+struct scmi_clk_rate_get_out
+{
+ rt_le32_t status;
+ rt_le32_t rate_lsb;
+ rt_le32_t rate_msb;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for SCMI_CLOCK_CONFIG_SET command
+ */
+struct scmi_clk_state_in
+{
+ rt_le32_t clock_id;
+ rt_le32_t attributes;
+ rt_le32_t ext_config_val;
+};
+
+/**
+ * struct scmi_clk_state_out - Response payload for SCMI_CLOCK_CONFIG_SET command
+ */
+struct scmi_clk_state_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_clk_name_in - Message payload for SCMI_CLOCK_NAME_GET command
+ */
+struct scmi_clk_name_in
+{
+ rt_le32_t clock_id;
+};
+
+/**
+ * struct scmi_clk_name_out - Response payload for SCMI_CLOCK_NAME_GET command
+ */
+struct scmi_clk_name_out
+{
+ rt_le32_t status;
+ rt_le32_t flags;
+ rt_uint8_t name[SCMI_MAX_STR_SIZE];
+};
+
+/*
+ * SCMI Sensor Domain Protocol
+ */
+enum scmi_sensor_message_id
+{
+ SCMI_SENSOR_DESCRIPTION_GET = 0x3,
+ SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x4,
+ SCMI_SENSOR_TRIP_POINT_CONFIG = 0x5,
+ SCMI_SENSOR_READING_GET = 0x6,
+ SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x7,
+ SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x8,
+ SCMI_SENSOR_CONFIG_GET = 0x9,
+ SCMI_SENSOR_CONFIG_SET = 0xa,
+ SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xb,
+ SCMI_SENSOR_NAME_GET = 0xc,
+ SCMI_SENSOR_AXIS_NAME_GET = 0xd,
+};
+
+enum scmi_sensor_type
+{
+ SCMI_SENSOR_TYPE_NONE = 0x0,
+ SCMI_SENSOR_TYPE_UNSPEC = 0x1,
+ SCMI_SENSOR_TYPE_TEMPERATURE_C = 0x2,
+ SCMI_SENSOR_TYPE_TEMPERATURE_F = 0x3,
+ SCMI_SENSOR_TYPE_TEMPERATURE_K = 0x4,
+ SCMI_SENSOR_TYPE_VOLTAGE = 0x5,
+ SCMI_SENSOR_TYPE_CURRENT = 0x6,
+ SCMI_SENSOR_TYPE_POWER = 0x7,
+ SCMI_SENSOR_TYPE_ENERGY = 0x8,
+ SCMI_SENSOR_TYPE_CHARGE = 0x9,
+ SCMI_SENSOR_TYPE_VOLTAMPERE = 0xa,
+ SCMI_SENSOR_TYPE_NITS = 0xb,
+ SCMI_SENSOR_TYPE_LUMENS = 0xc,
+ SCMI_SENSOR_TYPE_LUX = 0xd,
+ SCMI_SENSOR_TYPE_CANDELAS = 0xe,
+ SCMI_SENSOR_TYPE_KPA = 0xf,
+ SCMI_SENSOR_TYPE_PSI = 0x10,
+ SCMI_SENSOR_TYPE_NEWTON = 0x11,
+ SCMI_SENSOR_TYPE_CFM = 0x12,
+ SCMI_SENSOR_TYPE_RPM = 0x13,
+ SCMI_SENSOR_TYPE_HERTZ = 0x14,
+ SCMI_SENSOR_TYPE_SECS = 0x15,
+ SCMI_SENSOR_TYPE_MINS = 0x16,
+ SCMI_SENSOR_TYPE_HOURS = 0x17,
+ SCMI_SENSOR_TYPE_DAYS = 0x18,
+ SCMI_SENSOR_TYPE_WEEKS = 0x19,
+ SCMI_SENSOR_TYPE_MILS = 0x1a,
+ SCMI_SENSOR_TYPE_INCHES = 0x1b,
+ SCMI_SENSOR_TYPE_FEET = 0x1c,
+ SCMI_SENSOR_TYPE_CUBIC_INCHES = 0x1d,
+ SCMI_SENSOR_TYPE_CUBIC_FEET = 0x1e,
+ SCMI_SENSOR_TYPE_METERS = 0x1f,
+ SCMI_SENSOR_TYPE_CUBIC_CM = 0x20,
+ SCMI_SENSOR_TYPE_CUBIC_METERS = 0x21,
+ SCMI_SENSOR_TYPE_LITERS = 0x22,
+ SCMI_SENSOR_TYPE_FLUID_OUNCES = 0x23,
+ SCMI_SENSOR_TYPE_RADIANS = 0x24,
+ SCMI_SENSOR_TYPE_STERADIANS = 0x25,
+ SCMI_SENSOR_TYPE_REVOLUTIONS = 0x26,
+ SCMI_SENSOR_TYPE_CYCLES = 0x27,
+ SCMI_SENSOR_TYPE_GRAVITIES = 0x28,
+ SCMI_SENSOR_TYPE_OUNCES = 0x29,
+ SCMI_SENSOR_TYPE_POUNDS = 0x2a,
+ SCMI_SENSOR_TYPE_FOOT_POUNDS = 0x2b,
+ SCMI_SENSOR_TYPE_OUNCE_INCHES = 0x2c,
+ SCMI_SENSOR_TYPE_GAUSS = 0x2d,
+ SCMI_SENSOR_TYPE_GILBERTS = 0x2e,
+ SCMI_SENSOR_TYPE_HENRIES = 0x2f,
+ SCMI_SENSOR_TYPE_FARADS = 0x30,
+ SCMI_SENSOR_TYPE_OHMS = 0x31,
+ SCMI_SENSOR_TYPE_SIEMENS = 0x32,
+ SCMI_SENSOR_TYPE_MOLES = 0x33,
+ SCMI_SENSOR_TYPE_BECQUERELS = 0x34,
+ SCMI_SENSOR_TYPE_PPM = 0x35,
+ SCMI_SENSOR_TYPE_DECIBELS = 0x36,
+ SCMI_SENSOR_TYPE_DBA = 0x37,
+ SCMI_SENSOR_TYPE_DBC = 0x38,
+ SCMI_SENSOR_TYPE_GRAYS = 0x39,
+ SCMI_SENSOR_TYPE_SIEVERTS = 0x3a,
+ SCMI_SENSOR_TYPE_COLOR_TEMP_K = 0x3b,
+ SCMI_SENSOR_TYPE_BITS = 0x3c,
+ SCMI_SENSOR_TYPE_BYTES = 0x3d,
+ SCMI_SENSOR_TYPE_WORDS = 0x3e,
+ SCMI_SENSOR_TYPE_DWORDS = 0x3f,
+ SCMI_SENSOR_TYPE_QWORDS = 0x40,
+ SCMI_SENSOR_TYPE_PERCENTAGE = 0x41,
+ SCMI_SENSOR_TYPE_PASCALS = 0x42,
+ SCMI_SENSOR_TYPE_COUNTS = 0x43,
+ SCMI_SENSOR_TYPE_GRAMS = 0x44,
+ SCMI_SENSOR_TYPE_NEWTON_METERS = 0x45,
+ SCMI_SENSOR_TYPE_HITS = 0x46,
+ SCMI_SENSOR_TYPE_MISSES = 0x47,
+ SCMI_SENSOR_TYPE_RETRIES = 0x48,
+ SCMI_SENSOR_TYPE_OVERRUNS = 0x49,
+ SCMI_SENSOR_TYPE_UNDERRUNS = 0x4a,
+ SCMI_SENSOR_TYPE_COLLISIONS = 0x4b,
+ SCMI_SENSOR_TYPE_PACKETS = 0x4c,
+ SCMI_SENSOR_TYPE_MESSAGES = 0x4d,
+ SCMI_SENSOR_TYPE_CHARS = 0x4e,
+ SCMI_SENSOR_TYPE_ERRORS = 0x4f,
+ SCMI_SENSOR_TYPE_CORRECTED_ERRS = 0x50,
+ SCMI_SENSOR_TYPE_UNCORRECTABLE_ERRS = 0x51,
+ SCMI_SENSOR_TYPE_SQ_MILS = 0x52,
+ SCMI_SENSOR_TYPE_SQ_INCHES = 0x53,
+ SCMI_SENSOR_TYPE_SQ_FEET = 0x54,
+ SCMI_SENSOR_TYPE_SQ_CM = 0x55,
+ SCMI_SENSOR_TYPE_SQ_METERS = 0x56,
+ SCMI_SENSOR_TYPE_RADIANS_SEC = 0x57,
+ SCMI_SENSOR_TYPE_BPM = 0x58,
+ SCMI_SENSOR_TYPE_METERS_SEC_SQUARED = 0x59,
+ SCMI_SENSOR_TYPE_METERS_SEC = 0x5a,
+ SCMI_SENSOR_TYPE_CUBIC_METERS_SEC = 0x5b,
+ SCMI_SENSOR_TYPE_MM_MERCURY = 0x5c,
+ SCMI_SENSOR_TYPE_RADIANS_SEC_SQUARED = 0x5d,
+ SCMI_SENSOR_TYPE_OEM_UNIT = 0xff
+};
+
+/**
+ * struct scmi_sensor_attributes - Response payload for SCMI_COM_MSG_ATTRIBUTES command
+ */
+struct scmi_sensor_attributes
+{
+ rt_le16_t num_sensors;
+ rt_uint8_t max_requests;
+ rt_uint8_t reserved;
+ rt_le32_t reg_addr_low;
+ rt_le32_t reg_addr_high;
+ rt_le32_t reg_size;
+};
+
+/**
+ * struct scmi_sensor_description_get_in - Payload for SCMI_SENSOR_DESCRIPTION_GET command
+ */
+struct scmi_sensor_description_get_in
+{
+ rt_le32_t desc_index;
+};
+
+/**
+ * struct scmi_sensor_description_get_out - Response payload for SCMI_SENSOR_DESCRIPTION_GET command
+ */
+struct scmi_sensor_description_get_out
+{
+ rt_le32_t status;
+#define SCMI_SENSOR_DESC_RETURNED_NR(x) RT_FIELD_GET(RT_GENMASK(11, 0), (x))
+#define SCMI_SENSOR_DESC_REMAINING_NR(x) RT_FIELD_GET(RT_GENMASK(31, 16), (x))
+ rt_le32_t num_sensor_flags;
+ struct
+ {
+ rt_le32_t id;
+#define SCMI_SENSOR_ASYNC_READ(x) RT_FIELD_GET(RT_BIT(31), (x))
+#define SCMI_SENSOR_EXT_NAMES(x) RT_FIELD_GET(RT_BIT(29), (x))
+#define SCMI_SENSOR_TRIP_POINTS_NR(x) RT_FIELD_GET(RT_GENMASK(7, 0), (x))
+ rt_le32_t attributes_low;
+#define SCMI_SENSOR_SCALE(x) RT_FIELD_GET(RT_GENMASK(15, 11), (x))
+#define SCMI_SENSOR_SCALE_SIGN RT_BIT(4)
+#define SCMI_SENSOR_SCALE_EXTEND RT_GENMASK(31, 5)
+#define SCMI_SENSOR_TYPE(x) RT_FIELD_GET(RT_GENMASK(7, 0), (x))
+ rt_le32_t attributes_high;
+ rt_uint8_t name[SCMI_SHORT_NAME_MAX_SIZE];
+ rt_le32_t power;
+ rt_le32_t resolution;
+ rt_le32_t min_range_low;
+ rt_le32_t min_range_high;
+ rt_le32_t max_range_low;
+ rt_le32_t max_range_high;
+ } desc[];
+};
+
+/**
+ * struct scmi_scmi_sensor_axis_description_get_in - Payload for SCMI_SENSOR_AXIS_DESCRIPTION_GET command
+ */
+struct scmi_scmi_sensor_axis_description_get_in
+{
+ rt_le32_t id;
+ rt_le32_t axis_desc_index;
+};
+
+/**
+ * struct scmi_scmi_sensor_axis_description_get_out - Response payload for SCMI_SENSOR_AXIS_DESCRIPTION_GET command
+ */
+struct scmi_scmi_sensor_axis_description_get_out
+{
+ rt_le32_t status;
+#define SCMI_SENSOR_AXIS_RETURNED_NR(x) RT_FIELD_GET(RT_GENMASK(5, 0), (x))
+#define SCMI_SENSOR_AXIS_REMAINING_NR(x) RT_FIELD_GET(RT_GENMASK(31, 26), (x))
+ rt_le32_t num_axis_flags;
+ struct
+ {
+ rt_le32_t axis_id;
+#define SCMI_SENSOR_AXIS_EXT_AXIS_NAME(x) RT_FIELD_GET(RT_BIT(9), (x))
+ rt_le32_t axis_attributes_low;
+#define SCMI_SENSOR_AXIS_SCALE(x) RT_FIELD_GET(RT_GENMASK(15, 11), (x))
+#define SCMI_SENSOR_AXIS_TYPE(x) RT_FIELD_GET(RT_GENMASK(7, 0), (x))
+ rt_le32_t axis_attributes_high;
+ rt_uint8_t name[SCMI_SHORT_NAME_MAX_SIZE];
+ rt_le32_t axis_resolution;
+ rt_le32_t axis_min_range_low;
+ rt_le32_t axis_min_range_high;
+ rt_le32_t axis_max_range_low;
+ rt_le32_t axis_max_range_high;
+ } desc[];
+};
+
+/**
+ * struct scmi_sensor_list_update_intervals_in - Payload for SCMI_SENSOR_LIST_UPDATE_INTERVALS command
+ */
+struct scmi_sensor_list_update_intervals_in
+{
+ rt_le32_t id;
+ rt_le32_t index;
+};
+
+/**
+ * struct scmi_sensor_list_update_intervals_out - Response payload for SCMI_SENSOR_LIST_UPDATE_INTERVALS command
+ */
+struct scmi_sensor_list_update_intervals_out
+{
+ rt_le32_t status;
+ rt_le32_t flags;
+ rt_le32_t intervals[];
+};
+
+/**
+ * struct scmi_sensor_trip_point_notify_in - Payload for SCMI_SENSOR_TRIP_POINT_NOTIFY command
+ */
+struct scmi_sensor_trip_point_notify_in
+{
+ rt_le32_t id;
+#define SCMI_SENSOR_NOTIFY_ALL RT_BIT(0)
+ rt_le32_t event_control;
+};
+
+/**
+ * struct scmi_sensor_trip_point_notify_out - Response payload for SCMI_SENSOR_TRIP_POINT_NOTIFY command
+ */
+struct scmi_sensor_trip_point_notify_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_sensor_trip_point_config_in - Payload for SCMI_SENSOR_TRIP_POINT_CONFIG command
+ */
+struct scmi_sensor_trip_point_config_in
+{
+ rt_le32_t id;
+#define SCMI_SENSOR_TRIP_POINT_EVENT_MASK 0x3
+#define SCMI_SENSOR_TRIP_POINT_DISABLED 0x0
+#define SCMI_SENSOR_TRIP_POINT_POSITIVE 0x1
+#define SCMI_SENSOR_TRIP_POINT_NEGATIVE 0x2
+#define SCMI_SENSOR_TRIP_POINT_BOTH 0x3
+#define SCMI_SENSOR_TRIP_POINT_ID(x) (((x) & 0xff) << 4)
+ rt_le32_t trip_point_ev_ctrl;
+ rt_le32_t trip_point_val_low;
+ rt_le32_t trip_point_val_high;
+};
+
+/**
+ * struct scmi_sensor_trip_point_config_out - Response payload for SCMI_SENSOR_TRIP_POINT_CONFIG command
+ */
+struct scmi_sensor_trip_point_config_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_sensor_config_get_in - Payload for SCMI_SENSOR_CONFIG_GET command
+ */
+struct scmi_sensor_config_get_in
+{
+ rt_le32_t id;
+};
+
+/**
+ * struct scmi_sensor_config_get_out - Response payload for SCMI_SENSOR_CONFIG_GET command
+ */
+struct scmi_sensor_config_get_out
+{
+ rt_le32_t status;
+#define SCMI_SENSOR_INTERVALS_SEC(x) RT_FIELD_GET(RT_GENMASK(31, 16), (x))
+#define SCMI_SENSOR_INTERVALS_EXP(x) RT_FIELD_GET(RT_GENMASK(15, 11), (x)) /* SEC x (10 ^ EXP) */
+#define SCMI_SENSOR_TEMP_RP(x) RT_FIELD_GET(RT_BIT(1), (x))
+#define SCMI_SENSOR_STATUS_EN(x) RT_FIELD_GET(RT_BIT(0), (x))
+ rt_le32_t config;
+};
+
+/**
+ * struct scmi_sensor_config_set_in - Payload for SCMI_SENSOR_CONFIG_SET command
+ */
+struct scmi_sensor_config_set_in
+{
+ rt_le32_t id;
+ rt_le32_t config;
+};
+
+/**
+ * struct scmi_sensor_config_set_out - Response payload for SCMI_SENSOR_CONFIG_SET command
+ */
+struct scmi_sensor_config_set_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_sensor_reading_in - Payload for SCMI_SENSOR_READING_GET command
+ */
+struct scmi_sensor_reading_in
+{
+ rt_le32_t id;
+#define SCMI_SENSOR_FLAG_ASYNC RT_BIT(0)
+ rt_le32_t flags;
+};
+
+/**
+ * struct scmi_sensor_reading_out - Response payload for SCMI_SENSOR_READING_GET command
+ */
+struct scmi_sensor_reading_out
+{
+ rt_le32_t status;
+ struct
+ {
+ rt_le32_t value_low;
+ rt_le32_t value_high;
+ rt_le32_t timestamp_low;
+ rt_le32_t timestamp_high;
+ } readings[];
+};
+
+/**
+ * struct scmi_sensor_continuous_update_notify_in - Payload for SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY command
+ */
+struct scmi_sensor_continuous_update_notify_in
+{
+ rt_le32_t id;
+#define SCMI_SENSOR_FLAG_NOTIFY_ENABLE RT_BIT(0)
+ rt_le32_t notify_enable;
+};
+
+/**
+ * struct scmi_sensor_continuous_update_notify_out - Response payload for SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY command
+ */
+struct scmi_sensor_continuous_update_notify_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_sensor_name_in - Payload for SCMI_SENSOR_NAME_GET command
+ */
+struct scmi_sensor_name_in
+{
+ rt_le32_t id;
+};
+
+/**
+ * struct scmi_sensor_name_out - Response payload for SCMI_SENSOR_NAME_GET command
+ */
+struct scmi_sensor_name_out
+{
+ rt_le32_t status;
+ rt_le32_t flags;
+ rt_uint8_t name[SCMI_MAX_STR_SIZE];
+};
+
+/**
+ * struct scmi_sensor_axis_name_in - Payload for SCMI_SENSOR_AXIS_NAME_GET command
+ */
+struct scmi_sensor_axis_name_in
+{
+ rt_le32_t id;
+ rt_le32_t axis_id;
+};
+
+/**
+ * struct scmi_sensor_axis_name_out - Response payload for SCMI_SENSOR_AXIS_NAME_GET command
+ */
+struct scmi_sensor_axis_name_out
+{
+ rt_le32_t status;
+ rt_le32_t flags;
+ struct
+ {
+ rt_le32_t axis_id;
+ rt_uint8_t name[SCMI_MAX_STR_SIZE];
+ } desc[];
+};
+
+/*
+ * SCMI Reset Domain Protocol
+ */
+
+enum scmi_reset_message_id
+{
+ SCMI_RESET_DOMAIN_ATTRIBUTES = 0x3,
+ SCMI_RESET_RESET = 0x4,
+};
+
+#define SCMI_RESET_ATTRIBUTES_FLAG_ASYNC RT_BIT(31)
+#define SCMI_RESET_ATTRIBUTES_FLAG_NOTIF RT_BIT(30)
+
+/**
+ * struct scmi_reset_attr_in - Payload for SCMI_RESET_DOMAIN_ATTRIBUTES message
+ */
+struct scmi_reset_attr_in
+{
+ rt_le32_t domain_id;
+};
+
+/**
+ * struct scmi_reset_attr_out - Payload for SCMI_RESET_DOMAIN_ATTRIBUTES response
+ */
+struct scmi_reset_attr_out
+{
+ rt_le32_t status;
+ rt_le32_t attributes;
+ rt_le32_t latency;
+ rt_uint8_t name[SCMI_SHORT_NAME_MAX_SIZE];
+};
+
+/**
+ * struct scmi_reset_in - Message payload for SCMI_RESET_RESET command
+ */
+struct scmi_reset_in
+{
+ rt_le32_t domain_id;
+#define SCMI_RESET_FLAG_RESET RT_BIT(0)
+#define SCMI_RESET_FLAG_ASSERT RT_BIT(1)
+#define SCMI_RESET_FLAG_ASYNC RT_BIT(2)
+ rt_le32_t flags;
+#define SCMI_ARCH_COLD_RESET 0
+ rt_le32_t reset_state;
+};
+
+/**
+ * struct scmi_reset_out - Response payload for SCMI_RESET_RESET command
+ */
+struct scmi_reset_out
+{
+ rt_le32_t status;
+};
+
+/*
+ * SCMI Voltage Domain Protocol
+ */
+
+enum scmi_voltage_domain_message_id
+{
+ SCMI_VOLTAGE_DOMAIN_ATTRIBUTES = 0x3,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_SET = 0x5,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_GET = 0x6,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_SET = 0x7,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_GET = 0x8,
+};
+
+#define SCMI_VOLTAGE_CONFIG_MASK RT_GENMASK(3, 0)
+#define SCMI_VOLTAGE_CONFIG_OFF 0
+#define SCMI_VOLTAGE_CONFIG_ON 0x7
+
+/**
+ * struct scmi_voltage_attributes - Response payload for SCMI_COM_MSG_ATTRIBUTES command
+ */
+struct scmi_voltage_attributes
+{
+ rt_le32_t status;
+ rt_le16_t num_domains;
+ rt_le16_t reserved;
+};
+
+/**
+ * struct scmi_voltage_attr_in - Payload for SCMI_VOLTAGE_DOMAIN_ATTRIBUTES message
+ */
+struct scmi_voltage_attr_in
+{
+ rt_le32_t domain_id;
+};
+
+/**
+ * struct scmi_voltage_attr_out - Payload for SCMI_VOLTAGE_DOMAIN_ATTRIBUTES response
+ */
+struct scmi_voltage_attr_out
+{
+ rt_le32_t status;
+ rt_le32_t attributes;
+ char name[SCMI_SHORT_NAME_MAX_SIZE];
+};
+
+/**
+ * struct scmi_voltage_config_set_in - Message payload for SCMI_VOLTAGE_DOMAIN_CONFIG_SET cmd
+ */
+struct scmi_voltage_config_set_in
+{
+ rt_le32_t domain_id;
+ rt_le32_t config;
+};
+
+/**
+ * struct scmi_voltage_config_set_out - Response for SCMI_VOLTAGE_DOMAIN_CONFIG_SET command
+ */
+struct scmi_voltage_config_set_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_voltage_config_get_in - Message payload for SCMI_VOLTAGE_CONFIG_GET cmd
+ */
+struct scmi_voltage_config_get_in
+{
+ rt_le32_t domain_id;
+};
+
+/**
+ * struct scmi_voltage_config_get_out - Response for SCMI_VOLTAGE_CONFIG_GET command
+ */
+struct scmi_voltage_config_get_out
+{
+ rt_le32_t status;
+ rt_le32_t config;
+};
+
+/**
+ * struct scmi_voltage_level_set_in - Message payload for SCMI_VOLTAGE_DOMAIN_LEVEL_SET cmd
+ */
+struct scmi_voltage_level_set_in
+{
+ rt_le32_t domain_id;
+ rt_le32_t flags;
+ rt_le32_t voltage_level;
+};
+
+/**
+ * struct scmi_voltage_level_set_out - Response for SCMI_VOLTAGE_DOMAIN_LEVEL_SET command
+ */
+struct scmi_voltage_level_set_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_voltage_level_get_in - Message payload for SCMI_VOLTAGE_DOMAIN_LEVEL_GET cmd
+ */
+struct scmi_voltage_level_get_in
+{
+ rt_le32_t domain_id;
+};
+
+/**
+ * struct scmi_voltage_level_get_out - Response for SCMI_VOLTAGE_DOMAIN_LEVEL_GET command
+ */
+struct scmi_voltage_level_get_out
+{
+ rt_le32_t status;
+ rt_le32_t voltage_level;
+};
+
+/*
+ * SCMI Pinctrl Protocol
+ */
+
+enum scmi_pinctrl_message_id
+{
+ SCMI_PINCTRL_ATTRIBUTES = 0x3,
+ SCMI_PINCTRL_LIST_ASSOCIATIONS = 0x4,
+ SCMI_PINCTRL_SETTINGS_GET = 0x5,
+ SCMI_PINCTRL_SETTINGS_CONFIGURE = 0x6,
+ SCMI_PINCTRL_REQUEST = 0x7,
+ SCMI_PINCTRL_RELEASE = 0x8,
+ SCMI_PINCTRL_NAME_GET = 0x9,
+ SCMI_PINCTRL_SET_PERMISSIONS = 0xa,
+};
+
+enum scmi_pinctrl_selector_type
+{
+ SCMI_PINCTRL_TYPE_PIN = 0,
+ SCMI_PINCTRL_TYPE_GROUP,
+ SCMI_PINCTRL_TYPE_FUNCTION,
+};
+
+enum scmi_pinctrl_conf_type
+{
+ SCMI_PINCTRL_DEFAULT = 0,
+ SCMI_PINCTRL_BIAS_BUS_HOLD = 1,
+ SCMI_PINCTRL_BIAS_DISABLE = 2,
+ SCMI_PINCTRL_BIAS_HIGH_IMPEDANCE = 3,
+ SCMI_PINCTRL_BIAS_PULL_UP = 4,
+ SCMI_PINCTRL_BIAS_PULL_DEFAULT = 5,
+ SCMI_PINCTRL_BIAS_PULL_DOWN = 6,
+ SCMI_PINCTRL_DRIVE_OPEN_DRAIN = 7,
+ SCMI_PINCTRL_DRIVE_OPEN_SOURCE = 8,
+ SCMI_PINCTRL_DRIVE_PUSH_PULL = 9,
+ SCMI_PINCTRL_DRIVE_STRENGTH = 10,
+ SCMI_PINCTRL_INPUT_DEBOUNCE = 11,
+ SCMI_PINCTRL_INPUT_MODE = 12,
+ SCMI_PINCTRL_PULL_MODE = 13,
+ SCMI_PINCTRL_INPUT_VALUE = 14,
+ SCMI_PINCTRL_INPUT_SCHMITT = 15,
+ SCMI_PINCTRL_LOW_POWER_MODE = 16,
+ SCMI_PINCTRL_OUTPUT_MODE = 17,
+ SCMI_PINCTRL_OUTPUT_VALUE = 18,
+ SCMI_PINCTRL_POWER_SOURCE = 19,
+ SCMI_PINCTRL_SLEW_RATE = 20,
+ SCMI_PINCTRL_OEM_START = 192,
+ SCMI_PINCTRL_OEM_END = 255,
+};
+
+/**
+ * struct scmi_pinctrl_protocol_attributes - Response payload for SCMI_COM_MSG_ATTRIBUTES command
+ */
+struct scmi_pinctrl_protocol_attributes
+{
+ rt_le32_t status;
+#define SCMI_PINCTRL_GROUPS_NR(x) RT_FIELD_GET(RT_GENMASK(31, 16), (x))
+#define SCMI_PINCTRL_PINS_NR(x) RT_FIELD_GET(RT_GENMASK(15, 0), (x))
+#define SCMI_PINCTRL_FUNCTIONS_NR(x) RT_FIELD_GET(RT_GENMASK(15, 0), (x))
+ rt_le32_t attributes_low;
+ rt_le32_t attributes_high;
+};
+
+/**
+ * struct scmi_pinctrl_attributes_in - Message payload for SCMI_PINCTRL_ATTRIBUTES command
+ */
+struct scmi_pinctrl_attributes_in
+{
+ rt_le32_t identifier;
+ rt_le32_t flags;
+};
+
+/**
+ * struct scmi_pinctrl_attributes_out - Response payload for SCMI_PINCTRL_ATTRIBUTES command
+ */
+struct scmi_pinctrl_attributes_out
+{
+#define SCMI_PINCTRL_EXT_NAME_FLAG(x) RT_FIELD_GET(RT_BIT(31), (x))
+#define SCMI_PINCTRL_NUM_ELEMS(x) RT_FIELD_GET(RT_GENMASK(15, 0), (x))
+ rt_le32_t status;
+ rt_le32_t attributes;
+ rt_uint8_t name[SCMI_SHORT_NAME_MAX_SIZE];
+};
+
+/**
+ * struct scmi_pinctrl_list_assoc_in - Message payload for SCMI_PINCTRL_LIST_ASSOCIATIONS command
+ */
+struct scmi_pinctrl_list_assoc_in
+{
+ rt_le32_t identifier;
+ rt_le32_t flags;
+ rt_le32_t index;
+};
+
+/**
+ * struct scmi_pinctrl_list_assoc_out - Response payload for SCMI_PINCTRL_LIST_ASSOCIATIONS command
+ */
+struct scmi_pinctrl_list_assoc_out
+{
+#define SCMI_PINCTRL_REMAINING(x) RT_FIELD_GET(RT_GENMASK(31, 16), (x))
+#define SCMI_PINCTRL_RETURNED(x) RT_FIELD_GET(RT_GENMASK(11, 0), (x))
+ rt_le32_t status;
+ rt_le32_t flags;
+ rt_le16_t array[];
+};
+
+/**
+ * struct scmi_pinctrl_settings_get_in - Message payload for SCMI_PINCTRL_SETTINGS_GET command
+ */
+struct scmi_pinctrl_settings_get_in
+{
+#define SCMI_PINCTRL_CONFIG_FLAG_MASK RT_GENMASK(19, 18)
+#define SCMI_PINCTRL_SELECTOR_MASK RT_GENMASK(17, 16)
+#define SCMI_PINCTRL_SKIP_CONFIGS_MASK RT_GENMASK(15, 8)
+#define SCMI_PINCTRL_CONFIG_TYPE_MASK RT_GENMASK(7, 0)
+ rt_le32_t identifier;
+ rt_le32_t attributes;
+};
+
+/**
+ * struct scmi_pinctrl_settings_get_out - Response payload for SCMI_PINCTRL_SETTINGS_GET command
+ */
+struct scmi_pinctrl_settings_get_out
+{
+ rt_le32_t status;
+ rt_le32_t function_selected;
+ rt_le32_t num_configs;
+ rt_le32_t configs[];
+};
+
+/**
+ * struct scmi_pinctrl_settings_conf_in - Message payload for SCMI_PINCTRL_SETTINGS_CONFIGURE command
+ */
+struct scmi_pinctrl_settings_conf_in
+{
+ rt_le32_t identifier;
+ rt_le32_t function_id;
+ rt_le32_t attributes;
+ rt_le32_t configs[];
+};
+
+/**
+ * struct scmi_pinctrl_settings_conf_out - Response payload for SCMI_PINCTRL_SETTINGS_CONFIGURE command
+ */
+struct scmi_pinctrl_settings_conf_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_pinctrl_request_in - Message payload for SCMI_PINCTRL_REQUEST command
+ */
+struct scmi_pinctrl_request_in
+{
+ rt_le32_t identifier;
+ rt_le32_t flags;
+};
+
+/**
+ * struct scmi_pinctrl_request_out - Response payload for SCMI_PINCTRL_REQUEST command
+ */
+struct scmi_pinctrl_request_out
+{
+ rt_le32_t status;
+};
+
+/**
+ * struct scmi_pinctrl_request_in - Message payload for SCMI_PINCTRL_NAME_GET command
+ */
+struct scmi_pinctrl_name_get_in
+{
+ rt_le32_t identifier;
+ rt_le32_t flags;
+};
+
+/**
+ * struct scmi_pinctrl_name_get_out - Response payload for SCMI_PINCTRL_NAME_GET command
+ */
+struct scmi_pinctrl_name_get_out
+{
+ rt_le32_t status;
+ rt_le32_t flags;
+ rt_uint8_t name[SCMI_MAX_STR_SIZE];
+};
+
+struct scmi_agent;
+
+struct rt_scmi_device_id
+{
+ rt_uint8_t protocol_id;
+ const char *name;
+};
+
+struct rt_scmi_device
+{
+ struct rt_device parent;
+
+ const char *name;
+ rt_uint8_t protocol_id;
+
+ struct scmi_agent *agent;
+};
+
+struct rt_scmi_driver
+{
+ struct rt_driver parent;
+
+ const char *name;
+ const struct rt_scmi_device_id *ids;
+
+ rt_err_t (*probe)(struct rt_scmi_device *sdev);
+ rt_err_t (*remove)(struct rt_scmi_device *sdev);
+ rt_err_t (*shutdown)(struct rt_scmi_device *sdev);
+};
+
+rt_err_t rt_scmi_driver_register(struct rt_scmi_driver *driver);
+rt_err_t rt_scmi_device_register(struct rt_scmi_device *device);
+
+#define RT_SCMI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, scmi, BUILIN)
+
+rt_err_t rt_scmi_process_msg(struct rt_scmi_device *sdev, struct rt_scmi_msg *msg);
+const char *rt_scmi_strerror(rt_base_t err);
+
+#endif /* __SCMI_H__ */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 7cda82c235..c260fa448b 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -131,6 +131,12 @@ extern "C" {
#include "drivers/thermal.h"
#endif /* RT_USING_THERMAL */
+#ifdef RT_USING_FIRMWARE
+#ifdef RT_FIRMWARE_ARM_SCMI
+#include "drivers/scmi.h"
+#endif /* RT_FIRMWARE_ARM_SCMI */
+#endif /* RT_USING_FIRMWARE */
+
#ifdef RT_USING_HWCACHE
#include "drivers/hwcache.h"
#endif /* RT_USING_HWCACHE */
diff --git a/components/drivers/pinctrl/Kconfig b/components/drivers/pinctrl/Kconfig
index 0a459af218..ac758e2672 100644
--- a/components/drivers/pinctrl/Kconfig
+++ b/components/drivers/pinctrl/Kconfig
@@ -4,6 +4,12 @@ menuconfig RT_USING_PINCTRL
depends on RT_USING_PIN
default n
+config RT_PINCTRL_SCMI
+ bool "Pinctrl driver via ARM SCMI interface"
+ depends on RT_USING_PINCTRL
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
config RT_PINCTRL_SINGLE
bool "Single Pinctrl driver"
depends on RT_USING_PINCTRL
diff --git a/components/drivers/pinctrl/SConscript b/components/drivers/pinctrl/SConscript
index fb4d53f420..213913231f 100644
--- a/components/drivers/pinctrl/SConscript
+++ b/components/drivers/pinctrl/SConscript
@@ -11,6 +11,9 @@ CPPPATH = [cwd + '/../include']
src = ['pinctrl.c']
+if GetDepend(['RT_PINCTRL_SCMI']):
+ src += ['pinctrl-scmi.c']
+
if GetDepend(['RT_PINCTRL_SINGLE']):
src += ['pinctrl-single.c']
diff --git a/components/drivers/pinctrl/pinctrl-scmi.c b/components/drivers/pinctrl/pinctrl-scmi.c
new file mode 100755
index 0000000000..ada365de2e
--- /dev/null
+++ b/components/drivers/pinctrl/pinctrl-scmi.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "pinctrl.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define ATTR_SEL(x) ((rt_uint32_t)(x) & 0x3U)
+#define ATTR_NUM(n) ((((rt_uint32_t)(n)) & 0xffU) << 2)
+#define ATTR_FUNCSEL (1u << 10)
+
+struct scmi_pinctrl_info
+{
+ rt_uint32_t identifier;
+ char name[64];
+};
+
+struct scmi_pinctrl
+{
+ struct rt_device_pin parent;
+
+ struct rt_scmi_device *sdev;
+
+ rt_size_t pins_nr;
+ struct scmi_pinctrl_info *pins;
+
+ rt_size_t groups_nr;
+ struct scmi_pinctrl_info *groups;
+
+ rt_size_t function_nr;
+ struct scmi_pinctrl_info *function;
+};
+
+#define raw_to_scmi_pinctrl(raw) rt_container_of(raw, struct scmi_pinctrl, parent)
+
+static const struct rt_pin_ctrl_conf_params scmi_conf_params[] =
+{
+ { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+ { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+ { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
+ { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+ { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+ { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+ { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
+ { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+ { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+ { "low-power-disable", PIN_CONFIG_MODE_LOW_POWER, 0 },
+ { "low-power-enable", PIN_CONFIG_MODE_LOW_POWER, 1 },
+ { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
+ { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+ { "output-high", PIN_CONFIG_OUTPUT, 1, },
+ { "output-impedance-ohms", PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, 0 },
+ { "output-low", PIN_CONFIG_OUTPUT, 0, },
+ { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
+ { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
+};
+
+static enum scmi_pinctrl_conf_type scmi_conf_params_map[] =
+{
+ SCMI_PINCTRL_BIAS_BUS_HOLD,
+ SCMI_PINCTRL_BIAS_DISABLE,
+ SCMI_PINCTRL_BIAS_HIGH_IMPEDANCE,
+ SCMI_PINCTRL_BIAS_PULL_UP,
+ SCMI_PINCTRL_BIAS_PULL_DEFAULT,
+ SCMI_PINCTRL_BIAS_PULL_DOWN,
+ SCMI_PINCTRL_DRIVE_OPEN_DRAIN,
+ SCMI_PINCTRL_DRIVE_OPEN_SOURCE,
+ SCMI_PINCTRL_DRIVE_PUSH_PULL,
+ SCMI_PINCTRL_DRIVE_STRENGTH,
+ SCMI_PINCTRL_DRIVE_STRENGTH,
+ SCMI_PINCTRL_INPUT_DEBOUNCE,
+ SCMI_PINCTRL_INPUT_MODE,
+ SCMI_PINCTRL_INPUT_MODE,
+ SCMI_PINCTRL_INPUT_SCHMITT,
+ SCMI_PINCTRL_INPUT_MODE,
+ SCMI_PINCTRL_INPUT_MODE,
+ SCMI_PINCTRL_LOW_POWER_MODE,
+ SCMI_PINCTRL_LOW_POWER_MODE,
+ SCMI_PINCTRL_OUTPUT_MODE,
+ SCMI_PINCTRL_OUTPUT_MODE,
+ SCMI_PINCTRL_OUTPUT_VALUE,
+ SCMI_PINCTRL_OUTPUT_VALUE,
+ SCMI_PINCTRL_OUTPUT_VALUE,
+ SCMI_PINCTRL_POWER_SOURCE,
+ SCMI_PINCTRL_SLEW_RATE,
+};
+
+static rt_bool_t scmi_pinconf_prop_name_to_param(const char *propname,
+ rt_uint32_t *default_value, rt_uint32_t *out_type)
+{
+ const struct rt_pin_ctrl_conf_params *params = scmi_conf_params;
+
+ for (int i = 0; i < RT_ARRAY_SIZE(scmi_conf_params); ++i, ++params)
+ {
+ if (!rt_strcmp(params->propname, propname))
+ {
+ *out_type = scmi_conf_params_map[i];
+ *default_value = params->default_value;
+
+ return RT_TRUE;
+ }
+ }
+
+ return RT_FALSE;
+}
+
+static rt_bool_t scmi_lookup_id(const struct scmi_pinctrl_info *info,
+ rt_size_t nr, const char *name, rt_uint32_t *out_id)
+{
+ for (rt_size_t i = 0; i < nr; ++i)
+ {
+ if (!rt_strcmp((const char *)info[i].name, name))
+ {
+ *out_id = info[i].identifier;
+ return RT_TRUE;
+ }
+ }
+
+ return RT_FALSE;
+}
+
+static rt_err_t scmi_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np)
+{
+ rt_err_t err = RT_EOK;
+ const char *string;
+ rt_uint32_t function_id = 0xffffffffU;
+ rt_size_t pins_nr = 0, groups_nr = 0, params_nr = 0;
+ rt_uint32_t pins_id[32], groups_id[32], params_type[32], params_val[32];
+ struct rt_ofw_prop *prop;
+ struct rt_ofw_node *np = fw_conf_np;
+ struct scmi_pinctrl *spctl = raw_to_scmi_pinctrl(device);
+
+ LOG_D("Pinctrl apply '%s'", rt_ofw_node_full_name(np));
+
+ rt_ofw_foreach_prop(np, prop)
+ {
+ if (!rt_strcmp(prop->name, "phandle"))
+ {
+ continue;
+ }
+ else if (!rt_strcmp(prop->name, "groups"))
+ {
+ for (string = rt_ofw_prop_next_string(prop, RT_NULL); string;
+ string = rt_ofw_prop_next_string(prop, string))
+ {
+ if (groups_nr >= RT_ARRAY_SIZE(groups_id))
+ {
+ return -RT_EFULL;
+ }
+
+ if (!scmi_lookup_id(spctl->groups, spctl->groups_nr, string, &groups_id[groups_nr]))
+ {
+ return -RT_EINVAL;
+ }
+ ++groups_nr;
+ }
+ }
+ else if (!rt_strcmp(prop->name, "pins"))
+ {
+ for (string = rt_ofw_prop_next_string(prop, RT_NULL); string;
+ string = rt_ofw_prop_next_string(prop, string))
+ {
+ if (pins_nr >= RT_ARRAY_SIZE(pins_id))
+ {
+ return -RT_EFULL;
+ }
+
+ if (!scmi_lookup_id(spctl->pins, spctl->pins_nr, string, &pins_id[pins_nr]))
+ {
+ return -RT_EINVAL;
+ }
+ ++pins_nr;
+ }
+ }
+ else if (!rt_strcmp(prop->name, "function"))
+ {
+ string = rt_ofw_prop_next_string(prop, RT_NULL);
+
+ if (!scmi_lookup_id(spctl->function, spctl->function_nr, string, &function_id))
+ {
+ return -RT_EINVAL;
+ }
+ }
+ else
+ {
+ if (params_nr >= RT_ARRAY_SIZE(params_type))
+ {
+ return -RT_EFULL;
+ }
+
+ if (!scmi_pinconf_prop_name_to_param(prop->name, &params_val[params_nr], &params_type[params_nr]))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (prop->length >= sizeof(rt_uint32_t))
+ {
+ rt_ofw_prop_next_u32(prop, RT_NULL, &params_val[params_nr]);
+ }
+
+ ++params_nr;
+ }
+ }
+
+ if (function_id != 0xffffffffU)
+ {
+ for (rt_size_t i = 0; i < groups_nr; ++i)
+ {
+ struct scmi_pinctrl_settings_conf_in in =
+ {
+ .identifier = rt_cpu_to_le32(groups_id[i]),
+ .function_id = rt_cpu_to_le32(function_id),
+ .attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_GROUP) | ATTR_FUNCSEL),
+ };
+ struct scmi_pinctrl_settings_conf_out out = {0};
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_SETTINGS_CONFIGURE, &in, &out);
+
+ if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
+ {
+ return err;
+ }
+
+ if (rt_le32_to_cpu(out.status) != 0)
+ {
+ return -RT_ERROR;
+ }
+ }
+ }
+
+ if (params_nr)
+ {
+ struct
+ {
+ struct scmi_pinctrl_settings_conf_in hdr;
+ rt_le32_t config[2 * 32];
+ } in;
+ struct scmi_pinctrl_settings_conf_out out = {0};
+ struct rt_scmi_msg msg = {
+ .sdev = spctl->sdev,
+ .message_id = SCMI_PINCTRL_SETTINGS_CONFIGURE,
+ .out_msg = (rt_uint8_t *)&out,
+ .out_msg_size = sizeof(out),
+ };
+
+ for (rt_size_t i = 0; i < params_nr; ++i)
+ {
+ in.config[2 * i + 0] = rt_cpu_to_le32(params_type[i]);
+ in.config[2 * i + 1] = rt_cpu_to_le32(params_val[i]);
+ }
+
+ for (rt_size_t i = 0; i < groups_nr; i++)
+ {
+ in.hdr.identifier = rt_cpu_to_le32(groups_id[i]);
+ in.hdr.function_id = rt_cpu_to_le32(0xffffffffU);
+ in.hdr.attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_GROUP) | ATTR_NUM(params_nr));
+
+ msg.in_msg = (rt_uint8_t *)&in;
+ msg.in_msg_size = (rt_uint32_t)(sizeof(in.hdr) + params_nr * 2 * sizeof(rt_le32_t));
+
+ if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
+ {
+ return err;
+ }
+
+ if (rt_le32_to_cpu(out.status) != 0)
+ {
+ return -RT_ERROR;
+ }
+ }
+
+ for (rt_size_t i = 0; i < pins_nr; i++)
+ {
+ in.hdr.identifier = rt_cpu_to_le32(pins_id[i]);
+ in.hdr.function_id = rt_cpu_to_le32(0xffffffffU);
+ in.hdr.attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_PIN) | ATTR_NUM(params_nr));
+
+ msg.in_msg = (rt_uint8_t *)&in;
+ msg.in_msg_size = (rt_uint32_t)(sizeof(in.hdr) + params_nr * 2 * sizeof(rt_le32_t));
+
+ if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
+ {
+ return err;
+ }
+
+ if (rt_le32_to_cpu(out.status) != 0)
+ {
+ return -RT_ERROR;
+ }
+ }
+ }
+
+ return err;
+}
+
+static const struct rt_pin_ops scmi_pinctrl_ops =
+{
+ .pin_ctrl_confs_apply = scmi_pinctrl_confs_apply,
+};
+
+static rt_err_t scmi_pinctrl_name_parse_one(struct rt_scmi_device *sdev,
+ enum scmi_pinctrl_selector_type sel, rt_size_t id, char *name)
+{
+ rt_err_t err;
+ struct scmi_pinctrl_attributes_in attr_in =
+ {
+ .identifier = rt_cpu_to_le32(id),
+ .flags = rt_cpu_to_le32(sel),
+ };
+ struct scmi_pinctrl_attributes_out attr_out = {0};
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_ATTRIBUTES, &attr_in, &attr_out);
+
+ name[0] = '\0';
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ return err;
+ }
+
+ if (rt_le32_to_cpu(attr_out.status) != 0)
+ {
+ return -RT_ERROR;
+ }
+
+ rt_strncpy(name, (char *)attr_out.name, sizeof(attr_out.name));
+
+ if (SCMI_PINCTRL_EXT_NAME_FLAG(rt_le32_to_cpu(attr_out.attributes)))
+ {
+ struct scmi_pinctrl_name_get_in name_in =
+ {
+ .identifier = rt_cpu_to_le32(id),
+ .flags = rt_cpu_to_le32(sel),
+ };
+ struct scmi_pinctrl_name_get_out name_out = {0};
+
+ msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_NAME_GET, &name_in, &name_out);
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ return err;
+ }
+
+ if (rt_le32_to_cpu(name_out.status) != 0)
+ {
+ return -RT_ERROR;
+ }
+
+ rt_strncpy(name, (char *)name_out.name, sizeof(name_out.name));
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t scmi_pinctrl_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ struct rt_scmi_msg msg;
+ struct rt_device *dev = &sdev->parent;
+ struct scmi_pinctrl_protocol_attributes protocol_attr_out;
+ struct scmi_pinctrl *spctl = rt_calloc(1, sizeof(*spctl));
+
+ if (!spctl)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_memset(&protocol_attr_out, 0, sizeof(protocol_attr_out));
+ msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &protocol_attr_out);
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ goto _fail;
+ }
+
+ if (rt_le32_to_cpu(protocol_attr_out.status) != 0)
+ {
+ err = -RT_ERROR;
+ goto _fail;
+ }
+
+ spctl->pins_nr = SCMI_PINCTRL_PINS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_low));
+ spctl->groups_nr = SCMI_PINCTRL_GROUPS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_low));
+ spctl->function_nr = SCMI_PINCTRL_FUNCTIONS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_high));
+
+ spctl->pins = rt_malloc(sizeof(*spctl->pins) * spctl->pins_nr);
+ spctl->groups = rt_malloc(sizeof(*spctl->groups) * spctl->groups_nr);
+ spctl->function = rt_malloc(sizeof(*spctl->function) * spctl->function_nr);
+
+ if (!spctl->pins || !spctl->groups || !spctl->function)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ for (rt_size_t i = 0; i < spctl->pins_nr; ++i)
+ {
+ if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_PIN, i, spctl->pins[i].name))
+ {
+ LOG_E("%s parse identifier = %d fail", "Pin", i);
+ continue;
+ }
+
+ spctl->pins[i].identifier = i;
+ }
+
+ for (rt_size_t i = 0; i < spctl->groups_nr; ++i)
+ {
+ if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_GROUP, i, spctl->groups[i].name))
+ {
+ LOG_E("%s parse identifier = %d fail", "Group", i);
+ continue;
+ }
+
+ spctl->groups[i].identifier = i;
+ }
+
+ for (rt_size_t i = 0; i < spctl->function_nr; ++i)
+ {
+ if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_FUNCTION, i, spctl->function[i].name))
+ {
+ LOG_E("%s parse identifier = %d fail", "Function", i);
+ continue;
+ }
+
+ spctl->function[i].identifier = i;
+ }
+
+ spctl->parent.ops = &scmi_pinctrl_ops;
+ spctl->sdev = sdev;
+ rt_ofw_data(dev->ofw_node) = &spctl->parent;
+
+ return RT_EOK;
+
+_fail:
+ if (spctl->pins)
+ {
+ rt_free(spctl->pins);
+ }
+
+ if (spctl->groups)
+ {
+ rt_free(spctl->groups);
+ }
+
+ if (spctl->function)
+ {
+ rt_free(spctl->function);
+ }
+
+ rt_free(spctl);
+
+ return err;
+}
+
+static const struct rt_scmi_device_id scmi_pinctrl_ids[] =
+{
+ { SCMI_PROTOCOL_ID_PINCTRL, "pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_pinctrl_driver =
+{
+ .name = "pinctrl-scmi",
+ .ids = scmi_pinctrl_ids,
+
+ .probe = scmi_pinctrl_probe,
+};
+RT_SCMI_DRIVER_EXPORT(scmi_pinctrl_driver);
diff --git a/components/drivers/pmdomain/Kconfig b/components/drivers/pmdomain/Kconfig
index 3d899f7463..89503f4aad 100644
--- a/components/drivers/pmdomain/Kconfig
+++ b/components/drivers/pmdomain/Kconfig
@@ -1,6 +1,11 @@
if RT_USING_DM
menu "Power Management (PM) Domains device drivers"
+ config RT_PMDOMAIN_SCMI
+ bool "ARM SCMI"
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
osource "$(SOC_DM_PMDOMAIN_DIR)/Kconfig"
endmenu
endif
diff --git a/components/drivers/pmdomain/SConscript b/components/drivers/pmdomain/SConscript
index 957416cfca..d63b9587d1 100644
--- a/components/drivers/pmdomain/SConscript
+++ b/components/drivers/pmdomain/SConscript
@@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include']
src = []
+if GetDepend(['RT_PMDOMAIN_SCMI']):
+ src += ['pm-domain-scmi.c']
+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/pmdomain/pm-domain-scmi.c b/components/drivers/pmdomain/pm-domain-scmi.c
new file mode 100755
index 0000000000..7a232ec0e8
--- /dev/null
+++ b/components/drivers/pmdomain/pm-domain-scmi.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-21 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "pm-domain.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct scmi_pm_domain_proxy;
+
+struct scmi_pm_domain
+{
+ struct rt_dm_power_domain parent;
+
+ rt_uint32_t domain;
+
+ struct scmi_pm_domain_proxy *proxy;
+};
+
+#define raw_to_scmi_pm_domain(raw) rt_container_of(raw, struct scmi_pm_domain, parent)
+
+struct scmi_pm_domain_proxy
+{
+ struct rt_dm_power_domain_proxy parent;
+
+ struct rt_scmi_device *sdev;
+
+ rt_uint32_t num_domains;
+ struct scmi_pm_domain domains[];
+};
+
+#define raw_to_scmi_pm_domain_proxy(raw) rt_container_of(raw, struct scmi_pm_domain_proxy, parent)
+
+static rt_err_t scmi_pm_domain_power(struct scmi_pm_domain *scmi_pd, rt_bool_t power_on)
+{
+ struct scmi_power_state_set_in in =
+ {
+ .flags = rt_cpu_to_le32(0),
+ .domain = rt_cpu_to_le32(scmi_pd->domain),
+ .state = rt_cpu_to_le32(power_on ? SCMI_POWER_STATE_GENERIC_ON : SCMI_POWER_STATE_GENERIC_OFF),
+ };
+ struct scmi_power_state_set_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_POWER_STATE_SET, &in, &out);
+
+ return rt_scmi_process_msg(scmi_pd->proxy->sdev, &msg);
+}
+
+static rt_err_t scmi_pd_power_on(struct rt_dm_power_domain *domain)
+{
+ return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_TRUE);
+}
+
+static rt_err_t scmi_pd_power_off(struct rt_dm_power_domain *domain)
+{
+ return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_FALSE);
+}
+
+static struct rt_dm_power_domain *scmi_pm_domain_proxy_ofw_parse(
+ struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args)
+{
+ struct scmi_pm_domain_proxy *scmi_proxy = raw_to_scmi_pm_domain_proxy(proxy);
+
+ return &scmi_proxy->domains[args->args[0]].parent;
+}
+
+static rt_err_t scmi_pm_domain_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ rt_uint32_t num_domains;
+ struct scmi_pm_domain *scmi_pds;
+ struct scmi_pm_domain_proxy *scmi_proxy;
+ struct scmi_power_attributes attr = {};
+ struct rt_scmi_msg msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ return err;
+ }
+
+ num_domains = rt_le16_to_cpu(attr.num_domains);
+ scmi_proxy = rt_calloc(1, sizeof(*scmi_proxy) + sizeof(*scmi_pds) * num_domains);
+
+ if (!scmi_proxy)
+ {
+ return -RT_ENOMEM;
+ }
+
+ scmi_proxy->sdev = sdev;
+ scmi_proxy->num_domains = num_domains;
+
+ scmi_pds = scmi_proxy->domains;
+
+ for (int i = 0; i < num_domains; ++i, ++scmi_pds)
+ {
+ struct rt_dm_power_domain *domain = &scmi_pds->parent;
+
+ domain->power_off = scmi_pd_power_off;
+ domain->power_on = scmi_pd_power_on;
+
+ scmi_pds->domain = i;
+ scmi_pds->proxy = scmi_proxy;
+
+ rt_dm_power_domain_register(domain);
+ }
+
+ scmi_proxy->parent.ofw_parse = scmi_pm_domain_proxy_ofw_parse;
+ rt_dm_power_domain_proxy_ofw_bind(&scmi_proxy->parent, sdev->parent.ofw_node);
+
+ return RT_EOK;
+}
+
+static const struct rt_scmi_device_id scmi_pm_domain_ids[] =
+{
+ { SCMI_PROTOCOL_ID_POWER, "genpd" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_pm_domain_driver =
+{
+ .name = "pm-domain-scmi",
+ .ids = scmi_pm_domain_ids,
+
+ .probe = scmi_pm_domain_probe,
+};
+RT_SCMI_DRIVER_EXPORT(scmi_pm_domain_driver);
diff --git a/components/drivers/regulator/Kconfig b/components/drivers/regulator/Kconfig
index 99bfdac1e8..9137bc4e58 100644
--- a/components/drivers/regulator/Kconfig
+++ b/components/drivers/regulator/Kconfig
@@ -18,6 +18,13 @@ config RT_REGULATOR_GPIO
depends on RT_USING_PIN
default y
+config RT_REGULATOR_SCMI
+ bool "SCMI regulator support"
+ depends on RT_USING_REGULATOR
+ depends on RT_USING_OFW
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
if RT_USING_REGULATOR
osource "$(SOC_DM_REGULATOR_DIR)/Kconfig"
endif
diff --git a/components/drivers/regulator/SConscript b/components/drivers/regulator/SConscript
index 29b567fad9..f95f49b196 100755
--- a/components/drivers/regulator/SConscript
+++ b/components/drivers/regulator/SConscript
@@ -16,6 +16,9 @@ if GetDepend(['RT_REGULATOR_FIXED']):
if GetDepend(['RT_REGULATOR_GPIO']):
src += ['regulator-gpio.c']
+if GetDepend(['RT_REGULATOR_SCMI']):
+ src += ['regulator-scmi.c']
+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/regulator/regulator-scmi.c b/components/drivers/regulator/regulator-scmi.c
new file mode 100755
index 0000000000..d4b0697e39
--- /dev/null
+++ b/components/drivers/regulator/regulator-scmi.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-21 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "regulator.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct scmi_regulator
+{
+ struct rt_regulator_node parent;
+ struct rt_regulator_param param;
+
+ struct rt_device dev;
+ struct rt_scmi_device *sdev;
+
+ rt_uint32_t domain_id;
+};
+
+#define raw_to_scmi_regulator(raw) rt_container_of(raw, struct scmi_regulator, parent)
+
+static rt_err_t scmi_regulator_set_enable(struct scmi_regulator *sreg, rt_bool_t enable)
+{
+ struct scmi_voltage_config_set_in in =
+ {
+ .domain_id = rt_cpu_to_le32(sreg->domain_id),
+ .config = rt_cpu_to_le32(enable ? SCMI_VOLTAGE_CONFIG_ON : SCMI_VOLTAGE_CONFIG_OFF),
+ };
+ struct scmi_voltage_config_set_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_VOLTAGE_DOMAIN_CONFIG_SET, &in, &out);
+
+ return rt_scmi_process_msg(sreg->sdev, &msg) ? : (out.status ? -RT_ERROR : RT_EOK);
+}
+
+static rt_err_t scmi_regulator_enable(struct rt_regulator_node *reg_np)
+{
+ struct scmi_regulator *sreg = raw_to_scmi_regulator(reg_np);
+
+ return scmi_regulator_set_enable(sreg, RT_TRUE);
+}
+
+static rt_err_t scmi_regulator_disable(struct rt_regulator_node *reg_np)
+{
+ struct scmi_regulator *sreg = raw_to_scmi_regulator(reg_np);
+
+ return scmi_regulator_set_enable(sreg, RT_FALSE);
+}
+
+static rt_bool_t scmi_regulator_is_enabled(struct rt_regulator_node *reg_np)
+{
+ struct scmi_regulator *sreg = raw_to_scmi_regulator(reg_np);
+ struct scmi_voltage_config_get_in in =
+ {
+ .domain_id = rt_cpu_to_le32(sreg->domain_id),
+ };
+ struct scmi_voltage_config_get_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_VOLTAGE_DOMAIN_CONFIG_GET, &in, &out);
+
+ return rt_scmi_process_msg(sreg->sdev, &msg) ? RT_FALSE : (out.config == SCMI_VOLTAGE_CONFIG_ON);
+}
+
+static rt_err_t scmi_regulator_set_voltage(struct rt_regulator_node *reg_np,
+ int min_uvolt, int max_uvolt)
+{
+ struct scmi_regulator *sreg = raw_to_scmi_regulator(reg_np);
+ struct scmi_voltage_level_set_in in =
+ {
+ .domain_id = rt_cpu_to_le32(sreg->domain_id),
+ .voltage_level = rt_cpu_to_le32((max_uvolt + min_uvolt) >> 1),
+ };
+ struct scmi_voltage_level_set_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_VOLTAGE_DOMAIN_LEVEL_SET, &in, &out);
+
+ return rt_scmi_process_msg(sreg->sdev, &msg);
+}
+
+static int scmi_regulator_get_voltage(struct rt_regulator_node *reg_np)
+{
+ struct scmi_regulator *sreg = raw_to_scmi_regulator(reg_np);
+ struct scmi_voltage_level_get_in in =
+ {
+ .domain_id = rt_cpu_to_le32(sreg->domain_id),
+ };
+ struct scmi_voltage_level_get_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_VOLTAGE_DOMAIN_LEVEL_GET, &in, &out);
+
+ return rt_scmi_process_msg(sreg->sdev, &msg) ? : out.voltage_level;
+}
+
+static const struct rt_regulator_ops scmi_regulator_voltage_ops =
+{
+ .enable = scmi_regulator_enable,
+ .disable = scmi_regulator_disable,
+ .is_enabled = scmi_regulator_is_enabled,
+ .set_voltage = scmi_regulator_set_voltage,
+ .get_voltage = scmi_regulator_get_voltage,
+};
+
+static rt_err_t scmi_regulator_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ rt_uint32_t dom_nr;
+ struct rt_regulator_node *rnp;
+ struct rt_ofw_node *np, *child_np;
+ struct scmi_regulator *sregs = RT_NULL, *sreg;
+
+ np = rt_ofw_get_child_by_tag(sdev->parent.ofw_node, "regulators");
+
+ if (!np)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ dom_nr = rt_ofw_get_child_count(np);
+
+ if (!dom_nr)
+ {
+ err = -RT_EEMPTY;
+ goto _fail;
+ }
+
+ sregs = rt_calloc(dom_nr, sizeof(*sregs));
+
+ if (!sregs)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ sreg = &sregs[0];
+
+ rt_ofw_foreach_child_node(np, child_np)
+ {
+ if ((err = rt_ofw_prop_read_u32(child_np, "reg", &sreg->domain_id)))
+ {
+ goto _fail;
+ }
+
+ sreg->sdev = sdev;
+
+ rnp = &sreg->parent;
+ sreg->dev.ofw_node = child_np;
+
+ rt_ofw_prop_read_string(child_np, "regulator-name", &rnp->supply_name);
+ rnp->ops = &scmi_regulator_voltage_ops;
+ rnp->param = &sreg->param;
+ rnp->dev = &sreg->dev;
+
+ ++sreg;
+ }
+ rt_ofw_node_put(np);
+
+ sreg = &sregs[0];
+
+ for (int i = 0; i < dom_nr; ++i, ++sreg)
+ {
+ if ((err = rt_regulator_register(&sreg->parent)))
+ {
+ while (i --> 0)
+ {
+ --sreg;
+
+ rt_regulator_unregister(&sreg->parent);
+ }
+
+ goto _fail;
+ }
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_ofw_node_put(np);
+
+ if (sregs)
+ {
+ rt_free(sregs);
+ }
+
+ return err;
+}
+
+static const struct rt_scmi_device_id scmi_regulator_ids[] =
+{
+ { SCMI_PROTOCOL_ID_VOLTAGE, "regulator" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_regulator_driver =
+{
+ .name = "scmi-regulator",
+ .ids = scmi_regulator_ids,
+
+ .probe = scmi_regulator_probe,
+};
+RT_SCMI_DRIVER_EXPORT(scmi_regulator_driver);
diff --git a/components/drivers/reset/Kconfig b/components/drivers/reset/Kconfig
index ccba575750..238fee2e98 100644
--- a/components/drivers/reset/Kconfig
+++ b/components/drivers/reset/Kconfig
@@ -4,6 +4,12 @@ menuconfig RT_USING_RESET
depends on RT_USING_OFW
default n
+config RT_RESET_SCMI
+ bool "Reset driver controlled via ARM SCMI interface"
+ depends on RT_USING_RESET
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
config RT_RESET_SIMPLE
bool "Simple Reset Controller Driver"
depends on RT_USING_RESET
diff --git a/components/drivers/reset/SConscript b/components/drivers/reset/SConscript
index 8e64f78643..5d9adee728 100755
--- a/components/drivers/reset/SConscript
+++ b/components/drivers/reset/SConscript
@@ -13,6 +13,9 @@ src = ['reset.c']
if GetDepend(['RT_RESET_SIMPLE']):
src += ['reset-simple.c']
+if GetDepend(['RT_RESET_SCMI']):
+ src += ['reset-scmi.c']
+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/reset/reset-scmi.c b/components/drivers/reset/reset-scmi.c
new file mode 100755
index 0000000000..d10d296d86
--- /dev/null
+++ b/components/drivers/reset/reset-scmi.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "reset.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct scmi_reset
+{
+ struct rt_reset_controller parent;
+
+ struct rt_scmi_device *sdev;
+};
+
+#define raw_to_scmi_reset(raw) rt_container_of(raw, struct scmi_reset, parent)
+
+static rt_err_t scmi_reset_do(struct scmi_reset *srst, int domain,
+ rt_uint32_t flags, rt_uint32_t state)
+{
+ struct scmi_reset_in in =
+ {
+ .domain_id = rt_cpu_to_le32(domain),
+ .flags = rt_cpu_to_le32(flags),
+ .reset_state = rt_cpu_to_le32(state),
+ };
+ struct scmi_reset_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_RESET_RESET, &in, &out);
+
+ return rt_scmi_process_msg(srst->sdev, &msg);
+}
+
+static rt_err_t scmi_reset_reset(struct rt_reset_control *rstc)
+{
+ struct scmi_reset *srst = raw_to_scmi_reset(rstc);
+
+ return scmi_reset_do(srst, rstc->id, SCMI_RESET_FLAG_RESET, SCMI_ARCH_COLD_RESET);
+}
+
+static rt_err_t scmi_reset_assert(struct rt_reset_control *rstc)
+{
+ struct scmi_reset *srst = raw_to_scmi_reset(rstc);
+
+ return scmi_reset_do(srst, rstc->id, SCMI_RESET_FLAG_ASSERT, SCMI_ARCH_COLD_RESET);
+}
+
+static rt_err_t scmi_reset_deassert(struct rt_reset_control *rstc)
+{
+ struct scmi_reset *srst = raw_to_scmi_reset(rstc);
+
+ return scmi_reset_do(srst, rstc->id, 0, SCMI_ARCH_COLD_RESET);
+}
+
+static rt_err_t scmi_reset_ofw_parse(struct rt_reset_control *rstc,
+ struct rt_ofw_cell_args *args)
+{
+ rt_err_t err;
+ struct scmi_reset *srst = raw_to_scmi_reset(rstc);
+ struct scmi_reset_attr_in in =
+ {
+ .domain_id = rt_cpu_to_le32(rstc->id),
+ };
+ struct scmi_reset_attr_out out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_RESET_DOMAIN_ATTRIBUTES, &in, &out);
+
+ if ((err = rt_scmi_process_msg(srst->sdev, &msg)))
+ {
+ return err;
+ }
+
+ return rt_le32_to_cpu(out.status) == 0 ? RT_EOK : -RT_ERROR;
+}
+
+static const struct rt_reset_control_ops scmi_reset_ops =
+{
+ .ofw_parse = scmi_reset_ofw_parse,
+ .reset = scmi_reset_reset,
+ .assert = scmi_reset_assert,
+ .deassert = scmi_reset_deassert,
+};
+
+static rt_err_t scmi_reset_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ struct rt_reset_controller *rstcer;
+ struct scmi_reset *srst = rt_calloc(1, sizeof(*srst));
+
+ if (!srst)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rstcer = &srst->parent;
+
+ rstcer->priv = srst;
+ rstcer->ofw_node = sdev->parent.ofw_node;
+ rstcer->ops = &scmi_reset_ops;
+
+ if ((err = rt_reset_controller_register(&srst->parent)))
+ {
+ rt_free(srst);
+ }
+
+ return err;
+}
+
+static const struct rt_scmi_device_id scmi_reset_ids[] =
+{
+ { SCMI_PROTOCOL_ID_RESET, "reset" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_reset_driver =
+{
+ .name = "reset-scmi",
+ .ids = scmi_reset_ids,
+
+ .probe = scmi_reset_probe,
+};
+RT_SCMI_DRIVER_EXPORT(scmi_reset_driver);
diff --git a/components/drivers/thermal/Kconfig b/components/drivers/thermal/Kconfig
index b993aafd82..91a394fe8b 100644
--- a/components/drivers/thermal/Kconfig
+++ b/components/drivers/thermal/Kconfig
@@ -7,6 +7,12 @@ if RT_USING_THERMAL
comment "Thermal Sensors Drivers"
endif
+config RT_THERMAL_SCMI
+ bool "ARM SCMI interface"
+ depends on RT_USING_THERMAL
+ depends on RT_FIRMWARE_ARM_SCMI
+ default n
+
if RT_USING_THERMAL
osource "$(SOC_DM_THERMAL_DIR)/Kconfig"
endif
diff --git a/components/drivers/thermal/SConscript b/components/drivers/thermal/SConscript
index d33d2d2046..31ba302381 100644
--- a/components/drivers/thermal/SConscript
+++ b/components/drivers/thermal/SConscript
@@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include']
src = ['thermal.c', 'thermal_dm.c']
+if GetDepend(['RT_THERMAL_SCMI']):
+ src += ['thermal-scmi.c']
+
if GetDepend(['RT_THERMAL_COOL_PWM_FAN']):
src += ['thermal-cool-pwm-fan.c']
diff --git a/components/drivers/thermal/thermal-scmi.c b/components/drivers/thermal/thermal-scmi.c
new file mode 100755
index 0000000000..05e0322d63
--- /dev/null
+++ b/components/drivers/thermal/thermal-scmi.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-26 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "thermal.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct scmi_thermal
+{
+ struct rt_thermal_zone_device parent;
+
+ rt_uint32_t sensor_id;
+ rt_uint32_t scale;
+ struct rt_scmi_device *sdev;
+};
+
+#define raw_to_scmi_thermal(raw) rt_container_of(raw, struct scmi_thermal, parent)
+
+static rt_err_t scmi_thermal_zone_get_temp(struct rt_thermal_zone_device *zdev,
+ int *out_temp)
+{
+ int scale;
+ rt_err_t err;
+ rt_uint64_t value, factor = 1;
+ struct scmi_thermal *st = raw_to_scmi_thermal(zdev);
+ struct scmi_sensor_reading_in reading_in =
+ {
+ .id = rt_cpu_to_le32(st->sensor_id),
+ .flags = rt_cpu_to_le32(0),
+ };
+ struct scmi_sensor_reading_out reading_out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_SENSOR_READING_GET, &reading_in, &reading_out);
+
+ if ((err = rt_scmi_process_msg(st->sdev, &msg)))
+ {
+ return err;
+ }
+
+ value = rt_le32_to_cpu(reading_out.value_high);
+ value <<= 32;
+ value |= rt_le32_to_cpu(reading_out.value_low);
+
+ scale = st->scale + 3;
+
+ if (scale == 0)
+ {
+ goto _end;
+ }
+
+ if (scale > 19 || scale < -19)
+ {
+ return -RT_EIO;
+ }
+
+ for (int i = 0; i < rt_abs(scale); i++)
+ {
+ factor *= 10;
+ }
+
+ if (scale > 0)
+ {
+ value *= factor;
+ }
+ else
+ {
+ value = rt_div_u64(value, factor);
+ }
+
+_end:
+ *out_temp = (int)value;
+
+ return err;
+}
+
+const static struct rt_thermal_zone_ops scmi_thermal_zone_ops =
+{
+ .get_temp = scmi_thermal_zone_get_temp,
+};
+
+static rt_err_t scmi_thermal_probe(struct rt_scmi_device *sdev)
+{
+ rt_err_t err;
+ struct scmi_sensor_attributes attr = {};
+ struct scmi_sensor_description_get_out *desc_out;
+ struct rt_scmi_msg msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ return err;
+ }
+
+ desc_out = rt_malloc(sizeof(*desc_out) + sizeof(desc_out->desc[0]));
+
+ if (!desc_out)
+ {
+ return -RT_ENOMEM;
+ }
+
+ for (int i = 0, ts_nr = 0; i < attr.num_sensors; ++i)
+ {
+ struct scmi_thermal *st;
+ struct rt_thermal_zone_device *tz;
+ struct scmi_sensor_description_get_in desc_in;
+
+ desc_in.desc_index = i;
+ msg = RT_SCMI_MSG_IN_OUT(SCMI_SENSOR_DESCRIPTION_GET, &desc_in, desc_out);
+
+ if ((err = rt_scmi_process_msg(sdev, &msg)))
+ {
+ goto _end;
+ }
+
+ if (SCMI_SENSOR_TYPE(rt_le32_to_cpu(desc_out->desc[0].attributes_high)) !=
+ SCMI_SENSOR_TYPE_TEMPERATURE_C)
+ {
+ continue;
+ }
+
+ if (!(st = rt_calloc(1, sizeof(*st))))
+ {
+ err = -RT_ENOMEM;
+ goto _end;
+ }
+
+ st->sdev = sdev;
+ st->sensor_id = rt_le32_to_cpu(desc_out->desc[0].id);
+ st->scale = SCMI_SENSOR_SCALE(desc_out->desc[0].attributes_high);
+
+ tz = &st->parent;
+ tz->zone_id = ts_nr;
+ tz->ops = &scmi_thermal_zone_ops;
+ tz->parent.ofw_node = sdev->parent.ofw_node;
+
+ rt_dm_dev_set_name(&tz->parent, "scmi-%s", desc_out->desc[0].name);
+
+ rt_thermal_zone_device_register(tz);
+
+ ++ts_nr;
+ }
+
+_end:
+ rt_free(desc_out);
+
+ return err;
+}
+
+static const struct rt_scmi_device_id scmi_thermal_ids[] =
+{
+ { SCMI_PROTOCOL_ID_SENSOR, "thermal" },
+ { /* sentinel */ },
+};
+
+static struct rt_scmi_driver scmi_thermal_driver =
+{
+ .name = "thermal-scmi",
+ .ids = scmi_thermal_ids,
+
+ .probe = scmi_thermal_probe,
+};
+RT_SCMI_DRIVER_EXPORT(scmi_thermal_driver);