Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge back thermal cotntrol material for v6.10.

+1087 -520
+7 -5
Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
··· 13 13 14 14 properties: 15 15 compatible: 16 - items: 17 - - enum: 18 - - amlogic,g12a-cpu-thermal 19 - - amlogic,g12a-ddr-thermal 20 - - const: amlogic,g12a-thermal 16 + oneOf: 17 + - items: 18 + - enum: 19 + - amlogic,g12a-cpu-thermal 20 + - amlogic,g12a-ddr-thermal 21 + - const: amlogic,g12a-thermal 22 + - const: amlogic,a1-cpu-thermal 21 23 22 24 reg: 23 25 maxItems: 1
+22 -2
Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
··· 18 18 oneOf: 19 19 - enum: 20 20 - loongson,ls2k1000-thermal 21 + - loongson,ls2k2000-thermal 21 22 - items: 22 23 - enum: 23 - - loongson,ls2k2000-thermal 24 + - loongson,ls2k0500-thermal 24 25 - const: loongson,ls2k1000-thermal 25 26 26 27 reg: 27 - maxItems: 1 28 + minItems: 1 29 + maxItems: 2 28 30 29 31 interrupts: 30 32 maxItems: 1 ··· 39 37 - reg 40 38 - interrupts 41 39 - '#thermal-sensor-cells' 40 + 41 + if: 42 + properties: 43 + compatible: 44 + contains: 45 + enum: 46 + - loongson,ls2k2000-thermal 47 + 48 + then: 49 + properties: 50 + reg: 51 + minItems: 2 52 + maxItems: 2 53 + 54 + else: 55 + properties: 56 + reg: 57 + maxItems: 1 42 58 43 59 unevaluatedProperties: false 44 60
+6
Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
··· 19 19 compatible: 20 20 enum: 21 21 - mediatek,mt7988-lvts-ap 22 + - mediatek,mt8186-lvts 23 + - mediatek,mt8188-lvts-ap 24 + - mediatek,mt8188-lvts-mcu 22 25 - mediatek,mt8192-lvts-ap 23 26 - mediatek,mt8192-lvts-mcu 24 27 - mediatek,mt8195-lvts-ap ··· 63 60 compatible: 64 61 contains: 65 62 enum: 63 + - mediatek,mt8188-lvts-ap 64 + - mediatek,mt8188-lvts-mcu 66 65 - mediatek,mt8192-lvts-ap 67 66 - mediatek,mt8192-lvts-mcu 68 67 then: ··· 80 75 compatible: 81 76 contains: 82 77 enum: 78 + - mediatek,mt8186-lvts 83 79 - mediatek,mt8195-lvts-ap 84 80 - mediatek,mt8195-lvts-mcu 85 81 then:
+8 -4
Documentation/devicetree/bindings/thermal/qcom-lmh.yaml
··· 17 17 18 18 properties: 19 19 compatible: 20 - enum: 21 - - qcom,sc8180x-lmh 22 - - qcom,sdm845-lmh 23 - - qcom,sm8150-lmh 20 + oneOf: 21 + - enum: 22 + - qcom,sc8180x-lmh 23 + - qcom,sdm845-lmh 24 + - qcom,sm8150-lmh 25 + - items: 26 + - const: qcom,qcm2290-lmh 27 + - const: qcom,sm8150-lmh 24 28 25 29 reg: 26 30 items:
+58
Documentation/devicetree/bindings/thermal/st,stih407-thermal.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/thermal/st,stih407-thermal.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: STMicroelectronics STi digital thermal sensor (DTS) 8 + 9 + maintainers: 10 + - Patrice Chotard <patrice.chotard@foss.st.com> 11 + - Lee Jones <lee@kernel.org> 12 + 13 + allOf: 14 + - $ref: thermal-sensor.yaml 15 + 16 + properties: 17 + compatible: 18 + const: st,stih407-thermal 19 + 20 + reg: 21 + maxItems: 1 22 + 23 + clocks: 24 + maxItems: 1 25 + 26 + clock-names: 27 + items: 28 + - const: thermal 29 + 30 + interrupts: 31 + description: 32 + For thermal sensors for which no interrupt has been defined, a polling 33 + delay of 1000ms will be used to read the temperature from device. 34 + maxItems: 1 35 + 36 + '#thermal-sensor-cells': 37 + const: 0 38 + 39 + required: 40 + - compatible 41 + - reg 42 + - clocks 43 + - clock-names 44 + 45 + unevaluatedProperties: false 46 + 47 + examples: 48 + - | 49 + #include <dt-bindings/interrupt-controller/arm-gic.h> 50 + temperature-sensor@91a0000 { 51 + compatible = "st,stih407-thermal"; 52 + reg = <0x91a0000 0x28>; 53 + clock-names = "thermal"; 54 + clocks = <&CLK_SYSIN>; 55 + interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>; 56 + #thermal-sensor-cells = <0>; 57 + }; 58 + ...
-32
Documentation/devicetree/bindings/thermal/st-thermal.txt
··· 1 - Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs. 2 - 3 - Required parameters: 4 - ------------------- 5 - 6 - compatible : Should be "st,stih407-thermal" 7 - 8 - clock-names : Should be "thermal". 9 - See: Documentation/devicetree/bindings/resource-names.txt 10 - clocks : Phandle of the clock used by the thermal sensor. 11 - See: Documentation/devicetree/bindings/clock/clock-bindings.txt 12 - 13 - Optional parameters: 14 - ------------------- 15 - 16 - reg : For non-sysconf based sensors, this should be the physical base 17 - address and length of the sensor's registers. 18 - interrupts : Standard way to define interrupt number. 19 - NB: For thermal sensor's for which no interrupt has been 20 - defined, a polling delay of 1000ms will be used to read the 21 - temperature from device. 22 - 23 - Example: 24 - 25 - temp0@91a0000 { 26 - compatible = "st,stih407-thermal"; 27 - reg = <0x91a0000 0x28>; 28 - clock-names = "thermal"; 29 - clocks = <&CLK_SYSIN>; 30 - interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>; 31 - st,passive_cooling_temp = <110>; 32 - };
+10
drivers/thermal/amlogic_thermal.c
··· 220 220 .regmap_config = &amlogic_thermal_regmap_config_g12a, 221 221 }; 222 222 223 + static const struct amlogic_thermal_data amlogic_thermal_a1_cpu_param = { 224 + .u_efuse_off = 0x114, 225 + .calibration_parameters = &amlogic_thermal_g12a, 226 + .regmap_config = &amlogic_thermal_regmap_config_g12a, 227 + }; 228 + 223 229 static const struct of_device_id of_amlogic_thermal_match[] = { 224 230 { 225 231 .compatible = "amlogic,g12a-ddr-thermal", ··· 234 228 { 235 229 .compatible = "amlogic,g12a-cpu-thermal", 236 230 .data = &amlogic_thermal_g12a_cpu_param, 231 + }, 232 + { 233 + .compatible = "amlogic,a1-cpu-thermal", 234 + .data = &amlogic_thermal_a1_cpu_param, 237 235 }, 238 236 { /* sentinel */ } 239 237 };
+2 -7
drivers/thermal/armada_thermal.c
··· 763 763 struct armada_thermal_priv *priv) 764 764 { 765 765 const char *name = dev_name(&pdev->dev); 766 - char *insane_char; 767 766 768 767 if (strlen(name) > THERMAL_NAME_LENGTH) { 769 768 /* ··· 780 781 /* Save the name locally */ 781 782 strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH); 782 783 783 - /* Then check there are no '-' or hwmon core will complain */ 784 - do { 785 - insane_char = strpbrk(priv->zone_name, "-"); 786 - if (insane_char) 787 - *insane_char = '_'; 788 - } while (insane_char); 784 + /* Then ensure there are no '-' or hwmon core will complain */ 785 + strreplace(priv->zone_name, '-', '_'); 789 786 } 790 787 791 788 /*
+5 -2
drivers/thermal/gov_fair_share.c
··· 17 17 18 18 static int get_trip_level(struct thermal_zone_device *tz) 19 19 { 20 - const struct thermal_trip *trip, *level_trip = NULL; 20 + const struct thermal_trip *level_trip = NULL; 21 + const struct thermal_trip_desc *td; 21 22 int trip_level = -1; 22 23 23 - for_each_trip(tz, trip) { 24 + for_each_trip_desc(tz, td) { 25 + const struct thermal_trip *trip = &td->trip; 26 + 24 27 if (trip->temperature >= tz->temperature) 25 28 continue; 26 29
+4 -2
drivers/thermal/gov_power_allocator.c
··· 496 496 const struct thermal_trip *first_passive = NULL; 497 497 const struct thermal_trip *last_passive = NULL; 498 498 const struct thermal_trip *last_active = NULL; 499 - const struct thermal_trip *trip; 499 + const struct thermal_trip_desc *td; 500 500 501 - for_each_trip(tz, trip) { 501 + for_each_trip_desc(tz, td) { 502 + const struct thermal_trip *trip = &td->trip; 503 + 502 504 switch (trip->type) { 503 505 case THERMAL_TRIP_PASSIVE: 504 506 if (!first_passive) {
+16 -25
drivers/thermal/gov_step_wise.c
··· 32 32 { 33 33 struct thermal_cooling_device *cdev = instance->cdev; 34 34 unsigned long cur_state; 35 - unsigned long next_target; 36 35 37 36 /* 38 37 * We keep this instance the way it is by default. ··· 39 40 * cdev in use to determine the next_target. 40 41 */ 41 42 cdev->ops->get_cur_state(cdev, &cur_state); 42 - next_target = instance->target; 43 43 dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state); 44 44 45 45 if (!instance->initialized) { 46 - if (throttle) { 47 - next_target = clamp((cur_state + 1), instance->lower, instance->upper); 48 - } else { 49 - next_target = THERMAL_NO_TARGET; 50 - } 46 + if (throttle) 47 + return clamp(cur_state + 1, instance->lower, instance->upper); 51 48 52 - return next_target; 49 + return THERMAL_NO_TARGET; 53 50 } 54 51 55 52 if (throttle) { 56 53 if (trend == THERMAL_TREND_RAISING) 57 - next_target = clamp((cur_state + 1), instance->lower, instance->upper); 58 - } else { 59 - if (trend == THERMAL_TREND_DROPPING) { 60 - if (cur_state <= instance->lower) 61 - next_target = THERMAL_NO_TARGET; 62 - else 63 - next_target = clamp((cur_state - 1), instance->lower, instance->upper); 64 - } 54 + return clamp(cur_state + 1, instance->lower, instance->upper); 55 + } else if (trend == THERMAL_TREND_DROPPING) { 56 + if (cur_state <= instance->lower) 57 + return THERMAL_NO_TARGET; 58 + 59 + return clamp(cur_state - 1, instance->lower, instance->upper); 65 60 } 66 61 67 - return next_target; 62 + return instance->target; 68 63 } 69 64 70 65 static void thermal_zone_trip_update(struct thermal_zone_device *tz, ··· 92 99 if (instance->initialized && old_target == instance->target) 93 100 continue; 94 101 95 - if (old_target == THERMAL_NO_TARGET && 96 - instance->target != THERMAL_NO_TARGET) { 97 - /* Activate a passive thermal instance */ 98 - if (trip->type == THERMAL_TRIP_PASSIVE) 102 + if (trip->type == THERMAL_TRIP_PASSIVE) { 103 + /* If needed, update the status of passive polling. */ 104 + if (old_target == THERMAL_NO_TARGET && 105 + instance->target != THERMAL_NO_TARGET) 99 106 tz->passive++; 100 - } else if (old_target != THERMAL_NO_TARGET && 101 - instance->target == THERMAL_NO_TARGET) { 102 - /* Deactivate a passive thermal instance */ 103 - if (trip->type == THERMAL_TRIP_PASSIVE) 107 + else if (old_target != THERMAL_NO_TARGET && 108 + instance->target == THERMAL_NO_TARGET) 104 109 tz->passive--; 105 110 } 106 111
+2 -2
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
··· 309 309 310 310 if (knob->type == ACPI_TYPE_STRING) { 311 311 memset(&psvt->limit, 0, sizeof(u64)); 312 - strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length); 312 + strscpy(psvt->limit.string, psvt_ptr->limit.str_ptr, ACPI_LIMIT_STR_MAX_LEN); 313 313 } else { 314 314 psvt->limit.integer = psvt_ptr->limit.integer; 315 315 } ··· 468 468 psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff; 469 469 psvt_user[i].control_knob_type = psvts[i].control_knob_type; 470 470 if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING) 471 - strncpy(psvt_user[i].limit.string, psvts[i].limit.string, 471 + strscpy(psvt_user[i].limit.string, psvts[i].limit.string, 472 472 ACPI_LIMIT_STR_MAX_LEN); 473 473 else 474 474 psvt_user[i].limit.integer = psvts[i].limit.integer;
+89 -8
drivers/thermal/intel/intel_hfi.c
··· 159 159 static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 }; 160 160 161 161 static int max_hfi_instances; 162 + static int hfi_clients_nr; 162 163 static struct hfi_instance *hfi_instances; 163 164 164 165 static struct hfi_features hfi_features; ··· 478 477 enable: 479 478 cpumask_set_cpu(cpu, hfi_instance->cpus); 480 479 481 - /* Enable this HFI instance if this is its first online CPU. */ 482 - if (cpumask_weight(hfi_instance->cpus) == 1) { 480 + /* 481 + * Enable this HFI instance if this is its first online CPU and 482 + * there are user-space clients of thermal events. 483 + */ 484 + if (cpumask_weight(hfi_instance->cpus) == 1 && hfi_clients_nr > 0) { 483 485 hfi_set_hw_table(hfi_instance); 484 486 hfi_enable(); 485 487 } ··· 577 573 return 0; 578 574 } 579 575 580 - static void hfi_do_enable(void) 576 + /* 577 + * If concurrency is not prevented by other means, the HFI enable/disable 578 + * routines must be called under hfi_instance_lock." 579 + */ 580 + static void hfi_enable_instance(void *ptr) 581 + { 582 + hfi_set_hw_table(ptr); 583 + hfi_enable(); 584 + } 585 + 586 + static void hfi_disable_instance(void *ptr) 587 + { 588 + hfi_disable(); 589 + } 590 + 591 + static void hfi_syscore_resume(void) 581 592 { 582 593 /* This code runs only on the boot CPU. */ 583 594 struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0); 584 595 struct hfi_instance *hfi_instance = info->hfi_instance; 585 596 586 597 /* No locking needed. There is no concurrency with CPU online. */ 587 - hfi_set_hw_table(hfi_instance); 588 - hfi_enable(); 598 + if (hfi_clients_nr > 0) 599 + hfi_enable_instance(hfi_instance); 589 600 } 590 601 591 - static int hfi_do_disable(void) 602 + static int hfi_syscore_suspend(void) 592 603 { 593 604 /* No locking needed. There is no concurrency with CPU offline. */ 594 605 hfi_disable(); ··· 612 593 } 613 594 614 595 static struct syscore_ops hfi_pm_ops = { 615 - .resume = hfi_do_enable, 616 - .suspend = hfi_do_disable, 596 + .resume = hfi_syscore_resume, 597 + .suspend = hfi_syscore_suspend, 598 + }; 599 + 600 + static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state, 601 + void *_notify) 602 + { 603 + struct thermal_genl_notify *notify = _notify; 604 + struct hfi_instance *hfi_instance; 605 + smp_call_func_t func = NULL; 606 + unsigned int cpu; 607 + int i; 608 + 609 + if (notify->mcgrp != THERMAL_GENL_EVENT_GROUP) 610 + return NOTIFY_DONE; 611 + 612 + if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND) 613 + return NOTIFY_DONE; 614 + 615 + mutex_lock(&hfi_instance_lock); 616 + 617 + switch (state) { 618 + case THERMAL_NOTIFY_BIND: 619 + if (++hfi_clients_nr == 1) 620 + func = hfi_enable_instance; 621 + break; 622 + case THERMAL_NOTIFY_UNBIND: 623 + if (--hfi_clients_nr == 0) 624 + func = hfi_disable_instance; 625 + break; 626 + } 627 + 628 + if (!func) 629 + goto out; 630 + 631 + for (i = 0; i < max_hfi_instances; i++) { 632 + hfi_instance = &hfi_instances[i]; 633 + if (cpumask_empty(hfi_instance->cpus)) 634 + continue; 635 + 636 + cpu = cpumask_any(hfi_instance->cpus); 637 + smp_call_function_single(cpu, func, hfi_instance, true); 638 + } 639 + 640 + out: 641 + mutex_unlock(&hfi_instance_lock); 642 + 643 + return NOTIFY_OK; 644 + } 645 + 646 + static struct notifier_block hfi_thermal_nb = { 647 + .notifier_call = hfi_thermal_notify, 617 648 }; 618 649 619 650 void __init intel_hfi_init(void) ··· 697 628 if (!hfi_updates_wq) 698 629 goto err_nomem; 699 630 631 + /* 632 + * Both thermal core and Intel HFI can not be build as modules. 633 + * As kernel build-in drivers they are initialized before user-space 634 + * starts, hence we can not miss BIND/UNBIND events when applications 635 + * add/remove thermal multicast group to/from a netlink socket. 636 + */ 637 + if (thermal_genl_register_notifier(&hfi_thermal_nb)) 638 + goto err_nl_notif; 639 + 700 640 register_syscore_ops(&hfi_pm_ops); 701 641 702 642 return; 643 + 644 + err_nl_notif: 645 + destroy_workqueue(hfi_updates_wq); 703 646 704 647 err_nomem: 705 648 for (j = 0; j < i; ++j) {
-1
drivers/thermal/k3_bandgap.c
··· 78 78 79 79 struct k3_bandgap { 80 80 void __iomem *base; 81 - const struct k3_bandgap_data *conf; 82 81 }; 83 82 84 83 /* common data structures */
+81 -40
drivers/thermal/loongson2_thermal.c
··· 14 14 #include <linux/property.h> 15 15 #include <linux/thermal.h> 16 16 #include <linux/units.h> 17 + 17 18 #include "thermal_hwmon.h" 18 19 19 - #define LOONGSON2_MAX_SENSOR_SEL_NUM 3 20 + #define LOONGSON2_MAX_SENSOR_SEL_NUM 3 20 21 21 - #define LOONGSON2_THSENS_CTRL_HI_REG 0x0 22 - #define LOONGSON2_THSENS_CTRL_LOW_REG 0x8 23 - #define LOONGSON2_THSENS_STATUS_REG 0x10 24 - #define LOONGSON2_THSENS_OUT_REG 0x14 22 + #define LOONGSON2_THSENS_CTRL_HI_REG 0x0 23 + #define LOONGSON2_THSENS_CTRL_LOW_REG 0x8 24 + #define LOONGSON2_THSENS_STATUS_REG 0x10 25 + #define LOONGSON2_THSENS_OUT_REG 0x14 25 26 26 - #define LOONGSON2_THSENS_INT_LO BIT(0) 27 - #define LOONGSON2_THSENS_INT_HIGH BIT(1) 28 - #define LOONGSON2_THSENS_OUT_MASK 0xFF 27 + #define LOONGSON2_THSENS_INT_LO BIT(0) 28 + #define LOONGSON2_THSENS_INT_HIGH BIT(1) 29 + #define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \ 30 + LOONGSON2_THSENS_INT_HIGH) 31 + #define LOONGSON2_THSENS_OUT_MASK 0xFF 32 + 33 + /* 34 + * This flag is used to indicate the temperature reading 35 + * method of the Loongson-2K2000 36 + */ 37 + #define LS2K2000_THSENS_OUT_FLAG BIT(0) 29 38 30 39 struct loongson2_thermal_chip_data { 31 - unsigned int thermal_sensor_sel; 40 + unsigned int thermal_sensor_sel; 41 + unsigned int flags; 32 42 }; 33 43 34 44 struct loongson2_thermal_data { 35 - void __iomem *regs; 45 + void __iomem *ctrl_reg; 46 + void __iomem *temp_reg; 36 47 const struct loongson2_thermal_chip_data *chip_data; 37 48 }; 38 49 39 - static int loongson2_thermal_set(struct loongson2_thermal_data *data, 40 - int low, int high, bool enable) 50 + static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data, 51 + int ctrl_data, bool low, bool enable) 41 52 { 42 - u64 reg_ctrl = 0; 43 - int reg_off = data->chip_data->thermal_sensor_sel * 2; 53 + int reg_ctrl = 0; 54 + int reg_off = data->chip_data->thermal_sensor_sel * 2; 55 + int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG; 44 56 45 - low = clamp(-40, low, high); 46 - high = clamp(125, low, high); 47 - 48 - low += HECTO; 49 - high += HECTO; 50 - 51 - reg_ctrl = low; 57 + reg_ctrl = ctrl_data + HECTO; 52 58 reg_ctrl |= enable ? 0x100 : 0; 53 - writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off); 59 + writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off); 60 + } 54 61 55 - reg_ctrl = high; 56 - reg_ctrl |= enable ? 0x100 : 0; 57 - writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off); 62 + static int loongson2_thermal_set(struct loongson2_thermal_data *data, 63 + int low, int high, bool enable) 64 + { 65 + /* Set low temperature threshold */ 66 + loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable); 67 + 68 + /* Set high temperature threshold */ 69 + loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable); 58 70 59 71 return 0; 60 72 } 61 73 62 - static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp) 74 + static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp) 63 75 { 64 - u32 reg_val; 76 + int val; 65 77 struct loongson2_thermal_data *data = thermal_zone_device_priv(tz); 66 78 67 - reg_val = readl(data->regs + LOONGSON2_THSENS_OUT_REG); 68 - *temp = ((reg_val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO; 79 + val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG); 80 + *temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO; 81 + 82 + return 0; 83 + } 84 + 85 + static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp) 86 + { 87 + int val; 88 + struct loongson2_thermal_data *data = thermal_zone_device_priv(tz); 89 + 90 + val = readl(data->temp_reg); 91 + *temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO; 69 92 70 93 return 0; 71 94 } ··· 98 75 struct thermal_zone_device *tzd = dev; 99 76 struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd); 100 77 101 - writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs + 102 - LOONGSON2_THSENS_STATUS_REG); 78 + writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG); 103 79 104 80 thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED); 105 81 ··· 112 90 return loongson2_thermal_set(data, low/MILLI, high/MILLI, true); 113 91 } 114 92 115 - static const struct thermal_zone_device_ops loongson2_of_thermal_ops = { 116 - .get_temp = loongson2_thermal_get_temp, 93 + static struct thermal_zone_device_ops loongson2_of_thermal_ops = { 94 + .get_temp = loongson2_2k1000_get_temp, 117 95 .set_trips = loongson2_thermal_set_trips, 118 96 }; 119 97 ··· 130 108 131 109 data->chip_data = device_get_match_data(dev); 132 110 133 - data->regs = devm_platform_ioremap_resource(pdev, 0); 134 - if (IS_ERR(data->regs)) 135 - return PTR_ERR(data->regs); 111 + data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0); 112 + if (IS_ERR(data->ctrl_reg)) 113 + return PTR_ERR(data->ctrl_reg); 114 + 115 + /* The temperature output register is separate for Loongson-2K2000 */ 116 + if (data->chip_data->flags & LS2K2000_THSENS_OUT_FLAG) { 117 + data->temp_reg = devm_platform_ioremap_resource(pdev, 1); 118 + if (IS_ERR(data->temp_reg)) 119 + return PTR_ERR(data->temp_reg); 120 + 121 + loongson2_of_thermal_ops.get_temp = loongson2_2k2000_get_temp; 122 + } 136 123 137 124 irq = platform_get_irq(pdev, 0); 138 125 if (irq < 0) 139 126 return irq; 140 127 141 - writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs + 142 - LOONGSON2_THSENS_STATUS_REG); 128 + writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG); 143 129 144 130 loongson2_thermal_set(data, 0, 0, false); 145 131 146 132 for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) { 147 133 tzd = devm_thermal_of_zone_register(dev, i, data, 148 - &loongson2_of_thermal_ops); 134 + &loongson2_of_thermal_ops); 149 135 150 136 if (!IS_ERR(tzd)) 151 137 break; ··· 165 135 } 166 136 167 137 ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread, 168 - IRQF_ONESHOT, "loongson2_thermal", tzd); 138 + IRQF_ONESHOT, "loongson2_thermal", tzd); 169 139 if (ret < 0) 170 140 return dev_err_probe(dev, ret, "failed to request alarm irq\n"); 171 141 ··· 176 146 177 147 static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = { 178 148 .thermal_sensor_sel = 0, 149 + .flags = 0, 150 + }; 151 + 152 + static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = { 153 + .thermal_sensor_sel = 0, 154 + .flags = LS2K2000_THSENS_OUT_FLAG, 179 155 }; 180 156 181 157 static const struct of_device_id of_loongson2_thermal_match[] = { 182 158 { 183 159 .compatible = "loongson,ls2k1000-thermal", 184 160 .data = &loongson2_thermal_ls2k1000_data, 161 + }, 162 + { 163 + .compatible = "loongson,ls2k2000-thermal", 164 + .data = &loongson2_thermal_ls2k2000_data, 185 165 }, 186 166 { /* end */ } 187 167 }; ··· 207 167 module_platform_driver(loongson2_thermal_driver); 208 168 209 169 MODULE_DESCRIPTION("Loongson2 thermal driver"); 170 + MODULE_AUTHOR("Loongson Technology Corporation Limited"); 210 171 MODULE_LICENSE("GPL");
+320 -118
drivers/thermal/mediatek/lvts_thermal.c
··· 91 91 #define LVTS_MSR_READ_TIMEOUT_US 400 92 92 #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) 93 93 94 - #define LVTS_HW_SHUTDOWN_MT7988 105000 95 - #define LVTS_HW_SHUTDOWN_MT8192 105000 96 - #define LVTS_HW_SHUTDOWN_MT8195 105000 94 + #define LVTS_HW_TSHUT_TEMP 105000 97 95 98 96 #define LVTS_MINIMUM_THRESHOLD 20000 99 97 ··· 100 102 101 103 struct lvts_sensor_data { 102 104 int dt_id; 105 + u8 cal_offsets[3]; 103 106 }; 104 107 105 108 struct lvts_ctrl_data { 106 109 struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX]; 107 110 int cal_offset[LVTS_SENSOR_MAX]; 108 - int hw_tshut_temp; 109 111 int num_lvts_sensor; 112 + u8 valid_sensor_mask; 110 113 int offset; 111 114 int mode; 112 115 }; 116 + 117 + #define VALID_SENSOR_MAP(s0, s1, s2, s3) \ 118 + .valid_sensor_mask = (((s0) ? BIT(0) : 0) | \ 119 + ((s1) ? BIT(1) : 0) | \ 120 + ((s2) ? BIT(2) : 0) | \ 121 + ((s3) ? BIT(3) : 0)) 122 + 123 + #define lvts_for_each_valid_sensor(i, lvts_ctrl_data) \ 124 + for ((i) = 0; (i) < LVTS_SENSOR_MAX; (i)++) \ 125 + if (!((lvts_ctrl_data)->valid_sensor_mask & BIT(i))) \ 126 + continue; \ 127 + else 113 128 114 129 struct lvts_data { 115 130 const struct lvts_ctrl_data *lvts_ctrl; 116 131 int num_lvts_ctrl; 117 132 int temp_factor; 118 133 int temp_offset; 134 + int gt_calib_bit_offset; 119 135 }; 120 136 121 137 struct lvts_sensor { ··· 147 135 const struct lvts_data *lvts_data; 148 136 u32 calibration[LVTS_SENSOR_MAX]; 149 137 u32 hw_tshut_raw_temp; 150 - int num_lvts_sensor; 151 138 int mode; 152 139 void __iomem *base; 153 140 int low_thresh; ··· 358 347 if (high > lvts_ctrl->high_thresh) 359 348 return true; 360 349 361 - for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) 350 + lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) 362 351 if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh 363 352 && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) 364 353 return false; ··· 562 551 const struct lvts_ctrl_data *lvts_ctrl_data) 563 552 { 564 553 struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors; 554 + 565 555 void __iomem *msr_regs[] = { 566 556 LVTS_MSR0(lvts_ctrl->base), 567 557 LVTS_MSR1(lvts_ctrl->base), ··· 579 567 580 568 int i; 581 569 582 - for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) { 570 + lvts_for_each_valid_sensor(i, lvts_ctrl_data) { 583 571 584 572 int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id; 585 573 ··· 618 606 lvts_sensor[i].low_thresh = INT_MIN; 619 607 lvts_sensor[i].high_thresh = INT_MIN; 620 608 }; 621 - 622 - lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; 623 609 624 610 return 0; 625 611 } ··· 678 668 * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8-----> 679 669 * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 680 670 * 681 - * The data description gives the offset of the calibration data in 682 - * this bytes stream for each sensor. 671 + * Note: In some cases, values don't strictly follow a little endian ordering. 672 + * The data description gives byte offsets constituting each calibration value 673 + * for each sensor. 683 674 */ 684 675 static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, 685 676 const struct lvts_ctrl_data *lvts_ctrl_data, 686 - u8 *efuse_calibration) 677 + u8 *efuse_calibration, 678 + size_t calib_len) 687 679 { 688 680 int i; 689 681 690 - for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) 691 - memcpy(&lvts_ctrl->calibration[i], 692 - efuse_calibration + lvts_ctrl_data->cal_offset[i], 2); 682 + lvts_for_each_valid_sensor(i, lvts_ctrl_data) { 683 + const struct lvts_sensor_data *sensor = 684 + &lvts_ctrl_data->lvts_sensor[i]; 685 + 686 + if (sensor->cal_offsets[0] >= calib_len || 687 + sensor->cal_offsets[1] >= calib_len || 688 + sensor->cal_offsets[2] >= calib_len) 689 + return -EINVAL; 690 + 691 + lvts_ctrl->calibration[i] = 692 + (efuse_calibration[sensor->cal_offsets[0]] << 0) + 693 + (efuse_calibration[sensor->cal_offsets[1]] << 8) + 694 + (efuse_calibration[sensor->cal_offsets[2]] << 16); 695 + } 693 696 694 697 return 0; 695 698 } ··· 757 734 return 0; 758 735 } 759 736 760 - static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset) 737 + static int lvts_golden_temp_init(struct device *dev, u8 *calib, 738 + const struct lvts_data *lvts_data) 761 739 { 762 740 u32 gt; 763 741 764 - gt = (*value) >> 24; 742 + /* 743 + * The golden temp information is contained in the first 32-bit 744 + * word of efuse data at a specific bit offset. 745 + */ 746 + gt = (((u32 *)calib)[0] >> lvts_data->gt_calib_bit_offset) & 0xff; 765 747 766 748 if (gt && gt < LVTS_GOLDEN_TEMP_MAX) 767 749 golden_temp = gt; 768 750 769 - golden_temp_offset = golden_temp * 500 + temp_offset; 751 + golden_temp_offset = golden_temp * 500 + lvts_data->temp_offset; 770 752 771 753 return 0; 772 754 } ··· 790 762 if (ret) 791 763 return ret; 792 764 793 - /* 794 - * The golden temp information is contained in the first chunk 795 - * of efuse data. 796 - */ 797 - ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset); 765 + ret = lvts_golden_temp_init(dev, lvts_td->calib, lvts_data); 798 766 if (ret) 799 767 return ret; 800 768 ··· 810 786 811 787 ret = lvts_calibration_init(dev, &lvts_ctrl[i], 812 788 &lvts_data->lvts_ctrl[i], 813 - lvts_td->calib); 789 + lvts_td->calib, 790 + lvts_td->calib_len); 814 791 if (ret) 815 792 return ret; 816 793 ··· 826 801 * after initializing the calibration. 827 802 */ 828 803 lvts_ctrl[i].hw_tshut_raw_temp = 829 - lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp, 804 + lvts_temp_to_raw(LVTS_HW_TSHUT_TEMP, 830 805 lvts_data->temp_factor); 831 806 832 807 lvts_ctrl[i].low_thresh = INT_MIN; ··· 1114 1089 u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? 1115 1090 sensor_imm_bitmap : sensor_filt_bitmap; 1116 1091 1117 - for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { 1092 + lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) { 1118 1093 1119 1094 int dt_id = lvts_sensors[i].dt_id; 1120 1095 ··· 1327 1302 1328 1303 static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = { 1329 1304 { 1330 - .cal_offset = { 0x00, 0x04, 0x08, 0x0c }, 1331 1305 .lvts_sensor = { 1332 - { .dt_id = MT7988_CPU_0 }, 1333 - { .dt_id = MT7988_CPU_1 }, 1334 - { .dt_id = MT7988_ETH2P5G_0 }, 1335 - { .dt_id = MT7988_ETH2P5G_1 } 1306 + { .dt_id = MT7988_CPU_0, 1307 + .cal_offsets = { 0x00, 0x01, 0x02 } }, 1308 + { .dt_id = MT7988_CPU_1, 1309 + .cal_offsets = { 0x04, 0x05, 0x06 } }, 1310 + { .dt_id = MT7988_ETH2P5G_0, 1311 + .cal_offsets = { 0x08, 0x09, 0x0a } }, 1312 + { .dt_id = MT7988_ETH2P5G_1, 1313 + .cal_offsets = { 0x0c, 0x0d, 0x0e } } 1336 1314 }, 1337 - .num_lvts_sensor = 4, 1315 + VALID_SENSOR_MAP(1, 1, 1, 1), 1338 1316 .offset = 0x0, 1339 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, 1340 1317 }, 1341 1318 { 1342 - .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, 1343 1319 .lvts_sensor = { 1344 - { .dt_id = MT7988_TOPS_0}, 1345 - { .dt_id = MT7988_TOPS_1}, 1346 - { .dt_id = MT7988_ETHWARP_0}, 1347 - { .dt_id = MT7988_ETHWARP_1} 1320 + { .dt_id = MT7988_TOPS_0, 1321 + .cal_offsets = { 0x14, 0x15, 0x16 } }, 1322 + { .dt_id = MT7988_TOPS_1, 1323 + .cal_offsets = { 0x18, 0x19, 0x1a } }, 1324 + { .dt_id = MT7988_ETHWARP_0, 1325 + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, 1326 + { .dt_id = MT7988_ETHWARP_1, 1327 + .cal_offsets = { 0x20, 0x21, 0x22 } } 1348 1328 }, 1349 - .num_lvts_sensor = 4, 1329 + VALID_SENSOR_MAP(1, 1, 1, 1), 1350 1330 .offset = 0x100, 1351 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, 1352 1331 } 1353 1332 }; 1354 1333 ··· 1388 1359 return 0; 1389 1360 } 1390 1361 1362 + /* 1363 + * The MT8186 calibration data is stored as packed 3-byte little-endian 1364 + * values using a weird layout that makes sense only when viewed as a 32-bit 1365 + * hexadecimal word dump. Let's suppose SxBy where x = sensor number and 1366 + * y = byte number where the LSB is y=0. We then have: 1367 + * 1368 + * [S0B2-S0B1-S0B0-S1B2] [S1B1-S1B0-S2B2-S2B1] [S2B0-S3B2-S3B1-S3B0] 1369 + * 1370 + * However, when considering a byte stream, those appear as follows: 1371 + * 1372 + * [S1B2] [S0B0[ [S0B1] [S0B2] [S2B1] [S2B2] [S1B0] [S1B1] [S3B0] [S3B1] [S3B2] [S2B0] 1373 + * 1374 + * Hence the rather confusing offsets provided below. 1375 + */ 1376 + static const struct lvts_ctrl_data mt8186_lvts_data_ctrl[] = { 1377 + { 1378 + .lvts_sensor = { 1379 + { .dt_id = MT8186_LITTLE_CPU0, 1380 + .cal_offsets = { 5, 6, 7 } }, 1381 + { .dt_id = MT8186_LITTLE_CPU1, 1382 + .cal_offsets = { 10, 11, 4 } }, 1383 + { .dt_id = MT8186_LITTLE_CPU2, 1384 + .cal_offsets = { 15, 8, 9 } }, 1385 + { .dt_id = MT8186_CAM, 1386 + .cal_offsets = { 12, 13, 14 } } 1387 + }, 1388 + VALID_SENSOR_MAP(1, 1, 1, 1), 1389 + .offset = 0x0, 1390 + }, 1391 + { 1392 + .lvts_sensor = { 1393 + { .dt_id = MT8186_BIG_CPU0, 1394 + .cal_offsets = { 22, 23, 16 } }, 1395 + { .dt_id = MT8186_BIG_CPU1, 1396 + .cal_offsets = { 27, 20, 21 } } 1397 + }, 1398 + VALID_SENSOR_MAP(1, 1, 0, 0), 1399 + .offset = 0x100, 1400 + }, 1401 + { 1402 + .lvts_sensor = { 1403 + { .dt_id = MT8186_NNA, 1404 + .cal_offsets = { 29, 30, 31 } }, 1405 + { .dt_id = MT8186_ADSP, 1406 + .cal_offsets = { 34, 35, 28 } }, 1407 + { .dt_id = MT8186_MFG, 1408 + .cal_offsets = { 39, 32, 33 } } 1409 + }, 1410 + VALID_SENSOR_MAP(1, 1, 1, 0), 1411 + .offset = 0x200, 1412 + } 1413 + }; 1414 + 1415 + static const struct lvts_ctrl_data mt8188_lvts_mcu_data_ctrl[] = { 1416 + { 1417 + .lvts_sensor = { 1418 + { .dt_id = MT8188_MCU_LITTLE_CPU0, 1419 + .cal_offsets = { 22, 23, 24 } }, 1420 + { .dt_id = MT8188_MCU_LITTLE_CPU1, 1421 + .cal_offsets = { 25, 26, 27 } }, 1422 + { .dt_id = MT8188_MCU_LITTLE_CPU2, 1423 + .cal_offsets = { 28, 29, 30 } }, 1424 + { .dt_id = MT8188_MCU_LITTLE_CPU3, 1425 + .cal_offsets = { 31, 32, 33 } }, 1426 + }, 1427 + VALID_SENSOR_MAP(1, 1, 1, 1), 1428 + .offset = 0x0, 1429 + .mode = LVTS_MSR_FILTERED_MODE, 1430 + }, 1431 + { 1432 + .lvts_sensor = { 1433 + { .dt_id = MT8188_MCU_BIG_CPU0, 1434 + .cal_offsets = { 34, 35, 36 } }, 1435 + { .dt_id = MT8188_MCU_BIG_CPU1, 1436 + .cal_offsets = { 37, 38, 39 } }, 1437 + }, 1438 + VALID_SENSOR_MAP(1, 1, 0, 0), 1439 + .offset = 0x100, 1440 + .mode = LVTS_MSR_FILTERED_MODE, 1441 + } 1442 + }; 1443 + 1444 + static const struct lvts_ctrl_data mt8188_lvts_ap_data_ctrl[] = { 1445 + { 1446 + .lvts_sensor = { 1447 + 1448 + { /* unused */ }, 1449 + { .dt_id = MT8188_AP_APU, 1450 + .cal_offsets = { 40, 41, 42 } }, 1451 + }, 1452 + VALID_SENSOR_MAP(0, 1, 0, 0), 1453 + .offset = 0x0, 1454 + .mode = LVTS_MSR_FILTERED_MODE, 1455 + }, 1456 + { 1457 + .lvts_sensor = { 1458 + { .dt_id = MT8188_AP_GPU1, 1459 + .cal_offsets = { 43, 44, 45 } }, 1460 + { .dt_id = MT8188_AP_GPU2, 1461 + .cal_offsets = { 46, 47, 48 } }, 1462 + { .dt_id = MT8188_AP_SOC1, 1463 + .cal_offsets = { 49, 50, 51 } }, 1464 + }, 1465 + VALID_SENSOR_MAP(1, 1, 1, 0), 1466 + .offset = 0x100, 1467 + .mode = LVTS_MSR_FILTERED_MODE, 1468 + }, 1469 + { 1470 + .lvts_sensor = { 1471 + { .dt_id = MT8188_AP_SOC2, 1472 + .cal_offsets = { 52, 53, 54 } }, 1473 + { .dt_id = MT8188_AP_SOC3, 1474 + .cal_offsets = { 55, 56, 57 } }, 1475 + }, 1476 + VALID_SENSOR_MAP(1, 1, 0, 0), 1477 + .offset = 0x200, 1478 + .mode = LVTS_MSR_FILTERED_MODE, 1479 + }, 1480 + { 1481 + .lvts_sensor = { 1482 + { .dt_id = MT8188_AP_CAM1, 1483 + .cal_offsets = { 58, 59, 60 } }, 1484 + { .dt_id = MT8188_AP_CAM2, 1485 + .cal_offsets = { 61, 62, 63 } }, 1486 + }, 1487 + VALID_SENSOR_MAP(1, 1, 0, 0), 1488 + .offset = 0x300, 1489 + .mode = LVTS_MSR_FILTERED_MODE, 1490 + } 1491 + }; 1492 + 1391 1493 static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = { 1392 1494 { 1393 - .cal_offset = { 0x04, 0x08 }, 1394 1495 .lvts_sensor = { 1395 - { .dt_id = MT8192_MCU_BIG_CPU0 }, 1396 - { .dt_id = MT8192_MCU_BIG_CPU1 } 1496 + { .dt_id = MT8192_MCU_BIG_CPU0, 1497 + .cal_offsets = { 0x04, 0x05, 0x06 } }, 1498 + { .dt_id = MT8192_MCU_BIG_CPU1, 1499 + .cal_offsets = { 0x08, 0x09, 0x0a } } 1397 1500 }, 1398 - .num_lvts_sensor = 2, 1501 + VALID_SENSOR_MAP(1, 1, 0, 0), 1399 1502 .offset = 0x0, 1400 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1401 1503 .mode = LVTS_MSR_FILTERED_MODE, 1402 1504 }, 1403 1505 { 1404 - .cal_offset = { 0x0c, 0x10 }, 1405 1506 .lvts_sensor = { 1406 - { .dt_id = MT8192_MCU_BIG_CPU2 }, 1407 - { .dt_id = MT8192_MCU_BIG_CPU3 } 1507 + { .dt_id = MT8192_MCU_BIG_CPU2, 1508 + .cal_offsets = { 0x0c, 0x0d, 0x0e } }, 1509 + { .dt_id = MT8192_MCU_BIG_CPU3, 1510 + .cal_offsets = { 0x10, 0x11, 0x12 } } 1408 1511 }, 1409 - .num_lvts_sensor = 2, 1512 + VALID_SENSOR_MAP(1, 1, 0, 0), 1410 1513 .offset = 0x100, 1411 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1412 1514 .mode = LVTS_MSR_FILTERED_MODE, 1413 1515 }, 1414 1516 { 1415 - .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, 1416 1517 .lvts_sensor = { 1417 - { .dt_id = MT8192_MCU_LITTLE_CPU0 }, 1418 - { .dt_id = MT8192_MCU_LITTLE_CPU1 }, 1419 - { .dt_id = MT8192_MCU_LITTLE_CPU2 }, 1420 - { .dt_id = MT8192_MCU_LITTLE_CPU3 } 1518 + { .dt_id = MT8192_MCU_LITTLE_CPU0, 1519 + .cal_offsets = { 0x14, 0x15, 0x16 } }, 1520 + { .dt_id = MT8192_MCU_LITTLE_CPU1, 1521 + .cal_offsets = { 0x18, 0x19, 0x1a } }, 1522 + { .dt_id = MT8192_MCU_LITTLE_CPU2, 1523 + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, 1524 + { .dt_id = MT8192_MCU_LITTLE_CPU3, 1525 + .cal_offsets = { 0x20, 0x21, 0x22 } } 1421 1526 }, 1422 - .num_lvts_sensor = 4, 1527 + VALID_SENSOR_MAP(1, 1, 1, 1), 1423 1528 .offset = 0x200, 1424 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1425 1529 .mode = LVTS_MSR_FILTERED_MODE, 1426 1530 } 1427 1531 }; 1428 1532 1429 1533 static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = { 1430 - { 1431 - .cal_offset = { 0x24, 0x28 }, 1534 + { 1432 1535 .lvts_sensor = { 1433 - { .dt_id = MT8192_AP_VPU0 }, 1434 - { .dt_id = MT8192_AP_VPU1 } 1536 + { .dt_id = MT8192_AP_VPU0, 1537 + .cal_offsets = { 0x24, 0x25, 0x26 } }, 1538 + { .dt_id = MT8192_AP_VPU1, 1539 + .cal_offsets = { 0x28, 0x29, 0x2a } } 1435 1540 }, 1436 - .num_lvts_sensor = 2, 1541 + VALID_SENSOR_MAP(1, 1, 0, 0), 1437 1542 .offset = 0x0, 1438 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1439 1543 }, 1440 1544 { 1441 - .cal_offset = { 0x2c, 0x30 }, 1442 1545 .lvts_sensor = { 1443 - { .dt_id = MT8192_AP_GPU0 }, 1444 - { .dt_id = MT8192_AP_GPU1 } 1546 + { .dt_id = MT8192_AP_GPU0, 1547 + .cal_offsets = { 0x2c, 0x2d, 0x2e } }, 1548 + { .dt_id = MT8192_AP_GPU1, 1549 + .cal_offsets = { 0x30, 0x31, 0x32 } } 1445 1550 }, 1446 - .num_lvts_sensor = 2, 1551 + VALID_SENSOR_MAP(1, 1, 0, 0), 1447 1552 .offset = 0x100, 1448 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1449 1553 }, 1450 1554 { 1451 - .cal_offset = { 0x34, 0x38 }, 1452 1555 .lvts_sensor = { 1453 - { .dt_id = MT8192_AP_INFRA }, 1454 - { .dt_id = MT8192_AP_CAM }, 1556 + { .dt_id = MT8192_AP_INFRA, 1557 + .cal_offsets = { 0x34, 0x35, 0x36 } }, 1558 + { .dt_id = MT8192_AP_CAM, 1559 + .cal_offsets = { 0x38, 0x39, 0x3a } }, 1455 1560 }, 1456 - .num_lvts_sensor = 2, 1561 + VALID_SENSOR_MAP(1, 1, 0, 0), 1457 1562 .offset = 0x200, 1458 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1459 1563 }, 1460 1564 { 1461 - .cal_offset = { 0x3c, 0x40, 0x44 }, 1462 1565 .lvts_sensor = { 1463 - { .dt_id = MT8192_AP_MD0 }, 1464 - { .dt_id = MT8192_AP_MD1 }, 1465 - { .dt_id = MT8192_AP_MD2 } 1566 + { .dt_id = MT8192_AP_MD0, 1567 + .cal_offsets = { 0x3c, 0x3d, 0x3e } }, 1568 + { .dt_id = MT8192_AP_MD1, 1569 + .cal_offsets = { 0x40, 0x41, 0x42 } }, 1570 + { .dt_id = MT8192_AP_MD2, 1571 + .cal_offsets = { 0x44, 0x45, 0x46 } } 1466 1572 }, 1467 - .num_lvts_sensor = 3, 1573 + VALID_SENSOR_MAP(1, 1, 1, 0), 1468 1574 .offset = 0x300, 1469 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, 1470 1575 } 1471 1576 }; 1472 1577 1473 1578 static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { 1474 1579 { 1475 - .cal_offset = { 0x04, 0x07 }, 1476 1580 .lvts_sensor = { 1477 - { .dt_id = MT8195_MCU_BIG_CPU0 }, 1478 - { .dt_id = MT8195_MCU_BIG_CPU1 } 1581 + { .dt_id = MT8195_MCU_BIG_CPU0, 1582 + .cal_offsets = { 0x04, 0x05, 0x06 } }, 1583 + { .dt_id = MT8195_MCU_BIG_CPU1, 1584 + .cal_offsets = { 0x07, 0x08, 0x09 } } 1479 1585 }, 1480 - .num_lvts_sensor = 2, 1586 + VALID_SENSOR_MAP(1, 1, 0, 0), 1481 1587 .offset = 0x0, 1482 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1483 1588 }, 1484 1589 { 1485 - .cal_offset = { 0x0d, 0x10 }, 1486 1590 .lvts_sensor = { 1487 - { .dt_id = MT8195_MCU_BIG_CPU2 }, 1488 - { .dt_id = MT8195_MCU_BIG_CPU3 } 1591 + { .dt_id = MT8195_MCU_BIG_CPU2, 1592 + .cal_offsets = { 0x0d, 0x0e, 0x0f } }, 1593 + { .dt_id = MT8195_MCU_BIG_CPU3, 1594 + .cal_offsets = { 0x10, 0x11, 0x12 } } 1489 1595 }, 1490 - .num_lvts_sensor = 2, 1596 + VALID_SENSOR_MAP(1, 1, 0, 0), 1491 1597 .offset = 0x100, 1492 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1493 1598 }, 1494 1599 { 1495 - .cal_offset = { 0x16, 0x19, 0x1c, 0x1f }, 1496 1600 .lvts_sensor = { 1497 - { .dt_id = MT8195_MCU_LITTLE_CPU0 }, 1498 - { .dt_id = MT8195_MCU_LITTLE_CPU1 }, 1499 - { .dt_id = MT8195_MCU_LITTLE_CPU2 }, 1500 - { .dt_id = MT8195_MCU_LITTLE_CPU3 } 1601 + { .dt_id = MT8195_MCU_LITTLE_CPU0, 1602 + .cal_offsets = { 0x16, 0x17, 0x18 } }, 1603 + { .dt_id = MT8195_MCU_LITTLE_CPU1, 1604 + .cal_offsets = { 0x19, 0x1a, 0x1b } }, 1605 + { .dt_id = MT8195_MCU_LITTLE_CPU2, 1606 + .cal_offsets = { 0x1c, 0x1d, 0x1e } }, 1607 + { .dt_id = MT8195_MCU_LITTLE_CPU3, 1608 + .cal_offsets = { 0x1f, 0x20, 0x21 } } 1501 1609 }, 1502 - .num_lvts_sensor = 4, 1610 + VALID_SENSOR_MAP(1, 1, 1, 1), 1503 1611 .offset = 0x200, 1504 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1505 1612 } 1506 1613 }; 1507 1614 1508 1615 static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = { 1509 - { 1510 - .cal_offset = { 0x25, 0x28 }, 1616 + { 1511 1617 .lvts_sensor = { 1512 - { .dt_id = MT8195_AP_VPU0 }, 1513 - { .dt_id = MT8195_AP_VPU1 } 1618 + { .dt_id = MT8195_AP_VPU0, 1619 + .cal_offsets = { 0x25, 0x26, 0x27 } }, 1620 + { .dt_id = MT8195_AP_VPU1, 1621 + .cal_offsets = { 0x28, 0x29, 0x2a } } 1514 1622 }, 1515 - .num_lvts_sensor = 2, 1623 + VALID_SENSOR_MAP(1, 1, 0, 0), 1516 1624 .offset = 0x0, 1517 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1518 1625 }, 1519 1626 { 1520 - .cal_offset = { 0x2e, 0x31 }, 1521 1627 .lvts_sensor = { 1522 - { .dt_id = MT8195_AP_GPU0 }, 1523 - { .dt_id = MT8195_AP_GPU1 } 1628 + { .dt_id = MT8195_AP_GPU0, 1629 + .cal_offsets = { 0x2e, 0x2f, 0x30 } }, 1630 + { .dt_id = MT8195_AP_GPU1, 1631 + .cal_offsets = { 0x31, 0x32, 0x33 } } 1524 1632 }, 1525 - .num_lvts_sensor = 2, 1633 + VALID_SENSOR_MAP(1, 1, 0, 0), 1526 1634 .offset = 0x100, 1527 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1528 1635 }, 1529 1636 { 1530 - .cal_offset = { 0x37, 0x3a, 0x3d }, 1531 1637 .lvts_sensor = { 1532 - { .dt_id = MT8195_AP_VDEC }, 1533 - { .dt_id = MT8195_AP_IMG }, 1534 - { .dt_id = MT8195_AP_INFRA }, 1638 + { .dt_id = MT8195_AP_VDEC, 1639 + .cal_offsets = { 0x37, 0x38, 0x39 } }, 1640 + { .dt_id = MT8195_AP_IMG, 1641 + .cal_offsets = { 0x3a, 0x3b, 0x3c } }, 1642 + { .dt_id = MT8195_AP_INFRA, 1643 + .cal_offsets = { 0x3d, 0x3e, 0x3f } } 1535 1644 }, 1536 - .num_lvts_sensor = 3, 1645 + VALID_SENSOR_MAP(1, 1, 1, 0), 1537 1646 .offset = 0x200, 1538 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1539 1647 }, 1540 1648 { 1541 - .cal_offset = { 0x43, 0x46 }, 1542 1649 .lvts_sensor = { 1543 - { .dt_id = MT8195_AP_CAM0 }, 1544 - { .dt_id = MT8195_AP_CAM1 } 1650 + { .dt_id = MT8195_AP_CAM0, 1651 + .cal_offsets = { 0x43, 0x44, 0x45 } }, 1652 + { .dt_id = MT8195_AP_CAM1, 1653 + .cal_offsets = { 0x46, 0x47, 0x48 } } 1545 1654 }, 1546 - .num_lvts_sensor = 2, 1655 + VALID_SENSOR_MAP(1, 1, 0, 0), 1547 1656 .offset = 0x300, 1548 - .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, 1549 1657 } 1550 1658 }; 1551 1659 ··· 1691 1525 .num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl), 1692 1526 .temp_factor = LVTS_COEFF_A_MT7988, 1693 1527 .temp_offset = LVTS_COEFF_B_MT7988, 1528 + .gt_calib_bit_offset = 24, 1529 + }; 1530 + 1531 + static const struct lvts_data mt8186_lvts_data = { 1532 + .lvts_ctrl = mt8186_lvts_data_ctrl, 1533 + .num_lvts_ctrl = ARRAY_SIZE(mt8186_lvts_data_ctrl), 1534 + .temp_factor = LVTS_COEFF_A_MT7988, 1535 + .temp_offset = LVTS_COEFF_B_MT7988, 1536 + .gt_calib_bit_offset = 24, 1537 + }; 1538 + 1539 + static const struct lvts_data mt8188_lvts_mcu_data = { 1540 + .lvts_ctrl = mt8188_lvts_mcu_data_ctrl, 1541 + .num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_mcu_data_ctrl), 1542 + .temp_factor = LVTS_COEFF_A_MT8195, 1543 + .temp_offset = LVTS_COEFF_B_MT8195, 1544 + .gt_calib_bit_offset = 20, 1545 + }; 1546 + 1547 + static const struct lvts_data mt8188_lvts_ap_data = { 1548 + .lvts_ctrl = mt8188_lvts_ap_data_ctrl, 1549 + .num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_ap_data_ctrl), 1550 + .temp_factor = LVTS_COEFF_A_MT8195, 1551 + .temp_offset = LVTS_COEFF_B_MT8195, 1552 + .gt_calib_bit_offset = 20, 1694 1553 }; 1695 1554 1696 1555 static const struct lvts_data mt8192_lvts_mcu_data = { 1697 1556 .lvts_ctrl = mt8192_lvts_mcu_data_ctrl, 1698 1557 .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl), 1558 + .temp_factor = LVTS_COEFF_A_MT8195, 1559 + .temp_offset = LVTS_COEFF_B_MT8195, 1560 + .gt_calib_bit_offset = 24, 1699 1561 }; 1700 1562 1701 1563 static const struct lvts_data mt8192_lvts_ap_data = { 1702 1564 .lvts_ctrl = mt8192_lvts_ap_data_ctrl, 1703 1565 .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl), 1566 + .temp_factor = LVTS_COEFF_A_MT8195, 1567 + .temp_offset = LVTS_COEFF_B_MT8195, 1568 + .gt_calib_bit_offset = 24, 1704 1569 }; 1705 1570 1706 1571 static const struct lvts_data mt8195_lvts_mcu_data = { ··· 1739 1542 .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), 1740 1543 .temp_factor = LVTS_COEFF_A_MT8195, 1741 1544 .temp_offset = LVTS_COEFF_B_MT8195, 1545 + .gt_calib_bit_offset = 24, 1742 1546 }; 1743 1547 1744 1548 static const struct lvts_data mt8195_lvts_ap_data = { ··· 1747 1549 .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl), 1748 1550 .temp_factor = LVTS_COEFF_A_MT8195, 1749 1551 .temp_offset = LVTS_COEFF_B_MT8195, 1552 + .gt_calib_bit_offset = 24, 1750 1553 }; 1751 1554 1752 1555 static const struct of_device_id lvts_of_match[] = { 1753 1556 { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, 1557 + { .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data }, 1558 + { .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data }, 1559 + { .compatible = "mediatek,mt8188-lvts-ap", .data = &mt8188_lvts_ap_data }, 1754 1560 { .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data }, 1755 1561 { .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data }, 1756 1562 { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
+3
drivers/thermal/qcom/lmh.c
··· 95 95 unsigned int enable_alg; 96 96 u32 node_id; 97 97 98 + if (!qcom_scm_is_available()) 99 + return -EPROBE_DEFER; 100 + 98 101 lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL); 99 102 if (!lmh_data) 100 103 return -ENOMEM;
-1
drivers/thermal/qcom/qcom-spmi-temp-alarm.c
··· 74 74 long temp; 75 75 unsigned int thresh; 76 76 unsigned int stage; 77 - unsigned int prev_stage; 78 77 unsigned int base; 79 78 /* protects .thresh, .stage and chip registers */ 80 79 struct mutex lock;
+1
drivers/thermal/qcom/tsens-v2.c
··· 107 107 static const struct tsens_ops ops_generic_v2 = { 108 108 .init = init_common, 109 109 .get_temp = get_temp_tsens_valid, 110 + .resume = tsens_resume_common, 110 111 }; 111 112 112 113 struct tsens_plat_data data_tsens_v2 = {
+32 -1
drivers/thermal/qcom/tsens.c
··· 17 17 #include <linux/pm.h> 18 18 #include <linux/regmap.h> 19 19 #include <linux/slab.h> 20 + #include <linux/suspend.h> 20 21 #include <linux/thermal.h> 21 22 #include "../thermal_hwmon.h" 22 23 #include "tsens.h" ··· 265 264 for (i = 0; i < priv->num_sensors; i++) { 266 265 dev_dbg(priv->dev, 267 266 "%s: sensor%d - data_point1:%#x data_point2:%#x\n", 268 - __func__, i, p1[i], p2[i]); 267 + __func__, i, p1[i], p2 ? p2[i] : 0); 269 268 270 269 if (!priv->sensor[i].slope) 271 270 priv->sensor[i].slope = SLOPE_DEFAULT; ··· 1193 1192 put_device(&pdev->dev); 1194 1193 return ret; 1195 1194 } 1195 + 1196 + #ifdef CONFIG_SUSPEND 1197 + static int tsens_reinit(struct tsens_priv *priv) 1198 + { 1199 + if (tsens_version(priv) >= VER_2_X) { 1200 + /* 1201 + * Re-enable the watchdog, unmask the bark. 1202 + * Disable cycle completion monitoring 1203 + */ 1204 + if (priv->feat->has_watchdog) { 1205 + regmap_field_write(priv->rf[WDOG_BARK_MASK], 0); 1206 + regmap_field_write(priv->rf[CC_MON_MASK], 1); 1207 + } 1208 + 1209 + /* Re-enable interrupts */ 1210 + tsens_enable_irq(priv); 1211 + } 1212 + 1213 + return 0; 1214 + } 1215 + 1216 + int tsens_resume_common(struct tsens_priv *priv) 1217 + { 1218 + if (pm_suspend_target_state == PM_SUSPEND_MEM) 1219 + tsens_reinit(priv); 1220 + 1221 + return 0; 1222 + } 1223 + 1224 + #endif /* !CONFIG_SUSPEND */ 1196 1225 1197 1226 static int tsens_register(struct tsens_priv *priv) 1198 1227 {
+5
drivers/thermal/qcom/tsens.h
··· 634 634 int init_common(struct tsens_priv *priv); 635 635 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp); 636 636 int get_temp_common(const struct tsens_sensor *s, int *temp); 637 + #ifdef CONFIG_SUSPEND 638 + int tsens_resume_common(struct tsens_priv *priv); 639 + #else 640 + #define tsens_resume_common NULL 641 + #endif 637 642 638 643 /* TSENS target */ 639 644 extern struct tsens_plat_data data_8960;
+88 -77
drivers/thermal/rcar_gen3_thermal.c
··· 65 65 66 66 #define TSC_MAX_NUM 5 67 67 68 - /* Structure for thermal temperature calculation */ 69 - struct equation_coefs { 70 - int a1; 71 - int b1; 72 - int a2; 73 - int b2; 74 - }; 75 - 76 68 struct rcar_gen3_thermal_priv; 77 69 78 70 struct rcar_thermal_info { 79 - int ths_tj_1; 71 + int scale; 72 + int adj_below; 73 + int adj_above; 80 74 void (*read_fuses)(struct rcar_gen3_thermal_priv *priv); 81 75 }; 82 76 77 + struct equation_set_coef { 78 + int a; 79 + int b; 80 + }; 81 + 83 82 struct rcar_gen3_thermal_tsc { 83 + struct rcar_gen3_thermal_priv *priv; 84 84 void __iomem *base; 85 85 struct thermal_zone_device *zone; 86 - struct equation_coefs coef; 87 - int tj_t; 86 + /* Different coefficients are used depending on a threshold. */ 87 + struct { 88 + struct equation_set_coef below; 89 + struct equation_set_coef above; 90 + } coef; 88 91 int thcode[3]; 89 92 }; 90 93 ··· 96 93 struct thermal_zone_device_ops ops; 97 94 unsigned int num_tscs; 98 95 int ptat[3]; 96 + int tj_t; 99 97 const struct rcar_thermal_info *info; 100 98 }; 101 99 ··· 115 111 /* 116 112 * Linear approximation for temperature 117 113 * 118 - * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a 114 + * [temp] = ((thadj - [reg]) * a) / b + adj 115 + * [reg] = thadj - ([temp] - adj) * b / a 119 116 * 120 117 * The constants a and b are calculated using two triplets of int values PTAT 121 118 * and THCODE. PTAT and THCODE can either be read from hardware or use hard 122 - * coded values from driver. The formula to calculate a and b are taken from 123 - * BSP and sparsely documented and understood. 119 + * coded values from the driver. The formula to calculate a and b are taken from 120 + * the datasheet. Different calculations are needed for a and b depending on 121 + * if the input variables ([temp] or [reg]) are above or below a threshold. The 122 + * threshold is also calculated from PTAT and THCODE using formulas from the 123 + * datasheet. 124 124 * 125 - * Examining the linear formula and the formula used to calculate constants a 126 - * and b while knowing that the span for PTAT and THCODE values are between 127 - * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001. 128 - * Integer also needs to be signed so that leaves 7 bits for binary 129 - * fixed point scaling. 125 + * The constant thadj is one of the THCODE values, which one to use depends on 126 + * the threshold and input value. 127 + * 128 + * The constants adj is taken verbatim from the datasheet. Two values exists, 129 + * which one to use depends on the input value and the calculated threshold. 130 + * Furthermore different SoC models supported by the driver have different sets 131 + * of values. The values for each model are stored in the device match data. 130 132 */ 131 133 132 - #define FIXPT_SHIFT 7 133 - #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT) 134 - #define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT) 135 - #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b)) 136 - #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT) 137 - 138 - #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ 139 - 140 - /* no idea where these constants come from */ 141 - #define TJ_3 -41 142 - 143 - static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv, 144 - struct rcar_gen3_thermal_tsc *tsc, 145 - int ths_tj_1) 134 + static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv) 146 135 { 147 - /* TODO: Find documentation and document constant calculation formula */ 148 - 149 - /* 150 - * Division is not scaled in BSP and if scaled it might overflow 151 - * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled 152 - */ 153 - tsc->tj_t = (FIXPT_INT((priv->ptat[1] - priv->ptat[2]) * (ths_tj_1 - TJ_3)) 154 - / (priv->ptat[0] - priv->ptat[2])) + FIXPT_INT(TJ_3); 155 - 156 - tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[2]), 157 - tsc->tj_t - FIXPT_INT(TJ_3)); 158 - tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3; 159 - 160 - tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[0]), 161 - tsc->tj_t - FIXPT_INT(ths_tj_1)); 162 - tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1; 136 + priv->tj_t = 137 + DIV_ROUND_CLOSEST((priv->ptat[1] - priv->ptat[2]) * priv->info->scale, 138 + priv->ptat[0] - priv->ptat[2]) 139 + + priv->info->adj_below; 163 140 } 164 - 165 - static int rcar_gen3_thermal_round(int temp) 141 + static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv, 142 + struct rcar_gen3_thermal_tsc *tsc) 166 143 { 167 - int result, round_offs; 144 + tsc->coef.below.a = priv->info->scale * (priv->ptat[2] - priv->ptat[1]); 145 + tsc->coef.above.a = priv->info->scale * (priv->ptat[0] - priv->ptat[1]); 168 146 169 - round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 : 170 - -RCAR3_THERMAL_GRAN / 2; 171 - result = (temp + round_offs) / RCAR3_THERMAL_GRAN; 172 - return result * RCAR3_THERMAL_GRAN; 147 + tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]); 148 + tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]); 173 149 } 174 150 175 151 static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp) 176 152 { 177 153 struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz); 178 - int mcelsius, val; 179 - int reg; 154 + struct rcar_gen3_thermal_priv *priv = tsc->priv; 155 + const struct equation_set_coef *coef; 156 + int adj, decicelsius, reg, thcode; 180 157 181 158 /* Read register and convert to mili Celsius */ 182 159 reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; 183 160 184 - if (reg <= tsc->thcode[1]) 185 - val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, 186 - tsc->coef.a1); 187 - else 188 - val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, 189 - tsc->coef.a2); 190 - mcelsius = FIXPT_TO_MCELSIUS(val); 161 + if (reg < tsc->thcode[1]) { 162 + adj = priv->info->adj_below; 163 + coef = &tsc->coef.below; 164 + thcode = tsc->thcode[2]; 165 + } else { 166 + adj = priv->info->adj_above; 167 + coef = &tsc->coef.above; 168 + thcode = tsc->thcode[0]; 169 + } 170 + 171 + /* 172 + * The dividend can't be grown as it might overflow, instead shorten the 173 + * divisor to convert to decidegree Celsius. If we convert after the 174 + * division precision is lost as we will scale up from whole degrees 175 + * Celsius. 176 + */ 177 + decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10); 191 178 192 179 /* Guaranteed operating range is -40C to 125C. */ 193 180 194 - /* Round value to device granularity setting */ 195 - *temp = rcar_gen3_thermal_round(mcelsius); 181 + /* Reporting is done in millidegree Celsius */ 182 + *temp = decicelsius * 100 + adj * 1000; 196 183 197 184 return 0; 198 185 } ··· 191 196 static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, 192 197 int mcelsius) 193 198 { 194 - int celsius, val; 199 + struct rcar_gen3_thermal_priv *priv = tsc->priv; 200 + const struct equation_set_coef *coef; 201 + int adj, celsius, thcode; 195 202 196 203 celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); 197 - if (celsius <= INT_FIXPT(tsc->tj_t)) 198 - val = celsius * tsc->coef.a1 + tsc->coef.b1; 199 - else 200 - val = celsius * tsc->coef.a2 + tsc->coef.b2; 204 + if (celsius < priv->tj_t) { 205 + coef = &tsc->coef.below; 206 + adj = priv->info->adj_below; 207 + thcode = tsc->thcode[2]; 208 + } else { 209 + coef = &tsc->coef.above; 210 + adj = priv->info->adj_above; 211 + thcode = tsc->thcode[0]; 212 + } 201 213 202 - return INT_FIXPT(val); 214 + return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a); 203 215 } 204 216 205 217 static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high) ··· 371 369 } 372 370 373 371 static const struct rcar_thermal_info rcar_m3w_thermal_info = { 374 - .ths_tj_1 = 116, 372 + .scale = 157, 373 + .adj_below = -41, 374 + .adj_above = 116, 375 375 .read_fuses = rcar_gen3_thermal_read_fuses_gen3, 376 376 }; 377 377 378 378 static const struct rcar_thermal_info rcar_gen3_thermal_info = { 379 - .ths_tj_1 = 126, 379 + .scale = 167, 380 + .adj_below = -41, 381 + .adj_above = 126, 380 382 .read_fuses = rcar_gen3_thermal_read_fuses_gen3, 381 383 }; 382 384 383 385 static const struct rcar_thermal_info rcar_gen4_thermal_info = { 384 - .ths_tj_1 = 126, 386 + .scale = 167, 387 + .adj_below = -41, 388 + .adj_above = 126, 385 389 .read_fuses = rcar_gen3_thermal_read_fuses_gen4, 386 390 }; 387 391 ··· 524 516 goto error_unregister; 525 517 } 526 518 519 + tsc->priv = priv; 527 520 tsc->base = devm_ioremap_resource(dev, res); 528 521 if (IS_ERR(tsc->base)) { 529 522 ret = PTR_ERR(tsc->base); ··· 539 530 if (!rcar_gen3_thermal_read_fuses(priv)) 540 531 dev_info(dev, "No calibration values fused, fallback to driver values\n"); 541 532 533 + rcar_gen3_thermal_shared_coefs(priv); 534 + 542 535 for (i = 0; i < priv->num_tscs; i++) { 543 536 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; 544 537 545 538 rcar_gen3_thermal_init(priv, tsc); 546 - rcar_gen3_thermal_calc_coefs(priv, tsc, priv->info->ths_tj_1); 539 + rcar_gen3_thermal_tsc_coefs(priv, tsc); 547 540 548 541 zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops); 549 542 if (IS_ERR(zone)) {
+76 -44
drivers/thermal/thermal_core.c
··· 15 15 #include <linux/slab.h> 16 16 #include <linux/kdev_t.h> 17 17 #include <linux/idr.h> 18 + #include <linux/list_sort.h> 18 19 #include <linux/thermal.h> 19 20 #include <linux/reboot.h> 20 21 #include <linux/string.h> ··· 362 361 } 363 362 364 363 static void handle_thermal_trip(struct thermal_zone_device *tz, 365 - struct thermal_trip *trip) 364 + struct thermal_trip_desc *td, 365 + struct list_head *way_up_list, 366 + struct list_head *way_down_list) 366 367 { 368 + const struct thermal_trip *trip = &td->trip; 369 + int old_threshold; 370 + 367 371 if (trip->temperature == THERMAL_TEMP_INVALID) 368 372 return; 369 373 370 - if (tz->last_temperature == THERMAL_TEMP_INVALID) { 371 - /* Initialization. */ 372 - trip->threshold = trip->temperature; 373 - if (tz->temperature >= trip->threshold) 374 - trip->threshold -= trip->hysteresis; 375 - } else if (tz->last_temperature < trip->threshold) { 374 + /* 375 + * If the trip temperature or hysteresis has been updated recently, 376 + * the threshold needs to be computed again using the new values. 377 + * However, its initial value still reflects the old ones and that 378 + * is what needs to be compared with the previous zone temperature 379 + * to decide which action to take. 380 + */ 381 + old_threshold = td->threshold; 382 + td->threshold = trip->temperature; 383 + 384 + if (tz->last_temperature >= old_threshold && 385 + tz->last_temperature != THERMAL_TEMP_INVALID) { 376 386 /* 377 - * The trip threshold is equal to the trip temperature, unless 378 - * the latter has changed in the meantime. In either case, 379 - * the trip is crossed if the current zone temperature is at 380 - * least equal to its temperature, but otherwise ensure that 381 - * the threshold and the trip temperature will be equal. 382 - */ 383 - if (tz->temperature >= trip->temperature) { 384 - thermal_notify_tz_trip_up(tz, trip); 385 - thermal_debug_tz_trip_up(tz, trip); 386 - trip->threshold = trip->temperature - trip->hysteresis; 387 - } else { 388 - trip->threshold = trip->temperature; 389 - } 390 - } else { 391 - /* 392 - * The previous zone temperature was above or equal to the trip 393 - * threshold, which would be equal to the "low temperature" of 394 - * the trip (its temperature minus its hysteresis), unless the 395 - * trip temperature or hysteresis had changed. In either case, 396 - * the trip is crossed if the current zone temperature is below 397 - * the low temperature of the trip, but otherwise ensure that 398 - * the trip threshold will be equal to the low temperature of 399 - * the trip. 387 + * Mitigation is under way, so it needs to stop if the zone 388 + * temperature falls below the low temperature of the trip. 389 + * In that case, the trip temperature becomes the new threshold. 400 390 */ 401 391 if (tz->temperature < trip->temperature - trip->hysteresis) { 402 - thermal_notify_tz_trip_down(tz, trip); 403 - thermal_debug_tz_trip_down(tz, trip); 404 - trip->threshold = trip->temperature; 392 + list_add(&td->notify_list_node, way_down_list); 393 + td->notify_temp = trip->temperature - trip->hysteresis; 405 394 } else { 406 - trip->threshold = trip->temperature - trip->hysteresis; 395 + td->threshold -= trip->hysteresis; 407 396 } 397 + } else if (tz->temperature >= trip->temperature) { 398 + /* 399 + * There is no mitigation under way, so it needs to be started 400 + * if the zone temperature exceeds the trip one. The new 401 + * threshold is then set to the low temperature of the trip. 402 + */ 403 + list_add_tail(&td->notify_list_node, way_up_list); 404 + td->notify_temp = trip->temperature; 405 + td->threshold -= trip->hysteresis; 408 406 } 409 407 410 408 if (trip->type == THERMAL_TRIP_CRITICAL || trip->type == THERMAL_TRIP_HOT) ··· 455 455 pos->initialized = false; 456 456 } 457 457 458 + static int thermal_trip_notify_cmp(void *ascending, const struct list_head *a, 459 + const struct list_head *b) 460 + { 461 + struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc, 462 + notify_list_node); 463 + struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc, 464 + notify_list_node); 465 + int ret = tdb->notify_temp - tda->notify_temp; 466 + 467 + return ascending ? ret : -ret; 468 + } 469 + 458 470 void __thermal_zone_device_update(struct thermal_zone_device *tz, 459 471 enum thermal_notify_event event) 460 472 { 461 - struct thermal_trip *trip; 473 + struct thermal_trip_desc *td; 474 + LIST_HEAD(way_down_list); 475 + LIST_HEAD(way_up_list); 462 476 463 477 if (tz->suspended) 464 478 return; ··· 486 472 487 473 tz->notify_event = event; 488 474 489 - for_each_trip(tz, trip) 490 - handle_thermal_trip(tz, trip); 475 + for_each_trip_desc(tz, td) 476 + handle_thermal_trip(tz, td, &way_up_list, &way_down_list); 477 + 478 + list_sort(&way_up_list, &way_up_list, thermal_trip_notify_cmp); 479 + list_for_each_entry(td, &way_up_list, notify_list_node) { 480 + thermal_notify_tz_trip_up(tz, &td->trip); 481 + thermal_debug_tz_trip_up(tz, &td->trip); 482 + } 483 + 484 + list_sort(NULL, &way_down_list, thermal_trip_notify_cmp); 485 + list_for_each_entry(td, &way_down_list, notify_list_node) { 486 + thermal_notify_tz_trip_down(tz, &td->trip); 487 + thermal_debug_tz_trip_down(tz, &td->trip); 488 + } 491 489 492 490 monitor_thermal_zone(tz); 493 491 } ··· 792 766 if (trip_index < 0 || trip_index >= tz->num_trips) 793 767 return -EINVAL; 794 768 795 - return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index], cdev, 769 + return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index].trip, cdev, 796 770 upper, lower, weight); 797 771 } 798 772 EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device); ··· 851 825 if (trip_index < 0 || trip_index >= tz->num_trips) 852 826 return -EINVAL; 853 827 854 - return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index], cdev); 828 + return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index].trip, cdev); 855 829 } 856 830 EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device); 857 831 ··· 1247 1221 1248 1222 int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) 1249 1223 { 1250 - int i, ret = -EINVAL; 1224 + const struct thermal_trip_desc *td; 1225 + int ret = -EINVAL; 1251 1226 1252 1227 if (tz->ops.get_crit_temp) 1253 1228 return tz->ops.get_crit_temp(tz, temp); 1254 1229 1255 1230 mutex_lock(&tz->lock); 1256 1231 1257 - for (i = 0; i < tz->num_trips; i++) { 1258 - if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) { 1259 - *temp = tz->trips[i].temperature; 1232 + for_each_trip_desc(tz, td) { 1233 + const struct thermal_trip *trip = &td->trip; 1234 + 1235 + if (trip->type == THERMAL_TRIP_CRITICAL) { 1236 + *temp = trip->temperature; 1260 1237 ret = 0; 1261 1238 break; 1262 1239 } ··· 1303 1274 const struct thermal_zone_params *tzp, 1304 1275 int passive_delay, int polling_delay) 1305 1276 { 1277 + const struct thermal_trip *trip = trips; 1306 1278 struct thermal_zone_device *tz; 1279 + struct thermal_trip_desc *td; 1307 1280 int id; 1308 1281 int result; 1309 1282 struct thermal_governor *governor; ··· 1370 1339 tz->device.class = thermal_class; 1371 1340 tz->devdata = devdata; 1372 1341 tz->num_trips = num_trips; 1373 - memcpy(tz->trips, trips, num_trips * sizeof(*trips)); 1342 + for_each_trip_desc(tz, td) 1343 + td->trip = *trip++; 1374 1344 1375 1345 thermal_set_delay_jiffies(&tz->passive_delay_jiffies, passive_delay); 1376 1346 thermal_set_delay_jiffies(&tz->polling_delay_jiffies, polling_delay);
+117 -2
drivers/thermal/thermal_core.h
··· 15 15 #include "thermal_netlink.h" 16 16 #include "thermal_debugfs.h" 17 17 18 + struct thermal_trip_desc { 19 + struct thermal_trip trip; 20 + struct list_head notify_list_node; 21 + int notify_temp; 22 + int threshold; 23 + }; 24 + 25 + /** 26 + * struct thermal_governor - structure that holds thermal governor information 27 + * @name: name of the governor 28 + * @bind_to_tz: callback called when binding to a thermal zone. If it 29 + * returns 0, the governor is bound to the thermal zone, 30 + * otherwise it fails. 31 + * @unbind_from_tz: callback called when a governor is unbound from a 32 + * thermal zone. 33 + * @throttle: callback called for every trip point even if temperature is 34 + * below the trip point temperature 35 + * @update_tz: callback called when thermal zone internals have changed, e.g. 36 + * thermal cooling instance was added/removed 37 + * @governor_list: node in thermal_governor_list (in thermal_core.c) 38 + */ 39 + struct thermal_governor { 40 + const char *name; 41 + int (*bind_to_tz)(struct thermal_zone_device *tz); 42 + void (*unbind_from_tz)(struct thermal_zone_device *tz); 43 + int (*throttle)(struct thermal_zone_device *tz, 44 + const struct thermal_trip *trip); 45 + void (*update_tz)(struct thermal_zone_device *tz, 46 + enum thermal_notify_event reason); 47 + struct list_head governor_list; 48 + }; 49 + 50 + /** 51 + * struct thermal_zone_device - structure for a thermal zone 52 + * @id: unique id number for each thermal zone 53 + * @type: the thermal zone device type 54 + * @device: &struct device for this thermal zone 55 + * @removal: removal completion 56 + * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature 57 + * @trip_type_attrs: attributes for trip points for sysfs: trip type 58 + * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis 59 + * @mode: current mode of this thermal zone 60 + * @devdata: private pointer for device private data 61 + * @num_trips: number of trip points the thermal zone supports 62 + * @passive_delay_jiffies: number of jiffies to wait between polls when 63 + * performing passive cooling. 64 + * @polling_delay_jiffies: number of jiffies to wait between polls when 65 + * checking whether trip points have been crossed (0 for 66 + * interrupt driven systems) 67 + * @temperature: current temperature. This is only for core code, 68 + * drivers should use thermal_zone_get_temp() to get the 69 + * current temperature 70 + * @last_temperature: previous temperature read 71 + * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION 72 + * @passive: 1 if you've crossed a passive trip point, 0 otherwise. 73 + * @prev_low_trip: the low current temperature if you've crossed a passive 74 + trip point. 75 + * @prev_high_trip: the above current temperature if you've crossed a 76 + passive trip point. 77 + * @need_update: if equals 1, thermal_zone_device_update needs to be invoked. 78 + * @ops: operations this &thermal_zone_device supports 79 + * @tzp: thermal zone parameters 80 + * @governor: pointer to the governor for this thermal zone 81 + * @governor_data: private pointer for governor data 82 + * @thermal_instances: list of &struct thermal_instance of this thermal zone 83 + * @ida: &struct ida to generate unique id for this zone's cooling 84 + * devices 85 + * @lock: lock to protect thermal_instances list 86 + * @node: node in thermal_tz_list (in thermal_core.c) 87 + * @poll_queue: delayed work for polling 88 + * @notify_event: Last notification event 89 + * @suspended: thermal zone suspend indicator 90 + * @trips: array of struct thermal_trip objects 91 + */ 92 + struct thermal_zone_device { 93 + int id; 94 + char type[THERMAL_NAME_LENGTH]; 95 + struct device device; 96 + struct completion removal; 97 + struct attribute_group trips_attribute_group; 98 + struct thermal_attr *trip_temp_attrs; 99 + struct thermal_attr *trip_type_attrs; 100 + struct thermal_attr *trip_hyst_attrs; 101 + enum thermal_device_mode mode; 102 + void *devdata; 103 + int num_trips; 104 + unsigned long passive_delay_jiffies; 105 + unsigned long polling_delay_jiffies; 106 + int temperature; 107 + int last_temperature; 108 + int emul_temperature; 109 + int passive; 110 + int prev_low_trip; 111 + int prev_high_trip; 112 + atomic_t need_update; 113 + struct thermal_zone_device_ops ops; 114 + struct thermal_zone_params *tzp; 115 + struct thermal_governor *governor; 116 + void *governor_data; 117 + struct list_head thermal_instances; 118 + struct ida ida; 119 + struct mutex lock; 120 + struct list_head node; 121 + struct delayed_work poll_queue; 122 + enum thermal_notify_event notify_event; 123 + bool suspended; 124 + #ifdef CONFIG_THERMAL_DEBUGFS 125 + struct thermal_debugfs *debugfs; 126 + #endif 127 + struct thermal_trip_desc trips[] __counted_by(num_trips); 128 + }; 129 + 18 130 /* Default Thermal Governor */ 19 131 #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) 20 132 #define DEFAULT_THERMAL_GOVERNOR "step_wise" ··· 232 120 enum thermal_notify_event reason); 233 121 234 122 /* Helpers */ 235 - #define for_each_trip(__tz, __trip) \ 236 - for (__trip = __tz->trips; __trip - __tz->trips < __tz->num_trips; __trip++) 123 + #define for_each_trip_desc(__tz, __td) \ 124 + for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++) 125 + 126 + #define trip_to_trip_desc(__trip) \ 127 + container_of(__trip, struct thermal_trip_desc, trip) 237 128 238 129 void __thermal_zone_set_trips(struct thermal_zone_device *tz); 239 130 int thermal_zone_trip_id(const struct thermal_zone_device *tz,
+4 -2
drivers/thermal/thermal_debugfs.c
··· 753 753 { 754 754 struct thermal_debugfs *thermal_dbg = s->private; 755 755 struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz; 756 - struct thermal_trip *trip; 756 + struct thermal_trip_desc *td; 757 757 struct tz_episode *tze; 758 758 const char *type; 759 759 int trip_id; ··· 766 766 767 767 seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n"); 768 768 769 - for_each_trip(tz, trip) { 769 + for_each_trip_desc(tz, td) { 770 + const struct thermal_trip *trip = &td->trip; 771 + 770 772 /* 771 773 * There is no possible mitigation happening at the 772 774 * critical trip point, so the stats will be always
+5 -3
drivers/thermal/thermal_helpers.c
··· 50 50 mutex_lock(&tz->lock); 51 51 mutex_lock(&cdev->lock); 52 52 53 - trip = &tz->trips[trip_index]; 53 + trip = &tz->trips[trip_index].trip; 54 54 55 55 list_for_each_entry(pos, &tz->thermal_instances, tz_node) { 56 56 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { ··· 82 82 */ 83 83 int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) 84 84 { 85 - const struct thermal_trip *trip; 85 + const struct thermal_trip_desc *td; 86 86 int crit_temp = INT_MAX; 87 87 int ret = -EINVAL; 88 88 ··· 91 91 ret = tz->ops.get_temp(tz, temp); 92 92 93 93 if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { 94 - for_each_trip(tz, trip) { 94 + for_each_trip_desc(tz, td) { 95 + const struct thermal_trip *trip = &td->trip; 96 + 95 97 if (trip->type == THERMAL_TRIP_CRITICAL) { 96 98 crit_temp = trip->temperature; 97 99 break;
+50 -18
drivers/thermal/thermal_netlink.c
··· 7 7 * Generic netlink for thermal management framework 8 8 */ 9 9 #include <linux/module.h> 10 + #include <linux/notifier.h> 10 11 #include <linux/kernel.h> 11 12 #include <net/genetlink.h> 12 13 #include <uapi/linux/thermal.h> 13 14 14 15 #include "thermal_core.h" 15 - 16 - enum thermal_genl_multicast_groups { 17 - THERMAL_GENL_SAMPLING_GROUP = 0, 18 - THERMAL_GENL_EVENT_GROUP = 1, 19 - }; 20 16 21 17 static const struct genl_multicast_group thermal_genl_mcgrps[] = { 22 18 [THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, ··· 70 74 71 75 typedef int (*cb_t)(struct param *); 72 76 73 - static struct genl_family thermal_gnl_family; 77 + static struct genl_family thermal_genl_family; 78 + static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain); 74 79 75 80 static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group) 76 81 { 77 - return genl_has_listeners(&thermal_gnl_family, &init_net, group); 82 + return genl_has_listeners(&thermal_genl_family, &init_net, group); 78 83 } 79 84 80 85 /************************** Sampling encoding *******************************/ ··· 92 95 if (!skb) 93 96 return -ENOMEM; 94 97 95 - hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, 98 + hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, 96 99 THERMAL_GENL_SAMPLING_TEMP); 97 100 if (!hdr) 98 101 goto out_free; ··· 105 108 106 109 genlmsg_end(skb, hdr); 107 110 108 - genlmsg_multicast(&thermal_gnl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL); 111 + genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL); 109 112 110 113 return 0; 111 114 out_cancel: ··· 279 282 return -ENOMEM; 280 283 p->msg = msg; 281 284 282 - hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event); 285 + hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event); 283 286 if (!hdr) 284 287 goto out_free_msg; 285 288 ··· 289 292 290 293 genlmsg_end(msg, hdr); 291 294 292 - genlmsg_multicast(&thermal_gnl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL); 295 + genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL); 293 296 294 297 return 0; 295 298 ··· 442 445 static int thermal_genl_cmd_tz_get_trip(struct param *p) 443 446 { 444 447 struct sk_buff *msg = p->msg; 445 - const struct thermal_trip *trip; 448 + const struct thermal_trip_desc *td; 446 449 struct thermal_zone_device *tz; 447 450 struct nlattr *start_trip; 448 451 int id; ··· 462 465 463 466 mutex_lock(&tz->lock); 464 467 465 - for_each_trip(tz, trip) { 468 + for_each_trip_desc(tz, td) { 469 + const struct thermal_trip *trip = &td->trip; 470 + 466 471 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, 467 472 thermal_zone_trip_id(tz, trip)) || 468 473 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) || ··· 592 593 int ret; 593 594 void *hdr; 594 595 595 - hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd); 596 + hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd); 596 597 if (!hdr) 597 598 return -EMSGSIZE; 598 599 ··· 624 625 return -ENOMEM; 625 626 p.msg = msg; 626 627 627 - hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd); 628 + hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd); 628 629 if (!hdr) 629 630 goto out_free_msg; 630 631 ··· 642 643 nlmsg_free(msg); 643 644 644 645 return ret; 646 + } 647 + 648 + static int thermal_genl_bind(int mcgrp) 649 + { 650 + struct thermal_genl_notify n = { .mcgrp = mcgrp }; 651 + 652 + if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) 653 + return -EINVAL; 654 + 655 + blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n); 656 + return 0; 657 + } 658 + 659 + static void thermal_genl_unbind(int mcgrp) 660 + { 661 + struct thermal_genl_notify n = { .mcgrp = mcgrp }; 662 + 663 + if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) 664 + return; 665 + 666 + blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n); 645 667 } 646 668 647 669 static const struct genl_small_ops thermal_genl_ops[] = { ··· 693 673 }, 694 674 }; 695 675 696 - static struct genl_family thermal_gnl_family __ro_after_init = { 676 + static struct genl_family thermal_genl_family __ro_after_init = { 697 677 .hdrsize = 0, 698 678 .name = THERMAL_GENL_FAMILY_NAME, 699 679 .version = THERMAL_GENL_VERSION, 700 680 .maxattr = THERMAL_GENL_ATTR_MAX, 701 681 .policy = thermal_genl_policy, 682 + .bind = thermal_genl_bind, 683 + .unbind = thermal_genl_unbind, 702 684 .small_ops = thermal_genl_ops, 703 685 .n_small_ops = ARRAY_SIZE(thermal_genl_ops), 704 686 .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1, ··· 708 686 .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), 709 687 }; 710 688 689 + int thermal_genl_register_notifier(struct notifier_block *nb) 690 + { 691 + return blocking_notifier_chain_register(&thermal_genl_chain, nb); 692 + } 693 + 694 + int thermal_genl_unregister_notifier(struct notifier_block *nb) 695 + { 696 + return blocking_notifier_chain_unregister(&thermal_genl_chain, nb); 697 + } 698 + 711 699 int __init thermal_netlink_init(void) 712 700 { 713 - return genl_register_family(&thermal_gnl_family); 701 + return genl_register_family(&thermal_genl_family); 714 702 } 715 703 716 704 void __init thermal_netlink_exit(void) 717 705 { 718 - genl_unregister_family(&thermal_gnl_family); 706 + genl_unregister_family(&thermal_genl_family); 719 707 }
+26
drivers/thermal/thermal_netlink.h
··· 10 10 int efficiency; 11 11 }; 12 12 13 + enum thermal_genl_multicast_groups { 14 + THERMAL_GENL_SAMPLING_GROUP = 0, 15 + THERMAL_GENL_EVENT_GROUP = 1, 16 + THERMAL_GENL_MAX_GROUP = THERMAL_GENL_EVENT_GROUP, 17 + }; 18 + 19 + #define THERMAL_NOTIFY_BIND 0 20 + #define THERMAL_NOTIFY_UNBIND 1 21 + 22 + struct thermal_genl_notify { 23 + int mcgrp; 24 + }; 25 + 13 26 struct thermal_zone_device; 14 27 struct thermal_trip; 15 28 struct thermal_cooling_device; ··· 31 18 #ifdef CONFIG_THERMAL_NETLINK 32 19 int __init thermal_netlink_init(void); 33 20 void __init thermal_netlink_exit(void); 21 + int thermal_genl_register_notifier(struct notifier_block *nb); 22 + int thermal_genl_unregister_notifier(struct notifier_block *nb); 23 + 34 24 int thermal_notify_tz_create(const struct thermal_zone_device *tz); 35 25 int thermal_notify_tz_delete(const struct thermal_zone_device *tz); 36 26 int thermal_notify_tz_enable(const struct thermal_zone_device *tz); ··· 60 44 } 61 45 62 46 static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz) 47 + { 48 + return 0; 49 + } 50 + 51 + static inline int thermal_genl_register_notifier(struct notifier_block *nb) 52 + { 53 + return 0; 54 + } 55 + 56 + static inline int thermal_genl_unregister_notifier(struct notifier_block *nb) 63 57 { 64 58 return 0; 65 59 }
+10 -10
drivers/thermal/thermal_sysfs.c
··· 88 88 if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1) 89 89 return -EINVAL; 90 90 91 - switch (tz->trips[trip_id].type) { 91 + switch (tz->trips[trip_id].trip.type) { 92 92 case THERMAL_TRIP_CRITICAL: 93 93 return sprintf(buf, "critical\n"); 94 94 case THERMAL_TRIP_HOT: ··· 120 120 121 121 mutex_lock(&tz->lock); 122 122 123 - trip = &tz->trips[trip_id]; 123 + trip = &tz->trips[trip_id].trip; 124 124 125 125 if (temp != trip->temperature) { 126 126 if (tz->ops.set_trip_temp) { ··· 150 150 if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1) 151 151 return -EINVAL; 152 152 153 - return sprintf(buf, "%d\n", tz->trips[trip_id].temperature); 153 + return sprintf(buf, "%d\n", tz->trips[trip_id].trip.temperature); 154 154 } 155 155 156 156 static ssize_t ··· 171 171 172 172 mutex_lock(&tz->lock); 173 173 174 - trip = &tz->trips[trip_id]; 174 + trip = &tz->trips[trip_id].trip; 175 175 176 176 if (hyst != trip->hysteresis) { 177 177 trip->hysteresis = hyst; ··· 194 194 if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1) 195 195 return -EINVAL; 196 196 197 - return sprintf(buf, "%d\n", tz->trips[trip_id].hysteresis); 197 + return sprintf(buf, "%d\n", tz->trips[trip_id].trip.hysteresis); 198 198 } 199 199 200 200 static ssize_t ··· 393 393 */ 394 394 static int create_trip_attrs(struct thermal_zone_device *tz) 395 395 { 396 - const struct thermal_trip *trip; 396 + const struct thermal_trip_desc *td; 397 397 struct attribute **attrs; 398 398 399 399 /* This function works only for zones with at least one trip */ ··· 429 429 return -ENOMEM; 430 430 } 431 431 432 - for_each_trip(tz, trip) { 433 - int indx = thermal_zone_trip_id(tz, trip); 432 + for_each_trip_desc(tz, td) { 433 + int indx = thermal_zone_trip_id(tz, &td->trip); 434 434 435 435 /* create trip type attribute */ 436 436 snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH, ··· 452 452 tz->trip_temp_attrs[indx].name; 453 453 tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO; 454 454 tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show; 455 - if (trip->flags & THERMAL_TRIP_FLAG_RW_TEMP) { 455 + if (td->trip.flags & THERMAL_TRIP_FLAG_RW_TEMP) { 456 456 tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR; 457 457 tz->trip_temp_attrs[indx].attr.store = 458 458 trip_point_temp_store; ··· 467 467 tz->trip_hyst_attrs[indx].name; 468 468 tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO; 469 469 tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show; 470 - if (trip->flags & THERMAL_TRIP_FLAG_RW_HYST) { 470 + if (td->trip.flags & THERMAL_TRIP_FLAG_RW_HYST) { 471 471 tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR; 472 472 tz->trip_hyst_attrs[indx].attr.store = 473 473 trip_point_hyst_store;
+2
drivers/thermal/thermal_trace.h
··· 9 9 #include <linux/thermal.h> 10 10 #include <linux/tracepoint.h> 11 11 12 + #include "thermal_core.h" 13 + 12 14 TRACE_DEFINE_ENUM(THERMAL_TRIP_CRITICAL); 13 15 TRACE_DEFINE_ENUM(THERMAL_TRIP_HOT); 14 16 TRACE_DEFINE_ENUM(THERMAL_TRIP_PASSIVE);
+2
drivers/thermal/thermal_trace_ipa.h
··· 7 7 8 8 #include <linux/tracepoint.h> 9 9 10 + #include "thermal_core.h" 11 + 10 12 TRACE_EVENT(thermal_power_allocator, 11 13 TP_PROTO(struct thermal_zone_device *tz, u32 total_req_power, 12 14 u32 total_granted_power, int num_actors, u32 power_range,
+8 -7
drivers/thermal/thermal_trip.c
··· 13 13 int (*cb)(struct thermal_trip *, void *), 14 14 void *data) 15 15 { 16 - struct thermal_trip *trip; 16 + struct thermal_trip_desc *td; 17 17 int ret; 18 18 19 - for_each_trip(tz, trip) { 20 - ret = cb(trip, data); 19 + for_each_trip_desc(tz, td) { 20 + ret = cb(&td->trip, data); 21 21 if (ret) 22 22 return ret; 23 23 } ··· 63 63 */ 64 64 void __thermal_zone_set_trips(struct thermal_zone_device *tz) 65 65 { 66 - const struct thermal_trip *trip; 66 + const struct thermal_trip_desc *td; 67 67 int low = -INT_MAX, high = INT_MAX; 68 68 int ret; 69 69 ··· 72 72 if (!tz->ops.set_trips) 73 73 return; 74 74 75 - for_each_trip(tz, trip) { 75 + for_each_trip_desc(tz, td) { 76 + const struct thermal_trip *trip = &td->trip; 76 77 int trip_low; 77 78 78 79 trip_low = trip->temperature - trip->hysteresis; ··· 111 110 if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip) 112 111 return -EINVAL; 113 112 114 - *trip = tz->trips[trip_id]; 113 + *trip = tz->trips[trip_id].trip; 115 114 return 0; 116 115 } 117 116 EXPORT_SYMBOL_GPL(__thermal_zone_get_trip); ··· 136 135 * Assume the trip to be located within the bounds of the thermal 137 136 * zone's trips[] table. 138 137 */ 139 - return trip - tz->trips; 138 + return trip_to_trip_desc(trip) - tz->trips; 140 139 } 141 140 void thermal_zone_trip_updated(struct thermal_zone_device *tz, 142 141 const struct thermal_trip *trip)
+26
include/dt-bindings/thermal/mediatek,lvts-thermal.h
··· 16 16 #define MT7988_ETHWARP_0 6 17 17 #define MT7988_ETHWARP_1 7 18 18 19 + #define MT8186_LITTLE_CPU0 0 20 + #define MT8186_LITTLE_CPU1 1 21 + #define MT8186_LITTLE_CPU2 2 22 + #define MT8186_CAM 3 23 + #define MT8186_BIG_CPU0 4 24 + #define MT8186_BIG_CPU1 5 25 + #define MT8186_NNA 6 26 + #define MT8186_ADSP 7 27 + #define MT8186_MFG 8 28 + 29 + #define MT8188_MCU_LITTLE_CPU0 0 30 + #define MT8188_MCU_LITTLE_CPU1 1 31 + #define MT8188_MCU_LITTLE_CPU2 2 32 + #define MT8188_MCU_LITTLE_CPU3 3 33 + #define MT8188_MCU_BIG_CPU0 4 34 + #define MT8188_MCU_BIG_CPU1 5 35 + 36 + #define MT8188_AP_APU 0 37 + #define MT8188_AP_GPU1 1 38 + #define MT8188_AP_GPU2 2 39 + #define MT8188_AP_SOC1 3 40 + #define MT8188_AP_SOC2 4 41 + #define MT8188_AP_SOC3 5 42 + #define MT8188_AP_CAM1 6 43 + #define MT8188_AP_CAM2 7 44 + 19 45 #define MT8195_MCU_BIG_CPU0 0 20 46 #define MT8195_MCU_BIG_CPU1 1 21 47 #define MT8195_MCU_BIG_CPU2 2
+2 -107
include/linux/thermal.h
··· 61 61 * struct thermal_trip - representation of a point in temperature domain 62 62 * @temperature: temperature value in miliCelsius 63 63 * @hysteresis: relative hysteresis in miliCelsius 64 - * @threshold: trip crossing notification threshold miliCelsius 65 64 * @type: trip point type 66 65 * @priv: pointer to driver data associated with this trip 67 66 * @flags: flags representing binary properties of the trip ··· 68 69 struct thermal_trip { 69 70 int temperature; 70 71 int hysteresis; 71 - int threshold; 72 72 enum thermal_trip_type type; 73 73 u8 flags; 74 74 void *priv; ··· 78 80 79 81 #define THERMAL_TRIP_FLAG_RW (THERMAL_TRIP_FLAG_RW_TEMP | \ 80 82 THERMAL_TRIP_FLAG_RW_HYST) 83 + 84 + struct thermal_zone_device; 81 85 82 86 struct thermal_zone_device_ops { 83 87 int (*bind) (struct thermal_zone_device *, ··· 124 124 #ifdef CONFIG_THERMAL_DEBUGFS 125 125 struct thermal_debugfs *debugfs; 126 126 #endif 127 - }; 128 - 129 - /** 130 - * struct thermal_zone_device - structure for a thermal zone 131 - * @id: unique id number for each thermal zone 132 - * @type: the thermal zone device type 133 - * @device: &struct device for this thermal zone 134 - * @removal: removal completion 135 - * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature 136 - * @trip_type_attrs: attributes for trip points for sysfs: trip type 137 - * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis 138 - * @mode: current mode of this thermal zone 139 - * @devdata: private pointer for device private data 140 - * @num_trips: number of trip points the thermal zone supports 141 - * @passive_delay_jiffies: number of jiffies to wait between polls when 142 - * performing passive cooling. 143 - * @polling_delay_jiffies: number of jiffies to wait between polls when 144 - * checking whether trip points have been crossed (0 for 145 - * interrupt driven systems) 146 - * @temperature: current temperature. This is only for core code, 147 - * drivers should use thermal_zone_get_temp() to get the 148 - * current temperature 149 - * @last_temperature: previous temperature read 150 - * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION 151 - * @passive: 1 if you've crossed a passive trip point, 0 otherwise. 152 - * @prev_low_trip: the low current temperature if you've crossed a passive 153 - trip point. 154 - * @prev_high_trip: the above current temperature if you've crossed a 155 - passive trip point. 156 - * @need_update: if equals 1, thermal_zone_device_update needs to be invoked. 157 - * @ops: operations this &thermal_zone_device supports 158 - * @tzp: thermal zone parameters 159 - * @governor: pointer to the governor for this thermal zone 160 - * @governor_data: private pointer for governor data 161 - * @thermal_instances: list of &struct thermal_instance of this thermal zone 162 - * @ida: &struct ida to generate unique id for this zone's cooling 163 - * devices 164 - * @lock: lock to protect thermal_instances list 165 - * @node: node in thermal_tz_list (in thermal_core.c) 166 - * @poll_queue: delayed work for polling 167 - * @notify_event: Last notification event 168 - * @suspended: thermal zone suspend indicator 169 - * @trips: array of struct thermal_trip objects 170 - */ 171 - struct thermal_zone_device { 172 - int id; 173 - char type[THERMAL_NAME_LENGTH]; 174 - struct device device; 175 - struct completion removal; 176 - struct attribute_group trips_attribute_group; 177 - struct thermal_attr *trip_temp_attrs; 178 - struct thermal_attr *trip_type_attrs; 179 - struct thermal_attr *trip_hyst_attrs; 180 - enum thermal_device_mode mode; 181 - void *devdata; 182 - int num_trips; 183 - unsigned long passive_delay_jiffies; 184 - unsigned long polling_delay_jiffies; 185 - int temperature; 186 - int last_temperature; 187 - int emul_temperature; 188 - int passive; 189 - int prev_low_trip; 190 - int prev_high_trip; 191 - atomic_t need_update; 192 - struct thermal_zone_device_ops ops; 193 - struct thermal_zone_params *tzp; 194 - struct thermal_governor *governor; 195 - void *governor_data; 196 - struct list_head thermal_instances; 197 - struct ida ida; 198 - struct mutex lock; 199 - struct list_head node; 200 - struct delayed_work poll_queue; 201 - enum thermal_notify_event notify_event; 202 - bool suspended; 203 - #ifdef CONFIG_THERMAL_DEBUGFS 204 - struct thermal_debugfs *debugfs; 205 - #endif 206 - struct thermal_trip trips[] __counted_by(num_trips); 207 - }; 208 - 209 - /** 210 - * struct thermal_governor - structure that holds thermal governor information 211 - * @name: name of the governor 212 - * @bind_to_tz: callback called when binding to a thermal zone. If it 213 - * returns 0, the governor is bound to the thermal zone, 214 - * otherwise it fails. 215 - * @unbind_from_tz: callback called when a governor is unbound from a 216 - * thermal zone. 217 - * @throttle: callback called for every trip point even if temperature is 218 - * below the trip point temperature 219 - * @update_tz: callback called when thermal zone internals have changed, e.g. 220 - * thermal cooling instance was added/removed 221 - * @governor_list: node in thermal_governor_list (in thermal_core.c) 222 - */ 223 - struct thermal_governor { 224 - const char *name; 225 - int (*bind_to_tz)(struct thermal_zone_device *tz); 226 - void (*unbind_from_tz)(struct thermal_zone_device *tz); 227 - int (*throttle)(struct thermal_zone_device *tz, 228 - const struct thermal_trip *trip); 229 - void (*update_tz)(struct thermal_zone_device *tz, 230 - enum thermal_notify_event reason); 231 - struct list_head governor_list; 232 127 }; 233 128 234 129 /* Structure to define Thermal Zone parameters */