* [PATCH v6 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1
2025-09-30 0:51 ` [PATCH v6 0/3] Add exynosautov920 thermal support Shin Son
@ 2025-09-30 0:51 ` Shin Son
2025-10-10 12:43 ` Krzysztof Kozlowski
2025-09-30 0:51 ` [PATCH v6 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son
2025-09-30 0:51 ` [PATCH v6 3/3] arm64: dts: exynosautov920: Add multiple sensors Shin Son
2 siblings, 1 reply; 8+ messages in thread
From: Shin Son @ 2025-09-30 0:51 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski,
Rafael J . Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Conor Dooley, Alim Akhtar, Henrik Grimler
Cc: Shin Son, linux-pm, linux-samsung-soc, devicetree,
linux-arm-kernel, linux-kernel
The ExynosAuto v920 SoC includes multiple TMU instances; each instance
monitors a subset of the SoC's up to 16 hardware thermal sensors.
Additionally, add myself to the bindings' maintainers list, as I plan
to actively work on the exynosautov920 TMU support and handle further
updates in this area.
Signed-off-by: Shin Son <shin.son@samsung.com>
---
.../thermal/samsung,exynos-thermal.yaml | 32 ++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml b/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml
index 29a08b0729ee..f9b399a7b82f 100644
--- a/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml
@@ -8,6 +8,7 @@ title: Samsung Exynos SoC Thermal Management Unit (TMU)
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
+ - Shin Son <shin.son@samsung.com>
description: |
For multi-instance tmu each instance should have an alias correctly numbered
@@ -27,6 +28,7 @@ properties:
- samsung,exynos5420-tmu-ext-triminfo
- samsung,exynos5433-tmu
- samsung,exynos7-tmu
+ - samsung,exynosautov920-tmu
clocks:
minItems: 1
@@ -62,11 +64,17 @@ properties:
minItems: 1
'#thermal-sensor-cells':
- const: 0
+ enum: [0, 1]
vtmu-supply:
description: The regulator node supplying voltage to TMU.
+ samsung,sensors:
+ description: Number of thermal sensors monitored by this TMU instance.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+
required:
- compatible
- clocks
@@ -97,6 +105,8 @@ allOf:
reg:
minItems: 2
maxItems: 2
+ '#thermal-sensor-cells':
+ const: 0
- if:
properties:
compatible:
@@ -119,6 +129,8 @@ allOf:
reg:
minItems: 1
maxItems: 1
+ '#thermal-sensor-cells':
+ const: 0
- if:
properties:
@@ -139,6 +151,24 @@ allOf:
reg:
minItems: 1
maxItems: 1
+ '#thermal-sensor-cells':
+ const: 0
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: samsung,exynosautov920-tmu
+ then:
+ properties:
+ clocks:
+ minItems: 1
+ maxItems: 1
+ reg:
+ minItems: 1
+ maxItems: 1
+ '#thermal-sensor-cells':
+ const: 1
additionalProperties: false
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v6 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface
2025-09-30 0:51 ` [PATCH v6 0/3] Add exynosautov920 thermal support Shin Son
2025-09-30 0:51 ` [PATCH v6 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son
@ 2025-09-30 0:51 ` Shin Son
2025-09-30 0:51 ` [PATCH v6 3/3] arm64: dts: exynosautov920: Add multiple sensors Shin Son
2 siblings, 0 replies; 8+ messages in thread
From: Shin Son @ 2025-09-30 0:51 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski,
Rafael J . Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Conor Dooley, Alim Akhtar, Henrik Grimler
Cc: Shin Son, linux-pm, linux-samsung-soc, devicetree,
linux-arm-kernel, linux-kernel
The Exynos tmu driver's private data structure has been extended
to support the exynosautov920 hardware, which requires per-sensor interrupt
enablement and multiple-zone handling:
- Add 'slope_comp' : compensation parameter below 25 degrees.
- Add 'calib_temp' : stores the fused calibaration temperature.
- Add 'sensor_count' : reflects the maximum sensor numbers.
- Rename 'tzd' -> 'tzd_array' to register multiple thermal zones.
Since splitting this patch causes runtime errors during temperature
emulation or problems where the read temperature feature fails to
retrieve values, I have submitted it as a single commit. To add support
for the exynosautov920 to the exisiting TMU interface, the following
changes are included:
1. Simplify "temp_to_code" and "code_to_temp" to one computation path
by normalizing calib_temp.
2. Loop over 'sensor_count' in critical-point setup.
3. Introduce 'update_con_reg' for exynosautov920 control-register updates.
4. Add exynosautov920-specific branch in 'exynos_tmu_update_temp' function.
5. Skip high & low temperature threshold setup in exynosautov920.
6. Enable interrupts via sensor_count in exynosautov920.
7. Initialize all new members during 'exynosautov920_tmu_initialize'.
8. Clear IRQs by iterating the sensor_count in exynosautov920.
9. Register each zone with 'devm_thermal_of_zone_register()'
based on 'sensor_count'.
Reviewed-by: Henrik Grimler <henrik@grimler.se>
Signed-off-by: Shin Son <shin.son@samsung.com>
---
drivers/thermal/samsung/exynos_tmu.c | 322 ++++++++++++++++++++++++---
1 file changed, 285 insertions(+), 37 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 47a99b3c5395..8fa188928b79 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -121,8 +121,51 @@
#define EXYNOS_NOISE_CANCEL_MODE 4
+/* ExynosAutov920 specific registers */
+#define EXYNOSAUTOV920_SLOPE_COMP 25
+#define EXYNOSAUTOV920_SLOPE_COMP_MASK 0xf
+#define EXYNOSAUTOV920_CALIB_SEL_TEMP 30
+#define EXYNOSAUTOV920_CALIB_SEL_TEMP_MASK 0x2
+
+#define EXYNOSAUTOV920_SENSOR0_TRIM_INFO 0x10
+#define EXYNOSAUTOV920_TRIM_MASK 0x1ff
+#define EXYNOSAUTOV920_TRIMINFO_25_SHIFT 0
+#define EXYNOSAUTOV920_TRIMINFO_85_SHIFT 9
+
+#define EXYNOSAUTOV920_TMU_REG_TRIMINFO2 0x04
+
+#define EXYNOSAUTOV920_TMU_REG_THRESHOLD(p) (((p)) * 0x50 + 0x00d0)
+#define EXYNOSAUTOV920_TMU_REG_INTEN(p) (((p)) * 0x50 + 0x00f0)
+#define EXYNOSAUTOV920_TMU_REG_INT_PEND(p) (((p)) * 0x50 + 0x00f8)
+
+#define EXYNOSAUTOV920_CURRENT_TEMP_P1_P0 0x084
+#define EXYNOSAUTOV920_TMU_REG_EMUL_CON 0x0b0
+
+#define EXYNOSAUTOV920_TMU_REG_CONTROL 0x50
+#define EXYNOSAUTOV920_TMU_REG_CONTROL1 0x54
+#define EXYNOSAUTOV920_TMU_REG_AVG_CONTROL 0x58
+#define EXYNOSAUTOV920_TMU_SAMPLING_INTERVAL 0x70
+#define EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE0 0x74
+#define EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE1 0x78
+
+#define EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_SHIFT 8
+#define EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_MASK 0x1f
+#define EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_SHIFT 3
+#define EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_MASK 0xf
+#define EXYNOSAUTOV920_TMU_NUM_PROBE_MASK 0xf
+#define EXYNOSAUTOV920_TMU_NUM_PROBE_SHIFT 16
+#define EXYNOSAUTOV920_TMU_LPI_MODE_MASK 1
+#define EXYNOSAUTOV920_TMU_LPI_MODE_SHIFT 10
+
+#define EXYNOSAUTOV920_TMU_AVG_CON_UPDATE 0x0008011a
+#define EXYNOSAUTOV920_TMU_COUNTER_VALUE0_UPDATE 0x030003c0
+#define EXYNOSAUTOV920_TMU_COUNTER_VALUE1_UPDATE 0x03c0004d
+
#define MCELSIUS 1000
+#define EXYNOS_DEFAULT_SENSOR_COUNT 1
+#define EXYNOS_MAX_SENSOR_COUNT 15
+
enum soc_type {
SOC_ARCH_EXYNOS3250 = 1,
SOC_ARCH_EXYNOS4210,
@@ -133,6 +176,7 @@ enum soc_type {
SOC_ARCH_EXYNOS5420_TRIMINFO,
SOC_ARCH_EXYNOS5433,
SOC_ARCH_EXYNOS7,
+ SOC_ARCH_EXYNOSAUTOV920,
};
/**
@@ -150,6 +194,8 @@ enum soc_type {
* @efuse_value: SoC defined fuse value
* @min_efuse_value: minimum valid trimming data
* @max_efuse_value: maximum valid trimming data
+ * @slope_comp: allocated value of the slope compensation.
+ * @calib_temp: calibration temperature of the TMU.
* @temp_error1: fused value of the first point trim.
* @temp_error2: fused value of the second point trim.
* @gain: gain of amplifier in the positive-TC generator block
@@ -157,7 +203,8 @@ enum soc_type {
* @reference_voltage: reference voltage of amplifier
* in the positive-TC generator block
* 0 < reference_voltage <= 31
- * @tzd: pointer to thermal_zone_device structure
+ * @sensor_count: The maximum number of the sensors
+ * @tzd_array: pointer array of thermal_zone_device structure
* @enabled: current status of TMU device
* @tmu_set_low_temp: SoC specific method to set trip (falling threshold)
* @tmu_set_high_temp: SoC specific method to set trip (rising threshold)
@@ -174,6 +221,7 @@ struct exynos_tmu_data {
void __iomem *base;
void __iomem *base_second;
int irq;
+ int sensor_count;
enum soc_type soc;
struct mutex lock;
struct clk *clk, *clk_sec, *sclk;
@@ -181,10 +229,12 @@ struct exynos_tmu_data {
u32 efuse_value;
u32 min_efuse_value;
u32 max_efuse_value;
+ u16 slope_comp;
+ u16 calib_temp;
u16 temp_error1, temp_error2;
u8 gain;
u8 reference_voltage;
- struct thermal_zone_device *tzd;
+ struct thermal_zone_device *tzd_array[EXYNOS_MAX_SENSOR_COUNT];
bool enabled;
void (*tmu_set_low_temp)(struct exynos_tmu_data *data, u8 temp);
@@ -205,13 +255,20 @@ struct exynos_tmu_data {
*/
static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
{
+ s32 temp_diff, code;
+
if (data->cal_type == TYPE_ONE_POINT_TRIMMING)
return temp + data->temp_error1 - EXYNOS_FIRST_POINT_TRIM;
- return (temp - EXYNOS_FIRST_POINT_TRIM) *
- (data->temp_error2 - data->temp_error1) /
- (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) +
- data->temp_error1;
+ temp_diff = temp - EXYNOS_FIRST_POINT_TRIM;
+
+ code = temp_diff * (data->temp_error2 - data->temp_error1) * MCELSIUS /
+ (data->calib_temp - EXYNOS_FIRST_POINT_TRIM);
+
+ if (data->soc == SOC_ARCH_EXYNOSAUTOV920 && temp_diff < 0)
+ code = code * (57 + data->slope_comp) / 65;
+
+ return code / MCELSIUS + data->temp_error1;
}
/*
@@ -220,13 +277,20 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
*/
static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
{
+ s32 code_diff, temp;
+
if (data->cal_type == TYPE_ONE_POINT_TRIMMING)
return temp_code - data->temp_error1 + EXYNOS_FIRST_POINT_TRIM;
- return (temp_code - data->temp_error1) *
- (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) /
- (data->temp_error2 - data->temp_error1) +
- EXYNOS_FIRST_POINT_TRIM;
+ code_diff = temp_code - data->temp_error1;
+
+ temp = code_diff * (data->calib_temp - EXYNOS_FIRST_POINT_TRIM) * MCELSIUS /
+ (data->temp_error2 - data->temp_error1);
+
+ if (data->soc == SOC_ARCH_EXYNOSAUTOV920 && code_diff < 0)
+ temp = temp * 65 / (57 + data->slope_comp);
+
+ return temp / MCELSIUS + EXYNOS_FIRST_POINT_TRIM;
}
static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
@@ -262,6 +326,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
clk_enable(data->clk_sec);
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
+ if (data->soc == SOC_ARCH_EXYNOSAUTOV920)
+ status = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+
if (!status) {
ret = -EBUSY;
} else {
@@ -280,27 +347,34 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
static int exynos_thermal_zone_configure(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
- struct thermal_zone_device *tzd = data->tzd;
- int ret, temp;
+ struct thermal_zone_device *tzd;
+ int ret, temp, idx;
- ret = thermal_zone_get_crit_temp(tzd, &temp);
- if (ret) {
- /* FIXME: Remove this special case */
- if (data->soc == SOC_ARCH_EXYNOS5433)
- return 0;
+ for (idx = 0; idx < data->sensor_count; idx++) {
+ tzd = data->tzd_array[idx];
- dev_err(&pdev->dev,
- "No CRITICAL trip point defined in device tree!\n");
- return ret;
- }
+ if (!tzd)
+ continue;
- mutex_lock(&data->lock);
- clk_enable(data->clk);
+ ret = thermal_zone_get_crit_temp(tzd, &temp);
+ if (ret) {
+ /* FIXME: Remove this special case */
+ if (data->soc == SOC_ARCH_EXYNOS5433)
+ return 0;
- data->tmu_set_crit_temp(data, temp / MCELSIUS);
+ dev_err(&pdev->dev,
+ "No CRITICAL trip point defined in device tree!\n");
+ return ret;
+ }
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ data->tmu_set_crit_temp(data, temp / MCELSIUS);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+ }
return 0;
}
@@ -323,6 +397,37 @@ static u32 get_con_reg(struct exynos_tmu_data *data, u32 con)
return con;
}
+static void update_con_reg(struct exynos_tmu_data *data)
+{
+ u32 val, t_buf_vref_sel, t_buf_slope_sel;
+
+ val = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+ t_buf_vref_sel = (val >> EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_SHIFT)
+ & EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_MASK;
+ t_buf_slope_sel = (val >> EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_SHIFT)
+ & EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_MASK;
+
+ val = readl(data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
+ val &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK << EXYNOS_TMU_REF_VOLTAGE_SHIFT);
+ val |= (t_buf_vref_sel << EXYNOS_TMU_REF_VOLTAGE_SHIFT);
+ val &= ~(EXYNOS_TMU_BUF_SLOPE_SEL_MASK << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
+ val |= (t_buf_slope_sel << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
+ writel(val, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
+
+ val = readl(data->base + EXYNOSAUTOV920_TMU_REG_CONTROL1);
+ val &= ~(EXYNOSAUTOV920_TMU_NUM_PROBE_MASK << EXYNOSAUTOV920_TMU_NUM_PROBE_SHIFT);
+ val &= ~(EXYNOSAUTOV920_TMU_LPI_MODE_MASK << EXYNOSAUTOV920_TMU_LPI_MODE_SHIFT);
+ val |= (data->sensor_count << EXYNOSAUTOV920_TMU_NUM_PROBE_SHIFT);
+ writel(val, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL1);
+
+ writel(1, data->base + EXYNOSAUTOV920_TMU_SAMPLING_INTERVAL);
+ writel(EXYNOSAUTOV920_TMU_AVG_CON_UPDATE, data->base + EXYNOSAUTOV920_TMU_REG_AVG_CONTROL);
+ writel(EXYNOSAUTOV920_TMU_COUNTER_VALUE0_UPDATE,
+ data->base + EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE0);
+ writel(EXYNOSAUTOV920_TMU_COUNTER_VALUE1_UPDATE,
+ data->base + EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE1);
+}
+
static void exynos_tmu_control(struct platform_device *pdev, bool on)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
@@ -354,9 +459,8 @@ static void exynos_tmu_update_temp(struct exynos_tmu_data *data, int reg_off,
u16 tmu_temp_mask;
u32 th;
- tmu_temp_mask =
- (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK
- : EXYNOS_TMU_TEMP_MASK;
+ tmu_temp_mask = (data->soc == SOC_ARCH_EXYNOS7 || data->soc == SOC_ARCH_EXYNOSAUTOV920)
+ ? EXYNOS7_TMU_TEMP_MASK : EXYNOS_TMU_TEMP_MASK;
th = readl(data->base + reg_off);
th &= ~(tmu_temp_mask << bit_off);
@@ -582,6 +686,68 @@ static void exynos7_tmu_initialize(struct platform_device *pdev)
sanitize_temp_error(data, trim_info);
}
+static void exynosautov920_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
+{
+ /*
+ * Failing thresholds are not supported on Exynosautov920.
+ * We use polling instead.
+ */
+}
+
+static void exynosautov920_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
+{
+ /*
+ * Rising thresholds are not supported on Exynosautov920.
+ * We use polling instead.
+ */
+}
+
+static void exynosautov920_tmu_disable_low(struct exynos_tmu_data *data)
+{
+ /* Again, this is handled by polling. */
+}
+
+static void exynosautov920_tmu_disable_high(struct exynos_tmu_data *data)
+{
+ /* Again, this is handled by polling. */
+}
+
+static void exynosautov920_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < data->sensor_count; idx++) {
+ if (!data->tzd_array[idx])
+ continue;
+
+ exynos_tmu_update_temp(data, EXYNOSAUTOV920_TMU_REG_THRESHOLD(idx), 16, temp);
+ exynos_tmu_update_bit(data, EXYNOSAUTOV920_TMU_REG_INTEN(idx), 7, true);
+ }
+}
+
+static void exynosautov920_tmu_initialize(struct platform_device *pdev)
+{
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ unsigned int val;
+
+ data->tmu_control(pdev, false);
+
+ update_con_reg(data);
+
+ val = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+ data->cal_type = TYPE_TWO_POINT_TRIMMING;
+ data->slope_comp = (val >> EXYNOSAUTOV920_SLOPE_COMP) & EXYNOSAUTOV920_SLOPE_COMP_MASK;
+
+ val = readl(data->base + EXYNOSAUTOV920_SENSOR0_TRIM_INFO);
+ data->temp_error1 = (val >> EXYNOSAUTOV920_TRIMINFO_25_SHIFT) & EXYNOSAUTOV920_TRIM_MASK;
+ data->temp_error2 = (val >> EXYNOSAUTOV920_TRIMINFO_85_SHIFT) & EXYNOSAUTOV920_TRIM_MASK;
+
+ val = readl(data->base + EXYNOSAUTOV920_TMU_REG_TRIMINFO2);
+ val = (val >> EXYNOSAUTOV920_CALIB_SEL_TEMP) & EXYNOSAUTOV920_CALIB_SEL_TEMP_MASK;
+
+ data->calib_temp = (EXYNOS_SECOND_POINT_TRIM + (20 * val));
+}
+
static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
@@ -633,6 +799,24 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
}
+static void exynosautov920_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ unsigned int con;
+
+ con = readl(data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
+
+ if (on) {
+ con |= BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+ con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
+ } else {
+ con &= ~BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+ con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
+ }
+
+ writel(con, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
+}
+
static int exynos_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct exynos_tmu_data *data = thermal_zone_device_priv(tz);
@@ -671,7 +855,7 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT);
val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT);
- if (data->soc == SOC_ARCH_EXYNOS7) {
+ if (data->soc == SOC_ARCH_EXYNOS7 || data->soc == SOC_ARCH_EXYNOSAUTOV920) {
val &= ~(EXYNOS7_EMUL_DATA_MASK <<
EXYNOS7_EMUL_DATA_SHIFT);
val |= (temp_to_code(data, temp) <<
@@ -703,6 +887,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
emul_con = EXYNOS5433_TMU_EMUL_CON;
else if (data->soc == SOC_ARCH_EXYNOS7)
emul_con = EXYNOS7_TMU_REG_EMUL_CON;
+ else if (data->soc == SOC_ARCH_EXYNOSAUTOV920)
+ emul_con = EXYNOSAUTOV920_TMU_REG_EMUL_CON;
else
emul_con = EXYNOS_EMUL_CON;
@@ -756,11 +942,23 @@ static int exynos7_tmu_read(struct exynos_tmu_data *data)
EXYNOS7_TMU_TEMP_MASK;
}
+static int exynosautov920_tmu_read(struct exynos_tmu_data *data)
+{
+ return readw(data->base + EXYNOSAUTOV920_CURRENT_TEMP_P1_P0) &
+ EXYNOS7_TMU_TEMP_MASK;
+}
+
static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id)
{
struct exynos_tmu_data *data = id;
+ int idx;
- thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED);
+ for (idx = 0; idx < data->sensor_count; idx++) {
+ if (!data->tzd_array[idx])
+ continue;
+
+ thermal_zone_device_update(data->tzd_array[idx], THERMAL_EVENT_UNSPECIFIED);
+ }
mutex_lock(&data->lock);
clk_enable(data->clk);
@@ -805,6 +1003,19 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
writel(val_irq, data->base + tmu_intclear);
}
+static void exynosautov920_tmu_clear_irqs(struct exynos_tmu_data *data)
+{
+ unsigned int idx, val_irq;
+
+ for (idx = 0; idx < data->sensor_count; idx++) {
+ if (!data->tzd_array[idx])
+ continue;
+
+ val_irq = readl(data->base + EXYNOSAUTOV920_TMU_REG_INT_PEND(idx));
+ writel(val_irq, data->base + EXYNOSAUTOV920_TMU_REG_INT_PEND(idx));
+ }
+}
+
static const struct of_device_id exynos_tmu_match[] = {
{
.compatible = "samsung,exynos3250-tmu",
@@ -833,6 +1044,9 @@ static const struct of_device_id exynos_tmu_match[] = {
}, {
.compatible = "samsung,exynos7-tmu",
.data = (const void *)SOC_ARCH_EXYNOS7,
+ }, {
+ .compatible = "samsung,exynosautov920-tmu",
+ .data = (const void *)SOC_ARCH_EXYNOSAUTOV920,
},
{ },
};
@@ -865,6 +1079,10 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data->soc = (uintptr_t)of_device_get_match_data(&pdev->dev);
+ data->sensor_count = EXYNOS_DEFAULT_SENSOR_COUNT;
+
+ data->calib_temp = EXYNOS_SECOND_POINT_TRIM;
+
switch (data->soc) {
case SOC_ARCH_EXYNOS4210:
data->tmu_set_low_temp = exynos4210_tmu_set_low_temp;
@@ -945,6 +1163,19 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data->min_efuse_value = 15;
data->max_efuse_value = 100;
break;
+ case SOC_ARCH_EXYNOSAUTOV920:
+ data->tmu_set_low_temp = exynosautov920_tmu_set_low_temp;
+ data->tmu_set_high_temp = exynosautov920_tmu_set_high_temp;
+ data->tmu_disable_low = exynosautov920_tmu_disable_low;
+ data->tmu_disable_high = exynosautov920_tmu_disable_high;
+ data->tmu_set_crit_temp = exynosautov920_tmu_set_crit_temp;
+ data->tmu_initialize = exynosautov920_tmu_initialize;
+ data->tmu_control = exynosautov920_tmu_control;
+ data->tmu_read = exynosautov920_tmu_read;
+ data->tmu_set_emulation = exynos4412_tmu_set_emulation;
+ data->tmu_clear_irqs = exynosautov920_tmu_clear_irqs;
+ data->sensor_count = EXYNOS_MAX_SENSOR_COUNT;
+ break;
default:
dev_err(&pdev->dev, "Platform not supported\n");
return -EINVAL;
@@ -952,6 +1183,14 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data->cal_type = TYPE_ONE_POINT_TRIMMING;
+ if (data->soc == SOC_ARCH_EXYNOSAUTOV920) {
+ if (of_property_read_u32(pdev->dev.of_node, "samsung,sensors",
+ &data->sensor_count)) {
+ dev_err(&pdev->dev, "failed to get sensor count\n");
+ return -ENODEV;
+ }
+ }
+
/*
* Check if the TMU shares some registers and then try to map the
* memory of common registers.
@@ -1006,7 +1245,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct exynos_tmu_data *data;
- int ret;
+ struct thermal_zone_device *tzd;
+ int ret, idx;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1084,11 +1324,19 @@ static int exynos_tmu_probe(struct platform_device *pdev)
goto err_sclk;
}
- data->tzd = devm_thermal_of_zone_register(dev, 0, data,
- &exynos_sensor_ops);
- if (IS_ERR(data->tzd)) {
- ret = dev_err_probe(dev, PTR_ERR(data->tzd), "Failed to register sensor\n");
- goto err_sclk;
+ for (idx = 0; idx < data->sensor_count; idx++) {
+ tzd = devm_thermal_of_zone_register(dev, idx, data, &exynos_sensor_ops);
+
+ if (IS_ERR(tzd)) {
+ if (PTR_ERR(tzd) == -ENODEV)
+ continue;
+
+ ret = dev_err_probe(dev, PTR_ERR(data->tzd_array[idx]),
+ "Failed to register sensor\n");
+ goto err_sclk;
+ }
+
+ data->tzd_array[idx] = tzd;
}
ret = exynos_thermal_zone_configure(pdev);
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v6 3/3] arm64: dts: exynosautov920: Add multiple sensors
2025-09-30 0:51 ` [PATCH v6 0/3] Add exynosautov920 thermal support Shin Son
2025-09-30 0:51 ` [PATCH v6 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son
2025-09-30 0:51 ` [PATCH v6 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son
@ 2025-09-30 0:51 ` Shin Son
2025-10-10 12:45 ` Krzysztof Kozlowski
2 siblings, 1 reply; 8+ messages in thread
From: Shin Son @ 2025-09-30 0:51 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski,
Rafael J . Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Rob Herring, Conor Dooley, Alim Akhtar, Henrik Grimler
Cc: Shin Son, linux-pm, linux-samsung-soc, devicetree,
linux-arm-kernel, linux-kernel
Create a new exynosautov920-tmu.dtsi describing new TMU hardware
and include it from exynosautov920.dtsi.
The exynosautov920-tmu node uses the misc clock as its source.
This TMU binding defines multiple thermal zones with a critical trip point
at 125 degrees:
tmu_top : cpus0-0, cpus0-1, cpus0-2, cpus0-3,
cpus1-0, cpus1-1, cpus1-2, cpus1-3,
cpus1-4, cpus1-5, cpus1-6, cpus1-7
tmu_sub0: cpus0-4, cpus0-5, cpus0-6, cpus0-7,
cpus2-0, cpus2-1, cpus2-2, cpus2-3
tmu_sub1: gpu0, gpu1, gpu2, gpu3, npu0, npu1
Signed-off-by: Shin Son <shin.son@samsung.com>
---
.../boot/dts/exynos/exynosautov920-tmu.dtsi | 377 ++++++++++++++++++
.../arm64/boot/dts/exynos/exynosautov920.dtsi | 31 ++
2 files changed, 408 insertions(+)
create mode 100644 arch/arm64/boot/dts/exynos/exynosautov920-tmu.dtsi
diff --git a/arch/arm64/boot/dts/exynos/exynosautov920-tmu.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920-tmu.dtsi
new file mode 100644
index 000000000000..641d142e0eeb
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/exynosautov920-tmu.dtsi
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Samsung's ExynosAuto920 TMU configurations device tree source
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Samsung's ExynosAuto920 SoC TMU(Thermal Managemenut Unit) are listed as
+ * device tree nodes in this file.
+ */
+
+/ {
+ thermal-zones {
+ cpus0-0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 9>;
+
+ trips {
+ cpus0_0_critical: cpus0-0-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 10>;
+
+ trips {
+ cpus0_1_critical: cpus0-1-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-2-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 11>;
+
+ trips {
+ cpus0_2_critical: cpus0-2-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-3-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 12>;
+
+ trips {
+ cpus0_3_critical: cpus0-3-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-4-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 7>;
+
+ trips {
+ cpus0_4_critical: cpus0-4-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-5-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 8>;
+
+ trips {
+ cpus0_5_critical: cpus0-5-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-6-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 9>;
+
+ trips {
+ cpus0_6_critical: cpus0-6-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus0-7-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 10>;
+
+ trips {
+ cpus0_7_critical: cpus0-7-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 1>;
+
+ trips {
+ cpus1_0_critical: cpus1-0-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 2>;
+
+ trips {
+ cpus1_1_critical: cpus1-1-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-2-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 3>;
+
+ trips {
+ cpus1_2_critical: cpus1-2-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-3-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 4>;
+
+ trips {
+ cpus1_3_critical: cpus1-3-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-4-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 5>;
+
+ trips {
+ cpus1_4_critical: cpus1-4-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-5-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 6>;
+
+ trips {
+ cpus1_5_critical: cpus1-5-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-6-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 7>;
+
+ trips {
+ cpus1_6_critical: cpus1-6-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus1-7-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_top 8>;
+
+ trips {
+ cpus1_7_critical: cpus1-7-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus2-0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 3>;
+
+ trips {
+ cpus2_0_critical: cpus2-0-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus2-1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 4>;
+
+ trips {
+ cpus2_1_critical: cpus2-1-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus2-2-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 5>;
+
+ trips {
+ cpus2_2_critical: cpus2-2-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ cpus2-3-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub0 6>;
+
+ trips {
+ cpus2_3_critical: cpus2-3-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ gpu0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 1>;
+
+ trips {
+ gpu0_critical: gpu0-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ gpu1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 2>;
+
+ trips {
+ gpu1_critical: gpu1-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ gpu2-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 3>;
+
+ trips {
+ gpu2_critical: gpu2-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ gpu3-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 4>;
+
+ trips {
+ gpu3_critical: gpu3-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ npu0-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 6>;
+
+ trips {
+ npu0_critical: npu0-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+
+ npu1-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tmu_sub1 7>;
+
+ trips {
+ npu1_critical: npu1-critical {
+ temperature = <125000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi
index 0fdf2062930a..fba403e48aed 100644
--- a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi
@@ -330,6 +330,36 @@ watchdog_cl1: watchdog@10070000 {
samsung,cluster-index = <1>;
};
+ tmu_top: tmu@100a0000 {
+ compatible = "samsung,exynosautov920-tmu";
+ reg = <0x100A0000 0x1000>;
+ interrupts = <GIC_SPI 951 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ clocks = <&cmu_misc CLK_DOUT_MISC_NOCP>;
+ clock-names = "tmu_apbif";
+ samsung,sensors = <12>;
+ };
+
+ tmu_sub0: tmu@100b0000 {
+ compatible = "samsung,exynosautov920-tmu";
+ reg = <0x100B0000 0x1000>;
+ interrupts = <GIC_SPI 950 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ clocks = <&cmu_misc CLK_DOUT_MISC_NOCP>;
+ clock-names = "tmu_apbif";
+ samsung,sensors = <10>;
+ };
+
+ tmu_sub1: tmu@100c0000 {
+ compatible = "samsung,exynosautov920-tmu";
+ reg = <0x100C0000 0x1000>;
+ interrupts = <GIC_SPI 949 IRQ_TYPE_LEVEL_HIGH>;
+ #thermal-sensor-cells = <1>;
+ clocks = <&cmu_misc CLK_DOUT_MISC_NOCP>;
+ clock-names = "tmu_apbif";
+ samsung,sensors = <7>;
+ };
+
gic: interrupt-controller@10400000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
@@ -1507,3 +1537,4 @@ timer {
};
#include "exynosautov920-pinctrl.dtsi"
+#include "exynosautov920-tmu.dtsi"
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread