mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
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:
parent
d41dcee41c
commit
b5de5be5e0
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user