IC - reset子系统

简介

  • 复杂的IC(SOC)内部有多个拥有独立功能的硬件模块,例如:cpu cores,tpu cores以及wdt,usb,mmc等各种外设。
  • 出于IC稳定性(异常后可恢复)等方面的考虑,SOC中会设计专门的reset电路,负责各个硬件模块的复位,在内部为硬件模块设计复位信号(reset signals),软件可通过寄存器控制硬件模块的复位。

SOC 示例

  • SOC(xx181x)的reset系统,比较复杂,设计了三个层级,主要功能:
  1. 外设模块的复位。
  2. CPU、TPU核的复位。
  3. 系统整体的复位。

使用

  • Reset系统实现比较复杂,但是暴露给用户使用的方式比较简单,一般是提供多个寄存器,每个寄存器以1 bit控制一个ip的复位,因此对于某个ip的复位只有两个操作:
  1. 复位,往控制该ip的特定bit写0
  2. 解复位,往控制该ip的特定bit写1
  • 先复位,延时一会,解复位,ip就能够复位成功。
  • SOC(xx181x)也提供了另外一套寄存器,同样以1 bit控制一个ip的复位,不同的是:复位时只需要往该bit写0,不需要再解复位(往该bit写1),ip就能复位成功。

适配

  1. 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";
    };
    ...
    }

  • 说明:

  1. 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

  2. <&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)) {
    ...
    }

相关推荐
序属秋秋秋13 小时前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程
云计算练习生14 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
虚伪的空想家17 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t198751281 天前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk81631 天前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
晚风吹人醒.1 天前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件
Hard but lovely1 天前
linux: pthread库的使用和理解
linux
这儿有一堆花1 天前
Kali Linux:探测存活到挖掘漏洞
linux·运维·服务器
松涛和鸣1 天前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
皮小白1 天前
ubuntu开机检查磁盘失败进入应急模式如何修复
linux·运维·ubuntu