mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
Thermal control updates for 6.20-rc1/7.0-rc1
- Add Panther Lake, Wildcat Lake and Nova Lake processor IDs to the
list of supported processors in the intel_tcc_cooling thermal
driver (Srinivas Pandruvada)
- Drop unnecessary explicit driver data clearing on removal from the
intel_pch_thermal driver (Kaushlendra Kumar)
- Add support for "slow" workload type hints to the int340x
processor_thermal driver and enable it on the Panther Lake
platform (Srinivas Pandruvada)
- Use sysfs_emit{_at}() in sysfs show functions in Intel thermal
drivers (Thorsten Blum)
- Update the x86_pkg_temp_thermal driver to handle THERMAL_TEMP_INVALID
that can be passed to it via sysfs as expected (Rafael Wysocki)
- Drop a redundant local variable from the intel_tcc_cooling thermal
driver and fix a kerneldoc comment typo in the TCC library (Sumeet
Pawnikar)
- Fix CFLAGS and LDFLAGS in the pkg-config libthermal template (Romain
Gantois)
- Support multiple temp to raw conversion functions in the Mediatek
LVTS thermal driver and add MT8196 and MT6991 support to it (Laura
Nao)
- Add Mediatek LVTS driver support for MT7987 (Frank Wunderlich)
- Use the existing HZ_PER_MHZ macro on STM32 (Andy Shevchenko)
- Use the existing clamp() macro on BCM2835 (Thorsten Blum)
- Make the reset line optional in order to support new Renesas SoCs
where it is not available and add support for RZ/T2H and RZ/N2H
to the rzg3e thermal driver (Cosmin Tanislav)
- Document RZ/V2N TSU in the r9a09g047-tsu DT bindings (Ovidiu
Panait)
- Fix all kernel-doc warnings in the internal thermal core header
file (Randy Dunlap)
- Fix a device node reference leak in thermal_of_cm_lookup() (Felix Gu)
- Replace some old-style library function calls with ones that are
currently recommended in several places in the thermal core and
debugfs code (Sumeet Pawnikar, Thorsten Blum)
-----BEGIN PGP SIGNATURE-----
iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmmDnCoSHHJqd0Byand5
c29ja2kubmV0AAoJEO5fvZ0v1OO1lyoIAJ5gQviWP4gmifh/osuBbc6EdN5qBnwL
d6oj6oKoTKYC8TCzgIVNf4sOU9BziJgiuB5WSUDqFG6MPy+C/kSztlZ3yVQDpJzW
XgGdgLMK/Sdza6IE8+AfHN3WeYTA4BD7Otda1L965FAY8PN1W4ZzzZyydWHd27Gt
4D9ruuCFZQ52EatMtbtpAX+loapIIFD3jUZ6fxBK1ziAN3en2F57xC4GeJvbS9fz
zpBJld+p19CdfTd/NCHMdqVTc01fL0d6cwnpzdH+aeqmam61SYAzLQrk0Wu3wlfr
m8jqx+F7qL9/X/CUSOoy50K7pBQimUAh80L7YPBV+/gwpW3IO4Ll3KU=
=AqXf
-----END PGP SIGNATURE-----
Merge tag 'thermal-6.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull thermal control updates from Rafael Wysocki:
"These add support for "slow" (long-term trend) workload type hints to
the Intel int340x thermal driver and selftests (and enable it for
Panther Lake), add support for MT8196 along with DT bindings and for
MT7987 to the Mediatek LVTS thermal driver, add support for RZ/T2H and
RZ/N2H along with DT bindings to the Renesas rzg3e thermal driver, add
support for the Panther Lake, Wildcat Lake and Nova Lake processors to
the intel_tcc_cooling driver, fix bugs, make some cosmetic changes
including code cleanups and library function substitutions, and update
documentation.
Specifics:
- Add Panther Lake, Wildcat Lake and Nova Lake processor IDs to the
list of supported processors in the intel_tcc_cooling thermal
driver (Srinivas Pandruvada)
- Drop unnecessary explicit driver data clearing on removal from the
intel_pch_thermal driver (Kaushlendra Kumar)
- Add support for "slow" workload type hints to the int340x
processor_thermal driver and enable it on the Panther Lake platform
(Srinivas Pandruvada)
- Use sysfs_emit{_at}() in sysfs show functions in Intel thermal
drivers (Thorsten Blum)
- Update the x86_pkg_temp_thermal driver to handle
THERMAL_TEMP_INVALID that can be passed to it via sysfs as expected
(Rafael Wysocki)
- Drop a redundant local variable from the intel_tcc_cooling thermal
driver and fix a kerneldoc comment typo in the TCC library (Sumeet
Pawnikar)
- Fix CFLAGS and LDFLAGS in the pkg-config libthermal template
(Romain Gantois)
- Support multiple temp to raw conversion functions in the Mediatek
LVTS thermal driver and add MT8196 and MT6991 support to it (Laura
Nao)
- Add Mediatek LVTS driver support for MT7987 (Frank Wunderlich)
- Use the existing HZ_PER_MHZ macro on STM32 (Andy Shevchenko)
- Use the existing clamp() macro on BCM2835 (Thorsten Blum)
- Make the reset line optional in order to support new Renesas SoCs
where it is not available and add support for RZ/T2H and RZ/N2H to
the rzg3e thermal driver (Cosmin Tanislav)
- Document RZ/V2N TSU in the r9a09g047-tsu DT bindings (Ovidiu
Panait)
- Fix all kernel-doc warnings in the internal thermal core header
file (Randy Dunlap)
- Fix a device node reference leak in thermal_of_cm_lookup() (Felix
Gu)
- Replace some old-style library function calls with ones that are
currently recommended in several places in the thermal core and
debugfs code (Sumeet Pawnikar, Thorsten Blum)
* tag 'thermal-6.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (34 commits)
drivers: thermal: intel: tcc_cooling: Drop redundant local variable
thermal/of: Fix reference leak in thermal_of_cm_lookup()
thermal: core: thermal_core.h: fix all kernel-doc warnings
thermal: intel: x86_pkg_temp_thermal: Handle invalid temperature
thermal: renesas: rzg3e: add support for RZ/T2H and RZ/N2H
dt-bindings: thermal: r9a09g047-tsu: document RZ/T2H and RZ/N2H
thermal: renesas: rzg3e: make calibration value retrieval per-chip
thermal: renesas: rzg3e: make min and max temperature per-chip
thermal: renesas: rzg3e: make reset optional
dt-bindings: thermal: r9a09g047-tsu: Document RZ/V2N TSU
thermal/drivers/broadcom: Use clamp to simplify bcm2835_thermal_temp2adc
thermal/drivers/stm32: Use predefined HZ_PER_MHZ instead of a custom one
thermal/drivers/mediatek/lvts_thermal: Add mt7987 support
dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT7987
dt-bindings: nvmem: mediatek: efuse: Add support for MT8196
thermal/drivers/mediatek/lvts_thermal: Add MT8196 support
thermal/drivers/mediatek/lvts: Support MSR offset for 16-bit calibration data
thermal/drivers/mediatek/lvts: Add support for ATP mode
thermal/drivers/mediatek/lvts: Add lvts_temp_to_raw variant
thermal/drivers/mediatek/lvts: Add platform ops to support alternative conversion logic
...
This commit is contained in:
commit
0506158ac7
26 changed files with 654 additions and 168 deletions
|
|
@ -28,6 +28,7 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt8188-efuse
|
||||
- mediatek,mt8189-efuse
|
||||
- mediatek,mt8196-efuse
|
||||
- const: mediatek,mt8186-efuse
|
||||
- const: mediatek,mt8186-efuse
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ description: |
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7987-lvts-ap
|
||||
- mediatek,mt7988-lvts-ap
|
||||
- mediatek,mt8186-lvts
|
||||
- mediatek,mt8188-lvts-ap
|
||||
|
|
@ -26,6 +27,8 @@ properties:
|
|||
- mediatek,mt8192-lvts-mcu
|
||||
- mediatek,mt8195-lvts-ap
|
||||
- mediatek,mt8195-lvts-mcu
|
||||
- mediatek,mt8196-lvts-ap
|
||||
- mediatek,mt8196-lvts-mcu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -17,10 +17,17 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: renesas,r9a09g047-tsu # RZ/G3E
|
||||
- enum:
|
||||
- renesas,r9a09g047-tsu # RZ/G3E
|
||||
- renesas,r9a09g077-tsu # RZ/T2H
|
||||
- items:
|
||||
- const: renesas,r9a09g057-tsu # RZ/V2H
|
||||
- enum:
|
||||
- renesas,r9a09g056-tsu # RZ/V2N
|
||||
- renesas,r9a09g057-tsu # RZ/V2H
|
||||
- const: renesas,r9a09g047-tsu # RZ/G3E
|
||||
- items:
|
||||
- const: renesas,r9a09g087-tsu # RZ/N2H
|
||||
- const: renesas,r9a09g077-tsu # RZ/T2H
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -63,12 +70,31 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- resets
|
||||
- power-domains
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- "#thermal-sensor-cells"
|
||||
- renesas,tsu-trim
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g047-tsu
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
- renesas,tsu-trim
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g077-tsu
|
||||
then:
|
||||
properties:
|
||||
resets: false
|
||||
renesas,tsu-trim: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
|
|||
|
|
@ -375,6 +375,9 @@ based on the processor generation.
|
|||
``workload_hint_enable`` (RW)
|
||||
Enable firmware to send workload type hints to user space.
|
||||
|
||||
``workload_slow_hint_enable`` (RW)
|
||||
Enable firmware to send slow workload type hints to user space.
|
||||
|
||||
``notification_delay_ms`` (RW)
|
||||
Minimum delay in milliseconds before firmware will notify OS. This is
|
||||
for the rate control of notifications. This delay is between changing
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
@ -80,12 +81,7 @@ static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
|
|||
temp -= offset;
|
||||
temp /= slope;
|
||||
|
||||
if (temp < 0)
|
||||
temp = 0;
|
||||
if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
|
||||
temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
|
||||
|
||||
return temp;
|
||||
return clamp(temp, 0, (int)BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1);
|
||||
}
|
||||
|
||||
static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <asm/msr.h>
|
||||
#include "int340x_thermal_zone.h"
|
||||
|
|
@ -23,7 +24,7 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
|
|||
{ \
|
||||
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%lu\n",\
|
||||
return sysfs_emit(buf, "%lu\n",\
|
||||
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
|||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
return sprintf(buf, "%d\n", offset);
|
||||
return sysfs_emit(buf, "%d\n", offset);
|
||||
}
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
MODULE_IMPORT_NS("INT340X_THERMAL");
|
||||
|
|
@ -211,9 +212,9 @@ static ssize_t suffix##_show(struct device *dev,\
|
|||
ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
|
||||
err = get_mapped_string(mapping, attr->attr.name, ret, &str);\
|
||||
if (!err)\
|
||||
return sprintf(buf, "%s\n", str);\
|
||||
return sysfs_emit(buf, "%s\n", str);\
|
||||
if (err == -EOPNOTSUPP)\
|
||||
return sprintf(buf, "%u\n", ret);\
|
||||
return sysfs_emit(buf, "%u\n", ret);\
|
||||
return err;\
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +399,7 @@ static ssize_t rfi_restriction_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%llu\n", resp);
|
||||
return sysfs_emit(buf, "%llu\n", resp);
|
||||
}
|
||||
|
||||
static ssize_t ddr_data_rate_show(struct device *dev,
|
||||
|
|
@ -413,7 +414,7 @@ static ssize_t ddr_data_rate_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%llu\n", resp);
|
||||
return sysfs_emit(buf, "%llu\n", resp);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(rfi_restriction);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#define SOC_WT GENMASK_ULL(47, 40)
|
||||
|
||||
#define SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT 22
|
||||
#define SOC_WT_PREDICTION_INT_ENABLE_BIT 23
|
||||
|
||||
#define SOC_WT_PREDICTION_INT_ACTIVE BIT(2)
|
||||
|
|
@ -47,6 +48,7 @@ static u16 notify_delay_ms = 1024;
|
|||
|
||||
static DEFINE_MUTEX(wt_lock);
|
||||
static u8 wt_enable;
|
||||
static u8 wt_slow_enable;
|
||||
|
||||
/* Show current predicted workload type index */
|
||||
static ssize_t workload_type_index_show(struct device *dev,
|
||||
|
|
@ -59,7 +61,7 @@ static ssize_t workload_type_index_show(struct device *dev,
|
|||
int wt;
|
||||
|
||||
mutex_lock(&wt_lock);
|
||||
if (!wt_enable) {
|
||||
if (!wt_enable && !wt_slow_enable) {
|
||||
mutex_unlock(&wt_lock);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
|
@ -84,9 +86,9 @@ static ssize_t workload_hint_enable_show(struct device *dev,
|
|||
return sysfs_emit(buf, "%d\n", wt_enable);
|
||||
}
|
||||
|
||||
static ssize_t workload_hint_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t workload_hint_enable(struct device *dev, u8 enable_bit, u8 *status,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u8 mode;
|
||||
|
|
@ -99,17 +101,17 @@ static ssize_t workload_hint_enable_store(struct device *dev,
|
|||
|
||||
if (mode)
|
||||
ret = processor_thermal_mbox_interrupt_config(pdev, true,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT,
|
||||
enable_bit,
|
||||
notify_delay);
|
||||
else
|
||||
ret = processor_thermal_mbox_interrupt_config(pdev, false,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT, 0);
|
||||
enable_bit, 0);
|
||||
|
||||
if (ret)
|
||||
goto ret_enable_store;
|
||||
|
||||
ret = size;
|
||||
wt_enable = mode;
|
||||
*status = mode;
|
||||
|
||||
ret_enable_store:
|
||||
mutex_unlock(&wt_lock);
|
||||
|
|
@ -117,8 +119,28 @@ ret_enable_store:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t workload_hint_enable_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
return workload_hint_enable(dev, SOC_WT_PREDICTION_INT_ENABLE_BIT, &wt_enable,
|
||||
attr, buf, size);
|
||||
}
|
||||
static DEVICE_ATTR_RW(workload_hint_enable);
|
||||
|
||||
static ssize_t workload_slow_hint_enable_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", wt_slow_enable);
|
||||
}
|
||||
|
||||
static ssize_t workload_slow_hint_enable_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
return workload_hint_enable(dev, SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT, &wt_slow_enable,
|
||||
attr, buf, size);
|
||||
}
|
||||
static DEVICE_ATTR_RW(workload_slow_hint_enable);
|
||||
|
||||
static ssize_t notification_delay_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -178,16 +200,35 @@ static ssize_t notification_delay_ms_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR_RW(notification_delay_ms);
|
||||
|
||||
static umode_t workload_hint_attr_visible(struct kobject *kobj, struct attribute *attr, int unused)
|
||||
{
|
||||
if (attr != &dev_attr_workload_slow_hint_enable.attr)
|
||||
return attr->mode;
|
||||
|
||||
switch (to_pci_dev(kobj_to_dev(kobj))->device) {
|
||||
case PCI_DEVICE_ID_INTEL_LNLM_THERMAL:
|
||||
case PCI_DEVICE_ID_INTEL_MTLP_THERMAL:
|
||||
case PCI_DEVICE_ID_INTEL_ARL_S_THERMAL:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
static struct attribute *workload_hint_attrs[] = {
|
||||
&dev_attr_workload_type_index.attr,
|
||||
&dev_attr_workload_hint_enable.attr,
|
||||
&dev_attr_workload_slow_hint_enable.attr,
|
||||
&dev_attr_notification_delay_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group workload_hint_attribute_group = {
|
||||
.attrs = workload_hint_attrs,
|
||||
.name = "workload_hint"
|
||||
.name = "workload_hint",
|
||||
.is_visible = workload_hint_attr_visible
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
/* List of workload types */
|
||||
|
|
@ -28,9 +29,9 @@ static ssize_t workload_available_types_show(struct device *dev,
|
|||
int ret = 0;
|
||||
|
||||
while (workload_types[i] != NULL)
|
||||
ret += sprintf(&buf[ret], "%s ", workload_types[i++]);
|
||||
ret += sysfs_emit_at(buf, ret, "%s ", workload_types[i++]);
|
||||
|
||||
ret += sprintf(&buf[ret], "\n");
|
||||
ret += sysfs_emit_at(buf, ret, "\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -85,7 +86,7 @@ static ssize_t workload_type_show(struct device *dev,
|
|||
if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%s\n", workload_types[cmd_resp]);
|
||||
return sysfs_emit(buf, "%s\n", workload_types[cmd_resp]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(workload_type);
|
||||
|
|
|
|||
|
|
@ -269,7 +269,6 @@ static void intel_pch_thermal_remove(struct pci_dev *pdev)
|
|||
|
||||
thermal_zone_device_unregister(ptd->tzd);
|
||||
iounmap(ptd->hw_base);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ static u32 get_temp_mask(bool pkg)
|
|||
|
||||
/**
|
||||
* intel_tcc_get_tjmax() - returns the default TCC activation Temperature
|
||||
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
|
||||
* @cpu: cpu that the MSR should be run on, negative value means any cpu.
|
||||
*
|
||||
* Get the TjMax value, which is the default thermal throttling or TCC
|
||||
* activation temperature in degrees C.
|
||||
|
|
@ -199,7 +199,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, "INTEL_TCC");
|
|||
|
||||
/**
|
||||
* intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
|
||||
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
|
||||
* @cpu: cpu that the MSR should be run on, negative value means any cpu.
|
||||
*
|
||||
* Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
|
||||
* activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
|
||||
|
|
@ -224,7 +224,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, "INTEL_TCC");
|
|||
|
||||
/**
|
||||
* intel_tcc_set_offset() - set the TCC offset value to Tjmax
|
||||
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
|
||||
* @cpu: cpu that the MSR should be run on, negative value means any cpu.
|
||||
* @offset: TCC offset value in degree C
|
||||
*
|
||||
* Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
|
||||
|
|
@ -267,7 +267,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, "INTEL_TCC");
|
|||
|
||||
/**
|
||||
* intel_tcc_get_temp() - returns the current temperature
|
||||
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
|
||||
* @cpu: cpu that the MSR should be run on, negative value means any cpu.
|
||||
* @temp: pointer to the memory for saving cpu temperature.
|
||||
* @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
|
|||
X86_MATCH_VFM(INTEL_RAPTORLAKE, NULL),
|
||||
X86_MATCH_VFM(INTEL_RAPTORLAKE_P, NULL),
|
||||
X86_MATCH_VFM(INTEL_RAPTORLAKE_S, NULL),
|
||||
X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL),
|
||||
X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE, NULL),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE_L, NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -72,10 +76,8 @@ MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
|
|||
|
||||
static int __init tcc_cooling_init(void)
|
||||
{
|
||||
int ret;
|
||||
u64 val;
|
||||
const struct x86_cpu_id *id;
|
||||
|
||||
int err;
|
||||
|
||||
id = x86_match_cpu(tcc_ids);
|
||||
|
|
@ -103,10 +105,9 @@ static int __init tcc_cooling_init(void)
|
|||
tcc_cdev =
|
||||
thermal_cooling_device_register("TCC Offset", NULL,
|
||||
&tcc_cooling_ops);
|
||||
if (IS_ERR(tcc_cdev)) {
|
||||
ret = PTR_ERR(tcc_cdev);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(tcc_cdev))
|
||||
return PTR_ERR(tcc_cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
|
@ -144,8 +145,8 @@ static ssize_t therm_throt_device_show_##event##_##name( \
|
|||
\
|
||||
preempt_disable(); /* CPU hotplug */ \
|
||||
if (cpu_online(cpu)) { \
|
||||
ret = sprintf(buf, "%lu\n", \
|
||||
per_cpu(thermal_state, cpu).event.name); \
|
||||
ret = sysfs_emit(buf, "%lu\n", \
|
||||
per_cpu(thermal_state, cpu).event.name); \
|
||||
} else \
|
||||
ret = 0; \
|
||||
preempt_enable(); \
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd,
|
|||
u32 l, h, mask, shift, intr;
|
||||
int tj_max, val, ret;
|
||||
|
||||
if (temp == THERMAL_TEMP_INVALID)
|
||||
temp = 0;
|
||||
|
||||
tj_max = intel_tcc_get_tjmax(zonedev->cpu);
|
||||
if (tj_max < 0)
|
||||
return tj_max;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@
|
|||
#define LVTS_EDATA01(__base) (__base + 0x0058)
|
||||
#define LVTS_EDATA02(__base) (__base + 0x005C)
|
||||
#define LVTS_EDATA03(__base) (__base + 0x0060)
|
||||
#define LVTS_MSROFT(__base) (__base + 0x006C)
|
||||
#define LVTS_ATP0(__base) (__base + 0x0070)
|
||||
#define LVTS_ATP1(__base) (__base + 0x0074)
|
||||
#define LVTS_ATP2(__base) (__base + 0x0078)
|
||||
#define LVTS_ATP3(__base) (__base + 0x007C)
|
||||
#define LVTS_MSR0(__base) (__base + 0x0090)
|
||||
#define LVTS_MSR1(__base) (__base + 0x0094)
|
||||
#define LVTS_MSR2(__base) (__base + 0x0098)
|
||||
|
|
@ -85,30 +90,43 @@
|
|||
#define LVTS_GOLDEN_TEMP_DEFAULT 50
|
||||
#define LVTS_COEFF_A_MT8195 -250460
|
||||
#define LVTS_COEFF_B_MT8195 250460
|
||||
#define LVTS_COEFF_A_MT7987 -204650
|
||||
#define LVTS_COEFF_B_MT7987 204650
|
||||
#define LVTS_COEFF_A_MT7988 -204650
|
||||
#define LVTS_COEFF_B_MT7988 204650
|
||||
#define LVTS_COEFF_A_MT8196 391460
|
||||
#define LVTS_COEFF_B_MT8196 -391460
|
||||
|
||||
#define LVTS_MSR_IMMEDIATE_MODE 0
|
||||
#define LVTS_MSR_FILTERED_MODE 1
|
||||
#define LVTS_MSR_OFFSET_MT8196 -984
|
||||
|
||||
#define LVTS_MSR_READ_TIMEOUT_US 400
|
||||
#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
|
||||
|
||||
#define LVTS_MINIMUM_THRESHOLD 20000
|
||||
|
||||
#define LVTS_MAX_CAL_OFFSETS 3
|
||||
#define LVTS_NUM_CAL_OFFSETS_MT7988 3
|
||||
#define LVTS_NUM_CAL_OFFSETS_MT8196 2
|
||||
|
||||
static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
|
||||
static int golden_temp_offset;
|
||||
|
||||
enum lvts_msr_mode {
|
||||
LVTS_MSR_IMMEDIATE_MODE,
|
||||
LVTS_MSR_FILTERED_MODE,
|
||||
LVTS_MSR_ATP_MODE,
|
||||
};
|
||||
|
||||
struct lvts_sensor_data {
|
||||
int dt_id;
|
||||
u8 cal_offsets[3];
|
||||
u8 cal_offsets[LVTS_MAX_CAL_OFFSETS];
|
||||
};
|
||||
|
||||
struct lvts_ctrl_data {
|
||||
struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
|
||||
u8 valid_sensor_mask;
|
||||
int offset;
|
||||
int mode;
|
||||
enum lvts_msr_mode mode;
|
||||
};
|
||||
|
||||
#define VALID_SENSOR_MAP(s0, s1, s2, s3) \
|
||||
|
|
@ -123,10 +141,17 @@ struct lvts_ctrl_data {
|
|||
continue; \
|
||||
else
|
||||
|
||||
struct lvts_platform_ops {
|
||||
int (*lvts_raw_to_temp)(u32 raw_temp, int temp_factor);
|
||||
u32 (*lvts_temp_to_raw)(int temperature, int temp_factor);
|
||||
};
|
||||
|
||||
struct lvts_data {
|
||||
const struct lvts_ctrl_data *lvts_ctrl;
|
||||
const struct lvts_platform_ops *ops;
|
||||
const u32 *conn_cmd;
|
||||
const u32 *init_cmd;
|
||||
int num_cal_offsets;
|
||||
int num_lvts_ctrl;
|
||||
int num_conn_cmd;
|
||||
int num_init_cmd;
|
||||
|
|
@ -134,6 +159,7 @@ struct lvts_data {
|
|||
int temp_offset;
|
||||
int gt_calib_bit_offset;
|
||||
unsigned int def_calibration;
|
||||
u16 msr_offset;
|
||||
};
|
||||
|
||||
struct lvts_sensor {
|
||||
|
|
@ -202,6 +228,11 @@ static const struct debugfs_reg32 lvts_regs[] = {
|
|||
LVTS_DEBUG_FS_REGS(LVTS_EDATA01),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_EDATA02),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_EDATA03),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_MSROFT),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_ATP0),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_ATP1),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_ATP2),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_ATP3),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_MSR0),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_MSR1),
|
||||
LVTS_DEBUG_FS_REGS(LVTS_MSR2),
|
||||
|
|
@ -269,7 +300,17 @@ static inline int lvts_debugfs_init(struct device *dev,
|
|||
|
||||
#endif
|
||||
|
||||
static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
|
||||
static int lvts_raw_to_temp(u32 raw_temp, const struct lvts_data *lvts_data)
|
||||
{
|
||||
return lvts_data->ops->lvts_raw_to_temp(raw_temp & 0xFFFF, lvts_data->temp_factor);
|
||||
}
|
||||
|
||||
static u32 lvts_temp_to_raw(int temperature, const struct lvts_data *lvts_data)
|
||||
{
|
||||
return lvts_data->ops->lvts_temp_to_raw(temperature, lvts_data->temp_factor);
|
||||
}
|
||||
|
||||
static int lvts_raw_to_temp_mt7988(u32 raw_temp, int temp_factor)
|
||||
{
|
||||
int temperature;
|
||||
|
||||
|
|
@ -279,7 +320,7 @@ static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
|
|||
return temperature;
|
||||
}
|
||||
|
||||
static u32 lvts_temp_to_raw(int temperature, int temp_factor)
|
||||
static u32 lvts_temp_to_raw_mt7988(int temperature, int temp_factor)
|
||||
{
|
||||
u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14;
|
||||
|
||||
|
|
@ -288,6 +329,15 @@ static u32 lvts_temp_to_raw(int temperature, int temp_factor)
|
|||
return raw_temp;
|
||||
}
|
||||
|
||||
static u32 lvts_temp_to_raw_mt8196(int temperature, int temp_factor)
|
||||
{
|
||||
u32 raw_temp;
|
||||
|
||||
raw_temp = temperature - golden_temp_offset;
|
||||
|
||||
return div_s64((s64)temp_factor << 14, raw_temp);
|
||||
}
|
||||
|
||||
static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
|
||||
|
|
@ -326,7 +376,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
if (rc)
|
||||
return -EAGAIN;
|
||||
|
||||
*temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor);
|
||||
*temp = lvts_raw_to_temp(value, lvts_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -396,8 +446,8 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
|
|||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
void __iomem *base = lvts_sensor->base;
|
||||
u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD,
|
||||
lvts_data->temp_factor);
|
||||
u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor);
|
||||
lvts_data);
|
||||
u32 raw_high = lvts_temp_to_raw(high, lvts_data);
|
||||
bool should_update_thresh;
|
||||
|
||||
lvts_sensor->low_thresh = low;
|
||||
|
|
@ -599,6 +649,13 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
|||
LVTS_IMMD3(lvts_ctrl->base)
|
||||
};
|
||||
|
||||
void __iomem *atp_regs[] = {
|
||||
LVTS_ATP0(lvts_ctrl->base),
|
||||
LVTS_ATP1(lvts_ctrl->base),
|
||||
LVTS_ATP2(lvts_ctrl->base),
|
||||
LVTS_ATP3(lvts_ctrl->base)
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
|
||||
|
|
@ -634,8 +691,20 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
|||
/*
|
||||
* Each sensor has its own register address to read from.
|
||||
*/
|
||||
lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
|
||||
imm_regs[i] : msr_regs[i];
|
||||
switch (lvts_ctrl_data->mode) {
|
||||
case LVTS_MSR_IMMEDIATE_MODE:
|
||||
lvts_sensor[i].msr = imm_regs[i];
|
||||
break;
|
||||
case LVTS_MSR_FILTERED_MODE:
|
||||
lvts_sensor[i].msr = msr_regs[i];
|
||||
break;
|
||||
case LVTS_MSR_ATP_MODE:
|
||||
lvts_sensor[i].msr = atp_regs[i];
|
||||
break;
|
||||
default:
|
||||
lvts_sensor[i].msr = imm_regs[i];
|
||||
break;
|
||||
}
|
||||
|
||||
lvts_sensor[i].low_thresh = INT_MIN;
|
||||
lvts_sensor[i].high_thresh = INT_MIN;
|
||||
|
|
@ -646,6 +715,26 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lvts_decode_sensor_calibration(const struct lvts_sensor_data *sensor,
|
||||
const u8 *efuse_calibration, u32 calib_len,
|
||||
u8 num_offsets, u32 *calib)
|
||||
{
|
||||
int i;
|
||||
u32 calib_val = 0;
|
||||
|
||||
for (i = 0; i < num_offsets; i++) {
|
||||
u8 offset = sensor->cal_offsets[i];
|
||||
|
||||
if (offset >= calib_len)
|
||||
return -EINVAL;
|
||||
// Pack each calibration byte into the correct position
|
||||
calib_val |= efuse_calibration[offset] << (8 * i);
|
||||
}
|
||||
|
||||
*calib = calib_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The efuse blob values follows the sensor enumeration per thermal
|
||||
* controller. The decoding of the stream is as follow:
|
||||
|
|
@ -702,6 +791,39 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
|||
* <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
|
||||
* 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
|
||||
*
|
||||
* MT8196 :
|
||||
* Stream index map for MCU Domain mt8196 :
|
||||
*
|
||||
* <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
|
||||
* 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B
|
||||
*
|
||||
* <-sensor#5--> <-sensor#4--> <-sensor#7--> <-sensor#6-->
|
||||
* 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13
|
||||
*
|
||||
* <-sensor#9--> <-sensor#8--> <-sensor#11-> <-sensor#10->
|
||||
* 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0X1B
|
||||
*
|
||||
* <-sensor#13-> <-sensor#12-> <-sensor#15-> <-sensor#14->
|
||||
* 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23
|
||||
*
|
||||
* Stream index map for APU Domain mt8196 :
|
||||
*
|
||||
* <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
|
||||
* 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B
|
||||
*
|
||||
* Stream index map for GPU Domain mt8196 :
|
||||
*
|
||||
* <-sensor#1--> <-sensor#0-->
|
||||
* 0x2C | 0x2D | 0x2E | 0x2F
|
||||
*
|
||||
* Stream index map for AP Domain mt8196 :
|
||||
*
|
||||
* <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2-->
|
||||
* 0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37
|
||||
*
|
||||
* <-sensor#5--> <-sensor#4--> <-sensor#6--> <-sensor#7-->
|
||||
* 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F
|
||||
*
|
||||
* Note: In some cases, values don't strictly follow a little endian ordering.
|
||||
* The data description gives byte offsets constituting each calibration value
|
||||
* for each sensor.
|
||||
|
|
@ -711,26 +833,29 @@ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl
|
|||
u8 *efuse_calibration,
|
||||
size_t calib_len)
|
||||
{
|
||||
int i;
|
||||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
int i, ret;
|
||||
u32 gt;
|
||||
|
||||
/* A zero value for gt means that device has invalid efuse data */
|
||||
gt = (((u32 *)efuse_calibration)[0] >> lvts_ctrl->lvts_data->gt_calib_bit_offset) & 0xff;
|
||||
gt = (((u32 *)efuse_calibration)[0] >> lvts_data->gt_calib_bit_offset) & 0xff;
|
||||
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
|
||||
const struct lvts_sensor_data *sensor =
|
||||
&lvts_ctrl_data->lvts_sensor[i];
|
||||
u32 calib = 0;
|
||||
|
||||
if (sensor->cal_offsets[0] >= calib_len ||
|
||||
sensor->cal_offsets[1] >= calib_len ||
|
||||
sensor->cal_offsets[2] >= calib_len)
|
||||
return -EINVAL;
|
||||
ret = lvts_decode_sensor_calibration(sensor, efuse_calibration,
|
||||
calib_len,
|
||||
lvts_data->num_cal_offsets,
|
||||
&calib);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (gt) {
|
||||
lvts_ctrl->calibration[i] =
|
||||
(efuse_calibration[sensor->cal_offsets[0]] << 0) +
|
||||
(efuse_calibration[sensor->cal_offsets[1]] << 8) +
|
||||
(efuse_calibration[sensor->cal_offsets[2]] << 16);
|
||||
lvts_ctrl->calibration[i] = calib;
|
||||
if (lvts_ctrl->lvts_data->msr_offset)
|
||||
lvts_ctrl->calibration[i] += lvts_ctrl->lvts_data->msr_offset;
|
||||
} else if (lvts_ctrl->lvts_data->def_calibration) {
|
||||
lvts_ctrl->calibration[i] = lvts_ctrl->lvts_data->def_calibration;
|
||||
} else {
|
||||
|
|
@ -884,7 +1009,7 @@ static void lvts_ctrl_monitor_enable(struct device *dev, struct lvts_ctrl *lvts_
|
|||
u32 sensor_map = 0;
|
||||
int i;
|
||||
|
||||
if (lvts_ctrl->mode != LVTS_MSR_FILTERED_MODE)
|
||||
if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE)
|
||||
return;
|
||||
|
||||
if (enable) {
|
||||
|
|
@ -1038,6 +1163,17 @@ static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
|
|||
for (i = 0; i < LVTS_SENSOR_MAX; i++)
|
||||
writel(lvts_ctrl->calibration[i], lvts_edata[i]);
|
||||
|
||||
/* LVTS_MSROFT : Constant offset applied to MSR values
|
||||
* for post-processing
|
||||
*
|
||||
* Bits:
|
||||
*
|
||||
* 20-0 : Constant data added to MSR values
|
||||
*/
|
||||
if (lvts_ctrl->lvts_data->msr_offset)
|
||||
writel(lvts_ctrl->lvts_data->msr_offset,
|
||||
LVTS_MSROFT(lvts_ctrl->base));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1373,6 +1509,20 @@ static void lvts_remove(struct platform_device *pdev)
|
|||
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
|
||||
}
|
||||
|
||||
static const struct lvts_ctrl_data mt7987_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT7987_CPU,
|
||||
.cal_offsets = { 0x04, 0x05, 0x06 } },
|
||||
{ .dt_id = MT7987_ETH2P5G,
|
||||
.cal_offsets = { 0x08, 0x09, 0x0a } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
|
|
@ -1455,6 +1605,12 @@ static const u32 default_init_cmds[] = {
|
|||
0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
|
||||
};
|
||||
|
||||
static const u32 mt7987_init_cmds[] = {
|
||||
0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC10308C7,
|
||||
0xC103098D, 0xC1030C7C, 0xC1030AA8, 0xC10308CE, 0xC10308C7,
|
||||
0xC1030B04, 0xC1030E01, 0xC10306B8
|
||||
};
|
||||
|
||||
static const u32 mt7988_init_cmds[] = {
|
||||
0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC,
|
||||
0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01,
|
||||
|
|
@ -1753,6 +1909,125 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8196_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU6_0,
|
||||
.cal_offsets = { 0x06, 0x07 } },
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU6_1,
|
||||
.cal_offsets = { 0x04, 0x05 } },
|
||||
{ .dt_id = MT8196_MCU_DSU2,
|
||||
.cal_offsets = { 0x0A, 0x0B } },
|
||||
{ .dt_id = MT8196_MCU_DSU3,
|
||||
.cal_offsets = { 0x08, 0x09 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x0,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_MCU_LITTLE_CPU3,
|
||||
.cal_offsets = { 0x0E, 0x0F } },
|
||||
{ .dt_id = MT8196_MCU_LITTLE_CPU0,
|
||||
.cal_offsets = { 0x0C, 0x0D } },
|
||||
{ .dt_id = MT8196_MCU_LITTLE_CPU1,
|
||||
.cal_offsets = { 0x12, 0x13 } },
|
||||
{ .dt_id = MT8196_MCU_LITTLE_CPU2,
|
||||
.cal_offsets = { 0x10, 0x11 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x100,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU4_0,
|
||||
.cal_offsets = { 0x16, 0x17 } },
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU4_1,
|
||||
.cal_offsets = { 0x14, 0x15 } },
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU5_0,
|
||||
.cal_offsets = { 0x1A, 0x1B } },
|
||||
{ .dt_id = MT8196_MCU_MEDIUM_CPU5_1,
|
||||
.cal_offsets = { 0x18, 0x19 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x200,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_MCU_DSU0,
|
||||
.cal_offsets = { 0x1E, 0x1F } },
|
||||
{ .dt_id = MT8196_MCU_DSU1,
|
||||
.cal_offsets = { 0x1C, 0x1D } },
|
||||
{ .dt_id = MT8196_MCU_BIG_CPU7_0,
|
||||
.cal_offsets = { 0x22, 0x23 } },
|
||||
{ .dt_id = MT8196_MCU_BIG_CPU7_1,
|
||||
.cal_offsets = { 0x20, 0x21 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x300,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8196_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_AP_TOP0,
|
||||
.cal_offsets = { 0x32, 0x33 } },
|
||||
{ .dt_id = MT8196_AP_TOP1,
|
||||
.cal_offsets = { 0x30, 0x31 } },
|
||||
{ .dt_id = MT8196_AP_TOP2,
|
||||
.cal_offsets = { 0x36, 0x37 } },
|
||||
{ .dt_id = MT8196_AP_TOP3,
|
||||
.cal_offsets = { 0x34, 0x35 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x0,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8196_AP_BOT0,
|
||||
.cal_offsets = { 0x3A, 0x3B } },
|
||||
{ .dt_id = MT8196_AP_BOT1,
|
||||
.cal_offsets = { 0x38, 0x39 } },
|
||||
{ .dt_id = MT8196_AP_BOT2,
|
||||
.cal_offsets = { 0x3E, 0x3F } },
|
||||
{ .dt_id = MT8196_AP_BOT3,
|
||||
.cal_offsets = { 0x3C, 0x3D } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x100,
|
||||
.mode = LVTS_MSR_ATP_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_platform_ops lvts_platform_ops_mt7988 = {
|
||||
.lvts_raw_to_temp = lvts_raw_to_temp_mt7988,
|
||||
.lvts_temp_to_raw = lvts_temp_to_raw_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_platform_ops lvts_platform_ops_mt8196 = {
|
||||
.lvts_raw_to_temp = lvts_raw_to_temp_mt7988,
|
||||
.lvts_temp_to_raw = lvts_temp_to_raw_mt8196,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt7987_lvts_ap_data = {
|
||||
.lvts_ctrl = mt7987_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt7987_lvts_ap_data_ctrl),
|
||||
.conn_cmd = mt7988_conn_cmds,
|
||||
.init_cmd = mt7987_init_cmds,
|
||||
.num_conn_cmd = ARRAY_SIZE(mt7988_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(mt7987_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT7987,
|
||||
.temp_offset = LVTS_COEFF_B_MT7987,
|
||||
.gt_calib_bit_offset = 32,
|
||||
.def_calibration = 19380,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt7988_lvts_ap_data = {
|
||||
.lvts_ctrl = mt7988_lvts_ap_data_ctrl,
|
||||
.conn_cmd = mt7988_conn_cmds,
|
||||
|
|
@ -1763,6 +2038,8 @@ static const struct lvts_data mt7988_lvts_ap_data = {
|
|||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8186_lvts_data = {
|
||||
|
|
@ -1776,6 +2053,8 @@ static const struct lvts_data mt8186_lvts_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.def_calibration = 19000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8188_lvts_mcu_data = {
|
||||
|
|
@ -1789,6 +2068,8 @@ static const struct lvts_data mt8188_lvts_mcu_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8188_lvts_ap_data = {
|
||||
|
|
@ -1802,6 +2083,8 @@ static const struct lvts_data mt8188_lvts_ap_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_mcu_data = {
|
||||
|
|
@ -1815,6 +2098,8 @@ static const struct lvts_data mt8192_lvts_mcu_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_ap_data = {
|
||||
|
|
@ -1828,6 +2113,8 @@ static const struct lvts_data mt8192_lvts_ap_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_mcu_data = {
|
||||
|
|
@ -1841,6 +2128,8 @@ static const struct lvts_data mt8195_lvts_mcu_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_ap_data = {
|
||||
|
|
@ -1854,9 +2143,36 @@ static const struct lvts_data mt8195_lvts_ap_data = {
|
|||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
.def_calibration = 35000,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988,
|
||||
.ops = &lvts_platform_ops_mt7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8196_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8196_lvts_mcu_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_mcu_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8196,
|
||||
.temp_offset = LVTS_COEFF_B_MT8196,
|
||||
.gt_calib_bit_offset = 0,
|
||||
.def_calibration = 14437,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196,
|
||||
.msr_offset = LVTS_MSR_OFFSET_MT8196,
|
||||
.ops = &lvts_platform_ops_mt8196,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8196_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8196_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8196,
|
||||
.temp_offset = LVTS_COEFF_B_MT8196,
|
||||
.gt_calib_bit_offset = 0,
|
||||
.def_calibration = 14437,
|
||||
.num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196,
|
||||
.msr_offset = LVTS_MSR_OFFSET_MT8196,
|
||||
.ops = &lvts_platform_ops_mt8196,
|
||||
};
|
||||
|
||||
static const struct of_device_id lvts_of_match[] = {
|
||||
{ .compatible = "mediatek,mt7987-lvts-ap", .data = &mt7987_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
|
||||
{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
|
||||
|
|
@ -1865,6 +2181,8 @@ static const struct of_device_id lvts_of_match[] = {
|
|||
{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8196-lvts-mcu", .data = &mt8196_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8196-lvts-ap", .data = &mt8196_lvts_ap_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lvts_of_match);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*
|
||||
* Copyright (C) 2025 Renesas Electronics Corporation
|
||||
*/
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -62,8 +63,6 @@
|
|||
#define TSU_SICR_CMPCLR BIT(1)
|
||||
|
||||
/* Temperature calculation constants from datasheet */
|
||||
#define TSU_TEMP_D (-41)
|
||||
#define TSU_TEMP_E 126
|
||||
#define TSU_CODE_MAX 0xFFF
|
||||
|
||||
/* Timing specifications from datasheet */
|
||||
|
|
@ -72,6 +71,18 @@
|
|||
#define TSU_POLL_DELAY_US 10 /* Polling interval */
|
||||
#define TSU_MIN_CLOCK_RATE 24000000 /* TSU_PCLK minimum 24MHz */
|
||||
|
||||
#define RZ_SIP_SVC_GET_SYSTSU 0x82000022
|
||||
#define OTP_TSU_REG_ADR_TEMPHI 0x01DC
|
||||
#define OTP_TSU_REG_ADR_TEMPLO 0x01DD
|
||||
|
||||
struct rzg3e_thermal_priv;
|
||||
|
||||
struct rzg3e_thermal_info {
|
||||
int (*get_trim)(struct rzg3e_thermal_priv *priv);
|
||||
int temp_d_mc;
|
||||
int temp_e_mc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg3e_thermal_priv - RZ/G3E TSU private data
|
||||
* @base: TSU register base
|
||||
|
|
@ -79,6 +90,7 @@
|
|||
* @syscon: regmap for calibration values
|
||||
* @zone: thermal zone device
|
||||
* @rstc: reset control
|
||||
* @info: chip type specific information
|
||||
* @trmval0: calibration value 0 (b)
|
||||
* @trmval1: calibration value 1 (c)
|
||||
* @trim_offset: offset for trim registers in syscon
|
||||
|
|
@ -87,12 +99,11 @@
|
|||
struct rzg3e_thermal_priv {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct regmap *syscon;
|
||||
struct thermal_zone_device *zone;
|
||||
struct reset_control *rstc;
|
||||
const struct rzg3e_thermal_info *info;
|
||||
u16 trmval0;
|
||||
u16 trmval1;
|
||||
u32 trim_offset;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
|
@ -161,17 +172,17 @@ static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv)
|
|||
*/
|
||||
static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code)
|
||||
{
|
||||
int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE;
|
||||
int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE;
|
||||
const struct rzg3e_thermal_info *info = priv->info;
|
||||
s64 numerator, denominator;
|
||||
int temp_mc;
|
||||
|
||||
numerator = (temp_e_mc - temp_d_mc) * (s64)(code - priv->trmval0);
|
||||
numerator = (info->temp_e_mc - info->temp_d_mc) *
|
||||
(s64)(code - priv->trmval0);
|
||||
denominator = priv->trmval1 - priv->trmval0;
|
||||
|
||||
temp_mc = div64_s64(numerator, denominator) + temp_d_mc;
|
||||
temp_mc = div64_s64(numerator, denominator) + info->temp_d_mc;
|
||||
|
||||
return clamp(temp_mc, temp_d_mc, temp_e_mc);
|
||||
return clamp(temp_mc, info->temp_d_mc, info->temp_e_mc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -180,13 +191,12 @@ static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code)
|
|||
*/
|
||||
static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_mc)
|
||||
{
|
||||
int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE;
|
||||
int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE;
|
||||
const struct rzg3e_thermal_info *info = priv->info;
|
||||
s64 numerator, denominator;
|
||||
s64 code;
|
||||
|
||||
numerator = (temp_mc - temp_d_mc) * (priv->trmval1 - priv->trmval0);
|
||||
denominator = temp_e_mc - temp_d_mc;
|
||||
numerator = (temp_mc - info->temp_d_mc) * (priv->trmval1 - priv->trmval0);
|
||||
denominator = info->temp_e_mc - info->temp_d_mc;
|
||||
|
||||
code = div64_s64(numerator, denominator) + priv->trmval0;
|
||||
|
||||
|
|
@ -330,48 +340,45 @@ static const struct thermal_zone_device_ops rzg3e_tz_ops = {
|
|||
.set_trips = rzg3e_thermal_set_trips,
|
||||
};
|
||||
|
||||
static int rzg3e_thermal_get_calibration(struct rzg3e_thermal_priv *priv)
|
||||
static int rzg3e_thermal_get_syscon_trim(struct rzg3e_thermal_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
struct device_node *np = priv->dev->of_node;
|
||||
struct regmap *syscon;
|
||||
u32 offset;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset);
|
||||
if (IS_ERR(syscon))
|
||||
return dev_err_probe(priv->dev, PTR_ERR(syscon),
|
||||
"Failed to parse renesas,tsu-trim\n");
|
||||
|
||||
/* Read calibration values from syscon */
|
||||
ret = regmap_read(priv->syscon, priv->trim_offset, &val);
|
||||
ret = regmap_read(syscon, offset, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
priv->trmval0 = val & GENMASK(11, 0);
|
||||
priv->trmval0 = val & TSU_CODE_MAX;
|
||||
|
||||
ret = regmap_read(priv->syscon, priv->trim_offset + 4, &val);
|
||||
ret = regmap_read(syscon, offset + 4, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
priv->trmval1 = val & GENMASK(11, 0);
|
||||
|
||||
/* Validate calibration data */
|
||||
if (!priv->trmval0 || !priv->trmval1 ||
|
||||
priv->trmval0 == priv->trmval1 ||
|
||||
priv->trmval0 == 0xFFF || priv->trmval1 == 0xFFF) {
|
||||
dev_err(priv->dev, "Invalid calibration: b=0x%03x, c=0x%03x\n",
|
||||
priv->trmval0, priv->trmval1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n",
|
||||
priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1);
|
||||
priv->trmval1 = val & TSU_CODE_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg3e_thermal_parse_dt(struct rzg3e_thermal_priv *priv)
|
||||
static int rzg3e_thermal_get_smc_trim(struct rzg3e_thermal_priv *priv)
|
||||
{
|
||||
struct device_node *np = priv->dev->of_node;
|
||||
u32 offset;
|
||||
struct arm_smccc_res local_res;
|
||||
|
||||
priv->syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset);
|
||||
if (IS_ERR(priv->syscon))
|
||||
return dev_err_probe(priv->dev, PTR_ERR(priv->syscon),
|
||||
"Failed to parse renesas,tsu-trim\n");
|
||||
arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPLO,
|
||||
0, 0, 0, 0, 0, 0, &local_res);
|
||||
priv->trmval0 = local_res.a0 & TSU_CODE_MAX;
|
||||
|
||||
arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPHI,
|
||||
0, 0, 0, 0, 0, 0, &local_res);
|
||||
priv->trmval1 = local_res.a0 & TSU_CODE_MAX;
|
||||
|
||||
priv->trim_offset = offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -392,15 +399,26 @@ static int rzg3e_thermal_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->info = device_get_match_data(dev);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
/* Parse device tree for trim register info */
|
||||
ret = rzg3e_thermal_parse_dt(priv);
|
||||
ret = priv->info->get_trim(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!priv->trmval0 || !priv->trmval1 ||
|
||||
priv->trmval0 == priv->trmval1 ||
|
||||
priv->trmval0 == TSU_CODE_MAX || priv->trmval1 == TSU_CODE_MAX)
|
||||
return dev_err_probe(priv->dev, -EINVAL,
|
||||
"Invalid calibration: b=0x%03x, c=0x%03x\n",
|
||||
priv->trmval0, priv->trmval1);
|
||||
|
||||
dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n",
|
||||
priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1);
|
||||
|
||||
/* Get clock to verify frequency - clock is managed by power domain */
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
|
|
@ -412,17 +430,11 @@ static int rzg3e_thermal_probe(struct platform_device *pdev)
|
|||
"Clock rate %lu Hz too low (min %u Hz)\n",
|
||||
clk_get_rate(clk), TSU_MIN_CLOCK_RATE);
|
||||
|
||||
priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
|
||||
priv->rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
|
||||
if (IS_ERR(priv->rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->rstc),
|
||||
"Failed to get/deassert reset control\n");
|
||||
|
||||
/* Get calibration data */
|
||||
ret = rzg3e_thermal_get_calibration(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get valid calibration data\n");
|
||||
|
||||
/* Get comparison interrupt */
|
||||
irq = platform_get_irq_byname(pdev, "adcmpi");
|
||||
if (irq < 0)
|
||||
|
|
@ -526,8 +538,21 @@ static const struct dev_pm_ops rzg3e_thermal_pm_ops = {
|
|||
SYSTEM_SLEEP_PM_OPS(rzg3e_thermal_suspend, rzg3e_thermal_resume)
|
||||
};
|
||||
|
||||
static const struct rzg3e_thermal_info rzg3e_thermal_info = {
|
||||
.get_trim = rzg3e_thermal_get_syscon_trim,
|
||||
.temp_d_mc = -41000,
|
||||
.temp_e_mc = 126000,
|
||||
};
|
||||
|
||||
static const struct rzg3e_thermal_info rzt2h_thermal_info = {
|
||||
.get_trim = rzg3e_thermal_get_smc_trim,
|
||||
.temp_d_mc = -40000,
|
||||
.temp_e_mc = 125000,
|
||||
};
|
||||
|
||||
static const struct of_device_id rzg3e_thermal_dt_ids[] = {
|
||||
{ .compatible = "renesas,r9a09g047-tsu" },
|
||||
{ .compatible = "renesas,r9a09g047-tsu", .data = &rzg3e_thermal_info },
|
||||
{ .compatible = "renesas,r9a09g077-tsu", .data = &rzt2h_thermal_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzg3e_thermal_dt_ids);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "../thermal_hwmon.h"
|
||||
|
||||
|
|
@ -76,7 +77,6 @@
|
|||
|
||||
/* Constants */
|
||||
#define ADJUST 100
|
||||
#define ONE_MHZ 1000000
|
||||
#define POLL_TIMEOUT 5000
|
||||
#define STARTUP_TIME 40
|
||||
#define TS1_T0_VAL0 30000 /* 30 celsius */
|
||||
|
|
@ -205,7 +205,7 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
|
|||
return -EINVAL;
|
||||
|
||||
prescaler = 0;
|
||||
clk_freq /= ONE_MHZ;
|
||||
clk_freq /= HZ_PER_MHZ;
|
||||
if (clk_freq) {
|
||||
while (prescaler <= clk_freq)
|
||||
prescaler++;
|
||||
|
|
|
|||
|
|
@ -1505,15 +1505,19 @@ thermal_zone_device_register_with_trips(const char *type,
|
|||
const struct thermal_trip *trip = trips;
|
||||
struct thermal_zone_device *tz;
|
||||
struct thermal_trip_desc *td;
|
||||
size_t type_len = 0;
|
||||
int id;
|
||||
int result;
|
||||
|
||||
if (!type || strlen(type) == 0) {
|
||||
if (type)
|
||||
type_len = strnlen(type, THERMAL_NAME_LENGTH);
|
||||
|
||||
if (type_len == 0) {
|
||||
pr_err("No thermal zone type defined\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (strlen(type) >= THERMAL_NAME_LENGTH) {
|
||||
if (type_len == THERMAL_NAME_LENGTH) {
|
||||
pr_err("Thermal zone name (%s) too long, should be under %d chars\n",
|
||||
type, THERMAL_NAME_LENGTH);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ struct thermal_governor {
|
|||
* @device: &struct device for this thermal zone
|
||||
* @removal: removal completion
|
||||
* @resume: resume completion
|
||||
* @trips_attribute_group: trip point sysfs attributes
|
||||
* @trips_high: trips above the current zone temperature
|
||||
* @trips_reached: trips below or at the current zone temperature
|
||||
* @trips_invalid: trips with invalid temperature
|
||||
|
|
@ -97,9 +98,9 @@ struct thermal_governor {
|
|||
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
|
||||
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
|
||||
* @prev_low_trip: the low current temperature if you've crossed a passive
|
||||
trip point.
|
||||
* trip point.
|
||||
* @prev_high_trip: the above current temperature if you've crossed a
|
||||
passive trip point.
|
||||
* passive trip point.
|
||||
* @ops: operations this &thermal_zone_device supports
|
||||
* @tzp: thermal zone parameters
|
||||
* @governor: pointer to the governor for this thermal zone
|
||||
|
|
@ -111,6 +112,8 @@ struct thermal_governor {
|
|||
* @poll_queue: delayed work for polling
|
||||
* @notify_event: Last notification event
|
||||
* @state: current state of the thermal zone
|
||||
* @debugfs: this thermal zone device's thermal zone debug info
|
||||
* @user_thresholds: list of userspace thresholds for temp. limit notifications
|
||||
* @trips: array of struct thermal_trip objects
|
||||
*/
|
||||
struct thermal_zone_device {
|
||||
|
|
|
|||
|
|
@ -807,7 +807,7 @@ static int tze_seq_show(struct seq_file *s, void *v)
|
|||
seq_printf(s, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n",
|
||||
ktime_to_ms(tze->timestamp), c, duration_ms, tze->max_temp);
|
||||
|
||||
seq_printf(s, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n");
|
||||
seq_puts(s, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n");
|
||||
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", temperature);
|
||||
return sysfs_emit(buf, "%d\n", temperature);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -84,7 +84,7 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", temperature);
|
||||
return sysfs_emit(buf, "%d\n", temperature);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -280,10 +280,10 @@ static bool thermal_of_cm_lookup(struct device_node *cm_np,
|
|||
struct cooling_spec *c)
|
||||
{
|
||||
for_each_child_of_node_scoped(cm_np, child) {
|
||||
struct device_node *tr_np;
|
||||
int count, i;
|
||||
|
||||
tr_np = of_parse_phandle(child, "trip", 0);
|
||||
struct device_node *tr_np __free(device_node) =
|
||||
of_parse_phandle(child, "trip", 0);
|
||||
if (tr_np != trip->priv)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
{
|
||||
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", tz->type);
|
||||
return sysfs_emit(buf, "%s\n", tz->type);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -41,7 +41,7 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
ret = thermal_zone_get_temp(tz, &temperature);
|
||||
|
||||
if (!ret)
|
||||
return sprintf(buf, "%d\n", temperature);
|
||||
return sysfs_emit(buf, "%d\n", temperature);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
return -ENODATA;
|
||||
|
|
@ -57,9 +57,9 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
guard(thermal_zone)(tz);
|
||||
|
||||
if (tz->mode == THERMAL_DEVICE_ENABLED)
|
||||
return sprintf(buf, "enabled\n");
|
||||
return sysfs_emit(buf, "enabled\n");
|
||||
|
||||
return sprintf(buf, "disabled\n");
|
||||
return sysfs_emit(buf, "disabled\n");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -97,7 +97,7 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct thermal_trip *trip = thermal_trip_of_attr(attr, type);
|
||||
|
||||
return sprintf(buf, "%s\n", thermal_trip_type_name(trip->type));
|
||||
return sysfs_emit(buf, "%s\n", thermal_trip_type_name(trip->type));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -142,7 +142,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);
|
||||
|
||||
return sprintf(buf, "%d\n", READ_ONCE(trip->temperature));
|
||||
return sysfs_emit(buf, "%d\n", READ_ONCE(trip->temperature));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -188,7 +188,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);
|
||||
|
||||
return sprintf(buf, "%d\n", READ_ONCE(trip->hysteresis));
|
||||
return sysfs_emit(buf, "%d\n", READ_ONCE(trip->hysteresis));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -199,7 +199,7 @@ policy_store(struct device *dev, struct device_attribute *attr,
|
|||
char name[THERMAL_NAME_LENGTH];
|
||||
int ret;
|
||||
|
||||
snprintf(name, sizeof(name), "%s", buf);
|
||||
strscpy(name, buf);
|
||||
|
||||
ret = thermal_zone_device_set_policy(tz, name);
|
||||
if (!ret)
|
||||
|
|
@ -213,7 +213,7 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
|
|||
{
|
||||
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", tz->governor->name);
|
||||
return sysfs_emit(buf, "%s\n", tz->governor->name);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -260,7 +260,7 @@ sustainable_power_show(struct device *dev, struct device_attribute *devattr,
|
|||
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
||||
|
||||
if (tz->tzp)
|
||||
return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
|
||||
return sysfs_emit(buf, "%u\n", tz->tzp->sustainable_power);
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr,
|
|||
struct thermal_zone_device *tz = to_thermal_zone(dev); \
|
||||
\
|
||||
if (tz->tzp) \
|
||||
return sprintf(buf, "%d\n", tz->tzp->name); \
|
||||
return sysfs_emit(buf, "%d\n", tz->tzp->name); \
|
||||
else \
|
||||
return -EIO; \
|
||||
} \
|
||||
|
|
@ -505,7 +505,7 @@ cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
{
|
||||
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", cdev->type);
|
||||
return sysfs_emit(buf, "%s\n", cdev->type);
|
||||
}
|
||||
|
||||
static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
|
||||
|
|
@ -513,7 +513,7 @@ static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
||||
|
||||
return sprintf(buf, "%ld\n", cdev->max_state);
|
||||
return sysfs_emit(buf, "%ld\n", cdev->max_state);
|
||||
}
|
||||
|
||||
static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
|
||||
|
|
@ -526,7 +526,7 @@ static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
|
|||
ret = cdev->ops->get_cur_state(cdev, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
return sprintf(buf, "%ld\n", state);
|
||||
return sysfs_emit(buf, "%ld\n", state);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -638,7 +638,7 @@ static ssize_t total_trans_show(struct device *dev,
|
|||
return 0;
|
||||
|
||||
spin_lock(&stats->lock);
|
||||
ret = sprintf(buf, "%u\n", stats->total_trans);
|
||||
ret = sysfs_emit(buf, "%u\n", stats->total_trans);
|
||||
spin_unlock(&stats->lock);
|
||||
|
||||
return ret;
|
||||
|
|
@ -664,8 +664,8 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
|
|||
update_time_in_state(stats);
|
||||
|
||||
for (i = 0; i <= cdev->max_state; i++) {
|
||||
len += sprintf(buf + len, "state%u\t%llu\n", i,
|
||||
ktime_to_ms(stats->time_in_state[i]));
|
||||
len += sysfs_emit_at(buf, len, "state%u\t%llu\n", i,
|
||||
ktime_to_ms(stats->time_in_state[i]));
|
||||
}
|
||||
spin_unlock(&stats->lock);
|
||||
|
||||
|
|
@ -846,7 +846,7 @@ trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
instance = container_of(attr, struct thermal_instance, attr);
|
||||
|
||||
return sprintf(buf, "%d\n", thermal_zone_trip_id(tz, instance->trip));
|
||||
return sysfs_emit(buf, "%d\n", thermal_zone_trip_id(tz, instance->trip));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
|
|
@ -856,7 +856,7 @@ weight_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
instance = container_of(attr, struct thermal_instance, weight_attr);
|
||||
|
||||
return sprintf(buf, "%d\n", instance->weight);
|
||||
return sysfs_emit(buf, "%d\n", instance->weight);
|
||||
}
|
||||
|
||||
ssize_t weight_store(struct device *dev, struct device_attribute *attr,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#ifndef __MEDIATEK_LVTS_DT_H
|
||||
#define __MEDIATEK_LVTS_DT_H
|
||||
|
||||
#define MT7987_CPU 0
|
||||
#define MT7987_ETH2P5G 1
|
||||
|
||||
#define MT7988_CPU_0 0
|
||||
#define MT7988_CPU_1 1
|
||||
#define MT7988_ETH2P5G_0 2
|
||||
|
|
@ -80,4 +83,30 @@
|
|||
#define MT8192_AP_MD1 15
|
||||
#define MT8192_AP_MD2 16
|
||||
|
||||
#define MT8196_MCU_MEDIUM_CPU6_0 0
|
||||
#define MT8196_MCU_MEDIUM_CPU6_1 1
|
||||
#define MT8196_MCU_DSU2 2
|
||||
#define MT8196_MCU_DSU3 3
|
||||
#define MT8196_MCU_LITTLE_CPU3 4
|
||||
#define MT8196_MCU_LITTLE_CPU0 5
|
||||
#define MT8196_MCU_LITTLE_CPU1 6
|
||||
#define MT8196_MCU_LITTLE_CPU2 7
|
||||
#define MT8196_MCU_MEDIUM_CPU4_0 8
|
||||
#define MT8196_MCU_MEDIUM_CPU4_1 9
|
||||
#define MT8196_MCU_MEDIUM_CPU5_0 10
|
||||
#define MT8196_MCU_MEDIUM_CPU5_1 11
|
||||
#define MT8196_MCU_DSU0 12
|
||||
#define MT8196_MCU_DSU1 13
|
||||
#define MT8196_MCU_BIG_CPU7_0 14
|
||||
#define MT8196_MCU_BIG_CPU7_1 15
|
||||
|
||||
#define MT8196_AP_TOP0 0
|
||||
#define MT8196_AP_TOP1 1
|
||||
#define MT8196_AP_TOP2 2
|
||||
#define MT8196_AP_TOP3 3
|
||||
#define MT8196_AP_BOT0 4
|
||||
#define MT8196_AP_BOT1 5
|
||||
#define MT8196_AP_BOT2 6
|
||||
#define MT8196_AP_BOT3 7
|
||||
|
||||
#endif /* __MEDIATEK_LVTS_DT_H */
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ Name: libthermal
|
|||
Description: thermal library
|
||||
Requires: libnl-3.0 libnl-genl-3.0
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lnl-genl-3 -lnl-3
|
||||
Cflags: -I${includedir} -I${include}/libnl3
|
||||
Libs: -L${libdir} -lnl-genl-3 -lnl-3 -lthermal
|
||||
Cflags: -I${includedir} -I${includedir}/libnl3
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms"
|
||||
#define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable"
|
||||
#define WORKLOAD_SLOW_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_slow_hint_enable"
|
||||
#define WORKLOAD_TYPE_INDEX_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index"
|
||||
|
||||
static const char * const workload_types[] = {
|
||||
|
|
@ -22,6 +23,9 @@ static const char * const workload_types[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static int wlt_slow;
|
||||
static char *wlt_enable_attr;
|
||||
|
||||
#define WORKLOAD_TYPE_MAX_INDEX 3
|
||||
|
||||
void workload_hint_exit(int signum)
|
||||
|
|
@ -30,7 +34,7 @@ void workload_hint_exit(int signum)
|
|||
|
||||
/* Disable feature via sysfs knob */
|
||||
|
||||
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
fd = open(wlt_enable_attr, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload type feature enable file");
|
||||
exit(1);
|
||||
|
|
@ -46,6 +50,26 @@ void workload_hint_exit(int signum)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
static void update_delay(char *delay_str)
|
||||
{
|
||||
int fd;
|
||||
|
||||
printf("Setting notification delay in ms to %s\n", delay_str);
|
||||
|
||||
fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload notification delay");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, delay_str, strlen(delay_str)) < 0) {
|
||||
perror("Can't set delay");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct pollfd ufd;
|
||||
|
|
@ -54,32 +78,26 @@ int main(int argc, char **argv)
|
|||
char delay_str[64];
|
||||
int delay = 0;
|
||||
|
||||
printf("Usage: workload_hint_test [notification delay in milli seconds]\n");
|
||||
printf("Usage: workload_hint_test [notification delay in milli seconds][slow]\n");
|
||||
|
||||
if (argc > 1) {
|
||||
ret = sscanf(argv[1], "%d", &delay);
|
||||
if (ret < 0) {
|
||||
printf("Invalid delay\n");
|
||||
exit(1);
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "slow")) {
|
||||
wlt_slow = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sscanf(argv[1], "%d", &delay);
|
||||
if (ret < 0) {
|
||||
printf("Invalid delay\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sprintf(delay_str, "%s\n", argv[1]);
|
||||
update_delay(delay_str);
|
||||
}
|
||||
|
||||
printf("Setting notification delay to %d ms\n", delay);
|
||||
if (delay < 0)
|
||||
exit(1);
|
||||
|
||||
sprintf(delay_str, "%s\n", argv[1]);
|
||||
fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload notification delay");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, delay_str, strlen(delay_str)) < 0) {
|
||||
perror("Can't set delay");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (signal(SIGINT, workload_hint_exit) == SIG_IGN)
|
||||
|
|
@ -89,8 +107,13 @@ int main(int argc, char **argv)
|
|||
if (signal(SIGTERM, workload_hint_exit) == SIG_IGN)
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
if (wlt_slow)
|
||||
wlt_enable_attr = WORKLOAD_SLOW_ENABLE_ATTRIBUTE;
|
||||
else
|
||||
wlt_enable_attr = WORKLOAD_ENABLE_ATTRIBUTE;
|
||||
|
||||
/* Enable feature via sysfs knob */
|
||||
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
fd = open(wlt_enable_attr, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload type feature enable file");
|
||||
exit(1);
|
||||
|
|
@ -145,6 +168,13 @@ int main(int argc, char **argv)
|
|||
if (ret < 0)
|
||||
break;
|
||||
|
||||
if (wlt_slow) {
|
||||
if (index & 0x10)
|
||||
printf("workload type slow:%s\n", "power");
|
||||
else
|
||||
printf("workload type slow:%s\n", "performance");
|
||||
}
|
||||
|
||||
index &= 0x0f;
|
||||
if (index > WORKLOAD_TYPE_MAX_INDEX)
|
||||
printf("Invalid workload type index\n");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue