@@ -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,31 @@ 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;
+ if (num_opps == 0)
+ return -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);
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 <praveen.talari@oss.qualcomm.com> --- drivers/soc/qcom/qcom-geni-se.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)