]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
thermal/drivers/amlogic: Add support for secure monitor calibration readout
authorRonald Claveau <linux-kernel-dev@aliel.fr>
Fri, 24 Apr 2026 15:45:12 +0000 (17:45 +0200)
committerDaniel Lezcano <daniel.lezcano@kernel.org>
Wed, 3 Jun 2026 07:12:17 +0000 (09:12 +0200)
Some SoCs (e.g. T7) expose thermal calibration data through the secure
monitor rather than a directly accessible eFuse register. Add a use_sm
flag to amlogic_thermal_data to select this path, and retrieve the
firmware handle and tsensor_id from the "amlogic,secure-monitor" DT
phandle with one fixed argument.

Also introduce the amlogic,t7-thermal compatible using this new path.

While refactoring, fix a pre-existing bug where
amlogic_thermal_initialize() was called after
devm_thermal_of_zone_register(), causing the thermal framework to
read an uninitialized trim_info on zone registration.

Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20260424-add-thermal-t7-vim4-v5-4-9040ca36afe2@aliel.fr
drivers/thermal/amlogic_thermal.c

index 5448d772db12abd1f11b3a185c5d84735dd8dffe..a0b530624b60c977cc68c1a675bf45711830cb93 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/thermal.h>
+#include <linux/firmware/meson/meson_sm.h>
 
 #include "thermal_hwmon.h"
 
@@ -84,12 +85,14 @@ struct amlogic_thermal_soc_calib_data {
  * @u_efuse_off: register offset to read fused calibration value
  * @calibration_parameters: calibration parameters structure pointer
  * @regmap_config: regmap config for the device
+ * @use_sm: read data from secure monitor instead of efuse
  * This structure is required for configuration of amlogic thermal driver.
  */
 struct amlogic_thermal_data {
        int u_efuse_off;
        const struct amlogic_thermal_soc_calib_data *calibration_parameters;
        const struct regmap_config *regmap_config;
+       bool use_sm;
 };
 
 struct amlogic_thermal {
@@ -100,6 +103,8 @@ struct amlogic_thermal {
        struct clk *clk;
        struct thermal_zone_device *tzd;
        u32 trim_info;
+       struct meson_sm_firmware *sm_fw;
+       u32 tsensor_id;
 };
 
 /*
@@ -133,26 +138,6 @@ static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
        return temp;
 }
 
-static int amlogic_thermal_initialize(struct amlogic_thermal *pdata)
-{
-       int ret = 0;
-       int ver;
-
-       regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
-                   &pdata->trim_info);
-
-       ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
-
-       if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
-               ret = -EINVAL;
-               dev_err(&pdata->pdev->dev,
-                       "tsensor thermal calibration not supported: 0x%x!\n",
-                       ver);
-       }
-
-       return ret;
-}
-
 static int amlogic_thermal_enable(struct amlogic_thermal *data)
 {
        int ret;
@@ -190,6 +175,67 @@ static int amlogic_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
        return 0;
 }
 
+static int amlogic_thermal_probe_sm(struct platform_device *pdev,
+                                   struct amlogic_thermal *pdata)
+{
+       struct device *dev = &pdev->dev;
+       struct of_phandle_args ph_args;
+       int ret;
+
+       ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+                                              "amlogic,secure-monitor",
+                                              1, 0, &ph_args);
+       if (ret)
+               return ret;
+
+       if (!ph_args.np) {
+               dev_err(dev, "Failed to parse secure monitor phandle\n");
+               return -ENODEV;
+       }
+
+       pdata->sm_fw = meson_sm_get(ph_args.np);
+       of_node_put(ph_args.np);
+       if (!pdata->sm_fw) {
+               dev_err(dev, "Failed to get secure monitor firmware\n");
+               return -EPROBE_DEFER;
+       }
+
+       pdata->tsensor_id = ph_args.args[0];
+
+       return meson_sm_get_thermal_calib(pdata->sm_fw,
+                                         &pdata->trim_info,
+                                         pdata->tsensor_id);
+}
+
+static int amlogic_thermal_probe_syscon(struct platform_device *pdev,
+                                       struct amlogic_thermal *pdata)
+{
+       struct device *dev = &pdev->dev;
+       int ver;
+
+       pdata->sec_ao_map =
+               syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                               "amlogic,ao-secure");
+       if (IS_ERR(pdata->sec_ao_map)) {
+               dev_err(dev, "syscon regmap lookup failed.\n");
+               return PTR_ERR(pdata->sec_ao_map);
+       }
+
+       regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
+                   &pdata->trim_info);
+
+       ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
+
+       if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
+               dev_err(&pdata->pdev->dev,
+                       "tsensor thermal calibration not supported: 0x%x!\n",
+                       ver);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct thermal_zone_device_ops amlogic_thermal_ops = {
        .get_temp       = amlogic_thermal_get_temp,
 };
@@ -226,6 +272,12 @@ static const struct amlogic_thermal_data amlogic_thermal_a1_cpu_param = {
        .regmap_config = &amlogic_thermal_regmap_config_g12a,
 };
 
+static const struct amlogic_thermal_data amlogic_thermal_t7_param = {
+       .use_sm                 = true,
+       .calibration_parameters = &amlogic_thermal_g12a,
+       .regmap_config          = &amlogic_thermal_regmap_config_g12a,
+};
+
 static const struct of_device_id of_amlogic_thermal_match[] = {
        {
                .compatible = "amlogic,g12a-ddr-thermal",
@@ -239,6 +291,10 @@ static const struct of_device_id of_amlogic_thermal_match[] = {
                .compatible = "amlogic,a1-cpu-thermal",
                .data = &amlogic_thermal_a1_cpu_param,
        },
+       {
+               .compatible = "amlogic,t7-thermal",
+               .data = &amlogic_thermal_t7_param,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match);
@@ -271,12 +327,12 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
        if (IS_ERR(pdata->clk))
                return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get clock\n");
 
-       pdata->sec_ao_map = syscon_regmap_lookup_by_phandle
-               (pdev->dev.of_node, "amlogic,ao-secure");
-       if (IS_ERR(pdata->sec_ao_map)) {
-               dev_err(dev, "syscon regmap lookup failed.\n");
-               return PTR_ERR(pdata->sec_ao_map);
-       }
+       if (pdata->data->use_sm)
+               ret = amlogic_thermal_probe_sm(pdev, pdata);
+       else
+               ret = amlogic_thermal_probe_syscon(pdev, pdata);
+       if (ret)
+               return ret;
 
        pdata->tzd = devm_thermal_of_zone_register(&pdev->dev,
                                                   0,
@@ -290,10 +346,6 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
 
        devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd);
 
-       ret = amlogic_thermal_initialize(pdata);
-       if (ret)
-               return ret;
-
        ret = amlogic_thermal_enable(pdata);
 
        return ret;