- Add QCM2290 compatible DT bindings for Lmh and fix a null pointer

dereference in the lmh driver in case the SCM is not present (Konrad
   Dybcio)
 
 - Use the strreplace() function instead of doing it manually in the
   Armada driver (Rasmus Villemoes)
 
 - Convert st,stih407-thermal to DT schema and fix up missing
   properties (Raphael Gallais-Pou)
 
 - Add suspend/resume by restoring the context of the tsens sensor
   (Priyansh Jain)
 
 - Support A1 SoC family Thermal Sensor controller and add the DT
   bindings (Dmitry Rokosov)
 
 - Improve the temperature approximation calculation and consolidate
   the Tj constant into a shared area of the structure instead of
   duplicating it on the Rcar Gen3 (Niklas Söderlund)
 
 - Fix the Mediatek LVTS sensor coefficient for the MT8192 in order to support
   it correctly (Hsin-Te Yuan)
 
 - Fix a null pointer dereference on the tsens driver when the function
   compute_intercept_slope() is called with a null parameter (Aleksandr
   Mishin)
 
 - Remove some unused fields in struct qpnp_tm_chip and k3_bandgap
   (Christophe Jaillet)
 
 - Fixup calibration efuse data decoding, consolidate the code by
   checking boundaries and refactor some part of the LVTS Mediatek
   driver. After setting the scene, add MT8186 and MT8188 along with
   the DT bindings (Nicolas Pitre)
 
 - Add Loongson-2K2000 support after some minor code adjustements and
   providing the DT bindings definition (Binbin Zhou)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmYzYJQACgkQqDIjiipP
 6E+siAgAjU4QO9x+akio7f2WeDbCUe5mCmVEcVxeoVumRw119I1PThRqN0fiZ2H9
 qjSy8/dDuXMYRMK2NBE51wPq8I7bD3SDUiPSqaL6eNyKJYMSr6ZcuJgBWNEYgwSv
 laeldN4h83+DGfp+UcZWfEEr8tnGv5SGCQ5htGFB3QOiQLBaUqdkObzrGvROeT92
 pZMX18+ryKr/5k/e9DkOPwPObcfLkzb8w1m8UOZeRwjt+fyFKdZbdp9s7GTtPiZc
 ULrhCwigYPWLD4GhS6My3V80eZyNNtO/UuEojKQyOpY/gKifHtKQViGv7DhPbDQA
 3goodE7tTiQjeEYPg7Dx2p/twsBAPA==
 =nDt+
 -----END PGP SIGNATURE-----

Merge tag 'thermal-v6.10-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux into thermal

Merge updates of thermal drivers for v6.10 from Daniel Lezcano:

"- Add QCM2290 compatible DT bindings for Lmh and fix a null pointer
   dereference in the lmh driver in case the SCM is not present (Konrad
   Dybcio)

 - Use the strreplace() function instead of doing it manually in the
   Armada driver (Rasmus Villemoes)

 - Convert st,stih407-thermal to DT schema and fix up missing
   properties (Raphael Gallais-Pou)

 - Add suspend/resume by restoring the context of the tsens sensor
   (Priyansh Jain)

 - Support A1 SoC family Thermal Sensor controller and add the DT
   bindings (Dmitry Rokosov)

 - Improve the temperature approximation calculation and consolidate
   the Tj constant into a shared area of the structure instead of
   duplicating it on the Rcar Gen3 (Niklas Söderlund)

 - Fix the Mediatek LVTS sensor coefficient for the MT8192 in order to support
   it correctly (Hsin-Te Yuan)

 - Fix a null pointer dereference on the tsens driver when the function
   compute_intercept_slope() is called with a null parameter (Aleksandr
   Mishin)

 - Remove some unused fields in struct qpnp_tm_chip and k3_bandgap
   (Christophe Jaillet)

 - Fixup calibration efuse data decoding, consolidate the code by
   checking boundaries and refactor some part of the LVTS Mediatek
   driver. After setting the scene, add MT8186 and MT8188 along with
   the DT bindings (Nicolas Pitre)

 - Add Loongson-2K2000 support after some minor code adjustements and
   providing the DT bindings definition (Binbin Zhou)"

* tag 'thermal-v6.10-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (28 commits)
  thermal/drivers/loongson2: Add Loongson-2K2000 support
  dt-bindings: thermal: loongson,ls2k-thermal: Fix incorrect compatible definition
  dt-bindings: thermal: loongson,ls2k-thermal: Add Loongson-2K0500 compatible
  thermal/drivers/loongson2: Trivial code style adjustment
  thermal/drivers/mediatek/lvts_thermal: Add MT8188 support
  dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT8188
  thermal/drivers/mediatek/lvts_thermal: Allow early empty sensor slots
  thermal/drivers/mediatek/lvts_thermal: Provision for gt variable location
  thermal/drivers/mediatek/lvts_thermal: Add MT8186 support
  dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT8186
  thermal/drivers/mediatek/lvts_thermal: Guard against efuse data buffer overflow
  thermal/drivers/mediatek/lvts_thermal: Use offsets for every calibration byte
  thermal/drivers/mediatek/lvts_thermal: Remove .hw_tshut_temp
  thermal/drivers/mediatek/lvts_thermal: Move comment
  thermal/drivers/mediatek/lvts_thermal: Retrieve all calibration bytes
  thermal/drivers/k3_bandgap: Remove some unused fields in struct k3_bandgap
  thermal/drivers/qcom: Remove some unused fields in struct qpnp_tm_chip
  thermal/drivers/tsens: Fix null pointer dereference
  thermal/drivers/mediatek/lvts_thermal: Add coeff for mt8192
  thermal/drivers/rcar_gen3: Update temperature approximation calculation
  ...
This commit is contained in:
Rafael J. Wysocki 2024-05-02 12:37:15 +02:00
commit e1242ff043
18 changed files with 669 additions and 288 deletions

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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>;
};
...

View File

@ -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>;
};

View File

@ -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);

View File

@ -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, '-', '_');
}
/*

View File

@ -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 */

View File

@ -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_OUT_MASK 0xFF
#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
/*
* 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 int loongson2_thermal_set(struct loongson2_thermal_data *data,
int low, int high, bool enable)
static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data,
int ctrl_data, bool low, bool enable)
{
u64 reg_ctrl = 0;
int reg_off = data->chip_data->thermal_sensor_sel * 2;
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;
low = clamp(-40, low, high);
high = clamp(125, low, high);
low += HECTO;
high += HECTO;
reg_ctrl = low;
reg_ctrl = ctrl_data + HECTO;
reg_ctrl |= enable ? 0x100 : 0;
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off);
writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
}
reg_ctrl = high;
reg_ctrl |= enable ? 0x100 : 0;
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off);
static int loongson2_thermal_set(struct loongson2_thermal_data *data,
int low, int high, bool enable)
{
/* Set low temperature threshold */
loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable);
/* Set high temperature threshold */
loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable);
return 0;
}
static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
static int loongson2_2k1000_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->ctrl_reg + LOONGSON2_THSENS_OUT_REG);
*temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;
return 0;
}
static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)
{
int val;
struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
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");

View File

@ -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 },

View File

@ -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;

View File

@ -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;

View File

@ -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 = {

View File

@ -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;

View File

@ -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;

View File

@ -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.
*
* 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 constant thadj is one of the THCODE values, which one to use depends on
* the threshold and input value.
*
* 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)) {

View File

@ -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