From 69c560d2eb3cff7ebe876cd224a3dc05852990b5 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Mon, 20 Sep 2021 22:38:49 +0200 Subject: [PATCH 01/18] thermal/drivers/thermal_mmio: Constify static struct thermal_mmio_ops The only usage of thermal_mmio_ops is to pass its address to devm_thermal_zone_of_sensor_register(), which has a pointer to const struct thermal_zone_of_device_ops as argument. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Acked-by: Talel Shenhar Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210920203849.32136-1-rikard.falkeborn@gmail.com --- drivers/thermal/thermal_mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/thermal_mmio.c b/drivers/thermal/thermal_mmio.c index ded1dd0d4ef7..360b0dfdc3b0 100644 --- a/drivers/thermal/thermal_mmio.c +++ b/drivers/thermal/thermal_mmio.c @@ -34,7 +34,7 @@ static int thermal_mmio_get_temperature(void *private, int *temp) return 0; } -static struct thermal_zone_of_device_ops thermal_mmio_ops = { +static const struct thermal_zone_of_device_ops thermal_mmio_ops = { .get_temp = thermal_mmio_get_temperature, }; From fc656fa14da7865774b4251afa88ffcf22bf02d2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sat, 2 Oct 2021 00:33:23 +0200 Subject: [PATCH 02/18] thermal/drivers/netlink: Add the temperature when crossing a trip point The slope of the temperature increase or decrease can be high and when the temperature crosses the trip point, there could be a significant difference between the trip temperature and the measured temperatures. That forces the userspace to read the temperature back right after receiving a trip violation notification. In order to be efficient, give the temperature which resulted in the trip violation. Signed-off-by: Daniel Lezcano Acked-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20211001223323.1836640-1-daniel.lezcano@linaro.org --- drivers/thermal/thermal_core.c | 6 ++++-- drivers/thermal/thermal_netlink.c | 11 ++++++----- drivers/thermal/thermal_netlink.h | 8 ++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 51374f4e1cca..9e243d9f929e 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -375,10 +375,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) if (tz->last_temperature != THERMAL_TEMP_INVALID) { if (tz->last_temperature < trip_temp && tz->temperature >= trip_temp) - thermal_notify_tz_trip_up(tz->id, trip); + thermal_notify_tz_trip_up(tz->id, trip, + tz->temperature); if (tz->last_temperature >= trip_temp && tz->temperature < (trip_temp - hyst)) - thermal_notify_tz_trip_down(tz->id, trip); + thermal_notify_tz_trip_down(tz->id, trip, + tz->temperature); } if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c index 1234dbe95895..a16dd4d5d710 100644 --- a/drivers/thermal/thermal_netlink.c +++ b/drivers/thermal/thermal_netlink.c @@ -121,7 +121,8 @@ static int thermal_genl_event_tz(struct param *p) static int thermal_genl_event_tz_trip_up(struct param *p) { if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || - nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp)) return -EMSGSIZE; return 0; @@ -285,16 +286,16 @@ int thermal_notify_tz_disable(int tz_id) return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); } -int thermal_notify_tz_trip_down(int tz_id, int trip_id) +int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp) { - struct param p = { .tz_id = tz_id, .trip_id = trip_id }; + struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); } -int thermal_notify_tz_trip_up(int tz_id, int trip_id) +int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp) { - struct param p = { .tz_id = tz_id, .trip_id = trip_id }; + struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); } diff --git a/drivers/thermal/thermal_netlink.h b/drivers/thermal/thermal_netlink.h index 828d1dddfa98..e554f76291f4 100644 --- a/drivers/thermal/thermal_netlink.h +++ b/drivers/thermal/thermal_netlink.h @@ -11,8 +11,8 @@ int thermal_notify_tz_create(int tz_id, const char *name); int thermal_notify_tz_delete(int tz_id); int thermal_notify_tz_enable(int tz_id); int thermal_notify_tz_disable(int tz_id); -int thermal_notify_tz_trip_down(int tz_id, int id); -int thermal_notify_tz_trip_up(int tz_id, int id); +int thermal_notify_tz_trip_down(int tz_id, int id, int temp); +int thermal_notify_tz_trip_up(int tz_id, int id, int temp); int thermal_notify_tz_trip_delete(int tz_id, int id); int thermal_notify_tz_trip_add(int tz_id, int id, int type, int temp, int hyst); @@ -49,12 +49,12 @@ static inline int thermal_notify_tz_disable(int tz_id) return 0; } -static inline int thermal_notify_tz_trip_down(int tz_id, int id) +static inline int thermal_notify_tz_trip_down(int tz_id, int id, int temp) { return 0; } -static inline int thermal_notify_tz_trip_up(int tz_id, int id) +static inline int thermal_notify_tz_trip_up(int tz_id, int id, int temp) { return 0; } From db03874b854368c14f21bdc41f1044cf6cda6200 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 4 Oct 2021 20:25:28 -0700 Subject: [PATCH 03/18] dt-bindings: thermal: qcom: add HC variant of adc-thermal monitor bindings The HC generation of the ADC Thermal Monitor is quite similar to the 5th generation, but differs in valid values for a few properties. Create a new binding for the HC version of the hardware, rather than sprinkle conditionals throughout the existing binding. Signed-off-by: Bjorn Andersson Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211005032531.2251928-2-bjorn.andersson@linaro.org Signed-off-by: Daniel Lezcano --- .../bindings/thermal/qcom-spmi-adc-tm-hc.yaml | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml new file mode 100644 index 000000000000..8273ac55b63f --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -0,0 +1,149 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/qcom-spmi-adc-tm-hc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm's SPMI PMIC ADC HC Thermal Monitoring +maintainers: + - Dmitry Baryshkov + +properties: + compatible: + const: qcom,spmi-adc-tm-hc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + description: + Number of cells required to uniquely identify the thermal sensors. Since + we have multiple sensors this is set to 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + qcom,avg-samples: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of samples to be used for measurement. + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + default: 1 + + qcom,decimation: + $ref: /schemas/types.yaml#/definitions/uint32 + description: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + enum: + - 256 + - 512 + - 1024 + default: 1024 + +patternProperties: + "^([-a-z0-9]*)@[0-7]$": + type: object + description: + Represent one thermal sensor. + + properties: + reg: + description: Specify the sensor channel. There are 8 channels in PMIC5's ADC TM + minimum: 0 + maximum: 7 + + io-channels: + description: + From common IIO binding. Used to pipe PMIC ADC channel to thermal monitor + + qcom,ratiometric: + $ref: /schemas/types.yaml#/definitions/flag + description: + Channel calibration type. + If this property is specified VADC will use the VDD reference + (1.875V) and GND for channel calibration. If property is not found, + channel will be calibrated with 0V and 1.25V reference channels, + also known as absolute calibration. + + qcom,hw-settle-time-us: + description: Time between AMUX getting configured and the ADC starting conversion. + enum: [0, 100, 200, 300, 400, 500, 600, 700, 1000, 2000, 4000, 6000, 8000, 10000] + + qcom,pre-scaling: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Used for scaling the channel input signal before the + signal is fed to VADC. The configuration for this node is to know the + pre-determined ratio and use it for post scaling. It is a pair of + integers, denoting the numerator and denominator of the fraction by + which input signal is multiplied. For example, <1 3> indicates the + signal is scaled down to 1/3 of its value before ADC measurement. If + property is not found default value depending on chip will be used. + items: + - const: 1 + - enum: [ 1, 3, 4, 6, 20, 8, 10 ] + + required: + - reg + - io-channels + + additionalProperties: + false + +required: + - compatible + - reg + - interrupts + - "#address-cells" + - "#size-cells" + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + #include + #include + spmi_bus { + #address-cells = <1>; + #size-cells = <0>; + pm8998_adc: adc@3100 { + reg = <0x3100>; + compatible = "qcom,spmi-adc-rev2"; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + /* Other propreties are omitted */ + adc-chan@4c { + reg = ; + }; + }; + + pm8998_adc_tm: adc-tm@3400 { + compatible = "qcom,spmi-adc-tm-hc"; + reg = <0x3400>; + interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + thermistor@1 { + reg = <1>; + io-channels = <&pm8998_adc ADC5_XO_THERM_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + }; + }; +... From f6c83676c6097d3f21895b360a03804f810e6d54 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 4 Oct 2021 20:25:29 -0700 Subject: [PATCH 04/18] thermal/drivers/qcom/spmi-adc-tm5: Add support for HC variant The variant of the ADC Thermal Monitor block found in e.g. PM8998 is "HC", add support for this variant to the ADC TM5 driver in order to support using VADC channels as thermal_zones on SDM845 et al. Signed-off-by: Bjorn Andersson Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211005032531.2251928-3-bjorn.andersson@linaro.org Signed-off-by: Daniel Lezcano --- drivers/thermal/qcom/qcom-spmi-adc-tm5.c | 41 +++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c index 8494cc04aa21..824671cf494a 100644 --- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c +++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c @@ -82,6 +82,7 @@ struct adc_tm5_data { const u32 full_scale_code_volt; unsigned int *decimation; unsigned int *hw_settle; + bool is_hc; }; enum adc_tm5_cal_method { @@ -146,6 +147,14 @@ static const struct adc_tm5_data adc_tm5_data_pmic = { 64000, 128000 }, }; +static const struct adc_tm5_data adc_tm_hc_data_pmic = { + .full_scale_code_volt = 0x70e4, + .decimation = (unsigned int []) { 256, 512, 1024 }, + .hw_settle = (unsigned int []) { 0, 100, 200, 300, 400, 500, 600, 700, + 1000, 2000, 4000, 6000, 8000, 10000 }, + .is_hc = true, +}; + static int adc_tm5_read(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len) { return regmap_bulk_read(adc_tm->regmap, adc_tm->base + offset, data, len); @@ -375,6 +384,29 @@ static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm) return 0; } +static int adc_tm_hc_init(struct adc_tm5_chip *chip) +{ + unsigned int i; + u8 buf[2]; + int ret; + + for (i = 0; i < chip->nchannels; i++) { + if (chip->channels[i].channel >= ADC_TM5_NUM_CHANNELS) { + dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel); + return -EINVAL; + } + } + + buf[0] = chip->decimation; + buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN; + + ret = adc_tm5_write(chip, ADC_TM5_ADC_DIG_PARAM, buf, sizeof(buf)); + if (ret) + dev_err(chip->dev, "block write failed: %d\n", ret); + + return ret; +} + static int adc_tm5_init(struct adc_tm5_chip *chip) { u8 buf[4], channels_available; @@ -591,7 +623,10 @@ static int adc_tm5_probe(struct platform_device *pdev) return ret; } - ret = adc_tm5_init(adc_tm); + if (adc_tm->data->is_hc) + ret = adc_tm_hc_init(adc_tm); + else + ret = adc_tm5_init(adc_tm); if (ret) { dev_err(dev, "adc-tm init failed\n"); return ret; @@ -612,6 +647,10 @@ static const struct of_device_id adc_tm5_match_table[] = { .compatible = "qcom,spmi-adc-tm5", .data = &adc_tm5_data_pmic, }, + { + .compatible = "qcom,spmi-adc-tm-hc", + .data = &adc_tm_hc_data_pmic, + }, { } }; MODULE_DEVICE_TABLE(of, adc_tm5_match_table); From b8aaf1415a1bc3a61f870366b3f989b3bc3e2824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Thu, 14 Oct 2021 12:38:15 +0200 Subject: [PATCH 05/18] thermal: rcar_gen3_thermal: Store thcode and ptat in priv data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for reading the THCODE and PTAT values from hardware fuses by storing the values used during calculations in the drivers private data structures. As the values are now stored directly in the private data structures there is no need to keep track of the TSC channel id as its only usage was to lookup the THCODE row, drop it. Signed-off-by: Niklas Söderlund Tested-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211014103816.1939782-2-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Daniel Lezcano --- drivers/thermal/rcar_gen3_thermal.c | 51 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 85228d308dd3..7d7e6ebe837a 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -62,15 +62,6 @@ #define TSC_MAX_NUM 5 -/* default THCODE values if FUSEs are missing */ -static const int thcodes[TSC_MAX_NUM][3] = { - { 3397, 2800, 2221 }, - { 3393, 2795, 2216 }, - { 3389, 2805, 2237 }, - { 3415, 2694, 2195 }, - { 3356, 2724, 2244 }, -}; - /* Structure for thermal temperature calculation */ struct equation_coefs { int a1; @@ -84,13 +75,14 @@ struct rcar_gen3_thermal_tsc { struct thermal_zone_device *zone; struct equation_coefs coef; int tj_t; - unsigned int id; /* thermal channel id */ + int thcode[3]; }; struct rcar_gen3_thermal_priv { struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; unsigned int num_tscs; void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc); + int ptat[3]; }; static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc, @@ -133,8 +125,8 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, /* no idea where these constants come from */ #define TJ_3 -41 -static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, - int *ptat, const int *thcode, +static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv, + struct rcar_gen3_thermal_tsc *tsc, int ths_tj_1) { /* TODO: Find documentation and document constant calculation formula */ @@ -143,16 +135,16 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, * 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((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3)) - / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3); + 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(thcode[1] - thcode[2]), + 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(thcode[2]) - tsc->coef.a1 * TJ_3; + tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3; - tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]), + 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(thcode[0]) - tsc->coef.a2 * ths_tj_1; + tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1; } static int rcar_gen3_thermal_round(int temp) @@ -174,7 +166,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) /* Read register and convert to mili Celsius */ reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; - if (reg <= thcodes[tsc->id][1]) + if (reg <= tsc->thcode[1]) val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1); else @@ -401,9 +393,15 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) unsigned int i; int ret; - /* default values if FUSEs are missing */ + /* Default THCODE values in case FUSEs are not set. */ /* TODO: Read values from hardware on supported platforms */ - int ptat[3] = { 2631, 1509, 435 }; + static const int thcodes[TSC_MAX_NUM][3] = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, + { 3415, 2694, 2195 }, + { 3356, 2724, 2244 }, + }; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -413,6 +411,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (soc_device_match(r8a7795es1)) priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; + priv->ptat[0] = 2631; + priv->ptat[1] = 1509; + priv->ptat[2] = 435; + platform_set_drvdata(pdev, priv); if (rcar_gen3_thermal_request_irqs(priv, pdev)) @@ -439,7 +441,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ret = PTR_ERR(tsc->base); goto error_unregister; } - tsc->id = i; + + tsc->thcode[0] = thcodes[i][0]; + tsc->thcode[1] = thcodes[i][1]; + tsc->thcode[2] = thcodes[i][2]; priv->tscs[i] = tsc; @@ -453,7 +458,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) tsc->zone = zone; priv->thermal_init(tsc); - rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); + rcar_gen3_thermal_calc_coefs(priv, tsc, *ths_tj_1); tsc->zone->tzp->no_hwmon = false; ret = thermal_add_hwmon_sysfs(tsc->zone); From c3131bd5586d3e8b67dc69516e1734a7a03e19d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Thu, 14 Oct 2021 12:38:16 +0200 Subject: [PATCH 06/18] thermal: rcar_gen3_thermal: Read calibration from hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In production hardware the calibration values used to convert register values to temperatures can be read from hardware. While pre-production hardware still depends on pseudo values hard-coded in the driver. Add support for reading out calibration values from hardware if it's fused. The presence of fused calibration is indicated in the THSCP register. Signed-off-by: Niklas Söderlund Tested-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211014103816.1939782-3-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Daniel Lezcano --- drivers/thermal/rcar_gen3_thermal.c | 94 +++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 7d7e6ebe837a..43eb25b167bc 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -34,6 +34,10 @@ #define REG_GEN3_THCODE1 0x50 #define REG_GEN3_THCODE2 0x54 #define REG_GEN3_THCODE3 0x58 +#define REG_GEN3_PTAT1 0x5c +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define REG_GEN3_THSCP 0x68 /* IRQ{STR,MSK,EN} bits */ #define IRQ_TEMP1 BIT(0) @@ -55,6 +59,9 @@ #define THCTR_PONM BIT(6) #define THCTR_THSST BIT(0) +/* THSCP bits */ +#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14)) + #define CTEMP_MASK 0xFFF #define MCELSIUS(temp) ((temp) * 1000) @@ -245,6 +252,64 @@ static const struct soc_device_attribute r8a7795es1[] = { { /* sentinel */ } }; +static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv) +{ + unsigned int i; + u32 thscp; + + /* If fuses are not set, fallback to pseudo values. */ + thscp = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_THSCP); + if ((thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) { + /* Default THCODE values in case FUSEs are not set. */ + static const int thcodes[TSC_MAX_NUM][3] = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, + { 3415, 2694, 2195 }, + { 3356, 2724, 2244 }, + }; + + priv->ptat[0] = 2631; + priv->ptat[1] = 1509; + priv->ptat[2] = 435; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; + + tsc->thcode[0] = thcodes[i][0]; + tsc->thcode[1] = thcodes[i][1]; + tsc->thcode[2] = thcodes[i][2]; + } + + return false; + } + + /* + * Set the pseudo calibration points with fused values. + * PTAT is shared between all TSCs but only fused for the first + * TSC while THCODEs are fused for each TSC. + */ + priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT1) & + GEN3_FUSE_MASK; + priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT2) & + GEN3_FUSE_MASK; + priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT3) & + GEN3_FUSE_MASK; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; + + tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE1) & + GEN3_FUSE_MASK; + tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE2) & + GEN3_FUSE_MASK; + tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE3) & + GEN3_FUSE_MASK; + } + + return true; +} + static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc) { rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR); @@ -393,16 +458,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) unsigned int i; int ret; - /* Default THCODE values in case FUSEs are not set. */ - /* TODO: Read values from hardware on supported platforms */ - static const int thcodes[TSC_MAX_NUM][3] = { - { 3397, 2800, 2221 }, - { 3393, 2795, 2216 }, - { 3389, 2805, 2237 }, - { 3415, 2694, 2195 }, - { 3356, 2724, 2244 }, - }; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -411,10 +466,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (soc_device_match(r8a7795es1)) priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; - priv->ptat[0] = 2631; - priv->ptat[1] = 1509; - priv->ptat[2] = 435; - platform_set_drvdata(pdev, priv); if (rcar_gen3_thermal_request_irqs(priv, pdev)) @@ -442,11 +493,16 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) goto error_unregister; } - tsc->thcode[0] = thcodes[i][0]; - tsc->thcode[1] = thcodes[i][1]; - tsc->thcode[2] = thcodes[i][2]; - priv->tscs[i] = tsc; + } + + priv->num_tscs = i; + + if (!rcar_gen3_thermal_read_fuses(priv)) + dev_info(dev, "No calibration values fused, fallback to driver values\n"); + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); @@ -476,8 +532,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret); } - priv->num_tscs = i; - if (!priv->num_tscs) { ret = -ENODEV; goto error_unregister; From 1dd7128b839f631b31a9e9dce3aaf639bef74e9d Mon Sep 17 00:00:00 2001 From: Yuanzheng Song Date: Fri, 15 Oct 2021 08:32:30 +0000 Subject: [PATCH 07/18] thermal/core: Fix null pointer dereference in thermal_release() If both dev_set_name() and device_register() failed, then null pointer dereference occurs in thermal_release() which will use strncmp() to compare the name. So fix it by adding dev_set_name() return value check. Signed-off-by: Yuanzheng Song Link: https://lore.kernel.org/r/20211015083230.67658-1-songyuanzheng@huawei.com Signed-off-by: Daniel Lezcano --- drivers/thermal/thermal_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 9e243d9f929e..6904b97fd6ea 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -904,6 +904,10 @@ __thermal_cooling_device_register(struct device_node *np, goto out_kfree_cdev; cdev->id = ret; + ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id); + if (ret) + goto out_ida_remove; + cdev->type = kstrdup(type ? type : "", GFP_KERNEL); if (!cdev->type) { ret = -ENOMEM; @@ -918,7 +922,6 @@ __thermal_cooling_device_register(struct device_node *np, cdev->device.class = &thermal_class; cdev->devdata = devdata; thermal_cooling_device_setup_sysfs(cdev); - dev_set_name(&cdev->device, "cooling_device%d", cdev->id); ret = device_register(&cdev->device); if (ret) goto out_kfree_type; @@ -1229,6 +1232,10 @@ thermal_zone_device_register(const char *type, int trips, int mask, tz->id = id; strlcpy(tz->type, type, sizeof(tz->type)); + result = dev_set_name(&tz->device, "thermal_zone%d", tz->id); + if (result) + goto remove_id; + if (!ops->critical) ops->critical = thermal_zone_device_critical; @@ -1250,7 +1257,6 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* A new thermal zone needs to be updated anyway. */ atomic_set(&tz->need_update, 1); - dev_set_name(&tz->device, "thermal_zone%d", tz->id); result = device_register(&tz->device); if (result) goto release_device; From 0a5c26712f963f0500161a23e0ffff8d29f742ab Mon Sep 17 00:00:00 2001 From: Ziyang Xuan Date: Fri, 15 Oct 2021 10:45:04 +0800 Subject: [PATCH 08/18] thermal/core: fix a UAF bug in __thermal_cooling_device_register() When device_register() return failed, program will goto out_kfree_type to release 'cdev->device' by put_device(). That will call thermal_release() to free 'cdev'. But the follow-up processes access 'cdev' continually. That trggers the UAF bug. ==================================================================== BUG: KASAN: use-after-free in __thermal_cooling_device_register+0x75b/0xa90 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Call Trace: dump_stack_lvl+0xe2/0x152 print_address_description.constprop.0+0x21/0x140 ? __thermal_cooling_device_register+0x75b/0xa90 kasan_report.cold+0x7f/0x11b ? __thermal_cooling_device_register+0x75b/0xa90 __thermal_cooling_device_register+0x75b/0xa90 ? memset+0x20/0x40 ? __sanitizer_cov_trace_pc+0x1d/0x50 ? __devres_alloc_node+0x130/0x180 devm_thermal_of_cooling_device_register+0x67/0xf0 max6650_probe.cold+0x557/0x6aa ...... Freed by task 258: kasan_save_stack+0x1b/0x40 kasan_set_track+0x1c/0x30 kasan_set_free_info+0x20/0x30 __kasan_slab_free+0x109/0x140 kfree+0x117/0x4c0 thermal_release+0xa0/0x110 device_release+0xa7/0x240 kobject_put+0x1ce/0x540 put_device+0x20/0x30 __thermal_cooling_device_register+0x731/0xa90 devm_thermal_of_cooling_device_register+0x67/0xf0 max6650_probe.cold+0x557/0x6aa [max6650] Do not use 'cdev' again after put_device() to fix the problem like doing in thermal_zone_device_register(). [dlezcano]: as requested by Rafael, change the affectation into two statements. Fixes: 584837618100 ("thermal/drivers/core: Use a char pointer for the cooling device name") Signed-off-by: Ziyang Xuan Reported-by: kernel test robot Link: https://lore.kernel.org/r/20211015024504.947520-1-william.xuanziyang@huawei.com Signed-off-by: Daniel Lezcano --- drivers/thermal/thermal_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 6904b97fd6ea..648829ab79ff 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -889,7 +889,7 @@ __thermal_cooling_device_register(struct device_node *np, { struct thermal_cooling_device *cdev; struct thermal_zone_device *pos = NULL; - int ret; + int id, ret; if (!ops || !ops->get_max_state || !ops->get_cur_state || !ops->set_cur_state) @@ -903,6 +903,7 @@ __thermal_cooling_device_register(struct device_node *np, if (ret < 0) goto out_kfree_cdev; cdev->id = ret; + id = ret; ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id); if (ret) @@ -946,8 +947,9 @@ __thermal_cooling_device_register(struct device_node *np, out_kfree_type: kfree(cdev->type); put_device(&cdev->device); + cdev = NULL; out_ida_remove: - ida_simple_remove(&thermal_cdev_ida, cdev->id); + ida_simple_remove(&thermal_cdev_ida, id); out_kfree_cdev: kfree(cdev); return ERR_PTR(ret); From 9e5a4fb8423081d0efbf165c71c7f4abdf5f918c Mon Sep 17 00:00:00 2001 From: Jackie Liu Date: Sat, 9 Oct 2021 09:58:53 +0800 Subject: [PATCH 09/18] thermal/drivers/qcom/lmh: make QCOM_LMH depends on QCOM_SCM Without QCOM_SCM, build failed, avoid like below: aarch64-linux-gnu-ld: Unexpected GOT/PLT entries detected! aarch64-linux-gnu-ld: Unexpected run-time procedure linkages detected! aarch64-linux-gnu-ld: drivers/thermal/qcom/lmh.o: in function `lmh_probe': /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:141: undefined reference to `qcom_scm_lmh_dcvsh_available' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:144: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:149: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:154: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:159: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:166: undefined reference to `qcom_scm_lmh_profile_change' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:173: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:180: undefined reference to `qcom_scm_lmh_dcvsh' aarch64-linux-gnu-ld: /data/arm/workspace/kernel-build/linux/build/../drivers/thermal/qcom/lmh.c:187: undefined reference to `qcom_scm_lmh_dcvsh' make[1]: *** [/data/arm/workspace/kernel-build/linux/Makefile:1183: vmlinux] Error 1 make[1]: Leaving directory '/data/arm/workspace/kernel-build/linux/build' make: *** [Makefile:219: __sub-make] Error 2 make: Leaving directory '/data/arm/workspace/kernel-build/linux' Fixes: 53bca371cdf7 ("thermal/drivers/qcom: Add support for LMh driver") Signed-off-by: Jackie Liu Link: https://lore.kernel.org/r/20211009015853.3509559-1-liu.yun@linux.dev Signed-off-by: Daniel Lezcano --- drivers/thermal/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index 7d942f71e532..bfd889422dd3 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -34,7 +34,7 @@ config QCOM_SPMI_TEMP_ALARM config QCOM_LMH tristate "Qualcomm Limits Management Hardware" - depends on ARCH_QCOM + depends on ARCH_QCOM && QCOM_SCM help This enables initialization of Qualcomm limits management hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on From d012f9189fda0f3a1b303780ba0bbc7298d0d349 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Thu, 7 Oct 2021 19:28:59 +0200 Subject: [PATCH 10/18] thermal/drivers/tsens: Add timeout to get_temp_tsens_valid The function can loop and lock the system if for whatever reason the bit for the target sensor is NEVER valid. This is the case if a sensor is disabled by the factory and the valid bit is never reported as actually valid. Add a timeout check and exit if a timeout occurs. As this is a very rare condition, handle the timeout only if the first read fails. While at it also rework the function to improve readability and convert to poll_timeout generic macro. Signed-off-by: Ansuel Smith Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211007172859.583-1-ansuelsmth@gmail.com Signed-off-by: Daniel Lezcano --- drivers/thermal/qcom/tsens.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index b1162e566a70..99a8d9f3e03c 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -603,22 +603,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) int ret; /* VER_0 doesn't have VALID bit */ - if (tsens_version(priv) >= VER_0_1) { - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - while (!valid) { - /* Valid bit is 0 for 6 AHB clock cycles. - * At 19.2MHz, 1 AHB clock is ~60ns. - * We should enter this loop very, very rarely. - */ - ndelay(400); - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - } - } + if (tsens_version(priv) == VER_0) + goto get_temp; + /* Valid bit is 0 for 6 AHB clock cycles. + * At 19.2MHz, 1 AHB clock is ~60ns. + * We should enter this loop very, very rarely. + * Wait 1 us since it's the min of poll_timeout macro. + * Old value was 400 ns. + */ + ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid, + valid, 1, 20 * USEC_PER_MSEC); + if (ret) + return ret; + +get_temp: /* Valid bit is set, OK to read the temperature */ *temp = tsens_hw_to_mC(s, temp_idx); From 07c54d9a409f1fd54df328ec742f156547594347 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Thu, 30 Sep 2021 13:05:14 +0200 Subject: [PATCH 11/18] dt-bindings: thermal: allow more resets for tsadc node in rockchip-thermal.yaml The tsadc node in rk356x.dtsi has more resets defined then currently allowed by rockchip-thermal.yaml, so fix that in the documentation. The driver now uses the devm_reset_control_array_get() function, so reset-names is no longer required, but keep it for legacy reasons. Signed-off-by: Johan Jonker Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210930110517.14323-1-jbx6244@gmail.com Signed-off-by: Daniel Lezcano --- .../devicetree/bindings/thermal/rockchip-thermal.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml index b96ea277b558..3c074706e95f 100644 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml @@ -37,11 +37,15 @@ properties: - const: apb_pclk resets: - maxItems: 1 + minItems: 1 + maxItems: 3 reset-names: + minItems: 1 items: - const: tsadc-apb + - const: tsadc + - const: tsadc-phy "#thermal-sensor-cells": const: 1 @@ -71,7 +75,6 @@ required: - clocks - clock-names - resets - - reset-names - "#thermal-sensor-cells" additionalProperties: false From 5f553ac2325456f484806df5aa695392364d39f5 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Thu, 30 Sep 2021 13:05:15 +0200 Subject: [PATCH 12/18] dt-bindings: thermal: remove redundant comments from rockchip-thermal.yaml Remove redundent comments from rockchip-thermal.yaml Sort compatibles in alphabetical order. Signed-off-by: Johan Jonker Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210930110517.14323-2-jbx6244@gmail.com Signed-off-by: Daniel Lezcano --- .../bindings/thermal/rockchip-thermal.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml index 3c074706e95f..f6c1be226aaa 100644 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml @@ -12,14 +12,14 @@ maintainers: properties: compatible: enum: - - rockchip,px30-tsadc # PX30 SoCs - - rockchip,rv1108-tsadc # RV1108 SoCs - - rockchip,rk3228-tsadc # RK3228 SoCs - - rockchip,rk3288-tsadc # RK3288 SoCs - - rockchip,rk3328-tsadc # RK3328 SoCs - - rockchip,rk3368-tsadc # RK3368 SoCs - - rockchip,rk3399-tsadc # RK3399 SoCs - - rockchip,rk3568-tsadc # RK3568 SoCs + - rockchip,px30-tsadc + - rockchip,rk3228-tsadc + - rockchip,rk3288-tsadc + - rockchip,rk3328-tsadc + - rockchip,rk3368-tsadc + - rockchip,rk3399-tsadc + - rockchip,rk3568-tsadc + - rockchip,rv1108-tsadc reg: maxItems: 1 From 02832ed8ae2c8b130efea4e43d3ecac50b4b7933 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Thu, 30 Sep 2021 13:05:16 +0200 Subject: [PATCH 13/18] thermal/drivers/rockchip_thermal: Allow more resets for tsadc node The tsadc node in rk356x.dtsi has more resets then currently supported by the rockchip_thermal.c driver, so use devm_reset_control_array_get() to reset them all. Signed-off-by: Johan Jonker Link: https://lore.kernel.org/r/20210930110517.14323-3-jbx6244@gmail.com Signed-off-by: Daniel Lezcano --- drivers/thermal/rockchip_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 657d84b9963e..dc3a9c276a09 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -1383,7 +1383,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) if (IS_ERR(thermal->regs)) return PTR_ERR(thermal->regs); - thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb"); + thermal->reset = devm_reset_control_array_get(&pdev->dev, false, false); if (IS_ERR(thermal->reset)) { error = PTR_ERR(thermal->reset); dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error); From 5041e63aaf36021f71b5f6244811a9cf2fe89fb4 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Mon, 18 Oct 2021 10:34:50 +0900 Subject: [PATCH 14/18] dt-bindings: thermal: uniphier: Add binding for NX1 SoC Update thermal binding document for UniPhier NX1 SoC. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1634520891-16801-2-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Daniel Lezcano --- .../devicetree/bindings/thermal/socionext,uniphier-thermal.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/socionext,uniphier-thermal.yaml b/Documentation/devicetree/bindings/thermal/socionext,uniphier-thermal.yaml index 553c9dcdaeeb..c5b25ce44956 100644 --- a/Documentation/devicetree/bindings/thermal/socionext,uniphier-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/socionext,uniphier-thermal.yaml @@ -20,6 +20,7 @@ properties: - socionext,uniphier-pxs2-thermal - socionext,uniphier-ld20-thermal - socionext,uniphier-pxs3-thermal + - socionext,uniphier-nx1-thermal interrupts: maxItems: 1 From fb6de59d3967f87fe4cae4b08f55cbe0d5a30b77 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Mon, 18 Oct 2021 10:34:51 +0900 Subject: [PATCH 15/18] thermal/drivers/uniphier: Add compatible string for NX1 SoC Add basic support for UniPhier NX1 SoC. This includes a compatible string and the same SoC-dependent data as LD20 SoC. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1634520891-16801-3-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Daniel Lezcano --- drivers/thermal/uniphier_thermal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c index bba2284412d3..4cae5561a2a3 100644 --- a/drivers/thermal/uniphier_thermal.c +++ b/drivers/thermal/uniphier_thermal.c @@ -358,6 +358,10 @@ static const struct of_device_id uniphier_tm_dt_ids[] = { .compatible = "socionext,uniphier-pxs3-thermal", .data = &uniphier_ld20_tm_data, }, + { + .compatible = "socionext,uniphier-nx1-thermal", + .data = &uniphier_ld20_tm_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids); From c4fcf1ada4ae63e0aab6afd19ca2e7d16833302c Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 9 Sep 2021 10:56:13 +0200 Subject: [PATCH 16/18] thermal/drivers/int340x: Improve the tcc offset saving for suspend/resume When the driver resumes, the tcc offset is set back to its previous value. But this only works if the value was user defined as otherwise the offset isn't saved. This asymmetric logic is harder to maintain and introduced some issues. Improve the logic by saving the tcc offset in a suspend op, so the right value is always restored after a resume. Signed-off-by: Antoine Tenart Reviewed-by: Srinivas Pandruvada Tested-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20210909085613.5577-3-atenart@kernel.org Signed-off-by: Daniel Lezcano --- .../intel/int340x_thermal/int3401_thermal.c | 8 ++++- .../processor_thermal_device.c | 36 ++++++++++++++----- .../processor_thermal_device.h | 1 + .../processor_thermal_device_pci.c | 18 +++++++++- .../processor_thermal_device_pci_legacy.c | 8 ++++- 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c index acebc8ba94e2..217786fba185 100644 --- a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c @@ -44,15 +44,21 @@ static int int3401_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP +static int int3401_thermal_suspend(struct device *dev) +{ + return proc_thermal_suspend(dev); +} static int int3401_thermal_resume(struct device *dev) { return proc_thermal_resume(dev); } #else +#define int3401_thermal_suspend NULL #define int3401_thermal_resume NULL #endif -static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume); +static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend, + int3401_thermal_resume); static struct platform_driver int3401_driver = { .probe = int3401_add, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index fb64acfd5e07..a8d98f1bd6c6 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -68,8 +68,7 @@ static const struct attribute_group power_limit_attribute_group = { .name = "power_limits" }; -static ssize_t tcc_offset_degree_celsius_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int tcc_get_offset(void) { u64 val; int err; @@ -78,8 +77,20 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev, if (err) return err; - val = (val >> 24) & 0x3f; - return sprintf(buf, "%d\n", (int)val); + return (val >> 24) & 0x3f; +} + +static ssize_t tcc_offset_degree_celsius_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int tcc; + + tcc = tcc_get_offset(); + if (tcc < 0) + return tcc; + + return sprintf(buf, "%d\n", tcc); } static int tcc_offset_update(unsigned int tcc) @@ -107,8 +118,6 @@ static int tcc_offset_update(unsigned int tcc) return 0; } -static int tcc_offset_save = -1; - static ssize_t tcc_offset_degree_celsius_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -131,8 +140,6 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, if (err) return err; - tcc_offset_save = tcc; - return count; } @@ -345,6 +352,18 @@ void proc_thermal_remove(struct proc_thermal_device *proc_priv) } EXPORT_SYMBOL_GPL(proc_thermal_remove); +static int tcc_offset_save = -1; + +int proc_thermal_suspend(struct device *dev) +{ + tcc_offset_save = tcc_get_offset(); + if (tcc_offset_save < 0) + dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save); + + return 0; +} +EXPORT_SYMBOL_GPL(proc_thermal_suspend); + int proc_thermal_resume(struct device *dev) { struct proc_thermal_device *proc_dev; @@ -352,6 +371,7 @@ int proc_thermal_resume(struct device *dev) proc_dev = dev_get_drvdata(dev); proc_thermal_read_ppcc(proc_dev); + /* Do not update if saving failed */ if (tcc_offset_save >= 0) tcc_offset_update(tcc_offset_save); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index 5a1cfe4864f1..c1d8de6dc3d1 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -83,6 +83,7 @@ void proc_thermal_mbox_remove(struct pci_dev *pdev); int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp); int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv); void proc_thermal_remove(struct proc_thermal_device *proc_priv); +int proc_thermal_suspend(struct device *dev); int proc_thermal_resume(struct device *dev); int proc_thermal_mmio_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index 11dd2e825f4f..b4bcd3fe9eb2 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -314,6 +314,20 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct proc_thermal_device *proc_priv; + struct proc_thermal_pci *pci_info; + + proc_priv = pci_get_drvdata(pdev); + pci_info = proc_priv->priv_data; + + if (!pci_info->no_legacy) + return proc_thermal_suspend(dev); + + return 0; +} static int proc_thermal_pci_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -335,10 +349,12 @@ static int proc_thermal_pci_resume(struct device *dev) return 0; } #else +#define proc_thermal_pci_suspend NULL #define proc_thermal_pci_resume NULL #endif -static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend, + proc_thermal_pci_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c index f5fc1791b11e..4571a1a53b84 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c @@ -107,15 +107,21 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_suspend(struct device *dev) +{ + return proc_thermal_suspend(dev); +} static int proc_thermal_pci_resume(struct device *dev) { return proc_thermal_resume(dev); } #else +#define proc_thermal_pci_suspend NULL #define proc_thermal_pci_resume NULL #endif -static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend, + proc_thermal_pci_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, From 0275c9fb0eff3f77d437ab8a95b16e6f8f80b7f2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 19 Oct 2021 18:35:05 +0200 Subject: [PATCH 17/18] thermal/core: Make the userspace governor deprecated The userspace governor is sending temperature when polling is active and trip point crossed events. Nothing else. AFAICT, this governor is used with custom kernels making the userspace governor co-existing with another governor on the same thermal zone because there was no notification mechanism, implying a hack in the framework to support this configuration. The new netlink thermal notification is able to provide more information than the userspace governor and give the opportunity to the users of this governor to replace it by a dedicated notification framework. The userspace governor will be removed as its usage is no longer needed. Add a warning message to tell the userspace governor is deprecated. Signed-off-by: Daniel Lezcano Acked-by: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://lore.kernel.org/r/20211019163506.2831454-1-daniel.lezcano@linaro.org --- drivers/thermal/gov_user_space.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/thermal/gov_user_space.c b/drivers/thermal/gov_user_space.c index 82a7198bbe71..f4fe050e1cbc 100644 --- a/drivers/thermal/gov_user_space.c +++ b/drivers/thermal/gov_user_space.c @@ -15,6 +15,14 @@ #include "thermal_core.h" +static int user_space_bind(struct thermal_zone_device *tz) +{ + pr_warn("Userspace governor deprecated: use thermal netlink " \ + "notification instead\n"); + + return 0; +} + /** * notify_user_space - Notifies user space about thermal events * @tz: thermal_zone_device @@ -43,5 +51,6 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip) static struct thermal_governor thermal_gov_user_space = { .name = "user_space", .throttle = notify_user_space, + .bind_to_tz = user_space_bind, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space); From a67a46af4ad6342378e332b7420c1d1a2818c53f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 19 Oct 2021 18:35:06 +0200 Subject: [PATCH 18/18] thermal/core: Deprecate changing cooling device state from userspace The cooling devices have their cooling device set_cur_state read-writable all the time in the sysfs directory, thus allowing the userspace to act on it. The thermal framework is wrongly used by userspace as a power capping framework by acting on the cooling device opaque state. This one then competes with the in-kernel governor decision. We have seen in out-of-tree kernels, a big number of devices which are abusely declaring themselves as cooling device just to act on their power. The role of the thermal framework is to protect the junction temperature of the silicon. Letting the userspace to play with a cooling device is invalid and potentially dangerous. The powercap framework is the right framework to do power capping and moreover it deals with the aggregation via the dev pm qos. As the userspace governor is marked deprecated and about to be removed, there is no point to keep this file writable also in the future. Emit a warning and deprecate the interface. Signed-off-by: Daniel Lezcano Acked-by: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://lore.kernel.org/r/20211019163506.2831454-2-daniel.lezcano@linaro.org --- drivers/thermal/thermal_sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 1c4aac8464a7..f154bada2906 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -610,6 +610,9 @@ cur_state_store(struct device *dev, struct device_attribute *attr, unsigned long state; int result; + dev_warn_once(&cdev->device, + "Setting cooling device state is deprecated\n"); + if (sscanf(buf, "%ld\n", &state) != 1) return -EINVAL;