diff --git a/drivers/interconnect/qcom/holi.c b/drivers/interconnect/qcom/holi.c index e0339b58eac7..77c85a11d554 100644 --- a/drivers/interconnect/qcom/holi.c +++ b/drivers/interconnect/qcom/holi.c @@ -21,6 +21,11 @@ #include "icc-rpm.h" #include "rpm-ids.h" +static LIST_HEAD(qnoc_probe_list); +static DEFINE_MUTEX(probe_list_lock); + +static int probe_count; + static const struct clk_bulk_data bus_clocks[] = { { .id = "bus" }, { .id = "bus_a" }, @@ -1232,6 +1237,9 @@ static int qnoc_probe(struct platform_device *pdev) provider->data = data; qp->dev = &pdev->dev; + qp->init = true; + qp->keepalive = of_property_read_bool(dev->of_node, "qcom,keepalive"); + qp->regmap = qcom_icc_map(pdev, desc); if (IS_ERR(qp->regmap)) return PTR_ERR(qp->regmap); @@ -1269,6 +1277,11 @@ static int qnoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qp); dev_info(dev, "Registered HOLI ICC\n"); + + mutex_lock(&probe_list_lock); + list_add_tail(&qp->probe_list, &qnoc_probe_list); + mutex_unlock(&probe_list_lock); + return 0; err: list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) { @@ -1314,12 +1327,54 @@ static const struct of_device_id qnoc_of_match[] = { }; MODULE_DEVICE_TABLE(of, qnoc_of_match); +static void qnoc_sync_state(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + int ret, i; + + mutex_lock(&probe_list_lock); + probe_count++; + + if (probe_count < ARRAY_SIZE(qnoc_of_match) - 1) { + mutex_unlock(&probe_list_lock); + return; + } + + list_for_each_entry(qp, &qnoc_probe_list, probe_list) { + qp->init = false; + + if (!qp->keepalive) + continue; + + for (i = 0; i < RPM_NUM_CXT; i++) { + if (i == RPM_ACTIVE_CXT) { + if (qp->bus_clk_cur_rate[i] == 0) + ret = clk_set_rate(qp->bus_clks[i].clk, + RPM_CLK_MIN_LEVEL); + else + ret = clk_set_rate(qp->bus_clks[i].clk, + qp->bus_clk_cur_rate[i]); + } + + if (ret) + pr_err("%s clk_set_rate error: %d\n", + qp->bus_clks[i].id, ret); + } + } + + mutex_unlock(&probe_list_lock); + + pr_err("HOLI ICC Sync State done\n"); +} + static struct platform_driver qnoc_driver = { .probe = qnoc_probe, .remove = qnoc_remove, .driver = { .name = "qnoc-holi", .of_match_table = qnoc_of_match, + .sync_state = qnoc_sync_state, }, }; diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 576c06ee3f39..90bfdd16e2c4 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -130,8 +130,21 @@ int qcom_icc_rpm_set(struct icc_node *src, struct icc_node *dst) for (i = 0; i < RPM_NUM_CXT; i++) { if (qp->bus_clk_cur_rate[i] != bus_clk_rate[i]) { - ret = clk_set_rate(qp->bus_clks[i].clk, - bus_clk_rate[i]); + if (qp->keepalive && i == RPM_ACTIVE_CXT) { + if (qp->init) + ret = clk_set_rate(qp->bus_clks[i].clk, + RPM_CLK_MAX_LEVEL); + else if (bus_clk_rate[i] == 0) + ret = clk_set_rate(qp->bus_clks[i].clk, + RPM_CLK_MIN_LEVEL); + else + ret = clk_set_rate(qp->bus_clks[i].clk, + bus_clk_rate[i]); + } else { + ret = clk_set_rate(qp->bus_clks[i].clk, + bus_clk_rate[i]); + } + if (ret) { pr_err("%s clk_set_rate error: %d\n", qp->bus_clks[i].id, ret); diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index 3904fe26ed2e..a87af7d34c8a 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -17,6 +17,8 @@ #define RPM_SLEEP_SET MSM_RPM_CTX_SLEEP_SET #define RPM_ACTIVE_SET MSM_RPM_CTX_ACTIVE_SET +#define RPM_CLK_MAX_LEVEL INT_MAX +#define RPM_CLK_MIN_LEVEL 19200000 #define to_qcom_provider(_provider) \ container_of(_provider, struct qcom_icc_provider, provider) @@ -45,14 +47,19 @@ enum qcom_icc_rpm_context { * @bus_clks: the clk_bulk_data table of bus clocks * @num_clks: the total number of clk_bulk_data entries * @bus_clk_cur_rate: current frequency of bus clock + * @keepalive: flag used to indicate whether a keepalive is required + * @init: flag to determine when init has completed. */ struct qcom_icc_provider { struct icc_provider provider; struct device *dev; struct regmap *regmap; + struct list_head probe_list; struct clk_bulk_data *bus_clks; int num_clks; u64 bus_clk_cur_rate[RPM_NUM_CXT]; + bool keepalive; + bool init; }; /**