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

相关推荐
筱源源2 分钟前
Elasticsearch-linux环境部署
linux·elasticsearch
pk_xz1234562 小时前
Shell 脚本中变量和字符串的入门介绍
linux·运维·服务器
小珑也要变强2 小时前
Linux之sed命令详解
linux·运维·服务器
Lary_Rock4 小时前
RK3576 LINUX RKNN SDK 测试
linux·运维·服务器
云飞云共享云桌面6 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
Peter_chq6 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
一坨阿亮7 小时前
Linux 使用中的问题
linux·运维
dsywws8 小时前
Linux学习笔记之vim入门
linux·笔记·学习
幺零九零零9 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
小林熬夜学编程11 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法