Linux can cast votes on resources through different RSCs (e.g. DISP). This can be done for many reasons, from latency to fine-grain on-SoC-power-grid management. With all the necessary bits in place, add the loops and ifs necessary to vote through different RSCs. Signed-off-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxx> --- drivers/interconnect/qcom/icc-rpmh.c | 49 ++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index 53298148f24b..3cdd9106b0c0 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -22,6 +22,8 @@ void qcom_icc_pre_aggregate(struct icc_node *node) { struct qcom_icc_provider *qp; struct qcom_icc_node *qn; + struct qcom_icc_bcm *bcm; + int voter_idx; int i; qn = node->data; @@ -32,8 +34,17 @@ void qcom_icc_pre_aggregate(struct icc_node *node) qn->max_peak[i] = 0; } - for (i = 0; i < qn->num_bcms; i++) - qcom_icc_bcm_voter_add(qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS], qn->bcms[i]); + for (i = 0; i < qn->num_bcms; i++) { + bcm = qn->bcms[i]; + + /* Old and incomplete device trees may not specify all voters. */ + if (qcom_icc_bcm_voters[bcm->voter_idx]) + voter_idx = bcm->voter_idx; + else + voter_idx = ICC_BCM_VOTER_APPS; + + qcom_icc_bcm_voter_add(qcom_icc_bcm_voters[voter_idx], bcm); + } } EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate); @@ -87,6 +98,7 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst) { struct qcom_icc_provider *qp; struct icc_node *node; + int i, ret; if (!src) node = dst; @@ -95,7 +107,11 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst) qp = to_qcom_provider(node->provider); - qcom_icc_bcm_voter_commit(qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS]); + for (i = 0; i < ICC_BCM_VOTER_MAX; i++) { + ret = qcom_icc_bcm_voter_commit(qcom_icc_bcm_voters[i]); + if (ret) + return ret; + } return 0; } @@ -168,6 +184,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) struct qcom_icc_node * const *qnodes, *qn; struct qcom_icc_provider *qp; struct device_node *bcm_node; + u32 val, voter_count = 0; struct icc_node *node; size_t num_nodes, i, j; int ret; @@ -201,10 +218,28 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) qp->bcms = desc->bcms; qp->num_bcms = desc->num_bcms; - /* Ensure the BCM voter is reachable (unless we don't have any) */ - qp->voter = qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS]; - if (qp->num_bcms && !qp->voter) - return -EPROBE_DEFER; + for (i = 0; i < ICC_BCM_VOTER_MAX; i++) { + bcm_node = of_parse_phandle(dev->of_node, "qcom,bcm-voters", voter_count); + if (!bcm_node) + break; + + voter_count++; + + ret = of_property_read_u32(bcm_node, "qcom,bcm-voter-idx", &val); + of_node_put(bcm_node); + /* Legacy DTs only ever referenced the APPS BCM voter */ + if (ret == -EINVAL) + val = ICC_BCM_VOTER_APPS; + else if (ret) + return ret; + + if (!qcom_icc_bcm_voters[val]) + return -EPROBE_DEFER; + } + + /* Let's not forget to add qcom,bcm-voters to the provider node! */ + if (qp->num_bcms && !voter_count) + return -EINVAL; for (i = 0; i < qp->num_bcms; i++) qcom_icc_bcm_init(qp->bcms[i], dev); -- 2.41.0