diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 13ad3a51b58c..15636a8dc907 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -282,6 +282,12 @@ struct se_fw_hdr { #define geni_setbits32(_addr, _v) writel(readl(_addr) | (_v), _addr) #define geni_clrbits32(_addr, _v) writel(readl(_addr) & ~(_v), _addr) +enum domain_idx { + DOMAIN_IDX_POWER, + DOMAIN_IDX_PERF, + DOMAIN_IDX_MAX +}; + /** * geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version * @se: Pointer to the corresponding serial engine. @@ -1096,6 +1102,50 @@ int geni_se_resources_activate(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_se_resources_activate); +/** + * geni_se_set_perf_level() - Set performance level for GENI SE. + * @se: Pointer to the struct geni_se instance. + * @level: The desired performance level. + * + * Sets the performance level by directly calling dev_pm_opp_set_level + * on the performance device associated with the SE. + * + * Return: 0 on success, or a negative error code on failure. + */ +int geni_se_set_perf_level(struct geni_se *se, unsigned long level) +{ + return dev_pm_opp_set_level(se->pd_list->pd_devs[DOMAIN_IDX_PERF], level); +} +EXPORT_SYMBOL_GPL(geni_se_set_perf_level); + +/** + * geni_se_set_perf_opp() - Set performance OPP for GENI SE by frequency. + * @se: Pointer to the struct geni_se instance. + * @clk_freq: The requested clock frequency. + * + * Finds the nearest operating performance point (OPP) for the given + * clock frequency and applies it to the SE's performance device. + * + * Return: 0 on success, or a negative error code on failure. + */ +int geni_se_set_perf_opp(struct geni_se *se, unsigned long clk_freq) +{ + struct device *perf_dev = se->pd_list->pd_devs[DOMAIN_IDX_PERF]; + struct dev_pm_opp *opp; + int ret; + + opp = dev_pm_opp_find_freq_floor(perf_dev, &clk_freq); + if (IS_ERR(opp)) { + dev_err(se->dev, "failed to find opp for freq %lu\n", clk_freq); + return PTR_ERR(opp); + } + + ret = dev_pm_opp_set_opp(perf_dev, opp); + dev_pm_opp_put(opp); + return ret; +} +EXPORT_SYMBOL_GPL(geni_se_set_perf_opp); + /** * geni_se_domain_attach() - Attach power domains to a GENI SE device. * @se: Pointer to the geni_se structure representing the GENI SE device. diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 5f75159c5531..c5e6ab85df09 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -550,5 +550,9 @@ int geni_se_resources_deactivate(struct geni_se *se); int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol); int geni_se_domain_attach(struct geni_se *se); + +int geni_se_set_perf_level(struct geni_se *se, unsigned long level); + +int geni_se_set_perf_opp(struct geni_se *se, unsigned long clk_freq); #endif #endif