فهرست منبع

[dm][firmware][scmi] support ARM-SCMI interface #11069

GUI 3 هفته پیش
والد
کامیت
43733268c1
32فایلهای تغییر یافته به همراه3561 افزوده شده و 0 حذف شده
  1. 1 0
      components/drivers/Kconfig
  2. 6 0
      components/drivers/clk/Kconfig
  3. 2 0
      components/drivers/clk/SConscript
  4. 411 0
      components/drivers/clk/clk-scmi.c
  5. 9 0
      components/drivers/firmware/Kconfig
  6. 15 0
      components/drivers/firmware/SConscript
  7. 23 0
      components/drivers/firmware/arm_scmi/Kconfig
  8. 21 0
      components/drivers/firmware/arm_scmi/SConscript
  9. 176 0
      components/drivers/firmware/arm_scmi/agent-mailbox.c
  10. 200 0
      components/drivers/firmware/arm_scmi/agent-smc.c
  11. 177 0
      components/drivers/firmware/arm_scmi/agent.c
  12. 36 0
      components/drivers/firmware/arm_scmi/agent.h
  13. 84 0
      components/drivers/firmware/arm_scmi/bus.c
  14. 110 0
      components/drivers/firmware/arm_scmi/shmem.c
  15. 23 0
      components/drivers/firmware/arm_scmi/shmem.h
  16. 1092 0
      components/drivers/include/drivers/scmi.h
  17. 6 0
      components/drivers/include/rtdevice.h
  18. 6 0
      components/drivers/pinctrl/Kconfig
  19. 3 0
      components/drivers/pinctrl/SConscript
  20. 485 0
      components/drivers/pinctrl/pinctrl-scmi.c
  21. 5 0
      components/drivers/pmdomain/Kconfig
  22. 3 0
      components/drivers/pmdomain/SConscript
  23. 134 0
      components/drivers/pmdomain/pm-domain-scmi.c
  24. 7 0
      components/drivers/regulator/Kconfig
  25. 3 0
      components/drivers/regulator/SConscript
  26. 206 0
      components/drivers/regulator/regulator-scmi.c
  27. 6 0
      components/drivers/reset/Kconfig
  28. 3 0
      components/drivers/reset/SConscript
  29. 129 0
      components/drivers/reset/reset-scmi.c
  30. 6 0
      components/drivers/thermal/Kconfig
  31. 3 0
      components/drivers/thermal/SConscript
  32. 170 0
      components/drivers/thermal/thermal-scmi.c

+ 1 - 0
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"

+ 6 - 0
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

+ 2 - 0
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)
 

+ 411 - 0
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);

+ 9 - 0
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

+ 15 - 0
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')

+ 23 - 0
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

+ 21 - 0
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')

+ 176 - 0
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,
+};

+ 200 - 0
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,
+};

+ 177 - 0
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);

+ 36 - 0
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__ */

+ 84 - 0
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);

+ 110 - 0
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;
+    }
+}

+ 23 - 0
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__ */

+ 1092 - 0
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__ */

+ 6 - 0
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 */

+ 6 - 0
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

+ 3 - 0
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']
 

+ 485 - 0
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);

+ 5 - 0
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

+ 3 - 0
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')

+ 134 - 0
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);

+ 7 - 0
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

+ 3 - 0
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')

+ 206 - 0
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);

+ 6 - 0
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

+ 3 - 0
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')

+ 129 - 0
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);

+ 6 - 0
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

+ 3 - 0
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']
 

+ 170 - 0
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);