* [PATCH V4 00/11] clk: imx: add imx8qxp clock support @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 00/11] clk: imx: add imx8qxp clock support @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* [PATCH V4 01/11] clk: imx: add configuration option for mmio clks 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 01/11] clk: imx: add configuration option for mmio clks @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 02/11] clk: imx: scu: add scu clock common part 2018-10-14 8:07 ` A.s. Dong @ 2018-10-16 21:31 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part @ 2018-10-16 21:31 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:31 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part @ 2018-10-17 9:11 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:11 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part @ 2018-10-17 15:07 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:07 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 02:11:03) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 02/11] clk: imx: scu: add scu clock common part @ 2018-10-17 15:27 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 15:27 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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 at 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 03/11] clk: imx: scu: add scu clock divider 2018-10-14 8:07 ` A.s. Dong @ 2018-10-16 21:26 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-16 21:26 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:26 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-17 8:56 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 8:56 UTC (permalink / raw) To: linux-arm-kernel > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-17 15:17 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:17 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 01:56:35) > > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-17 15:45 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 15:45 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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 at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-17 16:05 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 16:05 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 08:45:05) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at 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 at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 03/11] clk: imx: scu: add scu clock divider @ 2018-10-18 2:35 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-18 2:35 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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 at 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 at 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] 84+ messages in thread
* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider 2018-10-14 8:07 ` A.s. Dong @ 2018-10-16 21:27 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider @ 2018-10-16 21:27 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:27 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider @ 2018-10-17 9:03 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:03 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 04/11] clk: imx: scu: add scu clock gpr divider @ 2018-10-17 15:17 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:17 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 02:03:28) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 05/11] clk: imx: scu: add scu clock gate 2018-10-14 8:07 ` A.s. Dong @ 2018-10-15 7:32 ` Sascha Hauer -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-15 7:32 ` Sascha Hauer 0 siblings, 0 replies; 84+ messages in thread From: Sascha Hauer @ 2018-10-15 7:32 UTC (permalink / raw) To: 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] 84+ 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 -1 siblings, 0 replies; 84+ 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&data=02%7C01%7Caisheng.dong%40nxp.com%7Ca8 > dc9d70c490491d116b08d6327050dc%7C686ea1d3bc2b4c6fa92cd99c5c3016 > 35%7C0%7C0%7C636751855312147344&sdata=RkcPJ0TNLnFP%2BBbTh > VrApN3Z%2B7MRR8%2FxJO1TSnqBv40%3D&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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-15 9:17 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-15 9:17 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Sascha Hauer [mailto:s.hauer at pengutronix.de] > Sent: Monday, October 15, 2018 3:32 PM > To: A.s. Dong <aisheng.dong@nxp.com> > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; mturquette at baylibre.com; > dl-linux-imx <linux-imx@nxp.com>; kernel at pengutronix.de; Fabio Estevam > <fabio.estevam@nxp.com>; shawnguo at kernel.org; > linux-arm-kernel at 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&data=02%7C01%7Caisheng.dong%40nxp.com%7Ca8 > dc9d70c490491d116b08d6327050dc%7C686ea1d3bc2b4c6fa92cd99c5c3016 > 35%7C0%7C0%7C636751855312147344&sdata=RkcPJ0TNLnFP%2BBbTh > VrApN3Z%2B7MRR8%2FxJO1TSnqBv40%3D&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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-15 9:53 ` Sascha Hauer 0 siblings, 0 replies; 84+ messages in thread From: Sascha Hauer @ 2018-10-15 9:53 UTC (permalink / raw) To: 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 at pengutronix.de] > > Sent: Monday, October 15, 2018 3:32 PM > > To: A.s. Dong <aisheng.dong@nxp.com> > > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; mturquette at baylibre.com; > > dl-linux-imx <linux-imx@nxp.com>; kernel at pengutronix.de; Fabio Estevam > > <fabio.estevam@nxp.com>; shawnguo at kernel.org; > > linux-arm-kernel at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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&data=02%7C01%7Caisheng.dong%40nxp.com%7C11 > c8f62f729749de7b8708d63284183f%7C686ea1d3bc2b4c6fa92cd99c5c30163 > 5%7C0%7C0%7C636751940255777834&sdata=tsICGc0z9Rcfgu4YcKWy5 > hu8sFHXeRYSy3lP8CjtxO8%3D&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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-15 15:30 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-15 15:30 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Sascha Hauer [mailto:s.hauer at pengutronix.de] > Sent: Monday, October 15, 2018 5:54 PM > To: A.s. Dong <aisheng.dong@nxp.com> > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; mturquette at baylibre.com; > dl-linux-imx <linux-imx@nxp.com>; kernel at pengutronix.de; Fabio Estevam > <fabio.estevam@nxp.com>; shawnguo at kernel.org; > linux-arm-kernel at 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 at pengutronix.de] > > > Sent: Monday, October 15, 2018 3:32 PM > > > To: A.s. Dong <aisheng.dong@nxp.com> > > > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; > > > mturquette at baylibre.com; dl-linux-imx <linux-imx@nxp.com>; > > > kernel at pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>; > > > shawnguo at kernel.org; linux-arm-kernel at 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&data=02%7C01%7Caisheng.dong%40nxp.com%7C11 > c8f62f729749de7b8708d63284183f%7C686ea1d3bc2b4c6fa92cd99c5c30163 > 5%7C0%7C0%7C636751940255777834&sdata=tsICGc0z9Rcfgu4YcKWy5 > hu8sFHXeRYSy3lP8CjtxO8%3D&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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-16 21:18 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:18 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-15 08:30:45) > > -----Original Message----- > > From: Sascha Hauer [mailto:s.hauer at pengutronix.de] > > Sent: Monday, October 15, 2018 5:54 PM > > To: A.s. Dong <aisheng.dong@nxp.com> > > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; mturquette at baylibre.com; > > dl-linux-imx <linux-imx@nxp.com>; kernel at pengutronix.de; Fabio Estevam > > <fabio.estevam@nxp.com>; shawnguo at kernel.org; > > linux-arm-kernel at 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 at pengutronix.de] > > > > Sent: Monday, October 15, 2018 3:32 PM > > > > To: A.s. Dong <aisheng.dong@nxp.com> > > > > Cc: linux-clk at vger.kernel.org; sboyd at kernel.org; > > > > mturquette at baylibre.com; dl-linux-imx <linux-imx@nxp.com>; > > > > kernel at pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>; > > > > shawnguo at kernel.org; linux-arm-kernel at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 05/11] clk: imx: scu: add scu clock gate @ 2018-10-17 7:28 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 7:28 UTC (permalink / raw) To: linux-arm-kernel > From: Stephen Boyd [mailto:sboyd at 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] 84+ messages in thread
* [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:07 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 06/11] clk: imx: scu: add scu clock gpr gate @ 2018-10-14 8:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:07 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* [PATCH V4 07/11] clk: imx: scu: add scu clock mux 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:08 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 07/11] clk: imx: scu: add scu clock mux @ 2018-10-14 8:08 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:08 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:08 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux @ 2018-10-14 8:08 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:08 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux 2018-10-14 8:08 ` A.s. Dong @ 2018-10-16 21:30 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux @ 2018-10-16 21:30 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:30 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux @ 2018-10-17 9:07 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:07 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 08/11] clk: imx: scu: add scu clock gpr mux @ 2018-10-17 15:18 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:18 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 02:07:00) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at 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] 84+ messages in thread
* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:08 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions @ 2018-10-14 8:08 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:08 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions 2018-10-14 8:08 ` A.s. Dong @ 2018-10-16 21:32 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions @ 2018-10-16 21:32 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:32 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions @ 2018-10-17 9:21 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:21 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 09/11] clk: imx: add common imx_clk_hw_fixed functions @ 2018-10-17 15:18 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:18 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 02:21:57) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at 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] 84+ messages in thread
* [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:08 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function @ 2018-10-14 8:08 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:08 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function 2018-10-14 8:08 ` A.s. Dong @ 2018-10-16 21:34 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function @ 2018-10-16 21:34 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:34 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 10/11] clk: imx: add imx_check_clk_hws helper function @ 2018-10-17 9:24 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:24 UTC (permalink / raw) To: linux-arm-kernel > From: Stephen Boyd [mailto:sboyd at 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] 84+ messages in thread
* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver 2018-10-14 8:07 ` A.s. Dong @ 2018-10-14 8:08 ` A.s. Dong -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver @ 2018-10-14 8:08 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-14 8:08 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ messages in thread
* Re: [PATCH V4 11/11] clk: imx: add imx8qxp clk driver 2018-10-14 8:08 ` A.s. Dong @ 2018-10-16 21:38 ` Stephen Boyd -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver @ 2018-10-16 21:38 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-16 21:38 UTC (permalink / raw) To: linux-arm-kernel 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver @ 2018-10-17 9:43 ` A.s. Dong 0 siblings, 0 replies; 84+ messages in thread From: A.s. Dong @ 2018-10-17 9:43 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Stephen Boyd [mailto:sboyd at kernel.org] > Sent: Wednesday, October 17, 2018 5:39 AM > To: A.s. Dong <aisheng.dong@nxp.com>; linux-clk at vger.kernel.org > Cc: linux-arm-kernel at lists.infradead.org; mturquette at baylibre.com; > shawnguo at kernel.org; Fabio Estevam <fabio.estevam@nxp.com>; dl-linux-imx > <linux-imx@nxp.com>; kernel at 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] 84+ 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 -1 siblings, 0 replies; 84+ 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] 84+ messages in thread
* [PATCH V4 11/11] clk: imx: add imx8qxp clk driver @ 2018-10-17 15:20 ` Stephen Boyd 0 siblings, 0 replies; 84+ messages in thread From: Stephen Boyd @ 2018-10-17 15:20 UTC (permalink / raw) To: linux-arm-kernel Quoting A.s. Dong (2018-10-17 02:43:05) > > -----Original Message----- > > From: Stephen Boyd [mailto:sboyd at kernel.org] > > Sent: Wednesday, October 17, 2018 5:39 AM > > To: A.s. Dong <aisheng.dong@nxp.com>; linux-clk at vger.kernel.org > > Cc: linux-arm-kernel at lists.infradead.org; mturquette at baylibre.com; > > shawnguo at kernel.org; Fabio Estevam <fabio.estevam@nxp.com>; dl-linux-imx > > <linux-imx@nxp.com>; kernel at 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] 84+ messages in thread
end of thread, other threads:[~2018-10-18 2:35 UTC | newest] Thread overview: 84+ 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 ` 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-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:31 ` Stephen Boyd 2018-10-16 21:31 ` Stephen Boyd 2018-10-17 9:11 ` A.s. Dong 2018-10-17 9:11 ` A.s. Dong 2018-10-17 15:07 ` Stephen Boyd 2018-10-17 15:07 ` Stephen Boyd 2018-10-17 15:27 ` A.s. Dong 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-14 8:07 ` A.s. Dong 2018-10-16 21:26 ` Stephen Boyd 2018-10-16 21:26 ` Stephen Boyd 2018-10-17 8:56 ` A.s. Dong 2018-10-17 8:56 ` A.s. Dong 2018-10-17 15:17 ` Stephen Boyd 2018-10-17 15:17 ` Stephen Boyd 2018-10-17 15:45 ` A.s. Dong 2018-10-17 15:45 ` A.s. Dong 2018-10-17 16:05 ` Stephen Boyd 2018-10-17 16:05 ` Stephen Boyd 2018-10-18 2:35 ` A.s. Dong 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-14 8:07 ` A.s. Dong 2018-10-16 21:27 ` Stephen Boyd 2018-10-16 21:27 ` Stephen Boyd 2018-10-17 9:03 ` A.s. Dong 2018-10-17 9:03 ` A.s. Dong 2018-10-17 15:17 ` Stephen Boyd 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-14 8:07 ` A.s. Dong 2018-10-15 7:32 ` Sascha Hauer 2018-10-15 7:32 ` Sascha Hauer 2018-10-15 9:17 ` A.s. Dong 2018-10-15 9:17 ` A.s. Dong 2018-10-15 9:53 ` Sascha Hauer 2018-10-15 9:53 ` Sascha Hauer 2018-10-15 15:30 ` A.s. Dong 2018-10-15 15:30 ` A.s. Dong 2018-10-16 21:18 ` Stephen Boyd 2018-10-16 21:18 ` Stephen Boyd 2018-10-17 7:28 ` A.s. Dong 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:07 ` 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 ` 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-14 8:08 ` A.s. Dong 2018-10-16 21:30 ` Stephen Boyd 2018-10-16 21:30 ` Stephen Boyd 2018-10-17 9:07 ` A.s. Dong 2018-10-17 9:07 ` A.s. Dong 2018-10-17 15:18 ` Stephen Boyd 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-14 8:08 ` A.s. Dong 2018-10-16 21:32 ` Stephen Boyd 2018-10-16 21:32 ` Stephen Boyd 2018-10-17 9:21 ` A.s. Dong 2018-10-17 9:21 ` A.s. Dong 2018-10-17 15:18 ` Stephen Boyd 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-14 8:08 ` A.s. Dong 2018-10-16 21:34 ` Stephen Boyd 2018-10-16 21:34 ` Stephen Boyd 2018-10-17 9:24 ` A.s. Dong 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-14 8:08 ` A.s. Dong 2018-10-16 21:38 ` Stephen Boyd 2018-10-16 21:38 ` Stephen Boyd 2018-10-17 9:43 ` A.s. Dong 2018-10-17 9:43 ` A.s. Dong 2018-10-17 15:20 ` Stephen Boyd 2018-10-17 15:20 ` Stephen Boyd
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.