@@ -12,13 +12,45 @@
#include <soc/tegra/bpmp.h>
#include <soc/tegra/bpmp-abi.h>
-#define EDVD_CORE_VOLT_FREQ(core) (0x20 + (core) * 0x4)
-#define EDVD_CORE_VOLT_FREQ_F_SHIFT 0
-#define EDVD_CORE_VOLT_FREQ_F_MASK 0xffff
-#define EDVD_CORE_VOLT_FREQ_V_SHIFT 16
+#define EDVD_OFFSET_A57(core) ((SZ_64K * 6) + (0x20 + (core) * 0x4))
+#define EDVD_OFFSET_DENVER(core) ((SZ_64K * 7) + (0x20 + (core) * 0x4))
+#define EDVD_CORE_VOLT_FREQ_F_SHIFT 0
+#define EDVD_CORE_VOLT_FREQ_F_MASK 0xffff
+#define EDVD_CORE_VOLT_FREQ_V_SHIFT 16
+
+struct tegra186_cpufreq_cpu {
+ unsigned int edvd_offset;
+};
+
+static const struct tegra186_cpufreq_cpu tegra186_cpus[] = {
+ /* CPU0 - A57 Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_A57(0)
+ },
+ /* CPU1 - Denver Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_DENVER(0)
+ },
+ /* CPU2 - Denver Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_DENVER(1)
+ },
+ /* CPU3 - A57 Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_A57(1)
+ },
+ /* CPU4 - A57 Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_A57(2)
+ },
+ /* CPU5 - A57 Cluster */
+ {
+ .edvd_offset = EDVD_OFFSET_A57(3)
+ },
+
+};
struct tegra186_cpufreq_cluster_info {
- unsigned long offset;
int cpus[4];
unsigned int bpmp_cluster_id;
};
@@ -27,13 +59,11 @@ struct tegra186_cpufreq_cluster_info {
static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = {
/* Denver cluster */
{
- .offset = SZ_64K * 7,
.cpus = { 1, 2, NO_CPU, NO_CPU },
.bpmp_cluster_id = 0,
},
/* A57 cluster */
{
- .offset = SZ_64K * 6,
.cpus = { 0, 3, 4, 5 },
.bpmp_cluster_id = 1,
},
@@ -51,6 +81,7 @@ struct tegra186_cpufreq_data {
size_t num_clusters;
struct tegra186_cpufreq_cluster *clusters;
+ const struct tegra186_cpufreq_cpu *cpus;
};
static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
@@ -71,13 +102,12 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
if (core == ARRAY_SIZE(info->cpus))
continue;
- policy->driver_data =
- data->regs + info->offset + EDVD_CORE_VOLT_FREQ(core);
policy->freq_table = cluster->table;
break;
}
policy->cpuinfo.transition_latency = 300 * 1000;
+ policy->driver_data = NULL;
return 0;
}
@@ -85,11 +115,12 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index)
{
+ struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
struct cpufreq_frequency_table *tbl = policy->freq_table + index;
- void __iomem *edvd_reg = policy->driver_data;
+ unsigned int edvd_offset = data->cpus[policy->cpu].edvd_offset;
u32 edvd_val = tbl->driver_data;
- writel(edvd_val, edvd_reg);
+ writel(edvd_val, data->regs + edvd_offset);
return 0;
}
@@ -98,16 +129,15 @@ static unsigned int tegra186_cpufreq_get(unsigned int cpu)
{
struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
struct cpufreq_policy *policy;
- void __iomem *edvd_reg;
- unsigned int i, freq = 0;
+ unsigned int i, edvd_offset, freq = 0;
u32 ndiv;
policy = cpufreq_cpu_get(cpu);
if (!policy)
return 0;
- edvd_reg = policy->driver_data;
- ndiv = readl(edvd_reg) & EDVD_CORE_VOLT_FREQ_F_MASK;
+ edvd_offset = data->cpus[policy->cpu].edvd_offset;
+ ndiv = readl(data->regs + edvd_offset) & EDVD_CORE_VOLT_FREQ_F_MASK;
for (i = 0; i < data->num_clusters; i++) {
struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
@@ -240,6 +270,7 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
return -ENOMEM;
data->num_clusters = ARRAY_SIZE(tegra186_clusters);
+ data->cpus = tegra186_cpus;
bpmp = tegra_bpmp_get(&pdev->dev);
if (IS_ERR(bpmp))
Sparse warns that the incorrect type is being assigned to the CPUFREQ driver_data variable in the Tegra186 CPUFREQ driver. The Tegra186 CPUFREQ driver is assigned a type of 'void __iomem *' to a pointer of type 'void *' ... drivers/cpufreq/tegra186-cpufreq.c:72:37: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected void *driver_data @@ got void [noderef] __iomem * @@ ... drivers/cpufreq/tegra186-cpufreq.c:87:40: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected void [noderef] __iomem *edvd_reg @@ got void *driver_data @@ The Tegra186 CPUFREQ driver is using the policy->driver_data variable to store and iomem pointer to a Tegra186 CPU register that is used to set the clock speed for the CPU. This is not necessary because the register base address is already stored in the driver data and the offset of the register for each CPU is static. Therefore, fix this by adding a new structure with the register offsets for each CPU and store this in the main driver data structure along with the register base address. Please note that a new structure has been added for storing the register offsets rather than a simple array, because this will permit further clean-ups and simplification of the driver. Signed-off-by: Jon Hunter <jonathanh@nvidia.com> --- drivers/cpufreq/tegra186-cpufreq.c | 61 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 15 deletions(-)