* [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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ 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 14:32 ` Huacai Chen 1 sibling, 1 reply; 6+ 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] 6+ 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 14:32 ` Huacai Chen 0 siblings, 0 replies; 6+ 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] 6+ messages in thread
end of thread, other threads:[~2026-07-10 16:24 UTC | newest] Thread overview: 6+ 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 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