summaryrefslogtreecommitdiff
path: root/drivers/interconnect/qcom
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 19:53:39 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 19:53:39 -0700
commitf8fd5c24830fbc259ba7d5e72817c9867c01b8e8 (patch)
tree106ba47cd85f3eaf67335a6125d0a4050bc5caf3 /drivers/interconnect/qcom
parent4a3b1007eeb26b2bb7ae4d734cc8577463325165 (diff)
parent41680df0975e04b959a28bf6ab85fd6a307ae0ea (diff)
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk subsystem updates from Stephen Boyd: "This pull request is full of clk driver changes. In fact, there aren't any changes to the clk framework this time around. That's probably because everyone was on vacation (yours truly included). We did lose a couple clk drivers this time around because nobody was using those devices. That skews the diffstat a bit, but either way, nothing looks out of the ordinary here. The usual suspects are chugging along adding support for more SoCs and fixing bugs. If I had to choose, I'd say the theme for the past few months has been "polish". There's quite a few patches that migrate to devm_platform_ioremap_resource() in here. And there's more than a handful of patches that move the NR_CLKS define from the DT binding header to the driver. There's even patches that migrate drivers to use clk_parent_data and clk_hw to describe clk tree topology. It seems that the spring (summer?) cleaning bug got some folks, or the semiconductor shortage finally hit the software side. New Drivers: - StarFive JH7110 SoC clock drivers - Qualcomm IPQ5018 Global Clock Controller driver - Versa3 clk generator to support 48KHz playback/record with audio codec on RZ/G2L SMARC EVK Removed Drivers: - Remove non-OF mmp clk drivers - Remove OXNAS clk driver Updates: - Add __counted_by to struct clk_hw_onecell_data and struct spmi_pmic_div_clk_cc - Move defines for numbers of clks (NR_CLKS) from DT headers to drivers - Introduce kstrdup_and_replace() and use it - Add PLL rates for Rockchip rk3568 - Add the display clock tree for Rockchip rv1126 - Add Audio Clock Generator (ADG) clocks on Renesas R-Car Gen3 and RZ/G2 SoCs - Convert sun9i-mmc clock to use devm_platform_get_and_ioremap_resource() - Fix function name in a comment in ccu_mmc_timing.c - Parameter name correction for ccu_nkm_round_rate() - Implement CLK_SET_RATE_PARENT for Allwinner NKM clocks, i.e. consider alternative parent rates when determining clock rates - Set CLK_SET_RATE_PARENT for Allwinner A64 pll-mipi - Support finding closest (as opposed to closest but not higher) clock rate for NM, NKM, mux and div type clocks, as use it for Allwinner A64 pll-video0 - Prefer current parent rate if able to generate ideal clock rate for Allwinner NKM clocks - Clean up Qualcomm SMD RPM driver, with interconnect bus clocks moved out to the interconnect drivers - Fix various PM runtime bugs across many Qualcomm clk drivers - Migrate Qualcomm MDM9615 is to parent_hw and parent_data - Add network related resets on Qualcomm IPQ4019 - Add a couple missing USB related clocks to Qualcomm IPQ9574 - Add missing gpll0_sleep_clk_src to Qualcomm MSM8917 global clock controller - In the Qualcomm QDU1000 global clock controller, GDSCs, clkrefs, and GPLL1 are added, while PCIe pipe clock, SDCC rcg ops are corrected - Add missing GDSCs to and correct GDSCs for the SC8280XP global clock controller driver - Support retention for the Qualcomm SC8280XP display clock controller GDSCs. - Qualcommm's SDCC apps_clk_src is marked with CLK_OPS_PARENT_ENABLE to fix issues with missing parent clocks across sc7180, sm7150, sm6350 and sm8250, while sm8450 is corrected to use floor ops - Correct Qualcomm SM6350 GPU clock controller's clock supplies - Drop unwanted clocks from the Qualcomm IPQ5332 GCC driver - Add missing OXILICX GDSC to Qualcomm MSM8226 GCC - Change the delay in the Qualcomm reset controller to fsleep() for correctness - Extend the Qualcomm SM83550 Video clock controller to support SC8280XP - Add graphics clock support on Renesas RZ/G2M, RZ/G2N, RZ/G2E, and R-Car H3, M3-W, and M3-N SoCs - Add Clocked Serial Interface (CSI) clocks on Renesas RZ/V2M - Add PWM (MTU3) clock and reset on Renesas RZ/G2UL and RZ/Five - Add the PDM IPC clock for i.MX93 - Add 519.75MHz frequency support for i.MX9 PLL - Simplify the .determine_rate() implementation for i.MX GPR mux - Make the i.MX8QXP LPCG clock use devm_platform_ioremap_resource() - Add the audio mux clock to i.MX8 - Fix the SPLL2 MULT range for PLLv4 - Update the SPLL2 type in i.MX8ULP - Fix the SAI4 clock on i.MX8MP - Add silicon revision print for i.MX25 on clocks init - Drop the return value from __mx25_clocks_init() - Fix the clock pauses on no-op set_rate for i.MX8M composite clock - Drop restrictions for i.MX PLL14xx and fix its max prediv value - Drop the 393216000 and 361267200 from i.MX PLL14xx rate table to allow glitch free switching" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (207 commits) clk: qcom: Fix SM_GPUCC_8450 dependencies clk: lmk04832: Support using PLL1_LD as SPI readback pin clk: lmk04832: Don't disable vco clock on probe fail clk: lmk04832: Set missing parent_names for output clocks clk: mvebu: Convert to devm_platform_ioremap_resource() clk: nuvoton: Convert to devm_platform_ioremap_resource() clk: socfpga: agilex: Convert to devm_platform_ioremap_resource() clk: ti: Use devm_platform_get_and_ioremap_resource() clk: mediatek: Convert to devm_platform_ioremap_resource() clk: hsdk-pll: Convert to devm_platform_ioremap_resource() clk: gemini: Convert to devm_platform_ioremap_resource() clk: fsl-sai: Convert to devm_platform_ioremap_resource() clk: bm1880: Convert to devm_platform_ioremap_resource() clk: axm5516: Convert to devm_platform_ioremap_resource() clk: actions: Convert to devm_platform_ioremap_resource() clk: cdce925: Remove redundant of_match_ptr() clk: pxa910: Move number of clocks to driver source clk: pxa1928: Move number of clocks to driver source clk: pxa168: Move number of clocks to driver source clk: mmp2: Move number of clocks to driver source ...
Diffstat (limited to 'drivers/interconnect/qcom')
-rw-r--r--drivers/interconnect/qcom/Makefile2
-rw-r--r--drivers/interconnect/qcom/icc-rpm-clocks.c77
-rw-r--r--drivers/interconnect/qcom/icc-rpm.c220
-rw-r--r--drivers/interconnect/qcom/icc-rpm.h56
-rw-r--r--drivers/interconnect/qcom/msm8916.c5
-rw-r--r--drivers/interconnect/qcom/msm8939.c6
-rw-r--r--drivers/interconnect/qcom/msm8974.c2
-rw-r--r--drivers/interconnect/qcom/msm8996.c10
-rw-r--r--drivers/interconnect/qcom/qcm2290.c8
-rw-r--r--drivers/interconnect/qcom/qcs404.c5
-rw-r--r--drivers/interconnect/qcom/sdm660.c8
-rw-r--r--drivers/interconnect/qcom/smd-rpm.c23
-rw-r--r--drivers/interconnect/qcom/smd-rpm.h15
13 files changed, 287 insertions, 150 deletions
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index ab988926433c..80d9d2da95d1 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -29,7 +29,7 @@ qnoc-sm8250-objs := sm8250.o
qnoc-sm8350-objs := sm8350.o
qnoc-sm8450-objs := sm8450.o
qnoc-sm8550-objs := sm8550.o
-icc-smd-rpm-objs := smd-rpm.o icc-rpm.o
+icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
diff --git a/drivers/interconnect/qcom/icc-rpm-clocks.c b/drivers/interconnect/qcom/icc-rpm-clocks.c
new file mode 100644
index 000000000000..63c82a91bbc7
--- /dev/null
+++ b/drivers/interconnect/qcom/icc-rpm-clocks.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Linaro Ltd
+ */
+
+#include <linux/soc/qcom/smd-rpm.h>
+
+#include "icc-rpm.h"
+
+const struct rpm_clk_resource aggre1_clk = {
+ .resource_type = QCOM_SMD_RPM_AGGR_CLK,
+ .clock_id = 1,
+};
+EXPORT_SYMBOL_GPL(aggre1_clk);
+
+const struct rpm_clk_resource aggre2_clk = {
+ .resource_type = QCOM_SMD_RPM_AGGR_CLK,
+ .clock_id = 2,
+};
+EXPORT_SYMBOL_GPL(aggre2_clk);
+
+const struct rpm_clk_resource bimc_clk = {
+ .resource_type = QCOM_SMD_RPM_MEM_CLK,
+ .clock_id = 0,
+};
+EXPORT_SYMBOL_GPL(bimc_clk);
+
+const struct rpm_clk_resource bus_0_clk = {
+ .resource_type = QCOM_SMD_RPM_BUS_CLK,
+ .clock_id = 0,
+};
+EXPORT_SYMBOL_GPL(bus_0_clk);
+
+const struct rpm_clk_resource bus_1_clk = {
+ .resource_type = QCOM_SMD_RPM_BUS_CLK,
+ .clock_id = 1,
+};
+EXPORT_SYMBOL_GPL(bus_1_clk);
+
+const struct rpm_clk_resource bus_2_clk = {
+ .resource_type = QCOM_SMD_RPM_BUS_CLK,
+ .clock_id = 2,
+};
+EXPORT_SYMBOL_GPL(bus_2_clk);
+
+const struct rpm_clk_resource mmaxi_0_clk = {
+ .resource_type = QCOM_SMD_RPM_MMAXI_CLK,
+ .clock_id = 0,
+};
+EXPORT_SYMBOL_GPL(mmaxi_0_clk);
+
+const struct rpm_clk_resource mmaxi_1_clk = {
+ .resource_type = QCOM_SMD_RPM_MMAXI_CLK,
+ .clock_id = 1,
+};
+EXPORT_SYMBOL_GPL(mmaxi_1_clk);
+
+const struct rpm_clk_resource qup_clk = {
+ .resource_type = QCOM_SMD_RPM_QUP_CLK,
+ .clock_id = 0,
+};
+EXPORT_SYMBOL_GPL(qup_clk);
+
+/* Branch clocks */
+const struct rpm_clk_resource aggre1_branch_clk = {
+ .resource_type = QCOM_SMD_RPM_AGGR_CLK,
+ .clock_id = 1,
+ .branch = true,
+};
+EXPORT_SYMBOL_GPL(aggre1_branch_clk);
+
+const struct rpm_clk_resource aggre2_branch_clk = {
+ .resource_type = QCOM_SMD_RPM_AGGR_CLK,
+ .clock_id = 2,
+ .branch = true,
+};
+EXPORT_SYMBOL_GPL(aggre2_branch_clk);
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index 6acc7686ed38..3209d8de709b 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -3,7 +3,6 @@
* Copyright (C) 2020 Linaro Ltd
*/
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -14,7 +13,6 @@
#include <linux/regmap.h>
#include <linux/slab.h>
-#include "smd-rpm.h"
#include "icc-common.h"
#include "icc-rpm.h"
@@ -50,6 +48,8 @@
#define NOC_QOS_MODE_FIXED_VAL 0x0
#define NOC_QOS_MODE_BYPASS_VAL 0x2
+#define ICC_BUS_CLK_MIN_RATE 19200ULL /* kHz */
+
static int qcom_icc_set_qnoc_qos(struct icc_node *src)
{
struct icc_provider *provider = src->provider;
@@ -204,34 +204,39 @@ static int qcom_icc_qos_set(struct icc_node *node)
}
}
-static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 sum_bw)
+static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw)
{
- int ret = 0;
+ int ret, rpm_ctx = 0;
+ u64 bw_bps;
if (qn->qos.ap_owned)
return 0;
- if (qn->mas_rpm_id != -1) {
- ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
- RPM_BUS_MASTER_REQ,
- qn->mas_rpm_id,
- sum_bw);
- if (ret) {
- pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
- qn->mas_rpm_id, ret);
- return ret;
+ for (rpm_ctx = 0; rpm_ctx < QCOM_SMD_RPM_STATE_NUM; rpm_ctx++) {
+ bw_bps = icc_units_to_bps(bw[rpm_ctx]);
+
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(rpm_ctx,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ bw_bps);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
+ qn->mas_rpm_id, ret);
+ return ret;
+ }
}
- }
- if (qn->slv_rpm_id != -1) {
- ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
- RPM_BUS_SLAVE_REQ,
- qn->slv_rpm_id,
- sum_bw);
- if (ret) {
- pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
- qn->slv_rpm_id, ret);
- return ret;
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(rpm_ctx,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ bw_bps);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
+ qn->slv_rpm_id, ret);
+ return ret;
+ }
}
}
@@ -248,7 +253,7 @@ static void qcom_icc_pre_bw_aggregate(struct icc_node *node)
size_t i;
qn = node->data;
- for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
+ for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
qn->sum_avg[i] = 0;
qn->max_peak[i] = 0;
}
@@ -272,9 +277,9 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
qn = node->data;
if (!tag)
- tag = QCOM_ICC_TAG_ALWAYS;
+ tag = RPM_ALWAYS_TAG;
- for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
+ for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
if (tag & BIT(i)) {
qn->sum_avg[i] += avg_bw;
qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
@@ -287,61 +292,45 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
}
/**
- * qcom_icc_bus_aggregate - aggregate bandwidth by traversing all nodes
+ * qcom_icc_bus_aggregate - calculate bus clock rates by traversing all nodes
* @provider: generic interconnect provider
- * @agg_avg: an array for aggregated average bandwidth of buckets
- * @agg_peak: an array for aggregated peak bandwidth of buckets
- * @max_agg_avg: pointer to max value of aggregated average bandwidth
+ * @agg_clk_rate: array containing the aggregated clock rates in kHz
*/
-static void qcom_icc_bus_aggregate(struct icc_provider *provider,
- u64 *agg_avg, u64 *agg_peak,
- u64 *max_agg_avg)
+static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate)
{
- struct icc_node *node;
+ u64 agg_avg_rate, agg_rate;
struct qcom_icc_node *qn;
- u64 sum_avg[QCOM_ICC_NUM_BUCKETS];
+ struct icc_node *node;
int i;
- /* Initialise aggregate values */
- for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
- agg_avg[i] = 0;
- agg_peak[i] = 0;
- }
-
- *max_agg_avg = 0;
-
/*
- * Iterate nodes on the interconnect and aggregate bandwidth
- * requests for every bucket.
+ * Iterate nodes on the provider, aggregate bandwidth requests for
+ * every bucket and convert them into bus clock rates.
*/
list_for_each_entry(node, &provider->nodes, node_list) {
qn = node->data;
- for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
+ for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
if (qn->channels)
- sum_avg[i] = div_u64(qn->sum_avg[i], qn->channels);
+ agg_avg_rate = div_u64(qn->sum_avg[i], qn->channels);
else
- sum_avg[i] = qn->sum_avg[i];
- agg_avg[i] += sum_avg[i];
- agg_peak[i] = max_t(u64, agg_peak[i], qn->max_peak[i]);
+ agg_avg_rate = qn->sum_avg[i];
+
+ agg_rate = max_t(u64, agg_avg_rate, qn->max_peak[i]);
+ do_div(agg_rate, qn->buswidth);
+
+ agg_clk_rate[i] = max_t(u64, agg_clk_rate[i], agg_rate);
}
}
-
- /* Find maximum values across all buckets */
- for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++)
- *max_agg_avg = max_t(u64, *max_agg_avg, agg_avg[i]);
}
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
- struct qcom_icc_provider *qp;
struct qcom_icc_node *src_qn = NULL, *dst_qn = NULL;
+ u64 agg_clk_rate[QCOM_SMD_RPM_STATE_NUM] = { 0 };
struct icc_provider *provider;
- u64 sum_bw;
- u64 rate;
- u64 agg_avg[QCOM_ICC_NUM_BUCKETS], agg_peak[QCOM_ICC_NUM_BUCKETS];
- u64 max_agg_avg;
- int ret, i;
- int bucket;
+ struct qcom_icc_provider *qp;
+ u64 active_rate, sleep_rate;
+ int ret;
src_qn = src->data;
if (dst)
@@ -349,56 +338,66 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
provider = src->provider;
qp = to_qcom_provider(provider);
- qcom_icc_bus_aggregate(provider, agg_avg, agg_peak, &max_agg_avg);
-
- sum_bw = icc_units_to_bps(max_agg_avg);
+ qcom_icc_bus_aggregate(provider, agg_clk_rate);
+ active_rate = agg_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE];
+ sleep_rate = agg_clk_rate[QCOM_SMD_RPM_SLEEP_STATE];
- ret = qcom_icc_rpm_set(src_qn, sum_bw);
+ ret = qcom_icc_rpm_set(src_qn, src_qn->sum_avg);
if (ret)
return ret;
if (dst_qn) {
- ret = qcom_icc_rpm_set(dst_qn, sum_bw);
+ ret = qcom_icc_rpm_set(dst_qn, dst_qn->sum_avg);
+ if (ret)
+ return ret;
+ }
+
+ /* Some providers don't have a bus clock to scale */
+ if (!qp->bus_clk_desc && !qp->bus_clk)
+ return 0;
+
+ /*
+ * Downstream checks whether the requested rate is zero, but it makes little sense
+ * to vote for a value that's below the lower threshold, so let's not do so.
+ */
+ if (qp->keep_alive)
+ active_rate = max(ICC_BUS_CLK_MIN_RATE, active_rate);
+
+ /* Some providers have a non-RPM-owned bus clock - convert kHz->Hz for the CCF */
+ if (qp->bus_clk) {
+ active_rate = max_t(u64, active_rate, sleep_rate);
+ /* ARM32 caps clk_set_rate arg to u32.. Nothing we can do about that! */
+ active_rate = min_t(u64, 1000ULL * active_rate, ULONG_MAX);
+ return clk_set_rate(qp->bus_clk, active_rate);
+ }
+
+ /* RPM only accepts <=INT_MAX rates */
+ active_rate = min_t(u64, active_rate, INT_MAX);
+ sleep_rate = min_t(u64, sleep_rate, INT_MAX);
+
+ if (active_rate != qp->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE]) {
+ ret = qcom_icc_rpm_set_bus_rate(qp->bus_clk_desc, QCOM_SMD_RPM_ACTIVE_STATE,
+ active_rate);
if (ret)
return ret;
+
+ /* Cache the rate after we've successfully commited it to RPM */
+ qp->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate;
}
- for (i = 0; i < qp->num_bus_clks; i++) {
- /*
- * Use WAKE bucket for active clock, otherwise, use SLEEP bucket
- * for other clocks. If a platform doesn't set interconnect
- * path tags, by default use sleep bucket for all clocks.
- *
- * Note, AMC bucket is not supported yet.
- */
- if (!strcmp(qp->bus_clks[i].id, "bus_a"))
- bucket = QCOM_ICC_BUCKET_WAKE;
- else
- bucket = QCOM_ICC_BUCKET_SLEEP;
-
- rate = icc_units_to_bps(max(agg_avg[bucket], agg_peak[bucket]));
- do_div(rate, src_qn->buswidth);
- rate = min_t(u64, rate, LONG_MAX);
-
- if (qp->bus_clk_rate[i] == rate)
- continue;
-
- ret = clk_set_rate(qp->bus_clks[i].clk, rate);
- if (ret) {
- pr_err("%s clk_set_rate error: %d\n",
- qp->bus_clks[i].id, ret);
+ if (sleep_rate != qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE]) {
+ ret = qcom_icc_rpm_set_bus_rate(qp->bus_clk_desc, QCOM_SMD_RPM_SLEEP_STATE,
+ sleep_rate);
+ if (ret)
return ret;
- }
- qp->bus_clk_rate[i] = rate;
+
+ /* Cache the rate after we've successfully commited it to RPM */
+ qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate;
}
return 0;
}
-static const char * const bus_clocks[] = {
- "bus", "bus_a",
-};
-
int qnoc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -440,6 +439,20 @@ int qnoc_probe(struct platform_device *pdev)
if (!qp->intf_clks)
return -ENOMEM;
+ if (desc->bus_clk_desc) {
+ qp->bus_clk_desc = devm_kzalloc(dev, sizeof(*qp->bus_clk_desc),
+ GFP_KERNEL);
+ if (!qp->bus_clk_desc)
+ return -ENOMEM;
+
+ qp->bus_clk_desc = desc->bus_clk_desc;
+ } else {
+ /* Some older SoCs may have a single non-RPM-owned bus clock. */
+ qp->bus_clk = devm_clk_get_optional(dev, "bus");
+ if (IS_ERR(qp->bus_clk))
+ return PTR_ERR(qp->bus_clk);
+ }
+
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
GFP_KERNEL);
if (!data)
@@ -449,10 +462,7 @@ int qnoc_probe(struct platform_device *pdev)
for (i = 0; i < cd_num; i++)
qp->intf_clks[i].id = cds[i];
- qp->num_bus_clks = desc->no_clk_scaling ? 0 : NUM_BUS_CLKS;
- for (i = 0; i < qp->num_bus_clks; i++)
- qp->bus_clks[i].id = bus_clocks[i];
-
+ qp->keep_alive = desc->keep_alive;
qp->type = desc->type;
qp->qos_offset = desc->qos_offset;
@@ -481,11 +491,7 @@ int qnoc_probe(struct platform_device *pdev)
}
regmap_done:
- ret = devm_clk_bulk_get(dev, qp->num_bus_clks, qp->bus_clks);
- if (ret)
- return ret;
-
- ret = clk_bulk_prepare_enable(qp->num_bus_clks, qp->bus_clks);
+ ret = clk_prepare_enable(qp->bus_clk);
if (ret)
return ret;
@@ -557,7 +563,7 @@ err_deregister_provider:
icc_provider_deregister(provider);
err_remove_nodes:
icc_nodes_remove(provider);
- clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);
+ clk_disable_unprepare(qp->bus_clk);
return ret;
}
@@ -569,7 +575,7 @@ int qnoc_remove(struct platform_device *pdev)
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
- clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);
+ clk_disable_unprepare(qp->bus_clk);
return 0;
}
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index ee705edf19dd..eed3451af3e6 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -6,7 +6,12 @@
#ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H
#define __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H
-#include <dt-bindings/interconnect/qcom,icc.h>
+#include <linux/soc/qcom/smd-rpm.h>
+
+#include <dt-bindings/interconnect/qcom,rpm-icc.h>
+#include <linux/clk.h>
+#include <linux/interconnect-provider.h>
+#include <linux/platform_device.h>
#define RPM_BUS_MASTER_REQ 0x73616d62
#define RPM_BUS_SLAVE_REQ 0x766c7362
@@ -20,31 +25,43 @@ enum qcom_icc_type {
QCOM_ICC_QNOC,
};
-#define NUM_BUS_CLKS 2
+/**
+ * struct rpm_clk_resource - RPM bus clock resource
+ * @resource_type: RPM resource type of the clock resource
+ * @clock_id: index of the clock resource of a specific resource type
+ * @branch: whether the resource represents a branch clock
+*/
+struct rpm_clk_resource {
+ u32 resource_type;
+ u32 clock_id;
+ bool branch;
+};
/**
* struct qcom_icc_provider - Qualcomm specific interconnect provider
* @provider: generic interconnect provider
- * @num_bus_clks: the total number of bus_clks clk_bulk_data entries (0 or 2)
* @num_intf_clks: the total number of intf_clks clk_bulk_data entries
* @type: the ICC provider type
* @regmap: regmap for QoS registers read/write access
* @qos_offset: offset to QoS registers
* @bus_clk_rate: bus clock rate in Hz
- * @bus_clks: the clk_bulk_data table of bus clocks
+ * @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks
+ * @bus_clk: a pointer to a HLOS-owned bus clock
* @intf_clks: a clk_bulk_data array of interface clocks
+ * @keep_alive: whether to always keep a minimum vote on the bus clocks
* @is_on: whether the bus is powered on
*/
struct qcom_icc_provider {
struct icc_provider provider;
- int num_bus_clks;
int num_intf_clks;
enum qcom_icc_type type;
struct regmap *regmap;
unsigned int qos_offset;
- u64 bus_clk_rate[NUM_BUS_CLKS];
- struct clk_bulk_data bus_clks[NUM_BUS_CLKS];
+ u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM];
+ const struct rpm_clk_resource *bus_clk_desc;
+ struct clk *bus_clk;
struct clk_bulk_data *intf_clks;
+ bool keep_alive;
bool is_on;
};
@@ -89,8 +106,8 @@ struct qcom_icc_node {
u16 num_links;
u16 channels;
u16 buswidth;
- u64 sum_avg[QCOM_ICC_NUM_BUCKETS];
- u64 max_peak[QCOM_ICC_NUM_BUCKETS];
+ u64 sum_avg[QCOM_SMD_RPM_STATE_NUM];
+ u64 max_peak[QCOM_SMD_RPM_STATE_NUM];
int mas_rpm_id;
int slv_rpm_id;
struct qcom_icc_qos qos;
@@ -99,10 +116,10 @@ struct qcom_icc_node {
struct qcom_icc_desc {
struct qcom_icc_node * const *nodes;
size_t num_nodes;
- const char * const *bus_clocks;
+ const struct rpm_clk_resource *bus_clk_desc;
const char * const *intf_clocks;
size_t num_intf_clocks;
- bool no_clk_scaling;
+ bool keep_alive;
enum qcom_icc_type type;
const struct regmap_config *regmap_cfg;
unsigned int qos_offset;
@@ -115,7 +132,24 @@ enum qos_mode {
NOC_QOS_MODE_BYPASS,
};
+extern const struct rpm_clk_resource aggre1_clk;
+extern const struct rpm_clk_resource aggre2_clk;
+extern const struct rpm_clk_resource bimc_clk;
+extern const struct rpm_clk_resource bus_0_clk;
+extern const struct rpm_clk_resource bus_1_clk;
+extern const struct rpm_clk_resource bus_2_clk;
+extern const struct rpm_clk_resource mmaxi_0_clk;
+extern const struct rpm_clk_resource mmaxi_1_clk;
+extern const struct rpm_clk_resource qup_clk;
+
+extern const struct rpm_clk_resource aggre1_branch_clk;
+extern const struct rpm_clk_resource aggre2_branch_clk;
+
int qnoc_probe(struct platform_device *pdev);
int qnoc_remove(struct platform_device *pdev);
+bool qcom_icc_rpm_smd_available(void);
+int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
+int qcom_icc_rpm_set_bus_rate(const struct rpm_clk_resource *clk, int ctx, u32 rate);
+
#endif
diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c
index 5c4ba2f37c8e..b567a2b4199c 100644
--- a/drivers/interconnect/qcom/msm8916.c
+++ b/drivers/interconnect/qcom/msm8916.c
@@ -4,7 +4,6 @@
* Author: Georgi Djakov <georgi.djakov@linaro.org>
*/
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -15,7 +14,6 @@
#include <dt-bindings/interconnect/qcom,msm8916.h>
-#include "smd-rpm.h"
#include "icc-rpm.h"
enum {
@@ -1232,6 +1230,7 @@ static const struct qcom_icc_desc msm8916_snoc = {
.type = QCOM_ICC_NOC,
.nodes = msm8916_snoc_nodes,
.num_nodes = ARRAY_SIZE(msm8916_snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
.regmap_cfg = &msm8916_snoc_regmap_config,
.qos_offset = 0x7000,
};
@@ -1260,6 +1259,7 @@ static const struct qcom_icc_desc msm8916_bimc = {
.type = QCOM_ICC_BIMC,
.nodes = msm8916_bimc_nodes,
.num_nodes = ARRAY_SIZE(msm8916_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
.regmap_cfg = &msm8916_bimc_regmap_config,
.qos_offset = 0x8000,
};
@@ -1329,6 +1329,7 @@ static const struct qcom_icc_desc msm8916_pcnoc = {
.type = QCOM_ICC_NOC,
.nodes = msm8916_pcnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8916_pcnoc_nodes),
+ .bus_clk_desc = &bus_0_clk,
.regmap_cfg = &msm8916_pcnoc_regmap_config,
.qos_offset = 0x7000,
};
diff --git a/drivers/interconnect/qcom/msm8939.c b/drivers/interconnect/qcom/msm8939.c
index caf0aefad668..6732eeeb8158 100644
--- a/drivers/interconnect/qcom/msm8939.c
+++ b/drivers/interconnect/qcom/msm8939.c
@@ -5,7 +5,6 @@
* With reference of msm8916 interconnect driver of Georgi Djakov.
*/
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -16,7 +15,6 @@
#include <dt-bindings/interconnect/qcom,msm8939.h>
-#include "smd-rpm.h"
#include "icc-rpm.h"
enum {
@@ -1285,6 +1283,7 @@ static const struct qcom_icc_desc msm8939_snoc = {
.type = QCOM_ICC_NOC,
.nodes = msm8939_snoc_nodes,
.num_nodes = ARRAY_SIZE(msm8939_snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
.regmap_cfg = &msm8939_snoc_regmap_config,
.qos_offset = 0x7000,
};
@@ -1305,6 +1304,7 @@ static const struct qcom_icc_desc msm8939_snoc_mm = {
.type = QCOM_ICC_NOC,
.nodes = msm8939_snoc_mm_nodes,
.num_nodes = ARRAY_SIZE(msm8939_snoc_mm_nodes),
+ .bus_clk_desc = &bus_2_clk,
.regmap_cfg = &msm8939_snoc_regmap_config,
.qos_offset = 0x7000,
};
@@ -1333,6 +1333,7 @@ static const struct qcom_icc_desc msm8939_bimc = {
.type = QCOM_ICC_BIMC,
.nodes = msm8939_bimc_nodes,
.num_nodes = ARRAY_SIZE(msm8939_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
.regmap_cfg = &msm8939_bimc_regmap_config,
.qos_offset = 0x8000,
};
@@ -1404,6 +1405,7 @@ static const struct qcom_icc_desc msm8939_pcnoc = {
.type = QCOM_ICC_NOC,
.nodes = msm8939_pcnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8939_pcnoc_nodes),
+ .bus_clk_desc = &bus_0_clk,
.regmap_cfg = &msm8939_pcnoc_regmap_config,
.qos_offset = 0x7000,
};
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index 1828deaca443..968162213d40 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -38,7 +38,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include "smd-rpm.h"
+#include "icc-rpm.h"
enum {
MSM8974_BIMC_MAS_AMPSS_M0 = 1,
diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c
index 20340fb62fe6..b9695c1931ce 100644
--- a/drivers/interconnect/qcom/msm8996.c
+++ b/drivers/interconnect/qcom/msm8996.c
@@ -5,7 +5,6 @@
* Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
*/
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -18,7 +17,6 @@
#include <dt-bindings/interconnect/qcom,msm8996.h>
#include "icc-rpm.h"
-#include "smd-rpm.h"
#include "msm8996.h"
static const char * const mm_intf_clocks[] = {
@@ -1819,7 +1817,6 @@ static const struct qcom_icc_desc msm8996_a0noc = {
.num_nodes = ARRAY_SIZE(a0noc_nodes),
.intf_clocks = a0noc_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(a0noc_intf_clocks),
- .no_clk_scaling = true,
.regmap_cfg = &msm8996_a0noc_regmap_config
};
@@ -1841,6 +1838,7 @@ static const struct qcom_icc_desc msm8996_a1noc = {
.type = QCOM_ICC_NOC,
.nodes = a1noc_nodes,
.num_nodes = ARRAY_SIZE(a1noc_nodes),
+ .bus_clk_desc = &aggre1_branch_clk,
.regmap_cfg = &msm8996_a1noc_regmap_config
};
@@ -1862,6 +1860,7 @@ static const struct qcom_icc_desc msm8996_a2noc = {
.type = QCOM_ICC_NOC,
.nodes = a2noc_nodes,
.num_nodes = ARRAY_SIZE(a2noc_nodes),
+ .bus_clk_desc = &aggre2_branch_clk,
.intf_clocks = a2noc_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
.regmap_cfg = &msm8996_a2noc_regmap_config
@@ -1890,6 +1889,7 @@ static const struct qcom_icc_desc msm8996_bimc = {
.type = QCOM_ICC_BIMC,
.nodes = bimc_nodes,
.num_nodes = ARRAY_SIZE(bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
.regmap_cfg = &msm8996_bimc_regmap_config
};
@@ -1948,6 +1948,7 @@ static const struct qcom_icc_desc msm8996_cnoc = {
.type = QCOM_ICC_NOC,
.nodes = cnoc_nodes,
.num_nodes = ARRAY_SIZE(cnoc_nodes),
+ .bus_clk_desc = &bus_2_clk,
.regmap_cfg = &msm8996_cnoc_regmap_config
};
@@ -2001,6 +2002,7 @@ static const struct qcom_icc_desc msm8996_mnoc = {
.type = QCOM_ICC_NOC,
.nodes = mnoc_nodes,
.num_nodes = ARRAY_SIZE(mnoc_nodes),
+ .bus_clk_desc = &mmaxi_0_clk,
.intf_clocks = mm_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
.regmap_cfg = &msm8996_mnoc_regmap_config
@@ -2039,6 +2041,7 @@ static const struct qcom_icc_desc msm8996_pnoc = {
.type = QCOM_ICC_NOC,
.nodes = pnoc_nodes,
.num_nodes = ARRAY_SIZE(pnoc_nodes),
+ .bus_clk_desc = &bus_0_clk,
.regmap_cfg = &msm8996_pnoc_regmap_config
};
@@ -2083,6 +2086,7 @@ static const struct qcom_icc_desc msm8996_snoc = {
.type = QCOM_ICC_NOC,
.nodes = snoc_nodes,
.num_nodes = ARRAY_SIZE(snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
.regmap_cfg = &msm8996_snoc_regmap_config
};
diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c
index a29cdb4fac03..8fc4acc4220b 100644
--- a/drivers/interconnect/qcom/qcm2290.c
+++ b/drivers/interconnect/qcom/qcm2290.c
@@ -7,7 +7,6 @@
*/
#include <dt-bindings/interconnect/qcom,qcm2290.h>
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -19,7 +18,6 @@
#include <linux/slab.h>
#include "icc-rpm.h"
-#include "smd-rpm.h"
enum {
QCM2290_MASTER_APPSS_PROC = 1,
@@ -1197,6 +1195,7 @@ static const struct qcom_icc_desc qcm2290_bimc = {
.type = QCOM_ICC_BIMC,
.nodes = qcm2290_bimc_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
.regmap_cfg = &qcm2290_bimc_regmap_config,
/* M_REG_BASE() in vendor msm_bus_bimc_adhoc driver */
.qos_offset = 0x8000,
@@ -1252,6 +1251,7 @@ static const struct qcom_icc_desc qcm2290_cnoc = {
.type = QCOM_ICC_NOC,
.nodes = qcm2290_cnoc_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_cnoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
.regmap_cfg = &qcm2290_cnoc_regmap_config,
};
@@ -1293,6 +1293,7 @@ static const struct qcom_icc_desc qcm2290_snoc = {
.type = QCOM_ICC_QNOC,
.nodes = qcm2290_snoc_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_snoc_nodes),
+ .bus_clk_desc = &bus_2_clk,
.regmap_cfg = &qcm2290_snoc_regmap_config,
/* Vendor DT node fab-sys_noc property 'qcom,base-offset' */
.qos_offset = 0x15000,
@@ -1307,6 +1308,7 @@ static const struct qcom_icc_desc qcm2290_qup_virt = {
.type = QCOM_ICC_QNOC,
.nodes = qcm2290_qup_virt_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_qup_virt_nodes),
+ .bus_clk_desc = &qup_clk,
};
static struct qcom_icc_node * const qcm2290_mmnrt_virt_nodes[] = {
@@ -1320,6 +1322,7 @@ static const struct qcom_icc_desc qcm2290_mmnrt_virt = {
.type = QCOM_ICC_QNOC,
.nodes = qcm2290_mmnrt_virt_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_mmnrt_virt_nodes),
+ .bus_clk_desc = &mmaxi_0_clk,
.regmap_cfg = &qcm2290_snoc_regmap_config,
.qos_offset = 0x15000,
};
@@ -1334,6 +1337,7 @@ static const struct qcom_icc_desc qcm2290_mmrt_virt = {
.type = QCOM_ICC_QNOC,
.nodes = qcm2290_mmrt_virt_nodes,
.num_nodes = ARRAY_SIZE(qcm2290_mmrt_virt_nodes),
+ .bus_clk_desc = &mmaxi_1_clk,
.regmap_cfg = &qcm2290_snoc_regmap_config,
.qos_offset = 0x15000,
};
diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c
index fae155344332..82fe905b74a9 100644
--- a/drivers/interconnect/qcom/qcs404.c
+++ b/drivers/interconnect/qcom/qcs404.c
@@ -4,7 +4,6 @@
*/
#include <dt-bindings/interconnect/qcom,qcs404.h>
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -13,7 +12,6 @@
#include <linux/of_device.h>
-#include "smd-rpm.h"
#include "icc-rpm.h"
enum {
@@ -985,6 +983,7 @@ static struct qcom_icc_node * const qcs404_bimc_nodes[] = {
};
static const struct qcom_icc_desc qcs404_bimc = {
+ .bus_clk_desc = &bimc_clk,
.nodes = qcs404_bimc_nodes,
.num_nodes = ARRAY_SIZE(qcs404_bimc_nodes),
};
@@ -1039,6 +1038,7 @@ static struct qcom_icc_node * const qcs404_pcnoc_nodes[] = {
};
static const struct qcom_icc_desc qcs404_pcnoc = {
+ .bus_clk_desc = &bus_0_clk,
.nodes = qcs404_pcnoc_nodes,
.num_nodes = ARRAY_SIZE(qcs404_pcnoc_nodes),
};
@@ -1067,6 +1067,7 @@ static struct qcom_icc_node * const qcs404_snoc_nodes[] = {
};
static const struct qcom_icc_desc qcs404_snoc = {
+ .bus_clk_desc = &bus_1_clk,
.nodes = qcs404_snoc_nodes,
.num_nodes = ARRAY_SIZE(qcs404_snoc_nodes),
};
diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c
index 7ffaf70d62d3..e1aed937c86b 100644
--- a/drivers/interconnect/qcom/sdm660.c
+++ b/drivers/interconnect/qcom/sdm660.c
@@ -5,7 +5,6 @@
*/
#include <dt-bindings/interconnect/qcom,sdm660.h>
-#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
@@ -17,7 +16,6 @@
#include <linux/slab.h>
#include "icc-rpm.h"
-#include "smd-rpm.h"
enum {
SDM660_MASTER_IPA = 1,
@@ -1512,6 +1510,7 @@ static const struct qcom_icc_desc sdm660_a2noc = {
.type = QCOM_ICC_NOC,
.nodes = sdm660_a2noc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_a2noc_nodes),
+ .bus_clk_desc = &aggre2_clk,
.intf_clocks = a2noc_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
.regmap_cfg = &sdm660_a2noc_regmap_config,
@@ -1540,6 +1539,7 @@ static const struct qcom_icc_desc sdm660_bimc = {
.type = QCOM_ICC_BIMC,
.nodes = sdm660_bimc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
.regmap_cfg = &sdm660_bimc_regmap_config,
};
@@ -1594,6 +1594,7 @@ static const struct qcom_icc_desc sdm660_cnoc = {
.type = QCOM_ICC_NOC,
.nodes = sdm660_cnoc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_cnoc_nodes),
+ .bus_clk_desc = &bus_2_clk,
.regmap_cfg = &sdm660_cnoc_regmap_config,
};
@@ -1616,7 +1617,6 @@ static const struct qcom_icc_desc sdm660_gnoc = {
.nodes = sdm660_gnoc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_gnoc_nodes),
.regmap_cfg = &sdm660_gnoc_regmap_config,
- .no_clk_scaling = true,
};
static struct qcom_icc_node * const sdm660_mnoc_nodes[] = {
@@ -1656,6 +1656,7 @@ static const struct qcom_icc_desc sdm660_mnoc = {
.type = QCOM_ICC_NOC,
.nodes = sdm660_mnoc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_mnoc_nodes),
+ .bus_clk_desc = &mmaxi_0_clk,
.intf_clocks = mm_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
.regmap_cfg = &sdm660_mnoc_regmap_config,
@@ -1693,6 +1694,7 @@ static const struct qcom_icc_desc sdm660_snoc = {
.type = QCOM_ICC_NOC,
.nodes = sdm660_snoc_nodes,
.num_nodes = ARRAY_SIZE(sdm660_snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
.regmap_cfg = &sdm660_snoc_regmap_config,
};
diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c
index dc8ff8d133a9..24bc994e1a12 100644
--- a/drivers/interconnect/qcom/smd-rpm.c
+++ b/drivers/interconnect/qcom/smd-rpm.c
@@ -13,9 +13,10 @@
#include <linux/platform_device.h>
#include <linux/soc/qcom/smd-rpm.h>
-#include "smd-rpm.h"
+#include "icc-rpm.h"
#define RPM_KEY_BW 0x00007762
+#define QCOM_RPM_SMD_KEY_RATE 0x007a484b
static struct qcom_smd_rpm *icc_smd_rpm;
@@ -44,6 +45,26 @@ int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val)
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_send);
+int qcom_icc_rpm_set_bus_rate(const struct rpm_clk_resource *clk, int ctx, u32 rate)
+{
+ struct clk_smd_rpm_req req = {
+ .key = cpu_to_le32(QCOM_RPM_SMD_KEY_RATE),
+ .nbytes = cpu_to_le32(sizeof(u32)),
+ };
+
+ /* Branch clocks are only on/off */
+ if (clk->branch)
+ rate = !!rate;
+
+ req.value = cpu_to_le32(rate);
+ return qcom_rpm_smd_write(icc_smd_rpm,
+ ctx,
+ clk->resource_type,
+ clk->clock_id,
+ &req, sizeof(req));
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_set_bus_rate);
+
static int qcom_icc_rpm_smd_remove(struct platform_device *pdev)
{
icc_smd_rpm = NULL;
diff --git a/drivers/interconnect/qcom/smd-rpm.h b/drivers/interconnect/qcom/smd-rpm.h
deleted file mode 100644
index ca9d0327b8ac..000000000000
--- a/drivers/interconnect/qcom/smd-rpm.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019, Linaro Ltd.
- * Author: Georgi Djakov <georgi.djakov@linaro.org>
- */
-
-#ifndef __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H
-#define __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H
-
-#include <linux/soc/qcom/smd-rpm.h>
-
-bool qcom_icc_rpm_smd_available(void);
-int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
-
-#endif