diff mbox series

[v2,3/4] clk: qcom: add IPQ9574 interconnect clocks support

Message ID 20240325102036.95484-4-quic_varada@quicinc.com (mailing list archive)
State Superseded
Headers show
Series Add interconnect driver for IPQ9574 SoC | expand

Commit Message

Varadarajan Narayanan March 25, 2024, 10:20 a.m. UTC
Unlike MSM platforms that manage NoC related clocks and scaling
from RPM, IPQ SoCs dont involve RPM in managing NoC related
clocks and there is no NoC scaling.

However, there is a requirement to enable some NoC interface
clocks for accessing the peripheral controllers present on
these NoCs. Though exposing these as normal clocks would work,
having a minimalistic interconnect driver to handle these clocks
would make it consistent with other Qualcomm platforms resulting
in common code paths.  This is similar to msm8996-cbf's usage of
icc-clk framework.

Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
---
v2: Move DTS to separate patch
    Update commit log
    Auto select CONFIG_INTERCONNECT & CONFIG_INTERCONNECT_CLK to fix build error
---
 drivers/clk/qcom/Kconfig       |  2 ++
 drivers/clk/qcom/gcc-ipq9574.c | 65 +++++++++++++++++++++++++++++++++-
 2 files changed, 66 insertions(+), 1 deletion(-)

Comments

Konrad Dybcio March 25, 2024, 7:42 p.m. UTC | #1
On 25.03.2024 11:20 AM, Varadarajan Narayanan wrote:
> Unlike MSM platforms that manage NoC related clocks and scaling
> from RPM, IPQ SoCs dont involve RPM in managing NoC related
> clocks and there is no NoC scaling.
> 
> However, there is a requirement to enable some NoC interface
> clocks for accessing the peripheral controllers present on
> these NoCs. Though exposing these as normal clocks would work,
> having a minimalistic interconnect driver to handle these clocks
> would make it consistent with other Qualcomm platforms resulting
> in common code paths.  This is similar to msm8996-cbf's usage of
> icc-clk framework.
> 
> Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
> ---

[...]

>  
> +
> +static struct icc_clk_data *icc_ipq9574;
> +

What does this help achieve?

[...]

> +static int noc_clks[] = {

We could probably use indexed identifiers here to avoid confusion:
[ICC_BINDING_NAME] = CLK_BINDING_NAME

>  static int gcc_ipq9574_probe(struct platform_device *pdev)
>  {
> -	return qcom_cc_probe(pdev, &gcc_ipq9574_desc);
> +	int ret = qcom_cc_probe(pdev, &gcc_ipq9574_desc);
> +	struct icc_provider *provider;
> +	struct icc_clk_data *icd;
> +	int i;
> +
> +	if (ret)

I'd personally prefer if you left ret uninitialized and assigned it
above the if-statement.

> +		return dev_err_probe(&pdev->dev, ret, "%s failed\n", __func__);

Please avoid the use of __func__ throughout your change and write
a more useful error message.

> +
> +	icd = devm_kmalloc(&pdev->dev, ARRAY_SIZE(noc_clks) * sizeof(*icd),
> +			   GFP_KERNEL);

devm_kcalloc

> +
> +	if (IS_ERR_OR_NULL(icd))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(icd),
> +				     "%s malloc failed\n", __func__);

ditto

> +
> +	icc_ipq9574 = icd;
> +
> +	for (i = 0; i < ARRAY_SIZE(noc_clks); i++, icd++) {
> +		icd->clk = gcc_ipq9574_clks[noc_clks[i]]->hw.clk;
> +		if (IS_ERR_OR_NULL(icd->clk)) {
> +			dev_err(&pdev->dev, "%s: %d clock not found\n",
> +				__func__, noc_clks[i]);
> +			return -ENOENT;

return dev_err_probe

> +		}
> +		icd->name = clk_hw_get_name(&gcc_ipq9574_clks[noc_clks[i]]->hw);
> +	}
> +
> +	provider = icc_clk_register(&pdev->dev, IPQ_APPS_ID,
> +				    ARRAY_SIZE(noc_clks), icc_ipq9574);
> +	if (IS_ERR_OR_NULL(provider))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(provider),
> +				     "%s: icc_clk_register failed\n", __func__);

ditto

On a second thought, since I'm assuming you're going to expand this to other
IPQ SoCs, it might be useful to factor this out into drivers/clk/qcom/common.c

Konrad
Varadarajan Narayanan March 26, 2024, 6:03 a.m. UTC | #2
On Mon, Mar 25, 2024 at 08:42:21PM +0100, Konrad Dybcio wrote:
> On 25.03.2024 11:20 AM, Varadarajan Narayanan wrote:
> > Unlike MSM platforms that manage NoC related clocks and scaling
> > from RPM, IPQ SoCs dont involve RPM in managing NoC related
> > clocks and there is no NoC scaling.
> >
> > However, there is a requirement to enable some NoC interface
> > clocks for accessing the peripheral controllers present on
> > these NoCs. Though exposing these as normal clocks would work,
> > having a minimalistic interconnect driver to handle these clocks
> > would make it consistent with other Qualcomm platforms resulting
> > in common code paths.  This is similar to msm8996-cbf's usage of
> > icc-clk framework.
> >
> > Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
> > ---
>
> [...]
>
> >
> > +
> > +static struct icc_clk_data *icc_ipq9574;
> > +
>
> What does this help achieve?

Had it as a place holder in case if the provider pointer is needed
for any debug. Will remove it.

> > +static int noc_clks[] = {
>
> We could probably use indexed identifiers here to avoid confusion:
> [ICC_BINDING_NAME] = CLK_BINDING_NAME

ok.

> >  static int gcc_ipq9574_probe(struct platform_device *pdev)
> >  {
> > -	return qcom_cc_probe(pdev, &gcc_ipq9574_desc);
> > +	int ret = qcom_cc_probe(pdev, &gcc_ipq9574_desc);
> > +	struct icc_provider *provider;
> > +	struct icc_clk_data *icd;
> > +	int i;
> > +
> > +	if (ret)
>
> I'd personally prefer if you left ret uninitialized and assigned it
> above the if-statement.

ok

> > +		return dev_err_probe(&pdev->dev, ret, "%s failed\n", __func__);
>
> Please avoid the use of __func__ throughout your change and write
> a more useful error message.
>
> > +
> > +	icd = devm_kmalloc(&pdev->dev, ARRAY_SIZE(noc_clks) * sizeof(*icd),
> > +			   GFP_KERNEL);
>
> devm_kcalloc

ok

> > +
> > +	if (IS_ERR_OR_NULL(icd))
> > +		return dev_err_probe(&pdev->dev, PTR_ERR(icd),
> > +				     "%s malloc failed\n", __func__);
>
> ditto

ok

> > +
> > +	icc_ipq9574 = icd;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(noc_clks); i++, icd++) {
> > +		icd->clk = gcc_ipq9574_clks[noc_clks[i]]->hw.clk;
> > +		if (IS_ERR_OR_NULL(icd->clk)) {
> > +			dev_err(&pdev->dev, "%s: %d clock not found\n",
> > +				__func__, noc_clks[i]);
> > +			return -ENOENT;
>
> return dev_err_probe

ok

> > +		}
> > +		icd->name = clk_hw_get_name(&gcc_ipq9574_clks[noc_clks[i]]->hw);
> > +	}
> > +
> > +	provider = icc_clk_register(&pdev->dev, IPQ_APPS_ID,
> > +				    ARRAY_SIZE(noc_clks), icc_ipq9574);
> > +	if (IS_ERR_OR_NULL(provider))
> > +		return dev_err_probe(&pdev->dev, PTR_ERR(provider),
> > +				     "%s: icc_clk_register failed\n", __func__);
>
> ditto

ok

> On a second thought, since I'm assuming you're going to expand this to other
> IPQ SoCs, it might be useful to factor this out into drivers/clk/qcom/common.c

Will move it.

Thanks
Varada
diff mbox series

Patch

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 8ab08e7b5b6c..af73a0b396eb 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -243,6 +243,8 @@  config IPQ_GCC_8074
 
 config IPQ_GCC_9574
 	tristate "IPQ9574 Global Clock Controller"
+	select INTERCONNECT
+	select INTERCONNECT_CLK
 	help
 	  Support for global clock controller on ipq9574 devices.
 	  Say Y if you want to use peripheral devices such as UART, SPI,
diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c
index 0a3f846695b8..ed25bb34216a 100644
--- a/drivers/clk/qcom/gcc-ipq9574.c
+++ b/drivers/clk/qcom/gcc-ipq9574.c
@@ -9,9 +9,12 @@ 
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/interconnect-clk.h>
+#include <linux/interconnect-provider.h>
 
 #include <dt-bindings/clock/qcom,ipq9574-gcc.h>
 #include <dt-bindings/reset/qcom,ipq9574-gcc.h>
+#include <dt-bindings/interconnect/qcom,ipq9574.h>
 
 #include "clk-alpha-pll.h"
 #include "clk-branch.h"
@@ -4301,6 +4304,33 @@  static const struct qcom_reset_map gcc_ipq9574_resets[] = {
 	[GCC_WCSS_Q6_TBU_BCR] = { 0x12054, 0 },
 };
 
+
+static struct icc_clk_data *icc_ipq9574;
+
+static int noc_clks[] = {
+	GCC_ANOC_PCIE0_1LANE_M_CLK,
+	GCC_SNOC_PCIE0_1LANE_S_CLK,
+	GCC_ANOC_PCIE1_1LANE_M_CLK,
+	GCC_SNOC_PCIE1_1LANE_S_CLK,
+	GCC_ANOC_PCIE2_2LANE_M_CLK,
+	GCC_SNOC_PCIE2_2LANE_S_CLK,
+	GCC_ANOC_PCIE3_2LANE_M_CLK,
+	GCC_SNOC_PCIE3_2LANE_S_CLK,
+	GCC_SNOC_USB_CLK,
+	GCC_ANOC_USB_AXI_CLK,
+	GCC_NSSNOC_NSSCC_CLK,
+	GCC_NSSNOC_SNOC_CLK,
+	GCC_NSSNOC_SNOC_1_CLK,
+	GCC_NSSNOC_PCNOC_1_CLK,
+	GCC_NSSNOC_QOSGEN_REF_CLK,
+	GCC_NSSNOC_TIMEOUT_REF_CLK,
+	GCC_NSSNOC_XO_DCD_CLK,
+	GCC_NSSNOC_ATB_CLK,
+	GCC_MEM_NOC_NSSNOC_CLK,
+	GCC_NSSNOC_MEMNOC_CLK,
+	GCC_NSSNOC_MEM_NOC_1_CLK,
+};
+
 static const struct of_device_id gcc_ipq9574_match_table[] = {
 	{ .compatible = "qcom,ipq9574-gcc" },
 	{ }
@@ -4327,7 +4357,40 @@  static const struct qcom_cc_desc gcc_ipq9574_desc = {
 
 static int gcc_ipq9574_probe(struct platform_device *pdev)
 {
-	return qcom_cc_probe(pdev, &gcc_ipq9574_desc);
+	int ret = qcom_cc_probe(pdev, &gcc_ipq9574_desc);
+	struct icc_provider *provider;
+	struct icc_clk_data *icd;
+	int i;
+
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "%s failed\n", __func__);
+
+	icd = devm_kmalloc(&pdev->dev, ARRAY_SIZE(noc_clks) * sizeof(*icd),
+			   GFP_KERNEL);
+
+	if (IS_ERR_OR_NULL(icd))
+		return dev_err_probe(&pdev->dev, PTR_ERR(icd),
+				     "%s malloc failed\n", __func__);
+
+	icc_ipq9574 = icd;
+
+	for (i = 0; i < ARRAY_SIZE(noc_clks); i++, icd++) {
+		icd->clk = gcc_ipq9574_clks[noc_clks[i]]->hw.clk;
+		if (IS_ERR_OR_NULL(icd->clk)) {
+			dev_err(&pdev->dev, "%s: %d clock not found\n",
+				__func__, noc_clks[i]);
+			return -ENOENT;
+		}
+		icd->name = clk_hw_get_name(&gcc_ipq9574_clks[noc_clks[i]]->hw);
+	}
+
+	provider = icc_clk_register(&pdev->dev, IPQ_APPS_ID,
+				    ARRAY_SIZE(noc_clks), icc_ipq9574);
+	if (IS_ERR_OR_NULL(provider))
+		return dev_err_probe(&pdev->dev, PTR_ERR(provider),
+				     "%s: icc_clk_register failed\n", __func__);
+
+	return 0;
 }
 
 static struct platform_driver gcc_ipq9574_driver = {