/* 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;
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;
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;
}
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);
}
/*
{
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);
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;
{
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;
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;
struct tegra_bpmp *bpmp;
struct device *cpu_dev;
int err, i;
+ u32 cpu;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
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);
}
}
+ 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 */