* [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
* 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 2026-07-14 6:53 ` Binbin Zhou 0 siblings, 2 replies; 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 2026-07-14 6:53 ` Binbin Zhou 1 sibling, 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
* 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 @ 2026-07-14 6:53 ` Binbin Zhou 1 sibling, 0 replies; 7+ messages in thread From: Binbin Zhou @ 2026-07-14 6:53 UTC (permalink / raw) To: Conor Dooley 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 Hi Conor: Thanks for your reply. On Sat, Jul 11, 2026 at 12:21 AM Conor Dooley <conor@kernel.org> 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? Yes, it can be viewed as part of the system configuration registers, which appear somewhat disorganized. Within this section, 0x16003fe0–0x16003ffc represents eight chip ID registers. 0x16003fe0 --> the 4th chip id 0x16003fe4 --> the 5th chip id 0x16003fe8 --> the 6th chip id 0x16003fec --> the 7th chip id 0x16003ff0 --> the 0th chip id 0x16003ff4 --> the 1st chip id 0x16003ff8 --> the 2nd chip id 0x16003ffc --> the 3rd chip id Perhaps I shouldn’t have referenced `0x16003ff0` separately here. It would be more reasonable to declare the entire chip ID address space as a separate syscon and have it referenced by thermal driver. For example: In DTS{i}: chipid_syscon: syscon@16003fe0 { compatible = “loongson,ls2k0300-cphipid-syscon”, “syscon”; reg = <0x0 0x16003fe0 0x0 0x20>; }; In thermal driver: Use `syscon_regmap_lookup_by_phandle(np, "loongson,chipid"); ` Or: `syscon_regmap_lookup_by_compatible("loongson,ls2k0300-cphipid-syscon");` get the chip id address space. > > > Thanks, > Conor. > > > + interrupt-parent = <&liointc1>; > > + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; > > + #thermal-sensor-cells = <1>; > > + }; > > -- > > 2.52.0 > > -- Thanks. Binbin ^ permalink raw reply [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 14:32 ` Huacai Chen 1 sibling, 1 reply; 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 14:32 ` Huacai Chen 0 siblings, 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
end of thread, other threads:[~2026-07-14 6:53 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-14 6:53 ` Binbin Zhou 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