i.MX8MP平台开发分享(TMU驱动及用户接口篇)

概念

  • thermal zone
    温度控制区域。
  • sensor
    获取温度。
  • trip points
    温度跳变点,或者是温度阈值。
  • cooling device
    Thermal Cooling Device 是可以降温设备的抽象,能降温的设备比如风扇,这些好理解,但是像CPU、GPU 这些 Cooling devices 怎么理解呢?
    其实降温可以从两方面来理解,一个是加快散热,另外一个就是降低产热量。风扇,散热片这些是用来加快散热,CPU、GPU 这些 Cooling devices 是通过降低产热来降温。
  • governor
    温度控制的策略。
    • step wise
      节流逻辑:使用趋势来节流。*如果热区域正在“升温”,这将通过一个步骤来限制所有与该区域及其特定跳变点相关的冷却设备。如果该区域正在“冷却”,它会将设备的性能提高一步。
    • user space
      给用户侧发送一个事件,由用户侧来处理
    • gov_bang_bang
      控制风扇的一种简单策略,当超过温度T0时开启风扇,当温度低于T1时关闭风扇,T0 > T1。
    • power_allocator
      使用PID控制算法来精细控制温度变化。

设备树定义

TMU的设备树定义了温度校准数据的存储位置。

			tmu: tmu@30260000 {
				compatible = "fsl,imx8mp-tmu";
				reg = <0x30260000 0x10000>;
				clocks = <&clk IMX8MP_CLK_TSENSOR_ROOT>;
				nvmem-cells = <&tmu_calib>;
				nvmem-cell-names = "calib";
				#thermal-sensor-cells = <1>;
			};

温控的thermal-zones有两个thermal, 分别对应两个TMU。可以看到设备树定义了温度范围,但是这个范围目前的驱动代码会被驱动覆盖。

thermal-zones {
		cpu-thermal {
			polling-delay-passive = <250>;
			polling-delay = <2000>;
			thermal-sensors = <&tmu 0>;
			trips {
				cpu_alert0: trip0 {
					temperature = <85000>;
					hysteresis = <2000>;
					type = "passive";
				};

				cpu_crit0: trip1 {
					temperature = <95000>;
					hysteresis = <2000>;
					type = "critical";
				};
			};

			cooling-maps {
				map0 {
					trip = <&cpu_alert0>;
					cooling-device =
						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&mix_gpu_ml 0 1>;
				};
			};
		};

		soc-thermal {
			polling-delay-passive = <250>;
			polling-delay = <2000>;
			thermal-sensors = <&tmu 1>;
			trips {
				soc_alert0: trip0 {
					temperature = <85000>;
					hysteresis = <2000>;
					type = "passive";
				};

				soc_crit0: trip1 {
					temperature = <95000>;
					hysteresis = <2000>;
					type = "critical";
				};
			};

			cooling-maps {
				map0 {
					trip = <&soc_alert0>;
					cooling-device =
						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
				};
			};
		};
	};

驱动

对于驱动初始化函数imx8mm_tmu_probe,首先将设备树中两个thermal信息依次注册进thermal 框架中,迭代每个传感器的所有trip点(阈值温度),使用thermal_zone_get_num_trips获取trip点的数量。然后调用thermal_zone_get_trip函数获取每个trip点的详细信息。然后根据trip点的类型(THERMAL_TRIP_CRITICALTHERMAL_TRIP_PASSIVE),分别设置传感器的temp_criticaltemp_passive字段。

for (i = 0; i < data->num_sensors; i++) {
		tmu->sensors[i].priv = tmu;
		tmu->sensors[i].tzd =
			devm_thermal_of_zone_register(&pdev->dev, i,
						      &tmu->sensors[i],
						      &tmu_tz_ops);
		tmu->sensors[i].hw_id = i;

		devm_thermal_add_hwmon_sysfs(&pdev->dev, tmu->sensors[i].tzd);

		for (j = 0; j < thermal_zone_get_num_trips(tmu->sensors[i].tzd); j++) {
			ret = thermal_zone_get_trip(tmu->sensors[i].tzd, j, &trip);
			if (ret)
				continue;

			if (trip.type == THERMAL_TRIP_CRITICAL) {
				tmu->sensors[i].temp_critical = trip.temperature;
			} else if(trip.type == THERMAL_TRIP_PASSIVE) {
				tmu->sensors[i].temp_passive = trip.temperature;
			}
		}
	}

然后imx8mm_tmu_probe_set_calib_v2读取nvmem中的校准数据,写入对应的温度校准寄存器。

最后通过写入寄存器来打开TMU监测。

设备树中的温度阈值会被imx8mp_tmu_get_temp读取的TMU中的温度阈值覆盖。

static int imx8mp_tmu_get_temp(void *data, int *temp)
{
	struct tmu_sensor *sensor = data;
	struct imx8mm_tmu *tmu = sensor->priv;
	unsigned long val;
	bool ready;

	if (sensor->hw_id > (MAX_SENSOR_NUMBER - 1))
		return -EINVAL;

	val = readl_relaxed(tmu->base + TRITSR);
	ready = test_bit(probe_status_offset(sensor->hw_id), &val);
	if (!ready)
		return -EAGAIN;

	val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
	      FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
	if (val & SIGN_BIT) /* negative */
		val = (~(val & TEMP_VAL_MASK) + 1);

	*temp = val * 1000;
	if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
		return -EAGAIN;

	return 0;
}

用户层接口

/sys/class/thermal/thermal_zoneX

/sys/class/thermal/thermal_zone0 # ls -l
-r--r--r-- available_policies //可选的温控governor,如 power_allocator user_space step_wise
--w------- emul_temp //模拟设置thermal的温度,单位毫摄氏度,设置后 update_temperature()中可获取到这个温度,和实际达到这个温度同效果。只有其为0,读取的才是真正的温度值,否则就是echo的模拟值
-rw-r--r-- integral_cutoff
-rw-r--r-- k_d
-rw-r--r-- k_i
-rw-r--r-- k_po
-rw-r--r-- k_pu
-rw-r--r-- mode //此thermalzone是否使能了,若是为disabled,对其sys文件的操作不生效,可以echo enabled使能
-rw-r--r-- offset
-rw-r--r-- passive
-rw-r--r-- policy //当前使用的governor是哪个
-rw-r--r-- slope
-rw-r--r-- sustainable_power
-r--r--r-- temp //该温区的当前温度,测试时往 emul_temp 中写的值也会体现在这里。
-rw-r--r-- trip_point_0_hyst //滞后温度,来自设备树 hysteresis 字段,此例中为 2000。有 trips 节点才会有此文件。
-rw-r--r-- trip_point_0_temp //触发温度,来自设备树 temperature字段,此例中为 116500,可以通过sysfs更改。
-r--r--r-- trip_point_0_type //触发点0的类型,来自设备树 type 字段,此例中为"critical"
-r--r--r-- type //该温区的名称,对应于设备树 thermal_zones 下子节点的名字,此例中为"soc_max"
-rw-r--r-- uevent

不同 thermal_zoneX 下的文件不完全相同,取决于在设备树中是否指定了trips成员,以及指定了几个。

/sys/class/thermal/cooling_deviceX

/sys/class/thermal/cooling_device0 # ls -l
-rw-r--r-- cur_state //该 cooling_device 的当前 cooling state
-r--r--r-- max_state //该 cooling_device 的最大 cooling state
drwxr-xr-x  stats
-r--r--r-- type //该cooling device的名称
-rw-r--r-- uevent

/sys/class/thermal/cooling_device0 # ls -l stats/
--w------- reset //对统计状态进行复位
-r--r--r-- time_in_state_ms //在每个state下停留的时间
-r--r--r-- total_trans //不同state之间转换的次数
-r--r--r-- trans_table //各个state状态转换表,最大只能显示1个页的内容

type 为 thermal-cpufreq-X 的 cool device 控制 CPU ClusterX 的频点,比如向 cur_state 中写入 max_state 的值,对应Cluster的 scaling_max_freq 文件将显示被限制到了最小频点。
type 为 thermal-cpufreq-X 的是通过 cpufreq_cooling.c 注册的 cool device,type 为 thermal-devfreq-X 的是通过 devfreq_cooling.c 注册的 cool device。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漫游嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值