[PATCH v2 1/2] thermal: mediatek: add support for MT7986 and MT7981

AngeloGioacchino Del Regno angelogioacchino.delregno at collabora.com
Thu Dec 1 05:24:17 PST 2022


Il 30/11/22 14:19, Daniel Golle ha scritto:
> Add support for V3 generation thermal found in MT7986 and MT7981 SoCs.
> Brings code to assign values from efuse as well as new function to
> convert raw temperature to millidegree celsius, as found in MediaTek's
> SDK sources (but cleaned up and de-duplicated)
> 
> [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/baf36c7eef477aae1f8f2653b6c29e2caf48475b
> Signed-off-by: Daniel Golle <daniel at makrotopia.org>
> Reviewed-by: Henry Yen <henry.yen at mediatek.com>
> ---
> Changes since v1: Drop use of adc_oe field in efuse, Henry Yen confirmed
> its use has been dropped intentionally in MTK SDK as well.
> 
>   drivers/thermal/mtk_thermal.c | 122 +++++++++++++++++++++++++++++++++-
>   1 file changed, 119 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> index 8440692e3890..6a69419f8960 100644
> --- a/drivers/thermal/mtk_thermal.c
> +++ b/drivers/thermal/mtk_thermal.c
> @@ -150,6 +150,21 @@
>   #define CALIB_BUF1_VALID_V2(x)		(((x) >> 4) & 0x1)
>   #define CALIB_BUF1_O_SLOPE_SIGN_V2(x)	(((x) >> 3) & 0x1)
>   
> +/*
> + * Layout of the fuses providing the calibration data
> + * These macros can be used for MT7981 and MT7986.
> + */
> +#define CALIB_BUF0_ADC_GE_V3(x)		(((x) >> 0) & 0x3ff)
> +#define CALIB_BUF0_ADC_OE_V3(x)		(((x) >> 10) & 0x3ff)
> +#define CALIB_BUF0_DEGC_CALI_V3(x)	(((x) >> 20) & 0x3f)
> +#define CALIB_BUF0_O_SLOPE_V3(x)	(((x) >> 26) & 0x3f)
> +#define CALIB_BUF1_VTS_TS1_V3(x)	(((x) >> 0) & 0x1ff)
> +#define CALIB_BUF1_VTS_TS2_V3(x)	(((x) >> 21) & 0x1ff)
> +#define CALIB_BUF1_VTS_TSABB_V3(x)	(((x) >> 9) & 0x1ff)
> +#define CALIB_BUF1_VALID_V3(x)		(((x) >> 18) & 0x1)
> +#define CALIB_BUF1_O_SLOPE_SIGN_V3(x)	(((x) >> 19) & 0x1)
> +#define CALIB_BUF1_ID_V3(x)		(((x) >> 20) & 0x1)
> +
>   enum {
>   	VTS1,
>   	VTS2,
> @@ -163,6 +178,7 @@ enum {
>   enum mtk_thermal_version {
>   	MTK_THERMAL_V1 = 1,
>   	MTK_THERMAL_V2,
> +	MTK_THERMAL_V3,
>   };
>   
>   /* MT2701 thermal sensors */
> @@ -245,6 +261,27 @@ enum mtk_thermal_version {
>   /* The calibration coefficient of sensor  */
>   #define MT8183_CALIBRATION	153
>   
> +/* AUXADC channel 11 is used for the temperature sensors */
> +#define MT7986_TEMP_AUXADC_CHANNEL	11
> +
> +/* The total number of temperature sensors in the MT7986 */
> +#define MT7986_NUM_SENSORS		1
> +
> +/* The number of banks in the MT7986 */
> +#define MT7986_NUM_ZONES		1
> +
> +/* The number of sensing points per bank */
> +#define MT7986_NUM_SENSORS_PER_ZONE	1
> +
> +/* MT7986 thermal sensors */
> +#define MT7986_TS1			0
> +
> +/* The number of controller in the MT7986 */
> +#define MT7986_NUM_CONTROLLER		1
> +
> +/* The calibration coefficient of sensor  */
> +#define MT7986_CALIBRATION		165
> +
>   struct mtk_thermal;
>   
>   struct thermal_bank_cfg {
> @@ -386,6 +423,14 @@ static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
>   static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
>   static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
>   
> +/* MT7986 thermal sensor data */
> +static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
> +static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
> +static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
> +static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
> +static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
> +static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
> +
>   /*
>    * The MT8173 thermal controller has four banks. Each bank can read up to
>    * four temperature sensors simultaneously. The MT8173 has a total of 5
> @@ -549,6 +594,30 @@ static const struct mtk_thermal_data mt8183_thermal_data = {
>   	.version = MTK_THERMAL_V1,
>   };
>   
> +/*
> + * MT7986 uses AUXADC Channel 11 for raw data access.
> + */
> +static const struct mtk_thermal_data mt7986_thermal_data = {
> +	.auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
> +	.num_banks = MT7986_NUM_ZONES,
> +	.num_sensors = MT7986_NUM_SENSORS,
> +	.vts_index = mt7986_vts_index,
> +	.cali_val = MT7986_CALIBRATION,
> +	.num_controller = MT7986_NUM_CONTROLLER,
> +	.controller_offset = mt7986_tc_offset,
> +	.need_switch_bank = true,
> +	.bank_data = {
> +		{
> +			.num_sensors = 1,
> +			.sensors = mt7986_bank_data,
> +		},
> +	},
> +	.msr = mt7986_msr,
> +	.adcpnp = mt7986_adcpnp,
> +	.sensor_mux_values = mt7986_mux_values,
> +	.version = MTK_THERMAL_V3,
> +};
> +
>   /**
>    * raw_to_mcelsius - convert a raw ADC value to mcelsius
>    * @mt:	The thermal controller
> @@ -603,6 +672,22 @@ static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
>   	return (format_2 - tmp) * 100;
>   }
>   
> +static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
> +{
> +	s32 tmp;
> +
> +	if (raw == 0)
> +		return 0;
> +
> +	raw &= 0xfff;
> +	tmp = 100000 * 15 / 16 * 10000;
> +	tmp /= 4096 - 512 + mt->adc_ge;
> +	tmp /= 1490;
> +	tmp *= raw - mt->vts[sensno] - 2900;
> +
> +	return mt->degc_cali * 500 - tmp;
> +}
> +
>   /**
>    * mtk_thermal_get_bank - get bank
>    * @bank:	The bank
> @@ -659,9 +744,12 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
>   		if (mt->conf->version == MTK_THERMAL_V1) {
>   			temp = raw_to_mcelsius_v1(
>   				mt, conf->bank_data[bank->id].sensors[i], raw);
> -		} else {
> +		} else if (mt->conf->version == MTK_THERMAL_V2) {
>   			temp = raw_to_mcelsius_v2(
>   				mt, conf->bank_data[bank->id].sensors[i], raw);
> +		} else {
> +			temp = raw_to_mcelsius_v3(
> +				mt, conf->bank_data[bank->id].sensors[i], raw);
>   		}

What about optimizing this with assigning a function pointer?
Like that, we wouldn't check any version in there... as in that case we'd
simply do something like

temp = conf->raw_to_mcelsius(mt, conf->bank...blahblah...);

...and this would also mean that the snippet saying "the first read of a sensor
often contains very high bogus temperature value [...]" would get merged in the v2
of raw_to_mcelsius (as that function is used only in mtk_thermal_bank_temperature).

>   
>   		/*
> @@ -887,6 +975,26 @@ static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
>   	return 0;
>   }
>   
> +static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
> +{
> +	if (!CALIB_BUF1_VALID_V3(buf[1]))
> +		return -EINVAL;
> +
> +	mt->adc_oe = CALIB_BUF0_ADC_OE_V3(buf[0]);
> +	mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
> +	mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
> +	mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
> +	mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
> +	mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
> +	mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
> +	mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
> +
> +	if (CALIB_BUF1_ID_V3(buf[1]) == 0)
> +		mt->o_slope = 0;
> +
> +	return 0;
> +}
> +
>   static int mtk_thermal_get_calibration_data(struct device *dev,
>   					    struct mtk_thermal *mt)
>   {
> @@ -897,6 +1005,7 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
>   
>   	/* Start with default values */
>   	mt->adc_ge = 512;
> +	mt->adc_oe = 512;
>   	for (i = 0; i < mt->conf->num_sensors; i++)
>   		mt->vts[i] = 260;
>   	mt->degc_cali = 40;
> @@ -924,8 +1033,10 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
>   
>   	if (mt->conf->version == MTK_THERMAL_V1)
>   		ret = mtk_thermal_extract_efuse_v1(mt, buf);
> -	else
> +	else if (mt->conf->version == MTK_THERMAL_V2)
>   		ret = mtk_thermal_extract_efuse_v2(mt, buf);
> +	else
> +		ret = mtk_thermal_extract_efuse_v3(mt, buf);

I propose to use a switch here instead.

	switch(mt->conf->version) {
	case MTK_THERMAL_V1:
		....
	case MTK_THERMAL_V2:
		....
	case MTK_THERMAL_V3:
		....
	default:
		ret = -EINVAL;
		break;
	};

This would also prevent a potential issue with getting an invalid calibration
due to us calling the wrong version of the get_calibration() function, in which
case, using the default calibration values would be at that point preferred.

Regards,
Angelo





More information about the Linux-mediatek mailing list