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

相关推荐
朝九晚五ฺ1 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream1 小时前
Linux的桌面
linux
xiaozhiwise2 小时前
Makefile 之 自动化变量
linux
意疏4 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
BLEACH-heiqiyihu4 小时前
RedHat7—Linux中kickstart自动安装脚本制作
linux·运维·服务器
一只爱撸猫的程序猿4 小时前
一个简单的Linux 服务器性能优化案例
linux·mysql·nginx
我的K84095 小时前
Flink整合Hudi及使用
linux·服务器·flink
1900436 小时前
linux6:常见命令介绍
linux·运维·服务器
Camellia-Echo6 小时前
【Linux从青铜到王者】Linux进程间通信(一)——待完善
linux·运维·服务器