Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a407fafc authored by Taniya Das's avatar Taniya Das
Browse files

cpufreq: qcom: cpufreq-hw: Add support for SDPM rail voting



Add support for shared digital rail vote for MX/CX when there is a
transition in the frequency of the CPU. Also add the suspend/resume
callbacks where the driver will vote for the minimum CPU frequency
during suspend and restore back once back in resume.

Change-Id: I26a5f65b0001551bd09c28902810c72fa9c9719a
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
parent 0a6012ab
Loading
Loading
Loading
Loading
+67 −6
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/bitfield.h>
@@ -31,6 +31,7 @@
#define GT_IRQ_STATUS			BIT(2)
#define MAX_FN_SIZE			20
#define LIMITS_POLLING_DELAY_MS		10
#define MAX_ROW				2

#define CYCLE_CNTR_OFFSET(c, m, acc_count)				\
			(acc_count ? ((c - cpumask_first(m) + 1) * 4) : 0)
@@ -60,6 +61,8 @@ struct cpufreq_qcom {
	struct cpufreq_frequency_table *table;
	void __iomem *base;
	void __iomem *pdmem_base;
	void __iomem **sdpm_base;
	int sdpm_base_count;
	cpumask_t related_cpus;
	unsigned long dcvsh_freq_limit;
	struct delayed_work freq_poll_work;
@@ -236,19 +239,25 @@ static int
qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
			     unsigned int index)
{
	struct cpufreq_qcom *c;
	struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu];
	unsigned long freq = policy->freq_table[index].frequency;
	int i;

	if (perf_lock_support) {
		c = qcom_freq_domain_map[policy->cpu];
		if (c->pdmem_base)
			writel_relaxed(index, c->pdmem_base);
	}

	for (i = 0; i < c->sdpm_base_count && freq > policy->cur; i++)
		writel_relaxed(freq / 1000, c->sdpm_base[i]);

	writel_relaxed(index, policy->driver_data + offsets[REG_PERF_STATE]);
	arch_set_freq_scale(policy->related_cpus,
			    policy->freq_table[index].frequency,
	arch_set_freq_scale(policy->related_cpus, freq,
			    policy->cpuinfo.max_freq);

	for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++)
		writel_relaxed(freq / 1000, c->sdpm_base[i]);

	return 0;
}

@@ -379,6 +388,30 @@ static void qcom_cpufreq_ready(struct cpufreq_policy *policy)
	of_node_put(np);
}

static int qcom_cpufreq_hw_suspend(struct cpufreq_policy *policy)
{
	struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu];
	unsigned long freq = policy->freq_table[0].frequency;
	int i;

	for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++)
		writel_relaxed(freq / 1000, c->sdpm_base[i]);

	return 0;
}

static int qcom_cpufreq_hw_resume(struct cpufreq_policy *policy)
{
	struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu];
	unsigned long freq = policy->cur;
	int i;

	for (i = 0; i < c->sdpm_base_count; i++)
		writel_relaxed(freq / 1000, c->sdpm_base[i]);

	return 0;
}

static struct cpufreq_driver cpufreq_qcom_hw_driver = {
	.flags		= CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
			  CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
@@ -391,6 +424,8 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
	.attr		= qcom_cpufreq_hw_attr,
	.boost_enabled	= true,
	.ready		= qcom_cpufreq_ready,
	.suspend	= qcom_cpufreq_hw_suspend,
	.resume		= qcom_cpufreq_hw_resume,
};

static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
@@ -486,7 +521,8 @@ static int qcom_cpu_resources_init(struct platform_device *pdev,
	struct device *dev = &pdev->dev;
	void __iomem *base;
	char pdmem_name[MAX_FN_SIZE] = {};
	int ret, cpu_r;
	char sdpm_name[MAX_FN_SIZE] = {};
	int ret, cpu_r, len, reg, size, i, j;

	c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
	if (!c)
@@ -543,6 +579,31 @@ static int qcom_cpu_resources_init(struct platform_device *pdev,
			c->pdmem_base = base;
	}

	snprintf(sdpm_name, sizeof(sdpm_name), "qcom,sdpm-cx-mx-%d", index);
	len = of_property_count_u32_elems(dev->of_node, sdpm_name);
	if (len > 0) {
		c->sdpm_base_count = len / MAX_ROW;
		c->sdpm_base = devm_kcalloc(dev, c->sdpm_base_count,
					sizeof(*c->sdpm_base), GFP_KERNEL);
		if (!c->sdpm_base)
			return -ENOMEM;

		for (i = 0, j = 0; i < c->sdpm_base_count; i++, j += 2) {
			of_property_read_u32_index(dev->of_node, sdpm_name,
								j, &reg);
			of_property_read_u32_index(dev->of_node, sdpm_name,
								j + 1, &size);
			base = devm_ioremap(dev, reg, size);
			if (IS_ERR(base)) {
				dev_err(dev, "Failed to map base %d domain-%d\n",
						i, index);
				return PTR_ERR(base);
			}

			c->sdpm_base[i] = base;
		}
	}

	if (of_find_property(dev->of_node, "interrupts", NULL)) {
		c->dcvsh_irq = of_irq_get(dev->of_node, index);
		if (c->dcvsh_irq > 0) {