简介
- 复杂的IC(SOC)内部有多个拥有独立功能的硬件模块,例如:cpu cores,tpu cores以及wdt,usb,mmc等各种外设。
- 出于IC稳定性(异常后可恢复)等方面的考虑,SOC中会设计专门的reset电路,负责各个硬件模块的复位,在内部为硬件模块设计复位信号(reset signals),软件可通过寄存器控制硬件模块的复位。
SOC 示例
- SOC(xx181x)的reset系统,比较复杂,设计了三个层级,主要功能:
- 外设模块的复位。
- CPU、TPU核的复位。
- 系统整体的复位。
使用
- Reset系统实现比较复杂,但是暴露给用户使用的方式比较简单,一般是提供多个寄存器,每个寄存器以1 bit控制一个ip的复位,因此对于某个ip的复位只有两个操作:
- 复位,往控制该ip的特定bit写0
- 解复位,往控制该ip的特定bit写1
- 先复位,延时一会,解复位,ip就能够复位成功。
- SOC(xx181x)也提供了另外一套寄存器,同样以1 bit控制一个ip的复位,不同的是:复位时只需要往该bit写0,不需要再解复位(往该bit写1),ip就能复位成功。
适配
- dts配置
-
需要在dts中配置reset-controller
/ {
...
rst: reset-controller {
compatible = "xxxxxx,reset";
reg = <0x0 0x03003000 0x0 0x10>;
};
...
} -
其它ip reset配置
#include <dt-bindings/reset/xxx-resets.h>
/{
...
watchdog0: wd@0x3010000 {
...
resets = <&rst RST_WDT>;
reset-names = "rst_wdt";
};
...
} -
说明:
-
xxx-resets.h是uboot和linux中,各个ip的reset id定义,如下:
#define RST_MAINRST_AP 0
#define RST_SECONDRST_AP 1
#define RST_DDR 2
#define RST_H264C 3
#define RST_WDT 4 -
<&rst RST_WDT> 中的RST_WDT是引用头文件中的reset id,填具体的数字也可以,如下:
resets = <&rst 4>;
uboot
-
reset id定义
file: u-boot-2021.10/include/dt-bindings/reset/xxx-resets.h
-
驱动实现
file: u-boot-2021.10/drivers/reset/reset-xxx.c
-
驱动中reset接口使用
-
uboot下有一套和linux类似的接口,使用略。
Linux
reset-controller驱动实现
-
reset id定义
//file: linux_5.10/include/dt-bindings/reset/xxx-resets.h
-
驱动接口定义
struct reset_control_ops{
int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);//复位+解复位
int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);//复位
int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);//解复位
int (*status)(struct reset_controller_dev *rcdev, unsigned long id);//复位状态查询
} -
驱动核心接口(assert、deassert)实现
//file: linux_5.10/drivers/reset/reset-xxx.c
static int xx_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
// 将reset id转换为对应的 寄存器和bit,对该bit写0。
// soc xx181x实现
int bank = id / 32;
int offset = id % 32;spin_lock_irqsave(&data->lock, flags); // 将该bit置 0 reg = readl(data->membase + (bank * 4)); writel(reg & ~BIT(offset), data->membase + (bank * 4)); spin_unlock_irqrestore(&data->lock, flags); return 0;
}
static int xx_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
// 将reset id转换为对应的 寄存器和bit,对该bit写1。
// soc xx181x实现同上,置0改为置1
return 0;
}static const struct reset_control_ops bm_reset_ops = {
.assert = xxx_reset_assert,
.deassert = xxx_reset_deassert,
};
reset framework core(provider)
-
reset 主逻辑以及API实现
// file: drivers/reset/core.c
struct reset_control {
struct reset_controller_dev *rcdev;
struct list_head list;
unsigned int id;
struct kref refcnt;
bool shared;
bool array;
atomic_t deassert_count;
atomic_t triggered_count;
};
... -
consumer使用的头文件(接口定义)
// file: include/linux/reset.h
// 获取reset handle
struct reset_control *devm_reset_control_get(struct device *dev, const char *id);devm_reset_control_get_exclusive:查找并获取reset_control的独占引用(不能与其他驱动程序共享)。
devm_reset_control_get_shared:查找并获取reset_control的共享引用(可以与另一个驱动程序共享)。
devm_reset_control_get:与 devm_reset_control_get_exclusive 相同。
devm_reset_control_get_optional:与 devm_reset_control_get 相同,只是引用名称是可选的。
devm_reset_control_get_optional_exclusive:与devm_reset_control_get_exclusive 相同,只是引用名称是可选的。
devm_reset_control_get_optional_shared:与devm_reset_control_get_shared 相同,只是引用名称是可选// reset 操作
int reset_control_reset(struct reset_control *rstc); //复位 + 解复位操作
int reset_control_assert(struct reset_control *rstc); //复位
int reset_control_deassert(struct reset_control *rstc); //解复位
其它驱动(consumer)使用
-
示例
struct reset_control *reset; int ret; // 1. get handle reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(reset)) { ... } // 2. 复位 ret = reset_control_assert(reset); if (ret) { ... } udelay(2); // 3. 解复位 reset_control_deassert(reset);
-
也可以根据dts中的reset-name获取handle
reset = devm_reset_control_get(&pdev->dev, "rst_wdt");
if (IS_ERR(reset)) {
...
}