文章目录
- [1 概要](#1 概要)
- [2 Linux下Remoteproc相关API](#2 Linux下Remoteproc相关API)
-
- [2.8 rproc 设备树节点](#2.8 rproc 设备树节点)
- [3 总结](#3 总结)
1 概要
使用正点原子的stm32mp157mini进行RPMSG多核通信试验。
硬件:STM32MP157
软件:STM32CubeIDE / STM32CubeMX
远程处理器(Remoteproc)框架负责根据固件资源表中可用的信息激活 Linux 端的进程间通信(IPC),本节我们来分析 Linux 下的 Remoteproc 相关驱动,了解 Remoteproc 是怎样控制远程处理器的。本小节的内容会涉及到分析代码,会比较枯燥乏味,如果只想了解 Remotepro使用方法,可以直接看本章的最后一小节。
本章分为如下几部分(文章末尾会附上链接):
- 资源表
- 存储和系统资源分配
- Linux 下 Remoteproc 相关 API
- 链接脚本
- Remoteproc 的使用
2 Linux下Remoteproc相关API
2.8 rproc 设备树节点
打开stm32mp151.dtsi 设备树文件,找到设备树中和M4相关的Remoteproc配置,如下:


在上面的代码段里,有三个节点:mlahb节点、m4_rproc节点和m4_system_resources节点。m4_rproc节点下就是加载和管理M4固件的配置信息。m4_system_resources节点(也就是M4的资源管理器)下就是M4的资源分配配置信息。第10行,compatible属性值为"st,stm32mp1m4",在Linux内核源码中搜索此属性值找到对应的驱动文件为drivers/remoteproc/stm32_rproc.c,打开此文件找到如下内容:
c
1 static const struct of_device_id stm32_rproc_match[] = {
2 { .compatible = "st,stm32mp1-m4" },
3 {},
4 };
5 MODULE_DEVICE_TABLE(of, stm32_rproc_match);
6 /* 此处省略部分代码 */
7 static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops,
8 stm32_rproc_suspend, stm32_rproc_resume);
9
10 static struct platform_driver stm32_rproc_driver = {
11 .probe = stm32_rproc_probe,
12 .remove = stm32_rproc_remove,
13 .shutdown = stm32_rproc_shutdown,
14 .driver = {
15 .name = "stm32-rproc",
16 .pm = &stm32_rproc_pm_ops,
17 .of_match_table = of_match_ptr(stm32_rproc_match),
18 },
19 };
20 /* 向Linux内核注册stm32_rproc_driver驱动 */
21 module_platform_driver(stm32_rproc_driver);
22 MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
23 MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
24 MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
25 MODULE_LICENSE("GPL v2");
上面的驱动代码是一个标准的platform驱动,第2行就是设备树下匹配到驱动程序的地方,在stm32_rproc_match中。第15行,成员name属性是stm32-rproc,即定义了驱动的名字是stm32-rproc,它是用于驱动与设备匹配的。
第17行,用于匹配对应的device,即匹配设备树中的节点。第21行module_platform_driver()函数向Linux内核注册stm32_rproc_driver这个platform驱动。当设备和驱动匹配成功以后,stm32_rproc_driver->probe函数(即stm32_rproc_probe()函数)就会被执行。下面,我们直接去
看stm32_rproc_probe()函数做了哪些操作。stm32_rproc_probe()函数在Linux内核源码的drivers/remoteproc/stm32_rproc.c文件下,其函数定义如下所示:
c
1 static int stm32_rproc_probe(struct platform_device *pdev)
2 {
3 struct device *dev = &pdev->dev;
4 struct stm32_rproc *ddata;
5 struct device_node *np = dev->of_node;
6 struct rproc *rproc;
7 int ret;
8
9 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
10 if (ret)
11 return ret;
12
13 rproc=rproc_alloc(dev,np->name,&st_rproc_ops,NULL,sizeof(*ddata));
14 if (!rproc)
15 return -ENOMEM;
16
17 rproc->has_iommu = false;
18 ddata = rproc->priv;
19 ddata->workqueue = create_workqueue(dev_name(dev));
20 if (!ddata->workqueue) {
21 dev_err(dev, "cannot create workqueue\n");
22 ret = -ENOMEM;
23 goto free_rproc;
24 }
25
26 platform_set_drvdata(pdev, rproc);
27
28 ret = stm32_rproc_parse_dt(pdev);
29 if (ret)
30 goto free_wkq;
31 if (!rproc->early_boot) {
32 ret = stm32_rproc_stop(rproc);
33 if (ret)
34 goto free_wkq;
35 }
36
37 ret = stm32_rproc_request_mbox(rproc);
38 if (ret)
39 goto free_wkq;
40
41 ret = rproc_add(rproc);
42 if (ret)
43 goto free_mb;
44
45 return 0;
46
47 free_mb:
48 stm32_rproc_free_mbox(rproc);
49 free_wkq:
50 destroy_workqueue(ddata->workqueue);
51 free_rproc:
52 if (device_may_wakeup(dev)) {
53 dev_pm_clear_wake_irq(dev);
54 device_init_wakeup(dev, false);
55 }
56 rproc_free(rproc);
57 return ret;
58 }
第4行,ddata指针是ST官方的私有数据stm32_rproc结构体。
第6行,声明了一个rproc类型的结构体。
第9行,DMA相关配置。
第13行,rproc_alloc函数主要作用是分配一个新的rproc结构体空间,同时st_rproc_ops地址赋值给rproc->ops参数,目的是调用回调函数完成对应的功能(类似XXX_ops的结构体中的成员变量就是一些回调函数),这行的目的就是分配一个新的远程处理器(rproc)结构体,使用此函数创建 rproc 结构体后,应调用 rproc_add() 以完成远程处理器的注册,在后面我们会看到调用此函数。
第18行,保存ST官方的私有数据到rproc结构体里。
第19行,创建工作队列,workqueue的名称是设备的名字,每个workqueue就是一个内核进程,为系统创建一个内核线程。
第28行,调用stm32_rproc_parse_dt()函数来获取设备树中的属性,目的就是完成M4设备的配置。
第31~35 行,如果没有加载固件则调用stm32_rproc_stop 函数,该函数会做一些操作,如请求关闭远程处理器,此时传输阻塞,会打印"warning: remote FW shutdown without ack",并将远程处理器状态设置为离线状态等。
第37行,stm32_rproc_request_mbox()函数为远程处理器申请邮箱,A7 和 M4 可通过邮箱发布数据。
第41行,rproc_add()函数在前面的介绍中我们已经了解了,就是注册一个远程处理器。
第56行,rproc_free()函数释放由 rproc_alloc ()分配的 rproc 。 下面我们来看看st_rproc_ops结构体,在stm32_rproc.c找到如下代码:

st_rproc_ops 结构体中有几个处理程序,每个处理程序对应一个回调函数,如 start 处理程序接受一个 rproc 结构体,然后打开设备电源并启动它。stop处理程序采用 rproc 并关闭远程处理器。kick处理程序接受一个 rproc 和一个放置新消息的虚拟队列的索引,调用此函数时会中断远程处理器并让它知道它有待处理的消息。find_loaded_rsc_table就是查找已经加载的固件资源表,执行的是stm32_rproc_elf_find_loaded_rsc_table()函数。 每个 Remoteproc 的实现至少应该提供 start 和 stop 处理程序,关于这些函数我们不必深入分析,只要我们知道这是ST官方实现操作M4相关的接口函数就行了。
3 总结
本章节讲述了Linux下Remoteproc相关API。