[PATCH 2/7] soc: qcom: geni-se: Populate clk_perf_tbl with SE source clock frequencies from perf OPP table
Praveen Talari <[email protected]> Wed, 05 Aug 2026 01:27:40 +0530
| Newsgroups | gmane.linux.serial,gmane.linux.ports.arm.kernel,gmane.linux.power-management.general,gmane.linux.kernel,gmane.linux.ports.arm.msm,gmane.linux.kernel.spi.devel,gmane.linux.drivers.i2c |
|---|---|
| Message-ID | <20260805-derive_clk_perf_tbl_from_perf_domain_opp_table-v1-2-61171ab1cdce@oss.qualcomm.com> |
Currently, on the SA8255P platform, protocol drivers attached via geni_se_domain_attach() treat each OPP on the perf domain as directly corresponding to a protocol value such as a baudrate or requested frequency, and simply request that OPP via geni_se_set_perf_level()/geni_se_set_perf_opp(). This does not allow computing a source clock and divider combination for a protocol requested frequency, unlike the Linux clock managed path which derives this from se->clk_perf_tbl via geni_se_clk_freq_match(), and then applies the matched source clock frequency with dev_pm_opp_set_rate(). Change this by treating the OPP table exposed on the perf domain device as representing the actual SE HW supported source clock frequencies, the same role clk_perf_tbl plays for the Linux clock managed path. Populate se->clk_perf_tbl and se->num_clk_levels by iterating over this OPP table in geni_se_domain_attach(), so that protocol drivers on the firmware managed (SA8255P) path can also use geni_se_clk_freq_match() to pick the closest supported source clock frequency and calculate the required divider, and apply it with dev_pm_opp_set_rate() the same way as it is done for the Linux clock managed path, instead of relying on a direct frequency/baudrate-to- perf-level mapping. Signed-off-by: Praveen Talari <[email protected]> --- drivers/soc/qcom/qcom-geni-se.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 873bfbd6b2b7..a88bd092b87e 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -1155,7 +1155,8 @@ EXPORT_SYMBOL_GPL(geni_se_set_perf_opp); * * This function attaches the power domains ("power" and "perf") required * in the SCMI auto-VM environment to the GENI Serial Engine device. It - * initializes se->pd_list with the attached domains. + * initializes se->pd_list with the attached domains, and populates + * se->clk_perf_tbl from the OPP table of the "perf" domain device. * * Return: 0 on success, or a negative error code on failure. */ @@ -1166,7 +1167,12 @@ int geni_se_domain_attach(struct geni_se *se) .pd_names = (const char*[]) { "power", "perf" }, .num_pd_names = 2, }; + struct device *perf_dev; + struct dev_pm_opp *opp; + unsigned int level; + int num_opps; int ret; + int i; ret = devm_pm_domain_attach_list(se->dev, &pd_data, &se->pd_list); @@ -1175,6 +1181,29 @@ int geni_se_domain_attach(struct geni_se *se) else if (ret < 0) return ret; + perf_dev = se->pd_list->pd_devs[DOMAIN_IDX_PERF]; + + num_opps = dev_pm_opp_get_opp_count(perf_dev); + if (num_opps <= 0) + return num_opps < 0 ? num_opps : -ENODEV; + + se->clk_perf_tbl = devm_kcalloc(se->dev, num_opps, + sizeof(*se->clk_perf_tbl), + GFP_KERNEL); + if (!se->clk_perf_tbl) + return -ENOMEM; + + for (i = 0, level = 0; i < num_opps; i++, level++) { + opp = dev_pm_opp_find_level_ceil(perf_dev, &level); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + se->clk_perf_tbl[i] = level; + dev_pm_opp_put(opp); + } + se->num_clk_levels = num_opps; + se->has_opp = true; + return 0; } EXPORT_SYMBOL_GPL(geni_se_domain_attach); -- 2.34.1