* [PATCH v5 0/3] Add exynosautov920 thermal support [not found] <CGME20250925022845epcas2p2b0e2bbe2e7674f408ae6404ac66a8627@epcas2p2.samsung.com> @ 2025-09-25 2:28 ` Shin Son 2025-09-25 2:28 ` [PATCH v5 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son ` (2 more replies) 0 siblings, 3 replies; 6+ messages in thread From: Shin Son @ 2025-09-25 2:28 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 This patch series adds support for exynosautov920, automotive-grade processor. Although the exynosautov920's TMU hardware differs slightly from exisiting platform, its read and calibration logic closely follow our legacy TMU interface. To prevent runtime and build time errors, it is kept as a single change rather than being split. This change merges the new exynosautov920-specific register definitions and timing parameters into the exynos-tmu driver, ensuring consistent behavior across all Exynos series. All new code paths have been tested on a exynosautov920 board and verified to correctly read temperatures and emulate behavior. Changes in v5: - Changed the maximum number of thermal sensors to 15. Changes in v4: - Kept 'addtionalProperties: false'. - Removed the 'samsung,hw-sensor-indices' property in the binding. - Added the 'samsung,sensors' property in the binding. - Dropped code-like formatting and rewrote the description in plain, hardware-focused language in the commit message. - Removed the bitmap and replaced the tz_count to sensor_count. Changes in v3: - Removed redundant commit message. - Rephrased the sentences to describe the hardware clearly. - Restricted sensor indices to V920. - Set #thermal-sensor-cells per variant. - Replaced 'additionalProperties' with 'unevaluatedProperties'. - Removed the duplicate #define and use the original. - Used lowercase hex in #define. - Simplified 'temp_to_code' and 'code_to_temp' to one computation path by normalizing calib_temp. Changes in v2: - Replace the generic property with a vendor-specific one. - Added an indices property instead of ranges. - Shortened thermal node name and made them more generic. - Updated the indices logic accordingly after removing the ranges property. Shin Son (3): dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 thermal: exynos_tmu: Support new hardware and update TMU interface arm64: dts: exynosautov920: Add multiple sensors .../thermal/samsung,exynos-thermal.yaml | 32 +- .../boot/dts/exynos/exynosautov920-tmu.dtsi | 377 ++++++++++++++++++ .../arm64/boot/dts/exynos/exynosautov920.dtsi | 31 ++ drivers/thermal/samsung/exynos_tmu.c | 322 +++++++++++++-- 4 files changed, 724 insertions(+), 38 deletions(-) create mode 100644 arch/arm64/boot/dts/exynos/exynosautov920-tmu.dtsi -- 2.50.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v5 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 2025-09-25 2:28 ` [PATCH v5 0/3] Add exynosautov920 thermal support Shin Son @ 2025-09-25 2:28 ` Shin Son 2025-09-25 2:28 ` [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son 2025-09-25 2:28 ` [PATCH v5 3/3] arm64: dts: exynosautov920: Add multiple sensors Shin Son 2 siblings, 0 replies; 6+ messages in thread From: Shin Son @ 2025-09-25 2:28 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] 6+ messages in thread
* [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface 2025-09-25 2:28 ` [PATCH v5 0/3] Add exynosautov920 thermal support Shin Son 2025-09-25 2:28 ` [PATCH v5 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son @ 2025-09-25 2:28 ` Shin Son 2025-09-25 20:08 ` Henrik Grimler 2025-09-25 2:28 ` [PATCH v5 3/3] arm64: dts: exynosautov920: Add multiple sensors Shin Son 2 siblings, 1 reply; 6+ messages in thread From: Shin Son @ 2025-09-25 2:28 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'. 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] 6+ messages in thread
* Re: [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface 2025-09-25 2:28 ` [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son @ 2025-09-25 20:08 ` Henrik Grimler 2025-09-26 7:34 ` 손신 0 siblings, 1 reply; 6+ messages in thread From: Henrik Grimler @ 2025-09-25 20:08 UTC (permalink / raw) To: Shin Son Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Rafael J . Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba, Rob Herring, Conor Dooley, Alim Akhtar, linux-pm, linux-samsung-soc, devicetree, linux-arm-kernel, linux-kernel On Thu, Sep 25, 2025 at 11:28:39AM +0900, Shin Son wrote: > 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'. > > Signed-off-by: Shin Son <shin.son@samsung.com> Reviewed-by: Henrik Grimler <henrik@grimler.se> Best regards, Henrik Grimler > --- > 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 [flat|nested] 6+ messages in thread
* RE: [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface 2025-09-25 20:08 ` Henrik Grimler @ 2025-09-26 7:34 ` 손신 0 siblings, 0 replies; 6+ messages in thread From: 손신 @ 2025-09-26 7:34 UTC (permalink / raw) To: 'Henrik Grimler' Cc: 'Bartlomiej Zolnierkiewicz', 'Krzysztof Kozlowski', 'Rafael J . Wysocki', 'Daniel Lezcano', 'Zhang Rui', 'Lukasz Luba', 'Rob Herring', 'Conor Dooley', 'Alim Akhtar', linux-pm, linux-samsung-soc, devicetree, linux-arm-kernel, linux-kernel Hello Henrik Grimler. > -----Original Message----- > From: Henrik Grimler [mailto:henrik@grimler.se] > Sent: Friday, September 26, 2025 5:08 AM > To: Shin Son <shin.son@samsung.com> > Cc: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>; Krzysztof Kozlowski > <krzk@kernel.org>; Rafael J . Wysocki <rafael@kernel.org>; Daniel Lezcano > <daniel.lezcano@linaro.org>; Zhang Rui <rui.zhang@intel.com>; Lukasz Luba > <lukasz.luba@arm.com>; Rob Herring <robh@kernel.org>; Conor Dooley > <conor+dt@kernel.org>; Alim Akhtar <alim.akhtar@samsung.com>; linux- > pm@vger.kernel.org; linux-samsung-soc@vger.kernel.org; > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux- > kernel@vger.kernel.org > Subject: Re: [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and > update TMU interface > > On Thu, Sep 25, 2025 at 11:28:39AM +0900, Shin Son wrote: > > 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'. > > > > Signed-off-by: Shin Son <shin.son@samsung.com> > > Reviewed-by: Henrik Grimler <henrik@grimler.se> > > Best regards, > Henrik Grimler Thank you for the review. I'll add your 'Reviewed-by' tag in the next version. Best regards, Shin Son > > > --- > > 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 [flat|nested] 6+ messages in thread
* [PATCH v5 3/3] arm64: dts: exynosautov920: Add multiple sensors 2025-09-25 2:28 ` [PATCH v5 0/3] Add exynosautov920 thermal support Shin Son 2025-09-25 2:28 ` [PATCH v5 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son 2025-09-25 2:28 ` [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son @ 2025-09-25 2:28 ` Shin Son 2 siblings, 0 replies; 6+ messages in thread From: Shin Son @ 2025-09-25 2:28 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] 6+ messages in thread
end of thread, other threads:[~2025-09-26 7:35 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CGME20250925022845epcas2p2b0e2bbe2e7674f408ae6404ac66a8627@epcas2p2.samsung.com>
2025-09-25 2:28 ` [PATCH v5 0/3] Add exynosautov920 thermal support Shin Son
2025-09-25 2:28 ` [PATCH v5 1/3] dt-bindings: thermal: samsung: Adjust '#thermal-sensor-cells' to 1 Shin Son
2025-09-25 2:28 ` [PATCH v5 2/3] thermal: exynos_tmu: Support new hardware and update TMU interface Shin Son
2025-09-25 20:08 ` Henrik Grimler
2025-09-26 7:34 ` 손신
2025-09-25 2:28 ` [PATCH v5 3/3] arm64: dts: exynosautov920: Add multiple sensors Shin Son
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox