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

Commit 9879ab03 authored by Danny Lin's avatar Danny Lin Committed by Akshay Kakatkar
Browse files

cpufreq: qcom-hw: Allow overriding CPU frequency tables in DT



Sometimes, it may be desirable to use CPU frequency tables different
from the ones in the hardware's LUTs, e.g. to remove inefficient
frequencies. This commit adds support for overriding each CPU's
frequency table with a list of allowed frequencies defined in the
cpufreq driver's DT node.

Signed-off-by: default avatarDanny Lin <danny@kdrag0n.dev>
parent f07b749a
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -190,5 +190,35 @@ DCVS state together.


		#freq-domains-cells = <2>
		#freq-domains-cells = <2>


		qcom,cpufreq-table-0 =
			< 300000>,
			< 576000>,
			< 614400>,
			< 864000>,
			<1075200>,
			<1363200>,
			<1516800>,
			<1651200>,
			<1804800>;

		qcom,cpufreq-table-1 =
			< 652800>,
			< 940800>,
			<1152000>,
			<1478400>,
			<1728000>,
			<1900800>,
			<2092800>,
			<2208000>;

		qcom,cpufreq-table-2 =
			< 806400>,
			<1094400>,
			<1401600>,
			<1766400>,
			<1996800>,
			<2188800>,
			<2304000>,
			<2400000>;
	};
	};
}
}
+62 −25
Original line number Original line Diff line number Diff line
@@ -491,14 +491,33 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
	.ready		= qcom_cpufreq_ready,
	.ready		= qcom_cpufreq_ready,
};
};


static bool of_find_freq(u32 *of_table, int of_len, long frequency)
{
	int i;

	if (!of_table)
		return true;

	for (i = 0; i < of_len; i++) {
		if (frequency == of_table[i])
			return true;
	}

	return false;
}

static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
				    struct cpufreq_qcom *c)
				    struct cpufreq_qcom *c,
				    int domain_index)
{
{
	struct device *dev = &pdev->dev, *cpu_dev;
	struct device *dev = &pdev->dev, *cpu_dev;
	void __iomem *base_freq, *base_volt;
	void __iomem *base_freq, *base_volt;
	u32 data, src, lval, i, core_count, prev_cc, prev_freq, cur_freq, volt;
	u32 data, src, lval, i, core_count, prev_cc, prev_freq, cur_freq, volt;
	u32 vc;
	u32 vc;
	unsigned long cpu;
	unsigned long cpu;
	int ret, of_len;
	u32 *of_table = NULL;
	char tbl_name[] = "qcom,cpufreq-table-##";


	c->table = devm_kcalloc(dev, lut_max_entries + 1,
	c->table = devm_kcalloc(dev, lut_max_entries + 1,
				sizeof(*c->table), GFP_KERNEL);
				sizeof(*c->table), GFP_KERNEL);
@@ -506,6 +525,25 @@ static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
		return -ENOMEM;
		return -ENOMEM;


	spin_lock_init(&c->skip_data.lock);
	spin_lock_init(&c->skip_data.lock);

	snprintf(tbl_name, sizeof(tbl_name), "qcom,cpufreq-table-%d",
		 domain_index);
	if (of_find_property(dev->of_node, tbl_name, &of_len) && of_len > 0) {
		of_len /= sizeof(*of_table);

		of_table = devm_kcalloc(dev, of_len, sizeof(*of_table),
					GFP_KERNEL);
		if (!of_table) {
			ret = -ENOMEM;
			goto err_cpufreq_table;
		}

		ret = of_property_read_u32_array(dev->of_node, tbl_name,
						 of_table, of_len);
		if (ret)
			goto err_of_table;
	}

	base_freq = c->reg_bases[REG_FREQ_LUT_TABLE];
	base_freq = c->reg_bases[REG_FREQ_LUT_TABLE];
	base_volt = c->reg_bases[REG_VOLT_LUT_TABLE];
	base_volt = c->reg_bases[REG_VOLT_LUT_TABLE];


@@ -531,39 +569,29 @@ static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
		dev_dbg(dev, "index=%d freq=%d, core_count %d\n",
		dev_dbg(dev, "index=%d freq=%d, core_count %d\n",
			i, c->table[i].frequency, core_count);
			i, c->table[i].frequency, core_count);


		if (core_count != c->max_cores) {
		if (!of_find_freq(of_table, of_len, c->table[i].frequency)) {
			if (core_count == (c->max_cores - 1)) {
			c->table[i].frequency = CPUFREQ_ENTRY_INVALID;
				c->skip_data.skip = true;
			cur_freq = CPUFREQ_ENTRY_INVALID;
				c->skip_data.high_temp_index = i;
				c->skip_data.freq = cur_freq;
				c->skip_data.cc = core_count;
				c->skip_data.final_index = i + 1;
				c->skip_data.low_temp_index = i + 1;
				c->skip_data.prev_freq =
						c->table[i-1].frequency;
				c->skip_data.prev_index = i - 1;
				c->skip_data.prev_cc = prev_cc;
		} else {
		} else {
			if (core_count != c->max_cores) {
				cur_freq = CPUFREQ_ENTRY_INVALID;
				cur_freq = CPUFREQ_ENTRY_INVALID;
				c->table[i].flags = CPUFREQ_BOOST_FREQ;
				c->table[i].flags = CPUFREQ_BOOST_FREQ;
			}
			}
		}


			/*
			/*
		 * Two of the same frequencies with the same core counts means
			 * Two of the same frequencies with the same core counts
		 * end of table.
			 * means end of table.
			*/
			*/
			if (i > 0 && c->table[i - 1].frequency ==
			if (i > 0 && c->table[i - 1].frequency ==
				c->table[i].frequency) {
			c->table[i].frequency && prev_cc == core_count) {
			if (prev_cc == core_count) {
				struct cpufreq_frequency_table *prev =
				struct cpufreq_frequency_table *prev =
					&c->table[i - 1];
					&c->table[i - 1];


				if (prev_freq == CPUFREQ_ENTRY_INVALID)
				if (prev_freq == CPUFREQ_ENTRY_INVALID)
					prev->flags = CPUFREQ_BOOST_FREQ;
					prev->flags = CPUFREQ_BOOST_FREQ;
			}
				break;
				break;
			}
			}
		}


		prev_cc = core_count;
		prev_cc = core_count;
		prev_freq = cur_freq;
		prev_freq = cur_freq;
@@ -591,7 +619,16 @@ static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
				c->skip_data.prev_cc);
				c->skip_data.prev_cc);
	}
	}


	if (of_table)
		devm_kfree(dev, of_table);

	return 0;
	return 0;

err_of_table:
	devm_kfree(dev, of_table);
err_cpufreq_table:
	devm_kfree(dev, c->table);
	return ret;
}
}


static int qcom_get_related_cpus(int index, struct cpumask *m)
static int qcom_get_related_cpus(int index, struct cpumask *m)
@@ -675,7 +712,7 @@ static int qcom_cpu_resources_init(struct platform_device *pdev,
	c->xo_rate = xo_rate;
	c->xo_rate = xo_rate;
	c->cpu_hw_rate = cpu_hw_rate;
	c->cpu_hw_rate = cpu_hw_rate;


	ret = qcom_cpufreq_hw_read_lut(pdev, c);
	ret = qcom_cpufreq_hw_read_lut(pdev, c, index);
	if (ret) {
	if (ret) {
		dev_err(dev, "Domain-%d failed to read LUT\n", index);
		dev_err(dev, "Domain-%d failed to read LUT\n", index);
		return ret;
		return ret;