Re: [PATCH 2/2] thermal: amlogic: Add support for A9 thermal controller
Daniel Lezcano <[email protected]>
| Newsgroups | org.kernel.vger.linux-pm,org.infradead.lists.linux-amlogic,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/30/26 10:34, Xianwei Zhao via B4 Relay wrote: > From: Xianwei Zhao <[email protected]> > > Add support for the Amlogic A9 thermal controller. > > The A9 thermal controller uses different calibration parameters, requires > separate core and bus clocks, and supports a hardware over-temperature > reset mechanism. > > Add the A9 calibration data, retrieve the clocks by name, and configure > the hardware reset temperature through the optional 'amlogic,hw-reset-temp' > DT property. When the property is absent, use the default reset temperature > of 110°C. > > Also restore the hardware reset configuration after resume. > > Signed-off-by: Xianwei Zhao <[email protected]> > --- > drivers/thermal/amlogic_thermal.c | 107 ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 104 insertions(+), 3 deletions(-) > > diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c > index a0b530624b60..c9c351496653 100644 > --- a/drivers/thermal/amlogic_thermal.c > +++ b/drivers/thermal/amlogic_thermal.c > @@ -45,6 +45,18 @@ > TSENSOR_CFG_REG1_DEM_EN | \ > TSENSOR_CFG_REG1_CH_SEL) > > +#define TSENSOR_CFG_REG2 0x8 > + #define TSENSOR_CFG_REG2_HITEMP_EN BIT(31) > + #define TSENSOR_CFG_REG2_REBOOT_EN BIT(30) > + #define TSENSOR_CFG_REG2_REBOOT_CODE GENMASK(15, 4) > + #define TSENSOR_CFG_REG2_REBOOT_TIME GENMASK(23, 16) > + #define TSENSOR_CFG_REG2_ENABLE \ > + (TSENSOR_CFG_REG2_HITEMP_EN | \ > + TSENSOR_CFG_REG2_REBOOT_EN | \ > + TSENSOR_CFG_REG2_REBOOT_TIME) > + > +#define TSENSOR_TEMP_CAL 1 > + > #define TSENSOR_STAT0 0x40 > > #define TSENSOR_STAT9 0x64 > @@ -63,6 +75,7 @@ > > #define TSENSOR_CALIB_OFFSET 1 > #define TSENSOR_CALIB_SHIFT 4 > +#define TSENSOR_HW_RESET_DEFAULT_TEMP 110000 > > /** > * struct amlogic_thermal_soc_calib_data > @@ -93,6 +106,7 @@ struct amlogic_thermal_data { > const struct amlogic_thermal_soc_calib_data *calibration_parameters; > const struct regmap_config *regmap_config; > bool use_sm; > + bool has_sysclk; > }; > > struct amlogic_thermal { > @@ -101,8 +115,10 @@ struct amlogic_thermal { > struct regmap *regmap; > struct regmap *sec_ao_map; > struct clk *clk; > + struct clk *sysclk; > struct thermal_zone_device *tzd; > u32 trim_info; > + u32 temp_code; > struct meson_sm_firmware *sm_fw; > u32 tsensor_id; > }; > @@ -138,6 +154,46 @@ static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata, > return temp; > } > > +/* > + * Calculate a temperature code from a temperature value . > + * The unit of the temperature is degree milliCelsius. > + */ > +static u32 amlogic_thermal_millicelsius_to_code(struct amlogic_thermal *pdata, int millicelsius) > +{ > + const struct amlogic_thermal_soc_calib_data *param = > + pdata->data->calibration_parameters; > + s64 factor, uptat, uefuse; > + u32 temp_code; > + > + uefuse = pdata->trim_info & TSENSOR_TRIM_SIGN_MASK ? > + ~(pdata->trim_info & TSENSOR_TRIM_TEMP_MASK) + 1 : > + (pdata->trim_info & TSENSOR_TRIM_TEMP_MASK); > + > + factor = param->B + div_s64(millicelsius, 100); > + factor = BIT(16) * factor; > + factor = div_s64(factor, param->A); > + factor = factor - (uefuse & TSENSOR_TRIM_TEMP_MASK); > + > + uptat = param->n * factor; > + uptat = div_s64(uptat, BIT(16)); > + uptat = param->m - uptat; > + > + factor = factor * 100; > + factor = div_s64(factor, uptat); > + > + temp_code = ((factor >> 0x4) & TSENSOR_TEMP_MASK) + TSENSOR_TEMP_CAL; > + > + return temp_code; > +} > + > +static void amlogic_tsensor_setup_hw_reset(struct amlogic_thermal *data) > +{ > + regmap_update_bits(data->regmap, TSENSOR_CFG_REG2, TSENSOR_CFG_REG2_REBOOT_CODE, > + data->temp_code << 0x4); > + regmap_update_bits(data->regmap, TSENSOR_CFG_REG2, > + TSENSOR_CFG_REG2_ENABLE, TSENSOR_CFG_REG2_ENABLE); > +} > + > static int amlogic_thermal_enable(struct amlogic_thermal *data) > { > int ret; > @@ -254,6 +310,13 @@ static const struct amlogic_thermal_soc_calib_data amlogic_thermal_g12a = { > .n = 324, > }; > > +static const struct amlogic_thermal_soc_calib_data amlogic_thermal_a9 = { > + .A = 9164, > + .B = 2747, > + .m = 370, > + .n = 270, > +}; > + > static const struct amlogic_thermal_data amlogic_thermal_g12a_cpu_param = { > .u_efuse_off = 0x128, > .calibration_parameters = &amlogic_thermal_g12a, > @@ -272,6 +335,13 @@ 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_a9_param = { > + .use_sm = true, > + .has_sysclk = true, > + .calibration_parameters = &amlogic_thermal_a9, > + .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, > @@ -291,6 +361,10 @@ static const struct of_device_id of_amlogic_thermal_match[] = { > .compatible = "amlogic,a1-cpu-thermal", > .data = &amlogic_thermal_a1_cpu_param, > }, > + { > + .compatible = "amlogic,a9-thermal", > + .data = &amlogic_thermal_a9_param, > + }, > { > .compatible = "amlogic,t7-thermal", > .data = &amlogic_thermal_t7_param, > @@ -305,6 +379,7 @@ static int amlogic_thermal_probe(struct platform_device *pdev) > struct device *dev = &pdev->dev; > void __iomem *base; > int ret; > + u32 reset_temp; > > pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); > if (!pdata) > @@ -323,9 +398,24 @@ static int amlogic_thermal_probe(struct platform_device *pdev) > if (IS_ERR(pdata->regmap)) > return PTR_ERR(pdata->regmap); > > - pdata->clk = devm_clk_get(dev, NULL); > - if (IS_ERR(pdata->clk)) > - return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get clock\n"); > + if (pdata->data->has_sysclk) { > + pdata->clk = devm_clk_get(dev, "core"); > + if (IS_ERR(pdata->clk)) > + return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get core clk\n"); > + pdata->sysclk = devm_clk_get_enabled(dev, "pclk"); > + if (IS_ERR(pdata->sysclk)) > + return dev_err_probe(dev, PTR_ERR(pdata->sysclk), "failed to get pclk\n"); > + } else { > + pdata->clk = devm_clk_get(dev, NULL); > + if (IS_ERR(pdata->clk)) > + return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get clock\n"); > + } > + > + if (of_property_read_u32(pdev->dev.of_node, "amlogic,hw-reset-temp", &reset_temp)) { > + dev_dbg(dev, "using default hardware reset temperature\n"); > + reset_temp = TSENSOR_HW_RESET_DEFAULT_TEMP; > + } Old SoC without the 'amlogic,hw-reset-temp' will now default to TSENSOR_HW_RESET_DEFAULT_TEMP > + > > if (pdata->data->use_sm) > ret = amlogic_thermal_probe_sm(pdev, pdata); > @@ -346,6 +436,10 @@ static int amlogic_thermal_probe(struct platform_device *pdev) > > devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd); > > + pdata->temp_code = amlogic_thermal_millicelsius_to_code(pdata, reset_temp); > + > + amlogic_tsensor_setup_hw_reset(pdata); Somehow related to the above comment, should it be only for A9 ? > + > ret = amlogic_thermal_enable(pdata); > > return ret; > @@ -355,6 +449,8 @@ static void amlogic_thermal_remove(struct platform_device *pdev) > { > struct amlogic_thermal *data = platform_get_drvdata(pdev); > > + if (data->data->has_sysclk) > + clk_disable_unprepare(data->sysclk); Not needed, devm_ is used in the probe function > amlogic_thermal_disable(data); > } > > @@ -363,6 +459,8 @@ static int amlogic_thermal_suspend(struct device *dev) > struct amlogic_thermal *data = dev_get_drvdata(dev); > > amlogic_thermal_disable(data); > + if (data->data->has_sysclk) > + clk_disable_unprepare(data->sysclk); > > return 0; > } > @@ -371,6 +469,9 @@ static int amlogic_thermal_resume(struct device *dev) > { > struct amlogic_thermal *data = dev_get_drvdata(dev); > > + amlogic_tsensor_setup_hw_reset(data); > + if (data->data->has_sysclk) > + clk_prepare_enable(data->sysclk); Shouldn't the clock enabled before accessing the register in amlogic_tsensor_setup_hw_reset() ? > return amlogic_thermal_enable(data); > } > >