* [PATCH v9 1/3] dt-bindings: thermal: imx: Document temperature offset property
2026-07-17 6:35 [PATCH v9 0/3] thermal: imx: Add temperature offset support Haoning CHENG via B4 Relay
@ 2026-07-17 6:35 ` Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 2/3] thermal/drivers/imx: Fix rounding and clamp for i.MX7D alarm Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support Haoning CHENG via B4 Relay
2 siblings, 0 replies; 5+ messages in thread
From: Haoning CHENG via B4 Relay @ 2026-07-17 6:35 UTC (permalink / raw)
To: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
Cc: linux-pm, devicetree, imx, linux-arm-kernel, linux-kernel,
Haoning CHENG, Krzysztof Kozlowski
From: Haoning CHENG <Haoning.CHENG@cn.bosch.com>
Some boards need the reported temperature to reflect the SoC
package-surface temperature rather than the internal die temperature.
Document the optional fsl,temp-calibration-offset-millicelsius property,
a signed offset in millicelsius applied to the internally measured
temperature to make it better correspond to the package-surface
temperature. The offset is board-specific and is determined through
thermal characterization. When absent, the offset is zero.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Haoning CHENG <Haoning.CHENG@cn.bosch.com>
---
.../devicetree/bindings/thermal/imx-thermal.yaml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
index 949b154856c5..6c268d56291b 100644
--- a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
@@ -59,6 +59,20 @@ properties:
clocks:
maxItems: 1
+ fsl,temp-calibration-offset-millicelsius:
+ minimum: -20000
+ maximum: 20000
+ description:
+ A signed offset, in millicelsius, added to the calculated
+ sensor temperature to make the TEMPMON reading better correspond
+ to the SoC package-surface temperature observed during board-level
+ thermal characterization. This is not a sensor calibration offset;
+ it is a board-specific conversion offset derived from the
+ relationship between the internal sensor reading and the
+ package-surface temperature, which depends on the package, PCB
+ layout, cooling arrangement, and operating environment. The range
+ is limited to ±20 °C. When absent, no offset is applied.
+
"#thermal-sensor-cells":
const: 0
@@ -109,6 +123,7 @@ examples:
nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
nvmem-cell-names = "calib", "temp_grade";
clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
+ fsl,temp-calibration-offset-millicelsius = <(-6400)>;
#thermal-sensor-cells = <0>;
};
};
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v9 2/3] thermal/drivers/imx: Fix rounding and clamp for i.MX7D alarm
2026-07-17 6:35 [PATCH v9 0/3] thermal: imx: Add temperature offset support Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 1/3] dt-bindings: thermal: imx: Document temperature offset property Haoning CHENG via B4 Relay
@ 2026-07-17 6:35 ` Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support Haoning CHENG via B4 Relay
2 siblings, 0 replies; 5+ messages in thread
From: Haoning CHENG via B4 Relay @ 2026-07-17 6:35 UTC (permalink / raw)
To: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
Cc: linux-pm, devicetree, imx, linux-arm-kernel, linux-kernel,
Haoning CHENG, Frank Li
From: Haoning CHENG <Haoning.CHENG@cn.bosch.com>
Convert the alarm temperature from millicelsius to degrees for i.MX7D
using ceiling division instead of integer division, ensuring rounding
errors do not cause the alarm to trigger below the intended threshold.
Use DIV_ROUND_UP() for non-negative values and plain integer division
for negative values, since C rounds toward zero which is equivalent to
ceiling when the divisor is positive.
Add clamp() to ensure the hardware register value stays within the 9-bit
range (0..0x1ff) of the i.MX7D alarm field, preventing silent truncation
if an out-of-range value is written.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Haoning Cheng <Haoning.CHENG@cn.bosch.com>
---
drivers/thermal/imx_thermal.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 38c993d1bcb3..7f7d1116b9d6 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -240,10 +240,16 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data,
data->alarm_temp = alarm_temp;
- if (data->socdata->version == TEMPMON_IMX7D)
- alarm_value = alarm_temp / 1000 + data->c1 - 25;
- else
+ if (data->socdata->version == TEMPMON_IMX7D) {
+ if (alarm_temp >= 0)
+ alarm_temp = DIV_ROUND_UP(alarm_temp, 1000);
+ else
+ alarm_temp /= 1000;
+ alarm_value = alarm_temp + data->c1 - 25;
+ alarm_value = clamp(alarm_value, 0, 0x1ff);
+ } else {
alarm_value = (data->c2 - alarm_temp) / data->c1;
+ }
regmap_write(map, soc_data->high_alarm_ctrl + REG_CLR,
soc_data->high_alarm_mask);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support
2026-07-17 6:35 [PATCH v9 0/3] thermal: imx: Add temperature offset support Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 1/3] dt-bindings: thermal: imx: Document temperature offset property Haoning CHENG via B4 Relay
2026-07-17 6:35 ` [PATCH v9 2/3] thermal/drivers/imx: Fix rounding and clamp for i.MX7D alarm Haoning CHENG via B4 Relay
@ 2026-07-17 6:35 ` Haoning CHENG via B4 Relay
2026-07-17 6:45 ` sashiko-bot
2 siblings, 1 reply; 5+ messages in thread
From: Haoning CHENG via B4 Relay @ 2026-07-17 6:35 UTC (permalink / raw)
To: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
Cc: linux-pm, devicetree, imx, linux-arm-kernel, linux-kernel,
Haoning CHENG, Frank Li
From: Haoning CHENG <Haoning.CHENG@cn.bosch.com>
Some boards need a small per-design offset to make the TEMPMON reading
better correspond to the SoC package-surface temperature. This is not a
sensor calibration that improves the die temperature accuracy; it is a
board-specific conversion from the internal sensor reading to a
package-surface temperature estimate required by certain applications.
Read the optional fsl,temp-calibration-offset-millicelsius property from
DT and apply it uniformly to the i.MX6/6SX/7D formulas.
The offset is applied symmetrically at two points to keep the trip point
semantics consistent:
1. In imx_set_alarm_temp() and imx_set_panic_temp(): the temperature
threshold is *subtracted* by the offset before being converted to a
hardware register value. This shifts the hardware IRQ trigger to the
die temperature that corresponds to the intended package-surface
threshold.
2. In imx_get_temp(): after computing the die temperature from the
hardware register, the offset is *added* to produce a value that
better correlates with the package-surface temperature. The thermal
framework always sees this package-surface estimate.
For example, if DT sets offset = +3000 m°C and the passive trip is 95°C:
imx_set_alarm_temp(95000):
alarm_temp = 95000 - 3000 = 92000
→ hardware register programmed for 92°C die temperature
Hardware IRQ fires at 92°C die temperature
imx_get_temp():
reads hardware, computes 92°C die temperature
*temp = 92000 + 3000 = 95000
→ thermal framework sees 95°C → correct trip
When the property is not present, the offset defaults to 0, preserving
the current behavior.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Haoning Cheng <Haoning.CHENG@cn.bosch.com>
---
drivers/thermal/imx_thermal.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 7f7d1116b9d6..d471acc16bce 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -85,6 +85,10 @@ enum imx_thermal_trip {
#define TEMPMON_IMX6SX 2
#define TEMPMON_IMX7D 3
+/* Calibration offset limits (±20 °C in millicelsius) */
+#define IMX_TEMP_CALIB_OFFSET_MIN (-20000)
+#define IMX_TEMP_CALIB_OFFSET_MAX 20000
+
struct thermal_soc_data {
u32 version;
@@ -207,6 +211,7 @@ struct imx_thermal_data {
struct regmap *tempmon;
u32 c1, c2; /* See formula in imx_init_calib() */
int temp_max;
+ s32 calibration_offset;
int alarm_temp;
int last_temp;
bool irq_enabled;
@@ -223,6 +228,7 @@ static void imx_set_panic_temp(struct imx_thermal_data *data,
struct regmap *map = data->tempmon;
int critical_value;
+ panic_temp -= data->calibration_offset;
critical_value = (data->c2 - panic_temp) / data->c1;
regmap_write(map, soc_data->panic_alarm_ctrl + REG_CLR,
@@ -239,6 +245,7 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data,
int alarm_value;
data->alarm_temp = alarm_temp;
+ alarm_temp -= data->calibration_offset;
if (data->socdata->version == TEMPMON_IMX7D) {
if (alarm_temp >= 0)
@@ -283,6 +290,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
*temp = (n_meas - data->c1 + 25) * 1000;
else
*temp = data->c2 - n_meas * data->c1;
+ *temp += data->calibration_offset;
/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
if (data->socdata->version == TEMPMON_IMX6Q) {
@@ -635,6 +643,25 @@ static int imx_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
+ if (of_property_present(dev->of_node,
+ "fsl,temp-calibration-offset-millicelsius")) {
+ ret = of_property_read_s32(dev->of_node,
+ "fsl,temp-calibration-offset-millicelsius",
+ &data->calibration_offset);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read calibration offset\n");
+
+ if (data->calibration_offset < IMX_TEMP_CALIB_OFFSET_MIN ||
+ data->calibration_offset > IMX_TEMP_CALIB_OFFSET_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "calibration offset %d millicelsius out of range\n",
+ data->calibration_offset);
+
+ dev_dbg(dev, "calibration offset: %d millicelsius\n",
+ data->calibration_offset);
+ }
+
if (of_property_present(dev->of_node, "nvmem-cells")) {
ret = imx_init_from_nvmem_cells(pdev);
if (ret)
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support
2026-07-17 6:35 ` [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support Haoning CHENG via B4 Relay
@ 2026-07-17 6:45 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-17 6:45 UTC (permalink / raw)
To: Haoning CHENG; +Cc: conor+dt, robh, devicetree, imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Critical] Temperature calibration offset compromises hardware die protection limits.
Pre-existing issues:
- [High] Use-After-Free of thermal zone device in the alarm IRQ thread during driver removal.
- [High] Race condition between imx_change_mode and the hardirq handler permanently disables the thermal alarm IRQ.
- [High] Missing pm_runtime_put calls in error paths leak runtime PM usage counters.
--
--- Patch [3]: [PATCH v9 3/3] thermal/drivers/imx: Add temperature offset support ---
commit 481f612125b42a851957ea2af55ad414681bb494
Author: Haoning CHENG <Haoning.CHENG@cn.bosch.com>
thermal/drivers/imx: Add temperature offset support
Some boards need a small per-design offset to make the TEMPMON reading
better correspond to the SoC package-surface temperature. This reads the
optional fsl,temp-calibration-offset-millicelsius property from DT and
applies it uniformly to the i.MX6/6SX/7D formulas.
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index 168069a16e930..87ae2e40cc6fe 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
[ ... ]
> @@ -223,6 +228,7 @@ static void imx_set_panic_temp(struct imx_thermal_data *data,
> struct regmap *map = data->tempmon;
> int critical_value;
>
> + panic_temp -= data->calibration_offset;
[Severity: Critical]
Can a negative calibration offset cause the hardware panic limit to exceed
the safe maximum die temperature?
If a negative offset is specified in the device tree for a cooler package,
subtracting it here shifts the hardware panic limit higher. For example,
if the OCOTP die limit is 95C and the offset is -20C, does this program
the hardware to alarm at 115C, which exceeds the safe threshold specified in
the SoC fuses?
[ ... ]
> @@ -283,6 +290,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
> *temp = (n_meas - data->c1 + 25) * 1000;
> else
> *temp = data->c2 - n_meas * data->c1;
> + *temp += data->calibration_offset;
>
> /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
> if (data->socdata->version == TEMPMON_IMX6Q) {
[Severity: High]
This is a pre-existing issue, but does this function leak runtime PM usage
counters on error paths?
Looking at imx_get_temp(), if the sensor data is invalid, it returns
without dropping the reference:
ret = pm_runtime_resume_and_get(data->dev);
if (ret < 0)
return ret;
regmap_read(map, soc_data->temp_data, &val);
if ((val & soc_data->temp_valid_mask) == 0)
return -EAGAIN;
Similarly, in imx_set_trip_temp(), if the requested temperature is out of
bounds, it returns -EINVAL without calling pm_runtime_put(). Do these
paths permanently prevent the device from suspending?
[Severity: High]
This isn't a bug introduced by this patch, but is there a use-after-free
of the thermal zone device during driver removal?
When the driver is removed, thermal_zone_device_unregister() is called
which frees data->tz:
imx_thermal_remove()
...
thermal_zone_device_unregister(data->tz);
However, the devm-managed IRQ is still registered and active until after
remove completes. If the thermal alarm fires in this window, will the IRQ
thread dereference the freed pointer here:
imx_thermal_alarm_irq_thread()
...
thermal_zone_device_update(data->tz, THERMAL_EVENT_UNSPECIFIED);
[Severity: High]
This is a pre-existing issue, but can a race condition permanently disable
the thermal alarm IRQ?
If imx_change_mode() is called to disable the thermal device, it performs
a check-then-act without locking against the hardirq:
imx_change_mode()
...
if (data->irq_enabled) {
disable_irq(data->irq);
data->irq_enabled = false;
}
If the thermal alarm fires concurrently, the hardirq handler will also
disable the IRQ:
imx_thermal_alarm_irq()
...
disable_irq_nosync(irq);
data->irq_enabled = false;
Does this cause the IRQ disable depth to increment to 2, meaning a
subsequent enable_irq() will leave the hardware alarm permanently disabled?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260717-b4-symana21-11221-imx-thermal-support-upstream-6-18-v9-0-75f4af8974f4@cn.bosch.com?part=3
^ permalink raw reply [flat|nested] 5+ messages in thread