Message ID | 20240326114743.712167-5-andre.przywara@arm.com |
---|---|
State | Superseded |
Headers | show |
Series | cpufreq: sun50i: Add Allwinner H616 support | expand |
Dne torek, 26. marec 2024 ob 12:47:39 CET je Andre Przywara napisal(a): > From: Brandon Cheo Fusi <fusibrandon13@gmail.com> > > 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: Brandon Cheo Fusi <fusibrandon13@gmail.com> > [Andre: merge output into return value] > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > --- > drivers/cpufreq/sun50i-cpufreq-nvmem.c | 74 +++++++++++++++++--------- > 1 file changed, 49 insertions(+), 25 deletions(-) > > diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c > index 32a9c88f8ff6d..7b44f3b13e7d2 100644 > --- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c > +++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c > @@ -25,19 +25,52 @@ > > 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 > - * @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) > { > struct nvmem_cell *speedbin_nvmem; > struct device_node *np; > struct device *cpu_dev; > - u32 *speedbin, efuse_value; > - size_t len; > + const struct of_device_id *match; > + const struct sunxi_cpufreq_data *opp_data; > + u32 *speedbin; nit: reverse christmas tree Other than that, Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Best regards, Jernej > int ret; > > cpu_dev = get_cpu_device(0); > @@ -48,12 +81,12 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) > if (!np) > return -ENOENT; > > - ret = of_device_is_compatible(np, > - "allwinner,sun50i-h6-operating-points"); > - if (!ret) { > + match = of_match_node(cpu_opp_match_list, np); > + if (!match) { > of_node_put(np); > return -ENOENT; > } > + opp_data = match->data; > > speedbin_nvmem = of_nvmem_cell_get(np, NULL); > of_node_put(np); > @@ -61,25 +94,16 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) > return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), > "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); > if (IS_ERR(speedbin)) > return PTR_ERR(speedbin); > > - 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) > - *versions = efuse_value - 1; > - else > - *versions = 0; > + ret = opp_data->efuse_xlate(*speedbin); > > kfree(speedbin); > - return 0; > + > + return ret; > }; > > 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; > char name[MAX_NAME_LEN]; > unsigned int cpu; > - u32 speed = 0; > + int speed; > int ret; > > opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens), > @@ -95,10 +119,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) > if (!opp_tokens) > return -ENOMEM; > > - ret = sun50i_cpufreq_get_efuse(&speed); > - if (ret) { > + speed = sun50i_cpufreq_get_efuse(); > + if (speed < 0) { > kfree(opp_tokens); > - return ret; > + return speed; > } > > snprintf(name, MAX_NAME_LEN, "speed%d", speed); >
diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c index 32a9c88f8ff6d..7b44f3b13e7d2 100644 --- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c +++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c @@ -25,19 +25,52 @@ 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 - * @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) { struct nvmem_cell *speedbin_nvmem; struct device_node *np; struct device *cpu_dev; - u32 *speedbin, efuse_value; - size_t len; + const struct of_device_id *match; + const struct sunxi_cpufreq_data *opp_data; + u32 *speedbin; int ret; cpu_dev = get_cpu_device(0); @@ -48,12 +81,12 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) if (!np) return -ENOENT; - ret = of_device_is_compatible(np, - "allwinner,sun50i-h6-operating-points"); - if (!ret) { + match = of_match_node(cpu_opp_match_list, np); + if (!match) { of_node_put(np); return -ENOENT; } + opp_data = match->data; speedbin_nvmem = of_nvmem_cell_get(np, NULL); of_node_put(np); @@ -61,25 +94,16 @@ static int sun50i_cpufreq_get_efuse(u32 *versions) return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), "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); if (IS_ERR(speedbin)) return PTR_ERR(speedbin); - 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) - *versions = efuse_value - 1; - else - *versions = 0; + ret = opp_data->efuse_xlate(*speedbin); kfree(speedbin); - return 0; + + return ret; }; 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; char name[MAX_NAME_LEN]; unsigned int cpu; - u32 speed = 0; + int speed; int ret; opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens), @@ -95,10 +119,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) if (!opp_tokens) return -ENOMEM; - ret = sun50i_cpufreq_get_efuse(&speed); - if (ret) { + speed = sun50i_cpufreq_get_efuse(); + if (speed < 0) { kfree(opp_tokens); - return ret; + return speed; } snprintf(name, MAX_NAME_LEN, "speed%d", speed);