diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index 367b70810db5..2d7d5f2b7341 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -177,4 +177,82 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev) } EXPORT_SYMBOL(qcom_icc_bcm_init); +static bool bcm_needs_qos_proxy(struct qcom_icc_bcm *bcm) +{ + int i; + + if (bcm->voter_idx == 0) + for (i = 0; i < bcm->num_nodes; i++) + if (bcm->nodes[i]->qosbox) + return true; + + return false; +} + +/** + * qcom_icc_enable_qos_deps - enable clocks and BCMs required for QoS + * @qp: interconnect provider associated with masters whose QoS to be set + * + * Return: 0 on success, or an error code otherwise + */ +int qcom_icc_enable_qos_deps(struct qcom_icc_provider *qp) +{ + struct qcom_icc_bcm *bcm; + struct bcm_voter *voter; + bool keepalive; + int ret, i; + + for (i = 0; i < qp->num_bcms; i++) { + bcm = qp->bcms[i]; + if (bcm_needs_qos_proxy(bcm)) { + keepalive = bcm->keepalive; + bcm->keepalive = true; + + voter = qp->voters[bcm->voter_idx]; + qcom_icc_bcm_voter_add(voter, bcm); + ret = qcom_icc_bcm_voter_commit(voter); + + bcm->keepalive = keepalive; + + if (ret) { + dev_err(qp->dev, "failed to vote BW to %s for QoS\n", + bcm->name); + return ret; + } + } + } + + ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks); + if (ret) { + dev_err(qp->dev, "failed to enable clocks for QoS\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(qcom_icc_enable_qos_deps); + +/** + * qcom_icc_disable_qos_deps - disable clocks and BCMs + * @qp: interconnect provider associated with masters whose QoS to be set + */ +void qcom_icc_disable_qos_deps(struct qcom_icc_provider *qp) +{ + struct qcom_icc_bcm *bcm; + struct bcm_voter *voter; + int i; + + clk_bulk_disable_unprepare(qp->num_clks, qp->clks); + + for (i = 0; i < qp->num_bcms; i++) { + bcm = qp->bcms[i]; + if (bcm_needs_qos_proxy(bcm)) { + voter = qp->voters[bcm->voter_idx]; + qcom_icc_bcm_voter_add(voter, bcm); + qcom_icc_bcm_voter_commit(voter); + } + } +} +EXPORT_SYMBOL(qcom_icc_disable_qos_deps); + MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index c4d255ffe365..ce0e9a5fb5fb 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. * */ @@ -149,5 +149,7 @@ int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, int qcom_icc_set(struct icc_node *src, struct icc_node *dst); int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev); void qcom_icc_pre_aggregate(struct icc_node *node); +int qcom_icc_enable_qos_deps(struct qcom_icc_provider *qp); +void qcom_icc_disable_qos_deps(struct qcom_icc_provider *qp); #endif