文章代码分析基于linux-5.19.13,架构基于aarch64(ARM64)。
1. 前言
复杂IC内部有很多具有独立功能的硬件模块,例如CPU cores、GPU cores、USB控制器、MMC控制器、等等,出于功耗、稳定性等方面的考虑,有些IC在内部为这些硬件模块设计了复位信号(reset signals),软件可通过寄存器(一般1个bit控制1个硬件)控制这些硬件模块的复位状态。
Linux kernel为了方便设备驱动的编写,抽象出一个简单的软件框架----reset framework,为reset的provider提供统一的reset资源管理手段,并为reset的consumer(各个硬件模块)提供便捷、统一的复位控制API。
2. 前言
reset子系统也分为了consumer和provider,结构体关系如下:
3. consumer
对于一个具体的硬件模块,它的要求很简单:复位我的硬件模块,而不必关注具体复位的手段(例如控制哪个寄存器的哪个bit位,等等)。
Linux kernel基于device tree提供了对应的reset framework:
-
首先,提供描述系统中reset资源的方法(参考provider的介绍),这样consumer可以基于这种描述,在自己的dts node中引用所需的reset信号。
-
然后,consumer设备在自己的dts node中使用“resets”、“reset-names”等关键字声明所需的reset的资源,例如("resets"字段的具体格式由reset provider决定):
device {
resets = <&rst 20>;
reset-names = "reset";
};
This represents a device with a single reset signal named "reset".
bus {
resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>;
reset-names = "i2s1", "i2s2", "dma", "mixer";
};
This represents a bus that controls the reset signal of each of four sub- ordinate devices. Consider for example a bus that fails to operate unless no child device has reset asserted.
- 最后,consumer driver在需要的时候,可以调用下面的API复位自己(具体可参考"include\linux\reset.h"):
- 只有一个reset信号的话,可以使用最简单的device_reset API
static inline int __must_check device_reset(struct device *dev)
- 如果需要更为复杂的控制(例如有多个reset信号、需要控制处于reset状态的长度的等),可以使用稍微复杂的API
/* 通过reset_control_get或者devm_reset_control_get获得reset句柄 */
struct reset_control *reset_control_get(struct device *dev, const char *id);
struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
/* 通过reset_control_put释放reset句柄 */
void reset_control_put(struct reset_control *rstc);
/* 通过reset_control_reset进行复位,或者通过reset_control_assert使设备处于复位生效状态,通过reset_control_deassert使复位失效 */
int reset_control_reset(struct reset_control *rstc); /先复位,延迟一会,然后解复位
int reset_control_assert(struct reset_control *rstc); //复位
int reset_control_deassert(struct reset_control *rstc);//解复位
4. provider
kernel为reset provider提供的API位于"include/linux/reset-controller.h"中,很简单,无非就是:创建并填充reset controller设备(struct reset_controller_dev),并调用相应的接口:
- reset_controller_register //注册reset_controller
- reset_controller_unregister //注销reset_controller
reset controller的抽象也很简单:
/**
* struct reset_controller_dev - reset controller entity that might
* provide multiple reset controls
* @ops: a pointer to device specific struct reset_control_ops
* @owner: kernel module of the reset controller driver
* @list: internal list of reset controller devices
* @reset_control_head: head of internal list of requested reset controls
* @dev: corresponding driver model device struct
* @of_node: corresponding device tree node as phandle target
* @of_reset_n_cells: number of cells in reset line specifiers
* @of_xlate: translation function to translate from specifier as found in the
* device tree to id as given to the reset control ops, defaults
* to :c:func:`of_reset_simple_xlate`.
* @nr_resets: number of reset controls in this reset controller device
*/
struct reset_controller_dev {
const struct reset_control_ops *ops;//ops提供reset操作的实现,基本上是reset provider的所有工作量。
s