* [PATCH 0/2] thermal: loongson2: Add support for Loongson-2K0300 SoC
@ 2026-07-10 8:24 Binbin Zhou
2026-07-10 8:24 ` [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
2026-07-10 8:25 ` [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support " Binbin Zhou
0 siblings, 2 replies; 7+ messages in thread
From: Binbin Zhou @ 2026-07-10 8:24 UTC (permalink / raw)
To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
Binbin Zhou
Hi all:
This patch series adds thermal zone support for the Loongson-2K0300 SoC.
The Loongson-2K0300's thermal sensor is generally compatible with the
existing Loongson-2K series, but it features several key differences:
1. It has an independent CPU ID register for reading chip version
information.
2. The raw temperature output field has been extended from 8 bits to 11
bits.
3. The temperature calculation formula has been updated to incorporate a
correction factor based on the version information.
To ensure robustness on older hardware revisions, a fallback mechanism
is included: if the calculated temperature falls outside the valid range
(-55 TO 125), the driver falls back to a simpler calculation and prints
a warning.
The patches have been validated on the Loongson-2K0300 development board.
Thanks.
Binbin
Binbin Zhou (2):
dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for
Loongson-2K0300
thermal/drivers/loongson2: Add thermal driver support for
Loongson-2K0300
.../thermal/loongson,ls2k-thermal.yaml | 68 +++++++++++----
drivers/thermal/loongson2_thermal.c | 83 +++++++++++++++++--
2 files changed, 127 insertions(+), 24 deletions(-)
base-commit: 795f1b1a91ae13ebc012a364075e42f486a1cafe
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300
2026-07-10 8:24 [PATCH 0/2] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
@ 2026-07-10 8:24 ` Binbin Zhou
2026-07-10 16:21 ` Conor Dooley
2026-07-10 8:25 ` [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support " Binbin Zhou
1 sibling, 1 reply; 7+ messages in thread
From: Binbin Zhou @ 2026-07-10 8:24 UTC (permalink / raw)
To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
Binbin Zhou
Add a new compatible string `loongson,ls2k0300-thermal` for the thermal
sensor found on the Loongson-2K0300 SoC.
The hardware differs from the existing SoCs in its register layout: it
requires two register regions (one for the thermal sensor control and
another for the CPU ID).
Update the binding to describe this new requirement.
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
.../thermal/loongson,ls2k-thermal.yaml | 68 ++++++++++++++-----
1 file changed, 50 insertions(+), 18 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
index 79e691b08341..b5cbfd201105 100644
--- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
@@ -10,13 +10,11 @@ maintainers:
- zhanghongchen <zhanghongchen@loongson.cn>
- Yinbo Zhu <zhuyinbo@loongson.cn>
-allOf:
- - $ref: /schemas/thermal/thermal-sensor.yaml#
-
properties:
compatible:
oneOf:
- enum:
+ - loongson,ls2k0300-thermal
- loongson,ls2k1000-thermal
- loongson,ls2k2000-thermal
- items:
@@ -39,23 +37,46 @@ required:
- reg
- interrupts
-if:
- properties:
- compatible:
- contains:
- enum:
- - loongson,ls2k2000-thermal
+allOf:
+ - $ref: /schemas/thermal/thermal-sensor.yaml#
-then:
- properties:
- reg:
- minItems: 2
- maxItems: 2
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k0300-thermal
+ then:
+ properties:
+ reg:
+ items:
+ - description: Thermal base register region
+ - description: CPU ID register region
-else:
- properties:
- reg:
- maxItems: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k1000-thermal
+ then:
+ properties:
+ reg:
+ items:
+ - description: Thermal base register region
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k2000-thermal
+ then:
+ properties:
+ reg:
+ items:
+ - description: Thermal base register region
+ - description: Thermal data output register region
unevaluatedProperties: false
@@ -69,3 +90,14 @@ examples:
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
+
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ thermal-sensor@16001500 {
+ compatible = "loongson,ls2k0300-thermal";
+ reg = <0x16001500 0x30>,
+ <0x16003ff0 0x8>;
+ interrupt-parent = <&liointc1>;
+ interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ };
--
2.52.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support for Loongson-2K0300
2026-07-10 8:24 [PATCH 0/2] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
2026-07-10 8:24 ` [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
@ 2026-07-10 8:25 ` Binbin Zhou
2026-07-10 8:36 ` sashiko-bot
2026-07-10 14:32 ` Huacai Chen
1 sibling, 2 replies; 7+ messages in thread
From: Binbin Zhou @ 2026-07-10 8:25 UTC (permalink / raw)
To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
Binbin Zhou
The Loongson-2K0300 SoC uses a new thermal sensor that requires reading
a separate CPU ID register to obtain hardware version information. This
version info is used as a correction factor (fix_data) in the
temperature calculation formula.
Its thermal sensor requires the following hardware-specific handling:
- Read chip ID register (offset 0x0 and 0x4) to get the compensation
value (comp_val). The value is stored in either bits [31:20] of the
ID0 register or bits [15:0] of the ID1 register, depending on the
EXTERN_ID bit.
- The compensation value is a signed 15-bit field; extract the value
and apply sign accordingly.
Additionally, some early Loongson-2K0300 chips may have an old fuse that
yields invalid temperature readings outside the -55 to 125 range. In
such cases, the driver falls back to a simplified formula (raw * 569 -
394700) and logs a warning, ensuring the system can still function
without crashing.
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
drivers/thermal/loongson2_thermal.c | 83 ++++++++++++++++++++++++++---
1 file changed, 77 insertions(+), 6 deletions(-)
diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index ea4dd2fb1f47..a7eb87070aa9 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -2,9 +2,11 @@
/*
* Author: zhanghongchen <zhanghongchen@loongson.cn>
* Yinbo Zhu <zhuyinbo@loongson.cn>
- * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
+ * Binbin Zhou <zhoubinbin@loongson.cn>
+ * Copyright (C) 2022-2026 Loongson Technology Corporation Limited
*/
+#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/minmax.h>
@@ -23,27 +25,44 @@
#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8
#define LOONGSON2_THSENS_STATUS_REG 0x10
#define LOONGSON2_THSENS_OUT_REG 0x14
+#define LOONGSON2_THSENS_CFG_REG 0x18
#define LOONGSON2_THSENS_INT_LO BIT(0)
#define LOONGSON2_THSENS_INT_HIGH BIT(1)
#define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \
LOONGSON2_THSENS_INT_HIGH)
#define LOONGSON2_THSENS_OUT_MASK 0xFF
+#define LS2K0300_THSENS_OUT_MASK GENMASK(10, 0)
+
+#define LS2K0300_CHIP_ID1 0x4
+#define LS2K0300_EXTERN_ID BIT(4)
+#define LS2K0300_ID0_VAL_MASK GENMASK(31, 20)
+#define LS2K0300_ID1_VAL_MASK GENMASK(15, 0)
+
+#define LS2K0300_COMP_VAL_MASK GENMASK(14, 0)
+#define LS2K0300_COMP_SIGN_BIT BIT(15)
+
+#define LS2K0300_LOWEST_VALID_TEMP (-55000)
+#define LS2K0300_HIGHEST_VALID_TEMP (125000)
/*
* This flag is used to indicate the temperature reading
* method of the Loongson-2K2000
*/
#define LS2K2000_THSENS_OUT_FLAG BIT(0)
+#define LS2K0300_CHIP_ID_FLAG BIT(1)
struct loongson2_thermal_chip_data {
unsigned int thermal_sensor_sel;
unsigned int flags;
+ const struct thermal_zone_device_ops *thermal_ops;
};
struct loongson2_thermal_data {
+ struct device *dev;
void __iomem *ctrl_reg;
void __iomem *temp_reg;
+ void __iomem *id_reg;
const struct loongson2_thermal_chip_data *chip_data;
};
@@ -71,6 +90,38 @@ static int loongson2_thermal_set(struct loongson2_thermal_data *data,
return 0;
}
+static int loongson2_2k0300_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+ struct loongson2_thermal_data *tdata = thermal_zone_device_priv(tz);
+ int calib_data, calib_offset, temp_mc, raw_adc;
+ u32 chip_id0, chip_id1;
+
+ raw_adc = FIELD_GET(LS2K0300_THSENS_OUT_MASK,
+ readl(tdata->ctrl_reg + LOONGSON2_THSENS_OUT_REG));
+ chip_id0 = readl(tdata->id_reg);
+ chip_id1 = readl(tdata->id_reg + LS2K0300_CHIP_ID1);
+
+ if (chip_id0 & LS2K0300_EXTERN_ID)
+ calib_data = FIELD_GET(LS2K0300_ID1_VAL_MASK, chip_id1);
+ else
+ calib_data = FIELD_GET(LS2K0300_ID0_VAL_MASK, chip_id0);
+
+ calib_offset = FIELD_GET(LS2K0300_COMP_VAL_MASK, calib_data);
+ if (calib_data & LS2K0300_COMP_SIGN_BIT)
+ calib_offset = -calib_offset;
+
+ temp_mc = (raw_adc + calib_offset) * 570 - 394700;
+
+ /* For old fuse which can not read right thermal data */
+ if (temp_mc < LS2K0300_LOWEST_VALID_TEMP || temp_mc > LS2K0300_HIGHEST_VALID_TEMP) {
+ dev_warn_once(tdata->dev, "It's an old fuse, thermal %d is not right\n", temp_mc);
+ temp_mc = raw_adc * 569 - 394700;
+ }
+ *temp = temp_mc;
+
+ return 0;
+}
+
static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
{
int val;
@@ -112,6 +163,11 @@ static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low,
return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
}
+static const struct thermal_zone_device_ops loongson2_2k0300_of_thermal_ops = {
+ .get_temp = loongson2_2k0300_get_temp,
+ .set_trips = loongson2_thermal_set_trips,
+};
+
static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
.get_temp = loongson2_2k1000_get_temp,
.set_trips = loongson2_thermal_set_trips,
@@ -124,7 +180,6 @@ static const struct thermal_zone_device_ops loongson2_2k2000_of_thermal_ops = {
static int loongson2_thermal_probe(struct platform_device *pdev)
{
- const struct thermal_zone_device_ops *thermal_ops;
struct device *dev = &pdev->dev;
struct loongson2_thermal_data *data;
struct thermal_zone_device *tzd;
@@ -134,6 +189,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->dev = dev;
data->chip_data = device_get_match_data(dev);
data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0);
@@ -145,10 +201,13 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
data->temp_reg = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(data->temp_reg))
return PTR_ERR(data->temp_reg);
+ }
- thermal_ops = &loongson2_2k2000_of_thermal_ops;
- } else {
- thermal_ops = &loongson2_2k1000_of_thermal_ops;
+ /* The chip id register is needed for Loongson-2K0300 */
+ if (data->chip_data->flags & LS2K0300_CHIP_ID_FLAG) {
+ data->id_reg = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(data->id_reg))
+ return PTR_ERR(data->id_reg);
}
irq = platform_get_irq(pdev, 0);
@@ -160,7 +219,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
loongson2_thermal_set(data, 0, 0, false);
for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
- tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
+ tzd = devm_thermal_of_zone_register(dev, i, data, data->chip_data->thermal_ops);
if (!IS_ERR(tzd))
break;
@@ -181,17 +240,29 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
return 0;
}
+static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k0300_data = {
+ .thermal_sensor_sel = 0,
+ .flags = LS2K0300_CHIP_ID_FLAG,
+ .thermal_ops = &loongson2_2k0300_of_thermal_ops,
+};
+
static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
.thermal_sensor_sel = 0,
.flags = 0,
+ .thermal_ops = &loongson2_2k1000_of_thermal_ops,
};
static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {
.thermal_sensor_sel = 0,
.flags = LS2K2000_THSENS_OUT_FLAG,
+ .thermal_ops = &loongson2_2k2000_of_thermal_ops,
};
static const struct of_device_id of_loongson2_thermal_match[] = {
+ {
+ .compatible = "loongson,ls2k0300-thermal",
+ .data = &loongson2_thermal_ls2k0300_data,
+ },
{
.compatible = "loongson,ls2k1000-thermal",
.data = &loongson2_thermal_ls2k1000_data,
--
2.52.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support for Loongson-2K0300
2026-07-10 8:25 ` [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support " Binbin Zhou
@ 2026-07-10 8:36 ` sashiko-bot
2026-07-10 14:32 ` Huacai Chen
1 sibling, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-07-10 8:36 UTC (permalink / raw)
To: Binbin Zhou; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Incorrect extraction mask and sign-evaluation for `chip_id0` calibration data breaks negative temperature calibration.
- [High] The loongson2_thermal_set_trips function programs invalid Celsius thresholds into the raw ADC comparator for the LS2K0300 sensor.
- [High] Dynamic 'old fuse' detection dangerously masks legitimate critical thermal events during a real thermal runaway.
Pre-existing issues:
- [High] Inverted error handling in the thermal zone registration loop passes an `ERR_PTR` to subsequent IRQ and sysfs setup.
--
--- Patch [2]: [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support for Loongson-2K0300 ---
commit 95ad3fc965f2e0fee5a82b9e68fbe20931624b5a
Author: Binbin Zhou <zhoubinbin@loongson.cn>
thermal/drivers/loongson2: Add thermal driver support for Loongson-2K0300
This commit adds support for the Loongson-2K0300 thermal sensor, introducing a
new temperature calculation formula based on a hardware version compensation
value read from a chip ID register. It also includes a fallback mechanism
for early chips with invalid fuses.
> diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
> index ea4dd2fb1f473..a7eb87070aa9f 100644
> --- a/drivers/thermal/loongson2_thermal.c
> +++ b/drivers/thermal/loongson2_thermal.c
[ ... ]
> +#define LS2K0300_ID0_VAL_MASK GENMASK(31, 20)
> +#define LS2K0300_ID1_VAL_MASK GENMASK(15, 0)
> +
> +#define LS2K0300_COMP_VAL_MASK GENMASK(14, 0)
> +#define LS2K0300_COMP_SIGN_BIT BIT(15)
[ ... ]
> +static int loongson2_2k0300_get_temp(struct thermal_zone_device *tz, int *temp)
> +{
[ ... ]
> + if (chip_id0 & LS2K0300_EXTERN_ID)
> + calib_data = FIELD_GET(LS2K0300_ID1_VAL_MASK, chip_id1);
> + else
> + calib_data = FIELD_GET(LS2K0300_ID0_VAL_MASK, chip_id0);
> +
> + calib_offset = FIELD_GET(LS2K0300_COMP_VAL_MASK, calib_data);
> + if (calib_data & LS2K0300_COMP_SIGN_BIT)
> + calib_offset = -calib_offset;
[Severity: High]
Is this sign check mathematically possible for chip_id0?
LS2K0300_ID0_VAL_MASK extracts a 12-bit value using GENMASK(31, 20). If
calib_data is populated from chip_id0, checking against BIT(15) will always
evaluate to false. Does this mean negative calibration offsets will never be
applied for this case?
> +
> + temp_mc = (raw_adc + calib_offset) * 570 - 394700;
> +
> + /* For old fuse which can not read right thermal data */
> + if (temp_mc < LS2K0300_LOWEST_VALID_TEMP || temp_mc > LS2K0300_HIGHEST_VALID_TEMP) {
> + dev_warn_once(tdata->dev, "It's an old fuse, thermal %d is not right\n", temp_mc);
> + temp_mc = raw_adc * 569 - 394700;
> + }
[Severity: High]
Could this dynamic bounds check mask a legitimate thermal runaway?
If the system genuinely overheats and exceeds LS2K0300_HIGHEST_VALID_TEMP
(125 C), this check assumes an old fuse and discards the calib_offset. If
that offset was positive, discarding it will suddenly drop the reported
temperature during severe heating. Might this hide the true severity from the
OS and prevent the system from reaching the critical trip points needed for an
emergency shutdown?
> + *temp = temp_mc;
> +
> + return 0;
> +}
[ ... ]
> +static const struct thermal_zone_device_ops loongson2_2k0300_of_thermal_ops = {
> + .get_temp = loongson2_2k0300_get_temp,
> + .set_trips = loongson2_thermal_set_trips,
> +};
[Severity: High]
Does loongson2_thermal_set_trips write invalid threshold data for this new
sensor?
That function adds 100 to the Celsius threshold via loongson2_set_ctrl_regs,
which matches the older LS2K1000 scale. Since the LS2K0300 uses an 11-bit ADC
format and a completely different calculation formula, wouldn't writing
Celsius + 100 into its hardware comparator cause an immediate threshold
mismatch and a potential interrupt storm?
[ ... ]
> @@ -160,7 +219,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> loongson2_thermal_set(data, 0, 0, false);
>
> for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> - tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
> + tzd = devm_thermal_of_zone_register(dev, i, data, data->chip_data->thermal_ops);
>
> if (!IS_ERR(tzd))
> break;
>
> if (PTR_ERR(tzd) != -ENODEV)
> continue;
>
> return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
> }
[Severity: High]
This is a pre-existing issue, but does this error handling logic inadvertently
pass an error pointer on fatal errors?
By continuing the loop when PTR_ERR(tzd) != -ENODEV, critical errors like
-ENOMEM are ignored. If all sensors fail to register, the loop terminates
with tzd holding an error pointer. This pointer is then blindly passed to
devm_request_threaded_irq and devm_thermal_add_hwmon_sysfs right after the
loop, potentially causing a kernel oops when dereferenced.
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support for Loongson-2K0300
2026-07-10 8:25 ` [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support " Binbin Zhou
2026-07-10 8:36 ` sashiko-bot
@ 2026-07-10 14:32 ` Huacai Chen
1 sibling, 0 replies; 7+ messages in thread
From: Huacai Chen @ 2026-07-10 14:32 UTC (permalink / raw)
To: Binbin Zhou
Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba, Xuerui Wang, loongarch, devicetree, linux-pm
Hi, Binbin,
On Fri, Jul 10, 2026 at 4:25 PM Binbin Zhou <zhoubinbin@loongson.cn> wrote:
>
> The Loongson-2K0300 SoC uses a new thermal sensor that requires reading
> a separate CPU ID register to obtain hardware version information. This
> version info is used as a correction factor (fix_data) in the
> temperature calculation formula.
>
> Its thermal sensor requires the following hardware-specific handling:
> - Read chip ID register (offset 0x0 and 0x4) to get the compensation
> value (comp_val). The value is stored in either bits [31:20] of the
> ID0 register or bits [15:0] of the ID1 register, depending on the
> EXTERN_ID bit.
>
> - The compensation value is a signed 15-bit field; extract the value
> and apply sign accordingly.
>
> Additionally, some early Loongson-2K0300 chips may have an old fuse that
> yields invalid temperature readings outside the -55 to 125 range. In
> such cases, the driver falls back to a simplified formula (raw * 569 -
> 394700) and logs a warning, ensuring the system can still function
> without crashing.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
> drivers/thermal/loongson2_thermal.c | 83 ++++++++++++++++++++++++++---
> 1 file changed, 77 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
> index ea4dd2fb1f47..a7eb87070aa9 100644
> --- a/drivers/thermal/loongson2_thermal.c
> +++ b/drivers/thermal/loongson2_thermal.c
> @@ -2,9 +2,11 @@
> /*
> * Author: zhanghongchen <zhanghongchen@loongson.cn>
> * Yinbo Zhu <zhuyinbo@loongson.cn>
> - * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
> + * Binbin Zhou <zhoubinbin@loongson.cn>
> + * Copyright (C) 2022-2026 Loongson Technology Corporation Limited
> */
>
> +#include <linux/bitfield.h>
> #include <linux/interrupt.h>
> #include <linux/io.h>
> #include <linux/minmax.h>
> @@ -23,27 +25,44 @@
> #define LOONGSON2_THSENS_CTRL_LOW_REG 0x8
> #define LOONGSON2_THSENS_STATUS_REG 0x10
> #define LOONGSON2_THSENS_OUT_REG 0x14
> +#define LOONGSON2_THSENS_CFG_REG 0x18
>
> #define LOONGSON2_THSENS_INT_LO BIT(0)
> #define LOONGSON2_THSENS_INT_HIGH BIT(1)
> #define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \
> LOONGSON2_THSENS_INT_HIGH)
> #define LOONGSON2_THSENS_OUT_MASK 0xFF
> +#define LS2K0300_THSENS_OUT_MASK GENMASK(10, 0)
The naming is a little strange, maybe use LOONGSON2_THSENS_OUT_8B_MASK
and LOONGSON2_THSENS_OUT_10B_MASK?
> +
> +#define LS2K0300_CHIP_ID1 0x4
Also define LS2K0300_CHIP_ID0 here?
> +#define LS2K0300_EXTERN_ID BIT(4)
> +#define LS2K0300_ID0_VAL_MASK GENMASK(31, 20)
> +#define LS2K0300_ID1_VAL_MASK GENMASK(15, 0)
> +
> +#define LS2K0300_COMP_VAL_MASK GENMASK(14, 0)
> +#define LS2K0300_COMP_SIGN_BIT BIT(15)
> +
> +#define LS2K0300_LOWEST_VALID_TEMP (-55000)
> +#define LS2K0300_HIGHEST_VALID_TEMP (125000)
>
> /*
> * This flag is used to indicate the temperature reading
> * method of the Loongson-2K2000
> */
> #define LS2K2000_THSENS_OUT_FLAG BIT(0)
> +#define LS2K0300_CHIP_ID_FLAG BIT(1)
>
> struct loongson2_thermal_chip_data {
> unsigned int thermal_sensor_sel;
> unsigned int flags;
> + const struct thermal_zone_device_ops *thermal_ops;
> };
>
> struct loongson2_thermal_data {
> + struct device *dev;
> void __iomem *ctrl_reg;
> void __iomem *temp_reg;
> + void __iomem *id_reg;
> const struct loongson2_thermal_chip_data *chip_data;
> };
>
> @@ -71,6 +90,38 @@ static int loongson2_thermal_set(struct loongson2_thermal_data *data,
> return 0;
> }
>
> +static int loongson2_2k0300_get_temp(struct thermal_zone_device *tz, int *temp)
> +{
> + struct loongson2_thermal_data *tdata = thermal_zone_device_priv(tz);
> + int calib_data, calib_offset, temp_mc, raw_adc;
> + u32 chip_id0, chip_id1;
> +
> + raw_adc = FIELD_GET(LS2K0300_THSENS_OUT_MASK,
> + readl(tdata->ctrl_reg + LOONGSON2_THSENS_OUT_REG));
> + chip_id0 = readl(tdata->id_reg);
> + chip_id1 = readl(tdata->id_reg + LS2K0300_CHIP_ID1);
> +
> + if (chip_id0 & LS2K0300_EXTERN_ID)
> + calib_data = FIELD_GET(LS2K0300_ID1_VAL_MASK, chip_id1);
> + else
> + calib_data = FIELD_GET(LS2K0300_ID0_VAL_MASK, chip_id0);
> +
> + calib_offset = FIELD_GET(LS2K0300_COMP_VAL_MASK, calib_data);
> + if (calib_data & LS2K0300_COMP_SIGN_BIT)
> + calib_offset = -calib_offset;
> +
> + temp_mc = (raw_adc + calib_offset) * 570 - 394700;
> +
> + /* For old fuse which can not read right thermal data */
> + if (temp_mc < LS2K0300_LOWEST_VALID_TEMP || temp_mc > LS2K0300_HIGHEST_VALID_TEMP) {
Is there a better way to detect the old fuse? Because I think temp_mc
between LS2K0300_LOWEST_VALID_TEMP and LS2K0300_HIGHEST_VALID_TEMP is
also not valid for the old fuse.
Huacai
> + dev_warn_once(tdata->dev, "It's an old fuse, thermal %d is not right\n", temp_mc);
> + temp_mc = raw_adc * 569 - 394700;
> + }
> + *temp = temp_mc;
> +
> + return 0;
> +}
> +
> static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
> {
> int val;
> @@ -112,6 +163,11 @@ static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low,
> return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
> }
>
> +static const struct thermal_zone_device_ops loongson2_2k0300_of_thermal_ops = {
> + .get_temp = loongson2_2k0300_get_temp,
> + .set_trips = loongson2_thermal_set_trips,
> +};
> +
> static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
> .get_temp = loongson2_2k1000_get_temp,
> .set_trips = loongson2_thermal_set_trips,
> @@ -124,7 +180,6 @@ static const struct thermal_zone_device_ops loongson2_2k2000_of_thermal_ops = {
>
> static int loongson2_thermal_probe(struct platform_device *pdev)
> {
> - const struct thermal_zone_device_ops *thermal_ops;
> struct device *dev = &pdev->dev;
> struct loongson2_thermal_data *data;
> struct thermal_zone_device *tzd;
> @@ -134,6 +189,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> if (!data)
> return -ENOMEM;
>
> + data->dev = dev;
> data->chip_data = device_get_match_data(dev);
>
> data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0);
> @@ -145,10 +201,13 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> data->temp_reg = devm_platform_ioremap_resource(pdev, 1);
> if (IS_ERR(data->temp_reg))
> return PTR_ERR(data->temp_reg);
> + }
>
> - thermal_ops = &loongson2_2k2000_of_thermal_ops;
> - } else {
> - thermal_ops = &loongson2_2k1000_of_thermal_ops;
> + /* The chip id register is needed for Loongson-2K0300 */
> + if (data->chip_data->flags & LS2K0300_CHIP_ID_FLAG) {
> + data->id_reg = devm_platform_ioremap_resource(pdev, 1);
> + if (IS_ERR(data->id_reg))
> + return PTR_ERR(data->id_reg);
> }
>
> irq = platform_get_irq(pdev, 0);
> @@ -160,7 +219,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> loongson2_thermal_set(data, 0, 0, false);
>
> for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> - tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
> + tzd = devm_thermal_of_zone_register(dev, i, data, data->chip_data->thermal_ops);
>
> if (!IS_ERR(tzd))
> break;
> @@ -181,17 +240,29 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> return 0;
> }
>
> +static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k0300_data = {
> + .thermal_sensor_sel = 0,
> + .flags = LS2K0300_CHIP_ID_FLAG,
> + .thermal_ops = &loongson2_2k0300_of_thermal_ops,
> +};
> +
> static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
> .thermal_sensor_sel = 0,
> .flags = 0,
> + .thermal_ops = &loongson2_2k1000_of_thermal_ops,
> };
>
> static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {
> .thermal_sensor_sel = 0,
> .flags = LS2K2000_THSENS_OUT_FLAG,
> + .thermal_ops = &loongson2_2k2000_of_thermal_ops,
> };
>
> static const struct of_device_id of_loongson2_thermal_match[] = {
> + {
> + .compatible = "loongson,ls2k0300-thermal",
> + .data = &loongson2_thermal_ls2k0300_data,
> + },
> {
> .compatible = "loongson,ls2k1000-thermal",
> .data = &loongson2_thermal_ls2k1000_data,
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300
2026-07-10 8:24 ` [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
@ 2026-07-10 16:21 ` Conor Dooley
2026-07-10 16:24 ` Conor Dooley
0 siblings, 1 reply; 7+ messages in thread
From: Conor Dooley @ 2026-07-10 16:21 UTC (permalink / raw)
To: Binbin Zhou
Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch, devicetree,
linux-pm
[-- Attachment #1: Type: text/plain, Size: 3601 bytes --]
On Fri, Jul 10, 2026 at 04:24:59PM +0800, Binbin Zhou wrote:
> Add a new compatible string `loongson,ls2k0300-thermal` for the thermal
> sensor found on the Loongson-2K0300 SoC.
>
> The hardware differs from the existing SoCs in its register layout: it
> requires two register regions (one for the thermal sensor control and
> another for the CPU ID).
>
> Update the binding to describe this new requirement.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
> .../thermal/loongson,ls2k-thermal.yaml | 68 ++++++++++++++-----
> 1 file changed, 50 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> index 79e691b08341..b5cbfd201105 100644
> --- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> +++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> @@ -10,13 +10,11 @@ maintainers:
> - zhanghongchen <zhanghongchen@loongson.cn>
> - Yinbo Zhu <zhuyinbo@loongson.cn>
>
> -allOf:
> - - $ref: /schemas/thermal/thermal-sensor.yaml#
> -
> properties:
> compatible:
> oneOf:
> - enum:
> + - loongson,ls2k0300-thermal
> - loongson,ls2k1000-thermal
> - loongson,ls2k2000-thermal
> - items:
> @@ -39,23 +37,46 @@ required:
> - reg
> - interrupts
>
> -if:
> - properties:
> - compatible:
> - contains:
> - enum:
> - - loongson,ls2k2000-thermal
> +allOf:
> + - $ref: /schemas/thermal/thermal-sensor.yaml#
>
> -then:
> - properties:
> - reg:
> - minItems: 2
> - maxItems: 2
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - loongson,ls2k0300-thermal
> + then:
> + properties:
> + reg:
> + items:
> + - description: Thermal base register region
> + - description: CPU ID register region
>
> -else:
> - properties:
> - reg:
> - maxItems: 1
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - loongson,ls2k1000-thermal
> + then:
> + properties:
> + reg:
> + items:
> + - description: Thermal base register region
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - loongson,ls2k2000-thermal
> + then:
> + properties:
> + reg:
> + items:
> + - description: Thermal base register region
> + - description: Thermal data output register region
>
> unevaluatedProperties: false
>
> @@ -69,3 +90,14 @@ examples:
> interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
> #thermal-sensor-cells = <1>;
> };
> +
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + thermal-sensor@16001500 {
> + compatible = "loongson,ls2k0300-thermal";
> + reg = <0x16001500 0x30>,
> + <0x16003ff0 0x8>;
Quite frankly, the address and size of this look like the second
register region here is actually a few bytes in a syscon that is being
misrepresented.
What lies at the addresses immediately before and after 0x16003ff0?
Thanks,
Conor.
> + interrupt-parent = <&liointc1>;
> + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
> + #thermal-sensor-cells = <1>;
> + };
> --
> 2.52.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300
2026-07-10 16:21 ` Conor Dooley
@ 2026-07-10 16:24 ` Conor Dooley
0 siblings, 0 replies; 7+ messages in thread
From: Conor Dooley @ 2026-07-10 16:24 UTC (permalink / raw)
To: Binbin Zhou
Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch, devicetree,
linux-pm
[-- Attachment #1: Type: text/plain, Size: 4068 bytes --]
On Fri, Jul 10, 2026 at 05:21:22PM +0100, Conor Dooley wrote:
> On Fri, Jul 10, 2026 at 04:24:59PM +0800, Binbin Zhou wrote:
> > Add a new compatible string `loongson,ls2k0300-thermal` for the thermal
> > sensor found on the Loongson-2K0300 SoC.
> >
> > The hardware differs from the existing SoCs in its register layout: it
> > requires two register regions (one for the thermal sensor control and
> > another for the CPU ID).
> >
> > Update the binding to describe this new requirement.
> >
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> > .../thermal/loongson,ls2k-thermal.yaml | 68 ++++++++++++++-----
> > 1 file changed, 50 insertions(+), 18 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> > index 79e691b08341..b5cbfd201105 100644
> > --- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> > +++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> > @@ -10,13 +10,11 @@ maintainers:
> > - zhanghongchen <zhanghongchen@loongson.cn>
> > - Yinbo Zhu <zhuyinbo@loongson.cn>
> >
> > -allOf:
> > - - $ref: /schemas/thermal/thermal-sensor.yaml#
> > -
> > properties:
> > compatible:
> > oneOf:
> > - enum:
> > + - loongson,ls2k0300-thermal
> > - loongson,ls2k1000-thermal
> > - loongson,ls2k2000-thermal
> > - items:
> > @@ -39,23 +37,46 @@ required:
> > - reg
> > - interrupts
> >
> > -if:
> > - properties:
> > - compatible:
> > - contains:
> > - enum:
> > - - loongson,ls2k2000-thermal
> > +allOf:
> > + - $ref: /schemas/thermal/thermal-sensor.yaml#
> >
> > -then:
> > - properties:
> > - reg:
> > - minItems: 2
> > - maxItems: 2
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - loongson,ls2k0300-thermal
> > + then:
> > + properties:
> > + reg:
> > + items:
> > + - description: Thermal base register region
> > + - description: CPU ID register region
> >
> > -else:
> > - properties:
> > - reg:
> > - maxItems: 1
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - loongson,ls2k1000-thermal
> > + then:
> > + properties:
> > + reg:
> > + items:
> > + - description: Thermal base register region
> > +
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - loongson,ls2k2000-thermal
> > + then:
> > + properties:
> > + reg:
> > + items:
> > + - description: Thermal base register region
> > + - description: Thermal data output register region
> >
> > unevaluatedProperties: false
> >
> > @@ -69,3 +90,14 @@ examples:
> > interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
> > #thermal-sensor-cells = <1>;
> > };
> > +
> > + - |
> > + #include <dt-bindings/interrupt-controller/irq.h>
> > + thermal-sensor@16001500 {
> > + compatible = "loongson,ls2k0300-thermal";
> > + reg = <0x16001500 0x30>,
> > + <0x16003ff0 0x8>;
>
> Quite frankly, the address and size of this look like the second
> register region here is actually a few bytes in a syscon that is being
> misrepresented.
> What lies at the addresses immediately before and after 0x16003ff0?
Hmm, I just realised that the new device is the 0300, making this second
reg property the "cpuid" region. That makes this doubly suspect looking.
>
>
> Thanks,
> Conor.
>
> > + interrupt-parent = <&liointc1>;
> > + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
> > + #thermal-sensor-cells = <1>;
> > + };
> > --
> > 2.52.0
> >
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-10 16:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 8:24 [PATCH 0/2] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
2026-07-10 8:24 ` [PATCH 1/2] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
2026-07-10 16:21 ` Conor Dooley
2026-07-10 16:24 ` Conor Dooley
2026-07-10 8:25 ` [PATCH 2/2] thermal/drivers/loongson2: Add thermal driver support " Binbin Zhou
2026-07-10 8:36 ` sashiko-bot
2026-07-10 14:32 ` Huacai Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox