From 83bbb43e7e43d217860cdd2477968e235b08b0e3 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 4 Aug 2022 00:22:33 +0530 Subject: coresight: etm4x: Fix crash observed on Qcom ETM parts with 'Low power override' Some Qualcomm ETM implementations require skipping powering up the trace unit, as the ETMs are in the same power domain as their CPU cores. Via commit 5214b563588e ("coresight: etm4x: Add support for sysreg only devices"), the setting of 'skip_power_up' flag was moved after the 'etm4_init_arch_data' function is called, whereas the flag value is itself used inside the function. This causes a crash when ETM mode 'Low-power state behavior override' is set on some Qualcomm parts. Fix the same. Fixes: 5214b563588e ("coresight: etm4x: Add support for sysreg only devices") Cc: Mike Leach Cc: Suzuki K Poulose Cc: Mathieu Poirier Cc: Greg Kroah-Hartman Signed-off-by: Bhupesh Sharma --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 1ea8f173cca0..136bd2ff1653 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1039,6 +1039,16 @@ static bool etm4_init_sysreg_access(struct etmv4_drvdata *drvdata, if (!cpu_supports_sysreg_trace()) return false; + /* + * Some Qualcomm implementations require skipping powering up the trace unit, + * as the ETMs are in the same power domain as their CPU cores. + * + * Since the 'skip_power_up' flag is used inside 'etm4_init_arch_data' function, + * initialize it before the function is called. + */ + if (fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) + drvdata->skip_power_up = true; + /* * ETMs implementing sysreg access must implement TRCDEVARCH. */ @@ -1984,8 +1994,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) return -EINVAL; /* TRCPDCR is not accessible with system instructions. */ - if (!desc.access.io_mem || - fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) + if (!desc.access.io_mem) drvdata->skip_power_up = true; major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); -- cgit v1.2.3 From ca8ae8365ff2a6804648bd82100a4aba68b16342 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Tue, 24 May 2022 12:15:37 +0530 Subject: firmware: qcom: scm: Add support for tsens reinit workaround Some versions of Qualcomm tsens controller might enter a 'bad state' while running stability tests causing sensor temperatures/interrupts status to be in an 'invalid' state. It is recommended to re-initialize the tsens controller via trustzone (secure registers) using scm call(s) when that happens. Add support for the same in the qcom_scm driver. Cc: Bjorn Andersson Cc: Amit Kucheria Cc: Thara Gopinath Cc: linux-pm@vger.kernel.org Cc: linux-arm-msm@vger.kernel.org Signed-off-by: Bhupesh Sharma --- drivers/firmware/qcom_scm.c | 15 +++++++++++++++ drivers/firmware/qcom_scm.h | 4 ++++ include/linux/firmware/qcom/qcom_scm.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 468d4d5ab550..acafcecfa08b 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -865,6 +865,21 @@ int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size, } EXPORT_SYMBOL(qcom_scm_mem_protect_video_var); +int qcom_scm_tsens_reinit(void) +{ + int ret; + const struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_TSENS, + .cmd = QCOM_SCM_TSENS_INIT_ID, + }; + struct qcom_scm_res res; + + ret = qcom_scm_call(__scm->dev, &desc, &res); + + return ret ? : res.result[0]; +} +EXPORT_SYMBOL(qcom_scm_tsens_reinit); + static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, size_t mem_sz, phys_addr_t src, size_t src_sz, phys_addr_t dest, size_t dest_sz) diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index e6e512bd57d1..f0ee22acecf9 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -97,6 +97,10 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a +/* TSENS Services and Function IDs */ +#define QCOM_SCM_SVC_TSENS 0x1E +#define QCOM_SCM_TSENS_INIT_ID 0x5 + #define QCOM_SCM_SVC_IO 0x05 #define QCOM_SCM_IO_READ 0x01 #define QCOM_SCM_IO_WRITE 0x02 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 1e449a5d7f5c..af573820706b 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -122,4 +122,6 @@ extern int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, extern int qcom_scm_lmh_profile_change(u32 profile_id); extern bool qcom_scm_lmh_dcvsh_available(void); +extern int qcom_scm_tsens_reinit(void); + #endif -- cgit v1.2.3 From 30f58fd1ece211f845d77368821a18931bdc6730 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Fri, 22 Jul 2022 14:14:27 +0530 Subject: thermal: qcom: tsens: Add hooks for supplying platform specific reinit quirks Add hooks inside platform specific data which can be used by Qualcomm tsens controller(s) which might need reinitialization via trustzone. Cc: Bjorn Andersson Cc: Amit Kucheria Cc: Thara Gopinath Cc: linux-pm@vger.kernel.org Cc: linux-arm-msm@vger.kernel.org Signed-off-by: Bhupesh Sharma --- drivers/thermal/qcom/tsens.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index dba9cd38f637..0d9531a94deb 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -522,6 +522,7 @@ struct tsens_features { * @num_sensors: Number of sensors supported by platform * @ops: operations the tsens instance supports * @hw_ids: Subset of sensors ids supported by platform, if not the first n + * @needs_reinit_wa: tsens controller might need reinit via trustzone * @feat: features of the IP * @fields: bitfield locations */ @@ -529,6 +530,7 @@ struct tsens_plat_data { const u32 num_sensors; const struct tsens_ops *ops; unsigned int *hw_ids; + bool needs_reinit_wa; struct tsens_features *feat; const struct reg_field *fields; }; @@ -551,6 +553,7 @@ struct tsens_context { * @srot_map: pointer to SROT register address space * @tm_offset: deal with old device trees that don't address TM and SROT * address space separately + * @needs_reinit_wa: tsens controller might need reinit via trustzone * @ul_lock: lock while processing upper/lower threshold interrupts * @crit_lock: lock while processing critical threshold interrupts * @rf: array of regmap_fields used to store value of the field @@ -568,6 +571,7 @@ struct tsens_priv { struct regmap *tm_map; struct regmap *srot_map; u32 tm_offset; + bool needs_reinit_wa; /* lock for upper/lower threshold interrupts */ spinlock_t ul_lock; -- cgit v1.2.3 From 357e123b8ec17622f96f14fa96a14bacbee78552 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Wed, 1 Jun 2022 12:55:16 +0530 Subject: thermal: qcom: tsens: Add driver support for re-initialization quirk Since for some Qualcomm tsens controllers, its suggested to monitor the controller health periodically and in case an issue is detected, to re-initialize the tsens controller via trustzone, add the support for the same in the qcom tsens driver. Note that once the tsens controller is reset using scm call, all SROT and TM region registers will enter the reset mode. While all the SROT registers will be re-programmed and re-enabled in trustzone prior to the scm call exit, the TM region registers will not re-initialized in trustzone and thus need to be handled by the tsens driver. Cc: Bjorn Andersson Cc: Amit Kucheria Cc: Thara Gopinath Cc: linux-pm@vger.kernel.org Cc: linux-arm-msm@vger.kernel.org Signed-off-by: Bhupesh Sharma Signed-off-by: Dmitry Baryshkov --- drivers/thermal/qcom/tsens-v2.c | 3 + drivers/thermal/qcom/tsens.c | 197 ++++++++++++++++++++++++++++++++++++++++ drivers/thermal/qcom/tsens.h | 12 +++ 3 files changed, 212 insertions(+) diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 29a61d2d6ca3..10983208b314 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -102,6 +102,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { /* TRDY: 1=ready, 0=in progress */ [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), + + /* FIRST_ROUND_COMPLETE: 1=complete, 0=not complete */ + [FIRST_ROUND_COMPLETE] = REG_FIELD(TM_TRDY_OFF, 3, 3), }; static const struct tsens_ops ops_generic_v2 = { diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 8020ead2794e..048640eb8b1a 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -733,6 +734,113 @@ static void tsens_disable_irq(struct tsens_priv *priv) regmap_field_write(priv->rf[INT_EN], 0); } +static int tsens_reenable_hw_after_scm(struct tsens_priv *priv) +{ + /* + * Re-enable watchdog, unmask the bark and + * disable cycle completion monitoring. + */ + regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1); + regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0); + regmap_field_write(priv->rf[WDOG_BARK_MASK], 0); + regmap_field_write(priv->rf[CC_MON_MASK], 1); + + /* Re-enable interrupts */ + tsens_enable_irq(priv); + + return 0; +} + +static int tsens_health_check_and_reinit(struct tsens_priv *priv, + int hw_id) +{ + int ret, trdy, first_round, sw_reg; + unsigned long timeout; + + /* First check if TRDY is SET */ + ret = regmap_field_read(priv->rf[TRDY], &trdy); + if (ret) + goto err; + + if (!trdy) { + ret = regmap_field_read(priv->rf[FIRST_ROUND_COMPLETE], &first_round); + if (ret) + goto err; + + if (!first_round) { + WARN_ON(!mutex_is_locked(&priv->reinit_mutex)); + + /* Wait for 2 ms for tsens controller to recover */ + timeout = jiffies + msecs_to_jiffies(RESET_TIMEOUT_MS); + do { + ret = regmap_field_read(priv->rf[FIRST_ROUND_COMPLETE], + &first_round); + if (ret) + goto err; + + if (first_round) { + dev_dbg(priv->dev, "tsens controller recovered\n"); + return 0; /* success */ + } + } while (time_before(jiffies, timeout)); + + spin_lock(&priv->reinit_lock); + + /* + * Invoke SCM call only if SW register write is + * reflecting in controller. Try it for 2 ms. + * In case that fails mark the tsens controller + * as unrecoverable. + */ + timeout = jiffies + msecs_to_jiffies(RESET_TIMEOUT_MS); + do { + ret = regmap_field_write(priv->rf[INT_EN], CRITICAL_INT_EN); + if (ret) + goto err; + + ret = regmap_field_read(priv->rf[INT_EN], &sw_reg); + if (ret) + goto err; + } while ((sw_reg & CRITICAL_INT_EN) && (time_before(jiffies, timeout))); + + if (!(sw_reg & CRITICAL_INT_EN)) { + ret = -ENOTRECOVERABLE; + goto err; + } + + /* + * tsens controller did not recover, + * proceed with SCM call to re-init it. + */ + ret = qcom_scm_tsens_reinit(); + if (ret) { + dev_err(priv->dev, "tsens reinit scm call failed (%d)\n", ret); + goto err; + } + + /* + * After the SCM call, we need to re-enable + * the interrupts and also set active threshold + * for each sensor. + */ + ret = tsens_reenable_hw_after_scm(priv); + if (ret) { + dev_err(priv->dev, + "tsens re-enable after scm call failed (%d)\n", ret); + goto err; + } + + /* Notify reinit wa worker */ + queue_work(system_highpri_wq, &priv->reinit_wa_notify); + + spin_unlock(&priv->reinit_lock); + } + } + +err: + return ret; +} + int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) { struct tsens_priv *priv = s->priv; @@ -746,6 +854,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) if (tsens_version(priv) == VER_0) goto get_temp; + /* + * For some tsens controllers, its suggested to + * monitor the controller health periodically + * and in case an issue is detected to reinit + * tsens controller via trustzone. + */ + if (priv->needs_reinit_wa) { + mutex_lock(&priv->reinit_mutex); + ret = tsens_health_check_and_reinit(priv, hw_id); + mutex_unlock(&priv->reinit_mutex); + + if (ret) + return ret; + } + /* Valid bit is 0 for 6 AHB clock cycles. * At 19.2MHz, 1 AHB clock is ~60ns. * We should enter this loop very, very rarely. @@ -871,6 +994,40 @@ static const struct regmap_config tsens_srot_config = { .reg_stride = 4, }; +static void __tsens_reinit_worker(struct tsens_priv *priv) +{ + int ret, temp; + unsigned int i; + struct tsens_irq_data d; + + for (i = 0; i < priv->num_sensors; i++) { + const struct tsens_sensor *s = &priv->sensor[i]; + u32 hw_id = s->hw_id; + + if (!s->tzd) + continue; + if (!tsens_threshold_violated(priv, hw_id, &d)) + continue; + + ret = get_temp_tsens_valid(s, &temp); + if (ret) { + dev_err(priv->dev, "[%u] error reading sensor during reinit\n", hw_id); + continue; + } + + tsens_read_irq_state(priv, hw_id, s, &d); + + if ((d.up_thresh < temp) || (d.low_thresh > temp)) { + dev_dbg(priv->dev, "[%u] TZ update trigger during reinit (%d mC)\n", + hw_id, temp); + thermal_zone_device_update(s->tzd, THERMAL_EVENT_UNSPECIFIED); + } else { + dev_dbg(priv->dev, "[%u] no violation during reinit (%d)\n", + hw_id, temp); + } + } +} + int __init init_common(struct tsens_priv *priv) { void __iomem *tm_base, *srot_base; @@ -992,6 +1149,14 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } + priv->rf[FIRST_ROUND_COMPLETE] = devm_regmap_field_alloc(dev, + priv->tm_map, + priv->fields[FIRST_ROUND_COMPLETE]); + if (IS_ERR(priv->rf[FIRST_ROUND_COMPLETE])) { + ret = PTR_ERR(priv->rf[FIRST_ROUND_COMPLETE]); + goto err_put_device; + } + /* This loop might need changes if enum regfield_ids is reordered */ for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { for (i = 0; i < priv->feat->max_sensors; i++) { @@ -1223,6 +1388,14 @@ static int tsens_register(struct tsens_priv *priv) return ret; } +static void tsens_reinit_worker_notify(struct work_struct *work) +{ + struct tsens_priv *priv = container_of(work, struct tsens_priv, + reinit_wa_notify); + + __tsens_reinit_worker(priv); +} + static int tsens_probe(struct platform_device *pdev) { int ret, i; @@ -1264,6 +1437,11 @@ static int tsens_probe(struct platform_device *pdev) priv->dev = dev; priv->num_sensors = num_sensors; + priv->needs_reinit_wa = data->needs_reinit_wa; + + if (priv->needs_reinit_wa && !qcom_scm_is_available()) + return -EPROBE_DEFER; + priv->ops = data->ops; for (i = 0; i < priv->num_sensors; i++) { if (data->hw_ids) @@ -1279,6 +1457,25 @@ static int tsens_probe(struct platform_device *pdev) if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) return -EINVAL; + /* + * Reinitialization workaround is currently supported only for + * tsens controller versions v2. + * + * If incorrect platform data is passed to this effect, ignore + * the requested setting and move forward. + */ + if (priv->needs_reinit_wa && (tsens_version(priv) < VER_2_X)) { + dev_warn(dev, + "%s: Reinit quirk available only for tsens v2\n", __func__); + priv->needs_reinit_wa = false; + } + + mutex_init(&priv->reinit_mutex); + spin_lock_init(&priv->reinit_lock); + + if (priv->needs_reinit_wa) + INIT_WORK(&priv->reinit_wa_notify, tsens_reinit_worker_notify); + ret = priv->ops->init(priv); if (ret < 0) { dev_err(dev, "%s: init failed\n", __func__); diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 0d9531a94deb..9335772cb44c 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -15,9 +15,12 @@ #define SLOPE_FACTOR 1000 #define SLOPE_DEFAULT 3200 #define TIMEOUT_US 100 +#define RESET_TIMEOUT_MS 2 #define THRESHOLD_MAX_ADC_CODE 0x3ff #define THRESHOLD_MIN_ADC_CODE 0x0 +#define CRITICAL_INT_EN (BIT(2)) + #define MAX_SENSORS 16 #include @@ -168,6 +171,7 @@ enum regfield_ids { /* ----- TM ------ */ /* TRDY */ TRDY, + FIRST_ROUND_COMPLETE, /* INTERRUPT ENABLE */ INT_EN, /* v2+ has separate enables for crit, upper and lower irq */ /* STATUS */ @@ -573,6 +577,14 @@ struct tsens_priv { u32 tm_offset; bool needs_reinit_wa; + struct work_struct reinit_wa_notify; + + /* protects reinit related serialization */ + struct mutex reinit_mutex; + + /* lock for reinit workaround */ + spinlock_t reinit_lock; + /* lock for upper/lower threshold interrupts */ spinlock_t ul_lock; -- cgit v1.2.3 From 6c51002e35d436b7b6dc14ee7d3878a9e6f97e18 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Wed, 25 May 2022 10:58:52 +0530 Subject: thermal: qcom: tsens: Add reinit quirk support for tsens v2 controllers Some Qualcomm tsens v2 controllers like those present on sm8150 SoC might require re-initialization via trustzone [via scm call(s)] when it enters a 'bad state' causing sensor temperatures/interrupts status to be in an 'invalid' state. Add hooks for the same in the qcom tsens driver. Devices requiring the same can pass the relevant compatible string in dt and the driver hook can be used accordingly. Cc: Bjorn Andersson Cc: Amit Kucheria Cc: Thara Gopinath Cc: linux-pm@vger.kernel.org Cc: linux-arm-msm@vger.kernel.org Signed-off-by: Bhupesh Sharma --- drivers/thermal/qcom/tsens-v2.c | 12 ++++++++++++ drivers/thermal/qcom/tsens.c | 3 +++ drivers/thermal/qcom/tsens.h | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 10983208b314..f0093f526f97 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -124,6 +124,18 @@ struct tsens_plat_data data_ipq8074 = { .fields = tsens_v2_regfields, }; +/* + * For some tsens v2 controllers, its suggested to monitor the + * controller health periodically and in case an issue is detected + * to reinit tsens controller via trustzone. + */ +struct tsens_plat_data data_tsens_v2_reinit = { + .ops = &ops_generic_v2, + .feat = &tsens_v2_feat, + .needs_reinit_wa = true, + .fields = tsens_v2_regfields, +}; + /* Kept around for backward compatibility with old msm8996.dtsi */ struct tsens_plat_data data_8996 = { .num_sensors = 13, diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 048640eb8b1a..fc62066bf220 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -1281,6 +1281,9 @@ static const struct of_device_id tsens_table[] = { }, { .compatible = "qcom,msm8996-tsens", .data = &data_8996, + }, { + .compatible = "qcom,sm8150-tsens", + .data = &data_tsens_v2_reinit, }, { .compatible = "qcom,tsens-v1", .data = &data_tsens_v1, diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 9335772cb44c..cf31da203619 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -657,6 +657,6 @@ extern struct tsens_plat_data data_8916, data_8939, data_8974, data_9607; extern struct tsens_plat_data data_tsens_v1, data_8976, data_8956; /* TSENS v2 targets */ -extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2; +extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2_reinit, data_tsens_v2; #endif /* __QCOM_TSENS_H__ */ -- cgit v1.2.3 From f90b61c9464a43d7d103715df785e0fbe91bcdea Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 28 Jul 2022 09:18:53 +0530 Subject: thermal: qcom: qmi_cooling: Add skeletal qmi cooling driver Add a skeleton driver for supporting Qualcomm QMI thermal mitigation (TMD) cooling devices. The QMI TMD cooling devices are used for various mitigations for remote subsystem(s) including remote processor mitigation, rail voltage restriction etc. This driver uses kernel QMI interface to send the message to remote subsystem(s). Each child node of the QMI TMD devicetree node should represent each remote subsystem and each child of this subsystem represents separate cooling devices. Cc: daniel.lezcano@linaro.org Cc: rafael@kernel.org Cc: andersson@kernel.org Signed-off-by: Bhupesh Sharma --- .../thermal/qcom/qmi_cooling/qcom_qmi_cooling.c | 632 +++++++++++++++++++++ .../thermal/qcom/qmi_cooling/qcom_tmd_services.c | 352 ++++++++++++ .../thermal/qcom/qmi_cooling/qcom_tmd_services.h | 120 ++++ 3 files changed, 1104 insertions(+) create mode 100644 drivers/thermal/qcom/qmi_cooling/qcom_qmi_cooling.c create mode 100644 drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.c create mode 100644 drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.h diff --git a/drivers/thermal/qcom/qmi_cooling/qcom_qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling/qcom_qmi_cooling.c new file mode 100644 index 000000000000..4cb601533b9d --- /dev/null +++ b/drivers/thermal/qcom/qmi_cooling/qcom_qmi_cooling.c @@ -0,0 +1,632 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qcom_tmd_services.h" + +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100) +#define QMI_CLIENT_NAME_LENGTH 40 +#define QMI_MAX_ALLOWED_INSTANCE_ID 0x80 + +/** + * struct qmi_plat_data - qmi compile-time platform data + * @ninstances: Number of instances supported by platform + */ +struct qmi_plat_data { + const u32 ninstances; +}; + +struct qmi_cooling_device { + struct device_node *np; + char cdev_name[THERMAL_NAME_LENGTH]; + char qmi_name[QMI_CLIENT_NAME_LENGTH]; + bool connection_active; + struct list_head qmi_node; + struct thermal_cooling_device *cdev; + unsigned int mtgn_state; + unsigned int max_level; + struct qmi_tmd_instance *instance; +}; + +struct qmi_tmd_instance { + struct device *dev; + struct qmi_handle handle; + struct mutex mutex; + u32 instance_id; + struct list_head tmd_cdev_list; + struct work_struct svc_arrive_work; +}; + +/** + * struct qmi_tmd_priv + * @dev: device. + * @instances: array of QMI TMD instances. + * @ninstances: number of QMI TMD instances. + */ +struct qmi_tmd_priv { + struct device *dev; + struct qmi_tmd_instance *instances; + u32 ninstances; +}; + +static char device_clients[][QMI_CLIENT_NAME_LENGTH] = { + {"pa"}, + {"pa_fr1"}, + {"cx_vdd_limit"}, + {"modem"}, + {"modem_current"}, + {"modem_skin"}, + {"modem_bw"}, + {"modem_bw_backoff"}, + {"vbatt_low"}, + {"charge_state"}, + {"mmw0"}, + {"mmw1"}, + {"mmw2"}, + {"mmw3"}, + {"mmw_skin0"}, + {"mmw_skin1"}, + {"mmw_skin2"}, + {"mmw_skin3"}, + {"wlan"}, + {"wlan_bw"}, + {"mmw_skin0_dsc"}, + {"mmw_skin1_dsc"}, + {"mmw_skin2_dsc"}, + {"mmw_skin3_dsc"}, + {"modem_skin_lte_dsc"}, + {"modem_skin_nr_dsc"}, + {"pa_dsc"}, + {"pa_fr1_dsc"}, + {"cdsp_sw"}, + {"cdsp_hw"}, + {"cpuv_restriction_cold"}, + {"cpr_cold"}, + {"modem_lte_dsc"}, + {"modem_nr_dsc"}, + {"modem_nr_scg_dsc"}, + {"sdr0_lte_dsc"}, + {"sdr1_lte_dsc"}, + {"sdr0_nr_dsc"}, + {"sdr1_nr_dsc"}, + {"pa_lte_sdr0_dsc"}, + {"pa_lte_sdr1_dsc"}, + {"pa_nr_sdr0_dsc"}, + {"pa_nr_sdr1_dsc"}, + {"pa_nr_sdr0_scg_dsc"}, + {"pa_nr_sdr1_scg_dsc"}, + {"mmw0_dsc"}, + {"mmw1_dsc"}, + {"mmw2_dsc"}, + {"mmw3_dsc"}, + {"mmw_ific_dsc"}, +}; + +static int qmi_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct qmi_cooling_device *qmi_cdev = cdev->devdata; + + if (!qmi_cdev) + return -EINVAL; + + *state = qmi_cdev->max_level; + + return 0; +} + +static int qmi_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct qmi_cooling_device *qmi_cdev = cdev->devdata; + + if (!qmi_cdev) + return -EINVAL; + + *state = qmi_cdev->mtgn_state; + + return 0; +} + +static int qmi_tmd_send_state_request(struct qmi_cooling_device *qmi_cdev, + uint8_t state) +{ + int ret = 0; + struct tmd_set_mitigation_level_req_msg_v01 req; + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp; + struct qmi_tmd_instance *tmd_instance = qmi_cdev->instance; + struct qmi_txn txn; + + memset(&req, 0, sizeof(req)); + memset(&tmd_resp, 0, sizeof(tmd_resp)); + + strscpy(req.mitigation_dev_id.mitigation_dev_id, qmi_cdev->qmi_name, + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01); + req.mitigation_level = state; + + mutex_lock(&tmd_instance->mutex); + + ret = qmi_txn_init(&tmd_instance->handle, &txn, + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp); + if (ret < 0) { + pr_err("qmi set state:%d txn init failed for %s ret:%d\n", + state, qmi_cdev->cdev_name, ret); + goto qmi_send_exit; + } + + ret = qmi_send_request(&tmd_instance->handle, NULL, &txn, + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01, + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN, + tmd_set_mitigation_level_req_msg_v01_ei, &req); + if (ret < 0) { + pr_err("qmi set state:%d txn send failed for %s ret:%d\n", + state, qmi_cdev->cdev_name, ret); + qmi_txn_cancel(&txn); + goto qmi_send_exit; + } + + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT); + if (ret < 0) { + pr_err("qmi set state:%d txn wait failed for %s ret:%d\n", + state, qmi_cdev->cdev_name, ret); + goto qmi_send_exit; + } + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ret = tmd_resp.resp.result; + pr_err("qmi set state:%d NOT success for %s ret:%d\n", + state, qmi_cdev->cdev_name, ret); + goto qmi_send_exit; + } + ret = 0; + pr_debug("Requested qmi state:%d for %s\n", state, qmi_cdev->cdev_name); + +qmi_send_exit: + mutex_unlock(&tmd_instance->mutex); + return ret; +} + +static int qmi_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct qmi_cooling_device *qmi_cdev = cdev->devdata; + int ret = 0; + + if (!qmi_cdev) + return -EINVAL; + + if (state > qmi_cdev->max_level) + return -EINVAL; + + if (qmi_cdev->mtgn_state == state) + return 0; + + /* save it and return if server exit */ + if (!qmi_cdev->connection_active) { + qmi_cdev->mtgn_state = state; + pr_debug("Pending request:%ld for %s\n", state, + qmi_cdev->cdev_name); + return 0; + } + + /* It is best effort to save state even if QMI fail */ + ret = qmi_tmd_send_state_request(qmi_cdev, (uint8_t)state); + + qmi_cdev->mtgn_state = state; + + return ret; +} + +static struct thermal_cooling_device_ops qmi_device_ops = { + .get_max_state = qmi_get_max_state, + .get_cur_state = qmi_get_cur_state, + .set_cur_state = qmi_set_cur_state, +}; + +static int qmi_register_cooling_device(struct qmi_cooling_device *qmi_cdev) +{ + qmi_cdev->cdev = thermal_of_cooling_device_register( + qmi_cdev->np, + qmi_cdev->cdev_name, + qmi_cdev, + &qmi_device_ops); + if (IS_ERR(qmi_cdev->cdev)) { + pr_err("Cooling register failed for %s, ret:%ld\n", + qmi_cdev->cdev_name, PTR_ERR(qmi_cdev->cdev)); + return PTR_ERR(qmi_cdev->cdev); + } + pr_debug("Cooling register success for %s\n", qmi_cdev->cdev_name); + + return 0; +} + +static int verify_devices_and_register(struct qmi_tmd_instance *tmd_instance) +{ + struct tmd_get_mitigation_device_list_req_msg_v01 req; + struct tmd_get_mitigation_device_list_resp_msg_v01 *tmd_resp; + int ret = 0, i; + struct qmi_txn txn; + + memset(&req, 0, sizeof(req)); + /* size of tmd_resp is very high, use heap memory rather than stack */ + tmd_resp = kzalloc(sizeof(*tmd_resp), GFP_KERNEL); + if (!tmd_resp) + return -ENOMEM; + + mutex_lock(&tmd_instance->mutex); + ret = qmi_txn_init(&tmd_instance->handle, &txn, + tmd_get_mitigation_device_list_resp_msg_v01_ei, tmd_resp); + if (ret < 0) { + pr_err("Transaction Init error for instance_id:0x%x ret:%d\n", + tmd_instance->instance_id, ret); + goto reg_exit; + } + + ret = qmi_send_request(&tmd_instance->handle, NULL, &txn, + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01, + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN, + tmd_get_mitigation_device_list_req_msg_v01_ei, + &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + goto reg_exit; + } + + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT); + if (ret < 0) { + pr_err("Transaction wait error for instance_id:0x%x ret:%d\n", + tmd_instance->instance_id, ret); + goto reg_exit; + } + if (tmd_resp->resp.result != QMI_RESULT_SUCCESS_V01) { + ret = tmd_resp->resp.result; + pr_err("Get device list NOT success for instance_id:0x%x ret:%d\n", + tmd_instance->instance_id, ret); + goto reg_exit; + } + mutex_unlock(&tmd_instance->mutex); + + for (i = 0; i < tmd_resp->mitigation_device_list_len; i++) { + struct qmi_cooling_device *qmi_cdev = NULL; + + list_for_each_entry(qmi_cdev, &tmd_instance->tmd_cdev_list, + qmi_node) { + struct tmd_mitigation_dev_list_type_v01 *device = + &tmd_resp->mitigation_device_list[i]; + + if ((strncasecmp(qmi_cdev->qmi_name, + device->mitigation_dev_id.mitigation_dev_id, + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01))) + continue; + + qmi_cdev->connection_active = true; + qmi_cdev->max_level = device->max_mitigation_level; + /* + * It is better to set current state + * initially or during restart + */ + qmi_tmd_send_state_request(qmi_cdev, + qmi_cdev->mtgn_state); + if (!qmi_cdev->cdev) + ret = qmi_register_cooling_device(qmi_cdev); + break; + } + } + + kfree(tmd_resp); + return ret; + +reg_exit: + mutex_unlock(&tmd_instance->mutex); + kfree(tmd_resp); + + return ret; +} + +static void qmi_tmd_svc_arrive(struct work_struct *work) +{ + struct qmi_tmd_instance *tmd_instance = container_of(work, + struct qmi_tmd_instance, + svc_arrive_work); + + verify_devices_and_register(tmd_instance); +} + +static void thermal_qmi_net_reset(struct qmi_handle *qmi) +{ + struct qmi_tmd_instance *tmd_instance = container_of(qmi, + struct qmi_tmd_instance, + handle); + struct qmi_cooling_device *qmi_cdev = NULL; + + list_for_each_entry(qmi_cdev, &tmd_instance->tmd_cdev_list, + qmi_node) { + if (qmi_cdev->connection_active) + qmi_tmd_send_state_request(qmi_cdev, + qmi_cdev->mtgn_state); + } +} + +static void thermal_qmi_del_server(struct qmi_handle *qmi, + struct qmi_service *service) +{ + struct qmi_tmd_instance *tmd_instance = container_of(qmi, + struct qmi_tmd_instance, + handle); + struct qmi_cooling_device *qmi_cdev = NULL; + + list_for_each_entry(qmi_cdev, &tmd_instance->tmd_cdev_list, qmi_node) + qmi_cdev->connection_active = false; +} + +static int thermal_qmi_new_server(struct qmi_handle *qmi, + struct qmi_service *service) +{ + struct qmi_tmd_instance *tmd_instance = container_of(qmi, + struct qmi_tmd_instance, + handle); + struct sockaddr_qrtr sq = {AF_QIPCRTR, service->node, service->port}; + + mutex_lock(&tmd_instance->mutex); + kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); + mutex_unlock(&tmd_instance->mutex); + queue_work(system_highpri_wq, &tmd_instance->svc_arrive_work); + + return 0; +} + +static struct qmi_ops thermal_qmi_event_ops = { + .new_server = thermal_qmi_new_server, + .del_server = thermal_qmi_del_server, + .net_reset = thermal_qmi_net_reset, +}; + +static void qmi_tmd_cleanup(struct qmi_tmd_priv *priv) +{ + int i; + struct qmi_tmd_instance *tmd_instance = priv->instances; + struct qmi_cooling_device *qmi_cdev, *c_next; + + for (i = 0; i < priv->ninstances; i++) { + mutex_lock(&tmd_instance[i].mutex); + list_for_each_entry_safe(qmi_cdev, c_next, + &tmd_instance[i].tmd_cdev_list, qmi_node) { + qmi_cdev->connection_active = false; + if (qmi_cdev->cdev) + thermal_cooling_device_unregister( + qmi_cdev->cdev); + + list_del(&qmi_cdev->qmi_node); + } + qmi_handle_release(&tmd_instance[i].handle); + + mutex_unlock(&tmd_instance[i].mutex); + } +} + +static int qmi_get_dt_instance_data(struct qmi_tmd_priv *priv, + struct qmi_tmd_instance *instance, + struct device_node *node) +{ + struct device *dev = priv->dev; + struct qmi_cooling_device *qmi_cdev; + struct device_node *subnode; + int ret, i; + u32 instance_id; + + ret = of_property_read_u32(node, "qcom,instance-id", &instance_id); + if (ret) { + dev_err(dev, "error reading qcom,instance-id (%d)\n", + ret); + return ret; + } + + if (instance_id >= QMI_MAX_ALLOWED_INSTANCE_ID) { + dev_err(dev, "Instance ID exceeds max allowed value (%d)\n", instance_id); + return -EINVAL; + } + + instance->instance_id = instance_id; + + instance->dev = dev; + mutex_init(&instance->mutex); + INIT_LIST_HEAD(&instance->tmd_cdev_list); + INIT_WORK(&instance->svc_arrive_work, qmi_tmd_svc_arrive); + + for_each_available_child_of_node(node, subnode) { + const char *qmi_name; + + qmi_cdev = devm_kzalloc(dev, sizeof(*qmi_cdev), + GFP_KERNEL); + if (!qmi_cdev) { + ret = -ENOMEM; + goto data_error; + } + + strscpy(qmi_cdev->cdev_name, subnode->name, + THERMAL_NAME_LENGTH); + + if (!of_property_read_string(subnode, + "label", + &qmi_name)) { + strscpy(qmi_cdev->qmi_name, qmi_name, + QMI_CLIENT_NAME_LENGTH); + } else { + dev_err(dev, "Fail to parse dev name for %s\n", + subnode->name); + of_node_put(subnode); + break; + } + + /* Check for supported qmi dev */ + for (i = 0; i < ARRAY_SIZE(device_clients); i++) { + if (strcmp(device_clients[i], + qmi_cdev->qmi_name) == 0) + break; + } + + if (i >= ARRAY_SIZE(device_clients)) { + dev_err(dev, "Not supported dev name for %s\n", + subnode->name); + of_node_put(subnode); + break; + } + qmi_cdev->instance = instance; + qmi_cdev->np = subnode; + qmi_cdev->mtgn_state = 0; + list_add(&qmi_cdev->qmi_node, &instance->tmd_cdev_list); + } + + of_node_put(node); + + return 0; +data_error: + of_node_put(subnode); + + return ret; +} + +static int qmi_tmd_device_init(struct qmi_tmd_priv *priv) +{ + int i, ret; + u32 ninstances = priv->ninstances; + + for (i = 0; i < ninstances; i++) { + struct qmi_tmd_instance *tmd_instance = &priv->instances[i]; + + if (list_empty(&tmd_instance->tmd_cdev_list)) + continue; + + ret = qmi_handle_init(&tmd_instance->handle, + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN, + &thermal_qmi_event_ops, NULL); + if (ret < 0) { + dev_err(priv->dev, "QMI[0x%x] handle init failed. err:%d\n", + tmd_instance->instance_id, ret); + priv->ninstances = i; + return ret; + } + + ret = qmi_add_lookup(&tmd_instance->handle, TMD_SERVICE_ID_V01, + TMD_SERVICE_VERS_V01, + tmd_instance->instance_id); + if (ret < 0) { + dev_err(priv->dev, "QMI register failed for 0x%x, ret:%d\n", + tmd_instance->instance_id, ret); + return ret; + } + } + + return 0; +} + +static const struct of_device_id qmi_tmd_device_table[] = { + {.compatible = "qcom,qmi-tmd-devices"}, + {} +}; +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table); + +static int qmi_tmd_device_probe(struct platform_device *pdev) +{ + struct device *dev; + struct device_node *np; + struct device_node *child; + struct qmi_tmd_instance *instances; + const struct qmi_plat_data *data; + const struct of_device_id *id; + struct qmi_tmd_priv *priv; + int ret; + u32 ninstances; + + if (pdev->dev.of_node) + dev = &pdev->dev; + else + dev = pdev->dev.parent; + + np = dev->of_node; + + id = of_match_node(qmi_tmd_device_table, np); + if (!id) + return -ENODEV; + + data = id->data; + + if (np) + ninstances = of_get_available_child_count(np); + + if (ninstances <= 0) { + dev_err(dev, "No instances to process\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->ninstances = ninstances; + + priv->instances = devm_kcalloc(dev, priv->ninstances, + sizeof(*priv->instances), GFP_KERNEL); + if (!priv->instances) + return -ENOMEM; + + instances = priv->instances; + + for_each_available_child_of_node(np, child) { + ret = qmi_get_dt_instance_data(priv, instances, child); + if (ret) { + of_node_put(child); + return ret; + } + + instances++; + } + + platform_set_drvdata(pdev, priv); + + ret = qmi_tmd_device_init(priv); + if (ret) + goto probe_err; + + dev_dbg(dev, "QMI Thermal Mitigation Device driver probe success!\n"); + return 0; + +probe_err: + qmi_tmd_cleanup(priv); + return ret; +} + +static int qmi_tmd_device_remove(struct platform_device *pdev) +{ + struct qmi_tmd_priv *priv = platform_get_drvdata(pdev); + + qmi_tmd_cleanup(priv); + + return 0; +} + +static struct platform_driver qmi_tmd_device_driver = { + .probe = qmi_tmd_device_probe, + .remove = qmi_tmd_device_remove, + .driver = { + .name = "qcom-qmi-tmd-devices", + .of_match_table = qmi_tmd_device_table, + }, +}; + +module_platform_driver(qmi_tmd_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver"); +MODULE_ALIAS("platform:qcom-qmi-tmd-devices"); diff --git a/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.c b/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.c new file mode 100644 index 000000000000..5b950b8952f0 --- /dev/null +++ b/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022, Linaro Limited + */ + +#include + +#include "qcom_tmd_services.h" + +static struct qmi_elem_info tmd_mitigation_dev_id_type_v01_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof( + struct tmd_mitigation_dev_id_type_v01, + mitigation_dev_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info tmd_mitigation_dev_list_type_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof( + struct tmd_mitigation_dev_list_type_v01, + mitigation_dev_id), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof( + struct tmd_mitigation_dev_list_type_v01, + max_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_get_mitigation_device_list_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01, + .elem_size = sizeof( + struct tmd_mitigation_dev_list_type_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list), + .ei_array = tmd_mitigation_dev_list_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_set_mitigation_level_req_msg_v01, + mitigation_dev_id), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_set_mitigation_level_req_msg_v01, + mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_set_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_get_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_get_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct tmd_get_mitigation_level_resp_msg_v01, + current_mitigation_level_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct tmd_get_mitigation_level_resp_msg_v01, + current_mitigation_level), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct tmd_get_mitigation_level_resp_msg_v01, + requested_mitigation_level_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct tmd_get_mitigation_level_resp_msg_v01, + requested_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_register_notification_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] + = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_register_notification_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] + = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct + tmd_deregister_notification_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] + = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + tmd_deregister_notification_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_mitigation_level_report_ind_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_mitigation_level_report_ind_msg_v01, + current_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; diff --git a/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.h b/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.h new file mode 100644 index 000000000000..8af0bfd7eb48 --- /dev/null +++ b/drivers/thermal/qcom/qmi_cooling/qcom_tmd_services.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022, Linaro Limited + */ + +#ifndef __QCOM_TMD_SERVICES_H +#define __QCOM_TMD_SERVICES_H + +#define TMD_SERVICE_ID_V01 0x18 +#define TMD_SERVICE_VERS_V01 0x01 + +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020 +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022 +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021 +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023 +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021 +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024 +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025 +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022 +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020 +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023 +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024 +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F + +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32 +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32 + +struct tmd_mitigation_dev_id_type_v01 { + char mitigation_dev_id[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1]; +}; + +struct tmd_mitigation_dev_list_type_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id; + uint8_t max_mitigation_level; +}; + +struct tmd_get_mitigation_device_list_req_msg_v01 { + char placeholder; +}; +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[]; + +struct tmd_get_mitigation_device_list_resp_msg_v01 { + struct qmi_response_type_v01 resp; + uint8_t mitigation_device_list_valid; + uint32_t mitigation_device_list_len; + struct tmd_mitigation_dev_list_type_v01 + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01]; +}; +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099 +extern struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[]; + +struct tmd_set_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id; + uint8_t mitigation_level; +}; +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40 +extern struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[]; + +struct tmd_set_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[]; + +struct tmd_get_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 +extern struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[]; + +struct tmd_get_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; + uint8_t current_mitigation_level_valid; + uint8_t current_mitigation_level; + uint8_t requested_mitigation_level_valid; + uint8_t requested_mitigation_level; +}; +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15 +extern struct qmi_elem_info tmd_get_mitigation_level_resp_msg_v01_ei[]; + +struct tmd_register_notification_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 +extern struct qmi_elem_info + tmd_register_notification_mitigation_level_req_msg_v01_ei[]; + +struct tmd_register_notification_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info + tmd_register_notification_mitigation_level_resp_msg_v01_ei[]; + +struct tmd_deregister_notification_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 +extern struct qmi_elem_info + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[]; + +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[]; + +struct tmd_mitigation_level_report_ind_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; + uint8_t current_mitigation_level; +}; +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40 +extern struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[]; + +#endif -- cgit v1.2.3 From b75f96a9b3f2047f0d537510c1cf65683cafdf1a Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 28 Jul 2022 09:21:09 +0530 Subject: thermal: qcom: Add Kconfig entry & compilation support for qmi cooling driver Add Kconfig entry & compilation support for Qualcomm qmi cooling driver. Cc: daniel.lezcano@linaro.org Cc: rafael@kernel.org Cc: andersson@kernel.org Signed-off-by: Bhupesh Sharma --- drivers/thermal/qcom/Kconfig | 4 ++++ drivers/thermal/qcom/Makefile | 2 ++ drivers/thermal/qcom/qmi_cooling/Kconfig | 14 ++++++++++++++ drivers/thermal/qcom/qmi_cooling/Makefile | 3 +++ 4 files changed, 23 insertions(+) create mode 100644 drivers/thermal/qcom/qmi_cooling/Kconfig create mode 100644 drivers/thermal/qcom/qmi_cooling/Makefile diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index 2c7f3f9a26eb..406240ccb86d 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -41,3 +41,7 @@ config QCOM_LMH input from temperature and current sensors. On many newer Qualcomm SoCs LMh is configured in the firmware and this feature need not be enabled. However, on certain SoCs like sdm845 LMh has to be configured from kernel. + +menu "Qualcomm QMI cooling drivers" +source "drivers/thermal/qcom/qmi_cooling/Kconfig" +endmenu diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 0fa2512042e7..61114129827a 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi_cooling/ + obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o qcom_tsens-y += tsens.o tsens-v2.o tsens-v1.o tsens-v0_1.o \ diff --git a/drivers/thermal/qcom/qmi_cooling/Kconfig b/drivers/thermal/qcom/qmi_cooling/Kconfig new file mode 100644 index 000000000000..96488181cd5f --- /dev/null +++ b/drivers/thermal/qcom/qmi_cooling/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config QCOM_QMI_COOLING + tristate "Qualcomm QMI cooling drivers" + depends on QCOM_RPROC_COMMON + depends on ARCH_QCOM || COMPILE_TEST + select QCOM_QMI_HELPERS + help + This enables the remote subsystem cooling devices. These cooling + devices will be used by Qualcomm chipset to place various remote + subsystem mitigations like remote processor passive mitigation, + remote subsystem voltage restriction at low temperatures etc. + The QMI cooling device will interface with remote subsystem + using Qualcomm remoteproc interface. diff --git a/drivers/thermal/qcom/qmi_cooling/Makefile b/drivers/thermal/qcom/qmi_cooling/Makefile new file mode 100644 index 000000000000..ea6cb3c8adb0 --- /dev/null +++ b/drivers/thermal/qcom/qmi_cooling/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_QCOM_QMI_COOLING) += qcom_cooling.o +qcom_cooling-y += qcom_tmd_services.o qcom_qmi_cooling.o -- cgit v1.2.3 From e796f4217d88fc6c97ab697436b06f8c5e251cd1 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Fri, 5 Aug 2022 03:35:52 +0530 Subject: dt-bindings: thermal: Add qcom,qmi-tmd-device and qcom,tmd-device yaml bindings Add qcom,qmi-tmd-device and qcom,tmd-device yaml bindings. Qualcomm QMI based TMD cooling device(s) are used for various mitigations for remote subsystem(s) including remote processor mitigation, rail voltage restriction etc. Each child node represents one remote subsystem and each child of this subsystem in-turn represents separate TMD cooling device. Cc: daniel.lezcano@linaro.org Cc: rafael@kernel.org Cc: andersson@kernel.org Cc: robh@kernel.org Signed-off-by: Bhupesh Sharma --- .../bindings/thermal/qcom,qmi-tmd-device.yaml | 78 +++++++++++++ .../bindings/thermal/qcom,tmd-device.yaml | 122 +++++++++++++++++++++ include/dt-bindings/thermal/qcom,tmd.h | 14 +++ 3 files changed, 214 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-tmd-device.yaml create mode 100644 Documentation/devicetree/bindings/thermal/qcom,tmd-device.yaml create mode 100644 include/dt-bindings/thermal/qcom,tmd.h diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-tmd-device.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-tmd-device.yaml new file mode 100644 index 000000000000..dfda5b611a93 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-tmd-device.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/thermal/qcom,qmi-tmd-device.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices. + +maintainers: + - Bhupesh Sharma + +description: + Qualcomm QMI based TMD cooling device(s) are used for various + mitigations for remote subsystem(s) including remote processor + mitigation, rail voltage restriction etc. + +properties: + $nodename: + const: qmi-tmd-devices + + compatible: + items: + - const: qcom,qmi-tmd-devices + + modem0: + $ref: /schemas/thermal/qcom,tmd-device.yaml# + + adsp: + $ref: /schemas/thermal/qcom,tmd-device.yaml# + + cdsp: + $ref: /schemas/thermal/qcom,tmd-device.yaml# + + slpi: + $ref: /schemas/thermal/qcom,tmd-device.yaml# + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + qmi-tmd-devices { + compatible = "qcom,qmi-tmd-devices"; + + modem0 { + qcom,instance-id = ; + + modem0_pa: tmd-device0 { + label = "pa"; + #cooling-cells = <2>; + }; + + modem0_proc: tmd-device1 { + label = "modem"; + #cooling-cells = <2>; + }; + + modem0_current: tmd-device2 { + label = "modem_current"; + #cooling-cells = <2>; + }; + + modem0_skin: tmd-device3 { + label = "modem_skin"; + #cooling-cells = <2>; + }; + + modem0_vdd: tmd-device4 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/thermal/qcom,tmd-device.yaml b/Documentation/devicetree/bindings/thermal/qcom,tmd-device.yaml new file mode 100644 index 000000000000..38ac62f03376 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom,tmd-device.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/thermal/qcom,tmd-device.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm thermal mitigation (TMD) cooling devices + +maintainers: + - Bhupesh Sharma + +description: + Qualcomm thermal mitigation (TMD) cooling devices. Each child node + represents one remote subsystem and each child of this subsystem in-turn + represents separate cooling devices. + +properties: + $nodename: + pattern: "^(modem|adsp|cdsp|slpi[0-9])?$" + + qcom,instance-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Remote subsystem QMI server instance id to be used for communicating with QMI. + +patternProperties: + "^tmd-device[0-9]?$": + type: object + description: + Subnodes indicating tmd cooling device of a specific category. + properties: + label: + maxItems: 1 + description: | + Remote subsystem device identifier. Acceptable device names - + "pa" -> for pa cooling device, + "cpuv_restriction_cold" -> for vdd restriction, + "cx_vdd_limit" -> for vdd limit, + "modem" -> for processor passive cooling device, + "modem_current" -> for current limiting device, + "modem_bw" -> for bus bandwidth limiting device, + "cpr_cold" -> for cpr restriction. + + "#cooling-cells": + const: 2 + + required: + - label + - "#cooling-cells" + + additionalProperties: false + +required: + - qcom,instance-id + +additionalProperties: false + +examples: + - | + #include + modem0 { + qcom,instance-id = ; + + modem0_pa: tmd-device0 { + label = "pa"; + #cooling-cells = <2>; + }; + + modem0_proc: tmd-device1 { + label = "modem"; + #cooling-cells = <2>; + }; + + modem0_current: tmd-device2 { + label = "modem_current"; + #cooling-cells = <2>; + }; + + modem0_skin: tmd-device3 { + label = "modem_skin"; + #cooling-cells = <2>; + }; + + modem0_vdd: tmd-device4 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + - | + #include + adsp { + qcom,instance-id = ; + + adsp_vdd: tmd-device1 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + - | + #include + cdsp { + qcom,instance-id = ; + + cdsp_vdd: tmd-device1 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + - | + #include + slpi { + qcom,instance-id = ; + + slpi_vdd: tmd-device1 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; diff --git a/include/dt-bindings/thermal/qcom,tmd.h b/include/dt-bindings/thermal/qcom,tmd.h new file mode 100644 index 000000000000..5ede4422e04e --- /dev/null +++ b/include/dt-bindings/thermal/qcom,tmd.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for the Qualcomm TMD instances. + */ + +#ifndef _DT_BINDINGS_THERMAL_QCOM_TMD_H_ +#define _DT_BINDINGS_THERMAL_QCOM_TMD_H_ + +#define MODEM0_INSTANCE_ID 0x0 +#define ADSP_INSTANCE_ID 0x1 +#define CDSP_INSTANCE_ID 0x43 +#define SLPI_INSTANCE_ID 0x53 + +#endif -- cgit v1.2.3 From 997035301430d1cdff9f6ddc57f2470bd43dd9a0 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Mon, 12 Sep 2022 12:46:29 +0530 Subject: MAINTAINERS: Add entry for Qualcomm Cooling Driver Add myself as the maintainer for the Qualcomm Cooling driver (aka Qualcomm Thermal Mitigation Device Driver). Cc: andersson@kernel.org Cc: daniel.lezcano@linaro.org Cc: rafael@kernel.org Signed-off-by: Bhupesh Sharma --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8d5bc223f305..7d300b591c79 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17372,6 +17372,16 @@ S: Maintained F: Documentation/devicetree/bindings/mtd/qcom,nandc.yaml F: drivers/mtd/nand/raw/qcom_nandc.c +QUALCOMM QMI COOLING DRIVER (THERMAL MITIGATION DEVICE DRIVER) +M: Bhupesh Sharma +L: linux-pm@vger.kernel.org +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/thermal/qcom,qmi-tmd-device.yaml +F: Documentation/devicetree/bindings/thermal/qcom,tmd-device.yaml +F: drivers/thermal/qcom/qmi_cooling/ +F: include/dt-bindings/thermal/qcom,tmd.h + QUALCOMM RMNET DRIVER M: Subash Abhinov Kasiviswanathan M: Sean Tranchetti -- cgit v1.2.3 From 550fa7caa7060f21308dd7ef386f0e4eb3221258 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Fri, 5 Aug 2022 12:01:53 +0530 Subject: arm64: dts: qcom: sm8150: Add qmi cooling device nodes Add qmi cooling nodes to sm8150 dts file. This node describes the various qmi thermal mitigation devices (tmd) which are available on remote processor subsystems. Cc: Rob Herring Cc: andersson@kernel.org Signed-off-by: Bhupesh Sharma --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index fd20096cfc6e..914236fd9ac2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include #include / { @@ -3333,6 +3334,67 @@ }; }; + qmi_tmd_devices: qmi-tmd-devices { + compatible = "qcom,qmi-tmd-devices"; + status = "disabled"; + + modem0 { + qcom,instance-id = ; + + modem0_pa: tmd-device0 { + label = "pa"; + #cooling-cells = <2>; + }; + + modem0_proc: tmd-device1 { + label = "modem"; + #cooling-cells = <2>; + }; + + modem0_current: tmd-device2 { + label = "modem_current"; + #cooling-cells = <2>; + }; + + modem0_skin: tmd-device3 { + label = "modem_skin"; + #cooling-cells = <2>; + }; + + modem0_vdd: tmd-device4 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = ; + + adsp_vdd: tmd-device0 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = ; + + cdsp_vdd: tmd-device0 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + slpi { + qcom,instance-id = ; + + slpi_vdd: tmd-device0 { + label = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + usb_1_hsphy: phy@88e2000 { compatible = "qcom,sm8150-usb-hs-phy", "qcom,usb-snps-hs-7nm-phy"; -- cgit v1.2.3 From bfac97a1262dca7f7da6f062b1080afd0665f974 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Sun, 11 Sep 2022 02:04:00 +0530 Subject: arm64: dts: qcom: sa8155p-adp: Enable qmi cooling device Enable qmi cooling devices for sa8155p adp platform. Cc: Rob Herring Cc: andersson@kernel.org Signed-off-by: Bhupesh Sharma --- arch/arm64/boot/dts/qcom/sa8155p-adp.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts index 459384ec8f23..90dbecb0d69d 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts @@ -368,6 +368,10 @@ }; }; +&qmi_tmd_devices { + status = "okay"; +}; + &qupv3_id_1 { status = "okay"; }; -- cgit v1.2.3 From de6bf8023d0abc1427c82bc2921cb466c613124e Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Tue, 30 Aug 2022 18:22:39 +0530 Subject: arm64: defconfig: Enable Qualcomm QMI cooling device driver Enable Qualcomm QMI cooling device driver which is available on several Qualcomm SoCs. Cc: andersson@kernel.org Cc: Catalin Marinas Cc: Will Deacon Cc: Arnd Bergmann Signed-off-by: Bhupesh Sharma --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 7790ee42c68a..e0f8ad6735ab 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -631,6 +631,7 @@ CONFIG_EXYNOS_THERMAL=y CONFIG_TEGRA_SOCTHERM=m CONFIG_TEGRA_BPMP_THERMAL=m CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_QCOM_QMI_COOLING=m CONFIG_QCOM_TSENS=y CONFIG_QCOM_SPMI_ADC_TM5=m CONFIG_QCOM_SPMI_TEMP_ALARM=m -- cgit v1.2.3 From 62b940c5424744eca98fe47a09e5fdde8b277d71 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 22 Sep 2022 02:13:12 +0530 Subject: arm64: dts: qcom: sa8155p-adp: Enable USB Device mode for emergency download port Enable USB-portB as 'device' in linux kernel. This port is also used as the USB emergency download port (for image download purposes) Signed-off-by: Bhupesh Sharma --- arch/arm64/boot/dts/qcom/sa8155p-adp.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts index 90dbecb0d69d..bc088db568a8 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts @@ -429,7 +429,7 @@ }; &usb_1_dwc3 { - dr_mode = "host"; + dr_mode = "peripheral"; pinctrl-names = "default"; pinctrl-0 = <&usb2phy_ac_en1_default>; @@ -443,7 +443,7 @@ }; &usb_1_qmpphy { - status = "disabled"; + status = "okay"; }; &usb_2 { -- cgit v1.2.3