Commit 6cc4bcce authored by Brandon Cheo Fusi's avatar Brandon Cheo Fusi Committed by Viresh Kumar

cpufreq: sun50i: Refactor speed bin decoding

Make converting the speed bin value into a speed grade generic and
determined by a platform specific callback. Also change the prototypes
involved to encode the speed bin directly in the return value.

This allows to extend the driver more easily to support more SoCs.
Signed-off-by: default avatarBrandon Cheo Fusi <fusibrandon13@gmail.com>
[Andre: merge output into return value]
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
Reviewed-by: default avatarJernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
parent 83d4e044
...@@ -25,19 +25,52 @@ ...@@ -25,19 +25,52 @@
static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev; static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
struct sunxi_cpufreq_data {
u32 (*efuse_xlate)(u32 speedbin);
};
static u32 sun50i_h6_efuse_xlate(u32 speedbin)
{
u32 efuse_value;
efuse_value = (speedbin >> NVMEM_SHIFT) & NVMEM_MASK;
/*
* We treat unexpected efuse values as if the SoC was from
* the slowest bin. Expected efuse values are 1-3, slowest
* to fastest.
*/
if (efuse_value >= 1 && efuse_value <= 3)
return efuse_value - 1;
else
return 0;
}
static struct sunxi_cpufreq_data sun50i_h6_cpufreq_data = {
.efuse_xlate = sun50i_h6_efuse_xlate,
};
static const struct of_device_id cpu_opp_match_list[] = {
{ .compatible = "allwinner,sun50i-h6-operating-points",
.data = &sun50i_h6_cpufreq_data,
},
{}
};
/** /**
* sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value * sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
* @versions: Set to the value parsed from efuse
* *
* Returns 0 if success. * Returns non-negative speed bin index on success, a negative error
* value otherwise.
*/ */
static int sun50i_cpufreq_get_efuse(u32 *versions) static int sun50i_cpufreq_get_efuse(void)
{ {
const struct sunxi_cpufreq_data *opp_data;
struct nvmem_cell *speedbin_nvmem; struct nvmem_cell *speedbin_nvmem;
const struct of_device_id *match;
struct device_node *np; struct device_node *np;
struct device *cpu_dev; struct device *cpu_dev;
u32 *speedbin, efuse_value; u32 *speedbin;
size_t len;
int ret; int ret;
cpu_dev = get_cpu_device(0); cpu_dev = get_cpu_device(0);
...@@ -48,12 +81,12 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) ...@@ -48,12 +81,12 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
if (!np) if (!np)
return -ENOENT; return -ENOENT;
ret = of_device_is_compatible(np, match = of_match_node(cpu_opp_match_list, np);
"allwinner,sun50i-h6-operating-points"); if (!match) {
if (!ret) {
of_node_put(np); of_node_put(np);
return -ENOENT; return -ENOENT;
} }
opp_data = match->data;
speedbin_nvmem = of_nvmem_cell_get(np, NULL); speedbin_nvmem = of_nvmem_cell_get(np, NULL);
of_node_put(np); of_node_put(np);
...@@ -61,25 +94,16 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) ...@@ -61,25 +94,16 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
"Could not get nvmem cell\n"); "Could not get nvmem cell\n");
speedbin = nvmem_cell_read(speedbin_nvmem, &len); speedbin = nvmem_cell_read(speedbin_nvmem, NULL);
nvmem_cell_put(speedbin_nvmem); nvmem_cell_put(speedbin_nvmem);
if (IS_ERR(speedbin)) if (IS_ERR(speedbin))
return PTR_ERR(speedbin); return PTR_ERR(speedbin);
efuse_value = (*speedbin >> NVMEM_SHIFT) & NVMEM_MASK; ret = opp_data->efuse_xlate(*speedbin);
/*
* We treat unexpected efuse values as if the SoC was from
* the slowest bin. Expected efuse values are 1-3, slowest
* to fastest.
*/
if (efuse_value >= 1 && efuse_value <= 3)
*versions = efuse_value - 1;
else
*versions = 0;
kfree(speedbin); kfree(speedbin);
return 0;
return ret;
}; };
static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
...@@ -87,7 +111,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) ...@@ -87,7 +111,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
int *opp_tokens; int *opp_tokens;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
unsigned int cpu; unsigned int cpu;
u32 speed = 0; int speed;
int ret; int ret;
opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens), opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens),
...@@ -95,10 +119,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) ...@@ -95,10 +119,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
if (!opp_tokens) if (!opp_tokens)
return -ENOMEM; return -ENOMEM;
ret = sun50i_cpufreq_get_efuse(&speed); speed = sun50i_cpufreq_get_efuse();
if (ret) { if (speed < 0) {
kfree(opp_tokens); kfree(opp_tokens);
return ret; return speed;
} }
snprintf(name, MAX_NAME_LEN, "speed%d", speed); snprintf(name, MAX_NAME_LEN, "speed%d", speed);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment