Skip to content

Commit

Permalink
cpufreq: tegra186: Fix get frequency callback
Browse files Browse the repository at this point in the history
Commit b89c01c ("cpufreq: tegra186: Fix initial frequency")
implemented the CPUFREQ 'get' callback to determine the current
operating frequency for each CPU. This implementation used a simple
looked up to determine the current operating frequency. The problem
with this is that frequency table for different Tegra186 devices may
vary and so the default boot frequency for Tegra186 device may or may
not be present in the frequency table. If the default boot frequency is
not present in the frequency table, this causes the function
tegra186_cpufreq_get() to return 0 and in turn causes cpufreq_online()
to fail which prevents CPUFREQ from working.

Fix this by always calculating the CPU frequency based upon the current
'ndiv' setting for the CPU. Note that the CPU frequency for Tegra186 is
calculated by reading the current 'ndiv' setting, multiplying by the
CPU reference clock and dividing by a constant divisor.

Fixes: b89c01c ("cpufreq: tegra186: Fix initial frequency")

Signed-off-by: Jon Hunter <[email protected]>
Signed-off-by: Viresh Kumar <[email protected]>
  • Loading branch information
jonhunter authored and vireshk committed Nov 17, 2020
1 parent 3650b22 commit e010d1d
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions drivers/cpufreq/tegra186-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = {
struct tegra186_cpufreq_cluster {
const struct tegra186_cpufreq_cluster_info *info;
struct cpufreq_frequency_table *table;
u32 ref_clk_khz;
u32 div;
};

struct tegra186_cpufreq_data {
Expand Down Expand Up @@ -94,7 +96,7 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,

static unsigned int tegra186_cpufreq_get(unsigned int cpu)
{
struct cpufreq_frequency_table *tbl;
struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
struct cpufreq_policy *policy;
void __iomem *edvd_reg;
unsigned int i, freq = 0;
Expand All @@ -104,17 +106,23 @@ static unsigned int tegra186_cpufreq_get(unsigned int cpu)
if (!policy)
return 0;

tbl = policy->freq_table;
edvd_reg = policy->driver_data;
ndiv = readl(edvd_reg) & EDVD_CORE_VOLT_FREQ_F_MASK;

for (i = 0; tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
if ((tbl[i].driver_data & EDVD_CORE_VOLT_FREQ_F_MASK) == ndiv) {
freq = tbl[i].frequency;
break;
for (i = 0; i < data->num_clusters; i++) {
struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
int core;

for (core = 0; core < ARRAY_SIZE(cluster->info->cpus); core++) {
if (cluster->info->cpus[core] != policy->cpu)
continue;

freq = (cluster->ref_clk_khz * ndiv) / cluster->div;
goto out;
}
}

out:
cpufreq_cpu_put(policy);

return freq;
Expand All @@ -133,7 +141,7 @@ static struct cpufreq_driver tegra186_cpufreq_driver = {

static struct cpufreq_frequency_table *init_vhint_table(
struct platform_device *pdev, struct tegra_bpmp *bpmp,
unsigned int cluster_id)
struct tegra186_cpufreq_cluster *cluster)
{
struct cpufreq_frequency_table *table;
struct mrq_cpu_vhint_request req;
Expand All @@ -152,7 +160,7 @@ static struct cpufreq_frequency_table *init_vhint_table(

memset(&req, 0, sizeof(req));
req.addr = phys;
req.cluster_id = cluster_id;
req.cluster_id = cluster->info->bpmp_cluster_id;

memset(&msg, 0, sizeof(msg));
msg.mrq = MRQ_CPU_VHINT;
Expand Down Expand Up @@ -185,6 +193,9 @@ static struct cpufreq_frequency_table *init_vhint_table(
goto free;
}

cluster->ref_clk_khz = data->ref_clk_hz / 1000;
cluster->div = data->pdiv * data->mdiv;

for (i = data->vfloor, j = 0; i <= data->vceil; i++) {
struct cpufreq_frequency_table *point;
u16 ndiv = data->ndiv[i];
Expand All @@ -202,8 +213,7 @@ static struct cpufreq_frequency_table *init_vhint_table(

point = &table[j++];
point->driver_data = edvd_val;
point->frequency = data->ref_clk_hz * ndiv / data->pdiv /
data->mdiv / 1000;
point->frequency = (cluster->ref_clk_khz * ndiv) / cluster->div;
}

table[j].frequency = CPUFREQ_TABLE_END;
Expand Down Expand Up @@ -245,8 +255,7 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];

cluster->info = &tegra186_clusters[i];
cluster->table = init_vhint_table(
pdev, bpmp, cluster->info->bpmp_cluster_id);
cluster->table = init_vhint_table(pdev, bpmp, cluster);
if (IS_ERR(cluster->table)) {
err = PTR_ERR(cluster->table);
goto put_bpmp;
Expand Down

0 comments on commit e010d1d

Please sign in to comment.