mirror of
https://github.com/lingble/meta-tegra.git
synced 2025-10-29 11:32:30 +00:00
202 lines
6.6 KiB
Diff
202 lines
6.6 KiB
Diff
From 72159b110a95f50887784dbb7771cbbcefde7576 Mon Sep 17 00:00:00 2001
|
|
From: Sumit Gupta <sumitg@nvidia.com>
|
|
Date: Wed, 4 Oct 2023 19:35:36 +0530
|
|
Subject: [PATCH 3/9] cpufreq: tegra194: save CPU data to avoid repeated SMP
|
|
calls
|
|
|
|
Currently, we make SMP call on every frequency set request to get the
|
|
physical 'CPU ID' and 'CLUSTER ID' for the target CPU. This change
|
|
optimizes the repeated calls by storing the physical IDs and the per
|
|
core frequency register offset for all CPUs during boot. Later this
|
|
info is used directly when required to set the frequency or read it
|
|
from ACTMON counters.
|
|
|
|
Upstream-Status: Pending
|
|
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
|
|
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
|
|
---
|
|
drivers/cpufreq/tegra194-cpufreq.c | 79 +++++++++++++++++++-----------
|
|
1 file changed, 51 insertions(+), 28 deletions(-)
|
|
|
|
diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c
|
|
index 386aed3637b4..f6a8e6cf6d94 100644
|
|
--- a/drivers/cpufreq/tegra194-cpufreq.c
|
|
+++ b/drivers/cpufreq/tegra194-cpufreq.c
|
|
@@ -39,6 +39,12 @@
|
|
/* cpufreq transisition latency */
|
|
#define TEGRA_CPUFREQ_TRANSITION_LATENCY (300 * 1000) /* unit in nanoseconds */
|
|
|
|
+struct tegra_cpu_data {
|
|
+ u32 cpuid;
|
|
+ u32 clusterid;
|
|
+ void __iomem *freq_core_reg;
|
|
+};
|
|
+
|
|
struct tegra_cpu_ctr {
|
|
u32 cpu;
|
|
u32 coreclk_cnt, last_coreclk_cnt;
|
|
@@ -69,6 +75,7 @@ struct tegra194_cpufreq_data {
|
|
struct cpufreq_frequency_table **bpmp_luts;
|
|
const struct tegra_cpufreq_soc *soc;
|
|
bool icc_dram_bw_scaling;
|
|
+ struct tegra_cpu_data *cpu_data;
|
|
};
|
|
|
|
static struct workqueue_struct *read_counters_wq;
|
|
@@ -116,14 +123,8 @@ static void tegra234_get_cpu_cluster_id(u32 cpu, u32 *cpuid, u32 *clusterid)
|
|
static int tegra234_get_cpu_ndiv(u32 cpu, u32 cpuid, u32 clusterid, u64 *ndiv)
|
|
{
|
|
struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
|
|
- void __iomem *freq_core_reg;
|
|
- u64 mpidr_id;
|
|
-
|
|
- /* use physical id to get address of per core frequency register */
|
|
- mpidr_id = (clusterid * data->soc->maxcpus_per_cluster) + cpuid;
|
|
- freq_core_reg = SCRATCH_FREQ_CORE_REG(data, mpidr_id);
|
|
|
|
- *ndiv = readl(freq_core_reg) & NDIV_MASK;
|
|
+ *ndiv = readl(data->cpu_data[cpu].freq_core_reg) & NDIV_MASK;
|
|
|
|
return 0;
|
|
}
|
|
@@ -131,19 +132,10 @@ static int tegra234_get_cpu_ndiv(u32 cpu, u32 cpuid, u32 clusterid, u64 *ndiv)
|
|
static void tegra234_set_cpu_ndiv(struct cpufreq_policy *policy, u64 ndiv)
|
|
{
|
|
struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
|
|
- void __iomem *freq_core_reg;
|
|
- u32 cpu, cpuid, clusterid;
|
|
- u64 mpidr_id;
|
|
-
|
|
- for_each_cpu_and(cpu, policy->cpus, cpu_online_mask) {
|
|
- data->soc->ops->get_cpu_cluster_id(cpu, &cpuid, &clusterid);
|
|
-
|
|
- /* use physical id to get address of per core frequency register */
|
|
- mpidr_id = (clusterid * data->soc->maxcpus_per_cluster) + cpuid;
|
|
- freq_core_reg = SCRATCH_FREQ_CORE_REG(data, mpidr_id);
|
|
+ u32 cpu;
|
|
|
|
- writel(ndiv, freq_core_reg);
|
|
- }
|
|
+ for_each_cpu_and(cpu, policy->cpus, cpu_online_mask)
|
|
+ writel(ndiv, data->cpu_data[cpu].freq_core_reg);
|
|
}
|
|
|
|
/*
|
|
@@ -157,11 +149,10 @@ static void tegra234_read_counters(struct tegra_cpu_ctr *c)
|
|
{
|
|
struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
|
|
void __iomem *actmon_reg;
|
|
- u32 cpuid, clusterid;
|
|
u64 val;
|
|
|
|
- data->soc->ops->get_cpu_cluster_id(c->cpu, &cpuid, &clusterid);
|
|
- actmon_reg = CORE_ACTMON_CNTR_REG(data, clusterid, cpuid);
|
|
+ actmon_reg = CORE_ACTMON_CNTR_REG(data, data->cpu_data[c->cpu].clusterid,
|
|
+ data->cpu_data[c->cpu].cpuid);
|
|
|
|
val = readq(actmon_reg);
|
|
c->last_refclk_cnt = upper_32_bits(val);
|
|
@@ -357,19 +348,17 @@ static void tegra194_set_cpu_ndiv(struct cpufreq_policy *policy, u64 ndiv)
|
|
static unsigned int tegra194_get_speed(u32 cpu)
|
|
{
|
|
struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
|
|
+ u32 clusterid = data->cpu_data[cpu].clusterid;
|
|
struct cpufreq_frequency_table *pos;
|
|
- u32 cpuid, clusterid;
|
|
unsigned int rate;
|
|
u64 ndiv;
|
|
int ret;
|
|
|
|
- data->soc->ops->get_cpu_cluster_id(cpu, &cpuid, &clusterid);
|
|
-
|
|
/* reconstruct actual cpu freq using counters */
|
|
rate = tegra194_calculate_speed(cpu);
|
|
|
|
/* get last written ndiv value */
|
|
- ret = data->soc->ops->get_cpu_ndiv(cpu, cpuid, clusterid, &ndiv);
|
|
+ ret = data->soc->ops->get_cpu_ndiv(cpu, data->cpu_data[cpu].cpuid, clusterid, &ndiv);
|
|
if (WARN_ON_ONCE(ret))
|
|
return rate;
|
|
|
|
@@ -475,13 +464,12 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
|
|
{
|
|
struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
|
|
int maxcpus_per_cluster = data->soc->maxcpus_per_cluster;
|
|
+ u32 clusterid = data->cpu_data[policy->cpu].clusterid;
|
|
struct cpufreq_frequency_table *freq_table;
|
|
struct cpufreq_frequency_table *bpmp_lut;
|
|
u32 start_cpu, cpu;
|
|
- u32 clusterid;
|
|
int ret;
|
|
|
|
- data->soc->ops->get_cpu_cluster_id(policy->cpu, NULL, &clusterid);
|
|
if (clusterid >= data->soc->num_clusters || !data->bpmp_luts[clusterid])
|
|
return -EINVAL;
|
|
|
|
@@ -659,6 +647,28 @@ tegra_cpufreq_bpmp_read_lut(struct platform_device *pdev, struct tegra_bpmp *bpm
|
|
return freq_table;
|
|
}
|
|
|
|
+static int tegra194_cpufreq_store_physids(unsigned int cpu, struct tegra194_cpufreq_data *data)
|
|
+{
|
|
+ int num_cpus = data->soc->maxcpus_per_cluster * data->soc->num_clusters;
|
|
+ u32 cpuid, clusterid;
|
|
+ u64 mpidr_id;
|
|
+
|
|
+ if (cpu > (num_cpus - 1)) {
|
|
+ pr_err("cpufreq: wrong num of cpus or clusters in soc data\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ data->soc->ops->get_cpu_cluster_id(cpu, &cpuid, &clusterid);
|
|
+
|
|
+ mpidr_id = (clusterid * data->soc->maxcpus_per_cluster) + cpuid;
|
|
+
|
|
+ data->cpu_data[cpu].cpuid = cpuid;
|
|
+ data->cpu_data[cpu].clusterid = clusterid;
|
|
+ data->cpu_data[cpu].freq_core_reg = SCRATCH_FREQ_CORE_REG(data, mpidr_id);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int tegra194_cpufreq_probe(struct platform_device *pdev)
|
|
{
|
|
const struct tegra_cpufreq_soc *soc;
|
|
@@ -666,6 +676,7 @@ static int tegra194_cpufreq_probe(struct platform_device *pdev)
|
|
struct tegra_bpmp *bpmp;
|
|
struct device *cpu_dev;
|
|
int err, i;
|
|
+ u32 cpu;
|
|
|
|
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
|
if (!data)
|
|
@@ -692,6 +703,12 @@ static int tegra194_cpufreq_probe(struct platform_device *pdev)
|
|
return PTR_ERR(data->regs);
|
|
}
|
|
|
|
+ data->cpu_data = devm_kcalloc(&pdev->dev, data->soc->num_clusters *
|
|
+ data->soc->maxcpus_per_cluster,
|
|
+ sizeof(*data->cpu_data), GFP_KERNEL);
|
|
+ if (!data->cpu_data)
|
|
+ return -ENOMEM;
|
|
+
|
|
platform_set_drvdata(pdev, data);
|
|
|
|
bpmp = tegra_bpmp_get(&pdev->dev);
|
|
@@ -713,6 +730,12 @@ static int tegra194_cpufreq_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
|
|
+ for_each_possible_cpu(cpu) {
|
|
+ err = tegra194_cpufreq_store_physids(cpu, data);
|
|
+ if (err)
|
|
+ goto err_free_res;
|
|
+ }
|
|
+
|
|
tegra194_cpufreq_driver.driver_data = data;
|
|
|
|
/* Check for optional OPPv2 and interconnect paths on CPU0 to enable ICC scaling */
|
|
--
|
|
2.25.1
|
|
|