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