Merge "dt-bindings: thermal: qmi_sensor: Add new modem qmi sensors"

This commit is contained in:
qctecmdr 2022-12-18 03:29:47 -08:00 committed by Gerrit - the friendly Code Review server
commit a5b00e08cf
7 changed files with 520 additions and 0 deletions

View file

@ -192,10 +192,12 @@ CONFIG_QTI_BCL_PMIC5=m
CONFIG_QTI_BCL_SOC_DRIVER=m
CONFIG_QTI_CHARGER_ULOG_GLINK=m
CONFIG_QTI_CPUCP_LOG=m
CONFIG_QTI_CPUFREQ_CDEV=m
CONFIG_QTI_CPU_HOTPLUG_COOLING_DEVICE=m
CONFIG_QTI_CPU_PAUSE_COOLING_DEVICE=m
CONFIG_QTI_CPU_VOLTAGE_COOLING_DEVICE=m
CONFIG_QTI_DDR_COOLING_DEVICE=m
CONFIG_QTI_DEVFREQ_CDEV=m
CONFIG_QTI_HW_KEY_MANAGER=m
CONFIG_QTI_IOMMU_SUPPORT=m
CONFIG_QTI_PMIC_EUSB2_REPEATER=m

View file

@ -103,6 +103,24 @@ config QTI_QMI_SENSOR_V2
the remote sensor. These sensors can take thresholds and notify the
thermal framework when the threshold is reached.
config QTI_CPUFREQ_CDEV
tristate "QTI CPU frequency cooling device"
depends on CPU_FREQ && THERMAL && PM_OPP
help
This enables the QTI cpufreq cooling device, which
will help register the cpu freq devices with thermal
framework and allow limiting the cpu frequency by
userspace.
config QTI_DEVFREQ_CDEV
tristate "QTI Devfreq cooling device"
depends on PM_DEVFREQ && THERMAL && PM_OPP
help
This enables the QTI devfreq cooling device, which
will help register the devfreq cooling devices with
thermal framework and allow limiting the devfreq
frequency.
config QTI_CPU_VOLTAGE_COOLING_DEVICE
tristate "QTI CPU VOLTAGE cooling devices"
depends on CPU_FREQ && THERMAL

View file

@ -17,6 +17,8 @@ qti_qmi_cdev-y += thermal_mitigation_device_service_v01.o qmi_cooling.o
obj-$(CONFIG_QTI_QMI_SENSOR_V2) += qti_qmi_sensor_v2.o
qti_qmi_sensor_v2-y += thermal_sensor_service_v02.o qmi_sensors_v2.o
obj-$(CONFIG_QTI_CPUFREQ_CDEV) += qti_cpufreq_cdev.o
obj-$(CONFIG_QTI_DEVFREQ_CDEV) += qti_devfreq_cdev.o
obj-$(CONFIG_QTI_CPU_VOLTAGE_COOLING_DEVICE) += cpu_voltage_cooling.o
obj-$(CONFIG_QTI_CPU_HOTPLUG_COOLING_DEVICE) += cpu_hotplug.o
obj-$(CONFIG_QTI_DDR_COOLING_DEVICE) += ddr_cdev.o

View file

@ -84,6 +84,12 @@ enum qmi_ts_sensor {
QMI_TS_EPM7,
QMI_TS_SDR0_PA,
QMI_TS_SDR1_PA,
QMI_TS_SUB0_SDR0_PA,
QMI_TS_SUB1_SDR0_PA,
QMI_SYS_THERM3,
QMI_SYS_THERM4,
QMI_SYS_THERM5,
QMI_SYS_THERM6,
QMI_TS_MAX_NR
};
@ -162,6 +168,12 @@ static char sensor_clients[QMI_TS_MAX_NR][QMI_CLIENT_NAME_LENGTH] = {
{"epm7"},
{"sdr0_pa"},
{"sdr1_pa"},
{"sub0_sdr0_pa"},
{"sub1_sdr0_pa"},
{"sys_therm3"},
{"sys_therm4"},
{"sys_therm5"},
{"sys_therm6"},
};
#endif /* __QMI_SENSORS_H__ */

View file

@ -0,0 +1,269 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/workqueue.h>
#define CPUFREQ_CDEV_NAME "cpu%d"
#define CPUFREQ_CDEV "qcom-cpufreq-cdev"
struct cpufreq_cdev_device {
struct list_head node;
struct thermal_cooling_device *cdev;
int cpu;
unsigned long cur_state;
unsigned long max_state;
unsigned int *freq_table;
struct freq_qos_request qos_max_freq_req;
char cdev_name[THERMAL_NAME_LENGTH];
struct cpufreq_policy *policy;
struct work_struct reg_work;
};
static DEFINE_MUTEX(qti_cpufreq_cdev_lock);
static LIST_HEAD(qti_cpufreq_cdev_list);
static enum cpuhp_state cpu_hp_online;
static unsigned int state_to_cpufreq(struct cpufreq_cdev_device *cdev_data,
unsigned long state)
{
return cdev_data->freq_table ?
cdev_data->freq_table[state] : UINT_MAX;
}
static int cpufreq_cdev_set_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct cpufreq_cdev_device *cdev_data = cdev->devdata;
int ret = 0;
unsigned int freq;
if (state > cdev_data->max_state)
return -EINVAL;
if (state == cdev_data->cur_state)
return 0;
if (freq_qos_request_active(&cdev_data->qos_max_freq_req)) {
freq = state_to_cpufreq(cdev_data, state);
pr_debug("cdev:%s Limit:%u\n", cdev->type, freq);
ret = freq_qos_update_request(&cdev_data->qos_max_freq_req,
freq);
if (ret < 0) {
pr_err("Error placing qos request:%u. cdev:%s err:%d\n",
freq, cdev->type, ret);
return ret;
}
}
cdev_data->cur_state = state;
return 0;
}
static int cpufreq_cdev_get_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct cpufreq_cdev_device *cdev_data = cdev->devdata;
*state = cdev_data->cur_state;
return 0;
}
static int cpufreq_cdev_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct cpufreq_cdev_device *cdev_data = cdev->devdata;
*state = cdev_data->max_state;
return 0;
}
static struct thermal_cooling_device_ops cpufreq_cdev_ops = {
.set_cur_state = cpufreq_cdev_set_state,
.get_cur_state = cpufreq_cdev_get_state,
.get_max_state = cpufreq_cdev_get_max_state,
};
static void cpufreq_cdev_register(struct work_struct *work)
{
struct cpufreq_cdev_device *cdev_data = container_of(work,
struct cpufreq_cdev_device, reg_work);
struct cpufreq_policy *policy = NULL;
int freq_count = 0, i;
policy = cpufreq_cpu_get(cdev_data->cpu);
if (!policy) {
pr_err("No policy for CPU:%d\n", cdev_data->cpu);
return;
}
freq_count = cpufreq_table_count_valid_entries(policy);
if (!freq_count) {
pr_debug("CPU%d freq policy table count error%d\n",
cdev_data->cpu, freq_count);
goto error_exit;
}
cdev_data->freq_table = kmalloc_array(freq_count,
sizeof(*cdev_data->freq_table),
GFP_KERNEL);
if (!cdev_data->freq_table)
goto error_exit;
for (i = 0; i < freq_count; i++) {
if (policy->freq_table_sorted ==
CPUFREQ_TABLE_SORTED_ASCENDING)
cdev_data->freq_table[i] =
policy->freq_table[freq_count - i - 1].frequency;
else
cdev_data->freq_table[i] =
policy->freq_table[i].frequency;
}
freq_count--;
cdev_data->policy = policy;
cdev_data->max_state = freq_count;
cdev_data->cur_state = 0;
freq_qos_add_request(&policy->constraints,
&cdev_data->qos_max_freq_req, FREQ_QOS_MAX,
state_to_cpufreq(cdev_data, 0));
cdev_data->cdev = thermal_cooling_device_register(cdev_data->cdev_name,
cdev_data, &cpufreq_cdev_ops);
if (IS_ERR(cdev_data->cdev)) {
pr_err("Cdev register failed for %s, ret:%d\n",
cdev_data->cdev_name, PTR_ERR(cdev_data->cdev));
freq_qos_remove_request(&cdev_data->qos_max_freq_req);
goto error_exit;
}
pr_debug("Cdev %s registered\n", cdev_data->cdev_name);
return;
error_exit:
if (policy)
cpufreq_cpu_put(policy);
if (cdev_data->cdev)
cdev_data->cdev = NULL;
kfree(cdev_data->freq_table);
}
static int cpufreq_cdev_hp_online(unsigned int online_cpu)
{
struct cpufreq_cdev_device *cdev_data;
mutex_lock(&qti_cpufreq_cdev_lock);
list_for_each_entry(cdev_data, &qti_cpufreq_cdev_list, node) {
if (cdev_data->cpu != online_cpu || cdev_data->cdev)
continue;
queue_work(system_highpri_wq, &cdev_data->reg_work);
}
mutex_unlock(&qti_cpufreq_cdev_lock);
return 0;
}
static int cpufreq_cdev_probe(struct platform_device *pdev)
{
struct cpufreq_cdev_device *cdev_data;
struct device_node *np = pdev->dev.of_node, *cpu_phandle = NULL;
struct device *dev = &pdev->dev;
struct device *cpu_dev;
int cpu = 0, ret = 0;
struct of_phandle_iterator it;
mutex_lock(&qti_cpufreq_cdev_lock);
of_phandle_iterator_init(&it, np, "qcom,cpus", NULL, 0);
while (of_phandle_iterator_next(&it) == 0) {
cdev_data = devm_kzalloc(dev, sizeof(*cdev_data), GFP_KERNEL);
if (!cdev_data) {
mutex_unlock(&qti_cpufreq_cdev_lock);
return -ENOMEM;
}
cpu_phandle = it.node;
cdev_data->cpu = -1;
for_each_possible_cpu(cpu) {
cpu_dev = get_cpu_device(cpu);
if (cpu_dev && cpu_dev->of_node == cpu_phandle) {
cdev_data->cpu = cpu;
break;
}
}
if (cdev_data->cpu == -1)
continue;
snprintf(cdev_data->cdev_name, THERMAL_NAME_LENGTH,
CPUFREQ_CDEV_NAME, cpu);
INIT_WORK(&cdev_data->reg_work,
cpufreq_cdev_register);
list_add(&cdev_data->node, &qti_cpufreq_cdev_list);
}
mutex_unlock(&qti_cpufreq_cdev_lock);
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal-cpu/cdev:online",
cpufreq_cdev_hp_online, NULL);
if (ret < 0)
return ret;
cpu_hp_online = ret;
return 0;
}
static int cpufreq_cdev_remove(struct platform_device *pdev)
{
struct cpufreq_cdev_device *cdev_data;
mutex_lock(&qti_cpufreq_cdev_lock);
if (cpu_hp_online) {
cpuhp_remove_state_nocalls(cpu_hp_online);
cpu_hp_online = 0;
}
list_for_each_entry(cdev_data, &qti_cpufreq_cdev_list, node) {
if (!cdev_data->cdev)
continue;
thermal_cooling_device_unregister(cdev_data->cdev);
if (freq_qos_request_active(&cdev_data->qos_max_freq_req))
freq_qos_remove_request(&cdev_data->qos_max_freq_req);
cdev_data->cdev = NULL;
cpufreq_cpu_put(cdev_data->policy);
kfree(cdev_data->freq_table);
}
mutex_unlock(&qti_cpufreq_cdev_lock);
return 0;
}
static const struct of_device_id cpufreq_cdev_match[] = {
{.compatible = "qcom,cpufreq-cdev"},
{}
};
static struct platform_driver cpufreq_cdev_driver = {
.probe = cpufreq_cdev_probe,
.remove = cpufreq_cdev_remove,
.driver = {
.name = CPUFREQ_CDEV,
.of_match_table = cpufreq_cdev_match,
},
};
static int __init cpufreq_cdev_init(void)
{
return platform_driver_register(&cpufreq_cdev_driver);
}
module_init(cpufreq_cdev_init);
static void __exit cpufreq_cdev_exit(void)
{
platform_driver_unregister(&cpufreq_cdev_driver);
}
module_exit(cpufreq_cdev_exit);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. cpufreq cooling driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,211 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
#include <linux/devfreq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/workqueue.h>
#define MAX_RETRY_CNT 20
#define RETRY_DELAY msecs_to_jiffies(1000)
#define DEVFREQ_CDEV_NAME "gpu"
#define DEVFREQ_CDEV "qcom-devfreq-cdev"
struct devfreq_cdev_device {
struct device_node *np;
struct devfreq *devfreq;
struct device *dev;
unsigned long *freq_table;
int cur_state;
int max_state;
int retry_cnt;
struct dev_pm_qos_request qos_max_freq_req;
struct delayed_work register_work;
struct thermal_cooling_device *cdev;
};
static struct devfreq_cdev_device *devfreq_cdev;
static int devfreq_cdev_set_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct devfreq_cdev_device *cdev_data = cdev->devdata;
int ret = 0;
unsigned long freq;
if (state > cdev_data->max_state)
return -EINVAL;
if (state == cdev_data->cur_state)
return 0;
freq = cdev_data->freq_table[state];
pr_debug("cdev:%s Limit:%lu\n", cdev->type, freq);
ret = dev_pm_qos_update_request(&cdev_data->qos_max_freq_req, freq);
if (ret < 0) {
pr_err("Error placing qos request:%u. cdev:%s err:%d\n",
freq, cdev->type, ret);
return ret;
}
cdev_data->cur_state = state;
return 0;
}
static int devfreq_cdev_get_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct devfreq_cdev_device *cdev_data = cdev->devdata;
*state = cdev_data->cur_state;
return 0;
}
static int devfreq_cdev_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct devfreq_cdev_device *cdev_data = cdev->devdata;
*state = cdev_data->max_state;
return 0;
}
static struct thermal_cooling_device_ops devfreq_cdev_ops = {
.set_cur_state = devfreq_cdev_set_state,
.get_cur_state = devfreq_cdev_get_state,
.get_max_state = devfreq_cdev_get_max_state,
};
static void devfreq_cdev_work(struct work_struct *work)
{
struct devfreq *df = NULL;
unsigned long freq = ULONG_MAX;
unsigned long *freq_table;
struct dev_pm_opp *opp;
int ret = 0, freq_ct, i;
struct devfreq_cdev_device *cdev_data = container_of(work,
struct devfreq_cdev_device,
register_work.work);
df = devfreq_get_devfreq_by_node(cdev_data->np);
if (IS_ERR(df)) {
ret = PTR_ERR(df);
pr_debug("Devfreq not available:%d\n", ret);
if (--cdev_data->retry_cnt)
queue_delayed_work(system_highpri_wq,
&cdev_data->register_work,
RETRY_DELAY);
return;
}
cdev_data->dev = df->dev.parent;
cdev_data->devfreq = df;
freq_ct = dev_pm_opp_get_opp_count(cdev_data->dev);
freq_table = kcalloc(freq_ct, sizeof(*freq_table), GFP_KERNEL);
if (!freq_table) {
ret = -ENOMEM;
return;
}
for (i = 0, freq = ULONG_MAX; i < freq_ct; i++, freq--) {
opp = dev_pm_opp_find_freq_floor(cdev_data->dev, &freq);
if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
goto qos_exit;
}
dev_pm_opp_put(opp);
freq_table[i] = DIV_ROUND_UP(freq, 1000); //hz to khz
pr_debug("%d. freq table:%d\n", i, freq_table[i]);
}
cdev_data->max_state = freq_ct-1;
cdev_data->freq_table = freq_table;
ret = dev_pm_qos_add_request(cdev_data->dev,
&cdev_data->qos_max_freq_req,
DEV_PM_QOS_MAX_FREQUENCY,
PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
if (ret < 0)
goto qos_exit;
cdev_data->cdev = thermal_cooling_device_register(DEVFREQ_CDEV_NAME,
cdev_data, &devfreq_cdev_ops);
if (IS_ERR(cdev_data->cdev)) {
pr_err("Cdev register failed for gpu, ret:%d\n",
PTR_ERR(cdev_data->cdev));
cdev_data->cdev = NULL;
goto qos_exit;
}
return;
qos_exit:
kfree(cdev_data->freq_table);
dev_pm_qos_remove_request(&cdev_data->qos_max_freq_req);
}
static int devfreq_cdev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
devfreq_cdev = devm_kzalloc(dev, sizeof(*devfreq_cdev), GFP_KERNEL);
if (!devfreq_cdev)
return -ENOMEM;
devfreq_cdev->np = of_parse_phandle(pdev->dev.of_node,
"qcom,devfreq", 0);
devfreq_cdev->retry_cnt = MAX_RETRY_CNT;
INIT_DEFERRABLE_WORK(&devfreq_cdev->register_work, devfreq_cdev_work);
queue_delayed_work(system_highpri_wq, &devfreq_cdev->register_work, 0);
return 0;
}
static int devfreq_cdev_remove(struct platform_device *pdev)
{
if (devfreq_cdev->cdev) {
thermal_cooling_device_unregister(devfreq_cdev->cdev);
dev_pm_qos_remove_request(&devfreq_cdev->qos_max_freq_req);
kfree(devfreq_cdev->freq_table);
devfreq_cdev->cdev = NULL;
}
return 0;
}
static const struct of_device_id devfreq_cdev_match[] = {
{.compatible = "qcom,devfreq-cdev"},
{}
};
static struct platform_driver devfreq_cdev_driver = {
.probe = devfreq_cdev_probe,
.remove = devfreq_cdev_remove,
.driver = {
.name = DEVFREQ_CDEV,
.of_match_table = devfreq_cdev_match,
},
};
static int __init devfreq_cdev_init(void)
{
return platform_driver_register(&devfreq_cdev_driver);
}
module_init(devfreq_cdev_init);
static void __exit devfreq_cdev_exit(void)
{
platform_driver_unregister(&devfreq_cdev_driver);
}
module_exit(devfreq_cdev_exit);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. devfreq cooling device driver");
MODULE_LICENSE("GPL");

View file

@ -88,6 +88,12 @@
#define QMI_EPM7 71
#define QMI_SDR0_PA 72
#define QMI_SDR1_PA 73
#define QMI_SUB0_SDR0_PA 74
#define QMI_SUB1_SDR0_PA 75
#define QMI_SYS_THERM_3 76
#define QMI_SYS_THERM_4 77
#define QMI_SYS_THERM_5 78
#define QMI_SYS_THERM_6 79
#define QMI_MODEM_INST_ID 0x0
#define QMI_ADSP_INST_ID 0x1