操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载本文围绕 RT-Thread 的 SCMISystem Control and Management Interface子系统展开说明在 AArch64Cortex-A / ARMv8平台上RT-Thread 如何通过安全固件TF-A、SCP、厂商 EL3提供的 SCMI 协议来管理时钟、稳压器、复位与电源域。读者将掌握 SCMI 子系统的分层架构、总线匹配机制、消息发送 API、三种传输通道Mailbox / SMC / Virtio的底层实现以及如何基于rt_scmi_driver扩展自定义协议驱动并让普通驱动通过rt_clk_*、rt_regulator_*等标准接口间接消费 SCMI 服务。SCMI 是什么OS 与固件之间的系统管理接口在 AArch64 平台上时钟、稳压器regulator、复位reset和电源域power domain等系统资源通常由安全固件TF-A、SCP、厂商 EL3 固件独占管理。OS 侧不能也不应直接触碰这些硬件寄存器而是通过SCMISystem Control and Management Interface协议向固件发消息来间接控制。RT-Thread 将整个 SCMI 协议栈拆分为四层层位置职责消息 / 协议 ID 定义components/drivers/include/drivers/scmi.h负载结构体、SCMI_PROTOCOL_ID_*协议号、RT_SCMI_MSG_*消息构造辅助宏SCMI 总线components/drivers/firmware/arm_scmi/bus.c按协议以及可选的名字匹配rt_scmi_driver↔rt_scmi_deviceAgent 传输层components/drivers/firmware/arm_scmi/平台驱动arm-scmi、共享内存、Mailbox / SMC / Virtio 三种传输实现协议提供者clk/、regulator/、reset/等目录下的*-scmi.c在 SCMI 总线上probe随后注册普通 DM 消费者rt_clk_*、rt_regulator_*等Kconfig 配置与构建条件SCMI 子系统由RT_FIRMWARE_ARM_SCMI开关控制定义在 components/drivers/firmware/arm_scmi/KconfigRT_FIRMWARE_ARM_SCMI总开关依赖RT_USING_FIRMWARE、RT_USING_OFW且仅当ARCH_ARM_CORTEX_A || ARCH_ARMV8时可用即 Cortex-A 与 ARMv8 平台RT_FIRMWARE_ARM_SCMI_TRANSPORT_MAILBOX基于 Mailbox 的传输依赖RT_USING_MBOX默认开启RT_FIRMWARE_ARM_SCMI_TRANSPORT_SMC基于 SMC 指令的传输默认开启RT_FIRMWARE_ARM_SCMI_TRANSPORT_VIRTIO由RT_VIRTIO_SCMI间接选择if RT_VIRTIO_SCMI时强制default y。对应的构建脚本 components/drivers/firmware/arm_scmi/SConscript 会按开关条件性纳入源码agent.c、bus.c、shmem.c总是编译agent-mailbox.c仅在 Mailbox 传输开启时编译agent-smc.c仅在 SMC 传输开启时编译。因此请按设备树实际使用的传输方式开启对应选项不需要的传输可以关闭以减小镜像。端到端工作流程从设备树节点到普通驱动的完整链路如下DT: compatible arm,scmi ( mboxes/shmem 或 smc-id) ↓ INIT_SUBSYS: 平台驱动 arm-scmi 注册agent.c ↓ INIT_PLATFORM: 平台设备 probe → scmi_probe() ├─ agent_ops-setup() 绑定传输通道 ├─ scmi_channels_setup() 遍历子节点 reg → rt_scmi_device_register() └─ 注册 BASE 协议设备0x10 ↓ INIT_DEVICEclk 例外见下文: RT_SCMI_DRIVER_EXPORT / rt_scmi_driver_register() ↓ scmi bus match(protocol_id [, name]) → driver-probe(sdev) ↓ Provider 注册 clk / regulator / reset / genpd / … ↓ 其他驱动通过标准 OFW 接口消费clocks …, resets …, …这里的关键设计是应用和绝大多数驱动永远不直接调用 SCMI它们使用与 MMIO 后端完全相同的 APIrt_clk_get_by_index、rt_regulator_get、rt_reset_control_get等。SCMI 只是这些子系统的一个透明后端实现这让上层代码完全无感知。核心数据结构scmi.h协议栈的核心对象定义在 components/drivers/include/drivers/scmi.hstruct rt_scmi_device { struct rt_device parent; /* parent.ofw_node, parent.bus, parent.drv */ const char *name; /* 可选参与总线匹配 */ rt_uint8_t protocol_id; /* 来自子节点属性 reg */ struct scmi_agent *agent; }; struct rt_scmi_device_id { rt_uint8_t protocol_id; const char *name; /* NULL 该协议下匹配任意名字 */ }; struct rt_scmi_driver { struct rt_driver parent; const char *name; const struct rt_scmi_device_id *ids; /* 哨兵protocol_id 0 */ 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); };协议 ID 常量同样定义在此文件宏值含义SCMI_PROTOCOL_ID_BASE0x10BASE 协议版本查询等SCMI_PROTOCOL_ID_POWER0x11电源域Power DomainSCMI_PROTOCOL_ID_SYSTEM0x12系统SystemSCMI_PROTOCOL_ID_PERF0x13性能PerformanceSCMI_PROTOCOL_ID_CLOCK0x14时钟SCMI_PROTOCOL_ID_SENSOR0x15传感器SCMI_PROTOCOL_ID_RESET0x16复位SCMI_PROTOCOL_ID_VOLTAGE0x17电压域稳压器SCMI_PROTOCOL_ID_POWERCAP0x18功率封顶SCMI_PROTOCOL_ID_PINCTRL0x19引脚控制每个协议都配套有类型化的输入/输出负载结构体例如时钟协议的scmi_clk_rate_set_in/out、scmi_clk_describe_rates_out电压协议的scmi_voltage_level_set_in/out复位协议的scmi_reset_in/out电源域的scmi_power_state_set_in/out等字段均为小端序rt_le32_t可直接填充后交给消息发送接口。总线匹配规则bus.c总线注册于scmi_bus_init()INIT_CORE_EXPORT匹配逻辑见 components/drivers/firmware/arm_scmi/bus.c遍历驱动ids[]表若某项id-protocol_id device-protocol_id且id-name为 NULL或id-name与设备name来自 OFW 子节点protocol-name或类似属性相等则匹配成功调用总线的probe即驱动的probe(device)。设备注册使用rt_scmi_device_register()内部调用rt_bus_add_device驱动注册使用rt_scmi_driver_register()内部调用rt_driver_register二者在 bus.c 中实现。启动与初始化顺序SCMI 各模块按照 RT-Thread 自动初始化机制分阶段注册导出 / 注册级别执行内容scmi_bus_initINIT_CORE_EXPORTrt_bus_register(scmi_bus)scmi_drv_registerarm-scmi平台驱动INIT_SUBSYS_EXPORTAgent 在批量 DT probe 之前就绪platform_ofw_device_probeINIT_PLATFORM_EXPORT创建arm,scmi平台设备 →scmi_probeRT_SCMI_DRIVER_EXPORT(...)INIT_DEVICE_EXPORT协议驱动注册 → probe 挂起的rt_scmi_devicescmi_clk_drv_registerINIT_SUBSYS_EXPORT例外clk-scmi.c手动调用rt_scmi_driver_register()早于RT_SCMI_DRIVER_EXPORT时钟驱动是唯一提前注册的例外见 components/drivers/clk/clk-scmi.c其通过INIT_SUBSYS_EXPORT在子系统阶段注册以更早提供rt_clk服务。如果某个协议驱动在对应的rt_scmi_device已经存在之后才注册rt_bus_add_driver会遍历已有设备并立即执行probe与平台总线相同的模式因此注册顺序并不严格要求先设备后驱动。发送一条 SCMI 消息所有传输最终都汇聚到统一入口rt_err_t rt_scmi_process_msg(struct rt_scmi_device *sdev, struct rt_scmi_msg *msg);其实现位于 components/drivers/firmware/arm_scmi/agent.c校验参数后将msg-sdev绑定到设备再委托给agent-ops-process_msg(agent, msg)。struct rt_scmi_msg承载消息上下文message_id、in_msg/in_msg_size、out_msg/out_msg_size以及可选的rx_callback异步接收回调。构建负载时使用类型化结构体与辅助宏struct rt_scmi_msg msg RT_SCMI_MSG_IN_OUT(SCMI_VOLTAGE_DOMAIN_LEVEL_SET, in, out); err rt_scmi_process_msg(sdev, msg); /* 先检查 err再检查 out.status固件 SCMI 状态码并不总是 -errno */辅助宏一览宏用途RT_SCMI_MSG_IN_OUT(id, in, out)固定大小输入 输出RT_SCMI_MSG_IN(id, in)仅输入的命令RT_SCMI_MSG_OUT(id, out)仅输出的命令RT_SCMI_MSG_RAW(...)可变缓冲区大小直接传指针与长度消息头由scmi_header(msg_id, msg_type, protocol_id, token)构造将 token、消息类型、协议 ID 与消息 ID 编码进一个 32 位字见 scmi.h 中的SCMI_HDR_*位域宏。固件返回码与错误映射固件在消息状态字段中返回SCMI_SUCCESS0或负的SCMI_ERR_*码范围 -1 到 -10对应 SUPPORT / PARAMS / ACCESS / ENTRY / RANGE / BUSY / COMMS / GENERIC / HARDWARE / PROTOCOL。rt_scmi_strerror()将这些码映射为短名字符串错误表定义在 agent.c。线程安全注意事项rt_scmi_process_msg在 Mailbox / SMC 路径上是阻塞式的内部使用自旋锁串行化因此不要在中断服务函数ISR中调用它除非所用传输被明确标注为 IRQ 安全。传输层与共享内存布局Agent 抽象Agent 是传输层的抽象定义在 components/drivers/firmware/arm_scmi/agent.hstruct 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); };scmi_probe()agent.c按设备树compatible从scmi_ofw_ids表选取agent_ops调用setup()绑定传输然后scmi_channels_setup()遍历arm,scmi节点的每个可用子节点读取其reg作为protocol_id为每个子节点注册一个rt_scmi_device最后额外注册一个 BASE0x10协议设备。Mailbox 传输对应compatible arm,scmi实现于 agent-mailbox.csetup()解析mboxes与shmem属性校验共享内存节点的compatible arm,scmi-shmemrt_ioremap映射共享内存并请求 mailbox 通道通道选择规则mbox_count 2 shmem_count 2时使用通道 1mbox_count 3时使用通道 2否则使用通道 0tx_prepare回调将消息写入共享内存scmi_shmem_msg_writetx_done在发送成功后清除通道状态scmi_shmem_clear_channelrx_callback负责把固件响应分发给msg-rx_callbackprocess_msg在自旋锁保护下调用rt_mbox_send(chan, msg, 30)即30 个 tick 的超时超时返回则释放锁并返回错误。SMC 传输对应compatible arm,scmi-smc、arm,scmi-smc-param、qcom,scmi-smc实现于 agent-smc.c读取arm,smc-id作为 SMC 功能号func_id映射共享内存共享内存按 4 KB 页组织SHMEM_SIZE 4KB、SHMEM_SHIFT 12param_page/param_offset由rt_kmem_v2p换算得到qcom,scmi-smc特殊处理从共享内存末尾 8 字节读取cap_id否则cap_id ~0UL若设备树提供了a2p中断则安装 ISRscmi_agent_smc_isr作为完成信号process_msg在自旋锁保护下先scmi_shmem_msg_write写入消息再执行arm_smccc_smc(func_id, ...)陷入固件根据返回值res.a0判断错误成功则scmi_shmem_msg_read读取响应最后清通道。Virtio 传输对应compatible arm,scmi-virtio实现位于 components/drivers/virtio/virtio-scmi.c由RT_FIRMWARE_ARM_SCMI_TRANSPORT_VIRTIO经RT_VIRTIO_SCMI使能适用于虚拟化场景如 QEMU。共享内存协议shmem.c共享内存布局定义在 components/drivers/firmware/arm_scmi/shmem.c偏移字段说明channel_statusbit0 CHANNEL_FREE通道空闲bit1 CHANNEL_ERROR通道错误flagsbit0 INTR_ENABLED中断使能length消息总长度含消息头msg_headerSCMI 消息头msg_payload[]消息负载scmi_shmem_msg_write()发送前检查CHANNEL_FREE位置忙并写入长度、头部与负载scmi_shmem_msg_read()检查CHANNEL_FREE读侧检测CHANNEL_ERROR并核对缓冲区长度是否足够防止溢出。这正是调试时观察通道忙/通道错误日志的底层来源。设备树配置控制器侧Mailbox 传输的设备树示例简化scmi: scmi { compatible arm,scmi; mboxes mbox 0; shmem scmi_shmem; /* 可选的按协议子节点 */ protocol14 { reg 0x14; /* SCMI_PROTOCOL_ID_CLOCK */ protocol-name clocks; /* 若驱动 ids[].name 设置了名字则必须匹配 */ }; protocol17 { reg 0x17; protocol-name regulator; }; }; scmi_shmem: sram… { compatible arm,scmi-shmem; reg …; };compatible与传输的对应关系见 agent.c 的scmi_ofw_ids表compatible传输arm,scmiMailboxagent-mailbox.carm,scmi-smc、arm,scmi-smc-param、qcom,scmi-smcSMCagent-smc.carm,scmi-virtioVirtiovirtio-scmi.c子节点reg即协议 ID取值与 scmi.h 中的SCMI_PROTOCOL_ID_*一致。Agent 为每个子节点注册一个rt_scmi_device协议驱动绑定到该节点的parent.ofw_node用于解析提供者专属的子节点例如电压协议下的regulators子节点。内置协议驱动协议 IDids[].name源码注册的服务0x14CLOCKclocksclk/clk-scmi.crt_clkprovider0x17VOLTAGEregulatorregulator/regulator-scmi.crt_regulator_register0x16RESETresetreset/reset-scmi.creset controller0x11POWERgenpdpmdomain/pm-domain-scmi.cpower domain 代理0x19PINCTRLpinctrlpinctrl/pinctrl-scmi.c基于 SCMI 的 pin 配置0x15SENSOR / thermalthermalthermal/thermal-scmi.cthermal zone各驱动的ids[]与名字可从源码确认例如 clk-scmi.c、regulator-scmi.c、reset-scmi.c、pm-domain-scmi.c、pinctrl-scmi.c、thermal-scmi.c。此外 dvfs/dvfs-scmi-cpufreq.c 也通过 SCMI 协议参与 CPU 调频。DT 中的消费者写法与 MMIO 后端完全一致、无需改动例如clocks scmi_clk 42; resets scmi_reset 3; power-domains scmi_pd 1;对应的子系统使用说明可参考仓库文档时钟page_device_clk、稳压器page_device_regulator、复位page_device_reset、电源域page_device_power_domain、引脚控制page_device_pinctrl。如何新增一个协议驱动实现probe(struct rt_scmi_device *sdev)—— 此时sdev-parent.ofw_node指向该协议子节点sdev-agent已由总线填充用rt_scmi_process_msg(sdev, msg)下发命令注册上层提供者clock、regulator 等让消费者可以按标准 API 使用发布驱动static const struct rt_scmi_device_id my_ids[] { { SCMI_PROTOCOL_ID_xxx, my-protocol-name }, /* 若使用名字须与 DT 一致 */ { /* sentinel */ }, }; static struct rt_scmi_driver my_scmi_driver { .name my-scmi, .ids my_ids, .probe my_probe, }; RT_SCMI_DRIVER_EXPORT(my_scmi_driver);匹配规则要点当ids[].name非 NULL 时必须与通道子节点上的protocol-name一致才能匹配成功若name为 NULL则该协议下匹配任意名字。调试指南先确认日志中arm-scmi是否 probe 成功、各子节点reg值是否符合预期日志标签scmi.agent、scmi.busMailbox 路径检查 mailbox TX/RX、共享内存channel free 位shmem.c以及rt_mbox_send的 30 tick 超时是否触发SMC 路径核对arm,smc-id、IRQ 完成信号以及arm,scmi-smc-param的页号/页内偏移换算是否正确版本不匹配若命令返回SCMI_ERR_PROTOCOL先通过 BASE 协议SCMI_COM_MSG_VERSION0x0查询固件与驱动端协议版本是否一致固件返回码不直观时用rt_scmi_strerror()把SCMI_ERR_*转成可读短名再对照错误表定位问题层级参数、访问权限、通信、硬件等。参考Agent 传输细节mailbox、SMC、shmem 布局见 SCMI Agent 文档Mailbox 门铃机制arm,scmi依赖见 Mailbox 文档核心头文件components/drivers/include/drivers/scmi.hAgent 与总线实现components/drivers/firmware/arm_scmi/agent.c、components/drivers/firmware/arm_scmi/bus.c赞分享操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载相关推荐RT-Thread Clock Time 子系统统一高精度时钟源与事件调度架构深度解析RT Thread Clock Time 子系统统一高精度时钟源与事件调度架构深度解析 Clock Time 是 RT Thread 中负责提供统一、高精度时操作系统嵌入式物联网嵌入式OSRTOSRT-Thread clock_time 子系统深度解析统一时间基准与高精度事件调度RT Thread clock_time 子系统深度解析统一时间基准与高精度事件调度 clock_time 是 RT Thread 中负责统一时间基准tim操作系统嵌入式物联网嵌入式OSRTOSRT-Thread Clock Time 子系统深度解析统一时间基准与高精度定时事件调度RT Thread Clock Time 子系统深度解析统一时间基准与高精度定时事件调度 RT Thread 的 Clock Time 子系统位于 comp操作系统嵌入式物联网嵌入式OSRTOS上一篇Multipass help 命令完全指南查看命令列表、选项与详细用法下一篇Visual C运行库终极解决方案5分钟修复所有Windows程序启动问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考