diff options
18 files changed, 667 insertions, 286 deletions
diff --git a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml index 20f8f9b3b971..01fccdfc4178 100644 --- a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml @@ -13,11 +13,13 @@ description: Binding for Amlogic Thermal properties: compatible: - items: - - enum: - - amlogic,g12a-cpu-thermal - - amlogic,g12a-ddr-thermal - - const: amlogic,g12a-thermal + oneOf: + - items: + - enum: + - amlogic,g12a-cpu-thermal + - amlogic,g12a-ddr-thermal + - const: amlogic,g12a-thermal + - const: amlogic,a1-cpu-thermal reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml index b634f57cd011..ca81c8afba79 100644 --- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml @@ -18,13 +18,15 @@ properties: oneOf: - enum: - loongson,ls2k1000-thermal + - loongson,ls2k2000-thermal - items: - enum: - - loongson,ls2k2000-thermal + - loongson,ls2k0500-thermal - const: loongson,ls2k1000-thermal reg: - maxItems: 1 + minItems: 1 + maxItems: 2 interrupts: maxItems: 1 @@ -38,6 +40,24 @@ required: - interrupts - '#thermal-sensor-cells' +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k2000-thermal + +then: + properties: + reg: + minItems: 2 + maxItems: 2 + +else: + properties: + reg: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml index e6665af52ee6..331cf4e662e3 100644 --- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml @@ -19,6 +19,9 @@ properties: compatible: enum: - mediatek,mt7988-lvts-ap + - mediatek,mt8186-lvts + - mediatek,mt8188-lvts-ap + - mediatek,mt8188-lvts-mcu - mediatek,mt8192-lvts-ap - mediatek,mt8192-lvts-mcu - mediatek,mt8195-lvts-ap @@ -60,6 +63,8 @@ allOf: compatible: contains: enum: + - mediatek,mt8188-lvts-ap + - mediatek,mt8188-lvts-mcu - mediatek,mt8192-lvts-ap - mediatek,mt8192-lvts-mcu then: @@ -75,6 +80,7 @@ allOf: compatible: contains: enum: + - mediatek,mt8186-lvts - mediatek,mt8195-lvts-ap - mediatek,mt8195-lvts-mcu then: diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml b/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml index 5ff72ce5c887..1175bb358382 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml @@ -17,10 +17,14 @@ description: properties: compatible: - enum: - - qcom,sc8180x-lmh - - qcom,sdm845-lmh - - qcom,sm8150-lmh + oneOf: + - enum: + - qcom,sc8180x-lmh + - qcom,sdm845-lmh + - qcom,sm8150-lmh + - items: + - const: qcom,qcm2290-lmh + - const: qcom,sm8150-lmh reg: items: diff --git a/Documentation/devicetree/bindings/thermal/st,stih407-thermal.yaml b/Documentation/devicetree/bindings/thermal/st,stih407-thermal.yaml new file mode 100644 index 000000000000..9f6fc5c95c55 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/st,stih407-thermal.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/st,stih407-thermal.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STi digital thermal sensor (DTS) + +maintainers: + - Patrice Chotard <patrice.chotard@foss.st.com> + - Lee Jones <lee@kernel.org> + +allOf: + - $ref: thermal-sensor.yaml + +properties: + compatible: + const: st,stih407-thermal + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: thermal + + interrupts: + description: + For thermal sensors for which no interrupt has been defined, a polling + delay of 1000ms will be used to read the temperature from device. + maxItems: 1 + + '#thermal-sensor-cells': + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + temperature-sensor@91a0000 { + compatible = "st,stih407-thermal"; + reg = <0x91a0000 0x28>; + clock-names = "thermal"; + clocks = <&CLK_SYSIN>; + interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/thermal/st-thermal.txt b/Documentation/devicetree/bindings/thermal/st-thermal.txt deleted file mode 100644 index a2f939137e35..000000000000 --- a/Documentation/devicetree/bindings/thermal/st-thermal.txt +++ /dev/null @@ -1,32 +0,0 @@ -Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs. - -Required parameters: -------------------- - -compatible : Should be "st,stih407-thermal" - -clock-names : Should be "thermal". - See: Documentation/devicetree/bindings/resource-names.txt -clocks : Phandle of the clock used by the thermal sensor. - See: Documentation/devicetree/bindings/clock/clock-bindings.txt - -Optional parameters: -------------------- - -reg : For non-sysconf based sensors, this should be the physical base - address and length of the sensor's registers. -interrupts : Standard way to define interrupt number. - NB: For thermal sensor's for which no interrupt has been - defined, a polling delay of 1000ms will be used to read the - temperature from device. - -Example: - - temp0@91a0000 { - compatible = "st,stih407-thermal"; - reg = <0x91a0000 0x28>; - clock-names = "thermal"; - clocks = <&CLK_SYSIN>; - interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>; - st,passive_cooling_temp = <110>; - }; diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c index df7a5ed55385..cd4776aa805e 100644 --- a/drivers/thermal/amlogic_thermal.c +++ b/drivers/thermal/amlogic_thermal.c @@ -220,6 +220,12 @@ static const struct amlogic_thermal_data amlogic_thermal_g12a_ddr_param = { .regmap_config = &amlogic_thermal_regmap_config_g12a, }; +static const struct amlogic_thermal_data amlogic_thermal_a1_cpu_param = { + .u_efuse_off = 0x114, + .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", @@ -229,6 +235,10 @@ static const struct of_device_id of_amlogic_thermal_match[] = { .compatible = "amlogic,g12a-cpu-thermal", .data = &amlogic_thermal_g12a_cpu_param, }, + { + .compatible = "amlogic,a1-cpu-thermal", + .data = &amlogic_thermal_a1_cpu_param, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match); diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index f783547ef964..fdcb077cfd54 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -763,7 +763,6 @@ static void armada_set_sane_name(struct platform_device *pdev, struct armada_thermal_priv *priv) { const char *name = dev_name(&pdev->dev); - char *insane_char; if (strlen(name) > THERMAL_NAME_LENGTH) { /* @@ -781,12 +780,8 @@ static void armada_set_sane_name(struct platform_device *pdev, /* Save the name locally */ strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH); - /* Then check there are no '-' or hwmon core will complain */ - do { - insane_char = strpbrk(priv->zone_name, "-"); - if (insane_char) - *insane_char = '_'; - } while (insane_char); + /* Then ensure there are no '-' or hwmon core will complain */ + strreplace(priv->zone_name, '-', '_'); } /* diff --git a/drivers/thermal/k3_bandgap.c b/drivers/thermal/k3_bandgap.c index e88192d2afea..2a703770fc91 100644 --- a/drivers/thermal/k3_bandgap.c +++ b/drivers/thermal/k3_bandgap.c @@ -78,7 +78,6 @@ static const int k3_adc_to_temp[] = { struct k3_bandgap { void __iomem *base; - const struct k3_bandgap_data *conf; }; /* common data structures */ diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c index 0f475fe46bc9..2d6b75b0539f 100644 --- a/drivers/thermal/loongson2_thermal.c +++ b/drivers/thermal/loongson2_thermal.c @@ -14,58 +14,81 @@ #include <linux/property.h> #include <linux/thermal.h> #include <linux/units.h> + #include "thermal_hwmon.h" -#define LOONGSON2_MAX_SENSOR_SEL_NUM 3 +#define LOONGSON2_MAX_SENSOR_SEL_NUM 3 + +#define LOONGSON2_THSENS_CTRL_HI_REG 0x0 +#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8 +#define LOONGSON2_THSENS_STATUS_REG 0x10 +#define LOONGSON2_THSENS_OUT_REG 0x14 -#define LOONGSON2_THSENS_CTRL_HI_REG 0x0 -#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8 -#define LOONGSON2_THSENS_STATUS_REG 0x10 -#define LOONGSON2_THSENS_OUT_REG 0x14 +#define LOONGSON2_THSENS_INT_LO BIT(0) +#define LOONGSON2_THSENS_INT_HIGH BIT(1) +#define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \ + LOONGSON2_THSENS_INT_HIGH) +#define LOONGSON2_THSENS_OUT_MASK 0xFF -#define LOONGSON2_THSENS_INT_LO BIT(0) -#define LOONGSON2_THSENS_INT_HIGH BIT(1) -#define LOONGSON2_THSENS_OUT_MASK 0xFF +/* + * This flag is used to indicate the temperature reading + * method of the Loongson-2K2000 + */ +#define LS2K2000_THSENS_OUT_FLAG BIT(0) struct loongson2_thermal_chip_data { - unsigned int thermal_sensor_sel; + unsigned int thermal_sensor_sel; + unsigned int flags; }; struct loongson2_thermal_data { - void __iomem *regs; + void __iomem *ctrl_reg; + void __iomem *temp_reg; const struct loongson2_thermal_chip_data *chip_data; }; +static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data, + int ctrl_data, bool low, bool enable) +{ + int reg_ctrl = 0; + int reg_off = data->chip_data->thermal_sensor_sel * 2; + int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG; + + reg_ctrl = ctrl_data + HECTO; + reg_ctrl |= enable ? 0x100 : 0; + writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off); +} + static int loongson2_thermal_set(struct loongson2_thermal_data *data, - int low, int high, bool enable) + int low, int high, bool enable) { - u64 reg_ctrl = 0; - int reg_off = data->chip_data->thermal_sensor_sel * 2; + /* Set low temperature threshold */ + loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable); - low = clamp(-40, low, high); - high = clamp(125, low, high); + /* Set high temperature threshold */ + loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable); - low += HECTO; - high += HECTO; + return 0; +} - reg_ctrl = low; - reg_ctrl |= enable ? 0x100 : 0; - writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off); +static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp) +{ + int val; + struct loongson2_thermal_data *data = thermal_zone_device_priv(tz); - reg_ctrl = high; - reg_ctrl |= enable ? 0x100 : 0; - writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off); + val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG); + *temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO; return 0; } -static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp) +static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp) { - u32 reg_val; + int val; struct loongson2_thermal_data *data = thermal_zone_device_priv(tz); - reg_val = readl(data->regs + LOONGSON2_THSENS_OUT_REG); - *temp = ((reg_val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO; + val = readl(data->temp_reg); + *temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO; return 0; } @@ -75,8 +98,7 @@ static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev) struct thermal_zone_device *tzd = dev; struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd); - writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs + - LOONGSON2_THSENS_STATUS_REG); + writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG); thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED); @@ -90,8 +112,8 @@ static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, return loongson2_thermal_set(data, low/MILLI, high/MILLI, true); } -static const struct thermal_zone_device_ops loongson2_of_thermal_ops = { - .get_temp = loongson2_thermal_get_temp, +static struct thermal_zone_device_ops loongson2_of_thermal_ops = { + .get_temp = loongson2_2k1000_get_temp, .set_trips = loongson2_thermal_set_trips, }; @@ -108,22 +130,30 @@ static int loongson2_thermal_probe(struct platform_device *pdev) data->chip_data = device_get_match_data(dev); - data->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->regs)) - return PTR_ERR(data->regs); + data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->ctrl_reg)) + return PTR_ERR(data->ctrl_reg); + + /* The temperature output register is separate for Loongson-2K2000 */ + if (data->chip_data->flags & LS2K2000_THSENS_OUT_FLAG) { + data->temp_reg = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(data->temp_reg)) + return PTR_ERR(data->temp_reg); + + loongson2_of_thermal_ops.get_temp = loongson2_2k2000_get_temp; + } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs + - LOONGSON2_THSENS_STATUS_REG); + writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG); loongson2_thermal_set(data, 0, 0, false); for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) { tzd = devm_thermal_of_zone_register(dev, i, data, - &loongson2_of_thermal_ops); + &loongson2_of_thermal_ops); if (!IS_ERR(tzd)) break; @@ -135,7 +165,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread, - IRQF_ONESHOT, "loongson2_thermal", tzd); + IRQF_ONESHOT, "loongson2_thermal", tzd); if (ret < 0) return dev_err_probe(dev, ret, "failed to request alarm irq\n"); @@ -146,6 +176,12 @@ static int loongson2_thermal_probe(struct platform_device *pdev) static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = { .thermal_sensor_sel = 0, + .flags = 0, +}; + +static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = { + .thermal_sensor_sel = 0, + .flags = LS2K2000_THSENS_OUT_FLAG, }; static const struct of_device_id of_loongson2_thermal_match[] = { @@ -153,6 +189,10 @@ static const struct of_device_id of_loongson2_thermal_match[] = { .compatible = "loongson,ls2k1000-thermal", .data = &loongson2_thermal_ls2k1000_data, }, + { + .compatible = "loongson,ls2k2000-thermal", + .data = &loongson2_thermal_ls2k2000_data, + }, { /* end */ } }; MODULE_DEVICE_TABLE(of, of_loongson2_thermal_match); @@ -167,4 +207,5 @@ static struct platform_driver loongson2_thermal_driver = { module_platform_driver(loongson2_thermal_driver); MODULE_DESCRIPTION("Loongson2 thermal driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); MODULE_LICENSE("GPL"); diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index fd4bd650c77a..86b2f44355ac 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -91,9 +91,7 @@ #define LVTS_MSR_READ_TIMEOUT_US 400 #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) -#define LVTS_HW_SHUTDOWN_MT7988 105000 -#define LVTS_HW_SHUTDOWN_MT8192 105000 -#define LVTS_HW_SHUTDOWN_MT8195 105000 +#define LVTS_HW_TSHUT_TEMP 105000 #define LVTS_MINIMUM_THRESHOLD 20000 @@ -102,22 +100,36 @@ static int golden_temp_offset; struct lvts_sensor_data { int dt_id; + u8 cal_offsets[3]; }; struct lvts_ctrl_data { struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX]; int cal_offset[LVTS_SENSOR_MAX]; - int hw_tshut_temp; int num_lvts_sensor; + u8 valid_sensor_mask; int offset; int mode; }; +#define VALID_SENSOR_MAP(s0, s1, s2, s3) \ + .valid_sensor_mask = (((s0) ? BIT(0) : 0) | \ + ((s1) ? BIT(1) : 0) | \ + ((s2) ? BIT(2) : 0) | \ + ((s3) ? BIT(3) : 0)) + +#define lvts_for_each_valid_sensor(i, lvts_ctrl_data) \ + for ((i) = 0; (i) < LVTS_SENSOR_MAX; (i)++) \ + if (!((lvts_ctrl_data)->valid_sensor_mask & BIT(i))) \ + continue; \ + else + struct lvts_data { const struct lvts_ctrl_data *lvts_ctrl; int num_lvts_ctrl; int temp_factor; int temp_offset; + int gt_calib_bit_offset; }; struct lvts_sensor { @@ -135,7 +147,6 @@ struct lvts_ctrl { const struct lvts_data *lvts_data; u32 calibration[LVTS_SENSOR_MAX]; u32 hw_tshut_raw_temp; - int num_lvts_sensor; int mode; void __iomem *base; int low_thresh; @@ -347,7 +358,7 @@ static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high) if (high > lvts_ctrl->high_thresh) return true; - for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) + lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) return false; @@ -551,6 +562,7 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, const struct lvts_ctrl_data *lvts_ctrl_data) { struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors; + void __iomem *msr_regs[] = { LVTS_MSR0(lvts_ctrl->base), LVTS_MSR1(lvts_ctrl->base), @@ -567,7 +579,7 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, int i; - for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) { + lvts_for_each_valid_sensor(i, lvts_ctrl_data) { int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id; @@ -607,8 +619,6 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, lvts_sensor[i].high_thresh = INT_MIN; }; - lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; - return 0; } @@ -668,18 +678,31 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8-----> * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 * - * The data description gives the offset of the calibration data in - * this bytes stream for each sensor. + * Note: In some cases, values don't strictly follow a little endian ordering. + * The data description gives byte offsets constituting each calibration value + * for each sensor. */ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, const struct lvts_ctrl_data *lvts_ctrl_data, - u8 *efuse_calibration) + u8 *efuse_calibration, + size_t calib_len) { int i; - for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) - memcpy(&lvts_ctrl->calibration[i], - efuse_calibration + lvts_ctrl_data->cal_offset[i], 2); + lvts_for_each_valid_sensor(i, lvts_ctrl_data) { + const struct lvts_sensor_data *sensor = + &lvts_ctrl_data->lvts_sensor[i]; + + if (sensor->cal_offsets[0] >= calib_len || + sensor->cal_offsets[1] >= calib_len || + sensor->cal_offsets[2] >= calib_len) + return -EINVAL; + + lvts_ctrl->calibration[i] = + (efuse_calibration[sensor->cal_offsets[0]] << 0) + + (efuse_calibration[sensor->cal_offsets[1]] << 8) + + (efuse_calibration[sensor->cal_offsets[2]] << 16); + } return 0; } @@ -734,16 +757,21 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td return 0; } -static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset) +static int lvts_golden_temp_init(struct device *dev, u8 *calib, + const struct lvts_data *lvts_data) { u32 gt; - gt = (*value) >> 24; + /* + * The golden temp information is contained in the first 32-bit + * word of efuse data at a specific bit offset. + */ + gt = (((u32 *)calib)[0] >> lvts_data->gt_calib_bit_offset) & 0xff; if (gt && gt < LVTS_GOLDEN_TEMP_MAX) golden_temp = gt; - golden_temp_offset = golden_temp * 500 + temp_offset; + golden_temp_offset = golden_temp * 500 + lvts_data->temp_offset; return 0; } @@ -762,11 +790,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, if (ret) return ret; - /* - * The golden temp information is contained in the first chunk - * of efuse data. - */ - ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset); + ret = lvts_golden_temp_init(dev, lvts_td->calib, lvts_data); if (ret) return ret; @@ -786,7 +810,8 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, ret = lvts_calibration_init(dev, &lvts_ctrl[i], &lvts_data->lvts_ctrl[i], - lvts_td->calib); + lvts_td->calib, + lvts_td->calib_len); if (ret) return ret; @@ -801,7 +826,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, * after initializing the calibration. */ lvts_ctrl[i].hw_tshut_raw_temp = - lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp, + lvts_temp_to_raw(LVTS_HW_TSHUT_TEMP, lvts_data->temp_factor); lvts_ctrl[i].low_thresh = INT_MIN; @@ -1089,7 +1114,7 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? sensor_imm_bitmap : sensor_filt_bitmap; - for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { + lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) { int dt_id = lvts_sensors[i].dt_id; @@ -1302,28 +1327,32 @@ static void lvts_remove(struct platform_device *pdev) static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = { { - .cal_offset = { 0x00, 0x04, 0x08, 0x0c }, .lvts_sensor = { - { .dt_id = MT7988_CPU_0 }, - { .dt_id = MT7988_CPU_1 }, - { .dt_id = MT7988_ETH2P5G_0 }, - { .dt_id = MT7988_ETH2P5G_1 } + { .dt_id = MT7988_CPU_0, + .cal_offsets = { 0x00, 0x01, 0x02 } }, + { .dt_id = MT7988_CPU_1, + .cal_offsets = { 0x04, 0x05, 0x06 } }, + { .dt_id = MT7988_ETH2P5G_0, + .cal_offsets = { 0x08, 0x09, 0x0a } }, + { .dt_id = MT7988_ETH2P5G_1, + .cal_offsets = { 0x0c, 0x0d, 0x0e } } }, - .num_lvts_sensor = 4, + VALID_SENSOR_MAP(1, 1, 1, 1), .offset = 0x0, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, }, { - .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, .lvts_sensor = { - { .dt_id = MT7988_TOPS_0}, - { .dt_id = MT7988_TOPS_1}, - { .dt_id = MT7988_ETHWARP_0}, - { .dt_id = MT7988_ETHWARP_1} + { .dt_id = MT7988_TOPS_0, + .cal_offsets = { 0x14, 0x15, 0x16 } }, + { .dt_id = MT7988_TOPS_1, + .cal_offsets = { 0x18, 0x19, 0x1a } }, + { .dt_id = MT7988_ETHWARP_0, + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, + { .dt_id = MT7988_ETHWARP_1, + .cal_offsets = { 0x20, 0x21, 0x22 } } }, - .num_lvts_sensor = 4, + VALID_SENSOR_MAP(1, 1, 1, 1), .offset = 0x100, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, } }; @@ -1359,164 +1388,301 @@ static int lvts_resume(struct device *dev) return 0; } +/* + * The MT8186 calibration data is stored as packed 3-byte little-endian + * values using a weird layout that makes sense only when viewed as a 32-bit + * hexadecimal word dump. Let's suppose SxBy where x = sensor number and + * y = byte number where the LSB is y=0. We then have: + * + * [S0B2-S0B1-S0B0-S1B2] [S1B1-S1B0-S2B2-S2B1] [S2B0-S3B2-S3B1-S3B0] + * + * However, when considering a byte stream, those appear as follows: + * + * [S1B2] [S0B0[ [S0B1] [S0B2] [S2B1] [S2B2] [S1B0] [S1B1] [S3B0] [S3B1] [S3B2] [S2B0] + * + * Hence the rather confusing offsets provided below. + */ +static const struct lvts_ctrl_data mt8186_lvts_data_ctrl[] = { + { + .lvts_sensor = { + { .dt_id = MT8186_LITTLE_CPU0, + .cal_offsets = { 5, 6, 7 } }, + { .dt_id = MT8186_LITTLE_CPU1, + .cal_offsets = { 10, 11, 4 } }, + { .dt_id = MT8186_LITTLE_CPU2, + .cal_offsets = { 15, 8, 9 } }, + { .dt_id = MT8186_CAM, + .cal_offsets = { 12, 13, 14 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x0, + }, + { + .lvts_sensor = { + { .dt_id = MT8186_BIG_CPU0, + .cal_offsets = { 22, 23, 16 } }, + { .dt_id = MT8186_BIG_CPU1, + .cal_offsets = { 27, 20, 21 } } + }, + VALID_SENSOR_MAP(1, 1, 0, 0), + .offset = 0x100, + }, + { + .lvts_sensor = { + { .dt_id = MT8186_NNA, + .cal_offsets = { 29, 30, 31 } }, + { .dt_id = MT8186_ADSP, + .cal_offsets = { 34, 35, 28 } }, + { .dt_id = MT8186_MFG, + .cal_offsets = { 39, 32, 33 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 0), + .offset = 0x200, + } +}; + +static const struct lvts_ctrl_data mt8188_lvts_mcu_data_ctrl[] = { + { + .lvts_sensor = { + { .dt_id = MT8188_MCU_LITTLE_CPU0, + .cal_offsets = { 22, 23, 24 } }, + { .dt_id = MT8188_MCU_LITTLE_CPU1, + .cal_offsets = { 25, 26, 27 } }, + { .dt_id = MT8188_MCU_LITTLE_CPU2, + .cal_offsets = { 28, 29, 30 } }, + { .dt_id = MT8188_MCU_LITTLE_CPU3, + .cal_offsets = { 31, 32, 33 } }, + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x0, + .mode = LVTS_MSR_FILTERED_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8188_MCU_BIG_CPU0, + .cal_offsets = { 34, 35, 36 } }, + { .dt_id = MT8188_MCU_BIG_CPU1, + .cal_offsets = { 37, 38, 39 } }, + }, + VALID_SENSOR_MAP(1, 1, 0, 0), + .offset = 0x100, + .mode = LVTS_MSR_FILTERED_MODE, + } +}; + +static const struct lvts_ctrl_data mt8188_lvts_ap_data_ctrl[] = { + { + .lvts_sensor = { + + { /* unused */ }, + { .dt_id = MT8188_AP_APU, + .cal_offsets = { 40, 41, 42 } }, + }, + VALID_SENSOR_MAP(0, 1, 0, 0), + .offset = 0x0, + .mode = LVTS_MSR_FILTERED_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8188_AP_GPU1, + .cal_offsets = { 43, 44, 45 } }, + { .dt_id = MT8188_AP_GPU2, + .cal_offsets = { 46, 47, 48 } }, + { .dt_id = MT8188_AP_SOC1, + .cal_offsets = { 49, 50, 51 } }, + }, + VALID_SENSOR_MAP(1, 1, 1, 0), + .offset = 0x100, + .mode = LVTS_MSR_FILTERED_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8188_AP_SOC2, + .cal_offsets = { 52, 53, 54 } }, + { .dt_id = MT8188_AP_SOC3, + .cal_offsets = { 55, 56, 57 } }, + }, + VALID_SENSOR_MAP(1, 1, 0, 0), + .offset = 0x200, + .mode = LVTS_MSR_FILTERED_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8188_AP_CAM1, + .cal_offsets = { 58, 59, 60 } }, + { .dt_id = MT8188_AP_CAM2, + .cal_offsets = { 61, 62, 63 } }, + }, + VALID_SENSOR_MAP(1, 1, 0, 0), + .offset = 0x300, + .mode = LVTS_MSR_FILTERED_MODE, + } +}; + static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = { { - .cal_offset = { 0x04, 0x08 }, .lvts_sensor = { - { .dt_id = MT8192_MCU_BIG_CPU0 }, - { .dt_id = MT8192_MCU_BIG_CPU1 } + { .dt_id = MT8192_MCU_BIG_CPU0, + .cal_offsets = { 0x04, 0x05, 0x06 } }, + { .dt_id = MT8192_MCU_BIG_CPU1, + .cal_offsets = { 0x08, 0x09, 0x0a } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x0, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, .mode = LVTS_MSR_FILTERED_MODE, }, { - .cal_offset = { 0x0c, 0x10 }, .lvts_sensor = { - { .dt_id = MT8192_MCU_BIG_CPU2 }, - { .dt_id = MT8192_MCU_BIG_CPU3 } + { .dt_id = MT8192_MCU_BIG_CPU2, + .cal_offsets = { 0x0c, 0x0d, 0x0e } }, + { .dt_id = MT8192_MCU_BIG_CPU3, + .cal_offsets = { 0x10, 0x11, 0x12 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x100, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, .mode = LVTS_MSR_FILTERED_MODE, }, { - .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, .lvts_sensor = { - { .dt_id = MT8192_MCU_LITTLE_CPU0 }, - { .dt_id = MT8192_MCU_LITTLE_CPU1 }, - { .dt_id = MT8192_MCU_LITTLE_CPU2 }, - { .dt_id = MT8192_MCU_LITTLE_CPU3 } + { .dt_id = MT8192_MCU_LITTLE_CPU0, + .cal_offsets = { 0x14, 0x15, 0x16 } }, + { .dt_id = MT8192_MCU_LITTLE_CPU1, + .cal_offsets = { 0x18, 0x19, 0x1a } }, + { .dt_id = MT8192_MCU_LITTLE_CPU2, + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, + { .dt_id = MT8192_MCU_LITTLE_CPU3, + .cal_offsets = { 0x20, 0x21, 0x22 } } }, - .num_lvts_sensor = 4, + VALID_SENSOR_MAP(1, 1, 1, 1), .offset = 0x200, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, .mode = LVTS_MSR_FILTERED_MODE, } }; static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = { - { - .cal_offset = { 0x24, 0x28 }, + { .lvts_sensor = { - { .dt_id = MT8192_AP_VPU0 }, - { .dt_id = MT8192_AP_VPU1 } + { .dt_id = MT8192_AP_VPU0, + .cal_offsets = { 0x24, 0x25, 0x26 } }, + { .dt_id = MT8192_AP_VPU1, + .cal_offsets = { 0x28, 0x29, 0x2a } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x0, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, }, { - .cal_offset = { 0x2c, 0x30 }, .lvts_sensor = { - { .dt_id = MT8192_AP_GPU0 }, - { .dt_id = MT8192_AP_GPU1 } + { .dt_id = MT8192_AP_GPU0, + .cal_offsets = { 0x2c, 0x2d, 0x2e } }, + { .dt_id = MT8192_AP_GPU1, + .cal_offsets = { 0x30, 0x31, 0x32 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x100, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, }, { - .cal_offset = { 0x34, 0x38 }, .lvts_sensor = { - { .dt_id = MT8192_AP_INFRA }, - { .dt_id = MT8192_AP_CAM }, + { .dt_id = MT8192_AP_INFRA, + .cal_offsets = { 0x34, 0x35, 0x36 } }, + { .dt_id = MT8192_AP_CAM, + .cal_offsets = { 0x38, 0x39, 0x3a } }, }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x200, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, }, { - .cal_offset = { 0x3c, 0x40, 0x44 }, .lvts_sensor = { - { .dt_id = MT8192_AP_MD0 }, - { .dt_id = MT8192_AP_MD1 }, - { .dt_id = MT8192_AP_MD2 } + { .dt_id = MT8192_AP_MD0, + .cal_offsets = { 0x3c, 0x3d, 0x3e } }, + { .dt_id = MT8192_AP_MD1, + .cal_offsets = { 0x40, 0x41, 0x42 } }, + { .dt_id = MT8192_AP_MD2, + .cal_offsets = { 0x44, 0x45, 0x46 } } }, - .num_lvts_sensor = 3, + VALID_SENSOR_MAP(1, 1, 1, 0), .offset = 0x300, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, } }; static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { { - .cal_offset = { 0x04, 0x07 }, .lvts_sensor = { - { .dt_id = MT8195_MCU_BIG_CPU0 }, - { .dt_id = MT8195_MCU_BIG_CPU1 } + { .dt_id = MT8195_MCU_BIG_CPU0, + .cal_offsets = { 0x04, 0x05, 0x06 } }, + { .dt_id = MT8195_MCU_BIG_CPU1, + .cal_offsets = { 0x07, 0x08, 0x09 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x0, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, }, { - .cal_offset = { 0x0d, 0x10 }, .lvts_sensor = { - { .dt_id = MT8195_MCU_BIG_CPU2 }, - { .dt_id = MT8195_MCU_BIG_CPU3 } + { .dt_id = MT8195_MCU_BIG_CPU2, + .cal_offsets = { 0x0d, 0x0e, 0x0f } }, + { .dt_id = MT8195_MCU_BIG_CPU3, + .cal_offsets = { 0x10, 0x11, 0x12 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x100, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, }, { - .cal_offset = { 0x16, 0x19, 0x1c, 0x1f }, .lvts_sensor = { - { .dt_id = MT8195_MCU_LITTLE_CPU0 }, - { .dt_id = MT8195_MCU_LITTLE_CPU1 }, - { .dt_id = MT8195_MCU_LITTLE_CPU2 }, - { .dt_id = MT8195_MCU_LITTLE_CPU3 } + { .dt_id = MT8195_MCU_LITTLE_CPU0, + .cal_offsets = { 0x16, 0x17, 0x18 } }, + { .dt_id = MT8195_MCU_LITTLE_CPU1, + .cal_offsets = { 0x19, 0x1a, 0x1b } }, + { .dt_id = MT8195_MCU_LITTLE_CPU2, + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, + { .dt_id = MT8195_MCU_LITTLE_CPU3, + .cal_offsets = { 0x1f, 0x20, 0x21 } } }, - .num_lvts_sensor = 4, + VALID_SENSOR_MAP(1, 1, 1, 1), .offset = 0x200, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, } }; static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = { - { - .cal_offset = { 0x25, 0x28 }, + { .lvts_sensor = { - { .dt_id = MT8195_AP_VPU0 }, - { .dt_id = MT8195_AP_VPU1 } + { .dt_id = MT8195_AP_VPU0, + .cal_offsets = { 0x25, 0x26, 0x27 } }, + { .dt_id = MT8195_AP_VPU1, + .cal_offsets = { 0x28, 0x29, 0x2a } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x0, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, }, { - .cal_offset = { 0x2e, 0x31 }, .lvts_sensor = { - { .dt_id = MT8195_AP_GPU0 }, - { .dt_id = MT8195_AP_GPU1 } + { .dt_id = MT8195_AP_GPU0, + .cal_offsets = { 0x2e, 0x2f, 0x30 } }, + { .dt_id = MT8195_AP_GPU1, + .cal_offsets = { 0x31, 0x32, 0x33 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x100, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, }, { - .cal_offset = { 0x37, 0x3a, 0x3d }, .lvts_sensor = { - { .dt_id = MT8195_AP_VDEC }, - { .dt_id = MT8195_AP_IMG }, - { .dt_id = MT8195_AP_INFRA }, + { .dt_id = MT8195_AP_VDEC, + .cal_offsets = { 0x37, 0x38, 0x39 } }, + { .dt_id = MT8195_AP_IMG, + .cal_offsets = { 0x3a, 0x3b, 0x3c } }, + { .dt_id = MT8195_AP_INFRA, + .cal_offsets = { 0x3d, 0x3e, 0x3f } } }, - .num_lvts_sensor = 3, + VALID_SENSOR_MAP(1, 1, 1, 0), .offset = 0x200, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, }, { - .cal_offset = { 0x43, 0x46 }, .lvts_sensor = { - { .dt_id = MT8195_AP_CAM0 }, - { .dt_id = MT8195_AP_CAM1 } + { .dt_id = MT8195_AP_CAM0, + .cal_offsets = { 0x43, 0x44, 0x45 } }, + { .dt_id = MT8195_AP_CAM1, + .cal_offsets = { 0x46, 0x47, 0x48 } } }, - .num_lvts_sensor = 2, + VALID_SENSOR_MAP(1, 1, 0, 0), .offset = 0x300, - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, } }; @@ -1525,16 +1691,47 @@ static const struct lvts_data mt7988_lvts_ap_data = { .num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl), .temp_factor = LVTS_COEFF_A_MT7988, .temp_offset = LVTS_COEFF_B_MT7988, + .gt_calib_bit_offset = 24, +}; + +static const struct lvts_data mt8186_lvts_data = { + .lvts_ctrl = mt8186_lvts_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8186_lvts_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT7988, + .temp_offset = LVTS_COEFF_B_MT7988, + .gt_calib_bit_offset = 24, +}; + +static const struct lvts_data mt8188_lvts_mcu_data = { + .lvts_ctrl = mt8188_lvts_mcu_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_mcu_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8195, + .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 20, +}; + +static const struct lvts_data mt8188_lvts_ap_data = { + .lvts_ctrl = mt8188_lvts_ap_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_ap_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8195, + .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 20, }; static const struct lvts_data mt8192_lvts_mcu_data = { .lvts_ctrl = mt8192_lvts_mcu_data_ctrl, .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8195, + .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 24, }; static const struct lvts_data mt8192_lvts_ap_data = { .lvts_ctrl = mt8192_lvts_ap_data_ctrl, .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8195, + .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 24, }; static const struct lvts_data mt8195_lvts_mcu_data = { @@ -1542,6 +1739,7 @@ static const struct lvts_data mt8195_lvts_mcu_data = { .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), .temp_factor = LVTS_COEFF_A_MT8195, .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 24, }; static const struct lvts_data mt8195_lvts_ap_data = { @@ -1549,10 +1747,14 @@ static const struct lvts_data mt8195_lvts_ap_data = { .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl), .temp_factor = LVTS_COEFF_A_MT8195, .temp_offset = LVTS_COEFF_B_MT8195, + .gt_calib_bit_offset = 24, }; static const struct of_device_id lvts_of_match[] = { { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, + { .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data }, + { .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data }, + { .compatible = "mediatek,mt8188-lvts-ap", .data = &mt8188_lvts_ap_data }, { .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data }, { .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data }, { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, diff --git a/drivers/thermal/qcom/lmh.c b/drivers/thermal/qcom/lmh.c index f6edb12ec004..5225b3621a56 100644 --- a/drivers/thermal/qcom/lmh.c +++ b/drivers/thermal/qcom/lmh.c @@ -95,6 +95,9 @@ static int lmh_probe(struct platform_device *pdev) unsigned int enable_alg; u32 node_id; + if (!qcom_scm_is_available()) + return -EPROBE_DEFER; + lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL); if (!lmh_data) return -ENOMEM; diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c index 78c5cfe6a0c0..3cd74f6cac8f 100644 --- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c @@ -74,7 +74,6 @@ struct qpnp_tm_chip { long temp; unsigned int thresh; unsigned int stage; - unsigned int prev_stage; unsigned int base; /* protects .thresh, .stage and chip registers */ struct mutex lock; diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 29a61d2d6ca3..0cb7301eca6e 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -107,6 +107,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { static const struct tsens_ops ops_generic_v2 = { .init = init_common, .get_temp = get_temp_tsens_valid, + .resume = tsens_resume_common, }; struct tsens_plat_data data_tsens_v2 = { diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 6d7c16ccb44d..e76e23026dc8 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -17,6 +17,7 @@ #include <linux/pm.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <linux/thermal.h> #include "../thermal_hwmon.h" #include "tsens.h" @@ -264,7 +265,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, for (i = 0; i < priv->num_sensors; i++) { dev_dbg(priv->dev, "%s: sensor%d - data_point1:%#x data_point2:%#x\n", - __func__, i, p1[i], p2[i]); + __func__, i, p1[i], p2 ? p2[i] : 0); if (!priv->sensor[i].slope) priv->sensor[i].slope = SLOPE_DEFAULT; @@ -1193,6 +1194,36 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname, return ret; } +#ifdef CONFIG_SUSPEND +static int tsens_reinit(struct tsens_priv *priv) +{ + if (tsens_version(priv) >= VER_2_X) { + /* + * Re-enable the watchdog, unmask the bark. + * Disable cycle completion monitoring + */ + if (priv->feat->has_watchdog) { + regmap_field_write(priv->rf[WDOG_BARK_MASK], 0); + regmap_field_write(priv->rf[CC_MON_MASK], 1); + } + + /* Re-enable interrupts */ + tsens_enable_irq(priv); + } + + return 0; +} + +int tsens_resume_common(struct tsens_priv *priv) +{ + if (pm_suspend_target_state == PM_SUSPEND_MEM) + tsens_reinit(priv); + + return 0; +} + +#endif /* !CONFIG_SUSPEND */ + static int tsens_register(struct tsens_priv *priv) { int i, ret; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index cb637fa289ca..cab39de045b1 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -634,6 +634,11 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mo int init_common(struct tsens_priv *priv); int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp); int get_temp_common(const struct tsens_sensor *s, int *temp); +#ifdef CONFIG_SUSPEND +int tsens_resume_common(struct tsens_priv *priv); +#else +#define tsens_resume_common NULL +#endif /* TSENS target */ extern struct tsens_plat_data data_8960; diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index a764cb1115a5..02494fa142c3 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -65,26 +65,29 @@ #define TSC_MAX_NUM 5 -/* Structure for thermal temperature calculation */ -struct equation_coefs { - int a1; - int b1; - int a2; - int b2; -}; - struct rcar_gen3_thermal_priv; struct rcar_thermal_info { - int ths_tj_1; + int scale; + int adj_below; + int adj_above; void (*read_fuses)(struct rcar_gen3_thermal_priv *priv); }; +struct equation_set_coef { + int a; + int b; +}; + struct rcar_gen3_thermal_tsc { + struct rcar_gen3_thermal_priv *priv; void __iomem *base; struct thermal_zone_device *zone; - struct equation_coefs coef; - int tj_t; + /* Different coefficients are used depending on a threshold. */ + struct { + struct equation_set_coef below; + struct equation_set_coef above; + } coef; int thcode[3]; }; @@ -93,6 +96,7 @@ struct rcar_gen3_thermal_priv { struct thermal_zone_device_ops ops; unsigned int num_tscs; int ptat[3]; + int tj_t; const struct rcar_thermal_info *info; }; @@ -111,84 +115,75 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, /* * Linear approximation for temperature * - * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a + * [temp] = ((thadj - [reg]) * a) / b + adj + * [reg] = thadj - ([temp] - adj) * b / a * * The constants a and b are calculated using two triplets of int values PTAT * and THCODE. PTAT and THCODE can either be read from hardware or use hard - * coded values from driver. The formula to calculate a and b are taken from - * BSP and sparsely documented and understood. + * coded values from the driver. The formula to calculate a and b are taken from + * the datasheet. Different calculations are needed for a and b depending on + * if the input variables ([temp] or [reg]) are above or below a threshold. The + * threshold is also calculated from PTAT and THCODE using formulas from the + * datasheet. + * + * The constant thadj is one of the THCODE values, which one to use depends on + * the threshold and input value. * - * Examining the linear formula and the formula used to calculate constants a - * and b while knowing that the span for PTAT and THCODE values are between - * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001. - * Integer also needs to be signed so that leaves 7 bits for binary - * fixed point scaling. + * The constants adj is taken verbatim from the datasheet. Two values exists, + * which one to use depends on the input value and the calculated threshold. + * Furthermore different SoC models supported by the driver have different sets + * of values. The values for each model are stored in the device match data. */ -#define FIXPT_SHIFT 7 -#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT) -#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT) -#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b)) -#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT) - -#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ - -/* no idea where these constants come from */ -#define TJ_3 -41 - -static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv, - struct rcar_gen3_thermal_tsc *tsc, - int ths_tj_1) +static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv) { - /* TODO: Find documentation and document constant calculation formula */ - - /* - * Division is not scaled in BSP and if scaled it might overflow - * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled - */ - tsc->tj_t = (FIXPT_INT((priv->ptat[1] - priv->ptat[2]) * (ths_tj_1 - TJ_3)) - / (priv->ptat[0] - priv->ptat[2])) + FIXPT_INT(TJ_3); - - tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[2]), - tsc->tj_t - FIXPT_INT(TJ_3)); - tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3; - - tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[0]), - tsc->tj_t - FIXPT_INT(ths_tj_1)); - tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1; + priv->tj_t = + DIV_ROUND_CLOSEST((priv->ptat[1] - priv->ptat[2]) * priv->info->scale, + priv->ptat[0] - priv->ptat[2]) + + priv->info->adj_below; } - -static int rcar_gen3_thermal_round(int temp) +static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv, + struct rcar_gen3_thermal_tsc *tsc) { - int result, round_offs; + tsc->coef.below.a = priv->info->scale * (priv->ptat[2] - priv->ptat[1]); + tsc->coef.above.a = priv->info->scale * (priv->ptat[0] - priv->ptat[1]); - round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 : - -RCAR3_THERMAL_GRAN / 2; - result = (temp + round_offs) / RCAR3_THERMAL_GRAN; - return result * RCAR3_THERMAL_GRAN; + tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]); + tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]); } static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp) { struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz); - int mcelsius, val; - int reg; + struct rcar_gen3_thermal_priv *priv = tsc->priv; + const struct equation_set_coef *coef; + int adj, decicelsius, reg, thcode; /* Read register and convert to mili Celsius */ reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; - if (reg <= tsc->thcode[1]) - val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, - tsc->coef.a1); - else - val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, - tsc->coef.a2); - mcelsius = FIXPT_TO_MCELSIUS(val); + if (reg < tsc->thcode[1]) { + adj = priv->info->adj_below; + coef = &tsc->coef.below; + thcode = tsc->thcode[2]; + } else { + adj = priv->info->adj_above; + coef = &tsc->coef.above; + thcode = tsc->thcode[0]; + } + + /* + * The dividend can't be grown as it might overflow, instead shorten the + * divisor to convert to decidegree Celsius. If we convert after the + * division precision is lost as we will scale up from whole degrees + * Celsius. + */ + decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10); /* Guaranteed operating range is -40C to 125C. */ - /* Round value to device granularity setting */ - *temp = rcar_gen3_thermal_round(mcelsius); + /* Reporting is done in millidegree Celsius */ + *temp = decicelsius * 100 + adj * 1000; return 0; } @@ -196,15 +191,22 @@ static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp) static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, int mcelsius) { - int celsius, val; + struct rcar_gen3_thermal_priv *priv = tsc->priv; + const struct equation_set_coef *coef; + int adj, celsius, thcode; celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); - if (celsius <= INT_FIXPT(tsc->tj_t)) - val = celsius * tsc->coef.a1 + tsc->coef.b1; - else - val = celsius * tsc->coef.a2 + tsc->coef.b2; + if (celsius < priv->tj_t) { + coef = &tsc->coef.below; + adj = priv->info->adj_below; + thcode = tsc->thcode[2]; + } else { + coef = &tsc->coef.above; + adj = priv->info->adj_above; + thcode = tsc->thcode[0]; + } - return INT_FIXPT(val); + return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a); } static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high) @@ -369,17 +371,23 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv, } static const struct rcar_thermal_info rcar_m3w_thermal_info = { - .ths_tj_1 = 116, + .scale = 157, + .adj_below = -41, + .adj_above = 116, .read_fuses = rcar_gen3_thermal_read_fuses_gen3, }; static const struct rcar_thermal_info rcar_gen3_thermal_info = { - .ths_tj_1 = 126, + .scale = 167, + .adj_below = -41, + .adj_above = 126, .read_fuses = rcar_gen3_thermal_read_fuses_gen3, }; static const struct rcar_thermal_info rcar_gen4_thermal_info = { - .ths_tj_1 = 126, + .scale = 167, + .adj_below = -41, + .adj_above = 126, .read_fuses = rcar_gen3_thermal_read_fuses_gen4, }; @@ -516,6 +524,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) goto error_unregister; } + tsc->priv = priv; tsc->base = devm_ioremap_resource(dev, res); if (IS_ERR(tsc->base)) { ret = PTR_ERR(tsc->base); @@ -530,11 +539,13 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (!rcar_gen3_thermal_read_fuses(priv)) dev_info(dev, "No calibration values fused, fallback to driver values\n"); + rcar_gen3_thermal_shared_coefs(priv); + for (i = 0; i < priv->num_tscs; i++) { struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; rcar_gen3_thermal_init(priv, tsc); - rcar_gen3_thermal_calc_coefs(priv, tsc, priv->info->ths_tj_1); + rcar_gen3_thermal_tsc_coefs(priv, tsc); zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops); if (IS_ERR(zone)) { diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h index 997e2f55128a..bf95309d2525 100644 --- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h +++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h @@ -16,6 +16,32 @@ #define MT7988_ETHWARP_0 6 #define MT7988_ETHWARP_1 7 +#define MT8186_LITTLE_CPU0 0 +#define MT8186_LITTLE_CPU1 1 +#define MT8186_LITTLE_CPU2 2 +#define MT8186_CAM 3 +#define MT8186_BIG_CPU0 4 +#define MT8186_BIG_CPU1 5 +#define MT8186_NNA 6 +#define MT8186_ADSP 7 +#define MT8186_MFG 8 + +#define MT8188_MCU_LITTLE_CPU0 0 +#define MT8188_MCU_LITTLE_CPU1 1 +#define MT8188_MCU_LITTLE_CPU2 2 +#define MT8188_MCU_LITTLE_CPU3 3 +#define MT8188_MCU_BIG_CPU0 4 +#define MT8188_MCU_BIG_CPU1 5 + +#define MT8188_AP_APU 0 +#define MT8188_AP_GPU1 1 +#define MT8188_AP_GPU2 2 +#define MT8188_AP_SOC1 3 +#define MT8188_AP_SOC2 4 +#define MT8188_AP_SOC3 5 +#define MT8188_AP_CAM1 6 +#define MT8188_AP_CAM2 7 + #define MT8195_MCU_BIG_CPU0 0 #define MT8195_MCU_BIG_CPU1 1 #define MT8195_MCU_BIG_CPU2 2 |