interconnect: qcom: icc-rpmh: Add support to scale local clocks

Add support to scale local clocks along with BW votes using
the clk framework, as opposed to only voting shared clocks
through BCM and then voting to DFS to scale clocks.

Change-Id: I62190e08a382551b2759cee22ce4bd50e760604f
Signed-off-by: Xubin Bai <quic_xubibai@quicinc.com>
This commit is contained in:
Xubin Bai 2022-08-15 23:49:46 -07:00
parent d41dcee41c
commit b5de5be5e0
2 changed files with 65 additions and 1 deletions

View File

@ -108,7 +108,9 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
struct icc_node *node;
int i;
struct qcom_icc_node *qn;
u64 clk_rate;
int i, ret;
if (!src)
node = dst;
@ -116,6 +118,45 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
node = src;
qp = to_qcom_provider(node->provider);
qn = node->data;
if (qn->bw_scale_numerator && qn->bw_scale_denominator) {
node->avg_bw *= qn->bw_scale_numerator;
do_div(node->avg_bw, qn->bw_scale_denominator);
node->peak_bw *= qn->bw_scale_numerator;
do_div(node->peak_bw, qn->bw_scale_denominator);
}
if (qn->clk) {
/*
* Multiply by 1000 to convert the unit of bandwidth from KBps
* to Bps, then divide by the bandwidth to get the clk rate in Hz.
*/
clk_rate = (u64)max(node->avg_bw, node->peak_bw) * 1000 / qn->buswidth;
clk_rate = clk_rate > U32_MAX ? U32_MAX : clk_rate;
if (clk_rate > 0) {
ret = clk_set_rate(qn->clk, clk_rate);
if (ret)
dev_warn(qp->dev, "Failed to set %s rate to %d for %s\n",
qn->clk_name, clk_rate, qn->name);
if (qn->toggle_clk && !qn->clk_enabled) {
ret = clk_prepare_enable(qn->clk);
if (ret) {
dev_err(qp->dev, "Failed to enable %s for %s\n",
qn->clk_name, qn->name);
return ret;
}
qn->clk_enabled = true;
}
} else if (qn->toggle_clk && qn->clk_enabled) {
clk_disable_unprepare(qn->clk);
qn->clk_enabled = false;
}
}
for (i = 0; i < qp->num_voters; i++)
qcom_icc_bcm_voter_commit(qp->voters[i]);
@ -418,6 +459,17 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
goto err;
}
if (qn->clk_name) {
qn->clk = devm_clk_get(qp->dev, qn->clk_name);
if (IS_ERR(qn->clk)) {
ret = PTR_ERR(qn->clk);
if (ret != -EPROBE_DEFER)
dev_err(qp->dev, "failed to get %s, err:(%d)\n",
qn->clk_name, ret);
goto err;
}
}
if (qn->qosbox && !qp->skip_qos)
qn->noc_ops->set_qos(qn);

View File

@ -68,6 +68,12 @@ struct bcm_db {
* @perf_mode: current OR aggregate value of all QCOM_ICC_TAG_PERF_MODE votes
* @bcms: list of bcms associated with this logical node
* @num_bcms: num of @bcms
* @clk: the local clock at this node
* @clk_name: the local clock name at this node
* @toggle_clk: flag used to indicate whether local clock can be enabled/disabled
* @clk_enabled: flag used to indicate whether local clock have been enabled
* @bw_scale_numerator: the numerator of the bandwidth scale factor
* @bw_scale_denominator: the denominator of the bandwidth scale factor
*/
struct qcom_icc_node {
const char *name;
@ -84,6 +90,12 @@ struct qcom_icc_node {
struct regmap *regmap;
struct qcom_icc_qosbox *qosbox;
const struct qcom_icc_noc_ops *noc_ops;
struct clk *clk;
const char *clk_name;
bool toggle_clk;
bool clk_enabled;
u16 bw_scale_numerator;
u16 bw_scale_denominator;
};
/**