linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V4 00/11] clk: imx: add imx8qxp clock support
@ 2018-10-14  8:07 A.s. Dong
  2018-10-14  8:07 ` [PATCH V4 01/11] clk: imx: add configuration option for mmio clks A.s. Dong
                   ` (10 more replies)
  0 siblings, 11 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

This patch series adds i.MX8QXP clock support which is based
on the clock service provided by SCU firmware.

Note: It depends on SCU driver which has already been merged by Shawn.
So this patch series could go through Shawn's tree as well.

ChangeLog:
v3->v4:
 * scu headfile path update
 * no functionality change
v2->v3:
 * structures/enums name update with imx_sc prefix
 * no functionality change
v1->v2:
 * structure and enums name update
 * api usage update due to api change
 * no functionality change

Dong Aisheng (11):
  clk: imx: add configuration option for mmio clks
  clk: imx: scu: add scu clock common part
  clk: imx: scu: add scu clock divider
  clk: imx: scu: add scu clock gpr divider
  clk: imx: scu: add scu clock gate
  clk: imx: scu: add scu clock gpr gate
  clk: imx: scu: add scu clock mux
  clk: imx: scu: add scu clock gpr mux
  clk: imx: add common imx_clk_hw_fixed functions
  clk: imx: add imx_check_clk_hws helper function
  clk: imx: add imx8qxp clk driver

 arch/arm/mach-imx/Kconfig                 |  11 +
 drivers/clk/Kconfig                       |   1 +
 drivers/clk/imx/Kconfig                   |   7 +
 drivers/clk/imx/Makefile                  |   4 +-
 drivers/clk/imx/clk-common.h              |  27 ++
 drivers/clk/imx/scu/Kconfig               |   5 +
 drivers/clk/imx/scu/Makefile              |  12 +
 drivers/clk/imx/scu/clk-divider-gpr-scu.c | 129 +++++++++
 drivers/clk/imx/scu/clk-divider-scu.c     | 176 +++++++++++++
 drivers/clk/imx/scu/clk-gate-gpr-scu.c    |  87 ++++++
 drivers/clk/imx/scu/clk-gate-scu.c        | 222 ++++++++++++++++
 drivers/clk/imx/scu/clk-imx8qxp.c         | 425 ++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-mux-gpr-scu.c     |  90 +++++++
 drivers/clk/imx/scu/clk-mux-scu.c         | 130 +++++++++
 drivers/clk/imx/scu/clk-scu.c             |  17 ++
 drivers/clk/imx/scu/clk-scu.h             |  97 +++++++
 include/dt-bindings/clock/imx8qxp-clock.h | 362 +++++++++++++++++++++++++
 include/soc/imx/imx8qxp/lpcg.h            | 186 +++++++++++++
 18 files changed, 1987 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/Kconfig
 create mode 100644 drivers/clk/imx/clk-common.h
 create mode 100644 drivers/clk/imx/scu/Kconfig
 create mode 100644 drivers/clk/imx/scu/Makefile
 create mode 100644 drivers/clk/imx/scu/clk-divider-gpr-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-divider-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-gate-gpr-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-gate-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-imx8qxp.c
 create mode 100644 drivers/clk/imx/scu/clk-mux-gpr-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-mux-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-scu.h
 create mode 100644 include/dt-bindings/clock/imx8qxp-clock.h
 create mode 100644 include/soc/imx/imx8qxp/lpcg.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH V4 01/11] clk: imx: add configuration option for mmio clks
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-14  8:07 ` [PATCH V4 02/11] clk: imx: scu: add scu clock common part A.s. Dong
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

The patch introduces CONFIG_MXC_CLK option for legacy MMIO clocks,
this is required to compile legacy MMIO clock conditionally when adding
SCU based clocks for MX8 platforms later.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 arch/arm/mach-imx/Kconfig | 11 +++++++++++
 drivers/clk/Kconfig       |  1 +
 drivers/clk/imx/Kconfig   |  5 +++++
 drivers/clk/imx/Makefile  |  2 +-
 4 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/Kconfig

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index abc3371..11a9661 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -57,23 +57,27 @@ config SOC_IMX21
 	select CPU_ARM926T
 	select IMX_HAVE_IOMUX_V1
 	select MXC_AVIC
+	select MXC_CLK
 
 config SOC_IMX27
 	bool
 	select CPU_ARM926T
 	select IMX_HAVE_IOMUX_V1
 	select MXC_AVIC
+	select MXC_CLK
 	select PINCTRL_IMX27
 
 config SOC_IMX31
 	bool
 	select CPU_V6
 	select MXC_AVIC
+	select MXC_CLK
 
 config SOC_IMX35
 	bool
 	select ARCH_MXC_IOMUX_V3
 	select MXC_AVIC
+	select MXC_CLK
 	select PINCTRL_IMX35
 
 if ARCH_MULTI_V5
@@ -417,6 +421,7 @@ config SOC_IMX1
 	bool "i.MX1 support"
 	select CPU_ARM920T
 	select MXC_AVIC
+	select MXC_CLK
 	select PINCTRL_IMX1
 	help
 	  This enables support for Freescale i.MX1 processor
@@ -430,6 +435,7 @@ config SOC_IMX25
 	select ARCH_MXC_IOMUX_V3
 	select CPU_ARM926T
 	select MXC_AVIC
+	select MXC_CLK
 	select PINCTRL_IMX25
 	help
 	  This enables support for Freescale i.MX25 processor
@@ -442,6 +448,7 @@ comment "Cortex-A platforms"
 config SOC_IMX5
 	bool
 	select HAVE_IMX_SRC
+	select MXC_CLK
 	select MXC_TZIC
 
 config	SOC_IMX50
@@ -478,6 +485,7 @@ config SOC_IMX6
 	select HAVE_IMX_MMDC
 	select HAVE_IMX_SRC
 	select MFD_SYSCON
+	select MXC_CLK
 	select PL310_ERRATA_769419 if CACHE_L2X0
 
 config SOC_IMX6Q
@@ -545,10 +553,12 @@ config SOC_IMX7D_CA7
 	select HAVE_IMX_MMDC
 	select HAVE_IMX_SRC
 	select IMX_GPCV2
+	select MXC_CLK
 
 config SOC_IMX7D_CM4
 	bool
 	select ARMV7M_SYSTICK
+	select MXC_CLK
 
 config SOC_IMX7D
 	bool "i.MX7 Dual support"
@@ -561,6 +571,7 @@ config SOC_IMX7D
 config SOC_VF610
 	bool "Vybrid Family VF610 support"
 	select ARM_GIC if ARCH_MULTI_V7
+	select MXC_CLK
 	select PINCTRL_VF610
 
 	help
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 292056b..09eba54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -287,6 +287,7 @@ source "drivers/clk/actions/Kconfig"
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/imgtec/Kconfig"
+source "drivers/clk/imx/Kconfig"
 source "drivers/clk/keystone/Kconfig"
 source "drivers/clk/mediatek/Kconfig"
 source "drivers/clk/meson/Kconfig"
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
new file mode 100644
index 0000000..43a3ecc
--- /dev/null
+++ b/drivers/clk/imx/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# common clock support for NXP i.MX SoC family.
+config MXC_CLK
+	bool
+	depends on ARCH_MXC
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 8c3baa7..d447f8c 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-y += \
+obj-$(CONFIG_MXC_CLK) += \
 	clk.o \
 	clk-busy.o \
 	clk-cpu.o \
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 02/11] clk: imx: scu: add scu clock common part
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
  2018-10-14  8:07 ` [PATCH V4 01/11] clk: imx: add configuration option for mmio clks A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-16 21:31   ` Stephen Boyd
  2018-10-14  8:07 ` [PATCH V4 03/11] clk: imx: scu: add scu clock divider A.s. Dong
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu clock common part which will be used by client clock drivers.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path change
v2->v3:
 * no changes
v1->v2:
 * update function call name
---
 drivers/clk/imx/Kconfig       |  2 ++
 drivers/clk/imx/Makefile      |  2 ++
 drivers/clk/imx/scu/Kconfig   |  5 +++++
 drivers/clk/imx/scu/Makefile  |  4 ++++
 drivers/clk/imx/scu/clk-scu.c | 17 +++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h | 18 ++++++++++++++++++
 6 files changed, 48 insertions(+)
 create mode 100644 drivers/clk/imx/scu/Kconfig
 create mode 100644 drivers/clk/imx/scu/Makefile
 create mode 100644 drivers/clk/imx/scu/clk-scu.c
 create mode 100644 drivers/clk/imx/scu/clk-scu.h

diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index 43a3ecc..b1599bf 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -3,3 +3,5 @@
 config MXC_CLK
 	bool
 	depends on ARCH_MXC
+
+source drivers/clk/imx/scu/Kconfig
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index d447f8c..79b641a 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_MXC_CLK) += \
 	clk-pllv3.o \
 	clk-pfd.o
 
+obj-y += scu/
+
 obj-$(CONFIG_SOC_IMX1)   += clk-imx1.o
 obj-$(CONFIG_SOC_IMX21)  += clk-imx21.o
 obj-$(CONFIG_SOC_IMX25)  += clk-imx25.o
diff --git a/drivers/clk/imx/scu/Kconfig b/drivers/clk/imx/scu/Kconfig
new file mode 100644
index 0000000..4d018fd
--- /dev/null
+++ b/drivers/clk/imx/scu/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# SCU based common clock support for NXP i.MX SoC family.
+config MXC_CLK_SCU
+	bool
+	depends on ARCH_MXC && ARM64
diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
new file mode 100644
index 0000000..7dead13
--- /dev/null
+++ b/drivers/clk/imx/scu/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_MXC_CLK_SCU) += \
+	clk-scu.o
diff --git a/drivers/clk/imx/scu/clk-scu.c b/drivers/clk/imx/scu/clk-scu.c
new file mode 100644
index 0000000..826049f
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-scu.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/errno.h>
+#include "clk-scu.h"
+
+DEFINE_SPINLOCK(imx_ccm_lock);
+struct imx_sc_ipc *ccm_ipc_handle;
+
+int imx_clk_scu_init(void)
+{
+	return imx_scu_get_handle(&ccm_ipc_handle);
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
new file mode 100644
index 0000000..b964f35
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ */
+
+#ifndef __IMX_CLK_SCU_H
+#define __IMX_CLK_SCU_H
+
+#include <linux/firmware/imx/sci.h>
+#include <linux/spinlock.h>
+
+extern spinlock_t imx_ccm_lock;
+extern struct imx_sc_ipc *ccm_ipc_handle;
+
+int imx_clk_scu_init(void);
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
  2018-10-14  8:07 ` [PATCH V4 01/11] clk: imx: add configuration option for mmio clks A.s. Dong
  2018-10-14  8:07 ` [PATCH V4 02/11] clk: imx: scu: add scu clock common part A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-16 21:26   ` Stephen Boyd
  2018-10-14  8:07 ` [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider A.s. Dong
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock divider.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structures/enums name update with imx_sc prefix
v1->v2:
 * move SCU clock API implementation into driver
---
 drivers/clk/imx/scu/Makefile          |   3 +-
 drivers/clk/imx/scu/clk-divider-scu.c | 176 ++++++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h         |  18 ++++
 3 files changed, 196 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-divider-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index 7dead13..7e360e2 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_MXC_CLK_SCU) += \
-	clk-scu.o
+	clk-scu.o \
+	clk-divider-scu.o
diff --git a/drivers/clk/imx/scu/clk-divider-scu.c b/drivers/clk/imx/scu/clk-divider-scu.c
new file mode 100644
index 0000000..51cb816
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-divider-scu.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+struct clk_divider_scu {
+	struct clk_hw	hw;
+	u32 rsrc_id;
+	u8 clk_type;
+};
+
+/* SCU Clock Protocol definitions */
+struct imx_sc_msg_req_set_clock_rate {
+	struct imx_sc_rpc_msg hdr;
+	u32 rate;
+	u16 resource;
+	u8 clk;
+} __packed;
+
+struct imx_sc_msg_req_get_clock_rate {
+	struct imx_sc_rpc_msg hdr;
+	u16 resource;
+	u8 clk;
+} __packed;
+
+struct imx_sc_msg_resp_get_clock_rate {
+	struct imx_sc_rpc_msg hdr;
+	u32 rate;
+} __packed;
+
+
+static inline struct clk_divider_scu *to_clk_divider_scu(struct clk_hw *hw)
+{
+	return container_of(hw, struct clk_divider_scu, hw);
+}
+
+/*
+ * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
+ * @hw: clock to get rate for
+ * @parent_rate: parent rate provided by common clock framework, not used
+ *
+ * Gets the current clock rate of a SCU clock. Returns the current
+ * clock rate, or zero in failure.
+ */
+static unsigned long clk_divider_scu_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct clk_divider_scu *div = to_clk_divider_scu(hw);
+	struct imx_sc_msg_req_get_clock_rate msg;
+	struct imx_sc_msg_resp_get_clock_rate *resp;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
+	hdr->func = (uint8_t)IMX_SC_PM_FUNC_GET_CLOCK_RATE;
+	hdr->size = 2;
+
+	msg.resource = div->rsrc_id;
+	msg.clk = div->clk_type;
+
+	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+	if (ret) {
+		pr_err("%s: failed to get clock rate %d\n",
+			clk_hw_get_name(hw), ret);
+		return 0;
+	}
+
+	resp = (struct imx_sc_msg_resp_get_clock_rate *)&msg;
+
+	return resp->rate;
+}
+
+/*
+ * clk_divider_scu_round_rate - Round clock rate for a SCU clock
+ * @hw: clock to round rate for
+ * @rate: rate to round
+ * @parent_rate: parent rate provided by common clock framework, not used
+ *
+ * Gets the current clock rate of a SCU clock. Returns the current
+ * clock rate, or zero in failure.
+ */
+static long clk_divider_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long *parent_rate)
+{
+	/*
+	 * Assume we support all the requested rate and let the SCU firmware
+	 * to handle the left work
+	 */
+	return rate;
+}
+
+/*
+ * clk_divider_scu_set_rate - Set rate for a SCU clock
+ * @hw: clock to change rate for
+ * @rate: target rate for the clock
+ * @parent_rate: rate of the clock parent, not used for SCU clocks
+ *
+ * Sets a clock frequency for a SCU clock. Returns the SCU
+ * protocol status.
+ */
+static int clk_divider_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct clk_divider_scu *div = to_clk_divider_scu(hw);
+	struct imx_sc_msg_req_set_clock_rate msg;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
+	hdr->func = (uint8_t)IMX_SC_PM_FUNC_SET_CLOCK_RATE;
+	hdr->size = 3;
+
+	msg.rate = rate;
+	msg.resource = div->rsrc_id;
+	msg.clk = div->clk_type;
+
+	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+	if (ret)
+		pr_err("%s: failed to set clock rate %ld : ret %d\n",
+			clk_hw_get_name(hw), rate, ret);
+
+	return 0;
+}
+
+static const struct clk_ops clk_divider_scu_ops = {
+	.recalc_rate = clk_divider_scu_recalc_rate,
+	.round_rate = clk_divider_scu_round_rate,
+	.set_rate = clk_divider_scu_set_rate,
+};
+
+struct clk_hw *imx_clk_register_divider_scu(const char *name,
+					    const char *parent_name,
+					    u32 rsrc_id,
+					    u8 clk_type)
+{
+	struct clk_divider_scu *div;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	div->rsrc_id = rsrc_id;
+	div->clk_type = clk_type;
+
+	init.name = name;
+	init.ops = &clk_divider_scu_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	div->hw.init = &init;
+
+	hw = &div->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(div);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index b964f35..e99af63 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -7,6 +7,7 @@
 #ifndef __IMX_CLK_SCU_H
 #define __IMX_CLK_SCU_H
 
+#include <linux/clk-provider.h>
 #include <linux/firmware/imx/sci.h>
 #include <linux/spinlock.h>
 
@@ -15,4 +16,21 @@ extern struct imx_sc_ipc *ccm_ipc_handle;
 
 int imx_clk_scu_init(void);
 
+struct clk_hw *imx_clk_register_divider_scu(const char *name,
+				const char *parent_name, u32 rsrc_id,
+				u8 clk_type);
+
+static inline struct clk_hw *imx_clk_divider_scu(const char *name,
+				u32 rsrc_id, u8 clk_type)
+{
+	return imx_clk_register_divider_scu(name, NULL, rsrc_id, clk_type);
+}
+
+static inline struct clk_hw *imx_clk_divider2_scu(const char *name,
+				const char *parent_name,
+				u32 rsrc_id, u8 clk_type)
+{
+	return imx_clk_register_divider_scu(name, parent_name, rsrc_id, clk_type);
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (2 preceding siblings ...)
  2018-10-14  8:07 ` [PATCH V4 03/11] clk: imx: scu: add scu clock divider A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-16 21:27   ` Stephen Boyd
  2018-10-14  8:07 ` [PATCH V4 05/11] clk: imx: scu: add scu clock gate A.s. Dong
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock gpr divider. Unlike the normal scu divider, such
dividers are controlled by GPR bits through SCU sc_misc_set_control
API.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structures name and api use update
v1->v2:
 * no changes except update headfile name
---
 drivers/clk/imx/scu/Makefile              |   3 +-
 drivers/clk/imx/scu/clk-divider-gpr-scu.c | 129 ++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h             |   3 +
 3 files changed, 134 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-divider-gpr-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index 7e360e2..9e7f4aa 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -2,4 +2,5 @@
 
 obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-scu.o \
-	clk-divider-scu.o
+	clk-divider-scu.o \
+	clk-divider-gpr-scu.o
diff --git a/drivers/clk/imx/scu/clk-divider-gpr-scu.c b/drivers/clk/imx/scu/clk-divider-gpr-scu.c
new file mode 100644
index 0000000..95c76dc
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-divider-gpr-scu.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+struct clk_divider_gpr_scu {
+	struct clk_hw	hw;
+	u32	rsrc_id;
+	u8	gpr_id;
+};
+
+static inline struct clk_divider_gpr_scu *to_clk_divider_gpr_scu(struct clk_hw *hw)
+{
+	return container_of(hw, struct clk_divider_gpr_scu, hw);
+}
+
+/*
+ * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
+ * @hw: clock to get rate for
+ * @parent_rate: parent rate provided by common clock framework
+ *
+ * Gets the current clock rate of a SCU clock. Returns the current
+ * clock rate, or zero in failure.
+ */
+static unsigned long clk_divider_gpr_scu_recalc_rate(struct clk_hw *hw,
+						     unsigned long parent_rate)
+{
+	struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
+	u32 val;
+	int ret;
+
+	ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+				      clk->gpr_id, &val);
+	if (ret) {
+		pr_err("%s: failed to get clock rate %d\n",
+			clk_hw_get_name(hw), ret);
+		return 0;
+	}
+
+	return val ? parent_rate / 2 : parent_rate;
+}
+
+/*
+ * clk_divider_scu_round_rate - Round clock rate for a SCU clock
+ * @hw: clock to round rate for
+ * @rate: rate to round
+ * @parent_rate: parent rate provided by common clock framework
+ *
+ * Round clock rate for a SCU clock according to parent rate
+ */
+static long clk_divider_gpr_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+					   unsigned long *prate)
+{
+	if (rate < *prate)
+		rate = *prate / 2;
+	else
+		rate = *prate;
+
+	return rate;
+}
+
+/*
+ * clk_divider_scu_set_rate - Set rate for a SCU clock
+ * @hw: clock to change rate for
+ * @rate: target rate for the clock
+ * @parent_rate: rate of the clock parent
+ *
+ * Sets a clock frequency for a SCU clock. Returns the SCU
+ * protocol status.
+ */
+static int clk_divider_gpr_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long parent_rate)
+{
+	struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
+	uint32_t val;
+
+	val = (rate < parent_rate) ? 1 : 0;
+
+	return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+				       clk->gpr_id, val);
+}
+
+static const struct clk_ops clk_divider_gpr_scu_ops = {
+	.recalc_rate = clk_divider_gpr_scu_recalc_rate,
+	.round_rate = clk_divider_gpr_scu_round_rate,
+	.set_rate = clk_divider_gpr_scu_set_rate,
+};
+
+struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
+				       u32 rsrc_id, u8 gpr_id)
+{
+	struct clk_divider_gpr_scu *div;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	div->rsrc_id = rsrc_id;
+	div->gpr_id = gpr_id;
+
+	init.name = name;
+	init.ops = &clk_divider_gpr_scu_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	div->hw.init = &init;
+
+	hw = &div->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(div);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index e99af63..f0796f3 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -33,4 +33,7 @@ static inline struct clk_hw *imx_clk_divider2_scu(const char *name,
 	return imx_clk_register_divider_scu(name, parent_name, rsrc_id, clk_type);
 }
 
+struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
+				u32 rsrc_id, u8 gpr_id);
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (3 preceding siblings ...)
  2018-10-14  8:07 ` [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-15  7:32   ` Sascha Hauer
  2018-10-14  8:07 ` [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate A.s. Dong
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock gate.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structure names and api usage update
v1->v2:
 * move SCU clock API implementation into driver
---
 drivers/clk/imx/scu/Makefile       |   3 +-
 drivers/clk/imx/scu/clk-gate-scu.c | 222 +++++++++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h      |  23 ++++
 3 files changed, 247 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-gate-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index 9e7f4aa..2abed17 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -3,4 +3,5 @@
 obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-scu.o \
 	clk-divider-scu.o \
-	clk-divider-gpr-scu.o
+	clk-divider-gpr-scu.o \
+	clk-gate-scu.o
diff --git a/drivers/clk/imx/scu/clk-gate-scu.c b/drivers/clk/imx/scu/clk-gate-scu.c
new file mode 100644
index 0000000..d86d2ee
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-gate-scu.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+/*
+ * basic gatable clock which can gate and ungate it's output
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - inherits rate from parent.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define CLK_GATE_SCU_LPCG_MASK		0x3
+#define CLK_GATE_SCU_LPCG_HW_SEL	BIT(0)
+#define CLK_GATE_SCU_LPCG_SW_SEL	BIT(1)
+
+struct clk_gate_scu {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8	bit_idx;
+	bool	hw_gate;
+	u32	rsrc_id;
+	u8	clk_type;
+};
+
+#define to_clk_gate_scu(_hw) container_of(_hw, struct clk_gate_scu, hw)
+
+/* SCU Clock Protocol definitions */
+struct imx_sc_msg_req_clock_enable {
+	struct imx_sc_rpc_msg hdr;
+	u16	resource;
+	u8	clk;
+	u8	enable;
+	u8	autog;
+} __packed;
+
+/* Write to the LPCG bits. */
+static int clk_gate_scu_enable(struct clk_hw *hw)
+{
+	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+	u32 reg;
+
+	if (gate->reg) {
+		reg = readl(gate->reg);
+		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
+		if (gate->hw_gate)
+			reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
+				CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
+		else
+			reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
+		writel(reg, gate->reg);
+	}
+
+	return 0;
+}
+
+static void clk_gate_scu_disable(struct clk_hw *hw)
+{
+	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+	u32 reg;
+
+	if (gate->reg) {
+		reg = readl(gate->reg);
+		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
+		writel(reg, gate->reg);
+	}
+}
+
+static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u32 resource,
+				   u8 clk, bool enable, bool autog)
+{
+	struct imx_sc_msg_req_clock_enable msg;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
+	hdr->func = (uint8_t)IMX_SC_PM_FUNC_CLOCK_ENABLE;
+	hdr->size = 3;
+
+	msg.resource = resource;
+	msg.clk = clk;
+	msg.enable = (uint8_t)enable;
+	msg.autog = (uint8_t)autog;
+
+	return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+}
+
+static int clk_gate_scu_prepare(struct clk_hw *hw)
+{
+	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+	int ret;
+
+	/* Enable the clock at the DSC slice level */
+	ret = sc_pm_clock_enable(ccm_ipc_handle, gate->rsrc_id,
+				 gate->clk_type, true, gate->hw_gate);
+	if (ret)
+		pr_err("%s: clk prepare failed %d\n", clk_hw_get_name(hw), ret);
+
+	return ret;
+}
+
+static void clk_gate_scu_unprepare(struct clk_hw *hw)
+{
+	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+	int ret;
+
+	ret = sc_pm_clock_enable(ccm_ipc_handle, gate->rsrc_id,
+				     gate->clk_type, false, false);
+	if (ret)
+		pr_err("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
+			ret);
+}
+
+static const struct clk_ops clk_gate_scu_ops = {
+	.prepare = clk_gate_scu_prepare,
+	.unprepare = clk_gate_scu_unprepare,
+	.enable = clk_gate_scu_enable,
+	.disable = clk_gate_scu_disable,
+};
+
+struct clk_hw *clk_register_gate_scu(const char *name, const char *parent_name,
+				     unsigned long flags, u32 rsrc_id,
+				     u8 clk_type, void __iomem *reg,
+				     u8 bit_idx, bool hw_gate)
+{
+	struct clk_gate_scu *gate;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->rsrc_id = rsrc_id;
+	gate->clk_type = clk_type;
+	if (reg) {
+		gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
+		if (!gate->reg) {
+			kfree(gate);
+			return ERR_PTR(-ENOMEM);
+		}
+	}
+
+	gate->bit_idx = bit_idx;
+	gate->hw_gate = hw_gate;
+
+	init.name = name;
+	init.ops = &clk_gate_scu_ops;
+	init.flags = flags;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		iounmap(gate->reg);
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+static const struct clk_ops clk_gate2_scu_ops = {
+	.enable = clk_gate_scu_enable,
+	.disable = clk_gate_scu_disable,
+};
+
+struct clk_hw *clk_register_gate2_scu(const char *name, const char *parent_name,
+				      unsigned long flags, void __iomem *reg,
+				      u8 bit_idx, bool hw_gate)
+{
+	struct clk_gate_scu *gate;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
+	if (!gate->reg) {
+		kfree(gate);
+		return ERR_PTR(-ENOMEM);
+	}
+	gate->bit_idx = bit_idx;
+	gate->hw_gate = hw_gate;
+
+	init.name = name;
+	init.ops = &clk_gate2_scu_ops;
+	init.flags = flags;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		iounmap(gate->reg);
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index f0796f3..4ff7837 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -36,4 +36,27 @@ static inline struct clk_hw *imx_clk_divider2_scu(const char *name,
 struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
 				u32 rsrc_id, u8 gpr_id);
 
+struct clk_hw *clk_register_gate_scu(const char *name, const char *parent_name,
+				unsigned long flags, u32 rsrc_id,
+				u8 clk_type, void __iomem *reg,
+				u8 bit_idx, bool hw_gate);
+
+struct clk_hw *clk_register_gate2_scu(const char *name, const char *parent_name,
+				unsigned long flags, void __iomem *reg,
+				u8 bit_idx, bool hw_gate);
+
+static inline struct clk_hw *imx_clk_gate_scu(const char *name, const char *parent,
+				u32 rsrc_id, u8 clk_type,
+				void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+	return clk_register_gate_scu(name, parent, CLK_SET_RATE_PARENT,
+				     rsrc_id, clk_type, reg, bit_idx, hw_gate);
+}
+
+static inline struct clk_hw *imx_clk_gate2_scu(const char *name, const char *parent,
+				void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+	return clk_register_gate2_scu(name, parent, 0, reg, bit_idx, hw_gate);
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (4 preceding siblings ...)
  2018-10-14  8:07 ` [PATCH V4 05/11] clk: imx: scu: add scu clock gate A.s. Dong
@ 2018-10-14  8:07 ` A.s. Dong
  2018-10-14  8:08 ` [PATCH V4 07/11] clk: imx: scu: add scu clock mux A.s. Dong
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:07 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock gpr gate. Unlike the normal scu gate, such
gates are controlled by GPR bits through SCU sc_misc_set_control
API.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structure name and api usage update
v1->v2:
 * no changes except update headfile name
---
 drivers/clk/imx/scu/Makefile           |  3 +-
 drivers/clk/imx/scu/clk-gate-gpr-scu.c | 87 ++++++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h          |  9 ++++
 3 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-gate-gpr-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index 2abed17..25d3511 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-scu.o \
 	clk-divider-scu.o \
 	clk-divider-gpr-scu.o \
-	clk-gate-scu.o
+	clk-gate-scu.o \
+	clk-gate-gpr-scu.o
diff --git a/drivers/clk/imx/scu/clk-gate-gpr-scu.c b/drivers/clk/imx/scu/clk-gate-gpr-scu.c
new file mode 100644
index 0000000..fd2700e
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-gate-gpr-scu.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+struct clk_gate_gpr_scu {
+	struct clk_hw hw;
+	u32	rsrc_id;
+	u8	gpr_id;
+
+	/* default: enable 1 disable 0 */
+	bool	invert;
+};
+
+#define to_clk_gate_gpr_scu(_hw) container_of(_hw, struct clk_gate_gpr_scu, hw)
+
+static int clk_gate_gpr_scu_enable(struct clk_hw *hw)
+{
+	struct clk_gate_gpr_scu *gate = to_clk_gate_gpr_scu(hw);
+	int ret;
+
+	ret = imx_sc_misc_set_control(ccm_ipc_handle, gate->rsrc_id,
+				      gate->gpr_id, !gate->invert);
+	if (ret)
+		pr_err("%s: clk enable failed %d\n", clk_hw_get_name(hw), ret);
+
+	return ret;
+}
+
+static void clk_gate_gpr_scu_disable(struct clk_hw *hw)
+{
+	struct clk_gate_gpr_scu *gate = to_clk_gate_gpr_scu(hw);
+	int ret;
+
+	ret  = imx_sc_misc_set_control(ccm_ipc_handle, gate->rsrc_id,
+				       gate->gpr_id, gate->invert);
+	if (ret)
+		pr_err("%s: clk disable failed %d\n", clk_hw_get_name(hw), ret);
+}
+
+static const struct clk_ops clk_gate_gpr_scu_ops = {
+	.enable = clk_gate_gpr_scu_enable,
+	.disable = clk_gate_gpr_scu_disable,
+};
+
+struct clk_hw *clk_register_gate_gpr_scu(const char *name, const char *parent_name,
+					 u32 rsrc_id, u8 gpr_id,
+					 bool invert_flag)
+{
+	struct clk_gate_gpr_scu *gate;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->rsrc_id = rsrc_id;
+	gate->gpr_id = gpr_id;
+	gate->invert = invert_flag;
+
+	init.name = name;
+	init.ops = &clk_gate_gpr_scu_ops;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index 4ff7837..56338ca 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -59,4 +59,13 @@ static inline struct clk_hw *imx_clk_gate2_scu(const char *name, const char *par
 	return clk_register_gate2_scu(name, parent, 0, reg, bit_idx, hw_gate);
 }
 
+struct clk_hw *clk_register_gate_gpr_scu(const char *name, const char *parent_name,
+				u32 rsrc_id, u8 gpr_id, bool invert_flag);
+
+static inline struct clk_hw *imx_clk_gate_gpr_scu(const char *name, const char *parent,
+				u32 rsrc_id, u8 gpr_id, bool invert_flag)
+{
+	return clk_register_gate_gpr_scu(name, parent, rsrc_id, gpr_id, invert_flag);
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 07/11] clk: imx: scu: add scu clock mux
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (5 preceding siblings ...)
  2018-10-14  8:07 ` [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate A.s. Dong
@ 2018-10-14  8:08 ` A.s. Dong
  2018-10-14  8:08 ` [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux A.s. Dong
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:08 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock mux.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structure name and api usage update
v1->v2:
 * move SCU clock API implementation into driver
---
 drivers/clk/imx/scu/Makefile      |   3 +-
 drivers/clk/imx/scu/clk-mux-scu.c | 130 ++++++++++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h     |  13 ++++
 3 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-mux-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index 25d3511..aee56bf 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-divider-scu.o \
 	clk-divider-gpr-scu.o \
 	clk-gate-scu.o \
-	clk-gate-gpr-scu.o
+	clk-gate-gpr-scu.o \
+	clk-mux-scu.o
diff --git a/drivers/clk/imx/scu/clk-mux-scu.c b/drivers/clk/imx/scu/clk-mux-scu.c
new file mode 100644
index 0000000..fdef58d
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-mux-scu.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+struct clk_mux_scu {
+	struct clk_hw hw;
+	u32 rsrc_id;
+	u8 clk_type;
+};
+
+#define to_clk_mux_scu(_hw) container_of(_hw, struct clk_mux_scu, hw)
+
+
+/* SCU Clock Protocol definitions */
+struct imx_sc_msg_req_set_clock_parent {
+	struct imx_sc_rpc_msg hdr;
+	u16 resource;
+	u8 clk;
+	u8 parent;
+} __packed;
+
+struct imx_sc_msg_req_get_clock_parent {
+	struct imx_sc_rpc_msg hdr;
+	u16 resource;
+	u8 clk;
+} __packed;
+
+struct imx_sc_msg_resp_get_clock_parent {
+	struct imx_sc_rpc_msg hdr;
+	u8 parent;
+} __packed;
+
+static u8 clk_mux_scu_get_parent(struct clk_hw *hw)
+{
+	struct clk_mux_scu *mux = to_clk_mux_scu(hw);
+	struct imx_sc_msg_req_get_clock_parent msg;
+	struct imx_sc_msg_resp_get_clock_parent *resp;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
+	hdr->func = (uint8_t)IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
+	hdr->size = 2;
+
+	msg.resource = mux->rsrc_id;
+	msg.clk = mux->clk_type;
+
+	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+	if (ret) {
+		pr_err("%s: failed to get clock parent %d\n",
+			clk_hw_get_name(hw), ret);
+		return ret;
+	}
+
+	resp = (struct imx_sc_msg_resp_get_clock_parent *)&msg;
+
+	return resp->parent;
+}
+
+static int clk_mux_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux_scu *mux = to_clk_mux_scu(hw);
+	struct imx_sc_msg_req_set_clock_parent msg;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
+	hdr->func = (uint8_t)IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
+	hdr->size = 2;
+
+	msg.resource = mux->rsrc_id;
+	msg.clk = mux->clk_type;
+	msg.parent = index;
+
+	ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+	if (ret)
+		pr_err("%s: failed to set clock parent %d : ret %d\n",
+			clk_hw_get_name(hw), index, ret);
+
+	return 0;
+}
+
+static const struct clk_ops clk_mux_scu_ops = {
+	.get_parent = clk_mux_scu_get_parent,
+	.set_parent = clk_mux_scu_set_parent,
+};
+
+struct clk_hw *clk_register_mux_scu(const char *name, const char * const *parents,
+				    int num_parents, unsigned long flags,
+				    u32 rsrc_id, u8 clk_type)
+{
+	struct clk_init_data init;
+	struct clk_mux_scu *mux;
+	struct clk_hw *hw;
+	int ret;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_mux_scu_ops;
+	init.parent_names = parents;
+	init.num_parents = num_parents;
+
+	mux->hw.init = &init;
+	mux->rsrc_id = rsrc_id;
+	mux->clk_type = clk_type;
+
+	hw = &mux->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(mux);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index 56338ca..b2b56d3 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -68,4 +68,17 @@ static inline struct clk_hw *imx_clk_gate_gpr_scu(const char *name, const char *
 	return clk_register_gate_gpr_scu(name, parent, rsrc_id, gpr_id, invert_flag);
 }
 
+struct clk_hw *clk_register_mux_scu(const char *name, const char * const *parents,
+			int num_parents, unsigned long flags,
+			u32 rsrc_id, u8 clk_type);
+
+static inline struct clk_hw *imx_clk_mux_scu(const char *name,
+			const char * const *parents, int num_parents,
+			u32 rsrc_id, u8 clk_type)
+{
+	return clk_register_mux_scu(name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT, rsrc_id,
+			clk_type);
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (6 preceding siblings ...)
  2018-10-14  8:08 ` [PATCH V4 07/11] clk: imx: scu: add scu clock mux A.s. Dong
@ 2018-10-14  8:08 ` A.s. Dong
  2018-10-16 21:30   ` Stephen Boyd
  2018-10-14  8:08 ` [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions A.s. Dong
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:08 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add scu based clock gpr mux. Unlike the normal scu mux, such
muxes are controlled by GPR bits through SCU sc_misc_set_control
API.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * structure name and api usage update
v1->v2:
 * no changes except headfile name updated
---
 drivers/clk/imx/scu/Makefile          |  3 +-
 drivers/clk/imx/scu/clk-mux-gpr-scu.c | 90 +++++++++++++++++++++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h         | 11 +++++
 3 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/scu/clk-mux-gpr-scu.c

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index aee56bf..a76ed78 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-divider-gpr-scu.o \
 	clk-gate-scu.o \
 	clk-gate-gpr-scu.o \
-	clk-mux-scu.o
+	clk-mux-scu.o \
+	clk-mux-gpr-scu.o
diff --git a/drivers/clk/imx/scu/clk-mux-gpr-scu.c b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
new file mode 100644
index 0000000..2ad7a80
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+
+struct clk_mux_gpr_scu {
+	struct clk_hw hw;
+	u32	rsrc_id;
+	u8	gpr_id;
+};
+
+#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct clk_mux_gpr_scu, hw)
+
+static u8 clk_mux_gpr_scu_get_parent(struct clk_hw *hw)
+{
+	struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
+	u32 val = 0;
+	int ret;
+
+	ret = imx_sc_misc_get_control(ccm_ipc_handle, gpr_mux->rsrc_id,
+				      gpr_mux->gpr_id, &val);
+	if (ret) {
+		pr_err("%s: failed to get clock parent %d\n",
+			clk_hw_get_name(hw), ret);
+		return 0;
+	}
+
+	return (u8)val;
+}
+
+static int clk_mux_gpr_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
+	int ret;
+
+	ret = imx_sc_misc_set_control(ccm_ipc_handle, gpr_mux->rsrc_id,
+				      gpr_mux->gpr_id, index);
+	if (ret)
+		pr_err("%s: failed to set clock parent %d\n",
+			clk_hw_get_name(hw), ret);
+
+	return ret;
+}
+
+static const struct clk_ops clk_mux_gpr_scu_ops = {
+	.get_parent = clk_mux_gpr_scu_get_parent,
+	.set_parent = clk_mux_gpr_scu_set_parent,
+};
+
+struct clk_hw *clk_register_mux_gpr_scu(const char *name, const char * const *parents,
+					int num_parents, unsigned long flags,
+					u32 rsrc_id, u8 gpr_id)
+{
+	struct clk_mux_gpr_scu *mux;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_mux_gpr_scu_ops;
+	init.parent_names = parents;
+	init.num_parents = num_parents;
+	init.flags = flags;
+
+	mux->hw.init = &init;
+	mux->rsrc_id = rsrc_id;
+	mux->gpr_id = gpr_id;
+
+	hw = &mux->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(mux);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index b2b56d3..8cc58e4 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -81,4 +81,15 @@ static inline struct clk_hw *imx_clk_mux_scu(const char *name,
 			clk_type);
 }
 
+struct clk_hw *clk_register_mux_gpr_scu(const char *name, const char * const *parents,
+			int num_parents, unsigned long flags,
+			u32 rsrc_id, u8 gpr_id);
+
+static inline struct clk_hw *imx_clk_mux_gpr_scu(const char *name, const char * const *parents,
+			int num_parents, u32 rsrc_id, u8 gpr_id)
+{
+	return clk_register_mux_gpr_scu(name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT, rsrc_id, gpr_id);
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (7 preceding siblings ...)
  2018-10-14  8:08 ` [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux A.s. Dong
@ 2018-10-14  8:08 ` A.s. Dong
  2018-10-16 21:32   ` Stephen Boyd
  2018-10-14  8:08 ` [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function A.s. Dong
  2018-10-14  8:08 ` [PATCH V4 11/11] clk: imx: add imx8qxp clk driver A.s. Dong
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:08 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

This may be used by both mmio and scu clks. So let's put it
into a common file.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 drivers/clk/imx/clk-common.h  | 16 ++++++++++++++++
 drivers/clk/imx/scu/clk-scu.h |  2 ++
 2 files changed, 18 insertions(+)
 create mode 100644 drivers/clk/imx/clk-common.h

diff --git a/drivers/clk/imx/clk-common.h b/drivers/clk/imx/clk-common.h
new file mode 100644
index 0000000..e3634a5
--- /dev/null
+++ b/drivers/clk/imx/clk-common.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ */
+
+#ifndef __IMX_CLK_COMMON_H
+#define __IMX_CLK_COMMON_H
+
+#include <linux/clk-provider.h>
+
+static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
+{
+	return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+#endif /* __IMX_CLK_COMMON_H */
diff --git a/drivers/clk/imx/scu/clk-scu.h b/drivers/clk/imx/scu/clk-scu.h
index 8cc58e4..4eeb252 100644
--- a/drivers/clk/imx/scu/clk-scu.h
+++ b/drivers/clk/imx/scu/clk-scu.h
@@ -11,6 +11,8 @@
 #include <linux/firmware/imx/sci.h>
 #include <linux/spinlock.h>
 
+#include "../clk-common.h"
+
 extern spinlock_t imx_ccm_lock;
 extern struct imx_sc_ipc *ccm_ipc_handle;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (8 preceding siblings ...)
  2018-10-14  8:08 ` [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions A.s. Dong
@ 2018-10-14  8:08 ` A.s. Dong
  2018-10-16 21:34   ` Stephen Boyd
  2018-10-14  8:08 ` [PATCH V4 11/11] clk: imx: add imx8qxp clk driver A.s. Dong
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:08 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add imx_check_clk_hws helper function

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 drivers/clk/imx/clk-common.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/clk/imx/clk-common.h b/drivers/clk/imx/clk-common.h
index e3634a5..01550fd 100644
--- a/drivers/clk/imx/clk-common.h
+++ b/drivers/clk/imx/clk-common.h
@@ -13,4 +13,15 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
 	return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
+static inline void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		if (IS_ERR(clks[i]))
+			pr_err("i.MX clk %u: register failed with %ld\n",
+				i, PTR_ERR(clks[i]));
+	}
+}
+
 #endif /* __IMX_CLK_COMMON_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
  2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
                   ` (9 preceding siblings ...)
  2018-10-14  8:08 ` [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function A.s. Dong
@ 2018-10-14  8:08 ` A.s. Dong
  2018-10-16 21:38   ` Stephen Boyd
  10 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-14  8:08 UTC (permalink / raw)
  To: linux-clk
  Cc: linux-arm-kernel, sboyd, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Add imx8qxp clk driver which is based on SCU firmware clock service.

Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
ChangeLog:
v3->v4:
 * scu headfile path update
v2->v3:
 * enum name update
v1->v2:
 * no changes except headfile name updated
---
 drivers/clk/imx/scu/Makefile              |   2 +
 drivers/clk/imx/scu/clk-imx8qxp.c         | 425 ++++++++++++++++++++++++++++++
 include/dt-bindings/clock/imx8qxp-clock.h | 362 +++++++++++++++++++++++++
 include/soc/imx/imx8qxp/lpcg.h            | 186 +++++++++++++
 4 files changed, 975 insertions(+)
 create mode 100644 drivers/clk/imx/scu/clk-imx8qxp.c
 create mode 100644 include/dt-bindings/clock/imx8qxp-clock.h
 create mode 100644 include/soc/imx/imx8qxp/lpcg.h

diff --git a/drivers/clk/imx/scu/Makefile b/drivers/clk/imx/scu/Makefile
index a76ed78..68e2d7f 100644
--- a/drivers/clk/imx/scu/Makefile
+++ b/drivers/clk/imx/scu/Makefile
@@ -8,3 +8,5 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
 	clk-gate-gpr-scu.o \
 	clk-mux-scu.o \
 	clk-mux-gpr-scu.o
+
+obj-$(CONFIG_SOC_IMX8QXP)	+= clk-imx8qxp.o
diff --git a/drivers/clk/imx/scu/clk-imx8qxp.c b/drivers/clk/imx/scu/clk-imx8qxp.c
new file mode 100644
index 0000000..958c26d
--- /dev/null
+++ b/drivers/clk/imx/scu/clk-imx8qxp.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *	Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/clock/imx8qxp-clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <soc/imx/imx8qxp/lpcg.h>
+
+#include "clk-scu.h"
+
+static struct clk_hw_onecell_data *clk_data;
+
+static const char * const enet_sels[] = { "enet_25MHz", "enet_125MHz", };
+static const char * const enet0_rmii_tx_sels[] = { "enet0_ref_div", "dummy", };
+static const char * const enet1_rmii_tx_sels[] = { "enet1_ref_div", "dummy", };
+
+static int imx8qxp_clk_probe(struct platform_device *pdev)
+{
+	struct device_node *ccm_node = pdev->dev.of_node;
+	struct clk_hw **clks;
+	int ret;
+
+	ret = imx_clk_scu_init();
+	if (ret)
+		return ret;
+
+	clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
+				sizeof(*clk_data->hws) * IMX8QXP_CLK_END,
+				GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->num = IMX8QXP_CLK_END;
+	clks = clk_data->hws;
+
+	/* Fixed clocks */
+	clks[IMX8QXP_CLK_DUMMY]		= imx_clk_hw_fixed("dummy", 0);
+	clks[IMX8QXP_24MHZ]		= imx_clk_hw_fixed("xtal_24MHz", 24000000);
+	clks[IMX8QXP_GPT_3M]		= imx_clk_hw_fixed("gpt_3m", 3000000);
+	clks[IMX8QXP_32KHZ]		= imx_clk_hw_fixed("xtal_32KHz", 32768);
+
+	/* ARM core */
+	clks[IMX8QXP_A35_DIV]		= imx_clk_divider_scu("a35_div", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+
+	clks[IMX8QXP_IPG_DMA_CLK_ROOT]	= imx_clk_hw_fixed("ipg_dma_clk_root", 120000000);
+	clks[IMX8QXP_AXI_CONN_CLK_ROOT] = imx_clk_hw_fixed("axi_conn_clk_root", 333333333);
+	clks[IMX8QXP_AHB_CONN_CLK_ROOT] = imx_clk_hw_fixed("ahb_conn_clk_root", 166666666);
+	clks[IMX8QXP_IPG_CONN_CLK_ROOT] = imx_clk_hw_fixed("ipg_conn_clk_root", 83333333);
+	clks[IMX8QXP_DC_AXI_EXT_CLK]	= imx_clk_hw_fixed("axi_ext_dc_clk_root", 800000000);
+	clks[IMX8QXP_DC_AXI_INT_CLK]	= imx_clk_hw_fixed("axi_int_dc_clk_root", 400000000);
+	clks[IMX8QXP_DC_CFG_CLK]	= imx_clk_hw_fixed("cfg_dc_clk_root", 100000000);
+	clks[IMX8QXP_MIPI_IPG_CLK]	= imx_clk_hw_fixed("ipg_mipi_clk_root", 120000000);
+	clks[IMX8QXP_IMG_AXI_CLK]	= imx_clk_hw_fixed("axi_img_clk_root", 400000000);
+	clks[IMX8QXP_IMG_IPG_CLK]	= imx_clk_hw_fixed("ipg_img_clk_root", 200000000);
+	clks[IMX8QXP_IMG_PXL_CLK]	= imx_clk_hw_fixed("pxl_img_clk_root", 600000000);
+	clks[IMX8QXP_HSIO_AXI_CLK]	= imx_clk_hw_fixed("axi_hsio_clk_root", 400000000);
+	clks[IMX8QXP_HSIO_PER_CLK]	= imx_clk_hw_fixed("per_hsio_clk_root", 133333333);
+
+	clks[IMX8QXP_UART0_DIV]		= imx_clk_divider_scu("uart0_div", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_UART0_IPG_CLK]	= imx_clk_gate2_scu("uart0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_0_LPCG), 16, 0);
+	clks[IMX8QXP_UART0_CLK]		= imx_clk_gate_scu("uart0_clk", "uart0_div", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_0_LPCG), 0, 0);
+
+	clks[IMX8QXP_GPU0_CORE_DIV]	= imx_clk_divider_scu("gpu_core0_div", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_GPU0_SHADER_DIV]	= imx_clk_divider_scu("gpu_shader0_div", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
+	clks[IMX8QXP_GPU0_CORE_CLK]	= imx_clk_gate_scu("gpu_core0_clk", "gpu_core0_div", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, NULL, 0, 0);
+	clks[IMX8QXP_GPU0_SHADER_CLK]	= imx_clk_gate_scu("gpu_shader0_clk", "gpu_shader0_div", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, NULL, 0, 0);
+
+	/* LSIO SS */
+	clks[IMX8QXP_LSIO_MEM_CLK]	= imx_clk_hw_fixed("lsio_mem_clk_root", 100000000);
+	clks[IMX8QXP_LSIO_BUS_CLK]	= imx_clk_hw_fixed("lsio_bus_clk_root", 200000000);
+
+	clks[IMX8QXP_LSIO_PWM0_DIV]		= imx_clk_divider_scu("pwm_0_div", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM0_IPG_S_CLK]	= imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM0_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_0_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM0_HF_CLK]		= imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM0_CLK]		= imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM1_DIV]		= imx_clk_divider_scu("pwm_1_div", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM1_IPG_S_CLK]	= imx_clk_gate_scu("pwm_1_ipg_s_clk", "pwm_1_div", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM1_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_1_ipg_slv_clk", "pwm_1_ipg_s_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM1_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_1_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_1_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM1_HF_CLK]		= imx_clk_gate_scu("pwm_1_hf_clk", "pwm_1_ipg_slv_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM1_CLK]		= imx_clk_gate_scu("pwm_1_clk", "pwm_1_ipg_slv_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM2_DIV]		= imx_clk_divider_scu("pwm_2_div", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM2_IPG_S_CLK]	= imx_clk_gate_scu("pwm_2_ipg_s_clk", "pwm_2_div", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM2_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_2_ipg_slv_clk", "pwm_2_ipg_s_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM2_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_2_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_2_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM2_HF_CLK]		= imx_clk_gate_scu("pwm_2_hf_clk", "pwm_2_ipg_slv_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM2_CLK]		= imx_clk_gate_scu("pwm_2_clk", "pwm_2_ipg_slv_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM3_DIV]		= imx_clk_divider_scu("pwm_3_div", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM3_IPG_S_CLK]	= imx_clk_gate_scu("pwm_3_ipg_s_clk", "pwm_3_div", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM3_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_3_ipg_slv_clk", "pwm_3_ipg_s_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM3_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_3_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_3_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM3_HF_CLK]		= imx_clk_gate_scu("pwm_3_hf_clk", "pwm_3_ipg_slv_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM3_CLK]		= imx_clk_gate_scu("pwm_3_clk", "pwm_3_ipg_slv_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM4_DIV]		= imx_clk_divider_scu("pwm_4_div", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM4_IPG_S_CLK]	= imx_clk_gate_scu("pwm_4_ipg_s_clk", "pwm_4_div", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM4_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_4_ipg_slv_clk", "pwm_4_ipg_s_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM4_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_4_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_4_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM4_HF_CLK]		= imx_clk_gate_scu("pwm_4_hf_clk", "pwm_4_ipg_slv_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM4_CLK]		= imx_clk_gate_scu("pwm_4_clk", "pwm_4_ipg_slv_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM5_DIV]		= imx_clk_divider_scu("pwm_5_div", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM5_IPG_S_CLK]	= imx_clk_gate_scu("pwm_5_ipg_s_clk", "pwm_5_div", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM5_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_5_ipg_slv_clk", "pwm_5_ipg_s_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM5_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_5_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_5_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM5_HF_CLK]		= imx_clk_gate_scu("pwm_5_hf_clk", "pwm_5_ipg_slv_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM5_CLK]		= imx_clk_gate_scu("pwm_5_clk", "pwm_5_ipg_slv_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM6_DIV]		= imx_clk_divider_scu("pwm_6_div", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM6_IPG_S_CLK]	= imx_clk_gate_scu("pwm_6_ipg_s_clk", "pwm_6_div", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM6_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_6_ipg_slv_clk", "pwm_6_ipg_s_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM6_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_6_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_6_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM6_HF_CLK]		= imx_clk_gate_scu("pwm_6_hf_clk", "pwm_6_ipg_slv_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM6_CLK]		= imx_clk_gate_scu("pwm_6_clk", "pwm_6_ipg_slv_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_PWM7_DIV]		= imx_clk_divider_scu("pwm_7_div", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_PWM7_IPG_S_CLK]	= imx_clk_gate_scu("pwm_7_ipg_s_clk", "pwm_7_div", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_PWM7_IPG_SLV_CLK]	= imx_clk_gate_scu("pwm_7_ipg_slv_clk", "pwm_7_ipg_s_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_PWM7_IPG_MSTR_CLK]	= imx_clk_gate2_scu("pwm_7_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_7_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_PWM7_HF_CLK]		= imx_clk_gate_scu("pwm_7_hf_clk", "pwm_7_ipg_slv_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_PWM7_CLK]		= imx_clk_gate_scu("pwm_7_clk", "pwm_7_ipg_slv_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT0_DIV]		= imx_clk_divider_scu("gpt_0_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_GPT0_IPG_S_CLK]	= imx_clk_gate_scu("gpt_0_ipg_s_clk", "gpt_0_div", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPT0_IPG_SLV_CLK]	= imx_clk_gate_scu("gpt_0_ipg_slv_clk", "gpt_0_ipg_s_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_GPT0_CLK]		= imx_clk_gate_scu("gpt_0_clk", "gpt_0_ipg_slv_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT0_IPG_MSTR_CLK]	= imx_clk_gate2_scu("gpt_0_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_0_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_GPT0_HF_CLK]		= imx_clk_gate_scu("gpt_0_hf_clk", "gpt_0_ipg_slv_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_GPT1_DIV]		= imx_clk_divider_scu("gpt_1_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_GPT1_IPG_S_CLK]	= imx_clk_gate_scu("gpt_1_ipg_s_clk", "gpt_1_div", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPT1_IPG_SLV_CLK]	= imx_clk_gate_scu("gpt_1_ipg_slv_clk", "gpt_1_ipg_s_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_GPT1_CLK]		= imx_clk_gate_scu("gpt_1_clk", "gpt_1_ipg_slv_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT1_HF_CLK]		= imx_clk_gate_scu("gpt_1_hf_clk", "gpt_1_ipg_slv_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_GPT1_IPG_MSTR_CLK]	= imx_clk_gate2_scu("gpt_1_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_1_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_GPT2_DIV]		= imx_clk_divider_scu("gpt_2_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_GPT2_IPG_S_CLK]	= imx_clk_gate_scu("gpt_2_ipg_s_clk", "gpt_2_div", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPT2_IPG_SLV_CLK]	= imx_clk_gate_scu("gpt_2_ipg_slv_clk", "gpt_2_ipg_s_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_GPT2_CLK]		= imx_clk_gate_scu("gpt_2_clk", "gpt_2_ipg_slv_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT2_HF_CLK]		= imx_clk_gate_scu("gpt_2_hf_clk", "gpt_2_div", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_GPT2_IPG_MSTR_CLK]	= imx_clk_gate2_scu("gpt_2_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_2_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_GPT3_DIV]		= imx_clk_divider_scu("gpt_3_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_GPT3_IPG_S_CLK]	= imx_clk_gate_scu("gpt_3_ipg_s_clk", "gpt_3_div", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPT3_IPG_SLV_CLK]	= imx_clk_gate_scu("gpt_3_ipg_slv_clk", "gpt_3_ipg_s_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_GPT3_CLK]		= imx_clk_gate_scu("gpt_3_clk", "gpt_3_ipg_slv_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT3_HF_CLK]		= imx_clk_gate_scu("gpt_3_hf_clk", "gpt_3_ipg_slv_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_GPT3_IPG_MSTR_CLK]	= imx_clk_gate2_scu("gpt_3_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_3_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_GPT4_DIV]		= imx_clk_divider_scu("gpt_4_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_GPT4_IPG_S_CLK]	= imx_clk_gate_scu("gpt_4_ipg_s_clk", "gpt_4_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPT4_IPG_SLV_CLK]	= imx_clk_gate_scu("gpt_4_ipg_slv_clk", "gpt_4_ipg_s_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_GPT4_CLK]		= imx_clk_gate_scu("gpt_4_clk", "gpt_4_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPT4_HF_CLK]		= imx_clk_gate_scu("gpt_4_hf_clk", "gpt_4_div", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 4, 0);
+	clks[IMX8QXP_LSIO_GPT4_IPG_MSTR_CLK]	= imx_clk_gate2_scu("gpt_4_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_4_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_FSPI0_DIV]		= imx_clk_divider_scu("fspi_0_div", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_FSPI0_HCLK]		= imx_clk_gate2_scu("fspi0_hclk_clk", "lsio_mem_clk_root", (void __iomem *)(FSPI_0_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_FSPI0_IPG_S_CLK]	= imx_clk_gate2_scu("fspi0_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(FSPI_0_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_FSPI0_IPG_CLK]	= imx_clk_gate2_scu("fspi0_ipg_clk", "fspi0_ipg_s_clk", (void __iomem *)(FSPI_0_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_FSPI0_CLK]		= imx_clk_gate_scu("fspi_0_clk", "fspi_0_div", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, (void __iomem *)(FSPI_0_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_FSPI1_DIV]		= imx_clk_divider_scu("fspi_1_div", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LSIO_FSPI1_HCLK]		= imx_clk_gate2_scu("fspi1_hclk_clk", "lsio_mem_clk_root", (void __iomem *)(FSPI_1_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_FSPI1_IPG_S_CLK]	= imx_clk_gate2_scu("fspi1_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(FSPI_1_LPCG), 0x18, 0);
+	clks[IMX8QXP_LSIO_FSPI1_IPG_CLK]	= imx_clk_gate2_scu("fspi1_ipg_clk", "fspi1_ipg_s_clk", (void __iomem *)(FSPI_1_LPCG), 0x14, 0);
+	clks[IMX8QXP_LSIO_FSPI1_CLK]		= imx_clk_gate_scu("fspi_1_clk", "fspi_1_div", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, (void __iomem *)(FSPI_1_LPCG), 0, 0);
+	clks[IMX8QXP_LSIO_GPIO0_IPG_S_CLK]	= imx_clk_gate2_scu("gpio0_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_0_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO1_IPG_S_CLK]	= imx_clk_gate2_scu("gpio1_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_1_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO2_IPG_S_CLK]	= imx_clk_gate2_scu("gpio2_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_2_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO3_IPG_S_CLK]	= imx_clk_gate2_scu("gpio3_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_3_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO4_IPG_S_CLK]	= imx_clk_gate2_scu("gpio4_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_4_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO5_IPG_S_CLK]	= imx_clk_gate2_scu("gpio5_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_5_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO6_IPG_S_CLK]	= imx_clk_gate2_scu("gpio6_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_6_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_GPIO7_IPG_S_CLK]	= imx_clk_gate2_scu("gpio7_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(GPIO_7_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_ROMCP_REG_CLK]	= imx_clk_gate2_scu("romcp_reg_clk", "lsio_bus_clk_root", (void __iomem *)(ROMCP_LPCG), 0x10, 0);
+	clks[IMX8QXP_LSIO_ROMCP_CLK]		= imx_clk_gate2_scu("romcp_clk", "lsio_mem_clk_root", (void __iomem *)(ROMCP_LPCG), 0x0, 0);
+	clks[IMX8QXP_LSIO_96KROM_CLK]		= imx_clk_gate2_scu("96krom_clk", "lsio_mem_clk_root", (void __iomem *)(ROMCP_LPCG), 0x4, 0);
+	clks[IMX8QXP_LSIO_OCRAM_MEM_CLK]	= imx_clk_gate2_scu("ocram_lk", "lsio_mem_clk_root", (void __iomem *)(OCRAM_LPCG), 0x4, 0);
+	clks[IMX8QXP_LSIO_OCRAM_CTRL_CLK]	= imx_clk_gate2_scu("ocram_ctrl_clk", "lsio_mem_clk_root", (void __iomem *)(OCRAM_LPCG), 0x0, 0);
+
+	/* ADMA SS */
+	clks[IMX8QXP_UART1_IPG_CLK]	= imx_clk_gate2_scu("uart1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_1_LPCG), 16, 0);
+	clks[IMX8QXP_UART2_IPG_CLK]	= imx_clk_gate2_scu("uart2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_2_LPCG), 16, 0);
+	clks[IMX8QXP_UART3_IPG_CLK]	= imx_clk_gate2_scu("uart3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_3_LPCG), 16, 0);
+	clks[IMX8QXP_UART1_DIV]		= imx_clk_divider_scu("uart1_div", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_UART2_DIV]		= imx_clk_divider_scu("uart2_div", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_UART3_DIV]		= imx_clk_divider_scu("uart3_div", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_UART1_CLK]		= imx_clk_gate_scu("uart1_clk", "uart1_div", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_1_LPCG), 0, 0);
+	clks[IMX8QXP_UART2_CLK]		= imx_clk_gate_scu("uart2_clk", "uart2_div", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_2_LPCG), 0, 0);
+	clks[IMX8QXP_UART3_CLK]		= imx_clk_gate_scu("uart3_clk", "uart3_div", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_3_LPCG), 0, 0);
+	clks[IMX8QXP_SPI0_IPG_CLK]	= imx_clk_gate2_scu("spi0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_0_LPCG), 16, 0);
+	clks[IMX8QXP_SPI1_IPG_CLK]	= imx_clk_gate2_scu("spi1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_1_LPCG), 16, 0);
+	clks[IMX8QXP_SPI2_IPG_CLK]	= imx_clk_gate2_scu("spi2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_2_LPCG), 16, 0);
+	clks[IMX8QXP_SPI3_IPG_CLK]	= imx_clk_gate2_scu("spi3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_3_LPCG), 16, 0);
+	clks[IMX8QXP_SPI0_DIV]		= imx_clk_divider_scu("spi0_div", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SPI1_DIV]		= imx_clk_divider_scu("spi1_div", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SPI2_DIV]		= imx_clk_divider_scu("spi2_div", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SPI3_DIV]		= imx_clk_divider_scu("spi3_div", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SPI0_CLK]		= imx_clk_gate_scu("spi0_clk", "spi0_div", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, (void __iomem *)(LPSPI_0_LPCG), 0, 0);
+	clks[IMX8QXP_SPI1_CLK]		= imx_clk_gate_scu("spi1_clk", "spi1_div", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, (void __iomem *)(LPSPI_1_LPCG), 0, 0);
+	clks[IMX8QXP_SPI2_CLK]		= imx_clk_gate_scu("spi2_clk", "spi2_div", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, (void __iomem *)(LPSPI_2_LPCG), 0, 0);
+	clks[IMX8QXP_SPI3_CLK]		= imx_clk_gate_scu("spi3_clk", "spi3_div", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, (void __iomem *)(LPSPI_3_LPCG), 0, 0);
+	clks[IMX8QXP_CAN0_IPG_CHI_CLK]	= imx_clk_gate2_scu("can0_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_0_LPCG), 20, 0);
+	clks[IMX8QXP_CAN0_IPG_CLK]	= imx_clk_gate2_scu("can0_ipg_clk", "can0_ipg_chi_clk", (void __iomem *)(FLEX_CAN_0_LPCG), 16, 0);
+	clks[IMX8QXP_CAN1_IPG_CHI_CLK]	= imx_clk_gate2_scu("can1_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_1_LPCG), 20, 0);
+	clks[IMX8QXP_CAN1_IPG_CLK]	= imx_clk_gate2_scu("can1_ipg_clk", "can1_ipg_chi_clk", (void __iomem *)(FLEX_CAN_1_LPCG), 16, 0);
+	clks[IMX8QXP_CAN2_IPG_CHI_CLK]	= imx_clk_gate2_scu("can2_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_2_LPCG), 20, 0);
+	clks[IMX8QXP_CAN2_IPG_CLK]	= imx_clk_gate2_scu("can2_ipg_clk", "can2_ipg_chi_clk", (void __iomem *)(FLEX_CAN_2_LPCG), 16, 0);
+	clks[IMX8QXP_CAN0_DIV]		= imx_clk_divider_scu("can0_div", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CAN1_DIV]		= imx_clk_divider_scu("can1_div", IMX_SC_R_CAN_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CAN2_DIV]		= imx_clk_divider_scu("can2_div", IMX_SC_R_CAN_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CAN0_CLK]		= imx_clk_gate_scu("can0_clk", "can0_div", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_0_LPCG), 0, 0);
+	clks[IMX8QXP_CAN1_CLK]		= imx_clk_gate_scu("can1_clk", "can1_div", IMX_SC_R_CAN_1, IMX_SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_1_LPCG), 0, 0);
+	clks[IMX8QXP_CAN2_CLK]		= imx_clk_gate_scu("can2_clk", "can2_div", IMX_SC_R_CAN_2, IMX_SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_2_LPCG), 0, 0);
+	clks[IMX8QXP_I2C0_IPG_CLK]	= imx_clk_gate2_scu("i2c0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_0_LPCG), 16, 0);
+	clks[IMX8QXP_I2C1_IPG_CLK]	= imx_clk_gate2_scu("i2c1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_1_LPCG), 16, 0);
+	clks[IMX8QXP_I2C2_IPG_CLK]	= imx_clk_gate2_scu("i2c2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_2_LPCG), 16, 0);
+	clks[IMX8QXP_I2C3_IPG_CLK]	= imx_clk_gate2_scu("i2c3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_3_LPCG), 16, 0);
+	clks[IMX8QXP_I2C0_DIV]		= imx_clk_divider_scu("i2c0_div", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_I2C1_DIV]		= imx_clk_divider_scu("i2c1_div", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_I2C2_DIV]		= imx_clk_divider_scu("i2c2_div", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_I2C3_DIV]		= imx_clk_divider_scu("i2c3_div", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_I2C0_CLK]		= imx_clk_gate_scu("i2c0_clk", "i2c0_div", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, (void __iomem *)(LPI2C_0_LPCG), 0, 0);
+	clks[IMX8QXP_I2C1_CLK]		= imx_clk_gate_scu("i2c1_clk", "i2c1_div", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, (void __iomem *)(LPI2C_1_LPCG), 0, 0);
+	clks[IMX8QXP_I2C2_CLK]		= imx_clk_gate_scu("i2c2_clk", "i2c2_div", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, (void __iomem *)(LPI2C_2_LPCG), 0, 0);
+	clks[IMX8QXP_I2C3_CLK]		= imx_clk_gate_scu("i2c3_clk", "i2c3_div", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, (void __iomem *)(LPI2C_3_LPCG), 0, 0);
+	clks[IMX8QXP_FTM0_IPG_CLK]	= imx_clk_gate2_scu("ftm0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(FTM_0_LPCG), 16, 0);
+	clks[IMX8QXP_FTM1_IPG_CLK]	= imx_clk_gate2_scu("ftm1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(FTM_1_LPCG), 16, 0);
+	clks[IMX8QXP_FTM0_DIV]		= imx_clk_divider_scu("ftm0_div", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_FTM1_DIV]		= imx_clk_divider_scu("ftm1_div", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_FTM0_CLK]		= imx_clk_gate_scu("ftm0_clk", "ftm0_div", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(FTM_0_LPCG), 0, 0);
+	clks[IMX8QXP_FTM1_CLK]		= imx_clk_gate_scu("ftm1_clk", "ftm1_div", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, (void __iomem *)(FTM_1_LPCG), 0, 0);
+	clks[IMX8QXP_ADC0_IPG_CLK]	= imx_clk_gate2_scu("adc0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(ADC_0_LPCG), 16, 0);
+	clks[IMX8QXP_ADC0_DIV]		= imx_clk_divider_scu("adc0_div", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_ADC0_CLK]		= imx_clk_gate_scu("adc0_clk", "adc0_div", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, (void __iomem *)(ADC_0_LPCG), 0, 0);
+	clks[IMX8QXP_PWM_IPG_CLK]	= imx_clk_gate2_scu("pwm_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(PWM_LPCG), 16, 0);
+	clks[IMX8QXP_PWM_DIV]		= imx_clk_divider_scu("pwm_div", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_PWM_CLK]		= imx_clk_gate_scu("pwm_clk", "pwm_div", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_LPCG), 0, 0);
+	clks[IMX8QXP_LCD_IPG_CLK]	= imx_clk_gate2_scu("lcd_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LCD_LPCG), 16, 0);
+	clks[IMX8QXP_LCD_DIV]		= imx_clk_divider_scu("lcd_div", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_LCD_CLK]		= imx_clk_gate_scu("lcd_clk", "lcd_div", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, (void __iomem *)(LCD_LPCG), 0, 0);
+
+	/* Connectivity */
+	clks[IMX8QXP_SDHC0_IPG_CLK]	= imx_clk_gate2_scu("sdhc0_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_0_LPCG), 16, 0);
+	clks[IMX8QXP_SDHC1_IPG_CLK]	= imx_clk_gate2_scu("sdhc1_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_1_LPCG), 16, 0);
+	clks[IMX8QXP_SDHC2_IPG_CLK]	= imx_clk_gate2_scu("sdhc2_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_2_LPCG), 16, 0);
+	clks[IMX8QXP_SDHC0_DIV]		= imx_clk_divider_scu("sdhc0_div", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SDHC1_DIV]		= imx_clk_divider_scu("sdhc1_div", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SDHC2_DIV]		= imx_clk_divider_scu("sdhc2_div", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_SDHC0_CLK]		= imx_clk_gate_scu("sdhc0_clk", "sdhc0_div", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, (void __iomem *)(USDHC_0_LPCG), 0, 0);
+	clks[IMX8QXP_SDHC1_CLK]		= imx_clk_gate_scu("sdhc1_clk", "sdhc1_div", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, (void __iomem *)(USDHC_1_LPCG), 0, 0);
+	clks[IMX8QXP_SDHC2_CLK]		= imx_clk_gate_scu("sdhc2_clk", "sdhc1_div", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, (void __iomem *)(USDHC_2_LPCG), 0, 0);
+	clks[IMX8QXP_ENET0_ROOT_DIV]	= imx_clk_divider_scu("enet0_root_div", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_ENET0_REF_DIV]	= imx_clk_divider_gpr_scu("enet0_ref_div", "enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_C_CLKDIV);
+	clks[IMX8QXP_ENET1_REF_DIV]	= imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV);
+	clks[IMX8QXP_ENET0_BYPASS_DIV]	= imx_clk_divider_scu("enet0_bypass_div", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
+	clks[IMX8QXP_ENET0_RGMII_DIV]	= imx_clk_divider_scu("enet0_rgmii_div", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
+	clks[IMX8QXP_ENET1_ROOT_DIV]	= imx_clk_divider_scu("enet1_root_div", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_ENET1_BYPASS_DIV]	= imx_clk_divider_scu("enet1_bypass_div", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
+	clks[IMX8QXP_ENET1_RGMII_DIV]	= imx_clk_divider_scu("enet1_rgmii_div", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
+	clks[IMX8QXP_ENET0_AHB_CLK]	= imx_clk_gate2_scu("enet0_ahb_clk", "axi_conn_clk_root", (void __iomem *)(ENET_0_LPCG), 8, 0);
+	clks[IMX8QXP_ENET0_IPG_S_CLK]	= imx_clk_gate2_scu("enet0_ipg_s_clk", "ipg_conn_clk_root", (void __iomem *)(ENET_0_LPCG), 20, 0);
+	clks[IMX8QXP_ENET0_IPG_CLK]	= imx_clk_gate2_scu("enet0_ipg_clk", "enet0_ipg_s_clk", (void __iomem *)(ENET_0_LPCG), 16, 0);
+	clks[IMX8QXP_ENET1_AHB_CLK]	= imx_clk_gate2_scu("enet1_ahb_clk", "axi_conn_clk_root", (void __iomem *)(ENET_1_LPCG), 8, 0);
+	clks[IMX8QXP_ENET1_IPG_S_CLK]	= imx_clk_gate2_scu("enet1_ipg_s_clk", "ipg_conn_clk_root", (void __iomem *)(ENET_1_LPCG), 20, 0);
+	clks[IMX8QXP_ENET1_IPG_CLK]	= imx_clk_gate2_scu("enet1_ipg_clk", "enet1_ipg_s_clk", (void __iomem *)(ENET_1_LPCG), 16, 0);
+	clks[IMX8QXP_ENET0_ROOT_CLK]	= imx_clk_gate_scu("enet0_root_clk", "enet0_root_div", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, NULL, 0, 0);
+	clks[IMX8QXP_ENET1_ROOT_CLK]	= imx_clk_gate_scu("enet1_root_clk", "enet1_root_div", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, NULL, 0, 0);
+	clks[IMX8QXP_ENET0_TX_CLK]	= imx_clk_gate2_scu("enet0_tx_2x_clk", "enet0_root_div", (void __iomem *)(ENET_0_LPCG), 4, 0);
+	clks[IMX8QXP_ENET1_TX_CLK]	= imx_clk_gate2_scu("enet1_tx_2x_clk", "enet1_root_div", (void __iomem *)(ENET_1_LPCG), 4, 0);
+	clks[IMX8QXP_ENET0_PTP_CLK]	= imx_clk_gate2_scu("enet0_ptp_clk", "enet0_ref_div", (void __iomem *)(ENET_0_LPCG), 0, 0);
+	clks[IMX8QXP_ENET1_PTP_CLK]	= imx_clk_gate2_scu("enet1_ptp_clk", "enet1_ref_div", (void __iomem *)(ENET_1_LPCG), 0, 0);
+	clks[IMX8QXP_ENET0_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet0_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), IMX_SC_R_ENET_0, IMX_SC_C_SEL_125);
+	clks[IMX8QXP_ENET1_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet1_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), IMX_SC_R_ENET_1, IMX_SC_C_SEL_125);
+	clks[IMX8QXP_ENET0_RMII_TX_SEL]	= imx_clk_mux_gpr_scu("enet0_rmii_tx_sel", enet0_rmii_tx_sels, ARRAY_SIZE(enet0_rmii_tx_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK);
+	clks[IMX8QXP_ENET1_RMII_TX_SEL]	= imx_clk_mux_gpr_scu("enet1_rmii_tx_sel", enet1_rmii_tx_sels, ARRAY_SIZE(enet1_rmii_tx_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK);
+	clks[IMX8QXP_ENET0_RGMII_TX_CLK] = imx_clk_gate2_scu("enet0_rgmii_tx_clk", "enet0_rmii_tx_sel", (void __iomem *)(ENET_0_LPCG), 12, 0);
+	clks[IMX8QXP_ENET1_RGMII_TX_CLK] = imx_clk_gate2_scu("enet1_rgmii_tx_clk", "enet1_rmii_tx_sel", (void __iomem *)(ENET_1_LPCG), 12, 0);
+	clks[IMX8QXP_ENET0_RMII_RX_CLK]	= imx_clk_gate2_scu("enet0_rgmii_rx_clk", "enet0_rgmii_div", (void __iomem *)(ENET_0_LPCG + 0x4), 0, 0);
+	clks[IMX8QXP_ENET1_RMII_RX_CLK]	= imx_clk_gate2_scu("enet1_rgmii_rx_clk", "enet1_rgmii_div", (void __iomem *)(ENET_1_LPCG + 0x4), 0, 0);
+	clks[IMX8QXP_ENET0_REF_25MHZ_125MHZ_CLK] = imx_clk_gate_gpr_scu("enet0_ref_25_125_clk", "enet0_ref_25_125_sel", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_125, true);
+	clks[IMX8QXP_ENET1_REF_25MHZ_125MHZ_CLK] = imx_clk_gate_gpr_scu("enet1_ref_25_125_clk", "enet1_ref_25_125_sel", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_125, true);
+	clks[IMX8QXP_ENET0_REF_50MHZ_CLK] = imx_clk_gate_gpr_scu("enet0_ref_50_clk", NULL, IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true);
+	clks[IMX8QXP_ENET1_REF_50MHZ_CLK] = imx_clk_gate_gpr_scu("enet1_ref_50_clk", NULL, IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true);
+	clks[IMX8QXP_GPMI_BCH_IO_DIV]	= imx_clk_divider_scu("gpmi_io_div", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
+	clks[IMX8QXP_GPMI_BCH_DIV]	= imx_clk_divider_scu("gpmi_bch_div", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_GPMI_APB_CLK]	= imx_clk_gate2_scu("gpmi_apb_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG), 16, 0);
+	clks[IMX8QXP_GPMI_APB_BCH_CLK]	= imx_clk_gate2_scu("gpmi_apb_bch_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG), 20, 0);
+	clks[IMX8QXP_GPMI_BCH_IO_CLK]	= imx_clk_gate_scu("gpmi_io_clk", "gpmi_io_div", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, (void __iomem *)(NAND_LPCG), 4, 0);
+	clks[IMX8QXP_GPMI_BCH_CLK]	= imx_clk_gate_scu("gpmi_bch_clk", "gpmi_bch_div", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, (void __iomem *)(NAND_LPCG), 0, 0);
+	clks[IMX8QXP_APBHDMA_CLK]	= imx_clk_gate2_scu("gpmi_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG + 0x4), 16, 0);
+	clks[IMX8QXP_USB3_ACLK_DIV]	= imx_clk_divider_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_USB3_BUS_DIV]	= imx_clk_divider_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
+	clks[IMX8QXP_USB3_LPM_DIV]	= imx_clk_divider_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
+	clks[IMX8QXP_USB2_OH_AHB_CLK]	= imx_clk_gate2_scu("usboh3", "ahb_conn_clk_root", (void __iomem *)(USB_2_LPCG), 24, 0);
+	clks[IMX8QXP_USB2_OH_IPG_S_CLK]	= imx_clk_gate2_scu("usboh3_ipg_s", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 16, 0);
+	clks[IMX8QXP_USB2_OH_IPG_S_PL301_CLK] = imx_clk_gate2_scu("usboh3_ipg_pl301_s", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 20, 0);
+	clks[IMX8QXP_USB2_PHY_IPG_CLK]	= imx_clk_gate2_scu("usboh3_phy_clk", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 28, 0);
+	clks[IMX8QXP_USB3_IPG_CLK]	= imx_clk_gate2_scu("usb3_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USB_3_LPCG), 16, 0);
+	clks[IMX8QXP_USB3_CORE_PCLK]	= imx_clk_gate2_scu("usb3_core_clk", "ipg_conn_clk_root", (void __iomem *)(USB_3_LPCG), 20, 0);
+	clks[IMX8QXP_USB3_PHY_CLK]	= imx_clk_gate2_scu("usb3_phy_clk", "usb3_ipg_clk", (void __iomem *)(USB_3_LPCG), 24, 0);
+	clks[IMX8QXP_USB3_ACLK]		= imx_clk_gate_scu("usb3_aclk", "usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, (void __iomem *)(USB_3_LPCG), 28, 0);
+	clks[IMX8QXP_USB3_BUS_CLK]	= imx_clk_gate_scu("usb3_bus_clk", "usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, (void __iomem *)(USB_3_LPCG), 0, 0);
+	clks[IMX8QXP_USB3_LPM_CLK]	= imx_clk_gate_scu("usb3_lpm_clk", "usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, (void __iomem *)(USB_3_LPCG), 4, 0);
+	clks[IMX8QXP_EDMA_CLK]		= imx_clk_gate2_scu("edma_clk", "axi_conn_clk_root", (void __iomem *)(EDMA_LPCG), 0, 0);
+	clks[IMX8QXP_EDMA_IPG_CLK]	= imx_clk_gate2_scu("edma_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(EDMA_LPCG), 16, 0);
+	clks[IMX8QXP_MLB_HCLK]		= imx_clk_gate2_scu("mlb_hclk", "axi_conn_clk_root", (void __iomem *)(MLB_LPCG), 20, 0);
+	clks[IMX8QXP_MLB_CLK]		= imx_clk_gate2_scu("mlb_clk", "mlb_hclk", (void __iomem *)(MLB_LPCG), 0, 0);
+	clks[IMX8QXP_MLB_IPG_CLK]	= imx_clk_gate2_scu("mlb_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(MLB_LPCG), 16, 0);
+
+	/* Display controller - DC0 SS */
+	clks[IMX8QXP_DC0_DISP0_CLK]	= imx_clk_gate_scu("dc0_disp0_clk", "dc0_disp0_div", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, (void __iomem *)(DC_0_LPCG), 0, 0);
+	clks[IMX8QXP_DC0_DISP1_CLK]	= imx_clk_gate_scu("dc0_disp1_clk", "dc0_disp1_div", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, (void __iomem *)(DC_0_LPCG), 4, 0);
+	clks[IMX8QXP_DC0_PRG0_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg0_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x20), 0, 0);
+	clks[IMX8QXP_DC0_PRG0_APB_CLK]	= imx_clk_gate2_scu("dc0_prg0_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x20), 16, 0);
+	clks[IMX8QXP_DC0_PRG1_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg1_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x24), 0, 0);
+	clks[IMX8QXP_DC0_PRG1_APB_CLK]	= imx_clk_gate2_scu("dc0_prg1_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x24), 16, 0);
+	clks[IMX8QXP_DC0_PRG2_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg2_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x28), 0, 0);
+	clks[IMX8QXP_DC0_PRG2_APB_CLK]	= imx_clk_gate2_scu("dc0_prg2_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x28), 16, 0);
+	clks[IMX8QXP_DC0_PRG3_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg3_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x34), 0, 0);
+	clks[IMX8QXP_DC0_PRG3_APB_CLK]	= imx_clk_gate2_scu("dc0_prg3_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x34), 16, 0);
+	clks[IMX8QXP_DC0_PRG4_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg4_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x38), 0, 0);
+	clks[IMX8QXP_DC0_PRG4_APB_CLK]	= imx_clk_gate2_scu("dc0_prg4_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x38), 16, 0);
+	clks[IMX8QXP_DC0_PRG5_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg5_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x3c), 0, 0);
+	clks[IMX8QXP_DC0_PRG5_APB_CLK]	= imx_clk_gate2_scu("dc0_prg5_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x3c), 16, 0);
+	clks[IMX8QXP_DC0_PRG6_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg6_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x40), 0, 0);
+	clks[IMX8QXP_DC0_PRG6_APB_CLK]	= imx_clk_gate2_scu("dc0_prg6_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x40), 16, 0);
+	clks[IMX8QXP_DC0_PRG7_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg7_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x44), 0, 0);
+	clks[IMX8QXP_DC0_PRG7_APB_CLK]	= imx_clk_gate2_scu("dc0_prg7_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x44), 16, 0);
+	clks[IMX8QXP_DC0_PRG8_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg8_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x48), 0, 0);
+	clks[IMX8QXP_DC0_PRG8_APB_CLK]	= imx_clk_gate2_scu("dc0_prg8_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x48), 16, 0);
+	clks[IMX8QXP_DC0_DPR0_APB_CLK]	= imx_clk_gate2_scu("dc0_dpr0_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x18), 16, 0);
+	clks[IMX8QXP_DC0_DPR0_B_CLK]	= imx_clk_gate2_scu("dc0_dpr0_b_clk", "axi_ext_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x18), 20, 0);
+	clks[IMX8QXP_DC0_RTRAM0_CLK]	= imx_clk_gate2_scu("dc0_rtrm0_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x1C), 0, 0);
+	clks[IMX8QXP_DC0_RTRAM1_CLK]	= imx_clk_gate2_scu("dc0_rtrm1_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x30), 0, 0);
+
+	/* Display interface - MIPI-LVDS SS */
+	clks[IMX8QXP_MIPI0_I2C0_DIV]	= imx_clk_divider_scu("mipi_i2c0_div", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
+	clks[IMX8QXP_MIPI0_I2C1_DIV]	= imx_clk_divider_scu("mipi_i2c1_div", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+	clks[IMX8QXP_MIPI0_I2C0_CLK]	= imx_clk_gate_scu("mipi_i2c0_clk", "mipi_i2c0_div", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, 0);
+	clks[IMX8QXP_MIPI0_I2C1_CLK]	= imx_clk_gate_scu("mipi_i2c1_clk", "mipi_i2c1_div", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, 0);
+	clks[IMX8QXP_MIPI0_I2C0_IPG_S_CLK] = imx_clk_gate2_scu("mipi_i2c0_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x10), 0, 0);
+	clks[IMX8QXP_MIPI0_I2C0_IPG_CLK]	= imx_clk_gate2_scu("mipi_i2c0_ipg_clk", "mipi_i2c0_ipg_s", (void __iomem *)(DI_MIPI0_LPCG), 0, 0);
+	clks[IMX8QXP_MIPI0_I2C1_IPG_S_CLK] = imx_clk_gate2_scu("mipi_i2c1_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, 0);
+	clks[IMX8QXP_MIPI0_I2C1_IPG_CLK]	= imx_clk_gate2_scu("mipi_i2c1_ipg_clk", "mipi_i2c1_ipg_s", (void __iomem *)(DI_MIPI0_LPCG), 0, 0);
+	clks[IMX8QXP_MIPI0_PWM_IPG_S_CLK] = imx_clk_gate2_scu("mipi_pwm_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 0, 0);
+	clks[IMX8QXP_MIPI0_PWM_IPG_CLK]	= imx_clk_gate2_scu("mipi_pwm_ipg_clk", "mipi_pwm_ipg_s", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 0, 0);
+	clks[IMX8QXP_MIPI0_PWM_32K_CLK]	= imx_clk_gate2_scu("mipi_pwm_32K_clk", "xtal_32KHz", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 0, 0);
+	clks[IMX8QXP_MIPI0_GPIO_IPG_CLK]	= imx_clk_gate2_scu("mipi_gpio_ipg_clk", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x8), 0, 0);
+
+	/* Imaging SS */
+	clks[IMX8QXP_IMG_JPEG_ENC_IPG_CLK]	= imx_clk_gate2_scu("img_jpeg_enc_ipg_clk", "ipg_img_clk_root", (void __iomem *)(IMG_JPEG_ENC_LPCG), 16, 0);
+	clks[IMX8QXP_IMG_JPEG_ENC_CLK]		= imx_clk_gate2_scu("img_jpeg_enc_clk", "img_jpeg_enc_ipg_clk", (void __iomem *)(IMG_JPEG_ENC_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_JPEG_DEC_IPG_CLK]	= imx_clk_gate2_scu("img_jpeg_dec_ipg_clk", "ipg_img_clk_root", (void __iomem *)(IMG_JPEG_DEC_LPCG), 16, 0);
+	clks[IMX8QXP_IMG_JPEG_DEC_CLK]		= imx_clk_gate2_scu("img_jpeg_dec_clk", "img_jpeg_dec_ipg_clk", (void __iomem *)(IMG_JPEG_DEC_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PXL_LINK_DC0_CLK]	= imx_clk_gate2_scu("img_pxl_link_dc0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_DC0_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PXL_LINK_DC1_CLK]	= imx_clk_gate2_scu("img_pxl_link_dc1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_DC1_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PXL_LINK_CSI0_CLK]	= imx_clk_gate2_scu("img_pxl_link_csi0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_CSI0_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PXL_LINK_CSI1_CLK]	= imx_clk_gate2_scu("img_pxl_link_csi1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_CSI1_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PXL_LINK_HDMI_IN_CLK]	= imx_clk_gate2_scu("img_pxl_link_hdmi_in_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_HDMI_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_0_CLK]		= imx_clk_gate2_scu("img_pdma0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_0_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_1_CLK]		= imx_clk_gate2_scu("img_pdma1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_1_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_2_CLK]		= imx_clk_gate2_scu("img_pdma2_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_2_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_3_CLK]		= imx_clk_gate2_scu("img_pdma3_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_3_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_4_CLK]		= imx_clk_gate2_scu("img_pdma4_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_4_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_5_CLK]		= imx_clk_gate2_scu("img_pdma5_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_5_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_6_CLK]		= imx_clk_gate2_scu("img_pdma6_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_6_LPCG), 0, 0);
+	clks[IMX8QXP_IMG_PDMA_7_CLK]		= imx_clk_gate2_scu("img_pdma7_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_7_LPCG), 0, 0);
+
+	/* MIPI CSI SS */
+	clks[IMX8QXP_CSI0_I2C0_DIV]	= imx_clk_divider_scu("mipi_csi0_i2c0_div", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CSI0_PWM0_DIV]	= imx_clk_divider_scu("mipi_csi0_pwm0_div", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CSI0_CORE_DIV]	= imx_clk_divider_scu("mipi_csi0_core_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
+	clks[IMX8QXP_CSI0_ESC_DIV]	= imx_clk_divider_scu("mipi_csi0_esc_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
+	clks[IMX8QXP_CSI0_IPG_CLK_S]	= imx_clk_gate2_scu("mipi_csi0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x8), 16, 0);
+	clks[IMX8QXP_CSI0_IPG_CLK]	= imx_clk_gate2_scu("mipi_csi0_ipg", "mipi_csi0_ipg_s", (void __iomem *)(MIPI_CSI_0_LPCG), 16, 0);
+	clks[IMX8QXP_CSI0_APB_CLK]	= imx_clk_gate2_scu("mipi_csi0_apb_clk", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x4), 16,  0);
+	clks[IMX8QXP_CSI0_I2C0_IPG_CLK]	= imx_clk_gate2_scu("mipi_csi0_i2c0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 16, 0);
+	clks[IMX8QXP_CSI0_I2C0_CLK]	= imx_clk_gate_scu("mipi_csi0_i2c0_clk", "mipi_csi0_i2c0_div", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 0, 0);
+	clks[IMX8QXP_CSI0_PWM0_IPG_CLK]	= imx_clk_gate2_scu("mipi_csi0_pwm0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 16, 0);
+	clks[IMX8QXP_CSI0_PWM0_CLK]	= imx_clk_gate_scu("mipi_csi0_pwm0_clk", "mipi_csi0_pwm0_div", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 0, 0);
+	clks[IMX8QXP_CSI0_CORE_CLK]	= imx_clk_gate_scu("mipi_csi0_core_clk", "mipi_csi0_core_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x18), 16, 0);
+	clks[IMX8QXP_CSI0_ESC_CLK]	= imx_clk_gate_scu("mipi_csi0_esc_clk", "mipi_csi0_esc_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, (void __iomem *)(MIPI_CSI_0_LPCG + 0x1C), 16, 0);
+
+	/* HSIO SS */
+	clks[IMX8QXP_HSIO_PCIE_MSTR_AXI_CLK]	= imx_clk_gate2_scu("hsio_pcie_mstr_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_PCIE_SLV_AXI_CLK]	= imx_clk_gate2_scu("hsio_pcie_slv_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 20, 0);
+	clks[IMX8QXP_HSIO_PCIE_DBI_AXI_CLK]	= imx_clk_gate2_scu("hsio_pcie_dbi_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 24, 0);
+	clks[IMX8QXP_HSIO_PCIE_X1_PER_CLK]	= imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_CRR3_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_PHY_X1_PER_CLK]	= imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_CRR1_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_MISC_PER_CLK]		= imx_clk_gate2_scu("hsio_misc_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_MISC_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_PHY_X1_APB_CLK]	= imx_clk_gate2_scu("hsio_phy_x1_apb_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_GPIO_CLK]		= imx_clk_gate2_scu("hsio_gpio_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_GPIO_LPCG), 16, 0);
+	clks[IMX8QXP_HSIO_PHY_X1_PCLK]		= imx_clk_gate2_scu("hsio_phy_x1_pclk", "dummy", (void __iomem *)(HSIO_PHY_X1_LPCG), 0, 0);
+
+	imx_check_clk_hws(clks, clk_data->num);
+
+	of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
+
+	pr_info("i.MX8QXP clock tree init done.\n");
+
+	return 0;
+}
+
+static const struct of_device_id imx8qxp_match[] = {
+	{ .compatible = "fsl,imx8qxp-clk", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver imx8qxp_clk_driver = {
+	.driver = {
+		.name = "imx8qxp-clk",
+		.of_match_table = imx8qxp_match,
+	},
+	.probe = imx8qxp_clk_probe,
+};
+
+static int __init imx8qxp_clk_init(void)
+{
+	return platform_driver_register(&imx8qxp_clk_driver);
+}
+core_initcall(imx8qxp_clk_init);
diff --git a/include/dt-bindings/clock/imx8qxp-clock.h b/include/dt-bindings/clock/imx8qxp-clock.h
new file mode 100644
index 0000000..c0b31aa
--- /dev/null
+++ b/include/dt-bindings/clock/imx8qxp-clock.h
@@ -0,0 +1,362 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_IMX8QXP_H
+#define __DT_BINDINGS_CLOCK_IMX8QXP_H
+
+#define IMX8QXP_CLK_DUMMY					0
+
+#define IMX8QXP_UART0_IPG_CLK					1
+#define IMX8QXP_UART0_DIV					2
+#define IMX8QXP_UART0_CLK					3
+
+#define IMX8QXP_IPG_DMA_CLK_ROOT				4
+
+/* GPU Clocks. */
+#define IMX8QXP_GPU0_CORE_DIV					5
+#define IMX8QXP_GPU0_CORE_CLK					6
+#define IMX8QXP_GPU0_SHADER_DIV					7
+#define IMX8QXP_GPU0_SHADER_CLK					8
+
+#define IMX8QXP_24MHZ						9
+#define IMX8QXP_GPT_3M						10
+#define IMX8QXP_32KHZ						11
+
+/* LSIO SS */
+#define IMX8QXP_LSIO_MEM_CLK					12
+#define IMX8QXP_LSIO_BUS_CLK					13
+#define IMX8QXP_LSIO_PWM0_DIV					14
+#define IMX8QXP_LSIO_PWM0_IPG_S_CLK				15
+#define IMX8QXP_LSIO_PWM0_IPG_SLV_CLK				16
+#define IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK				17
+#define IMX8QXP_LSIO_PWM0_HF_CLK				18
+#define IMX8QXP_LSIO_PWM0_CLK					19
+#define IMX8QXP_LSIO_PWM1_DIV					20
+#define IMX8QXP_LSIO_PWM1_IPG_S_CLK				21
+#define IMX8QXP_LSIO_PWM1_IPG_SLV_CLK				22
+#define IMX8QXP_LSIO_PWM1_IPG_MSTR_CLK				23
+#define IMX8QXP_LSIO_PWM1_HF_CLK				24
+#define IMX8QXP_LSIO_PWM1_CLK					25
+#define IMX8QXP_LSIO_PWM2_DIV					26
+#define IMX8QXP_LSIO_PWM2_IPG_S_CLK				27
+#define IMX8QXP_LSIO_PWM2_IPG_SLV_CLK				28
+#define IMX8QXP_LSIO_PWM2_IPG_MSTR_CLK				29
+#define IMX8QXP_LSIO_PWM2_HF_CLK				30
+#define IMX8QXP_LSIO_PWM2_CLK					31
+#define IMX8QXP_LSIO_PWM3_DIV					32
+#define IMX8QXP_LSIO_PWM3_IPG_S_CLK				33
+#define IMX8QXP_LSIO_PWM3_IPG_SLV_CLK				34
+#define IMX8QXP_LSIO_PWM3_IPG_MSTR_CLK				35
+#define IMX8QXP_LSIO_PWM3_HF_CLK				36
+#define IMX8QXP_LSIO_PWM3_CLK					37
+#define IMX8QXP_LSIO_PWM4_DIV					38
+#define IMX8QXP_LSIO_PWM4_IPG_S_CLK				39
+#define IMX8QXP_LSIO_PWM4_IPG_SLV_CLK				40
+#define IMX8QXP_LSIO_PWM4_IPG_MSTR_CLK				42
+#define IMX8QXP_LSIO_PWM4_HF_CLK				43
+#define IMX8QXP_LSIO_PWM4_CLK					44
+#define IMX8QXP_LSIO_PWM5_DIV					45
+#define IMX8QXP_LSIO_PWM5_IPG_S_CLK				46
+#define IMX8QXP_LSIO_PWM5_IPG_SLV_CLK				47
+#define IMX8QXP_LSIO_PWM5_IPG_MSTR_CLK				48
+#define IMX8QXP_LSIO_PWM5_HF_CLK				49
+#define IMX8QXP_LSIO_PWM5_CLK					50
+#define IMX8QXP_LSIO_PWM6_DIV					51
+#define IMX8QXP_LSIO_PWM6_IPG_S_CLK				52
+#define IMX8QXP_LSIO_PWM6_IPG_SLV_CLK				53
+#define IMX8QXP_LSIO_PWM6_IPG_MSTR_CLK				54
+#define IMX8QXP_LSIO_PWM6_HF_CLK				55
+#define IMX8QXP_LSIO_PWM6_CLK					56
+#define IMX8QXP_LSIO_PWM7_DIV					57
+#define IMX8QXP_LSIO_PWM7_IPG_S_CLK				58
+#define IMX8QXP_LSIO_PWM7_IPG_SLV_CLK				59
+#define IMX8QXP_LSIO_PWM7_IPG_MSTR_CLK				60
+#define IMX8QXP_LSIO_PWM7_HF_CLK				61
+#define IMX8QXP_LSIO_PWM7_CLK					62
+#define IMX8QXP_LSIO_GPT0_DIV					63
+#define IMX8QXP_LSIO_GPT0_IPG_S_CLK				64
+#define IMX8QXP_LSIO_GPT0_IPG_SLV_CLK				65
+#define IMX8QXP_LSIO_GPT0_IPG_MSTR_CLK				66
+#define IMX8QXP_LSIO_GPT0_HF_CLK				67
+#define IMX8QXP_LSIO_GPT0_CLK					68
+#define IMX8QXP_LSIO_GPT1_DIV					69
+#define IMX8QXP_LSIO_GPT1_IPG_S_CLK				70
+#define IMX8QXP_LSIO_GPT1_IPG_SLV_CLK				71
+#define IMX8QXP_LSIO_GPT1_IPG_MSTR_CLK				72
+#define IMX8QXP_LSIO_GPT1_HF_CLK				73
+#define IMX8QXP_LSIO_GPT1_CLK					74
+#define IMX8QXP_LSIO_GPT2_DIV					75
+#define IMX8QXP_LSIO_GPT2_IPG_S_CLK				76
+#define IMX8QXP_LSIO_GPT2_IPG_SLV_CLK				77
+#define IMX8QXP_LSIO_GPT2_IPG_MSTR_CLK				78
+#define IMX8QXP_LSIO_GPT2_HF_CLK				79
+#define IMX8QXP_LSIO_GPT2_CLK					80
+#define IMX8QXP_LSIO_GPT3_DIV					81
+#define IMX8QXP_LSIO_GPT3_IPG_S_CLK				82
+#define IMX8QXP_LSIO_GPT3_IPG_SLV_CLK				83
+#define IMX8QXP_LSIO_GPT3_IPG_MSTR_CLK				84
+#define IMX8QXP_LSIO_GPT3_HF_CLK				85
+#define IMX8QXP_LSIO_GPT3_CLK					86
+#define IMX8QXP_LSIO_GPT4_DIV					87
+#define IMX8QXP_LSIO_GPT4_IPG_S_CLK				88
+#define IMX8QXP_LSIO_GPT4_IPG_SLV_CLK				89
+#define IMX8QXP_LSIO_GPT4_IPG_MSTR_CLK				90
+#define IMX8QXP_LSIO_GPT4_HF_CLK				91
+#define IMX8QXP_LSIO_GPT4_CLK					92
+#define IMX8QXP_LSIO_FSPI0_DIV					93
+#define IMX8QXP_LSIO_FSPI0_HCLK					94
+#define IMX8QXP_LSIO_FSPI0_IPG_S_CLK				95
+#define IMX8QXP_LSIO_FSPI0_IPG_CLK				96
+#define IMX8QXP_LSIO_FSPI0_CLK					97
+#define IMX8QXP_LSIO_FSPI1_DIV					98
+#define IMX8QXP_LSIO_FSPI1_HCLK					99
+#define IMX8QXP_LSIO_FSPI1_IPG_S_CLK				100
+#define IMX8QXP_LSIO_FSPI1_IPG_CLK				101
+#define IMX8QXP_LSIO_FSPI1_CLK					102
+#define IMX8QXP_LSIO_GPIO0_IPG_S_CLK				103
+#define IMX8QXP_LSIO_GPIO1_IPG_S_CLK				104
+#define IMX8QXP_LSIO_GPIO2_IPG_S_CLK				105
+#define IMX8QXP_LSIO_GPIO3_IPG_S_CLK				106
+#define IMX8QXP_LSIO_GPIO4_IPG_S_CLK				107
+#define IMX8QXP_LSIO_GPIO5_IPG_S_CLK				108
+#define IMX8QXP_LSIO_GPIO6_IPG_S_CLK				109
+#define IMX8QXP_LSIO_GPIO7_IPG_S_CLK				110
+#define IMX8QXP_LSIO_ROMCP_REG_CLK				111
+#define IMX8QXP_LSIO_ROMCP_CLK					112
+#define IMX8QXP_LSIO_96KROM_CLK					113
+#define IMX8QXP_LSIO_OCRAM_MEM_CLK				114
+#define IMX8QXP_LSIO_OCRAM_CTRL_CLK				115
+
+/* ADMA SS */
+#define IMX8QXP_UART1_IPG_CLK					116
+#define IMX8QXP_UART2_IPG_CLK					117
+#define IMX8QXP_UART3_IPG_CLK					118
+#define IMX8QXP_UART1_DIV					119
+#define IMX8QXP_UART2_DIV					120
+#define IMX8QXP_UART3_DIV					121
+#define IMX8QXP_UART1_CLK					122
+#define IMX8QXP_UART2_CLK					123
+#define IMX8QXP_UART3_CLK					124
+#define IMX8QXP_SPI0_IPG_CLK					125
+#define IMX8QXP_SPI1_IPG_CLK					126
+#define IMX8QXP_SPI2_IPG_CLK					127
+#define IMX8QXP_SPI3_IPG_CLK					128
+#define IMX8QXP_SPI0_DIV					129
+#define IMX8QXP_SPI1_DIV					130
+#define IMX8QXP_SPI2_DIV					131
+#define IMX8QXP_SPI3_DIV					132
+#define IMX8QXP_SPI0_CLK					133
+#define IMX8QXP_SPI1_CLK					134
+#define IMX8QXP_SPI2_CLK					135
+#define IMX8QXP_SPI3_CLK					136
+#define IMX8QXP_CAN0_IPG_CHI_CLK				137
+#define IMX8QXP_CAN1_IPG_CHI_CLK				138
+#define IMX8QXP_CAN2_IPG_CHI_CLK				139
+#define IMX8QXP_CAN0_IPG_CLK					140
+#define IMX8QXP_CAN1_IPG_CLK					141
+#define IMX8QXP_CAN2_IPG_CLK					142
+#define IMX8QXP_CAN0_DIV					143
+#define IMX8QXP_CAN1_DIV					144
+#define IMX8QXP_CAN2_DIV					145
+#define IMX8QXP_CAN0_CLK					146
+#define IMX8QXP_CAN1_CLK					147
+#define IMX8QXP_CAN2_CLK					148
+#define IMX8QXP_I2C0_IPG_CLK					149
+#define IMX8QXP_I2C1_IPG_CLK					150
+#define IMX8QXP_I2C2_IPG_CLK					151
+#define IMX8QXP_I2C3_IPG_CLK					152
+#define IMX8QXP_I2C0_DIV					153
+#define IMX8QXP_I2C1_DIV					154
+#define IMX8QXP_I2C2_DIV					155
+#define IMX8QXP_I2C3_DIV					156
+#define IMX8QXP_I2C0_CLK					157
+#define IMX8QXP_I2C1_CLK					158
+#define IMX8QXP_I2C2_CLK					159
+#define IMX8QXP_I2C3_CLK					160
+#define IMX8QXP_FTM0_IPG_CLK					161
+#define IMX8QXP_FTM1_IPG_CLK					162
+#define IMX8QXP_FTM0_DIV					163
+#define IMX8QXP_FTM1_DIV					164
+#define IMX8QXP_FTM0_CLK					165
+#define IMX8QXP_FTM1_CLK					166
+#define IMX8QXP_ADC0_IPG_CLK					167
+#define IMX8QXP_ADC0_DIV					168
+#define IMX8QXP_ADC0_CLK					169
+#define IMX8QXP_PWM_IPG_CLK					170
+#define IMX8QXP_PWM_DIV						171
+#define IMX8QXP_PWM_CLK						172
+#define IMX8QXP_LCD_IPG_CLK					173
+#define IMX8QXP_LCD_DIV						174
+#define IMX8QXP_LCD_CLK						175
+
+/* Connectivity SS */
+#define IMX8QXP_AXI_CONN_CLK_ROOT				176
+#define IMX8QXP_AHB_CONN_CLK_ROOT				177
+#define IMX8QXP_IPG_CONN_CLK_ROOT				178
+#define IMX8QXP_SDHC0_IPG_CLK					179
+#define IMX8QXP_SDHC1_IPG_CLK					180
+#define IMX8QXP_SDHC2_IPG_CLK					181
+#define IMX8QXP_SDHC0_DIV					182
+#define IMX8QXP_SDHC1_DIV					183
+#define IMX8QXP_SDHC2_DIV					184
+#define IMX8QXP_SDHC0_CLK					185
+#define IMX8QXP_SDHC1_CLK					186
+#define IMX8QXP_SDHC2_CLK					187
+#define IMX8QXP_ENET0_ROOT_DIV					188
+#define IMX8QXP_ENET0_REF_DIV					189
+#define IMX8QXP_ENET1_REF_DIV					190
+#define IMX8QXP_ENET0_BYPASS_DIV				191
+#define IMX8QXP_ENET0_RGMII_DIV					192
+#define IMX8QXP_ENET1_ROOT_DIV					193
+#define IMX8QXP_ENET1_BYPASS_DIV				194
+#define IMX8QXP_ENET1_RGMII_DIV					195
+#define IMX8QXP_ENET0_AHB_CLK					196
+#define IMX8QXP_ENET0_IPG_S_CLK					197
+#define IMX8QXP_ENET0_IPG_CLK					198
+#define IMX8QXP_ENET1_AHB_CLK					199
+#define IMX8QXP_ENET1_IPG_S_CLK					200
+#define IMX8QXP_ENET1_IPG_CLK					201
+#define IMX8QXP_ENET0_ROOT_CLK					202
+#define IMX8QXP_ENET1_ROOT_CLK					203
+#define IMX8QXP_ENET0_TX_CLK					204
+#define IMX8QXP_ENET1_TX_CLK					205
+#define IMX8QXP_ENET0_PTP_CLK					206
+#define IMX8QXP_ENET1_PTP_CLK					207
+#define IMX8QXP_ENET0_REF_25MHZ_125MHZ_SEL			208
+#define IMX8QXP_ENET1_REF_25MHZ_125MHZ_SEL			209
+#define IMX8QXP_ENET0_RMII_TX_SEL				210
+#define IMX8QXP_ENET1_RMII_TX_SEL				211
+#define IMX8QXP_ENET0_RGMII_TX_CLK				212
+#define IMX8QXP_ENET1_RGMII_TX_CLK				213
+#define IMX8QXP_ENET0_RMII_RX_CLK				214
+#define IMX8QXP_ENET1_RMII_RX_CLK				215
+#define IMX8QXP_ENET0_REF_25MHZ_125MHZ_CLK			216
+#define IMX8QXP_ENET1_REF_25MHZ_125MHZ_CLK			217
+#define IMX8QXP_ENET0_REF_50MHZ_CLK				218
+#define IMX8QXP_ENET1_REF_50MHZ_CLK				219
+#define IMX8QXP_GPMI_BCH_IO_DIV					220
+#define IMX8QXP_GPMI_BCH_DIV					221
+#define IMX8QXP_GPMI_APB_CLK					222
+#define IMX8QXP_GPMI_APB_BCH_CLK				223
+#define IMX8QXP_GPMI_BCH_IO_CLK					224
+#define IMX8QXP_GPMI_BCH_CLK					225
+#define IMX8QXP_APBHDMA_CLK					226
+#define IMX8QXP_USB3_ACLK_DIV					227
+#define IMX8QXP_USB3_BUS_DIV					228
+#define IMX8QXP_USB3_LPM_DIV					229
+#define IMX8QXP_USB3_IPG_CLK					230
+#define IMX8QXP_USB3_CORE_PCLK					231
+#define IMX8QXP_USB3_PHY_CLK					232
+#define IMX8QXP_USB3_ACLK					233
+#define IMX8QXP_USB3_BUS_CLK					234
+#define IMX8QXP_USB3_LPM_CLK					235
+#define IMX8QXP_USB2_OH_AHB_CLK					236
+#define IMX8QXP_USB2_OH_IPG_S_CLK				237
+#define IMX8QXP_USB2_OH_IPG_S_PL301_CLK				238
+#define IMX8QXP_USB2_PHY_IPG_CLK				239
+#define IMX8QXP_EDMA_CLK					240
+#define IMX8QXP_EDMA_IPG_CLK					241
+#define IMX8QXP_MLB_HCLK					242
+#define IMX8QXP_MLB_CLK						243
+#define IMX8QXP_MLB_IPG_CLK					244
+
+/* Display controller SS */
+/* DC part1 */
+#define IMX8QXP_DC_AXI_EXT_CLK					245
+#define IMX8QXP_DC_AXI_INT_CLK					246
+#define IMX8QXP_DC_CFG_CLK					247
+#define IMX8QXP_DC0_DISP0_CLK					248
+#define IMX8QXP_DC0_DISP1_CLK					249
+#define IMX8QXP_DC0_PRG0_RTRAM_CLK				250
+#define IMX8QXP_DC0_PRG0_APB_CLK				251
+#define IMX8QXP_DC0_PRG1_RTRAM_CLK				252
+#define IMX8QXP_DC0_PRG1_APB_CLK				253
+#define IMX8QXP_DC0_PRG2_RTRAM_CLK				254
+#define IMX8QXP_DC0_PRG2_APB_CLK				255
+#define IMX8QXP_DC0_PRG3_RTRAM_CLK				256
+#define IMX8QXP_DC0_PRG3_APB_CLK				257
+#define IMX8QXP_DC0_PRG4_RTRAM_CLK				258
+#define IMX8QXP_DC0_PRG4_APB_CLK				259
+#define IMX8QXP_DC0_PRG5_RTRAM_CLK				260
+#define IMX8QXP_DC0_PRG5_APB_CLK				261
+#define IMX8QXP_DC0_PRG6_RTRAM_CLK				262
+#define IMX8QXP_DC0_PRG6_APB_CLK				263
+#define IMX8QXP_DC0_PRG7_RTRAM_CLK				264
+#define IMX8QXP_DC0_PRG7_APB_CLK				265
+#define IMX8QXP_DC0_PRG8_RTRAM_CLK				266
+#define IMX8QXP_DC0_PRG8_APB_CLK				267
+#define IMX8QXP_DC0_DPR0_APB_CLK				268
+#define IMX8QXP_DC0_DPR0_B_CLK					269
+#define IMX8QXP_DC0_RTRAM0_CLK					270
+#define IMX8QXP_DC0_RTRAM1_CLK					271
+
+/* MIPI-LVDS part1 */
+#define IMX8QXP_MIPI_IPG_CLK					272
+#define IMX8QXP_MIPI0_I2C0_DIV					273
+#define IMX8QXP_MIPI0_I2C1_DIV					274
+#define IMX8QXP_MIPI0_I2C0_CLK					275
+#define IMX8QXP_MIPI0_I2C1_CLK					276
+#define IMX8QXP_MIPI0_I2C0_IPG_S_CLK				277
+#define IMX8QXP_MIPI0_I2C0_IPG_CLK				278
+#define IMX8QXP_MIPI0_I2C1_IPG_S_CLK				279
+#define IMX8QXP_MIPI0_I2C1_IPG_CLK				280
+#define IMX8QXP_MIPI0_PWM_IPG_S_CLK				281
+#define IMX8QXP_MIPI0_PWM_IPG_CLK				282
+#define IMX8QXP_MIPI0_PWM_32K_CLK				283
+#define IMX8QXP_MIPI0_GPIO_IPG_CLK				284
+
+#define IMX8QXP_IMG_JPEG_ENC_IPG_CLK				285
+#define IMX8QXP_IMG_JPEG_ENC_CLK				286
+#define IMX8QXP_IMG_JPEG_DEC_IPG_CLK				287
+#define IMX8QXP_IMG_JPEG_DEC_CLK				288
+#define IMX8QXP_IMG_PXL_LINK_DC0_CLK				289
+#define IMX8QXP_IMG_PXL_LINK_DC1_CLK				290
+#define IMX8QXP_IMG_PXL_LINK_CSI0_CLK				291
+#define IMX8QXP_IMG_PXL_LINK_CSI1_CLK				292
+#define IMX8QXP_IMG_PXL_LINK_HDMI_IN_CLK			293
+#define IMX8QXP_IMG_PDMA_0_CLK					294
+#define IMX8QXP_IMG_PDMA_1_CLK					295
+#define IMX8QXP_IMG_PDMA_2_CLK					296
+#define IMX8QXP_IMG_PDMA_3_CLK					297
+#define IMX8QXP_IMG_PDMA_4_CLK					298
+#define IMX8QXP_IMG_PDMA_5_CLK					299
+#define IMX8QXP_IMG_PDMA_6_CLK					300
+#define IMX8QXP_IMG_PDMA_7_CLK					301
+#define IMX8QXP_IMG_AXI_CLK					302
+#define IMX8QXP_IMG_IPG_CLK					303
+#define IMX8QXP_IMG_PXL_CLK					304
+
+#define IMX8QXP_CSI0_I2C0_DIV					305
+#define IMX8QXP_CSI0_PWM0_DIV					306
+#define IMX8QXP_CSI0_CORE_DIV					307
+#define IMX8QXP_CSI0_ESC_DIV					308
+#define IMX8QXP_CSI0_IPG_CLK_S					309
+#define IMX8QXP_CSI0_IPG_CLK					310
+#define IMX8QXP_CSI0_APB_CLK					311
+#define IMX8QXP_CSI0_I2C0_IPG_CLK				312
+#define IMX8QXP_CSI0_I2C0_CLK					313
+#define IMX8QXP_CSI0_PWM0_IPG_CLK				314
+#define IMX8QXP_CSI0_PWM0_CLK					315
+#define IMX8QXP_CSI0_CORE_CLK					316
+#define IMX8QXP_CSI0_ESC_CLK					317
+
+#define IMX8QXP_HSIO_AXI_CLK					318
+#define IMX8QXP_HSIO_PER_CLK					319
+#define IMX8QXP_HSIO_PCIE_MSTR_AXI_CLK				320
+#define IMX8QXP_HSIO_PCIE_SLV_AXI_CLK				321
+#define IMX8QXP_HSIO_PCIE_DBI_AXI_CLK				322
+#define IMX8QXP_HSIO_PCIE_X1_PER_CLK				323
+#define IMX8QXP_HSIO_PHY_X1_PER_CLK				324
+#define IMX8QXP_HSIO_MISC_PER_CLK				325
+#define IMX8QXP_HSIO_PHY_X1_APB_CLK				326
+#define IMX8QXP_HSIO_GPIO_CLK					327
+#define IMX8QXP_HSIO_PHY_X1_PCLK				328
+
+#define IMX8QXP_A35_DIV						329
+
+#define IMX8QXP_CLK_END						330
+
+#endif /* __DT_BINDINGS_CLOCK_IMX8QXP_H */
diff --git a/include/soc/imx/imx8qxp/lpcg.h b/include/soc/imx/imx8qxp/lpcg.h
new file mode 100644
index 0000000..afbb5da
--- /dev/null
+++ b/include/soc/imx/imx8qxp/lpcg.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *
+ */
+
+#ifndef _SC_LPCG_H
+#define _SC_LPCG_H
+
+/*LSIO SS */
+#define		PWM_0_LPCG		0x5D400000
+#define		PWM_1_LPCG		0x5D410000
+#define		PWM_2_LPCG		0x5D420000
+#define		PWM_3_LPCG		0x5D430000
+#define		PWM_4_LPCG		0x5D440000
+#define		PWM_5_LPCG		0x5D450000
+#define		PWM_6_LPCG		0x5D460000
+#define		PWM_7_LPCG		0x5D470000
+#define		GPIO_0_LPCG		0x5D480000
+#define		GPIO_1_LPCG		0x5D490000
+#define		GPIO_2_LPCG		0x5D4A0000
+#define		GPIO_3_LPCG		0x5D4B0000
+#define		GPIO_4_LPCG		0x5D4C0000
+#define		GPIO_5_LPCG		0x5D4D0000
+#define		GPIO_6_LPCG		0x5D4E0000
+#define		GPIO_7_LPCG		0x5D4F0000
+#define		FSPI_0_LPCG		0x5D520000
+#define		FSPI_1_LPCG		0x5D530000
+#define		GPT_0_LPCG		0x5D540000
+#define		GPT_1_LPCG		0x5D550000
+#define		GPT_2_LPCG		0x5D560000
+#define		GPT_3_LPCG		0x5D570000
+#define		GPT_4_LPCG		0x5D580000
+#define		OCRAM_LPCG		0x5D590000
+#define		KPP_LPCG		0x5D5A0000
+#define		ROMCP_LPCG		0x5D500000
+
+/* HSIO SS */
+#define		CRR_5_LPCG		0x5F0F0000
+#define		CRR_4_LPCG		0x5F0E0000
+#define		CRR_3_LPCG		0x5F0D0000
+#define		CRR_2_LPCG		0x5F0C0000
+#define		CRR_1_LPCG		0x5F0B0000
+#define		CRR_0_LPCG		0x5F0A0000
+#define		PHY_1_LPCG		0x5F090000
+#define		PHY_2_LPCG		0x5F080000
+#define		SATA_0_LPCG		0x5F070000
+#define		PCIE_B_LPCG		0x5F060000
+#define		PCIE_A_LPCG		0x5F050000
+
+/* DMA SS */
+#define		FLEX_CAN_2_LPCG		0x5ACF0000
+#define		FLEX_CAN_1_LPCG		0x5ACE0000
+#define		FLEX_CAN_0_LPCG		0x5ACD0000
+#define		FTM_1_LPCG		0x5ACB0000
+#define		FTM_0_LPCG		0x5ACA0000
+#define		ADC_0_LPCG		0x5AC80000
+#define		LPI2C_3_LPCG		0x5AC30000
+#define		LPI2C_2_LPCG		0x5AC20000
+#define		LPI2C_1_LPCG		0x5AC10000
+#define		LPI2C_0_LPCG		0x5AC00000
+#define		PWM_LPCG		0x5A590000
+#define		LCD_LPCG		0x5A580000
+#define		LPUART_3_LPCG		0x5A490000
+#define		LPUART_2_LPCG		0x5A480000
+#define		LPUART_1_LPCG		0x5A470000
+#define		LPUART_0_LPCG		0x5A460000
+#define		LPSPI_3_LPCG		0x5A430000
+#define		LPSPI_2_LPCG		0x5A420000
+#define		LPSPI_1_LPCG		0x5A410000
+#define		LPSPI_0_LPCG		0x5A400000
+
+/* Display SS */
+#define		DC_0_LPCG		0x56010000
+#define		DC_1_LPCG		0x57010000
+
+/* LVDS */
+#define		DI_LVDS_0_LPCG		0x56243000
+#define		DI_LVDS_1_LPCG		0x57243000
+
+/* DI HDMI */
+#define		DI_HDMI_LPCG		0x56263000
+
+/* RX-HDMI */
+#define		RX_HDMI_LPCG		0x58263000
+
+/* MIPI CSI SS */
+#define		MIPI_CSI_0_LPCG		0x58223000
+#define		MIPI_CSI_1_LPCG		0x58243000
+
+/* PARALLEL CSI SS */
+#define		PARALLEL_CSI_LPCG	0x58263000
+
+/* Display MIPI SS */
+#define		DI_MIPI0_LPCG		0x56223000
+#define		DI_MIPI1_LPCG		0x56243000
+
+/* Imaging SS */
+#define		IMG_JPEG_ENC_LPCG	0x585F0000
+#define		IMG_JPEG_DEC_LPCG	0x585D0000
+#define		IMG_PXL_LINK_DC1_LPCG	0x585C0000
+#define		IMG_PXL_LINK_DC0_LPCG	0x585B0000
+#define		IMG_PXL_LINK_HDMI_LPCG	0x585A0000
+#define		IMG_PXL_LINK_CSI1_LPCG	0x58590000
+#define		IMG_PXL_LINK_CSI0_LPCG	0x58580000
+#define		IMG_PDMA_7_LPCG		0x58570000
+#define		IMG_PDMA_6_LPCG		0x58560000
+#define		IMG_PDMA_5_LPCG		0x58550000
+#define		IMG_PDMA_4_LPCG		0x58540000
+#define		IMG_PDMA_3_LPCG		0x58530000
+#define		IMG_PDMA_2_LPCG		0x58520000
+#define		IMG_PDMA_1_LPCG		0x58510000
+#define		IMG_PDMA_0_LPCG		0x58500000
+
+/* HSIO SS */
+#define		HSIO_GPIO_LPCG		0x5F100000
+#define		HSIO_MISC_LPCG		0x5F0F0000
+#define		HSIO_SATA_CRR4_LPCG	0x5F0E0000
+#define		HSIO_PCIE_X1_CRR3_LPCG	0x5F0D0000
+#define		HSIO_PCIE_X2_CRR2_LPCG	0x5F0C0000
+#define		HSIO_PHY_X1_CRR1_LPCG	0x5F0B0000
+#define		HSIO_PHY_X2_CRR0_LPCG	0x5F0A0000
+#define		HSIO_PHY_X1_LPCG	0x5F090000
+#define		HSIO_PHY_X2_LPCG	0x5F080000
+#define		HSIO_SATA_LPCG		0x5F070000
+#define		HSIO_PCIE_X1_LPCG	0x5F060000
+#define		HSIO_PCIE_X2_LPCG	0x5F050000
+
+/* M4 SS */
+#define		M4_0_I2C_LPCG		0x37630000
+#define		M4_0_LPUART_LPCG	0x37620000
+#define		M4_0_LPIT_LPCG		0x37610000
+#define		M4_1_I2C_LPCG		0x3B630000
+#define		M4_1_LPUART_LPCG	0x3B620000
+#define		M4_1_LPIT_LPCG		0x3B610000
+
+/* Audio SS */
+#define		AUD_ASRC_0_LPCG		0x59400000
+#define		AUD_ESAI_0_LPCG		0x59410000
+#define		AUD_SPDIF_0_LPCG	0x59420000
+#define		AUD_SAI_0_LPCG		0x59440000
+#define		AUD_SAI_1_LPCG		0x59450000
+#define		AUD_SAI_2_LPCG		0x59460000
+#define		AUD_SAI_3_LPCG		0x59470000
+#define		AUD_GPT_5_LPCG		0x594B0000
+#define		AUD_GPT_6_LPCG		0x594C0000
+#define		AUD_GPT_7_LPCG		0x594D0000
+#define		AUD_GPT_8_LPCG		0x594E0000
+#define		AUD_GPT_9_LPCG		0x594F0000
+#define		AUD_GPT_10_LPCG		0x59500000
+#define		AUD_HIFI_LPCG		0x59580000
+#define		AUD_OCRAM_LPCG		0x59590000
+#define		AUD_EDMA_0_LPCG		0x595f0000
+#define		AUD_ASRC_1_LPCG		0x59c00000
+#define		AUD_SAI_4_LPCG		0x59c20000
+#define		AUD_SAI_5_LPCG		0x59c30000
+#define		AUD_AMIX_LPCG		0x59c40000
+#define		AUD_MQS_LPCG		0x59c50000
+#define		AUD_ACM_LPCG		0x59c60000
+#define		AUD_REC_CLK0_LPCG	0x59d00000
+#define		AUD_REC_CLK1_LPCG	0x59d10000
+#define		AUD_PLL_CLK0_LPCG	0x59d20000
+#define		AUD_PLL_CLK1_LPCG	0x59d30000
+#define		AUD_MCLKOUT0_LPCG	0x59d50000
+#define		AUD_MCLKOUT1_LPCG	0x59d60000
+#define		AUD_EDMA_1_LPCG		0x59df0000
+
+
+/* Connectivity SS */
+#define		USDHC_0_LPCG		0x5B200000
+#define		USDHC_1_LPCG		0x5B210000
+#define		USDHC_2_LPCG		0x5B220000
+#define		ENET_0_LPCG		0x5B230000
+#define		ENET_1_LPCG		0x5B240000
+#define		DTCP_LPCG		0x5B250000
+#define		MLB_LPCG		0x5B260000
+#define		USB_2_LPCG		0x5B270000
+#define		USB_3_LPCG		0x5B280000
+#define		NAND_LPCG		0x5B290000
+#define		EDMA_LPCG		0x5B2A0000
+
+/* CM40 SS */
+#define		CM40_I2C_LPCG		0x37630000
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-14  8:07 ` [PATCH V4 05/11] clk: imx: scu: add scu clock gate A.s. Dong
@ 2018-10-15  7:32   ` Sascha Hauer
  2018-10-15  9:17     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Sascha Hauer @ 2018-10-15  7:32 UTC (permalink / raw)
  To: A.s. Dong
  Cc: linux-clk, sboyd, mturquette, dl-linux-imx, kernel,
	Fabio Estevam, shawnguo, linux-arm-kernel

On Sun, Oct 14, 2018 at 08:07:56AM +0000, A.s. Dong wrote:
> +/* Write to the LPCG bits. */
> +static int clk_gate_scu_enable(struct clk_hw *hw)
> +{
> +	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
> +	u32 reg;
> +
> +	if (gate->reg) {
> +		reg = readl(gate->reg);
> +		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
> +		if (gate->hw_gate)
> +			reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
> +				CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
> +		else
> +			reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
> +		writel(reg, gate->reg);
> +	}

These register manipulations look like they need locking.

> +
> +	return 0;
> +}
> +
> +struct clk_hw *clk_register_gate_scu(const char *name, const char *parent_name,
> +				     unsigned long flags, u32 rsrc_id,
> +				     u8 clk_type, void __iomem *reg,
> +				     u8 bit_idx, bool hw_gate)
> +{
> +	struct clk_gate_scu *gate;
> +	struct clk_init_data init;
> +	struct clk_hw *hw;
> +	int ret;
> +
> +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +	if (!gate)
> +		return ERR_PTR(-ENOMEM);
> +
> +	gate->rsrc_id = rsrc_id;
> +	gate->clk_type = clk_type;
> +	if (reg) {
> +		gate->reg = ioremap((phys_addr_t)reg, SZ_64K);

ioremap never takes a void __iomem * as argument. Given that you have to
cast it here to another type and to void __iomem * when calling this
function is a clear sign that the type of this variable is poorly
chosen.

> +		if (!gate->reg) {
> +			kfree(gate);
> +			return ERR_PTR(-ENOMEM);
> +		}
> +	}
> +
> +	gate->bit_idx = bit_idx;
> +	gate->hw_gate = hw_gate;
> +
> +	init.name = name;
> +	init.ops = &clk_gate_scu_ops;
> +	init.flags = flags;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +
> +	gate->hw.init = &init;
> +
> +	hw = &gate->hw;
> +	ret = clk_hw_register(NULL, hw);
> +	if (ret) {
> +		iounmap(gate->reg);

Is iounmap on a NULL pointer allowed? Otherwise the error path is wrong
here.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-15  7:32   ` Sascha Hauer
@ 2018-10-15  9:17     ` A.s. Dong
  2018-10-15  9:53       ` Sascha Hauer
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-15  9:17 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-clk, sboyd, mturquette, dl-linux-imx, kernel,
	Fabio Estevam, shawnguo, linux-arm-kernel

> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> Sent: Monday, October 15, 2018 3:32 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: linux-clk@vger.kernel.org; sboyd@kernel.org; mturquette@baylibre.com;
> dl-linux-imx <linux-imx@nxp.com>; kernel@pengutronix.de; Fabio Estevam
> <fabio.estevam@nxp.com>; shawnguo@kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> 
> On Sun, Oct 14, 2018 at 08:07:56AM +0000, A.s. Dong wrote:
> > +/* Write to the LPCG bits. */
> > +static int clk_gate_scu_enable(struct clk_hw *hw) {
> > +	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
> > +	u32 reg;
> > +
> > +	if (gate->reg) {
> > +		reg = readl(gate->reg);
> > +		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
> > +		if (gate->hw_gate)
> > +			reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
> > +				CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
> > +		else
> > +			reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
> > +		writel(reg, gate->reg);
> > +	}
> 
> These register manipulations look like they need locking.
> 

Unlike the legacy MX6&7 SoCs, each clock has a separate LPCG register.
Do we still need locking?

> > +
> > +	return 0;
> > +}
> > +
> > +struct clk_hw *clk_register_gate_scu(const char *name, const char
> *parent_name,
> > +				     unsigned long flags, u32 rsrc_id,
> > +				     u8 clk_type, void __iomem *reg,
> > +				     u8 bit_idx, bool hw_gate)
> > +{
> > +	struct clk_gate_scu *gate;
> > +	struct clk_init_data init;
> > +	struct clk_hw *hw;
> > +	int ret;
> > +
> > +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> > +	if (!gate)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	gate->rsrc_id = rsrc_id;
> > +	gate->clk_type = clk_type;
> > +	if (reg) {
> > +		gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
> 
> ioremap never takes a void __iomem * as argument. Given that you have to
> cast it here to another type and to void __iomem * when calling this function
> is a clear sign that the type of this variable is poorly chosen.
> 

Good catch. I missed it.
Thanks for pointing it out.
Looks like I should use struct phy_addr_t for it by default.

> > +		if (!gate->reg) {
> > +			kfree(gate);
> > +			return ERR_PTR(-ENOMEM);
> > +		}
> > +	}
> > +
> > +	gate->bit_idx = bit_idx;
> > +	gate->hw_gate = hw_gate;
> > +
> > +	init.name = name;
> > +	init.ops = &clk_gate_scu_ops;
> > +	init.flags = flags;
> > +	init.parent_names = parent_name ? &parent_name : NULL;
> > +	init.num_parents = parent_name ? 1 : 0;
> > +
> > +	gate->hw.init = &init;
> > +
> > +	hw = &gate->hw;
> > +	ret = clk_hw_register(NULL, hw);
> > +	if (ret) {
> > +		iounmap(gate->reg);
> 
> Is iounmap on a NULL pointer allowed? Otherwise the error path is wrong
> here.
> 

If gate->reg is NULL, the execution seems can't reach here.
Am I missing something?

Regards
Dong Aisheng

> Sascha
> 
> --
> Pengutronix e.K.                           |
> |
> Industrial Linux Solutions                 |
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.
> pengutronix.de%2F&amp;data=02%7C01%7Caisheng.dong%40nxp.com%7Ca8
> dc9d70c490491d116b08d6327050dc%7C686ea1d3bc2b4c6fa92cd99c5c3016
> 35%7C0%7C0%7C636751855312147344&amp;sdata=RkcPJ0TNLnFP%2BBbTh
> VrApN3Z%2B7MRR8%2FxJO1TSnqBv40%3D&amp;reserved=0  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0
> |
> Amtsgericht Hildesheim, HRA 2686           | Fax:
> +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-15  9:17     ` A.s. Dong
@ 2018-10-15  9:53       ` Sascha Hauer
  2018-10-15 15:30         ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Sascha Hauer @ 2018-10-15  9:53 UTC (permalink / raw)
  To: A.s. Dong
  Cc: linux-clk, sboyd, mturquette, dl-linux-imx, kernel,
	Fabio Estevam, shawnguo, linux-arm-kernel

On Mon, Oct 15, 2018 at 09:17:14AM +0000, A.s. Dong wrote:
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > Sent: Monday, October 15, 2018 3:32 PM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: linux-clk@vger.kernel.org; sboyd@kernel.org; mturquette@baylibre.com;
> > dl-linux-imx <linux-imx@nxp.com>; kernel@pengutronix.de; Fabio Estevam
> > <fabio.estevam@nxp.com>; shawnguo@kernel.org;
> > linux-arm-kernel@lists.infradead.org
> > Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> > 
> > On Sun, Oct 14, 2018 at 08:07:56AM +0000, A.s. Dong wrote:
> > > +/* Write to the LPCG bits. */
> > > +static int clk_gate_scu_enable(struct clk_hw *hw) {
> > > +	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
> > > +	u32 reg;
> > > +
> > > +	if (gate->reg) {
> > > +		reg = readl(gate->reg);
> > > +		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
> > > +		if (gate->hw_gate)
> > > +			reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
> > > +				CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
> > > +		else
> > > +			reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
> > > +		writel(reg, gate->reg);
> > > +	}
> > 
> > These register manipulations look like they need locking.
> > 
> 
> Unlike the legacy MX6&7 SoCs, each clock has a separate LPCG register.
> Do we still need locking?

Let's take PWM_0_LPCG as an example:

+       clks[IMX8QXP_LSIO_PWM0_IPG_S_CLK]       = imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x10, 0);
+       clks[IMX8QXP_LSIO_PWM0_IPG_SLV_CLK]     = imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x14, 0);
+       clks[IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK]    = imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_0_LPCG), 0x18, 0);
+       clks[IMX8QXP_LSIO_PWM0_HF_CLK]          = imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 4, 0);
+       clks[IMX8QXP_LSIO_PWM0_CLK]             = imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0, 0);

This register is used in five different clocks.

> 
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +struct clk_hw *clk_register_gate_scu(const char *name, const char
> > *parent_name,
> > > +				     unsigned long flags, u32 rsrc_id,
> > > +				     u8 clk_type, void __iomem *reg,
> > > +				     u8 bit_idx, bool hw_gate)
> > > +{
> > > +	struct clk_gate_scu *gate;
> > > +	struct clk_init_data init;
> > > +	struct clk_hw *hw;
> > > +	int ret;
> > > +
> > > +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> > > +	if (!gate)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	gate->rsrc_id = rsrc_id;
> > > +	gate->clk_type = clk_type;
> > > +	if (reg) {
> > > +		gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
> > 
> > ioremap never takes a void __iomem * as argument. Given that you have to
> > cast it here to another type and to void __iomem * when calling this function
> > is a clear sign that the type of this variable is poorly chosen.
> > 
> 
> Good catch. I missed it.
> Thanks for pointing it out.
> Looks like I should use struct phy_addr_t for it by default.
> 
> > > +		if (!gate->reg) {
> > > +			kfree(gate);
> > > +			return ERR_PTR(-ENOMEM);
> > > +		}
> > > +	}
> > > +
> > > +	gate->bit_idx = bit_idx;
> > > +	gate->hw_gate = hw_gate;
> > > +
> > > +	init.name = name;
> > > +	init.ops = &clk_gate_scu_ops;
> > > +	init.flags = flags;
> > > +	init.parent_names = parent_name ? &parent_name : NULL;
> > > +	init.num_parents = parent_name ? 1 : 0;
> > > +
> > > +	gate->hw.init = &init;
> > > +
> > > +	hw = &gate->hw;
> > > +	ret = clk_hw_register(NULL, hw);
> > > +	if (ret) {
> > > +		iounmap(gate->reg);
> > 
> > Is iounmap on a NULL pointer allowed? Otherwise the error path is wrong
> > here.
> > 
> 
> If gate->reg is NULL, the execution seems can't reach here.
> Am I missing something?

Yes. gate->reg is only valid when the input parameter reg in non NULL.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-15  9:53       ` Sascha Hauer
@ 2018-10-15 15:30         ` A.s. Dong
  2018-10-16 21:18           ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-15 15:30 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-clk, sboyd, mturquette, dl-linux-imx, kernel,
	Fabio Estevam, shawnguo, linux-arm-kernel

> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> Sent: Monday, October 15, 2018 5:54 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: linux-clk@vger.kernel.org; sboyd@kernel.org; mturquette@baylibre.com;
> dl-linux-imx <linux-imx@nxp.com>; kernel@pengutronix.de; Fabio Estevam
> <fabio.estevam@nxp.com>; shawnguo@kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> 
> On Mon, Oct 15, 2018 at 09:17:14AM +0000, A.s. Dong wrote:
> > > -----Original Message-----
> > > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > > Sent: Monday, October 15, 2018 3:32 PM
> > > To: A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: linux-clk@vger.kernel.org; sboyd@kernel.org;
> > > mturquette@baylibre.com; dl-linux-imx <linux-imx@nxp.com>;
> > > kernel@pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>;
> > > shawnguo@kernel.org; linux-arm-kernel@lists.infradead.org
> > > Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> > >
> > > On Sun, Oct 14, 2018 at 08:07:56AM +0000, A.s. Dong wrote:
> > > > +/* Write to the LPCG bits. */
> > > > +static int clk_gate_scu_enable(struct clk_hw *hw) {
> > > > +	struct clk_gate_scu *gate = to_clk_gate_scu(hw);
> > > > +	u32 reg;
> > > > +
> > > > +	if (gate->reg) {
> > > > +		reg = readl(gate->reg);
> > > > +		reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
> > > > +		if (gate->hw_gate)
> > > > +			reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
> > > > +				CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
> > > > +		else
> > > > +			reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
> > > > +		writel(reg, gate->reg);
> > > > +	}
> > >
> > > These register manipulations look like they need locking.
> > >
> >
> > Unlike the legacy MX6&7 SoCs, each clock has a separate LPCG register.
> > Do we still need locking?
> 
> Let's take PWM_0_LPCG as an example:
> 
> +       clks[IMX8QXP_LSIO_PWM0_IPG_S_CLK]       =
> imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", IMX_SC_R_PWM_0,
> IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x10, 0);
> +       clks[IMX8QXP_LSIO_PWM0_IPG_SLV_CLK]     =
> imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk",
> IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG),
> 0x14, 0);
> +       clks[IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK]    =
> imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", (void
> __iomem *)(PWM_0_LPCG), 0x18, 0);
> +       clks[IMX8QXP_LSIO_PWM0_HF_CLK]          =
> imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0,
> IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 4, 0);
> +       clks[IMX8QXP_LSIO_PWM0_CLK]             =
> imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0,
> IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0, 0);
> 
> This register is used in five different clocks.
> 

Good catch.
BTW, it seems for the same clk group, we may still not need lock
as the clock framework already defined the global enable/disable lock
for the same group.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/driver-api/clk.rst
" Drivers don't need to manually protect resources shared between the operations
of one group, regardless of whether those resources are shared by multiple
clocks or not. However, access to resources that are shared between operations
of the two groups needs to be protected by the drivers."

Do you think it's okay to drop it?

Regards
Dong Aisheng

> >
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +struct clk_hw *clk_register_gate_scu(const char *name, const char
> > > *parent_name,
> > > > +				     unsigned long flags, u32 rsrc_id,
> > > > +				     u8 clk_type, void __iomem *reg,
> > > > +				     u8 bit_idx, bool hw_gate) {
> > > > +	struct clk_gate_scu *gate;
> > > > +	struct clk_init_data init;
> > > > +	struct clk_hw *hw;
> > > > +	int ret;
> > > > +
> > > > +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> > > > +	if (!gate)
> > > > +		return ERR_PTR(-ENOMEM);
> > > > +
> > > > +	gate->rsrc_id = rsrc_id;
> > > > +	gate->clk_type = clk_type;
> > > > +	if (reg) {
> > > > +		gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
> > >
> > > ioremap never takes a void __iomem * as argument. Given that you
> > > have to cast it here to another type and to void __iomem * when
> > > calling this function is a clear sign that the type of this variable is poorly
> chosen.
> > >
> >
> > Good catch. I missed it.
> > Thanks for pointing it out.
> > Looks like I should use struct phy_addr_t for it by default.
> >
> > > > +		if (!gate->reg) {
> > > > +			kfree(gate);
> > > > +			return ERR_PTR(-ENOMEM);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	gate->bit_idx = bit_idx;
> > > > +	gate->hw_gate = hw_gate;
> > > > +
> > > > +	init.name = name;
> > > > +	init.ops = &clk_gate_scu_ops;
> > > > +	init.flags = flags;
> > > > +	init.parent_names = parent_name ? &parent_name : NULL;
> > > > +	init.num_parents = parent_name ? 1 : 0;
> > > > +
> > > > +	gate->hw.init = &init;
> > > > +
> > > > +	hw = &gate->hw;
> > > > +	ret = clk_hw_register(NULL, hw);
> > > > +	if (ret) {
> > > > +		iounmap(gate->reg);
> > >
> > > Is iounmap on a NULL pointer allowed? Otherwise the error path is
> > > wrong here.
> > >
> >
> > If gate->reg is NULL, the execution seems can't reach here.
> > Am I missing something?
> 
> Yes. gate->reg is only valid when the input parameter reg in non NULL.
> 
> Sascha
> 
> 
> --
> Pengutronix e.K.                           |
> |
> Industrial Linux Solutions                 |
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.
> pengutronix.de%2F&amp;data=02%7C01%7Caisheng.dong%40nxp.com%7C11
> c8f62f729749de7b8708d63284183f%7C686ea1d3bc2b4c6fa92cd99c5c30163
> 5%7C0%7C0%7C636751940255777834&amp;sdata=tsICGc0z9Rcfgu4YcKWy5
> hu8sFHXeRYSy3lP8CjtxO8%3D&amp;reserved=0  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0
> |
> Amtsgericht Hildesheim, HRA 2686           | Fax:
> +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-15 15:30         ` A.s. Dong
@ 2018-10-16 21:18           ` Stephen Boyd
  2018-10-17  7:28             ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:18 UTC (permalink / raw)
  To: A.s. Dong, Sascha Hauer
  Cc: linux-clk, mturquette, dl-linux-imx, kernel, Fabio Estevam,
	shawnguo, linux-arm-kernel

Quoting A.s. Dong (2018-10-15 08:30:45)
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > Sent: Monday, October 15, 2018 5:54 PM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: linux-clk@vger.kernel.org; sboyd@kernel.org; mturquette@baylibre.com;
> > dl-linux-imx <linux-imx@nxp.com>; kernel@pengutronix.de; Fabio Estevam
> > <fabio.estevam@nxp.com>; shawnguo@kernel.org;
> > linux-arm-kernel@lists.infradead.org
> > Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> > 
> > On Mon, Oct 15, 2018 at 09:17:14AM +0000, A.s. Dong wrote:
> > > > -----Original Message-----
> > > > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > > > Sent: Monday, October 15, 2018 3:32 PM
> > > > To: A.s. Dong <aisheng.dong@nxp.com>
> > > > Cc: linux-clk@vger.kernel.org; sboyd@kernel.org;
> > > > mturquette@baylibre.com; dl-linux-imx <linux-imx@nxp.com>;
> > > > kernel@pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>;
> > > > shawnguo@kernel.org; linux-arm-kernel@lists.infradead.org
> > > > Subject: Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
> > > >
> > > > On Sun, Oct 14, 2018 at 08:07:56AM +0000, A.s. Dong wrote:
> > > > > +/* Write to the LPCG bits. */
> > > > > +static int clk_gate_scu_enable(struct clk_hw *hw) {
> > > > > +       struct clk_gate_scu *gate = to_clk_gate_scu(hw);
> > > > > +       u32 reg;
> > > > > +
> > > > > +       if (gate->reg) {
> > > > > +               reg = readl(gate->reg);
> > > > > +               reg &= ~(CLK_GATE_SCU_LPCG_MASK << gate->bit_idx);
> > > > > +               if (gate->hw_gate)
> > > > > +                       reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
> > > > > +                               CLK_GATE_SCU_LPCG_SW_SEL) << gate->bit_idx;
> > > > > +               else
> > > > > +                       reg |= (CLK_GATE_SCU_LPCG_SW_SEL << gate->bit_idx);
> > > > > +               writel(reg, gate->reg);
> > > > > +       }
> > > >
> > > > These register manipulations look like they need locking.
> > > >
> > >
> > > Unlike the legacy MX6&7 SoCs, each clock has a separate LPCG register.
> > > Do we still need locking?
> > 
> > Let's take PWM_0_LPCG as an example:
> > 
> > +       clks[IMX8QXP_LSIO_PWM0_IPG_S_CLK]       =
> > imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", IMX_SC_R_PWM_0,
> > IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x10, 0);
> > +       clks[IMX8QXP_LSIO_PWM0_IPG_SLV_CLK]     =
> > imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk",
> > IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG),
> > 0x14, 0);
> > +       clks[IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK]    =
> > imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", (void
> > __iomem *)(PWM_0_LPCG), 0x18, 0);
> > +       clks[IMX8QXP_LSIO_PWM0_HF_CLK]          =
> > imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0,
> > IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 4, 0);
> > +       clks[IMX8QXP_LSIO_PWM0_CLK]             =
> > imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", IMX_SC_R_PWM_0,
> > IMX_SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0, 0);
> > 
> > This register is used in five different clocks.
> > 
> 
> Good catch.
> BTW, it seems for the same clk group, we may still not need lock
> as the clock framework already defined the global enable/disable lock
> for the same group.
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/driver-api/clk.rst
> " Drivers don't need to manually protect resources shared between the operations
> of one group, regardless of whether those resources are shared by multiple
> clocks or not. However, access to resources that are shared between operations
> of the two groups needs to be protected by the drivers."
> 
> Do you think it's okay to drop it?
> 

No it's not OK. We prefer that clk drivers don't assume the global locks
in the clk framework are going to protect them from concurrent access to
the same resource between different clks. Drivers can assume that a clk
op won't be called in parallel for the same clk, but they shouldn't
assume that everything is protected otherwise. If they did, we would
have to go find all the drivers that make this assumption and then fix
them when we eventually split the lock into smaller pieces.

Long story short, if you have something shared (i.e. a register) and you
plan to write to it and read from it for multiple clks, add a lock
around it.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-14  8:07 ` [PATCH V4 03/11] clk: imx: scu: add scu clock divider A.s. Dong
@ 2018-10-16 21:26   ` Stephen Boyd
  2018-10-17  8:56     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:26 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:07:49)
> diff --git a/drivers/clk/imx/scu/clk-divider-scu.c b/drivers/clk/imx/scu/clk-divider-scu.c
> new file mode 100644
> index 0000000..51cb816
> --- /dev/null
> +++ b/drivers/clk/imx/scu/clk-divider-scu.c
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017~2018 NXP
> + *     Dong Aisheng <aisheng.dong@nxp.com>
> + *
> + */
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>

Is this used?

> +#include <linux/slab.h>
> +
> +#include "clk-scu.h"
> +
> +struct clk_divider_scu {
> +       struct clk_hw   hw;

Nitpick: No idea why this is spaced out from clk_hw.

> +       u32 rsrc_id;
> +       u8 clk_type;
> +};
> +
> +/* SCU Clock Protocol definitions */
> +struct imx_sc_msg_req_set_clock_rate {
> +       struct imx_sc_rpc_msg hdr;
> +       u32 rate;
> +       u16 resource;
> +       u8 clk;
> +} __packed;
> +
> +struct imx_sc_msg_req_get_clock_rate {
> +       struct imx_sc_rpc_msg hdr;
> +       u16 resource;
> +       u8 clk;
> +} __packed;
> +
> +struct imx_sc_msg_resp_get_clock_rate {
> +       struct imx_sc_rpc_msg hdr;
> +       u32 rate;
> +} __packed;
> +
> +
> +static inline struct clk_divider_scu *to_clk_divider_scu(struct clk_hw *hw)
> +{
> +       return container_of(hw, struct clk_divider_scu, hw);
> +}
> +
> +/*
> + * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
> + * @hw: clock to get rate for
> + * @parent_rate: parent rate provided by common clock framework, not used
> + *
> + * Gets the current clock rate of a SCU clock. Returns the current
> + * clock rate, or zero in failure.
> + */
> +static unsigned long clk_divider_scu_recalc_rate(struct clk_hw *hw,
> +                                                 unsigned long parent_rate)
> +{
> +       struct clk_divider_scu *div = to_clk_divider_scu(hw);
> +       struct imx_sc_msg_req_get_clock_rate msg;
> +       struct imx_sc_msg_resp_get_clock_rate *resp;
> +       struct imx_sc_rpc_msg *hdr = &msg.hdr;
> +       int ret;
> +
> +       hdr->ver = IMX_SC_RPC_VERSION;
> +       hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
> +       hdr->func = (uint8_t)IMX_SC_PM_FUNC_GET_CLOCK_RATE;
> +       hdr->size = 2;
> +
> +       msg.resource = div->rsrc_id;
> +       msg.clk = div->clk_type;
> +
> +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> +       if (ret) {
> +               pr_err("%s: failed to get clock rate %d\n",
> +                       clk_hw_get_name(hw), ret);
> +               return 0;
> +       }
> +
> +       resp = (struct imx_sc_msg_resp_get_clock_rate *)&msg;

Does the response get written to the same place that the message is
written? If so, it would be better to combine the different structs into
a union that's always large enough to handle this? For example, it looks
like there are only 16 + 8 bytes for the get_clock_rate structure, but
then the response is returning the rate in 32 bytes. When we cast that
here we're now getting an extra 8 bytes of stack, aren't we? Combining
the different structures into one bigger structure would alleviate this
and avoid the need for casting.

> +
> +       return resp->rate;
> +}
> +
> +/*
> + * clk_divider_scu_round_rate - Round clock rate for a SCU clock
> + * @hw: clock to round rate for
> + * @rate: rate to round
> + * @parent_rate: parent rate provided by common clock framework, not used
> + *
> + * Gets the current clock rate of a SCU clock. Returns the current
> + * clock rate, or zero in failure.
> + */
> +static long clk_divider_scu_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                      unsigned long *parent_rate)
> +{
> +       /*
> +        * Assume we support all the requested rate and let the SCU firmware
> +        * to handle the left work
> +        */
> +       return rate;
> +}
> +
> +/*
> + * clk_divider_scu_set_rate - Set rate for a SCU clock
> + * @hw: clock to change rate for
> + * @rate: target rate for the clock
> + * @parent_rate: rate of the clock parent, not used for SCU clocks
> + *
> + * Sets a clock frequency for a SCU clock. Returns the SCU
> + * protocol status.
> + */
> +static int clk_divider_scu_set_rate(struct clk_hw *hw, unsigned long rate,
> +                                   unsigned long parent_rate)
> +{
> +       struct clk_divider_scu *div = to_clk_divider_scu(hw);
> +       struct imx_sc_msg_req_set_clock_rate msg;
> +       struct imx_sc_rpc_msg *hdr = &msg.hdr;
> +       int ret;
> +
> +       hdr->ver = IMX_SC_RPC_VERSION;
> +       hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
> +       hdr->func = (uint8_t)IMX_SC_PM_FUNC_SET_CLOCK_RATE;

Are these casts necessary?

> +       hdr->size = 3;
> +
> +       msg.rate = rate;
> +       msg.resource = div->rsrc_id;
> +       msg.clk = div->clk_type;
> +
> +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> +       if (ret)
> +               pr_err("%s: failed to set clock rate %ld : ret %d\n",
> +                       clk_hw_get_name(hw), rate, ret);
> +
> +       return 0;
> +}
> +
> +static const struct clk_ops clk_divider_scu_ops = {
> +       .recalc_rate = clk_divider_scu_recalc_rate,
> +       .round_rate = clk_divider_scu_round_rate,
> +       .set_rate = clk_divider_scu_set_rate,
> +};
> +
> +struct clk_hw *imx_clk_register_divider_scu(const char *name,
> +                                           const char *parent_name,
> +                                           u32 rsrc_id,
> +                                           u8 clk_type)
> +{
> +       struct clk_divider_scu *div;
> +       struct clk_init_data init;
> +       struct clk_hw *hw;
> +       int ret;
> +
> +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> +       if (!div)
> +               return ERR_PTR(-ENOMEM);
> +
> +       div->rsrc_id = rsrc_id;
> +       div->clk_type = clk_type;
> +
> +       init.name = name;
> +       init.ops = &clk_divider_scu_ops;
> +       init.flags = CLK_GET_RATE_NOCACHE;

Why nocache? Please have a good reason and add a comment indicating why.

> +       init.parent_names = parent_name ? &parent_name : NULL;
> +       init.num_parents = parent_name ? 1 : 0;
> +       div->hw.init = &init;
> +
> +       hw = &div->hw;
> +       ret = clk_hw_register(NULL, hw);
> +       if (ret) {
> +               kfree(div);
> +               hw = ERR_PTR(ret);
> +       }
> +
> +       return hw;
> +}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider
  2018-10-14  8:07 ` [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider A.s. Dong
@ 2018-10-16 21:27   ` Stephen Boyd
  2018-10-17  9:03     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:27 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:07:52)
> +/*
> + * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
> + * @hw: clock to get rate for
> + * @parent_rate: parent rate provided by common clock framework
> + *
> + * Gets the current clock rate of a SCU clock. Returns the current
> + * clock rate, or zero in failure.
> + */
> +static unsigned long clk_divider_gpr_scu_recalc_rate(struct clk_hw *hw,
> +                                                    unsigned long parent_rate)
> +{
> +       struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
> +       u32 val;
> +       int ret;
> +
> +       ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
> +                                     clk->gpr_id, &val);
> +       if (ret) {
> +               pr_err("%s: failed to get clock rate %d\n",
> +                       clk_hw_get_name(hw), ret);
> +               return 0;
> +       }
> +
> +       return val ? parent_rate / 2 : parent_rate;

I hope parent_rate can't be zero here.

> +}
> +
> +/*
> + * clk_divider_scu_round_rate - Round clock rate for a SCU clock
> + * @hw: clock to round rate for
> + * @rate: rate to round
> + * @parent_rate: parent rate provided by common clock framework
> + *
> + * Round clock rate for a SCU clock according to parent rate
> + */
> +static long clk_divider_gpr_scu_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                          unsigned long *prate)
> +{
> +       if (rate < *prate)
> +               rate = *prate / 2;
> +       else
> +               rate = *prate;
> +
> +       return rate;
> +}
> +
> +/*
> + * clk_divider_scu_set_rate - Set rate for a SCU clock
> + * @hw: clock to change rate for
> + * @rate: target rate for the clock
> + * @parent_rate: rate of the clock parent
> + *
> + * Sets a clock frequency for a SCU clock. Returns the SCU
> + * protocol status.
> + */
> +static int clk_divider_gpr_scu_set_rate(struct clk_hw *hw, unsigned long rate,
> +                                       unsigned long parent_rate)
> +{
> +       struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
> +       uint32_t val;
> +
> +       val = (rate < parent_rate) ? 1 : 0;

Nitpick: Write it out as 

	val = 0;
	if (rate < parent_rate)
		val = 1;

> +
> +       return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
> +                                      clk->gpr_id, val);
> +}
> +
> +static const struct clk_ops clk_divider_gpr_scu_ops = {
> +       .recalc_rate = clk_divider_gpr_scu_recalc_rate,
> +       .round_rate = clk_divider_gpr_scu_round_rate,
> +       .set_rate = clk_divider_gpr_scu_set_rate,
> +};
> +
> +struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
> +                                      u32 rsrc_id, u8 gpr_id)
> +{
> +       struct clk_divider_gpr_scu *div;
> +       struct clk_init_data init;
> +       struct clk_hw *hw;
> +       int ret;
> +
> +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> +       if (!div)
> +               return ERR_PTR(-ENOMEM);
> +
> +       div->rsrc_id = rsrc_id;
> +       div->gpr_id = gpr_id;
> +
> +       init.name = name;
> +       init.ops = &clk_divider_gpr_scu_ops;
> +       init.flags = CLK_GET_RATE_NOCACHE;

Same NOCACHE comment.

> +       init.parent_names = parent_name ? &parent_name : NULL;
> +       init.num_parents = parent_name ? 1 : 0;
> +
> +       div->hw.init = &init;
> +
> +       hw = &div->hw;
> +       ret = clk_hw_register(NULL, hw);
> +       if (ret) {
> +               kfree(div);
> +               hw = ERR_PTR(ret);
> +       }
> +
> +       return hw;
> +}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux
  2018-10-14  8:08 ` [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux A.s. Dong
@ 2018-10-16 21:30   ` Stephen Boyd
  2018-10-17  9:07     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:30 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:08:06)
> diff --git a/drivers/clk/imx/scu/clk-mux-gpr-scu.c b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> new file mode 100644
> index 0000000..2ad7a80
> --- /dev/null
> +++ b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017~2018 NXP
> + *     Dong Aisheng <aisheng.dong@nxp.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +
> +#include "clk-scu.h"
> +
> +struct clk_mux_gpr_scu {
> +       struct clk_hw hw;
> +       u32     rsrc_id;
> +       u8      gpr_id;
> +};
> +
> +#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct clk_mux_gpr_scu, hw)
> +
> +static u8 clk_mux_gpr_scu_get_parent(struct clk_hw *hw)
> +{
> +       struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
> +       u32 val = 0;
> +       int ret;
> +
> +       ret = imx_sc_misc_get_control(ccm_ipc_handle, gpr_mux->rsrc_id,
> +                                     gpr_mux->gpr_id, &val);
> +       if (ret) {
> +               pr_err("%s: failed to get clock parent %d\n",
> +                       clk_hw_get_name(hw), ret);
> +               return 0;
> +       }
> +
> +       return (u8)val;

Nitpick: Please drop explicit casts.

> +}
> +
> +static int clk_mux_gpr_scu_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
> +       int ret;
> +
> +       ret = imx_sc_misc_set_control(ccm_ipc_handle, gpr_mux->rsrc_id,
> +                                     gpr_mux->gpr_id, index);
> +       if (ret)
> +               pr_err("%s: failed to set clock parent %d\n",
> +                       clk_hw_get_name(hw), ret);

Nitpick: These printks are cluttering the code, any chance they can be
removed and you can rely on callers to care if something failed?

> +
> +       return ret;
> +}
> +
> +static const struct clk_ops clk_mux_gpr_scu_ops = {
> +       .get_parent = clk_mux_gpr_scu_get_parent,
> +       .set_parent = clk_mux_gpr_scu_set_parent,
> +};
> +
> +struct clk_hw *clk_register_mux_gpr_scu(const char *name, const char * const *parents,

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 02/11] clk: imx: scu: add scu clock common part
  2018-10-14  8:07 ` [PATCH V4 02/11] clk: imx: scu: add scu clock common part A.s. Dong
@ 2018-10-16 21:31   ` Stephen Boyd
  2018-10-17  9:11     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:31 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:07:45)
> Add scu clock common part which will be used by client clock drivers.
> 
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> ---
> ChangeLog:
> v3->v4:
>  * scu headfile path change
> v2->v3:
>  * no changes
> v1->v2:
>  * update function call name
> ---
>  drivers/clk/imx/Kconfig       |  2 ++
>  drivers/clk/imx/Makefile      |  2 ++
>  drivers/clk/imx/scu/Kconfig   |  5 +++++
>  drivers/clk/imx/scu/Makefile  |  4 ++++
>  drivers/clk/imx/scu/clk-scu.c | 17 +++++++++++++++++
>  drivers/clk/imx/scu/clk-scu.h | 18 ++++++++++++++++++

Why is scu nested one level deeper in the imx directory? Can't we just
keep them all within imx toplevel directory?

>  6 files changed, 48 insertions(+)
>  create mode 100644 drivers/clk/imx/scu/Kconfig
>  create mode 100644 drivers/clk/imx/scu/Makefile
>  create mode 100644 drivers/clk/imx/scu/clk-scu.c
>  create mode 100644 drivers/clk/imx/scu/clk-scu.h
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions
  2018-10-14  8:08 ` [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions A.s. Dong
@ 2018-10-16 21:32   ` Stephen Boyd
  2018-10-17  9:21     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:32 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:08:09)
> This may be used by both mmio and scu clks. So let's put it
> into a common file.
> 
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> ---
>  drivers/clk/imx/clk-common.h  | 16 ++++++++++++++++
>  drivers/clk/imx/scu/clk-scu.h |  2 ++
>  2 files changed, 18 insertions(+)
>  create mode 100644 drivers/clk/imx/clk-common.h
> 
> diff --git a/drivers/clk/imx/clk-common.h b/drivers/clk/imx/clk-common.h
> new file mode 100644
> index 0000000..e3634a5
> --- /dev/null
> +++ b/drivers/clk/imx/clk-common.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2018 NXP
> + */
> +
> +#ifndef __IMX_CLK_COMMON_H
> +#define __IMX_CLK_COMMON_H
> +
> +#include <linux/clk-provider.h>
> +
> +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
> +{
> +       return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
> +}

Why do we need this wrapper file? Just call the registration function
directly with the right arguments instead of wrapping them in another
function please.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function
  2018-10-14  8:08 ` [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function A.s. Dong
@ 2018-10-16 21:34   ` Stephen Boyd
  2018-10-17  9:24     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:34 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:08:13)
> Add imx_check_clk_hws helper function
> 
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> ---
>  drivers/clk/imx/clk-common.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/clk/imx/clk-common.h b/drivers/clk/imx/clk-common.h
> index e3634a5..01550fd 100644
> --- a/drivers/clk/imx/clk-common.h
> +++ b/drivers/clk/imx/clk-common.h
> @@ -13,4 +13,15 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
>         return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
>  }
>  
> +static inline void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
> +{
> +       unsigned int i;
> +
> +       for (i = 0; i < count; i++) {
> +               if (IS_ERR(clks[i]))
> +                       pr_err("i.MX clk %u: register failed with %ld\n",
> +                               i, PTR_ERR(clks[i]));
> +       }
> +}

And get rid of this too? I don't see the need for layers on top of code
snippets. Just write them many times in the same driver, and then
decide to consolidate that logic behind something larger than a few
helper functions.

> +

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
  2018-10-14  8:08 ` [PATCH V4 11/11] clk: imx: add imx8qxp clk driver A.s. Dong
@ 2018-10-16 21:38   ` Stephen Boyd
  2018-10-17  9:43     ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-16 21:38 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel, A.s. Dong

Quoting A.s. Dong (2018-10-14 01:08:16)
> diff --git a/drivers/clk/imx/scu/clk-imx8qxp.c b/drivers/clk/imx/scu/clk-imx8qxp.c
> new file mode 100644
> index 0000000..958c26d
> --- /dev/null
> +++ b/drivers/clk/imx/scu/clk-imx8qxp.c
> @@ -0,0 +1,425 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017~2018 NXP
> + *     Dong Aisheng <aisheng.dong@nxp.com>
> + */
> +
> +#include <dt-bindings/clock/imx8qxp-clock.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include <soc/imx/imx8qxp/lpcg.h>
> +
> +#include "clk-scu.h"
> +
> +static struct clk_hw_onecell_data *clk_data;

Please give this static global variable a more unique name as opposed to
'clk_data'.


> +
> +static const char * const enet_sels[] = { "enet_25MHz", "enet_125MHz", };
> +static const char * const enet0_rmii_tx_sels[] = { "enet0_ref_div", "dummy", };
> +static const char * const enet1_rmii_tx_sels[] = { "enet1_ref_div", "dummy", };
> +
> +static int imx8qxp_clk_probe(struct platform_device *pdev)
> +{
> +       struct device_node *ccm_node = pdev->dev.of_node;
> +       struct clk_hw **clks;
> +       int ret;
> +
> +       ret = imx_clk_scu_init();
> +       if (ret)
> +               return ret;
> +
> +       clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> +                               sizeof(*clk_data->hws) * IMX8QXP_CLK_END,
> +                               GFP_KERNEL);
> +       if (!clk_data)
> +               return -ENOMEM;
> +
> +       clk_data->num = IMX8QXP_CLK_END;
> +       clks = clk_data->hws;
> +
> +       /* Fixed clocks */
> +       clks[IMX8QXP_CLK_DUMMY]         = imx_clk_hw_fixed("dummy", 0);
> +       clks[IMX8QXP_24MHZ]             = imx_clk_hw_fixed("xtal_24MHz", 24000000);
> +       clks[IMX8QXP_GPT_3M]            = imx_clk_hw_fixed("gpt_3m", 3000000);
> +       clks[IMX8QXP_32KHZ]             = imx_clk_hw_fixed("xtal_32KHz", 32768);
> +
> +       /* ARM core */
> +       clks[IMX8QXP_A35_DIV]           = imx_clk_divider_scu("a35_div", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
> +
> +       clks[IMX8QXP_IPG_DMA_CLK_ROOT]  = imx_clk_hw_fixed("ipg_dma_clk_root", 120000000);
> +       clks[IMX8QXP_AXI_CONN_CLK_ROOT] = imx_clk_hw_fixed("axi_conn_clk_root", 333333333);
> +       clks[IMX8QXP_AHB_CONN_CLK_ROOT] = imx_clk_hw_fixed("ahb_conn_clk_root", 166666666);
> +       clks[IMX8QXP_IPG_CONN_CLK_ROOT] = imx_clk_hw_fixed("ipg_conn_clk_root", 83333333);
> +       clks[IMX8QXP_DC_AXI_EXT_CLK]    = imx_clk_hw_fixed("axi_ext_dc_clk_root", 800000000);
> +       clks[IMX8QXP_DC_AXI_INT_CLK]    = imx_clk_hw_fixed("axi_int_dc_clk_root", 400000000);
> +       clks[IMX8QXP_DC_CFG_CLK]        = imx_clk_hw_fixed("cfg_dc_clk_root", 100000000);
> +       clks[IMX8QXP_MIPI_IPG_CLK]      = imx_clk_hw_fixed("ipg_mipi_clk_root", 120000000);
> +       clks[IMX8QXP_IMG_AXI_CLK]       = imx_clk_hw_fixed("axi_img_clk_root", 400000000);
> +       clks[IMX8QXP_IMG_IPG_CLK]       = imx_clk_hw_fixed("ipg_img_clk_root", 200000000);
> +       clks[IMX8QXP_IMG_PXL_CLK]       = imx_clk_hw_fixed("pxl_img_clk_root", 600000000);
> +       clks[IMX8QXP_HSIO_AXI_CLK]      = imx_clk_hw_fixed("axi_hsio_clk_root", 400000000);
> +       clks[IMX8QXP_HSIO_PER_CLK]      = imx_clk_hw_fixed("per_hsio_clk_root", 133333333);

Can these fixed rate clks come from DT? Or what's going on here?

> +
> +       clks[IMX8QXP_UART0_DIV]         = imx_clk_divider_scu("uart0_div", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
> +       clks[IMX8QXP_UART0_IPG_CLK]     = imx_clk_gate2_scu("uart0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_0_LPCG), 16, 0);
> +       clks[IMX8QXP_UART0_CLK]         = imx_clk_gate_scu("uart0_clk", "uart0_div", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_0_LPCG), 0, 0);
> +
[...]
> +       clks[IMX8QXP_IMG_PDMA_2_CLK]            = imx_clk_gate2_scu("img_pdma2_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_2_LPCG), 0, 0);
> +       clks[IMX8QXP_IMG_PDMA_3_CLK]            = imx_clk_gate2_scu("img_pdma3_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_3_LPCG), 0, 0);
> +       clks[IMX8QXP_IMG_PDMA_4_CLK]            = imx_clk_gate2_scu("img_pdma4_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_4_LPCG), 0, 0);
> +       clks[IMX8QXP_IMG_PDMA_5_CLK]            = imx_clk_gate2_scu("img_pdma5_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_5_LPCG), 0, 0);
> +       clks[IMX8QXP_IMG_PDMA_6_CLK]            = imx_clk_gate2_scu("img_pdma6_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_6_LPCG), 0, 0);
> +       clks[IMX8QXP_IMG_PDMA_7_CLK]            = imx_clk_gate2_scu("img_pdma7_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_7_LPCG), 0, 0);

All the casts in here shouldn't be necessary, see below.

> +
> +       /* MIPI CSI SS */
> +       clks[IMX8QXP_CSI0_I2C0_DIV]     = imx_clk_divider_scu("mipi_csi0_i2c0_div", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
> +       clks[IMX8QXP_CSI0_PWM0_DIV]     = imx_clk_divider_scu("mipi_csi0_pwm0_div", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
> +       clks[IMX8QXP_CSI0_CORE_DIV]     = imx_clk_divider_scu("mipi_csi0_core_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
> +       clks[IMX8QXP_CSI0_ESC_DIV]      = imx_clk_divider_scu("mipi_csi0_esc_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
> +       clks[IMX8QXP_CSI0_IPG_CLK_S]    = imx_clk_gate2_scu("mipi_csi0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x8), 16, 0);
> +       clks[IMX8QXP_CSI0_IPG_CLK]      = imx_clk_gate2_scu("mipi_csi0_ipg", "mipi_csi0_ipg_s", (void __iomem *)(MIPI_CSI_0_LPCG), 16, 0);
> +       clks[IMX8QXP_CSI0_APB_CLK]      = imx_clk_gate2_scu("mipi_csi0_apb_clk", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x4), 16,  0);
> +       clks[IMX8QXP_CSI0_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_i2c0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 16, 0);
> +       clks[IMX8QXP_CSI0_I2C0_CLK]     = imx_clk_gate_scu("mipi_csi0_i2c0_clk", "mipi_csi0_i2c0_div", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 0, 0);
> +       clks[IMX8QXP_CSI0_PWM0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_pwm0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 16, 0);
> +       clks[IMX8QXP_CSI0_PWM0_CLK]     = imx_clk_gate_scu("mipi_csi0_pwm0_clk", "mipi_csi0_pwm0_div", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 0, 0);
> +       clks[IMX8QXP_CSI0_CORE_CLK]     = imx_clk_gate_scu("mipi_csi0_core_clk", "mipi_csi0_core_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x18), 16, 0);
> +       clks[IMX8QXP_CSI0_ESC_CLK]      = imx_clk_gate_scu("mipi_csi0_esc_clk", "mipi_csi0_esc_div", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, (void __iomem *)(MIPI_CSI_0_LPCG + 0x1C), 16, 0);
> +
> +       /* HSIO SS */
> +       clks[IMX8QXP_HSIO_PCIE_MSTR_AXI_CLK]    = imx_clk_gate2_scu("hsio_pcie_mstr_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_PCIE_SLV_AXI_CLK]     = imx_clk_gate2_scu("hsio_pcie_slv_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 20, 0);
> +       clks[IMX8QXP_HSIO_PCIE_DBI_AXI_CLK]     = imx_clk_gate2_scu("hsio_pcie_dbi_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 24, 0);
> +       clks[IMX8QXP_HSIO_PCIE_X1_PER_CLK]      = imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_CRR3_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_PHY_X1_PER_CLK]       = imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_CRR1_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_MISC_PER_CLK]         = imx_clk_gate2_scu("hsio_misc_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_MISC_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_PHY_X1_APB_CLK]       = imx_clk_gate2_scu("hsio_phy_x1_apb_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_GPIO_CLK]             = imx_clk_gate2_scu("hsio_gpio_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_GPIO_LPCG), 16, 0);
> +       clks[IMX8QXP_HSIO_PHY_X1_PCLK]          = imx_clk_gate2_scu("hsio_phy_x1_pclk", "dummy", (void __iomem *)(HSIO_PHY_X1_LPCG), 0, 0);
> +
> +       imx_check_clk_hws(clks, clk_data->num);
> +
> +       of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
> +
> +       pr_info("i.MX8QXP clock tree init done.\n");

Please no "I'm alive!" messages.

> +
> +       return 0;
> +}
> +
> +static const struct of_device_id imx8qxp_match[] = {
> +       { .compatible = "fsl,imx8qxp-clk", },
> +       { /* sentinel */ }
> +};
> +
> +static struct platform_driver imx8qxp_clk_driver = {
> +       .driver = {
> +               .name = "imx8qxp-clk",
> +               .of_match_table = imx8qxp_match,
> +       },
> +       .probe = imx8qxp_clk_probe,
> +};
> +
> +static int __init imx8qxp_clk_init(void)
> +{
> +       return platform_driver_register(&imx8qxp_clk_driver);
> +}
> +core_initcall(imx8qxp_clk_init);
> diff --git a/include/soc/imx/imx8qxp/lpcg.h b/include/soc/imx/imx8qxp/lpcg.h
> new file mode 100644
> index 0000000..afbb5da
> --- /dev/null
> +++ b/include/soc/imx/imx8qxp/lpcg.h
> @@ -0,0 +1,186 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017~2018 NXP
> + *
> + */
> +
> +#ifndef _SC_LPCG_H
> +#define _SC_LPCG_H
> +
> +/*LSIO SS */
> +#define                PWM_0_LPCG              0x5D400000

Are these virtual or physical addresses? Because up above they're casted
right into void __iomem pointers, which makes me thing they're virtual
addresses, but then that would mean there's some sort of static iomap
being used, but I'm not aware of anything like that.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 05/11] clk: imx: scu: add scu clock gate
  2018-10-16 21:18           ` Stephen Boyd
@ 2018-10-17  7:28             ` A.s. Dong
  0 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  7:28 UTC (permalink / raw)
  To: Stephen Boyd, Sascha Hauer
  Cc: linux-clk, mturquette, dl-linux-imx, kernel, Fabio Estevam,
	shawnguo, linux-arm-kernel


> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:19 AM

[...]

> > " Drivers don't need to manually protect resources shared between the
> > operations of one group, regardless of whether those resources are
> > shared by multiple clocks or not. However, access to resources that
> > are shared between operations of the two groups needs to be protected by
> the drivers."
> >
> > Do you think it's okay to drop it?
> >
> 
> No it's not OK. We prefer that clk drivers don't assume the global locks in the
> clk framework are going to protect them from concurrent access to the same
> resource between different clks. Drivers can assume that a clk op won't be
> called in parallel for the same clk, but they shouldn't assume that everything is
> protected otherwise. If they did, we would have to go find all the drivers that
> make this assumption and then fix them when we eventually split the lock into
> smaller pieces.
> 
> Long story short, if you have something shared (i.e. a register) and you plan to
> write to it and read from it for multiple clks, add a lock around it.

Okay, got it. Appreciated for the detailed explanation.

Regards
Dong Aisheng

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-16 21:26   ` Stephen Boyd
@ 2018-10-17  8:56     ` A.s. Dong
  2018-10-17 15:17       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  8:56 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:26 AM
> Quoting A.s. Dong (2018-10-14 01:07:49)
> > diff --git a/drivers/clk/imx/scu/clk-divider-scu.c
> > b/drivers/clk/imx/scu/clk-divider-scu.c
> > new file mode 100644
> > index 0000000..51cb816
> > --- /dev/null
> > +++ b/drivers/clk/imx/scu/clk-divider-scu.c
> > @@ -0,0 +1,176 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017~2018 NXP
> > + *     Dong Aisheng <aisheng.dong@nxp.com>
> > + *
> > + */
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/jiffies.h>
> 
> Is this used?
> 

Good catch, it's introduced by test code and should be removed.

> > +#include <linux/slab.h>
> > +
> > +#include "clk-scu.h"
> > +
> > +struct clk_divider_scu {
> > +       struct clk_hw   hw;
> 
> Nitpick: No idea why this is spaced out from clk_hw.
> 

Yes, better aligned.

> > +       u32 rsrc_id;
> > +       u8 clk_type;
> > +};
> > +
> > +/* SCU Clock Protocol definitions */
> > +struct imx_sc_msg_req_set_clock_rate {
> > +       struct imx_sc_rpc_msg hdr;
> > +       u32 rate;
> > +       u16 resource;
> > +       u8 clk;
> > +} __packed;
> > +
> > +struct imx_sc_msg_req_get_clock_rate {
> > +       struct imx_sc_rpc_msg hdr;
> > +       u16 resource;
> > +       u8 clk;
> > +} __packed;
> > +
> > +struct imx_sc_msg_resp_get_clock_rate {
> > +       struct imx_sc_rpc_msg hdr;
> > +       u32 rate;
> > +} __packed;
> > +
> > +
> > +static inline struct clk_divider_scu *to_clk_divider_scu(struct
> > +clk_hw *hw) {
> > +       return container_of(hw, struct clk_divider_scu, hw); }
> > +
> > +/*
> > + * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
> > + * @hw: clock to get rate for
> > + * @parent_rate: parent rate provided by common clock framework, not
> > +used
> > + *
> > + * Gets the current clock rate of a SCU clock. Returns the current
> > + * clock rate, or zero in failure.
> > + */
> > +static unsigned long clk_divider_scu_recalc_rate(struct clk_hw *hw,
> > +                                                 unsigned long
> > +parent_rate) {
> > +       struct clk_divider_scu *div = to_clk_divider_scu(hw);
> > +       struct imx_sc_msg_req_get_clock_rate msg;
> > +       struct imx_sc_msg_resp_get_clock_rate *resp;
> > +       struct imx_sc_rpc_msg *hdr = &msg.hdr;
> > +       int ret;
> > +
> > +       hdr->ver = IMX_SC_RPC_VERSION;
> > +       hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
> > +       hdr->func = (uint8_t)IMX_SC_PM_FUNC_GET_CLOCK_RATE;
> > +       hdr->size = 2;
> > +
> > +       msg.resource = div->rsrc_id;
> > +       msg.clk = div->clk_type;
> > +
> > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > +       if (ret) {
> > +               pr_err("%s: failed to get clock rate %d\n",
> > +                       clk_hw_get_name(hw), ret);
> > +               return 0;
> > +       }
> > +
> > +       resp = (struct imx_sc_msg_resp_get_clock_rate *)&msg;
> 
> Does the response get written to the same place that the message is written? If

Yes

> so, it would be better to combine the different structs into a union that's
> always large enough to handle this? For example, it looks like there are only 16
> + 8 bytes for the get_clock_rate structure, but then the response is returning
> the rate in 32 bytes. When we cast that here we're now getting an extra 8
> bytes of stack, aren't we? Combining the different structures into one bigger
> structure would alleviate this and avoid the need for casting.
> 

Good catch.
Thanks for the professional explanation.

How about do something like below?
struct req_get_clock_rate {
        u16 resource;
        u8 clk;
} __packed;

struct resp_get_clock_rate {
        u32 rate;
} __packed;

struct imx_sc_msg_get_clock_rate {
        struct imx_sc_rpc_msg hdr;
        union {
                struct req_get_clock_rate req;
                struct resp_get_clock_rate resp;
        } data;
} __packed;

> > +
> > +       return resp->rate;
> > +}
> > +
> > +/*
> > + * clk_divider_scu_round_rate - Round clock rate for a SCU clock
> > + * @hw: clock to round rate for
> > + * @rate: rate to round
> > + * @parent_rate: parent rate provided by common clock framework, not
> > +used
> > + *
> > + * Gets the current clock rate of a SCU clock. Returns the current
> > + * clock rate, or zero in failure.
> > + */
> > +static long clk_divider_scu_round_rate(struct clk_hw *hw, unsigned long
> rate,
> > +                                      unsigned long *parent_rate) {
> > +       /*
> > +        * Assume we support all the requested rate and let the SCU
> firmware
> > +        * to handle the left work
> > +        */
> > +       return rate;
> > +}
> > +
> > +/*
> > + * clk_divider_scu_set_rate - Set rate for a SCU clock
> > + * @hw: clock to change rate for
> > + * @rate: target rate for the clock
> > + * @parent_rate: rate of the clock parent, not used for SCU clocks
> > + *
> > + * Sets a clock frequency for a SCU clock. Returns the SCU
> > + * protocol status.
> > + */
> > +static int clk_divider_scu_set_rate(struct clk_hw *hw, unsigned long rate,
> > +                                   unsigned long parent_rate) {
> > +       struct clk_divider_scu *div = to_clk_divider_scu(hw);
> > +       struct imx_sc_msg_req_set_clock_rate msg;
> > +       struct imx_sc_rpc_msg *hdr = &msg.hdr;
> > +       int ret;
> > +
> > +       hdr->ver = IMX_SC_RPC_VERSION;
> > +       hdr->svc = (uint8_t)IMX_SC_RPC_SVC_PM;
> > +       hdr->func = (uint8_t)IMX_SC_PM_FUNC_SET_CLOCK_RATE;
> 
> Are these casts necessary?
> 

I guess the explicit case may not need. Will double check.

> > +       hdr->size = 3;
> > +
> > +       msg.rate = rate;
> > +       msg.resource = div->rsrc_id;
> > +       msg.clk = div->clk_type;
> > +
> > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > +       if (ret)
> > +               pr_err("%s: failed to set clock rate %ld : ret %d\n",
> > +                       clk_hw_get_name(hw), rate, ret);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct clk_ops clk_divider_scu_ops = {
> > +       .recalc_rate = clk_divider_scu_recalc_rate,
> > +       .round_rate = clk_divider_scu_round_rate,
> > +       .set_rate = clk_divider_scu_set_rate, };
> > +
> > +struct clk_hw *imx_clk_register_divider_scu(const char *name,
> > +                                           const char
> *parent_name,
> > +                                           u32 rsrc_id,
> > +                                           u8 clk_type) {
> > +       struct clk_divider_scu *div;
> > +       struct clk_init_data init;
> > +       struct clk_hw *hw;
> > +       int ret;
> > +
> > +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> > +       if (!div)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       div->rsrc_id = rsrc_id;
> > +       div->clk_type = clk_type;
> > +
> > +       init.name = name;
> > +       init.ops = &clk_divider_scu_ops;
> > +       init.flags = CLK_GET_RATE_NOCACHE;
> 
> Why nocache? Please have a good reason and add a comment indicating why.
> 

Because on MX8, the clocks are tightly couple with power domain that
once the power domain is off, the clock status will be lost.
Making it NOCACHE helps user to retrieve the real clock status from HW
Instead of using the possible invalid cached rate.

Is that reasonable enough to specify it?

Regards
Dong Aisheng

> > +       init.parent_names = parent_name ? &parent_name : NULL;
> > +       init.num_parents = parent_name ? 1 : 0;
> > +       div->hw.init = &init;
> > +
> > +       hw = &div->hw;
> > +       ret = clk_hw_register(NULL, hw);
> > +       if (ret) {
> > +               kfree(div);
> > +               hw = ERR_PTR(ret);
> > +       }
> > +
> > +       return hw;
> > +}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider
  2018-10-16 21:27   ` Stephen Boyd
@ 2018-10-17  9:03     ` A.s. Dong
  2018-10-17 15:17       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:03 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:28 AM
[...]
> Quoting A.s. Dong (2018-10-14 01:07:52)
> > +/*
> > + * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
> > + * @hw: clock to get rate for
> > + * @parent_rate: parent rate provided by common clock framework
> > + *
> > + * Gets the current clock rate of a SCU clock. Returns the current
> > + * clock rate, or zero in failure.
> > + */
> > +static unsigned long clk_divider_gpr_scu_recalc_rate(struct clk_hw *hw,
> > +                                                    unsigned long
> > +parent_rate) {
> > +       struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
> > +       u32 val;
> > +       int ret;
> > +
> > +       ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
> > +                                     clk->gpr_id, &val);
> > +       if (ret) {
> > +               pr_err("%s: failed to get clock rate %d\n",
> > +                       clk_hw_get_name(hw), ret);
> > +               return 0;
> > +       }
> > +
> > +       return val ? parent_rate / 2 : parent_rate;
> 
> I hope parent_rate can't be zero here.
> 

It can be zero, I guess.
But zero seems safe to me, am I wrong?

> > +}
> > +
> > +/*
> > + * clk_divider_scu_round_rate - Round clock rate for a SCU clock
> > + * @hw: clock to round rate for
> > + * @rate: rate to round
> > + * @parent_rate: parent rate provided by common clock framework
> > + *
> > + * Round clock rate for a SCU clock according to parent rate  */
> > +static long clk_divider_gpr_scu_round_rate(struct clk_hw *hw, unsigned
> long rate,
> > +                                          unsigned long *prate) {
> > +       if (rate < *prate)
> > +               rate = *prate / 2;
> > +       else
> > +               rate = *prate;
> > +
> > +       return rate;
> > +}
> > +
> > +/*
> > + * clk_divider_scu_set_rate - Set rate for a SCU clock
> > + * @hw: clock to change rate for
> > + * @rate: target rate for the clock
> > + * @parent_rate: rate of the clock parent
> > + *
> > + * Sets a clock frequency for a SCU clock. Returns the SCU
> > + * protocol status.
> > + */
> > +static int clk_divider_gpr_scu_set_rate(struct clk_hw *hw, unsigned long
> rate,
> > +                                       unsigned long parent_rate) {
> > +       struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
> > +       uint32_t val;
> > +
> > +       val = (rate < parent_rate) ? 1 : 0;
> 
> Nitpick: Write it out as
> 
> 	val = 0;
> 	if (rate < parent_rate)
> 		val = 1;
> 

Good suggestion

> > +
> > +       return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
> > +                                      clk->gpr_id, val); }
> > +
> > +static const struct clk_ops clk_divider_gpr_scu_ops = {
> > +       .recalc_rate = clk_divider_gpr_scu_recalc_rate,
> > +       .round_rate = clk_divider_gpr_scu_round_rate,
> > +       .set_rate = clk_divider_gpr_scu_set_rate, };
> > +
> > +struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char
> *parent_name,
> > +                                      u32 rsrc_id, u8 gpr_id) {
> > +       struct clk_divider_gpr_scu *div;
> > +       struct clk_init_data init;
> > +       struct clk_hw *hw;
> > +       int ret;
> > +
> > +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> > +       if (!div)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       div->rsrc_id = rsrc_id;
> > +       div->gpr_id = gpr_id;
> > +
> > +       init.name = name;
> > +       init.ops = &clk_divider_gpr_scu_ops;
> > +       init.flags = CLK_GET_RATE_NOCACHE;
> 
> Same NOCACHE comment.
> 

Replied in another mail.

Regards
Dong Aisheng

> > +       init.parent_names = parent_name ? &parent_name : NULL;
> > +       init.num_parents = parent_name ? 1 : 0;
> > +
> > +       div->hw.init = &init;
> > +
> > +       hw = &div->hw;
> > +       ret = clk_hw_register(NULL, hw);
> > +       if (ret) {
> > +               kfree(div);
> > +               hw = ERR_PTR(ret);
> > +       }
> > +
> > +       return hw;
> > +}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux
  2018-10-16 21:30   ` Stephen Boyd
@ 2018-10-17  9:07     ` A.s. Dong
  2018-10-17 15:18       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:07 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:31 AM
> Quoting A.s. Dong (2018-10-14 01:08:06)
> > diff --git a/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > new file mode 100644
> > index 0000000..2ad7a80
> > --- /dev/null
> > +++ b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > @@ -0,0 +1,90 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017~2018 NXP
> > + *     Dong Aisheng <aisheng.dong@nxp.com>
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/slab.h>
> > +
> > +#include "clk-scu.h"
> > +
> > +struct clk_mux_gpr_scu {
> > +       struct clk_hw hw;
> > +       u32     rsrc_id;
> > +       u8      gpr_id;
> > +};
> > +
> > +#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct
> > +clk_mux_gpr_scu, hw)
> > +
> > +static u8 clk_mux_gpr_scu_get_parent(struct clk_hw *hw) {
> > +       struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
> > +       u32 val = 0;
> > +       int ret;
> > +
> > +       ret = imx_sc_misc_get_control(ccm_ipc_handle, gpr_mux->rsrc_id,
> > +                                     gpr_mux->gpr_id, &val);
> > +       if (ret) {
> > +               pr_err("%s: failed to get clock parent %d\n",
> > +                       clk_hw_get_name(hw), ret);
> > +               return 0;
> > +       }
> > +
> > +       return (u8)val;
> 
> Nitpick: Please drop explicit casts.
> 

Compiler does it for us already, right?
Will drop it.

> > +}
> > +
> > +static int clk_mux_gpr_scu_set_parent(struct clk_hw *hw, u8 index) {
> > +       struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
> > +       int ret;
> > +
> > +       ret = imx_sc_misc_set_control(ccm_ipc_handle, gpr_mux->rsrc_id,
> > +                                     gpr_mux->gpr_id, index);
> > +       if (ret)
> > +               pr_err("%s: failed to set clock parent %d\n",
> > +                       clk_hw_get_name(hw), ret);
> 
> Nitpick: These printks are cluttering the code, any chance they can be removed
> and you can rely on callers to care if something failed?
> 

Yes, good suggestion.

Regards
Dong Aisheng

> > +
> > +       return ret;
> > +}
> > +
> > +static const struct clk_ops clk_mux_gpr_scu_ops = {
> > +       .get_parent = clk_mux_gpr_scu_get_parent,
> > +       .set_parent = clk_mux_gpr_scu_set_parent, };
> > +
> > +struct clk_hw *clk_register_mux_gpr_scu(const char *name, const char
> > +* const *parents,

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 02/11] clk: imx: scu: add scu clock common part
  2018-10-16 21:31   ` Stephen Boyd
@ 2018-10-17  9:11     ` A.s. Dong
  2018-10-17 15:07       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:11 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:32 AM
> Quoting A.s. Dong (2018-10-14 01:07:45)
> > Add scu clock common part which will be used by client clock drivers.
> >
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Cc: Sascha Hauer <kernel@pengutronix.de>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: Stephen Boyd <sboyd@kernel.org>
> > Cc: Michael Turquette <mturquette@baylibre.com>
> > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > ---
> > ChangeLog:
> > v3->v4:
> >  * scu headfile path change
> > v2->v3:
> >  * no changes
> > v1->v2:
> >  * update function call name
> > ---
> >  drivers/clk/imx/Kconfig       |  2 ++
> >  drivers/clk/imx/Makefile      |  2 ++
> >  drivers/clk/imx/scu/Kconfig   |  5 +++++
> >  drivers/clk/imx/scu/Makefile  |  4 ++++
> > drivers/clk/imx/scu/clk-scu.c | 17 +++++++++++++++++
> > drivers/clk/imx/scu/clk-scu.h | 18 ++++++++++++++++++
> 
> Why is scu nested one level deeper in the imx directory? Can't we just keep
> them all within imx toplevel directory?
> 

Mostly because SCU clocks are totally different from the legacy clocks.
(No much legacy things can be reused) So organized them together in a deeper folder
for clear separation and better maintenance

Do you think we still should put them within imx toplevel directory and mix them with
Legacy clocks?

Regards
Dong Aisheng

> >  6 files changed, 48 insertions(+)
> >  create mode 100644 drivers/clk/imx/scu/Kconfig  create mode 100644
> > drivers/clk/imx/scu/Makefile  create mode 100644
> > drivers/clk/imx/scu/clk-scu.c  create mode 100644
> > drivers/clk/imx/scu/clk-scu.h
> >

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions
  2018-10-16 21:32   ` Stephen Boyd
@ 2018-10-17  9:21     ` A.s. Dong
  2018-10-17 15:18       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:21 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:33 AM
> Quoting A.s. Dong (2018-10-14 01:08:09)
> > This may be used by both mmio and scu clks. So let's put it into a
> > common file.
> >
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Cc: Sascha Hauer <kernel@pengutronix.de>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: Stephen Boyd <sboyd@kernel.org>
> > Cc: Michael Turquette <mturquette@baylibre.com>
> > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > ---
> >  drivers/clk/imx/clk-common.h  | 16 ++++++++++++++++
> > drivers/clk/imx/scu/clk-scu.h |  2 ++
> >  2 files changed, 18 insertions(+)
> >  create mode 100644 drivers/clk/imx/clk-common.h
> >
> > diff --git a/drivers/clk/imx/clk-common.h
> > b/drivers/clk/imx/clk-common.h new file mode 100644 index
> > 0000000..e3634a5
> > --- /dev/null
> > +++ b/drivers/clk/imx/clk-common.h
> > @@ -0,0 +1,16 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright 2018 NXP
> > + */
> > +
> > +#ifndef __IMX_CLK_COMMON_H
> > +#define __IMX_CLK_COMMON_H
> > +
> > +#include <linux/clk-provider.h>
> > +
> > +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int
> > +rate) {
> > +       return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
> > +}
> 
> Why do we need this wrapper file? 

This file clk-common.h is used to put the common bits between legacy clocks and scu clocks.
Only imx_clk_hw_fixed() is added in this patch.

> Just call the registration function directly
> with the right arguments instead of wrapping them in another function please.

That's legacy way and widely used before in order to save unnecessary parameters
for imx clocks.
e.g.
drivers/clk/imx/clk.h
static inline struct clk *imx_clk_fixed(const char *name, int rate)
{
        return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}

static inline struct clk *imx_clk_divider(const char *name, const char *parent,
                void __iomem *reg, u8 shift, u8 width)
{
        return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
                        reg, shift, width, 0, &imx_ccm_lock);
}

I can remove it if you dislike it.

Just one question, in later patch, another common function will also be added here:
static inline void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
{
        unsigned int i;

        for (i = 0; i < count; i++) {
                if (IS_ERR(clks[i]))
                        pr_err("i.MX clk %u: register failed with %ld\n",
                                i, PTR_ERR(clks[i])); 
        }
}

Should we remove it as well?

Regards
Dong Aisheng

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function
  2018-10-16 21:34   ` Stephen Boyd
@ 2018-10-17  9:24     ` A.s. Dong
  0 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:24 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:35 AM
> Quoting A.s. Dong (2018-10-14 01:08:13)
> > Add imx_check_clk_hws helper function
> >
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Cc: Sascha Hauer <kernel@pengutronix.de>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: Stephen Boyd <sboyd@kernel.org>
> > Cc: Michael Turquette <mturquette@baylibre.com>
> > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > ---
> >  drivers/clk/imx/clk-common.h | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/clk/imx/clk-common.h
> > b/drivers/clk/imx/clk-common.h index e3634a5..01550fd 100644
> > --- a/drivers/clk/imx/clk-common.h
> > +++ b/drivers/clk/imx/clk-common.h
> > @@ -13,4 +13,15 @@ static inline struct clk_hw *imx_clk_hw_fixed(const
> char *name, int rate)
> >         return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
> > }
> >
> > +static inline void imx_check_clk_hws(struct clk_hw *clks[], unsigned
> > +int count) {
> > +       unsigned int i;
> > +
> > +       for (i = 0; i < count; i++) {
> > +               if (IS_ERR(clks[i]))
> > +                       pr_err("i.MX clk %u: register failed with %ld\n",
> > +                               i, PTR_ERR(clks[i]));
> > +       }
> > +}
> 
> And get rid of this too? I don't see the need for layers on top of code snippets.
> Just write them many times in the same driver, and then decide to consolidate
> that logic behind something larger than a few helper functions.

Okay, just see this, then forget my former question in another email talking about
this function. Will remove them all.
Thanks for the suggestion.

Regards
Dong Aisheng

> 
> > +

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
  2018-10-16 21:38   ` Stephen Boyd
@ 2018-10-17  9:43     ` A.s. Dong
  2018-10-17 15:20       ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17  9:43 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 5:39 AM
> To: A.s. Dong <aisheng.dong@nxp.com>; linux-clk@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org; mturquette@baylibre.com;
> shawnguo@kernel.org; Fabio Estevam <fabio.estevam@nxp.com>; dl-linux-imx
> <linux-imx@nxp.com>; kernel@pengutronix.de; A.s. Dong
> <aisheng.dong@nxp.com>
> Subject: Re: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
> 
> Quoting A.s. Dong (2018-10-14 01:08:16)
> > diff --git a/drivers/clk/imx/scu/clk-imx8qxp.c
> > b/drivers/clk/imx/scu/clk-imx8qxp.c
> > new file mode 100644
> > index 0000000..958c26d
> > --- /dev/null
> > +++ b/drivers/clk/imx/scu/clk-imx8qxp.c
> > @@ -0,0 +1,425 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017~2018 NXP
> > + *     Dong Aisheng <aisheng.dong@nxp.com>
> > + */
> > +
> > +#include <dt-bindings/clock/imx8qxp-clock.h>
> > +#include <linux/clk.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +
> > +#include <soc/imx/imx8qxp/lpcg.h>
> > +
> > +#include "clk-scu.h"
> > +
> > +static struct clk_hw_onecell_data *clk_data;
> 
> Please give this static global variable a more unique name as opposed to
> 'clk_data'.
> 

Got it.

> 
> > +
> > +static const char * const enet_sels[] = { "enet_25MHz",
> > +"enet_125MHz", }; static const char * const enet0_rmii_tx_sels[] = {
> > +"enet0_ref_div", "dummy", }; static const char * const
> > +enet1_rmii_tx_sels[] = { "enet1_ref_div", "dummy", };
> > +
> > +static int imx8qxp_clk_probe(struct platform_device *pdev) {
> > +       struct device_node *ccm_node = pdev->dev.of_node;
> > +       struct clk_hw **clks;
> > +       int ret;
> > +
> > +       ret = imx_clk_scu_init();
> > +       if (ret)
> > +               return ret;
> > +
> > +       clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> > +                               sizeof(*clk_data->hws) *
> IMX8QXP_CLK_END,
> > +                               GFP_KERNEL);
> > +       if (!clk_data)
> > +               return -ENOMEM;
> > +
> > +       clk_data->num = IMX8QXP_CLK_END;
> > +       clks = clk_data->hws;
> > +
> > +       /* Fixed clocks */
> > +       clks[IMX8QXP_CLK_DUMMY]         =
> imx_clk_hw_fixed("dummy", 0);
> > +       clks[IMX8QXP_24MHZ]             =
> imx_clk_hw_fixed("xtal_24MHz", 24000000);
> > +       clks[IMX8QXP_GPT_3M]            =
> imx_clk_hw_fixed("gpt_3m", 3000000);
> > +       clks[IMX8QXP_32KHZ]             =
> imx_clk_hw_fixed("xtal_32KHz", 32768);
> > +

These are external clocks and should be put in Devicetree.

> > +       /* ARM core */
> > +       clks[IMX8QXP_A35_DIV]           =
> imx_clk_divider_scu("a35_div", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
> > +
> > +       clks[IMX8QXP_IPG_DMA_CLK_ROOT]  =
> imx_clk_hw_fixed("ipg_dma_clk_root", 120000000);
> > +       clks[IMX8QXP_AXI_CONN_CLK_ROOT] =
> imx_clk_hw_fixed("axi_conn_clk_root", 333333333);
> > +       clks[IMX8QXP_AHB_CONN_CLK_ROOT] =
> imx_clk_hw_fixed("ahb_conn_clk_root", 166666666);
> > +       clks[IMX8QXP_IPG_CONN_CLK_ROOT] =
> imx_clk_hw_fixed("ipg_conn_clk_root", 83333333);
> > +       clks[IMX8QXP_DC_AXI_EXT_CLK]    =
> imx_clk_hw_fixed("axi_ext_dc_clk_root", 800000000);
> > +       clks[IMX8QXP_DC_AXI_INT_CLK]    =
> imx_clk_hw_fixed("axi_int_dc_clk_root", 400000000);
> > +       clks[IMX8QXP_DC_CFG_CLK]        =
> imx_clk_hw_fixed("cfg_dc_clk_root", 100000000);
> > +       clks[IMX8QXP_MIPI_IPG_CLK]      =
> imx_clk_hw_fixed("ipg_mipi_clk_root", 120000000);
> > +       clks[IMX8QXP_IMG_AXI_CLK]       =
> imx_clk_hw_fixed("axi_img_clk_root", 400000000);
> > +       clks[IMX8QXP_IMG_IPG_CLK]       =
> imx_clk_hw_fixed("ipg_img_clk_root", 200000000);
> > +       clks[IMX8QXP_IMG_PXL_CLK]       =
> imx_clk_hw_fixed("pxl_img_clk_root", 600000000);
> > +       clks[IMX8QXP_HSIO_AXI_CLK]      =
> imx_clk_hw_fixed("axi_hsio_clk_root", 400000000);
> > +       clks[IMX8QXP_HSIO_PER_CLK]      =
> imx_clk_hw_fixed("per_hsio_clk_root", 133333333);
> 
> Can these fixed rate clks come from DT? Or what's going on here?
> 

Those are not external clocks.
Do we have to put them in device tree as well?

> > +
> > +       clks[IMX8QXP_UART0_DIV]         =
> imx_clk_divider_scu("uart0_div", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
> > +       clks[IMX8QXP_UART0_IPG_CLK]     =
> imx_clk_gate2_scu("uart0_ipg_clk", "ipg_dma_clk_root", (void __iomem
> *)(LPUART_0_LPCG), 16, 0);
> > +       clks[IMX8QXP_UART0_CLK]         =
> imx_clk_gate_scu("uart0_clk", "uart0_div", IMX_SC_R_UART_0,
> IMX_SC_PM_CLK_PER, (void __iomem *)(LPUART_0_LPCG), 0, 0);
> > +
> [...]
> > +       clks[IMX8QXP_IMG_PDMA_2_CLK]            =
> imx_clk_gate2_scu("img_pdma2_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_2_LPCG), 0, 0);
> > +       clks[IMX8QXP_IMG_PDMA_3_CLK]            =
> imx_clk_gate2_scu("img_pdma3_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_3_LPCG), 0, 0);
> > +       clks[IMX8QXP_IMG_PDMA_4_CLK]            =
> imx_clk_gate2_scu("img_pdma4_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_4_LPCG), 0, 0);
> > +       clks[IMX8QXP_IMG_PDMA_5_CLK]            =
> imx_clk_gate2_scu("img_pdma5_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_5_LPCG), 0, 0);
> > +       clks[IMX8QXP_IMG_PDMA_6_CLK]            =
> imx_clk_gate2_scu("img_pdma6_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_6_LPCG), 0, 0);
> > +       clks[IMX8QXP_IMG_PDMA_7_CLK]            =
> imx_clk_gate2_scu("img_pdma7_clk", "pxl_img_clk_root", (void __iomem
> *)(IMG_PDMA_7_LPCG), 0, 0);
> 
> All the casts in here shouldn't be necessary, see below.
> 
> > +
> > +       /* MIPI CSI SS */
> > +       clks[IMX8QXP_CSI0_I2C0_DIV]     =
> imx_clk_divider_scu("mipi_csi0_i2c0_div", IMX_SC_R_CSI_0_I2C_0,
> IMX_SC_PM_CLK_PER);
> > +       clks[IMX8QXP_CSI0_PWM0_DIV]     =
> imx_clk_divider_scu("mipi_csi0_pwm0_div", IMX_SC_R_CSI_0_PWM_0,
> IMX_SC_PM_CLK_PER);
> > +       clks[IMX8QXP_CSI0_CORE_DIV]     =
> imx_clk_divider_scu("mipi_csi0_core_div", IMX_SC_R_CSI_0,
> IMX_SC_PM_CLK_PER);
> > +       clks[IMX8QXP_CSI0_ESC_DIV]      =
> imx_clk_divider_scu("mipi_csi0_esc_div", IMX_SC_R_CSI_0,
> IMX_SC_PM_CLK_MISC);
> > +       clks[IMX8QXP_CSI0_IPG_CLK_S]    =
> imx_clk_gate2_scu("mipi_csi0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem
> *)(MIPI_CSI_0_LPCG + 0x8), 16, 0);
> > +       clks[IMX8QXP_CSI0_IPG_CLK]      =
> imx_clk_gate2_scu("mipi_csi0_ipg", "mipi_csi0_ipg_s", (void __iomem
> *)(MIPI_CSI_0_LPCG), 16, 0);
> > +       clks[IMX8QXP_CSI0_APB_CLK]      =
> imx_clk_gate2_scu("mipi_csi0_apb_clk", "ipg_mipi_csi_clk_root", (void
> __iomem *)(MIPI_CSI_0_LPCG + 0x4), 16,  0);
> > +       clks[IMX8QXP_CSI0_I2C0_IPG_CLK] =
> imx_clk_gate2_scu("mipi_csi0_i2c0_ipg_s", "ipg_mipi_csi_clk_root", (void
> __iomem *)(MIPI_CSI_0_LPCG + 0x14), 16, 0);
> > +       clks[IMX8QXP_CSI0_I2C0_CLK]     =
> imx_clk_gate_scu("mipi_csi0_i2c0_clk", "mipi_csi0_i2c0_div",
> IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, (void __iomem
> *)(MIPI_CSI_0_LPCG + 0x14), 0, 0);
> > +       clks[IMX8QXP_CSI0_PWM0_IPG_CLK] =
> imx_clk_gate2_scu("mipi_csi0_pwm0_ipg_s", "ipg_mipi_csi_clk_root", (void
> __iomem *)(MIPI_CSI_0_LPCG + 0x10), 16, 0);
> > +       clks[IMX8QXP_CSI0_PWM0_CLK]     =
> imx_clk_gate_scu("mipi_csi0_pwm0_clk", "mipi_csi0_pwm0_div",
> IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, (void __iomem
> *)(MIPI_CSI_0_LPCG + 0x10), 0, 0);
> > +       clks[IMX8QXP_CSI0_CORE_CLK]     =
> imx_clk_gate_scu("mipi_csi0_core_clk", "mipi_csi0_core_div",
> IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG +
> 0x18), 16, 0);
> > +       clks[IMX8QXP_CSI0_ESC_CLK]      =
> imx_clk_gate_scu("mipi_csi0_esc_clk", "mipi_csi0_esc_div", IMX_SC_R_CSI_0,
> IMX_SC_PM_CLK_MISC, (void __iomem *)(MIPI_CSI_0_LPCG + 0x1C), 16, 0);
> > +
> > +       /* HSIO SS */
> > +       clks[IMX8QXP_HSIO_PCIE_MSTR_AXI_CLK]    =
> imx_clk_gate2_scu("hsio_pcie_mstr_axi_clk", "axi_hsio_clk_root", (void
> __iomem *)(HSIO_PCIE_X1_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_PCIE_SLV_AXI_CLK]     =
> imx_clk_gate2_scu("hsio_pcie_slv_axi_clk", "axi_hsio_clk_root", (void
> __iomem *)(HSIO_PCIE_X1_LPCG), 20, 0);
> > +       clks[IMX8QXP_HSIO_PCIE_DBI_AXI_CLK]     =
> imx_clk_gate2_scu("hsio_pcie_dbi_axi_clk", "axi_hsio_clk_root", (void
> __iomem *)(HSIO_PCIE_X1_LPCG), 24, 0);
> > +       clks[IMX8QXP_HSIO_PCIE_X1_PER_CLK]      =
> imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", (void
> __iomem *)(HSIO_PCIE_X1_CRR3_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_PHY_X1_PER_CLK]       =
> imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", (void
> __iomem *)(HSIO_PHY_X1_CRR1_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_MISC_PER_CLK]         =
> imx_clk_gate2_scu("hsio_misc_per_clk", "per_hsio_clk_root", (void __iomem
> *)(HSIO_MISC_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_PHY_X1_APB_CLK]       =
> imx_clk_gate2_scu("hsio_phy_x1_apb_clk", "per_hsio_clk_root", (void
> __iomem *)(HSIO_PHY_X1_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_GPIO_CLK]             =
> imx_clk_gate2_scu("hsio_gpio_clk", "per_hsio_clk_root", (void __iomem
> *)(HSIO_GPIO_LPCG), 16, 0);
> > +       clks[IMX8QXP_HSIO_PHY_X1_PCLK]          =
> imx_clk_gate2_scu("hsio_phy_x1_pclk", "dummy", (void __iomem
> *)(HSIO_PHY_X1_LPCG), 0, 0);
> > +
> > +       imx_check_clk_hws(clks, clk_data->num);
> > +
> > +       of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get,
> > + clk_data);
> > +
> > +       pr_info("i.MX8QXP clock tree init done.\n");
> 
> Please no "I'm alive!" messages.
> 

Got it

> > +
> > +       return 0;
> > +}
> > +
> > +static const struct of_device_id imx8qxp_match[] = {
> > +       { .compatible = "fsl,imx8qxp-clk", },
> > +       { /* sentinel */ }
> > +};
> > +
> > +static struct platform_driver imx8qxp_clk_driver = {
> > +       .driver = {
> > +               .name = "imx8qxp-clk",
> > +               .of_match_table = imx8qxp_match,
> > +       },
> > +       .probe = imx8qxp_clk_probe,
> > +};
> > +
> > +static int __init imx8qxp_clk_init(void) {
> > +       return platform_driver_register(&imx8qxp_clk_driver);
> > +}
> > +core_initcall(imx8qxp_clk_init);
> > diff --git a/include/soc/imx/imx8qxp/lpcg.h
> > b/include/soc/imx/imx8qxp/lpcg.h new file mode 100644 index
> > 0000000..afbb5da
> > --- /dev/null
> > +++ b/include/soc/imx/imx8qxp/lpcg.h
> > @@ -0,0 +1,186 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017~2018 NXP
> > + *
> > + */
> > +
> > +#ifndef _SC_LPCG_H
> > +#define _SC_LPCG_H
> > +
> > +/*LSIO SS */
> > +#define                PWM_0_LPCG              0x5D400000
> 
> Are these virtual or physical addresses? Because up above they're casted right
> into void __iomem pointers, which makes me thing they're virtual addresses,
> but then that would mean there's some sort of static iomap being used, but
> I'm not aware of anything like that.

Yes, you're right. Those should be physical address and iomem cast is not necessary.
Sorry about missing that.

Regards
Dong Aisheng


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 02/11] clk: imx: scu: add scu clock common part
  2018-10-17  9:11     ` A.s. Dong
@ 2018-10-17 15:07       ` Stephen Boyd
  2018-10-17 15:27         ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:07 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 02:11:03)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:32 AM
> > Quoting A.s. Dong (2018-10-14 01:07:45)
> > > Add scu clock common part which will be used by client clock drivers.
> > >
> > > Cc: Shawn Guo <shawnguo@kernel.org>
> > > Cc: Sascha Hauer <kernel@pengutronix.de>
> > > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > > Cc: Stephen Boyd <sboyd@kernel.org>
> > > Cc: Michael Turquette <mturquette@baylibre.com>
> > > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > > ---
> > > ChangeLog:
> > > v3->v4:
> > >  * scu headfile path change
> > > v2->v3:
> > >  * no changes
> > > v1->v2:
> > >  * update function call name
> > > ---
> > >  drivers/clk/imx/Kconfig       |  2 ++
> > >  drivers/clk/imx/Makefile      |  2 ++
> > >  drivers/clk/imx/scu/Kconfig   |  5 +++++
> > >  drivers/clk/imx/scu/Makefile  |  4 ++++
> > > drivers/clk/imx/scu/clk-scu.c | 17 +++++++++++++++++
> > > drivers/clk/imx/scu/clk-scu.h | 18 ++++++++++++++++++
> > 
> > Why is scu nested one level deeper in the imx directory? Can't we just keep
> > them all within imx toplevel directory?
> > 
> 
> Mostly because SCU clocks are totally different from the legacy clocks.
> (No much legacy things can be reused) So organized them together in a deeper folder
> for clear separation and better maintenance
> 
> Do you think we still should put them within imx toplevel directory and mix them with
> Legacy clocks?
> 

Yes. Or make a new imx-foo directory for your new fangled SoC clk driver
code in drivers/clk/.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-17  8:56     ` A.s. Dong
@ 2018-10-17 15:17       ` Stephen Boyd
  2018-10-17 15:45         ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:17 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 01:56:35)
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:26 AM
> > Quoting A.s. Dong (2018-10-14 01:07:49)
> > > diff --git a/drivers/clk/imx/scu/clk-divider-scu.c
> > > b/drivers/clk/imx/scu/clk-divider-scu.c
> > > new file mode 100644
> > > index 0000000..51cb816
> > > --- /dev/null
> > > +++ b/drivers/clk/imx/scu/clk-divider-scu.c
> > > @@ -0,0 +1,176 @@
> > > +       msg.clk = div->clk_type;
> > > +
> > > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > > +       if (ret) {
> > > +               pr_err("%s: failed to get clock rate %d\n",
> > > +                       clk_hw_get_name(hw), ret);
> > > +               return 0;
> > > +       }
> > > +
> > > +       resp = (struct imx_sc_msg_resp_get_clock_rate *)&msg;
> > 
> > Does the response get written to the same place that the message is written? If
> 
> Yes
> 
> > so, it would be better to combine the different structs into a union that's
> > always large enough to handle this? For example, it looks like there are only 16
> > + 8 bytes for the get_clock_rate structure, but then the response is returning
> > the rate in 32 bytes. When we cast that here we're now getting an extra 8
> > bytes of stack, aren't we? Combining the different structures into one bigger
> > structure would alleviate this and avoid the need for casting.
> > 
> 
> Good catch.
> Thanks for the professional explanation.
> 
> How about do something like below?
> struct req_get_clock_rate {
>         u16 resource;
>         u8 clk;
> } __packed;
> 
> struct resp_get_clock_rate {
>         u32 rate;
> } __packed;

This doesn't need __packed because it's a single u32.

> 
> struct imx_sc_msg_get_clock_rate {
>         struct imx_sc_rpc_msg hdr;
>         union {
>                 struct req_get_clock_rate req;
>                 struct resp_get_clock_rate resp;
>         } data;
> } __packed;
> 

Yes something like this would be best. And now I wonder if
imx_scu_call_rpc() is doing endianness swapping? Or does it copy data
into these response structures? I'm saying that the u32/16/8 may need to
be __le32/16/8 and then have the proper accessors.

> 
> > > +       hdr->size = 3;
> > > +
> > > +       msg.rate = rate;
> > > +       msg.resource = div->rsrc_id;
> > > +       msg.clk = div->clk_type;
> > > +
> > > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > > +       if (ret)
> > > +               pr_err("%s: failed to set clock rate %ld : ret %d\n",
> > > +                       clk_hw_get_name(hw), rate, ret);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static const struct clk_ops clk_divider_scu_ops = {
> > > +       .recalc_rate = clk_divider_scu_recalc_rate,
> > > +       .round_rate = clk_divider_scu_round_rate,
> > > +       .set_rate = clk_divider_scu_set_rate, };
> > > +
> > > +struct clk_hw *imx_clk_register_divider_scu(const char *name,
> > > +                                           const char
> > *parent_name,
> > > +                                           u32 rsrc_id,
> > > +                                           u8 clk_type) {
> > > +       struct clk_divider_scu *div;
> > > +       struct clk_init_data init;
> > > +       struct clk_hw *hw;
> > > +       int ret;
> > > +
> > > +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> > > +       if (!div)
> > > +               return ERR_PTR(-ENOMEM);
> > > +
> > > +       div->rsrc_id = rsrc_id;
> > > +       div->clk_type = clk_type;
> > > +
> > > +       init.name = name;
> > > +       init.ops = &clk_divider_scu_ops;
> > > +       init.flags = CLK_GET_RATE_NOCACHE;
> > 
> > Why nocache? Please have a good reason and add a comment indicating why.
> > 
> 
> Because on MX8, the clocks are tightly couple with power domain that
> once the power domain is off, the clock status will be lost.
> Making it NOCACHE helps user to retrieve the real clock status from HW
> Instead of using the possible invalid cached rate.
> 
> Is that reasonable enough to specify it?

Yes, you can add a comment like that. Or the clk rate can be restored
when the power domain is enabled again?


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider
  2018-10-17  9:03     ` A.s. Dong
@ 2018-10-17 15:17       ` Stephen Boyd
  0 siblings, 0 replies; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:17 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 02:03:28)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:28 AM
> [...]
> > Quoting A.s. Dong (2018-10-14 01:07:52)
> > > +/*
> > > + * clk_divider_scu_recalc_rate - Get clock rate for a SCU clock
> > > + * @hw: clock to get rate for
> > > + * @parent_rate: parent rate provided by common clock framework
> > > + *
> > > + * Gets the current clock rate of a SCU clock. Returns the current
> > > + * clock rate, or zero in failure.
> > > + */
> > > +static unsigned long clk_divider_gpr_scu_recalc_rate(struct clk_hw *hw,
> > > +                                                    unsigned long
> > > +parent_rate) {
> > > +       struct clk_divider_gpr_scu *clk = to_clk_divider_gpr_scu(hw);
> > > +       u32 val;
> > > +       int ret;
> > > +
> > > +       ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
> > > +                                     clk->gpr_id, &val);
> > > +       if (ret) {
> > > +               pr_err("%s: failed to get clock rate %d\n",
> > > +                       clk_hw_get_name(hw), ret);
> > > +               return 0;
> > > +       }
> > > +
> > > +       return val ? parent_rate / 2 : parent_rate;
> > 
> > I hope parent_rate can't be zero here.
> > 
> 
> It can be zero, I guess.
> But zero seems safe to me, am I wrong?

No nothing goes wrong so it's fine.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux
  2018-10-17  9:07     ` A.s. Dong
@ 2018-10-17 15:18       ` Stephen Boyd
  0 siblings, 0 replies; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:18 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 02:07:00)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:31 AM
> > Quoting A.s. Dong (2018-10-14 01:08:06)
> > > diff --git a/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > > b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > > new file mode 100644
> > > index 0000000..2ad7a80
> > > --- /dev/null
> > > +++ b/drivers/clk/imx/scu/clk-mux-gpr-scu.c
> > > @@ -0,0 +1,90 @@
> > > +// SPDX-License-Identifier: GPL-2.0+
> > > +/*
> > > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > > + * Copyright 2017~2018 NXP
> > > + *     Dong Aisheng <aisheng.dong@nxp.com>
> > > + */
> > > +
> > > +#include <linux/clk-provider.h>
> > > +#include <linux/err.h>
> > > +#include <linux/io.h>
> > > +#include <linux/slab.h>
> > > +
> > > +#include "clk-scu.h"
> > > +
> > > +struct clk_mux_gpr_scu {
> > > +       struct clk_hw hw;
> > > +       u32     rsrc_id;
> > > +       u8      gpr_id;
> > > +};
> > > +
> > > +#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct
> > > +clk_mux_gpr_scu, hw)
> > > +
> > > +static u8 clk_mux_gpr_scu_get_parent(struct clk_hw *hw) {
> > > +       struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
> > > +       u32 val = 0;
> > > +       int ret;
> > > +
> > > +       ret = imx_sc_misc_get_control(ccm_ipc_handle, gpr_mux->rsrc_id,
> > > +                                     gpr_mux->gpr_id, &val);
> > > +       if (ret) {
> > > +               pr_err("%s: failed to get clock parent %d\n",
> > > +                       clk_hw_get_name(hw), ret);
> > > +               return 0;
> > > +       }
> > > +
> > > +       return (u8)val;
> > 
> > Nitpick: Please drop explicit casts.
> > 
> 
> Compiler does it for us already, right?
> Will drop it.

Yes and my brain is a tired compiler :)


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions
  2018-10-17  9:21     ` A.s. Dong
@ 2018-10-17 15:18       ` Stephen Boyd
  0 siblings, 0 replies; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:18 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 02:21:57)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:33 AM
> > Quoting A.s. Dong (2018-10-14 01:08:09)
> > > This may be used by both mmio and scu clks. So let's put it into a
> > > common file.
> > >
> > > Cc: Shawn Guo <shawnguo@kernel.org>
> > > Cc: Sascha Hauer <kernel@pengutronix.de>
> > > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > > Cc: Stephen Boyd <sboyd@kernel.org>
> > > Cc: Michael Turquette <mturquette@baylibre.com>
> > > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > > ---
> > >  drivers/clk/imx/clk-common.h  | 16 ++++++++++++++++
> > > drivers/clk/imx/scu/clk-scu.h |  2 ++
> > >  2 files changed, 18 insertions(+)
> > >  create mode 100644 drivers/clk/imx/clk-common.h
> > >
> > > diff --git a/drivers/clk/imx/clk-common.h
> > > b/drivers/clk/imx/clk-common.h new file mode 100644 index
> > > 0000000..e3634a5
> > > --- /dev/null
> > > +++ b/drivers/clk/imx/clk-common.h
> > > @@ -0,0 +1,16 @@
> > > +/* SPDX-License-Identifier: GPL-2.0+ */
> > > +/*
> > > + * Copyright 2018 NXP
> > > + */
> > > +
> > > +#ifndef __IMX_CLK_COMMON_H
> > > +#define __IMX_CLK_COMMON_H
> > > +
> > > +#include <linux/clk-provider.h>
> > > +
> > > +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int
> > > +rate) {
> > > +       return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
> > > +}
> > 
> > Why do we need this wrapper file? 
> 
> This file clk-common.h is used to put the common bits between legacy clocks and scu clocks.
> Only imx_clk_hw_fixed() is added in this patch.
> 
> > Just call the registration function directly
> > with the right arguments instead of wrapping them in another function please.
> 
> That's legacy way and widely used before in order to save unnecessary parameters
> for imx clocks.
> e.g.
> drivers/clk/imx/clk.h
> static inline struct clk *imx_clk_fixed(const char *name, int rate)
> {
>         return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
> }
> 
> static inline struct clk *imx_clk_divider(const char *name, const char *parent,
>                 void __iomem *reg, u8 shift, u8 width)
> {
>         return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
>                         reg, shift, width, 0, &imx_ccm_lock);
> }
> 
> I can remove it if you dislike it.
> 
> Just one question, in later patch, another common function will also be added here:
> static inline void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
> {
>         unsigned int i;
> 
>         for (i = 0; i < count; i++) {
>                 if (IS_ERR(clks[i]))
>                         pr_err("i.MX clk %u: register failed with %ld\n",
>                                 i, PTR_ERR(clks[i])); 
>         }
> }
> 
> Should we remove it as well?
> 

Yes please remove this whole file.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
  2018-10-17  9:43     ` A.s. Dong
@ 2018-10-17 15:20       ` Stephen Boyd
  0 siblings, 0 replies; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 15:20 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 02:43:05)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 5:39 AM
> > To: A.s. Dong <aisheng.dong@nxp.com>; linux-clk@vger.kernel.org
> > Cc: linux-arm-kernel@lists.infradead.org; mturquette@baylibre.com;
> > shawnguo@kernel.org; Fabio Estevam <fabio.estevam@nxp.com>; dl-linux-imx
> > <linux-imx@nxp.com>; kernel@pengutronix.de; A.s. Dong
> > <aisheng.dong@nxp.com>
> > Subject: Re: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver
> > 
> > Quoting A.s. Dong (2018-10-14 01:08:16)
> > > diff --git a/drivers/clk/imx/scu/clk-imx8qxp.c
> > > b/drivers/clk/imx/scu/clk-imx8qxp.c
> > > new file mode 100644
> > > index 0000000..958c26d
> > > --- /dev/null
> > > +++ b/drivers/clk/imx/scu/clk-imx8qxp.c
> > 
> > > +
> > > +static const char * const enet_sels[] = { "enet_25MHz",
> > > +"enet_125MHz", }; static const char * const enet0_rmii_tx_sels[] = {
> > > +"enet0_ref_div", "dummy", }; static const char * const
> > > +enet1_rmii_tx_sels[] = { "enet1_ref_div", "dummy", };
> > > +
> > > +static int imx8qxp_clk_probe(struct platform_device *pdev) {
> > > +       struct device_node *ccm_node = pdev->dev.of_node;
> > > +       struct clk_hw **clks;
> > > +       int ret;
> > > +
> > > +       ret = imx_clk_scu_init();
> > > +       if (ret)
> > > +               return ret;
> > > +
> > > +       clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> > > +                               sizeof(*clk_data->hws) *
> > IMX8QXP_CLK_END,
> > > +                               GFP_KERNEL);
> > > +       if (!clk_data)
> > > +               return -ENOMEM;
> > > +
> > > +       clk_data->num = IMX8QXP_CLK_END;
> > > +       clks = clk_data->hws;
> > > +
> > > +       /* Fixed clocks */
> > > +       clks[IMX8QXP_CLK_DUMMY]         =
> > imx_clk_hw_fixed("dummy", 0);
> > > +       clks[IMX8QXP_24MHZ]             =
> > imx_clk_hw_fixed("xtal_24MHz", 24000000);
> > > +       clks[IMX8QXP_GPT_3M]            =
> > imx_clk_hw_fixed("gpt_3m", 3000000);
> > > +       clks[IMX8QXP_32KHZ]             =
> > imx_clk_hw_fixed("xtal_32KHz", 32768);
> > > +
> 
> These are external clocks and should be put in Devicetree.

Ok, great!

> 
> > > +       /* ARM core */
> > > +       clks[IMX8QXP_A35_DIV]           =
> > imx_clk_divider_scu("a35_div", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
> > > +
> > > +       clks[IMX8QXP_IPG_DMA_CLK_ROOT]  =
> > imx_clk_hw_fixed("ipg_dma_clk_root", 120000000);
> > > +       clks[IMX8QXP_AXI_CONN_CLK_ROOT] =
> > imx_clk_hw_fixed("axi_conn_clk_root", 333333333);
> > > +       clks[IMX8QXP_AHB_CONN_CLK_ROOT] =
> > imx_clk_hw_fixed("ahb_conn_clk_root", 166666666);
> > > +       clks[IMX8QXP_IPG_CONN_CLK_ROOT] =
> > imx_clk_hw_fixed("ipg_conn_clk_root", 83333333);
> > > +       clks[IMX8QXP_DC_AXI_EXT_CLK]    =
> > imx_clk_hw_fixed("axi_ext_dc_clk_root", 800000000);
> > > +       clks[IMX8QXP_DC_AXI_INT_CLK]    =
> > imx_clk_hw_fixed("axi_int_dc_clk_root", 400000000);
> > > +       clks[IMX8QXP_DC_CFG_CLK]        =
> > imx_clk_hw_fixed("cfg_dc_clk_root", 100000000);
> > > +       clks[IMX8QXP_MIPI_IPG_CLK]      =
> > imx_clk_hw_fixed("ipg_mipi_clk_root", 120000000);
> > > +       clks[IMX8QXP_IMG_AXI_CLK]       =
> > imx_clk_hw_fixed("axi_img_clk_root", 400000000);
> > > +       clks[IMX8QXP_IMG_IPG_CLK]       =
> > imx_clk_hw_fixed("ipg_img_clk_root", 200000000);
> > > +       clks[IMX8QXP_IMG_PXL_CLK]       =
> > imx_clk_hw_fixed("pxl_img_clk_root", 600000000);
> > > +       clks[IMX8QXP_HSIO_AXI_CLK]      =
> > imx_clk_hw_fixed("axi_hsio_clk_root", 400000000);
> > > +       clks[IMX8QXP_HSIO_PER_CLK]      =
> > imx_clk_hw_fixed("per_hsio_clk_root", 133333333);
> > 
> > Can these fixed rate clks come from DT? Or what's going on here?
> > 
> 
> Those are not external clocks.
> Do we have to put them in device tree as well?

No if they're not external clks then it's fine to keep specifying them
in this driver.

> 
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static const struct of_device_id imx8qxp_match[] = {
> > > +       { .compatible = "fsl,imx8qxp-clk", },
> > > +       { /* sentinel */ }
> > > +};
> > > +
> > > +static struct platform_driver imx8qxp_clk_driver = {
> > > +       .driver = {
> > > +               .name = "imx8qxp-clk",
> > > +               .of_match_table = imx8qxp_match,
> > > +       },
> > > +       .probe = imx8qxp_clk_probe,
> > > +};
> > > +
> > > +static int __init imx8qxp_clk_init(void) {
> > > +       return platform_driver_register(&imx8qxp_clk_driver);
> > > +}
> > > +core_initcall(imx8qxp_clk_init);
> > > diff --git a/include/soc/imx/imx8qxp/lpcg.h
> > > b/include/soc/imx/imx8qxp/lpcg.h new file mode 100644 index
> > > 0000000..afbb5da
> > > --- /dev/null
> > > +++ b/include/soc/imx/imx8qxp/lpcg.h
> > > @@ -0,0 +1,186 @@
> > > +/* SPDX-License-Identifier: GPL-2.0+ */
> > > +/*
> > > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > > + * Copyright 2017~2018 NXP
> > > + *
> > > + */
> > > +
> > > +#ifndef _SC_LPCG_H
> > > +#define _SC_LPCG_H
> > > +
> > > +/*LSIO SS */
> > > +#define                PWM_0_LPCG              0x5D400000
> > 
> > Are these virtual or physical addresses? Because up above they're casted right
> > into void __iomem pointers, which makes me thing they're virtual addresses,
> > but then that would mean there's some sort of static iomap being used, but
> > I'm not aware of anything like that.
> 
> Yes, you're right. Those should be physical address and iomem cast is not necessary.
> Sorry about missing that.
> 

Ok. Thanks for fixing it.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 02/11] clk: imx: scu: add scu clock common part
  2018-10-17 15:07       ` Stephen Boyd
@ 2018-10-17 15:27         ` A.s. Dong
  0 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-17 15:27 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 11:07 PM
> Quoting A.s. Dong (2018-10-17 02:11:03)
> > > -----Original Message-----
> > > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > > Sent: Wednesday, October 17, 2018 5:32 AM Quoting A.s. Dong
> > > (2018-10-14 01:07:45)
> > > > Add scu clock common part which will be used by client clock drivers.
> > > >
> > > > Cc: Shawn Guo <shawnguo@kernel.org>
> > > > Cc: Sascha Hauer <kernel@pengutronix.de>
> > > > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > > > Cc: Stephen Boyd <sboyd@kernel.org>
> > > > Cc: Michael Turquette <mturquette@baylibre.com>
> > > > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > > > ---
> > > > ChangeLog:
> > > > v3->v4:
> > > >  * scu headfile path change
> > > > v2->v3:
> > > >  * no changes
> > > > v1->v2:
> > > >  * update function call name
> > > > ---
> > > >  drivers/clk/imx/Kconfig       |  2 ++
> > > >  drivers/clk/imx/Makefile      |  2 ++
> > > >  drivers/clk/imx/scu/Kconfig   |  5 +++++
> > > >  drivers/clk/imx/scu/Makefile  |  4 ++++
> > > > drivers/clk/imx/scu/clk-scu.c | 17 +++++++++++++++++
> > > > drivers/clk/imx/scu/clk-scu.h | 18 ++++++++++++++++++
> > >
> > > Why is scu nested one level deeper in the imx directory? Can't we
> > > just keep them all within imx toplevel directory?
> > >
> >
> > Mostly because SCU clocks are totally different from the legacy clocks.
> > (No much legacy things can be reused) So organized them together in a
> > deeper folder for clear separation and better maintenance
> >
> > Do you think we still should put them within imx toplevel directory
> > and mix them with Legacy clocks?
> >
> 
> Yes. Or make a new imx-foo directory for your new fangled SoC clk driver code
> in drivers/clk/.

Okay, then let's still put them in the same imx directory.

Regards
Dong Aisheng

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-17 15:17       ` Stephen Boyd
@ 2018-10-17 15:45         ` A.s. Dong
  2018-10-17 16:05           ` Stephen Boyd
  0 siblings, 1 reply; 42+ messages in thread
From: A.s. Dong @ 2018-10-17 15:45 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Wednesday, October 17, 2018 11:17 PM
> Quoting A.s. Dong (2018-10-17 01:56:35)
> > > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > > Sent: Wednesday, October 17, 2018 5:26 AM Quoting A.s. Dong
> > > (2018-10-14 01:07:49)
> > > > diff --git a/drivers/clk/imx/scu/clk-divider-scu.c
> > > > b/drivers/clk/imx/scu/clk-divider-scu.c
> > > > new file mode 100644
> > > > index 0000000..51cb816
> > > > --- /dev/null
> > > > +++ b/drivers/clk/imx/scu/clk-divider-scu.c
> > > > @@ -0,0 +1,176 @@
> > > > +       msg.clk = div->clk_type;
> > > > +
> > > > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > > > +       if (ret) {
> > > > +               pr_err("%s: failed to get clock rate %d\n",
> > > > +                       clk_hw_get_name(hw), ret);
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       resp = (struct imx_sc_msg_resp_get_clock_rate *)&msg;
> > >
> > > Does the response get written to the same place that the message is
> > > written? If
> >
> > Yes
> >
> > > so, it would be better to combine the different structs into a union
> > > that's always large enough to handle this? For example, it looks
> > > like there are only 16
> > > + 8 bytes for the get_clock_rate structure, but then the response is
> > > + returning
> > > the rate in 32 bytes. When we cast that here we're now getting an
> > > extra 8 bytes of stack, aren't we? Combining the different
> > > structures into one bigger structure would alleviate this and avoid the need
> for casting.
> > >
> >
> > Good catch.
> > Thanks for the professional explanation.
> >
> > How about do something like below?
> > struct req_get_clock_rate {
> >         u16 resource;
> >         u8 clk;
> > } __packed;
> >
> > struct resp_get_clock_rate {
> >         u32 rate;
> > } __packed;
> 
> This doesn't need __packed because it's a single u32.
> 

It's a safe writing, but yes, can be removed.

> >
> > struct imx_sc_msg_get_clock_rate {
> >         struct imx_sc_rpc_msg hdr;
> >         union {
> >                 struct req_get_clock_rate req;
> >                 struct resp_get_clock_rate resp;
> >         } data;
> > } __packed;
> >
> 
> Yes something like this would be best. And now I wonder if
> imx_scu_call_rpc() is doing endianness swapping? Or does it copy data into
> these response structures? I'm saying that the u32/16/8 may need to be
> __le32/16/8 and then have the proper accessors.
> 

No endianness swapping. It's fixed little endian.
SCU protocol isn't aware of these structures. The structures are defined
according to SCU protocol definition to make sure each field position and size
are correct. Then SCU IPC driver just send and receive them sequentially.
Client driver uses the structures to retrieve the responding filed values.

We do this like drivers/firmware/ti_sci.h
Do you think we still need specify __le32/16/8 for this case?

> >
> > > > +       hdr->size = 3;
> > > > +
> > > > +       msg.rate = rate;
> > > > +       msg.resource = div->rsrc_id;
> > > > +       msg.clk = div->clk_type;
> > > > +
> > > > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > > > +       if (ret)
> > > > +               pr_err("%s: failed to set clock rate %ld : ret %d\n",
> > > > +                       clk_hw_get_name(hw), rate, ret);
> > > > +
> > > > +       return 0;
> > > > +}
> > > > +
> > > > +static const struct clk_ops clk_divider_scu_ops = {
> > > > +       .recalc_rate = clk_divider_scu_recalc_rate,
> > > > +       .round_rate = clk_divider_scu_round_rate,
> > > > +       .set_rate = clk_divider_scu_set_rate, };
> > > > +
> > > > +struct clk_hw *imx_clk_register_divider_scu(const char *name,
> > > > +                                           const char
> > > *parent_name,
> > > > +                                           u32 rsrc_id,
> > > > +                                           u8 clk_type) {
> > > > +       struct clk_divider_scu *div;
> > > > +       struct clk_init_data init;
> > > > +       struct clk_hw *hw;
> > > > +       int ret;
> > > > +
> > > > +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> > > > +       if (!div)
> > > > +               return ERR_PTR(-ENOMEM);
> > > > +
> > > > +       div->rsrc_id = rsrc_id;
> > > > +       div->clk_type = clk_type;
> > > > +
> > > > +       init.name = name;
> > > > +       init.ops = &clk_divider_scu_ops;
> > > > +       init.flags = CLK_GET_RATE_NOCACHE;
> > >
> > > Why nocache? Please have a good reason and add a comment indicating
> why.
> > >
> >
> > Because on MX8, the clocks are tightly couple with power domain that
> > once the power domain is off, the clock status will be lost.
> > Making it NOCACHE helps user to retrieve the real clock status from HW
> > Instead of using the possible invalid cached rate.
> >
> > Is that reasonable enough to specify it?
> 
> Yes, you can add a comment like that. Or the clk rate can be restored when the
> power domain is enabled again?

No restore when power domain is enabled again. That needs driver to do special
handling. 

Can we add the comment in commit message as there're still many other places
using this?

Regards
Dong Aisheng

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-17 15:45         ` A.s. Dong
@ 2018-10-17 16:05           ` Stephen Boyd
  2018-10-18  2:35             ` A.s. Dong
  0 siblings, 1 reply; 42+ messages in thread
From: Stephen Boyd @ 2018-10-17 16:05 UTC (permalink / raw)
  To: A.s. Dong, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

Quoting A.s. Dong (2018-10-17 08:45:05)
> > -----Original Message-----
> > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > Sent: Wednesday, October 17, 2018 11:17 PM
> > Quoting A.s. Dong (2018-10-17 01:56:35)
> > > > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > > > Sent: Wednesday, October 17, 2018 5:26 AM Quoting A.s. Dong
> > > > (2018-10-14 01:07:49)
> > >
> > > How about do something like below?
> > > struct req_get_clock_rate {
> > >         u16 resource;
> > >         u8 clk;
> > > } __packed;
> > >
> > > struct resp_get_clock_rate {
> > >         u32 rate;
> > > } __packed;
> > 
> > This doesn't need __packed because it's a single u32.
> > 
> 
> It's a safe writing, but yes, can be removed.
> 
> > >
> > > struct imx_sc_msg_get_clock_rate {
> > >         struct imx_sc_rpc_msg hdr;
> > >         union {
> > >                 struct req_get_clock_rate req;
> > >                 struct resp_get_clock_rate resp;
> > >         } data;
> > > } __packed;
> > >
> > 
> > Yes something like this would be best. And now I wonder if
> > imx_scu_call_rpc() is doing endianness swapping? Or does it copy data into
> > these response structures? I'm saying that the u32/16/8 may need to be
> > __le32/16/8 and then have the proper accessors.
> > 
> 
> No endianness swapping. It's fixed little endian.
> SCU protocol isn't aware of these structures. The structures are defined
> according to SCU protocol definition to make sure each field position and size
> are correct. Then SCU IPC driver just send and receive them sequentially.
> Client driver uses the structures to retrieve the responding filed values.
> 
> We do this like drivers/firmware/ti_sci.h
> Do you think we still need specify __le32/16/8 for this case?

Probably, because the CPU in linux could be big endian or little endian.
It doesn't hurt to do it right to begin with and then you get the
support for free if it's ever used later on.

> 
> > >
> > > > > +       hdr->size = 3;
> > > > > +
> > > > > +       msg.rate = rate;
> > > > > +       msg.resource = div->rsrc_id;
> > > > > +       msg.clk = div->clk_type;
> > > > > +
> > > > > +       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
> > > > > +       if (ret)
> > > > > +               pr_err("%s: failed to set clock rate %ld : ret %d\n",
> > > > > +                       clk_hw_get_name(hw), rate, ret);
> > > > > +
> > > > > +       return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct clk_ops clk_divider_scu_ops = {
> > > > > +       .recalc_rate = clk_divider_scu_recalc_rate,
> > > > > +       .round_rate = clk_divider_scu_round_rate,
> > > > > +       .set_rate = clk_divider_scu_set_rate, };
> > > > > +
> > > > > +struct clk_hw *imx_clk_register_divider_scu(const char *name,
> > > > > +                                           const char
> > > > *parent_name,
> > > > > +                                           u32 rsrc_id,
> > > > > +                                           u8 clk_type) {
> > > > > +       struct clk_divider_scu *div;
> > > > > +       struct clk_init_data init;
> > > > > +       struct clk_hw *hw;
> > > > > +       int ret;
> > > > > +
> > > > > +       div = kzalloc(sizeof(*div), GFP_KERNEL);
> > > > > +       if (!div)
> > > > > +               return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +       div->rsrc_id = rsrc_id;
> > > > > +       div->clk_type = clk_type;
> > > > > +
> > > > > +       init.name = name;
> > > > > +       init.ops = &clk_divider_scu_ops;
> > > > > +       init.flags = CLK_GET_RATE_NOCACHE;
> > > >
> > > > Why nocache? Please have a good reason and add a comment indicating
> > why.
> > > >
> > >
> > > Because on MX8, the clocks are tightly couple with power domain that
> > > once the power domain is off, the clock status will be lost.
> > > Making it NOCACHE helps user to retrieve the real clock status from HW
> > > Instead of using the possible invalid cached rate.
> > >
> > > Is that reasonable enough to specify it?
> > 
> > Yes, you can add a comment like that. Or the clk rate can be restored when the
> > power domain is enabled again?
> 
> No restore when power domain is enabled again. That needs driver to do special
> handling. 
> 
> Can we add the comment in commit message as there're still many other places
> using this?
> 

Sure. Please also add the comment into the code so we don't have to dig
it out of commit text.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH V4 03/11] clk: imx: scu: add scu clock divider
  2018-10-17 16:05           ` Stephen Boyd
@ 2018-10-18  2:35             ` A.s. Dong
  0 siblings, 0 replies; 42+ messages in thread
From: A.s. Dong @ 2018-10-18  2:35 UTC (permalink / raw)
  To: Stephen Boyd, linux-clk
  Cc: linux-arm-kernel, mturquette, shawnguo, Fabio Estevam,
	dl-linux-imx, kernel

> -----Original Message-----
> From: Stephen Boyd [mailto:sboyd@kernel.org]
> Sent: Thursday, October 18, 2018 12:06 AM
> Quoting A.s. Dong (2018-10-17 08:45:05)
> > > -----Original Message-----
> > > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > > Sent: Wednesday, October 17, 2018 11:17 PM Quoting A.s. Dong
> > > (2018-10-17 01:56:35)
> > > > > From: Stephen Boyd [mailto:sboyd@kernel.org]
> > > > > Sent: Wednesday, October 17, 2018 5:26 AM Quoting A.s. Dong
> > > > > (2018-10-14 01:07:49)
> > > >
> > > > How about do something like below?
> > > > struct req_get_clock_rate {
> > > >         u16 resource;
> > > >         u8 clk;
> > > > } __packed;
> > > >
> > > > struct resp_get_clock_rate {
> > > >         u32 rate;
> > > > } __packed;
> > >
> > > This doesn't need __packed because it's a single u32.
> > >
> >
> > It's a safe writing, but yes, can be removed.
> >
> > > >
> > > > struct imx_sc_msg_get_clock_rate {
> > > >         struct imx_sc_rpc_msg hdr;
> > > >         union {
> > > >                 struct req_get_clock_rate req;
> > > >                 struct resp_get_clock_rate resp;
> > > >         } data;
> > > > } __packed;
> > > >
> > >
> > > Yes something like this would be best. And now I wonder if
> > > imx_scu_call_rpc() is doing endianness swapping? Or does it copy
> > > data into these response structures? I'm saying that the u32/16/8
> > > may need to be
> > > __le32/16/8 and then have the proper accessors.
> > >
> >
> > No endianness swapping. It's fixed little endian.
> > SCU protocol isn't aware of these structures. The structures are
> > defined according to SCU protocol definition to make sure each field
> > position and size are correct. Then SCU IPC driver just send and receive them
> sequentially.
> > Client driver uses the structures to retrieve the responding filed values.
> >
> > We do this like drivers/firmware/ti_sci.h Do you think we still need
> > specify __le32/16/8 for this case?
> 
> Probably, because the CPU in linux could be big endian or little endian.
> It doesn't hurt to do it right to begin with and then you get the support for free
> if it's ever used later on.
> 

All right for me. Thanks for the suggestion.

Regards
Dong Aisheng

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2018-10-18  2:35 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-14  8:07 [PATCH V4 00/11] clk: imx: add imx8qxp clock support A.s. Dong
2018-10-14  8:07 ` [PATCH V4 01/11] clk: imx: add configuration option for mmio clks A.s. Dong
2018-10-14  8:07 ` [PATCH V4 02/11] clk: imx: scu: add scu clock common part A.s. Dong
2018-10-16 21:31   ` Stephen Boyd
2018-10-17  9:11     ` A.s. Dong
2018-10-17 15:07       ` Stephen Boyd
2018-10-17 15:27         ` A.s. Dong
2018-10-14  8:07 ` [PATCH V4 03/11] clk: imx: scu: add scu clock divider A.s. Dong
2018-10-16 21:26   ` Stephen Boyd
2018-10-17  8:56     ` A.s. Dong
2018-10-17 15:17       ` Stephen Boyd
2018-10-17 15:45         ` A.s. Dong
2018-10-17 16:05           ` Stephen Boyd
2018-10-18  2:35             ` A.s. Dong
2018-10-14  8:07 ` [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider A.s. Dong
2018-10-16 21:27   ` Stephen Boyd
2018-10-17  9:03     ` A.s. Dong
2018-10-17 15:17       ` Stephen Boyd
2018-10-14  8:07 ` [PATCH V4 05/11] clk: imx: scu: add scu clock gate A.s. Dong
2018-10-15  7:32   ` Sascha Hauer
2018-10-15  9:17     ` A.s. Dong
2018-10-15  9:53       ` Sascha Hauer
2018-10-15 15:30         ` A.s. Dong
2018-10-16 21:18           ` Stephen Boyd
2018-10-17  7:28             ` A.s. Dong
2018-10-14  8:07 ` [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate A.s. Dong
2018-10-14  8:08 ` [PATCH V4 07/11] clk: imx: scu: add scu clock mux A.s. Dong
2018-10-14  8:08 ` [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux A.s. Dong
2018-10-16 21:30   ` Stephen Boyd
2018-10-17  9:07     ` A.s. Dong
2018-10-17 15:18       ` Stephen Boyd
2018-10-14  8:08 ` [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions A.s. Dong
2018-10-16 21:32   ` Stephen Boyd
2018-10-17  9:21     ` A.s. Dong
2018-10-17 15:18       ` Stephen Boyd
2018-10-14  8:08 ` [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function A.s. Dong
2018-10-16 21:34   ` Stephen Boyd
2018-10-17  9:24     ` A.s. Dong
2018-10-14  8:08 ` [PATCH V4 11/11] clk: imx: add imx8qxp clk driver A.s. Dong
2018-10-16 21:38   ` Stephen Boyd
2018-10-17  9:43     ` A.s. Dong
2018-10-17 15:20       ` Stephen Boyd

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).