Skip to contentSkip to conversation

clk: imx: add imx8qxp clock support

PATCH In review A.s. Dong 3 participants 16 messages Nov 10, 2018 – Dec 3, 2018

Subsystems (4)
lore
Share & tools
lore

A.s. Dong

author
#0 lore raw

v6 cover clk: imx: add imx8qxp clock support

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:
v5->v6:
* simply the driver a lot by re-orgnizing the driver into a few clock types:
scu clock (merge scu divider/gate/mux) and scu gpr lock which accessing is through SCU protocol and LPCG clock which is directly accessible by CPU.
* LPCG clock is separate from SCU clock, gpr clock is still not used and will be added later.
* remove old year license as the code is totally rewritten
* scu mux support will be added later as it's also still not used.
v4->v5:
Address all Stephen and Sascha's review comments, see details in each patch
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 (6):
clk: imx: add scu clock common part
dt-bindings: clock: imx8qxp: add SCU clock IDs
clk: imx: add imx8qxp clk driver
dt-bindings: clock: add imx8qxp lpcg clock binding
clk: imx: add lpcg clock support
clk: imx: add imx8qxp lpcg driver

 .../devicetree/bindings/clock/imx8qxp-lpcg.txt     |  51 ++++
 drivers/clk/imx/Kconfig                            |   4 +
 drivers/clk/imx/Makefile                           |   6 +
 drivers/clk/imx/clk-imx8qxp-lpcg.c                 | 198 ++++++++++++++
 drivers/clk/imx/clk-imx8qxp-lpcg.h                 | 102 ++++++++
 drivers/clk/imx/clk-imx8qxp.c                      | 156 +++++++++++
 drivers/clk/imx/clk-lpcg-scu.c                     | 108 ++++++++
 drivers/clk/imx/clk-scu.c                          | 237 +++++++++++++++++
 drivers/clk/imx/clk-scu.h                          |  24 ++
 include/dt-bindings/clock/imx8qxp-clock.h          | 289 +++++++++++++++++++++
 10 files changed, 1175 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
 create mode 100644 drivers/clk/imx/clk-imx8qxp-lpcg.c
 create mode 100644 drivers/clk/imx/clk-imx8qxp-lpcg.h
 create mode 100644 drivers/clk/imx/clk-imx8qxp.c
 create mode 100644 drivers/clk/imx/clk-lpcg-scu.c
 create mode 100644 drivers/clk/imx/clk-scu.c
 create mode 100644 drivers/clk/imx/clk-scu.h
 create mode 100644 include/dt-bindings/clock/imx8qxp-clock.h
Signature · 1 line
2.7.4
author
#1 lore raw

PATCH v6 1/6 clk: imx: add scu clock common part

Add scu clock common part which will be used by client clock drivers. SCU clocks are totally different from the legacy clocks (No much legacy things can be reused). So a new configuration option CONFIG_MXC_CLK_SCU is added.

Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Stephen Boyd <[email protected]>
Cc Michael Turquette <[email protected]>

---
ChangeLog:
v5->v6:
* simply the whole clock driver a lot by re-orgnizing the driver into a few clock types:: scu clock (merge scu divider/gate/mux) and scu gpr lock which accessing is through SCU protocol and LPCG clock which is directly accessible by CPU.
* LPCG clock support will be added in next patch, gpr clock is still not used and will be added later.
* remove old year license as the code is totally rewritten
* scu mux support will be added later as it's also still not used.
v4->v5:
* add more explanation in commit message on why put scu clocks
in a deeper folder.
* move scu clk files into the top directory of imx folder
v3->v4:
* scu headfile path change
v2->v3:
* no changes
v1->v2:
* update function call name

---
 drivers/clk/imx/Kconfig   |   4 +
 drivers/clk/imx/Makefile  |   3 +
 drivers/clk/imx/clk-scu.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/imx/clk-scu.h |  21 ++++
 4 files changed, 265 insertions(+)
 create mode 100644 drivers/clk/imx/clk-scu.c
 create mode 100644 drivers/clk/imx/clk-scu.h
drivers/clk/imx/Kconfig +4 -0
index 43a3ecc..63e7b01 100644
@@ -3,3 +3,7 @@
 config MXC_CLK
 	bool
 	depends on ARCH_MXC
+
+config MXC_CLK_SCU
+	bool
+	depends on ARCH_MXC && ARM64
drivers/clk/imx/Makefile +3 -0
index d447f8c..eec6d72 100644
@@ -13,6 +13,9 @@ obj-$(CONFIG_MXC_CLK) += \
 	clk-pllv3.o \
 	clk-pfd.o
 
+obj-$(CONFIG_MXC_CLK_SCU) += \
+	clk-scu.o
+
 obj-$(CONFIG_SOC_IMX1)   += clk-imx1.o
 obj-$(CONFIG_SOC_IMX21)  += clk-imx21.o
 obj-$(CONFIG_SOC_IMX25)  += clk-imx25.o
drivers/clk/imx/clk-scu.c new file +237 -0

237 lines not on this page · raw message

drivers/clk/imx/clk-scu.h new file +21 -0
new file mode 100644
index 0000000..09f381b
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ *   Dong Aisheng <[email protected]>
+ */
+
+#ifndef __IMX_CLK_SCU_H
+#define __IMX_CLK_SCU_H
+
+#include <linux/firmware/imx/sci.h>
+
+extern struct imx_sc_ipc *ccm_ipc_handle;
+
+static inline int imx_clk_scu_init(void)
+{
+	return imx_scu_get_handle(&ccm_ipc_handle);
+}
+
+struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type);
+
+#endif
Signature · 1 line
2.7.4
author
#2 lore raw

PATCH v6 2/6 dt-bindings: clock: imx8qxp: add SCU clock IDs

In reply to A.s. Dong

Add IMX8QXP SCU clock IDs.

Cc Rob Herring <[email protected]>
Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc devicetree at vger.kernel.org
Cc linux-clk at vger.kernel.org

---
v6: new patch, separate from driver changes to avoid a checkpatch warning
IDs are changed a lot due to SCU divider/gate/mux are merged into one general SCU clock and LPCG clocks are moved out.

---
 include/dt-bindings/clock/imx8qxp-clock.h | 136 ++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)
 create mode 100644 include/dt-bindings/clock/imx8qxp-clock.h
include/dt-bindings/clock/imx8qxp-clock.h new file +136 -0
new file mode 100644
index 0000000..d72a39c
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ *   Dong Aisheng <[email protected]>
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_IMX8QXP_H
+#define __DT_BINDINGS_CLOCK_IMX8QXP_H
+
+/* SCU Clocks */
+
+#define IMX8QXP_CLK_DUMMY				0
+
+/* CPU */
+#define IMX8QXP_A35_CLK					1
+
+/* LSIO SS */
+#define IMX8QXP_LSIO_MEM_CLK				2
+#define IMX8QXP_LSIO_BUS_CLK				3
+#define IMX8QXP_LSIO_PWM0_CLK				10
+#define IMX8QXP_LSIO_PWM1_CLK				11
+#define IMX8QXP_LSIO_PWM2_CLK				12
+#define IMX8QXP_LSIO_PWM3_CLK				13
+#define IMX8QXP_LSIO_PWM4_CLK				14
+#define IMX8QXP_LSIO_PWM5_CLK				15
+#define IMX8QXP_LSIO_PWM6_CLK				16
+#define IMX8QXP_LSIO_PWM7_CLK				17
+#define IMX8QXP_LSIO_GPT0_CLK				18
+#define IMX8QXP_LSIO_GPT1_CLK				19
+#define IMX8QXP_LSIO_GPT2_CLK				20
+#define IMX8QXP_LSIO_GPT3_CLK				21
+#define IMX8QXP_LSIO_GPT4_CLK				22
+#define IMX8QXP_LSIO_FSPI0_CLK				23
+#define IMX8QXP_LSIO_FSPI1_CLK				24
+
+/* Connectivity SS */
+#define IMX8QXP_CONN_AXI_CLK_ROOT			30
+#define IMX8QXP_CONN_AHB_CLK_ROOT			31
+#define IMX8QXP_CONN_IPG_CLK_ROOT			32
+#define IMX8QXP_CONN_SDHC0_CLK				40
+#define IMX8QXP_CONN_SDHC1_CLK				41
+#define IMX8QXP_CONN_SDHC2_CLK				42
+#define IMX8QXP_CONN_ENET0_ROOT_CLK			43
+#define IMX8QXP_CONN_ENET0_BYPASS_CLK			44
+#define IMX8QXP_CONN_ENET0_RGMII_CLK			45
+#define IMX8QXP_CONN_ENET1_ROOT_CLK			46
+#define IMX8QXP_CONN_ENET1_BYPASS_CLK			47
+#define IMX8QXP_CONN_ENET1_RGMII_CLK			48
+#define IMX8QXP_CONN_GPMI_BCH_IO_CLK			49
+#define IMX8QXP_CONN_GPMI_BCH_CLK			50
+#define IMX8QXP_CONN_USB2_ACLK				51
+#define IMX8QXP_CONN_USB2_BUS_CLK			52
+#define IMX8QXP_CONN_USB2_LPM_CLK			53
+
+/* HSIO SS */
+#define IMX8QXP_HSIO_AXI_CLK				60
+#define IMX8QXP_HSIO_PER_CLK				61
+
+/* Display controller SS */
+#define IMX8QXP_DC_AXI_EXT_CLK				70
+#define IMX8QXP_DC_AXI_INT_CLK				71
+#define IMX8QXP_DC_CFG_CLK				72
+#define IMX8QXP_DC0_PLL0_CLK				80
+#define IMX8QXP_DC0_PLL1_CLK				81
+#define IMX8QXP_DC0_DISP0_CLK				82
+#define IMX8QXP_DC0_DISP1_CLK				83
+
+/* MIPI-LVDS SS */
+#define IMX8QXP_MIPI_IPG_CLK				90
+#define IMX8QXP_MIPI0_PIXEL_CLK				100
+#define IMX8QXP_MIPI0_BYPASS_CLK			101
+#define IMX8QXP_MIPI0_LVDS_PIXEL_CLK			102
+#define IMX8QXP_MIPI0_LVDS_BYPASS_CLK			103
+#define IMX8QXP_MIPI0_LVDS_PHY_CLK			104
+#define IMX8QXP_MIPI0_I2C0_CLK				105
+#define IMX8QXP_MIPI0_I2C1_CLK				106
+#define IMX8QXP_MIPI0_PWM0_CLK				107
+#define IMX8QXP_MIPI1_PIXEL_CLK				108
+#define IMX8QXP_MIPI1_BYPASS_CLK			109
+#define IMX8QXP_MIPI1_LVDS_PIXEL_CLK			110
+#define IMX8QXP_MIPI1_LVDS_BYPASS_CLK			111
+#define IMX8QXP_MIPI1_LVDS_PHY_CLK			112
+#define IMX8QXP_MIPI1_I2C0_CLK				113
+#define IMX8QXP_MIPI1_I2C1_CLK				114
+#define IMX8QXP_MIPI1_PWM0_CLK				115
+
+/* IMG SS */
+#define IMX8QXP_IMG_AXI_CLK				120
+#define IMX8QXP_IMG_IPG_CLK				121
+#define IMX8QXP_IMG_PXL_CLK				122
+
+/* MIPI-CSI SS */
+#define IMX8QXP_CSI0_CORE_CLK				130
+#define IMX8QXP_CSI0_ESC_CLK				131
+#define IMX8QXP_CSI0_PWM0_CLK				132
+#define IMX8QXP_CSI0_I2C0_CLK				133
+
+/* PARALLER CSI SS */
+#define IMX8QXP_PARALLEL_CSI_DPLL_CLK			140
+#define IMX8QXP_PARALLEL_CSI_PIXEL_CLK			141
+#define IMX8QXP_PARALLEL_CSI_MCLK_CLK			142
+
+/* VPU SS */
+#define IMX8QXP_VPU_ENC_CLK				150
+#define IMX8QXP_VPU_DEC_CLK				151
+
+/* GPU SS */
+#define IMX8QXP_GPU0_CORE_CLK				160
+#define IMX8QXP_GPU0_SHADER_CLK				161
+
+/* ADMA SS */
+#define IMX8QXP_ADMA_IPG_CLK_ROOT			165
+#define IMX8QXP_ADMA_UART0_CLK				170
+#define IMX8QXP_ADMA_UART1_CLK				171
+#define IMX8QXP_ADMA_UART2_CLK				172
+#define IMX8QXP_ADMA_UART3_CLK				173
+#define IMX8QXP_ADMA_SPI0_CLK				174
+#define IMX8QXP_ADMA_SPI1_CLK				175
+#define IMX8QXP_ADMA_SPI2_CLK				176
+#define IMX8QXP_ADMA_SPI3_CLK				177
+#define IMX8QXP_ADMA_CAN0_CLK				178
+#define IMX8QXP_ADMA_CAN1_CLK				179
+#define IMX8QXP_ADMA_CAN2_CLK				180
+#define IMX8QXP_ADMA_I2C0_CLK				181
+#define IMX8QXP_ADMA_I2C1_CLK				182
+#define IMX8QXP_ADMA_I2C2_CLK				183
+#define IMX8QXP_ADMA_I2C3_CLK				184
+#define IMX8QXP_ADMA_FTM0_CLK				185
+#define IMX8QXP_ADMA_FTM1_CLK				186
+#define IMX8QXP_ADMA_ADC0_CLK				187
+#define IMX8QXP_ADMA_PWM_CLK				188
+#define IMX8QXP_ADMA_LCD_CLK				189
+
+#define IMX8QXP_SCU_CLK_END				190
+
+#endif /* __DT_BINDINGS_CLOCK_IMX8QXP_H */
Signature · 1 line
2.7.4
maintainer
#3 lore raw

PATCH v6 2/6 dt-bindings: clock: imx8qxp: add SCU clock IDs

Quoted 9 lines · A.s. Dong

Add IMX8QXP SCU clock IDs.

Cc Rob Herring <[email protected]>
Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc devicetree at vger.kernel.org
Cc linux-clk at vger.kernel.org
Quoted 9 lines

---
v6: new patch, separate from driver changes to avoid a checkpatch warning
IDs are changed a lot due to SCU divider/gate/mux are merged into one general SCU clock and LPCG clocks are moved out.

---
 include/dt-bindings/clock/imx8qxp-clock.h | 136 ++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)
 create mode 100644 include/dt-bindings/clock/imx8qxp-clock.h
author
#4 lore raw

PATCH v6 3/6 clk: imx: add imx8qxp clk driver

In reply to A.s. Dong

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

Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Stephen Boyd <[email protected]>
Cc Michael Turquette <[email protected]>

---
ChangeLog:
v5->v6:
* changed to new scu clock type imx_clk_scu
clk number is reduced signifcantly
* moved lpcgs clock out into separate driver
v4->v5:
Address all comments from Stephen
* more unique name for clk_data
* remove void __iomem * cast for LPCG physical address
* move out external fixed clk definition
* drop using of imx_clk_hw_fixed and imx_check_clk_hws wrappers
* remove i'm alive message
* move scu clk files into imx top directory
v3->v4:
* scu headfile path update
v2->v3:
* enum name update
v1->v2:
* no changes except headfile name updated

---
 drivers/clk/imx/Makefile      |   2 +
 drivers/clk/imx/clk-imx8qxp.c | 156 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)
 create mode 100644 drivers/clk/imx/clk-imx8qxp.c
drivers/clk/imx/Makefile +2 -0
index eec6d72..8369a34 100644
@@ -30,3 +30,5 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
 obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
 obj-$(CONFIG_SOC_IMX7D)  += clk-imx7d.o
 obj-$(CONFIG_SOC_VF610)  += clk-vf610.o
+
+obj-$(CONFIG_SOC_IMX8QXP)	+= clk-imx8qxp.o
drivers/clk/imx/clk-imx8qxp.c new file +156 -0

156 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#5 lore raw

PATCH v6 4/6 dt-bindings: clock: add imx8qxp lpcg clock binding

In reply to A.s. Dong

The Low-Power Clock Gate (LPCG) modules contain a local programming model to control the clock gates for the peripherals. An LPCG module is used to locally gate the clocks for the associated peripheral.

Note:
This level of clock gating is provided after the clocks are generated by the SCU resources and clock controls. Thus even if the clock is enabled by these control bits, it might still not be running based on the base resource.

Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Rob Herring <[email protected]>
Cc devicetree at vger.kernel.org
---
 .../devicetree/bindings/clock/imx8qxp-lpcg.txt     |  51 +++++++
 include/dt-bindings/clock/imx8qxp-clock.h          | 153 +++++++++++++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt new file +51 -0
new file mode 100644
index 0000000..965cfa4
@@ -0,0 +1,51 @@
+* NXP i.MX8QXP LPCG (Low-Power Clock Gating) Clock bindings
+
+The Low-Power Clock Gate (LPCG) modules contain a local programming
+model to control the clock gates for the peripherals. An LPCG module
+is used to locally gate the clocks for the associated peripheral.
+
+Note:
+This level of clock gating is provided after the clocks are generated
+by the SCU resources and clock controls. Thus even if the clock is
+enabled by these control bits, it might still not be running based
+on the base resource.
+
+Required properties:
+- compatible:	Should be one of:
+		  "fsl,imx8qxp-lpcg-adma",
+		  "fsl,imx8qxp-lpcg-conn",
+		  "fsl,imx8qxp-lpcg-dc",
+		  "fsl,imx8qxp-lpcg-dsp",
+		  "fsl,imx8qxp-lpcg-gpu",
+		  "fsl,imx8qxp-lpcg-hsio",
+		  "fsl,imx8qxp-lpcg-img",
+		  "fsl,imx8qxp-lpcg-lsio",
+		  "fsl,imx8qxp-lpcg-vpu"
+- reg:		Address and length of the register set
+- #clock-cells:	Should be <1>
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell.
+See the full list of clock IDs from:
+include/dt-bindings/clock/imx8qxp-clock.h
+
+Examples:
+
+#include <dt-bindings/clock/imx8qxp-clock.h>
+
+conn_lpcg: clock-controller at 5b200000 {
+	compatible = "fsl,imx8qxp-lpcg-conn";
+	reg = <0x5b200000 0xb0000>;
+	#clock-cells = <1>;
+};
+
+usdhc1: mmc at 5b010000 {
+	compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
+	interrupt-parent = <&gic>;
+	interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+	reg = <0x5b010000 0x10000>;
+	clocks = <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_IPG_CLK>,
+		 <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_PER_CLK>,
+		 <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_HCLK>;
+	clock-names = "ipg", "per", "ahb";
+};
include/dt-bindings/clock/imx8qxp-clock.h +153 -0

157 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#6 lore raw

PATCH v6 4/6 dt-bindings: clock: add imx8qxp lpcg clock binding

Quoted 16 lines · A.s. Dong

The Low-Power Clock Gate (LPCG) modules contain a local programming model to control the clock gates for the peripherals. An LPCG module is used to locally gate the clocks for the associated peripheral.

Note:
This level of clock gating is provided after the clocks are generated by the SCU resources and clock controls. Thus even if the clock is enabled by these control bits, it might still not be running based on the base resource.

Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Rob Herring <[email protected]>
Cc devicetree at vger.kernel.org
Quoted 6 lines
---
 .../devicetree/bindings/clock/imx8qxp-lpcg.txt     |  51 +++++++
 include/dt-bindings/clock/imx8qxp-clock.h          | 153 +++++++++++++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
author
#7 lore raw

PATCH v6 5/6 clk: imx: add lpcg clock support

In reply to A.s. Dong

The Low-Power Clock Gate (LPCG) modules contain a local programming model to control the clock gates for the peripherals. An LPCG module is used to locally gate the clocks for the associated peripheral. And they're bedind the SCU clock.

Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Michael Turquette <[email protected]>

---
ChangeLog:
v6: separate from [PATCH V5 5/9] clk: imx: scu: add scu clock gate

---
 drivers/clk/imx/Makefile       |   3 +-
 drivers/clk/imx/clk-lpcg-scu.c | 108 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/imx/clk-scu.h      |   3 ++
 3 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/clk-lpcg-scu.c
drivers/clk/imx/Makefile +2 -1
index 8369a34..cd2b6f0 100644
@@ -14,7 +14,8 @@ obj-$(CONFIG_MXC_CLK) += \
 	clk-pfd.o
 
 obj-$(CONFIG_MXC_CLK_SCU) += \
-	clk-scu.o
+	clk-scu.o \
+	clk-lpcg-scu.o
 
 obj-$(CONFIG_SOC_IMX1)   += clk-imx1.o
 obj-$(CONFIG_SOC_IMX21)  += clk-imx21.o
drivers/clk/imx/clk-lpcg-scu.c new file +108 -0

108 lines not on this page · raw message

drivers/clk/imx/clk-scu.h +3 -0
index 09f381b..b8e91b1 100644
@@ -18,4 +18,7 @@ static inline int imx_clk_scu_init(void)
 
 struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type);
 
+struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
+				unsigned long flags, void __iomem *reg,
+				u8 bit_idx, bool hw_gate);
 #endif
Signature · 1 line
2.7.4
maintainer
#8 lore raw

PATCH v6 5/6 clk: imx: add lpcg clock support

Quoting A.s. Dong (2018-11-10 07:20:04)

Quoted 19 lines
drivers/clk/imx/clk-lpcg-scu.c new file +13 -0
new file mode 100644
index 0000000..54a1cb3
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ *     Dong Aisheng <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(imx_lpcg_scu_lock);

drivers/clk/imx/clk-lpcg-scu.c line 23

Quoted 10 lines
drivers/clk/imx/clk-lpcg-scu.c new file +10 -0
+
+#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_lpcg_scu {
+       struct clk_hw hw;
+       void __iomem *reg;
+       u8 bit_idx;
+       bool hw_gate;

What does hw_gate mean? Can you add kernel-doc to this structure?

drivers/clk/imx/clk-lpcg-scu.c line 28

Quoted 5 lines
drivers/clk/imx/clk-lpcg-scu.c new file +5 -0
+};
+
+#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
+
+/* Write to the LPCG bits. */

Please remove this useless comment.

drivers/clk/imx/clk-lpcg-scu.c line 32

Quoted 4 lines
drivers/clk/imx/clk-lpcg-scu.c new file +4 -0
+static int clk_lpcg_scu_enable(struct clk_hw *hw)
+{
+       struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+       unsigned long flags = 0;

Don't initialize flags here.

Quoted 14 lines
drivers/clk/imx/clk-lpcg-scu.c new file +14 -0
+       u32 reg;
+
+       spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
+
+       if (clk->reg) {
+               reg = readl(clk->reg);
+               reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
+               if (clk->hw_gate)
+                       reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
+                               CLK_GATE_SCU_LPCG_SW_SEL) << clk->bit_idx;
+               else
+                       reg |= (CLK_GATE_SCU_LPCG_SW_SEL << clk->bit_idx);
+               writel(reg, clk->reg);
+       }

drivers/clk/imx/clk-lpcg-scu.c line 56

Quoted 10 lines
drivers/clk/imx/clk-lpcg-scu.c new file +10 -0
+
+       spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
+
+       return 0;
+}
+
+static void clk_lpcg_scu_disable(struct clk_hw *hw)
+{
+       struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+       unsigned long flags = 0;

Same comment.

drivers/clk/imx/clk-lpcg-scu.c line 37

Quoted 5 lines
drivers/clk/imx/clk-lpcg-scu.c new file +5 -0
+       u32 reg;
+
+       spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
+
+       if (clk->reg) {

Why do we even call this function if there isn't a clk->reg value? Can't we just not assign the clk_ops in that case?

Quoted 8 lines
drivers/clk/imx/clk-lpcg-scu.c new file +8 -0
+               reg = readl(clk->reg);
+               reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
+               writel(reg, clk->reg);
+       }
+
+       spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
+}
+
#9 lore raw

PATCH v6 5/6 clk: imx: add lpcg clock support

Quoted 2 lines

-----Original Message-----
From: Stephen Boyd [mailto:sboyd at kernel.org]

[...]

Quoted 24 lines

Quoting A.s. Dong (2018-11-10 07:20:04)

Quoted 23 lines
(quoted diff) +0 -0

b/drivers/clk/imx/clk-lpcg-scu.c new file mode 100644 index 0000000..54a1cb3

drivers/clk/imx/clk-lpcg-scu.c new file +17 -0
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ *     Dong Aisheng <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
+
+#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)
Quoted 9 lines

drivers/clk/imx/clk-lpcg-scu.c line 23

Quoted 6 lines
drivers/clk/imx/clk-lpcg-scu.c new file +6 -0
+
+struct clk_lpcg_scu {
+       struct clk_hw hw;
+       void __iomem *reg;
+       u8 bit_idx;
+       bool hw_gate;

What does hw_gate mean? Can you add kernel-doc to this structure?

It's for enabling HW auto gate feature.
Up till now, mostly IP drivers does not use it, but we still keep it in case someone wants it in the future.
I will add kernel doc for it later.

Quoted 9 lines

drivers/clk/imx/clk-lpcg-scu.c line 28

Quoted 6 lines
drivers/clk/imx/clk-lpcg-scu.c new file +6 -0
+};
+
+#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu,
+hw)
+
+/* Write to the LPCG bits. */

Please remove this useless comment.

Got it.

Quoted 6 lines

drivers/clk/imx/clk-lpcg-scu.c line 32

Quoted 3 lines
drivers/clk/imx/clk-lpcg-scu.c new file +3 -0
+static int clk_lpcg_scu_enable(struct clk_hw *hw) {
+       struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+       unsigned long flags = 0;

Don't initialize flags here.

Can't remember whether initialize it to avoid a kernel warning. Will check and remove it if not needed.

Quoted 28 lines

drivers/clk/imx/clk-lpcg-scu.c

Quoted 10 lines
drivers/clk/imx/clk-lpcg-scu.c new file +10 -0
+       u32 reg;
+
+       spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
+
+       if (clk->reg) {
+               reg = readl(clk->reg);
+               reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
+               if (clk->hw_gate)
+                       reg |= (CLK_GATE_SCU_LPCG_HW_SEL |
+                               CLK_GATE_SCU_LPCG_SW_SEL) <<

clk->bit_idx;

drivers/clk/imx/clk-lpcg-scu.c line 44

Quoted 2 lines
drivers/clk/imx/clk-lpcg-scu.c new file +2 -0
+               else
+                       reg |= (CLK_GATE_SCU_LPCG_SW_SEL <<

clk->bit_idx);

drivers/clk/imx/clk-lpcg-scu.c line 56

Quoted 11 lines
drivers/clk/imx/clk-lpcg-scu.c new file +11 -0
+               writel(reg, clk->reg);
+       }
+
+       spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
+
+       return 0;
+}
+
+static void clk_lpcg_scu_disable(struct clk_hw *hw) {
+       struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+       unsigned long flags = 0;

Same comment.

Quoted 9 lines

drivers/clk/imx/clk-lpcg-scu.c line 37

Quoted 5 lines
drivers/clk/imx/clk-lpcg-scu.c new file +5 -0
+       u32 reg;
+
+       spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
+
+       if (clk->reg) {

Why do we even call this function if there isn't a clk->reg value? Can't we just not assign the clk_ops in that case?

Good catch, this is legacy code and could be removed.

Regards
Dong Aisheng

Quoted 7 lines
Quoted 7 lines
drivers/clk/imx/clk-lpcg-scu.c new file +7 -0
+               reg = readl(clk->reg);
+               reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
+               writel(reg, clk->reg);
+       }
+
+       spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); }
+
author
#10 lore raw

PATCH v6 6/6 clk: imx: add imx8qxp lpcg driver

In reply to A.s. Dong

Add imx8qxp lpcg driver support

Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Michael Turquette <[email protected]>

---
ChangeLog:
v6: new patch, separate from scu gate driver

---
 drivers/clk/imx/Makefile           |   2 +-
 drivers/clk/imx/clk-imx8qxp-lpcg.c | 198 +++++++++++++++++++++++++++++++++++++
 drivers/clk/imx/clk-imx8qxp-lpcg.h | 102 +++++++++++++++++++
 3 files changed, 301 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/imx/clk-imx8qxp-lpcg.c
 create mode 100644 drivers/clk/imx/clk-imx8qxp-lpcg.h
drivers/clk/imx/Makefile +1 -1
index cd2b6f0..96ab82b 100644
@@ -32,4 +32,4 @@ obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
 obj-$(CONFIG_SOC_IMX7D)  += clk-imx7d.o
 obj-$(CONFIG_SOC_VF610)  += clk-vf610.o
 
-obj-$(CONFIG_SOC_IMX8QXP)	+= clk-imx8qxp.o
+obj-$(CONFIG_SOC_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +198 -0

198 lines not on this page · raw message

drivers/clk/imx/clk-imx8qxp-lpcg.h new file +102 -0

102 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#11 lore raw

PATCH v6 6/6 clk: imx: add imx8qxp lpcg driver

Quoting A.s. Dong (2018-11-10 07:20:08)

Quoted 8 lines

Add imx8qxp lpcg driver support

Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Michael Turquette <[email protected]>

I like it!

drivers/clk/imx/clk-imx8qxp-lpcg.c line 7

Quoted 13 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
new file mode 100644
index 0000000..7b318d7
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ *     Dong Aisheng <[email protected]>
+ */
+
+#include <dt-bindings/clock/imx8qxp-clock.h>

Include this after <linux/*> and before locals please.

Quoted 17 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +17 -0
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+#include "clk-imx8qxp-lpcg.h"
+
+struct imx8qxp_lpcg_data {
+       int id;
+       char *name;
+       char *parent;
+       unsigned long flags;

drivers/clk/imx/clk-imx8qxp-lpcg.c line 34

Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+       u32 offset;
+       u8 bit_idx;
+       bool hw_gate;
+};
+
+struct imx8qxp_ss_lpcg {
+       const struct imx8qxp_lpcg_data *lpcg;
+       u8 num_lpcg;
+       u8 num_max;
+};

Any chance we can get kernel-doc on these structs and members of the structs?

Quoted 6 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +6 -0
+
+static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
+       { IMX8QXP_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },
+       { IMX8QXP_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },
+       { IMX8QXP_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },
+       { IMX8QXP_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },

[...]

drivers/clk/imx/clk-imx8qxp-lpcg.c line 143

Quoted 12 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +12 -0
+
+static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct clk_hw_onecell_data *clk_data;
+       const struct imx8qxp_ss_lpcg *ss_lpcg;
+       const struct imx8qxp_lpcg_data *lpcg;
+       struct resource *res;
+       struct clk_hw **clks;
+       void __iomem *base;
+       int i;

That's a good amount of local variables!

drivers/clk/imx/clk-imx8qxp-lpcg.c line 150

Quoted 7 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
+
+       ss_lpcg = of_device_get_match_data(dev);
+       if (!ss_lpcg)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap(dev, res->start, resource_size(res));

Why not devm_ioremap_resource()?

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 2 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +2 -0
+       if (!base)
+               return -ENOMEM;

And then return the error code out of it?

drivers/clk/imx/clk-imx8qxp-lpcg.c line 155

Quoted 3 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +3 -0
+
+       clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
+                               sizeof(*clk_data->hws) * ss_lpcg->num_max,

Can you use struct_size() here?

Quoted 8 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +8 -0
+                               GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->num = ss_lpcg->num_max;
+       clks = clk_data->hws;
+
+       for (i = 0; i < ss_lpcg->num_lpcg; i++) {

drivers/clk/imx/clk-imx8qxp-lpcg.c line 173

Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+               lpcg = ss_lpcg->lpcg + i;
+               clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent,
+                                                 lpcg->flags, base + lpcg->offset,
+                                                 lpcg->bit_idx, lpcg->hw_gate);
+       }
+
+       for (i = 0; i < clk_data->num; i++) {
+               if (IS_ERR(clks[i]))
+                       pr_err("i.MX clk %u: register failed with %ld\n",
+                               i, PTR_ERR(clks[i]));

But we're OK to continue? Alright...

drivers/clk/imx/clk-imx8qxp-lpcg.c line 176

Quoted 3 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +3 -0
+       }
+
+       return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);

Why not use devm_? Or can the driver never be unbound from sysfs?

Quoted 12 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +12 -0
+}
+
+static const struct of_device_id imx8qxp_lpcg_match[] = {
+       { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
+       { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
+       { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
+       { /* sentinel */ }
+};
+
+static struct platform_driver imx8qxp_lpcg_clk_driver = {
+       .driver = {
+               .name = "imx8qxp-lpcg-clk",

drivers/clk/imx/clk-imx8qxp-lpcg.c line 198

Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+               .of_match_table = imx8qxp_lpcg_match,
+       },
+       .probe = imx8qxp_lpcg_clk_probe,
+};
+
+builtin_platform_driver(imx8qxp_lpcg_clk_driver);
+
+MODULE_AUTHOR("Dong Aisheng <[email protected]>");
+MODULE_DESCRIPTION("IMX8QXP LPCG Clock driver");
+MODULE_LICENSE("GPL v2");

If the module is builtin all the time because of builtin_platform_driver() I think we don't need these MODULE_ macros.

author
#12 lore raw

PATCH v6 6/6 clk: imx: add imx8qxp lpcg driver

Hi Stephen,

Thanks for the quick review! :)

Quoted 3 lines

-----Original Message-----
From: Stephen Boyd [mailto:sboyd at kernel.org]
Sent: Thursday, November 15, 2018 7:29 AM

[...]

Quoted 4 lines

Quoting A.s. Dong (2018-11-10 07:20:08)

Quoted 2 lines

Add imx8qxp lpcg driver support

Quoted 9 lines
Quoted 6 lines
Cc Stephen Boyd <[email protected]>
Cc Shawn Guo <[email protected]>
Cc Sascha Hauer <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Michael Turquette <[email protected]>

I like it!

Great to know that.

Quoted 8 lines
Quoted 8 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +1 -0
new file mode 100644
index 0000000..7b318d7
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 7

Quoted 6 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +6 -0
+/*
+ * Copyright 2018 NXP
+ *     Dong Aisheng <[email protected]>
+ */
+
+#include <dt-bindings/clock/imx8qxp-clock.h>

Include this after <linux/*> and before locals please.

Got it.

Quoted 22 lines
Quoted 22 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +22 -0
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-scu.h"
+#include "clk-imx8qxp-lpcg.h"
+
+struct imx8qxp_lpcg_data {
+       int id;
+       char *name;
+       char *parent;
+       unsigned long flags;
+       u32 offset;
+       u8 bit_idx;
+       bool hw_gate;
+};
+
Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 34

Quoted 5 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +5 -0
+struct imx8qxp_ss_lpcg {
+       const struct imx8qxp_lpcg_data *lpcg;
+       u8 num_lpcg;
+       u8 num_max;
+};

Any chance we can get kernel-doc on these structs and members of the structs?

I can add it.

Quoted 12 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 3 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +3 -0
+
+static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
+       { IMX8QXP_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk",

"dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },

drivers/clk/imx/clk-imx8qxp-lpcg.c line 38

Quoted 1 line
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +1 -0
+       { IMX8QXP_ADMA_LPCG_UART0_BAUD_CLK,

"uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },

drivers/clk/imx/clk-imx8qxp-lpcg.c line 39

Quoted 1 line
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +1 -0
+       { IMX8QXP_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk",

"dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },

drivers/clk/imx/clk-imx8qxp-lpcg.c line 40

Quoted 1 line
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +1 -0
+       { IMX8QXP_ADMA_LPCG_UART1_BAUD_CLK,

"uart1_lpcg_baud_clk",

Quoted 1 line
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +1 -0
+"uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },

[...]

Quoted 13 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 143

Quoted 11 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +11 -0
+
+static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) {
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct clk_hw_onecell_data *clk_data;
+       const struct imx8qxp_ss_lpcg *ss_lpcg;
+       const struct imx8qxp_lpcg_data *lpcg;
+       struct resource *res;
+       struct clk_hw **clks;
+       void __iomem *base;
+       int i;

That's a good amount of local variables!

Yes, seems we need them.
Please let me know if you have a better idea.

Quoted 10 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 150

Quoted 8 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
+
+       ss_lpcg = of_device_get_match_data(dev);
+       if (!ss_lpcg)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap(dev, res->start, resource_size(res));

Why not devm_ioremap_resource()?

Because LPCGs are distributed in various subsystem memory space which may be overlapped with some IP modules. So we can't use devm_ioremap_resource which has a request_mem_region() in it.
It's something like what we've done for drivers/mfd/syscon.c.

Quoted 6 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 3 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +2 -0
+       if (!base)
+               return -ENOMEM;

And then return the error code out of it?

See above.

Quoted 7 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 4 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +4 -0
+
+       clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
+                               sizeof(*clk_data->hws) *
+ ss_lpcg->num_max,

Can you use struct_size() here?

Got it, thanks for pointing to this new api.

Quoted 15 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+                               GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->num = ss_lpcg->num_max;
+       clks = clk_data->hws;
+
+       for (i = 0; i < ss_lpcg->num_lpcg; i++) {
+               lpcg = ss_lpcg->lpcg + i;
+               clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name,

lpcg->parent,

Quoted 1 line

+ lpcg->flags, base +

lpcg->offset,

Quoted 1 line

+ lpcg->bit_idx,

lpcg->hw_gate);

Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 173

Quoted 6 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +6 -0
+       }
+
+       for (i = 0; i < clk_data->num; i++) {
+               if (IS_ERR(clks[i]))
+                       pr_err("i.MX clk %u: register failed with %ld\n",
+                               i, PTR_ERR(clks[i]));

But we're OK to continue? Alright...

Yes, probably better to use pr_warn()?

Quoted 7 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 4 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +4 -0
+       }
+
+       return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+ clk_data);

Why not use devm_? Or can the driver never be unbound from sysfs?

We expect the driver to be never unbound from sysfs. Probably we'd better add .suppress_bind_attrs.

Quoted 21 lines
Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+}
+
+static const struct of_device_id imx8qxp_lpcg_match[] = {
+       { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
+       { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
+       { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
+       { /* sentinel */ }
+};
+
+static struct platform_driver imx8qxp_lpcg_clk_driver = {

drivers/clk/imx/clk-imx8qxp-lpcg.c line 197

Quoted 10 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+       .driver = {
+               .name = "imx8qxp-lpcg-clk",
+               .of_match_table = imx8qxp_lpcg_match,
+       },
+       .probe = imx8qxp_lpcg_clk_probe, };
+
+builtin_platform_driver(imx8qxp_lpcg_clk_driver);
+
+MODULE_AUTHOR("Dong Aisheng <[email protected]>");
+MODULE_DESCRIPTION("IMX8QXP LPCG Clock driver");

MODULE_LICENSE("GPL

Quoted 4 lines
Quoted 1 line

+v2");

If the module is builtin all the time because of builtin_platform_driver() I think we don't need these MODULE_ macros.

Okay, I can remove them.

Regards
Dong Aisheng

maintainer
#13 lore raw

PATCH v6 6/6 clk: imx: add imx8qxp lpcg driver

Quoting A.s. Dong (2018-11-14 17:28:05)

Quoted 14 lines
Quoted 4 lines

-----Original Message-----
From: Stephen Boyd [mailto:sboyd at kernel.org]

Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 150

Quoted 7 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
+
+       ss_lpcg = of_device_get_match_data(dev);
+       if (!ss_lpcg)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap(dev, res->start, resource_size(res));

Why not devm_ioremap_resource()?

Quoted 4 lines

Because LPCGs are distributed in various subsystem memory space which may be overlapped with some IP modules. So we can't use devm_ioremap_resource which has a request_mem_region() in it.
It's something like what we've done for drivers/mfd/syscon.c.

Ok. Any chance that the various subsystems that are combined with the clk controller can be split up so that we can use devm_ioremap_resource() here? It may be better to carve up the I/O space of this SoC into device nodes that map to the hardware IP blocks, and then have those device drivers generate sub-devices for the various logical subsystems that the hardware IP spans. Or it could be a big driver that registers with multiple subsytems/frameworks from one device driver. This way, the logical structure of the linux kernel device driver design doesn't leak into the DT description of the SoC.

Quoted 23 lines
Quoted 23 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 11 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+                               GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->num = ss_lpcg->num_max;
+       clks = clk_data->hws;
+
+       for (i = 0; i < ss_lpcg->num_lpcg; i++) {
+               lpcg = ss_lpcg->lpcg + i;
+               clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name,

lpcg->parent,

Quoted 1 line

+ lpcg->flags, base +

lpcg->offset,

Quoted 1 line

+ lpcg->bit_idx,

lpcg->hw_gate);

Quoted 6 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +6 -0
+       }
+
+       for (i = 0; i < clk_data->num; i++) {
+               if (IS_ERR(clks[i]))
+                       pr_err("i.MX clk %u: register failed with %ld\n",
+                               i, PTR_ERR(clks[i]));
Quoted 4 lines
Quoted 2 lines

But we're OK to continue? Alright...

Yes, probably better to use pr_warn()?

Yes.

Quoted 11 lines
Quoted 8 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 5 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +4 -0
+       }
+
+       return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+ clk_data);

Why not use devm_? Or can the driver never be unbound from sysfs?

We expect the driver to be never unbound from sysfs. Probably we'd better add .suppress_bind_attrs.

Ok. Please add it.

#14 lore raw

PATCH v6 6/6 clk: imx: add imx8qxp lpcg driver

Quoted 2 lines

-----Original Message-----
From: Stephen Boyd [mailto:sboyd at kernel.org]

[...]

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 150

Quoted 7 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
+
+       ss_lpcg = of_device_get_match_data(dev);
+       if (!ss_lpcg)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap(dev, res->start, resource_size(res));

Why not devm_ioremap_resource()?

Quoted 8 lines
Quoted 4 lines

Because LPCGs are distributed in various subsystem memory space which may be overlapped with some IP modules. So we can't use devm_ioremap_resource which has a request_mem_region() in it. It's something like what we've done for drivers/mfd/syscon.c.

Ok. Any chance that the various subsystems that are combined with the clk controller can be split up so that we can use devm_ioremap_resource() here?

We can achieve that by describing each LPCGS node in devicetree, but that would bloat the Devicetree seriously as we have hundreds of LPCGS.

This is similar as what we did for legacy SoCs, e.g MX7D. The difference is that on MX7D LPCGS are continuous. e.g.
Table 5-19. CCGR Mapping Table
Gating Register LPCG Enable Offset
CCM_CCGR4 sim_main 0x4040
CCM_CCGR5 sim_display 0x4050
...
CCM_CCGR168 iomux 0x4A80
CCM_CCGR169 iomux_lpsr 0x4A90
CCM_CCGR170 kpp 0x4AA0

But on MX8QXP/QM, they're not continuous anymore and distributed in each SS. And we probably want to push our IC designer to re-orgnize them into a continuous memory map again for new chips in the future.

So do you think we can start with this way for MX8 as well? Then we won't block MX8QXP booting up too long or probably could improve it Later.

Quoted 8 lines

It may be better to carve up the I/O space of
this SoC into device nodes that map to the hardware IP blocks, and then have those device drivers generate sub-devices for the various logical subsystems that the hardware IP spans. Or it could be a big driver that registers with multiple subsytems/frameworks from one device driver. This way, the logical structure of the linux kernel device driver design doesn't leak into the DT description of the SoC.

Yes, we currently already describe them with each subsystems in Devicetree.
https://patchwork.kernel.org/patch/10677311/

Regards
Dong Aisheng

Quoted 45 lines
Quoted 14 lines
Quoted 14 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 11 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +10 -0
+                               GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->num = ss_lpcg->num_max;
+       clks = clk_data->hws;
+
+       for (i = 0; i < ss_lpcg->num_lpcg; i++) {
+               lpcg = ss_lpcg->lpcg + i;
+               clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name,

lpcg->parent,

Quoted 2 lines

+ lpcg->flags,
+ base +

Quoted 8 lines
Quoted 8 lines

lpcg->offset,

Quoted 1 line

+ lpcg->bit_idx,

lpcg->hw_gate);

Quoted 5 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +5 -0
+       }
+
+       for (i = 0; i < clk_data->num; i++) {
+               if (IS_ERR(clks[i]))
+                       pr_err("i.MX clk %u: register failed

with %ld\n",

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

+ i, PTR_ERR(clks[i]));

But we're OK to continue? Alright...

Yes, probably better to use pr_warn()?

Yes.

Quoted 11 lines
Quoted 8 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c

Quoted 5 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +4 -0
+       }
+
+       return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+ clk_data);

Why not use devm_? Or can the driver never be unbound from sysfs?

We expect the driver to be never unbound from sysfs. Probably we'd better add .suppress_bind_attrs.

Ok. Please add it.

maintainer
#15 lore raw

RE: [PATCH V6 6/6] clk: imx: add imx8qxp lpcg driver

Quoting Aisheng DONG (2018-11-20 17:50:47)

Quoted 37 lines
Quoted 2 lines

-----Original Message-----
From: Stephen Boyd [mailto:[email protected]]

[...]

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

drivers/clk/imx/clk-imx8qxp-lpcg.c line 150

Quoted 7 lines
drivers/clk/imx/clk-imx8qxp-lpcg.c new file +7 -0
+
+       ss_lpcg = of_device_get_match_data(dev);
+       if (!ss_lpcg)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap(dev, res->start, resource_size(res));

Why not devm_ioremap_resource()?

Quoted 8 lines
Quoted 4 lines

Because LPCGs are distributed in various subsystem memory space which may be overlapped with some IP modules. So we can't use devm_ioremap_resource which has a request_mem_region() in it. It's something like what we've done for drivers/mfd/syscon.c.

Ok. Any chance that the various subsystems that are combined with the clk controller can be split up so that we can use devm_ioremap_resource() here?

We can achieve that by describing each LPCGS node in devicetree, but that would bloat the Devicetree seriously as we have hundreds of LPCGS.

This is similar as what we did for legacy SoCs, e.g MX7D. The difference is that on MX7D LPCGS are continuous. e.g.
Table 5-19. CCGR Mapping Table
Gating Register LPCG Enable Offset
CCM_CCGR4 sim_main 0x4040
CCM_CCGR5 sim_display 0x4050
...
CCM_CCGR168 iomux 0x4A80
CCM_CCGR169 iomux_lpsr 0x4A90
CCM_CCGR170 kpp 0x4AA0

Quoted 7 lines

But on MX8QXP/QM, they're not continuous anymore and distributed in each SS. And we probably want to push our IC designer to re-orgnize them into a continuous memory map again for new chips in the future.

So do you think we can start with this way for MX8 as well? Then we won't block MX8QXP booting up too long or probably could improve it Later.

Ok, I don't really understand the memory map of this SoC. I wouldn't push the IC designer to reorganize everything. I'd push the designer to make clock controller hw blocks, maybe even one per subsystem is OK, and then have that build on basic clk types that the clock controller drivers could use to implement the clk support.

Either way, this hardware must already exist so I think we're done here. I'm OK with whatever works at this point.

Quoted 10 lines
Quoted 9 lines

It may be better to carve up the I/O space of
this SoC into device nodes that map to the hardware IP blocks, and then have those device drivers generate sub-devices for the various logical subsystems that the hardware IP spans. Or it could be a big driver that registers with multiple subsytems/frameworks from one device driver. This way, the logical structure of the linux kernel device driver design doesn't leak into the DT description of the SoC.

Quoted 3 lines

Yes, we currently already describe them with each subsystems in Devicetree.
https://patchwork.kernel.org/patch/10677311/

Ok.