RK3399 Thermal (温度控制)

RK3399 Thermal (温度控制)

本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。

  • Thermal 是什么
  • 配置⽅法
    • Menuconfig配置
    • Tsadc配置
    • CPU & GPU配置
    • Termal zone 配置
  • ⽤⼾态接口
  • 常用设置
    • 获取当前温度
    • 关闭温度控制功能
  • 参考

Thermal 是什么

Thermal是内核开发者定义的⼀套⽀持根据指定governor控制系统温度,以防⽌芯⽚过热的框架模型。Thermal framework由governor、core、cooling device、sensor driver组成,软件架构如下:

RK3399 Thermal (温度控制)_第1张图片

  • Thermal governor:⽤于决定cooling device是否需要降频,降到什么程度。⽬前Linux4.4内核中包含了如下⼏种governor:
  • power_allocator:引⼊PID(⽐例-积分-微分)控制,根据当前温度,动态给各cooling device分配power,并将power转换为频率,从而达到根据温度限制频率的效果。
  • step_wise :根据当前温度,cooling device逐级降频。
  • fair share :频率档位⽐较多的cooling device优先降频。
  • userspace:不限制频率。
  • Thermal core: 对thermal governors和thermal driver进⾏了封装和抽象,并定义了清晰的接口。
  • Thermal sensor driver:sensor驱动,⽤于获取温度,⽐如tsadc。
  • Thermal cooling device:发热源或者可以降温的设备,⽐如CPU、GPU、DDR等。

配置⽅法

Menuconfig配置

<*> Generic Thermal sysfs driver   --->
 --- Generic Thermal sysfs driver
 [*]   APIs to parse thermal data out of device tree
 [*]   Enable writable trip points
 Default Thermal governor ( power_allocator )   --->   /* default thermal governor */
 [ ]   Fair -share thermal governor
 [ ]   Step_wise thermal governor                       /* step_wise governor */
 [ ]   Bang Bang thermal governor
 [*]   User_space thermal governor                     /* user_space governor */
 -*-   Power allocator thermal governor                 /* power_allocator governor */
 [*]   generic cpu cooling support                     /* cooling device */
 [ ]   Generic clock cooling support
 [*]   Generic device cooling support                   /* cooling device */
 [ ]   Thermal emulation mode support
 < >   Temperature sensor driver for Freescale i.MX SoCs
 <*>   Rockchip thermal driver                         /* thermal sensor driver */
 < >     rk_virtual thermal driver
 <*>     rk3368 thermal driver legacy                   /* thermal sensor driver */

通过“Default Thermal governor”配置项,可以选择温控策略,开发者可以根据实际产品需求进⾏修改。

Tsadc配置

Tsadc在温控中作为thermal sensor,⽤于获取温度,通常需要在DTSI和DTS都做配置。
以RK3399为例,DTSI包括如下配置:

tsadc : tsadc@ff260000 {
    compatible = "rockchip,rk3399-tsadc" ;
    reg = <0x0 0xff260000 0x0 0x100 >;                 /* 寄存器基地址和寄存器地址总⻓度 */
    interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH 0>; /* 中断号及中断触发⽅式 */
    assigned -clocks = <& cru SCLK_TSADC >;             /* ⼯作时钟,750KHz */
    assigned -clock -rates = <750000 >;
    clocks = <& cru SCLK_TSADC >, <& cru PCLK_TSADC >;   /* ⼯作时钟和配置时钟 */
    clock -names = "tsadc" , "apb_pclk" ;
    resets = <& cru SRST_TSADC >;                       /* 复位信号 */
    reset -names = "tsadc-apb" ;
    rockchip ,grf = <& grf >;                           /* 引⽤grf 模块,部分平台需要 */
    rockchip ,hw -tshut -temp = <120000 >;               /* 过温重启阀值,120 摄⽒度 */
    /* tsadc 输出引脚配置,⽀持两种模式:gpio 和otpout */
    pinctrl -names = "gpio" , "otpout" ;
    pinctrl -0 = <& otp_gpio >;
    pinctrl -1 = <& otp_out >;
    /*
    * thermal sensor 标识,表⽰tsadc 可以作为⼀个thermal sensor ,
    * 并指定了引⽤tsadc 节点的时候需要带⼏个参数。
    * 如果SoC ⾥⾯只有⼀个tsadc ,可以设置为0,超过⼀个必须设置为1。
    */
    #thermal-sensor-cells = <1>;
    status = "disabled" ;
};
/* IO 口配置 */
pinctrl : pinctrl {
    ...
    tsadc {
        /* 配置为gpio 模式 */
        otp_gpio : otp -gpio {
        rockchip ,pins = <1 6 RK_FUNC_GPIO &pcfg_pull_none >;
        };
        /* 配置为over temperature protection 模式 */
        otp_out : otp -out {
        rockchip ,pins = <1 6 RK_FUNC_1 &pcfg_pull_none >;
        };
    };
    ....
}

DTS的配置,主要⽤于选择通过CRU复位还是GPIO复位,低电平复位还是⾼电平复位。需要特别注意的是如果配置成GPIO复位,硬件上需要否把tsadc输出引脚连到PMIC的复位脚,否则只能配置成CRU复位。

&tsadc {
     rockchip ,hw -tshut -mode = <1>;     /* tshut mode 0:CRU 1:GPIO */
     rockchip ,hw -tshut -polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
     status = "okay" ;
};

CPU & GPU配置

CPU在温控中作为cooling device,节点中需要包含#cooling-cells、dynamic-power-coefficient属性。
以RK3399为例:

cpu_l0 : cpu@0 {
    device_type = "cpu" ;
    compatible = "arm,cortex-a53" , "arm,armv8" ;
    reg = <0x0 0x0 >;
    enable -method = "psci" ;
    #cooling-cells = <2>; /* cooling device 标识,表⽰该设备可以作为⼀个cooling device */
    clocks = <& cru ARMCLKL >;
    cpu -idle -states = <& CPU_SLEEP &CLUSTER_SLEEP >;
    dynamic -power -coefficient = <100 >; /* 动态功耗常数C,动态功耗公式为Pdyn=C*V^2*F */
};
...
cpu_b0 : cpu@100 {
    device_type = "cpu" ;
    compatible = "arm,cortex-a72" , "arm,armv8" ;
    reg = <0x0 0x100 >;
    enable -method = "psci" ;
    #cooling-cells = <2>; /* cooling device 标识,表⽰该设备可以作为⼀个cooling device */
    clocks = <& cru ARMCLKB >;
    cpu -idle -states = <& CPU_SLEEP &CLUSTER_SLEEP >;
    dynamic -power -coefficient = <436 >; /* ⽤于计算动态功耗的参数 */
};

GPU在温控中作为cooling device,节点需要包含#cooling-cells属性和power_model⼦节点。
以RK3399为例:

gpu : gpu@ff9a0000 {
    compatible = "arm,malit860" ,"arm,malit86x" ,"arm,malit8xx" , "arm,mali-midgard" ;
    reg = <0x0 0xff9a0000 0x0 0x10000 >;
    interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH 0>, <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH 0>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH 0>;
    interrupt -names = "GPU" , "JOB" , "MMU" ;
    clocks = <& cru ACLK_GPU >;
    clock -names = "clk_mali" ;
    #cooling-cells = <2>; /* cooling device 标识,表⽰该设备可以作为⼀个cooling device */
    power -domains = <& power RK3399_PD_GPU >;
    power -off -delay -ms = <200 >;
    status = "disabled" ;

    gpu_power_model : power_model {
        compatible = "arm,mali-simple-power-model" ;
        static -coefficient = <411000 >; /* ⽤于计算静态功耗的参数 */
        dynamic -coefficient = <733 >;   /* ⽤于计算动态功耗的参数 */
        ts = <32000 4700 ( -80 ) 2>;     /* ⽤于计算静态功耗的参数 */
        thermal -zone = "gpu-thermal" ;   /* 从gpu-thermal 获取温度,⽤于计算静态功耗 */
    };
};

Termal zone 配置

Termal zone节点主要⽤于配置温控策略相关的参数并⽣成对应的⽤⼾态接口。
以RK3399为例:

thermal_zones : thermal -zones {
    /* ⼀个节点对应⼀个thermal zone ,并包含温控策略相关参数 */
    soc_thermal : soc -thermal {
        /* 温度⾼于trip-point-0 指定的值,每隔20ms 获取⼀次温度 */
        polling -delay -passive = <20 >; /* milliseconds */
        /* 温度低于trip-point-0 指定的值,每隔1000ms 获取⼀次温度 */
        polling -delay = <1000 >; /* milliseconds */
        /* 温度等于trip-point-1 指定的值时,系统分配给cooling device 的能量 */
        sustainable -power = <1000 >; /* milliwatts */
        /* 当前thermal zone 通过tsadc0 获取温度 */
        thermal -sensors = <& tsadc 0>;

        /* trips 包含不同温度阀值,不同的温控策略,配置不⼀定相同 */
        trips {
            /*
            * 温控阀值,超过该值温控策略开始⼯作,但不⼀定⻢上限制频率,
            * power 小到⼀定程度才开始限制频率
            */
            threshold : trip -point -0 {
                /* 超过70 摄⽒度,温控策略开始⼯作,并且70 摄⽒度也是tsadc 触发中断的⼀个阀值 */
                temperature = <70000 >; /* millicelsius */
                /* 温度低于temperature-hysteresis 时触发中断,当前未实现,但是框架要求必须填 */
                hysteresis = <2000 >; /* millicelsius */
                type = "passive" ; /* 表⽰超过该温度值时,使⽤polling-delay-passive */
            };

            /* 温控⽬标温度,期望通过降频使得芯⽚不超过该值 */
            target : trip -point -1 {
                /* 期望通过降频使得芯⽚不超过85 摄⽒度,并且85 摄⽒度也是tsadc 触发中断的⼀个阀值 */
                temperature = <85000 >; /* millicelsius */
                /* 温度低于temperature-hysteresis 时触发中断,当前未实现,但是框架要求必须填 */
                hysteresis = <2000 >; /* millicelsius */
                type = "passive" ; /* 表⽰超过该温度值时,使⽤polling-delay-passive */
            };

            /* 过温保护阀值,如果降频后温度仍然上升,那么超过该值后,让系统重启 */
            soc_crit : soc -crit {
                /* 超过115 摄⽒度重启,并且115 摄⽒度也是tsadc 触发中断的⼀个阀值 */
                temperature = <115000 >; /* millicelsius */
                /* 温度低于temperature-hysteresis 时触发中断,当前未实现,但是框架要求必须填 */
                hysteresis = <2000 >; /* millicelsius */
                type = "critical" ; /* 表⽰超过该温度值时,重启 */
            };
        };

        /* cooling device 配置节点,每个⼦节点代表⼀个cooling device */
        cooling -maps {
            map0 {
                /*
                * 表⽰在target trip 下,该cooling device 才起作⽤,
                * 对于power allocater 策略必须填target
                */
                trip = <& target >;
                /* A53 做为cooloing device , THERMAL_NO_LIMIT 不起作⽤,但必须填 */
                cooling -device = <& cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT >;
                contribution = <4096 >; /* 计算功耗时乘以4096/1024 倍,⽤于调整降频顺序和尺度 */
                };
            map1 {
                /*
                * 表⽰在target trip 下,该cooling device 才起作⽤,
                * 对于power allocater 策略必须填target
                */
                trip = <& target >;
                /* A72 做为cooloing device , THERMAL_NO_LIMIT 不起作⽤,但必须填 */
                cooling -device = <& cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT >;
                contribution = <1024 >;/* 计算功耗时乘以1024/1024 倍,⽤于调整降频顺序和尺度 */
                };
            map2 {
                /*
                * 表⽰在target trip 下,该cooling device 才起作⽤,
                * 对于power allocater 策略必须填target
                */
                trip = <& target >;
                /* GPU 做为cooloing device , THERMAL_NO_LIMIT 不起作⽤,但必须填 */
                cooling -device = <& gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT >;
                contribution = <4096 >;/* 计算功耗时乘以4096/1024 倍,⽤于调整降频顺序和尺度 */
                };
        };
    };

    /* ⼀个节点对应⼀个thermal zone ,并包含温控策略相关参数,当前thermal zone 只⽤于获取温度 */
    gpu_thermal : gpu -thermal {
        /* 包含温控策略配置的情况下才起作⽤,架要求必须填 */
        polling -delay -passive = <100 >; /* milliseconds */
        /* 每隔1000ms 获取⼀次温度 */
        polling -delay = <1000 >; /* milliseconds */
        /* 当前thermal zone 通过tsadc1 获取温度 */
        thermal -sensors = <& tsadc 1>;
    };
};

⽤⼾态接口

⽤⼾态接口在/sys/class/thermal/⽬录下,具体内容和DTSI中thermal zone节点的配置对应。有的平台thermalzone节点下只有⼀个⼦节点,对应/sys/class/thermal/⽬录下也只有thermal_zone0⼦⽬录;有的平台有两个⼦节点,对应/sys/class/thermal/⽬录下就会有thermal_zone0和thermal_zone1⼦⽬录。通过⽤⼾态接口可以切换温控策略,查看当前温度等。
以RK3399为例⼦,/sys/class/thermal/thermal_zone0/⽬录下包含如下常⽤的信息:

temp                     /* 当前温度 */
available_policies /* ⽀持的温控策略 */
policy /* 当前使⽤的温控策略 */
sustainable_power /* 期望的最⾼温度下对应的power 值 */
integral_cutoff /* PID 算法中I的触发条件:当前温度-期望的最⾼温度

常用设置

获取当前温度

直接查看⽤⼾态接口thermal_zone0或者thermal_zone1⽬录下的temp节点即可。
以RK3399为例,获取CPU温度,在串口中输⼊如下命令:

cat /sys /class /thermal /thermal_zone0 /temp

获取GPU温度,在串口中输⼊如下命令:

cat /sys /class /thermal /thermal_zone1 /temp

关闭温度控制功能

⽅法⼀:menuconfig中默认温控策略设置为user_space。

<*> Generic Thermal sysfs driver   --->
 --- Generic Thermal sysfs driver
 [*]   APIs to parse thermal data out of device tree
 [*]   Enable writable trip points
 Default Thermal governor ( user_space )   --->   /* power_allocator 改为user_space */

⽅法⼆:开机后通过命令关温控。
⾸先,把温控策略切换到user_space,即把⽤⼾态接口下的policy节点改成user_space;或者把mode设置成
disabled状态;然后,解除频率限制,即将⽤⼾态接口下的所有cdev的cur_state设置为0。
以RK3399为例,策略切换到user_space:

echo user_space > /sys /class /thermal /thermal_zone0 /policy

或者把mode设置成disabled状态:

echo disabled > /sys /class /thermal /thermal_zone0 /mode

解除频率限制:

/* 具体有多少个cdev ,根据实际情况修改 */
echo 0 > /sys /class /thermal /thermal_zone0 /cdev0 /cur_state
echo 0 > /sys /class /thermal /thermal_zone0 /cdev1 /cur_state
echo 0 > /sys /class /thermal /thermal_zone0 /cdev2 /cur_state

参考

Thermal开发指南

你可能感兴趣的:(嵌入式(linux))