summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDong Aisheng <aisheng.dong@nxp.com>2019-12-02 18:02:07 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-12-02 18:02:07 +0800
commit9872ac864756839cbe0557ba4cdc975c44ec70d7 (patch)
tree9df4298c118128f7dacdc52f558488faaf75140b
parent1e188020fb52fdde34c9782d2189d068f6ef4d28 (diff)
parentc8505b1bc2dd3a3d6f9e0b624f58f2d45a258a4f (diff)
Merge branch 'clock/next' into next
* clock/next: (122 commits) LF-279 clk: imx: scu: ignore cpu resources when do owned check clk: s32v234: Enable FlexCAN clock clk: s32v234: Add definitions for CAN clocks clk: imx: Add missing mipi1_dsi_phy_clk LF-202-3 clk: imx: scu: ignore clks not owned ...
-rw-r--r--Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt12
-rw-r--r--Documentation/devicetree/bindings/clock/fsl,plldig.yaml54
-rw-r--r--Documentation/devicetree/bindings/clock/imx7ulp-clock.txt1
-rw-r--r--Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt46
-rw-r--r--Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt31
-rw-r--r--Documentation/devicetree/bindings/clock/s32v234-mc_me.txt16
-rw-r--r--arch/arm64/Kconfig.platforms6
-rw-r--r--drivers/clk/Kconfig11
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/clk-plldig.c301
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/imx/Makefile4
-rw-r--r--drivers/clk/imx/clk-composite-7ulp.c14
-rw-r--r--drivers/clk/imx/clk-composite-8m.c19
-rw-r--r--drivers/clk/imx/clk-gate2.c69
-rw-r--r--drivers/clk/imx/clk-imx25.c12
-rw-r--r--drivers/clk/imx/clk-imx27.c13
-rw-r--r--drivers/clk/imx/clk-imx31.c12
-rw-r--r--drivers/clk/imx/clk-imx35.c10
-rw-r--r--drivers/clk/imx/clk-imx5.c30
-rw-r--r--drivers/clk/imx/clk-imx6q.c114
-rw-r--r--drivers/clk/imx/clk-imx6sl.c26
-rw-r--r--drivers/clk/imx/clk-imx6sll.c33
-rw-r--r--drivers/clk/imx/clk-imx6sx.c172
-rw-r--r--drivers/clk/imx/clk-imx6ul.c6
-rw-r--r--drivers/clk/imx/clk-imx7d.c33
-rw-r--r--drivers/clk/imx/clk-imx7ulp.c30
-rw-r--r--drivers/clk/imx/clk-imx8mm.c49
-rw-r--r--drivers/clk/imx/clk-imx8mn.c44
-rw-r--r--drivers/clk/imx/clk-imx8mq.c62
-rw-r--r--drivers/clk/imx/clk-imx8qm-acm.c288
-rw-r--r--drivers/clk/imx/clk-imx8qm-rsrc.c118
-rw-r--r--drivers/clk/imx/clk-imx8qxp-acm.c248
-rw-r--r--drivers/clk/imx/clk-imx8qxp-lpcg.c242
-rw-r--r--drivers/clk/imx/clk-imx8qxp-lpcg.h45
-rw-r--r--drivers/clk/imx/clk-imx8qxp-rsrc.c89
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c319
-rw-r--r--drivers/clk/imx/clk-lpcg-scu.c47
-rw-r--r--drivers/clk/imx/clk-pfd.c49
-rw-r--r--drivers/clk/imx/clk-pfdv2.c6
-rw-r--r--drivers/clk/imx/clk-pll14xx.c17
-rw-r--r--drivers/clk/imx/clk-pllv3.c76
-rw-r--r--drivers/clk/imx/clk-scu.c580
-rw-r--r--drivers/clk/imx/clk-scu.h85
-rw-r--r--drivers/clk/imx/clk.c53
-rw-r--r--drivers/clk/imx/clk.h44
-rw-r--r--drivers/clk/s32/Kconfig4
-rw-r--r--drivers/clk/s32/Makefile2
-rw-r--r--drivers/clk/s32/clk-core.c53
-rw-r--r--drivers/clk/s32/clk.h55
-rw-r--r--drivers/clk/s32/s32v234/Makefile1
-rw-r--r--drivers/clk/s32/s32v234/clk-dfs.c236
-rw-r--r--drivers/clk/s32/s32v234/clk-plldig.c240
-rw-r--r--drivers/clk/s32/s32v234/clk.c299
-rw-r--r--drivers/clk/s32/s32v234/clk.h31
-rw-r--r--drivers/clk/s32/s32v234/dfs.h78
-rw-r--r--drivers/clk/s32/s32v234/mc_cgm.h70
-rw-r--r--drivers/clk/s32/s32v234/mc_me.h110
-rw-r--r--drivers/clk/s32/s32v234/pll.h78
-rw-r--r--drivers/clk/s32/s32v234/src.h17
-rw-r--r--include/dt-bindings/clock/imx6qdl-clock.h7
-rw-r--r--include/dt-bindings/clock/imx7d-clock.h5
-rw-r--r--include/dt-bindings/clock/imx7ulp-clock.h15
-rw-r--r--include/dt-bindings/clock/imx8-clock.h336
-rw-r--r--include/dt-bindings/clock/imx8mq-clock.h6
-rw-r--r--include/dt-bindings/clock/s32v234-clock.h65
-rw-r--r--include/linux/clk-provider.h1
-rw-r--r--include/soc/imx/gpc.h7
-rw-r--r--include/soc/imx/src.h6
69 files changed, 4365 insertions, 898 deletions
diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
index c149fadc6f47..fc5c22e81c61 100644
--- a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
+++ b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
@@ -89,7 +89,7 @@ Required properties:
"fsl,imx8qm-clock"
"fsl,imx8qxp-clock"
followed by "fsl,scu-clk"
-- #clock-cells: Should be 1. Contains the Clock ID value.
+- #clock-cells: Should be 2: Contains the Resource and Clock ID value.
- clocks: List of clock specifiers, must contain an entry for
each required entry in clock-names
- clock-names: Should include entries "xtal_32KHz", "xtal_24MHz"
@@ -97,9 +97,6 @@ Required properties:
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
-
Pinctrl bindings based on SCU Message Protocol
------------------------------------------------------------
@@ -186,7 +183,7 @@ firmware {
clk: clk {
compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
- #clock-cells = <1>;
+ #clock-cells = <2>;
};
iomuxc {
@@ -231,8 +228,7 @@ serial@5a060000 {
...
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpuart0>;
- clocks = <&clk IMX8QXP_UART0_CLK>,
- <&clk IMX8QXP_UART0_IPG_CLK>;
- clock-names = "per", "ipg";
+ clocks = <&uart0_clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>;
+ clock-names = "ipg";
power-domains = <&pd IMX_SC_R_UART_0>;
};
diff --git a/Documentation/devicetree/bindings/clock/fsl,plldig.yaml b/Documentation/devicetree/bindings/clock/fsl,plldig.yaml
new file mode 100644
index 000000000000..ee5b5c61a471
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/fsl,plldig.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/clock/fsl,plldig.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP QorIQ Layerscape LS1028A Display PIXEL Clock Binding
+
+maintainers:
+ - Wen He <wen.he_1@nxp.com>
+
+description: |
+ NXP LS1028A has a clock domain PXLCLK0 used for the Display output
+ interface in the display core, as implemented in TSMC CLN28HPM PLL.
+ which generate and offers pixel clocks to Display.
+
+properties:
+ compatible:
+ const: fsl,ls1028a-plldig
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 0
+
+ vco-frequency:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: Optional for VCO frequency of the PLL in Hertz.
+ The VCO frequency of this PLL cannot be changed during runtime
+ only at startup. Therefore, the output frequencies are very
+ limited and might not even closely match the requested frequency.
+ To work around this restriction the user may specify its own
+ desired VCO frequency for the PLL. The frequency has to be in the
+ range of 650000000 to 1300000000.
+ If not set, the default frequency is 1188000000.
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - '#clock-cells'
+
+examples:
+ # Display PIXEL Clock node:
+ - |
+ dpclk: clock-display@f1f0000 {
+ compatible = "fsl,ls1028a-plldig";
+ reg = <0x0 0xf1f0000 0x0 0xffff>;
+ #clock-cells = <0>;
+ clocks = <&osc_27m>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
index a4f8cd478f92..93d89adb7afe 100644
--- a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
@@ -82,7 +82,6 @@ pcc2: pcc2@403f0000 {
<&scg1 IMX7ULP_CLK_APLL_PFD0>,
<&scg1 IMX7ULP_CLK_UPLL>,
<&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
- <&scg1 IMX7ULP_CLK_MIPI_PLL>,
<&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
<&scg1 IMX7ULP_CLK_ROSC>,
<&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
diff --git a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
index 965cfa42e025..8faee11b20b4 100644
--- a/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
+++ b/Documentation/devicetree/bindings/clock/imx8qxp-lpcg.txt
@@ -11,32 +11,38 @@ 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>
+- compatible: Should be one of:
+ "fsl,imx8qxp-lpcg"
+ "fsl,imx8qm-lpcg" followed by "fsl,imx8qxp-lpcg".
+- reg: Address and length of the register set.
+- #clock-cells: Should be 1. One LPCG supports multiple clocks.
+- clocks: Input parent clocks phandle array for each clock.
+- bit-offset: An integer array indicating the bit offset for each clock.
+- hw-autogate: Boolean array indicating whether supports HW autogate for
+ each clock.
+- clock-output-names: Shall be the corresponding names of the outputs.
+ NOTE this property must be specified in the same order
+ as the clock bit-offset and hw-autogate property.
+- power-domains: Should contain the power domain used by this clock.
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@5b200000 {
- compatible = "fsl,imx8qxp-lpcg-conn";
- reg = <0x5b200000 0xb0000>;
+sdhc0_lpcg: clock-controller@5b200000 {
+ compatible = "fsl,imx8qxp-lpcg";
+ reg = <0x5b200000 0x10000>;
#clock-cells = <1>;
+ clocks = <&sdhc0_clk IMX_SC_PM_CLK_PER>,
+ <&conn_ipg_clk>, <&conn_axi_clk>;
+ bit-offset = <0 16 20>;
+ clock-output-names = "sdhc0_lpcg_per_clk",
+ "sdhc0_lpcg_ipg_clk",
+ "sdhc0_lpcg_ahb_clk";
+ power-domains = <&pd IMX_SC_R_SDHC_0>;
};
usdhc1: mmc@5b010000 {
@@ -44,8 +50,8 @@ usdhc1: mmc@5b010000 {
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>;
+ clocks = <&sdhc0_lpcg 1>,
+ <&sdhc0_lpcg 0>,
+ <&sdhc0_lpcg 2>;
clock-names = "ipg", "per", "ahb";
};
diff --git a/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt b/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt
new file mode 100644
index 000000000000..d0d43e6ae597
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/s32v234-mc_cgm.txt
@@ -0,0 +1,31 @@
+* NXP S32V234 Clock Generation Modules (MC_CGMs)
+
+The SoC supports four Clock Generation Modules, which provide registers for
+system and peripherals clock source selection and division. See chapters 22
+("Clocking"), 23 ("Clock Generation Module (MC_CGM)") and 69 ("Mode Entry
+Module (MC_ME)") in the reference manual[1].
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be:
+ - "fsl,s32v234-mc_cgm0" for MC_CGM_0
+ - "fsl,s32v234-mc_cgm1" for MC_CGM_1
+ - "fsl,s32v234-mc_cgm2" for MC_CGM_2
+ - "fsl,s32v234-mc_cgm3" for MC_CGM_3
+- reg:
+ Location and length of the register set
+- #clock-cells (only for MC_CGM_0):
+ Should be <1>. See dt-bindings/clock/s32v234-clock.h for the clock
+ specifiers allowed in the clocks property of consumers.
+
+Example:
+clks: mc_cgm0@4003c000 {
+ compatible = "fsl,s32v234-mc_cgm0";
+ reg = <0x0 0x4003C000 0x0 0x1000>;
+ #clock-cells = <1>;
+};
+
+[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM
diff --git a/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt b/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt
new file mode 100644
index 000000000000..e9f4dcc3a257
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/s32v234-mc_me.txt
@@ -0,0 +1,16 @@
+* NXP S32V234 Mode Entry Module (MC_ME)
+
+See chapters 22 ("Clocking") and 69 ("Mode Entry Module (MC_ME)") in the
+reference manual[1].
+
+Required properties:
+- compatible: Should be "fsl,s32v234-mc_me"
+- reg: Location and length of the register set
+
+Example:
+mc_me: mc_me@4004a000 {
+ compatible = "fsl,s32v234-mc_me";
+ reg = <0x0 0x4004A000 0x0 0x1000>;
+};
+
+[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 577c8ae2a0c2..b4a5a4de80ee 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -218,6 +218,12 @@ config ARCH_ROCKCHIP
This enables support for the ARMv8 based Rockchip chipsets,
like the RK3368.
+config ARCH_S32
+ bool "NXP S32 SoC Family"
+ select ARCH_S32_CLK
+ help
+ This enables support for the NXP S32 family of processors.
+
config ARCH_SEATTLE
bool "AMD Seattle SoC Family"
help
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c44247d0b83e..2e67d597ab12 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -218,6 +218,16 @@ config CLK_QORIQ
This adds the clock driver support for Freescale QorIQ platforms
using common clock framework.
+config CLK_LS1028A_PLLDIG
+ tristate "Clock driver for LS1028A Display output"
+ depends on ARCH_LAYERSCAPE || COMPILE_TEST
+ default ARCH_LAYERSCAPE
+ help
+ This driver support the Display output interfaces(LCD, DPHY) pixel clocks
+ of the QorIQ Layerscape LS1028A, as implemented TSMC CLN28HPM PLL. Not all
+ features of the PLL are currently supported by the driver. By default,
+ configured bypass mode with this PLL.
+
config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC"
default ARCH_XGENE
@@ -318,6 +328,7 @@ source "drivers/clk/meson/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
+source "drivers/clk/s32/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sifive/Kconfig"
source "drivers/clk/sprd/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0138fb14e6f8..15488d4d358b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
+obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
@@ -97,6 +98,7 @@ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+obj-$(CONFIG_ARCH_S32) += s32/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SIRF) += sirf/
diff --git a/drivers/clk/clk-plldig.c b/drivers/clk/clk-plldig.c
new file mode 100644
index 000000000000..365edd30da8c
--- /dev/null
+++ b/drivers/clk/clk-plldig.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ *
+ * Clock driver for LS1028A Display output interfaces(LCD, DPHY).
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/bitfield.h>
+
+/* PLLDIG register offsets and bit masks */
+#define PLLDIG_REG_PLLSR 0x24
+#define PLLDIG_LOCK_MASK BIT(2)
+#define PLLDIG_REG_PLLDV 0x28
+#define PLLDIG_MFD_MASK GENMASK(7, 0)
+#define PLLDIG_RFDPHI1_MASK GENMASK(30, 25)
+#define PLLDIG_REG_PLLFM 0x2c
+#define PLLDIG_SSCGBYP_ENABLE BIT(30)
+#define PLLDIG_REG_PLLFD 0x30
+#define PLLDIG_FDEN BIT(30)
+#define PLLDIG_FRAC_MASK GENMASK(15, 0)
+#define PLLDIG_DTH_MASK GENMASK(17, 16)
+#define PLLDIG_DTH_DISABLE 3
+#define PLLDIG_REG_PLLCAL1 0x38
+#define PLLDIG_REG_PLLCAL2 0x3c
+
+/* Range of the VCO frequencies, in Hz */
+#define PLLDIG_MIN_VCO_FREQ 650000000
+#define PLLDIG_MAX_VCO_FREQ 1300000000
+
+/* Range of the output frequencies, in Hz */
+#define PHI1_MIN_FREQ 27000000
+#define PHI1_MAX_FREQ 600000000
+
+/* Maximum value of the reduced frequency divider */
+#define MAX_RFDPHI1 63UL
+
+/* Best value of multiplication factor divider */
+#define PLLDIG_DEFAULT_MFD 44
+
+/*
+ * Denominator part of the fractional part of the
+ * loop multiplication factor.
+ */
+#define MFDEN 20480
+
+static const struct clk_parent_data parent_data[] = {
+ {.index = 0},
+};
+
+struct clk_plldig {
+ struct clk_hw hw;
+ void __iomem *regs;
+ unsigned int vco_freq;
+};
+
+#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw)
+
+static int plldig_enable(struct clk_hw *hw)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ u32 val;
+
+ val = readl(data->regs + PLLDIG_REG_PLLFM);
+ /*
+ * Use Bypass mode with PLL off by default, the frequency overshoot
+ * detector output was disable. SSCG Bypass mode should be enable.
+ */
+ val |= PLLDIG_SSCGBYP_ENABLE;
+ writel(val, data->regs + PLLDIG_REG_PLLFM);
+
+ return 0;
+}
+
+static void plldig_disable(struct clk_hw *hw)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ u32 val;
+
+ val = readl(data->regs + PLLDIG_REG_PLLFM);
+
+ val &= ~PLLDIG_SSCGBYP_ENABLE;
+ val |= FIELD_PREP(PLLDIG_SSCGBYP_ENABLE, 0x0);
+
+ writel(val, data->regs + PLLDIG_REG_PLLFM);
+}
+
+static int plldig_is_enabled(struct clk_hw *hw)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+
+ return (readl(data->regs + PLLDIG_REG_PLLFM) &
+ PLLDIG_SSCGBYP_ENABLE);
+}
+
+static unsigned long plldig_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ u32 val, rfdphi1;
+
+ val = readl(data->regs + PLLDIG_REG_PLLDV);
+
+ /* Check if PLL is bypassed */
+ if (val & PLLDIG_SSCGBYP_ENABLE)
+ return parent_rate;
+
+ rfdphi1 = FIELD_GET(PLLDIG_RFDPHI1_MASK, val);
+
+ /*
+ * If RFDPHI1 has a value of 1 the VCO frequency is also divided by
+ * one.
+ */
+ if (!rfdphi1)
+ rfdphi1 = 1;
+
+ return DIV_ROUND_UP(data->vco_freq, rfdphi1);
+}
+
+static unsigned long plldig_calc_target_div(unsigned long vco_freq,
+ unsigned long target_rate)
+{
+ unsigned long div;
+
+ div = DIV_ROUND_CLOSEST(vco_freq, target_rate);
+ div = max(1UL, div);
+ div = min(div, MAX_RFDPHI1);
+
+ return div;
+}
+
+static int plldig_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ unsigned int div;
+
+ if (req->rate < PHI1_MIN_FREQ)
+ req->rate = PHI1_MIN_FREQ;
+ if (req->rate > PHI1_MAX_FREQ)
+ req->rate = PHI1_MAX_FREQ;
+
+ div = plldig_calc_target_div(data->vco_freq, req->rate);
+ req->rate = DIV_ROUND_UP(data->vco_freq, div);
+
+ return 0;
+}
+
+static int plldig_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ unsigned int val, cond;
+ unsigned int rfdphi1;
+
+ if (rate < PHI1_MIN_FREQ)
+ rate = PHI1_MIN_FREQ;
+ if (rate > PHI1_MAX_FREQ)
+ rate = PHI1_MAX_FREQ;
+
+ rfdphi1 = plldig_calc_target_div(data->vco_freq, rate);
+
+ /* update the divider value */
+ val = readl(data->regs + PLLDIG_REG_PLLDV);
+ val &= ~PLLDIG_RFDPHI1_MASK;
+ val |= FIELD_PREP(PLLDIG_RFDPHI1_MASK, rfdphi1);
+ writel(val, data->regs + PLLDIG_REG_PLLDV);
+
+ /* delay 200us make sure that old lock state is cleared */
+ udelay(200);
+
+ /* Wait until PLL is locked or timeout (maximum 1000 usecs) */
+ return readl_poll_timeout_atomic(data->regs + PLLDIG_REG_PLLSR, cond,
+ cond & PLLDIG_LOCK_MASK, 0,
+ USEC_PER_MSEC);
+}
+
+static const struct clk_ops plldig_clk_ops = {
+ .enable = plldig_enable,
+ .disable = plldig_disable,
+ .is_enabled = plldig_is_enabled,
+ .recalc_rate = plldig_recalc_rate,
+ .determine_rate = plldig_determine_rate,
+ .set_rate = plldig_set_rate,
+};
+
+static int plldig_init(struct clk_hw *hw)
+{
+ struct clk_plldig *data = to_clk_plldig(hw);
+ struct clk_hw *parent = clk_hw_get_parent(hw);
+ unsigned long parent_rate = clk_hw_get_rate(parent);
+ unsigned long val;
+ unsigned long long lltmp;
+ unsigned int mfd, fracdiv = 0;
+
+ if (!parent)
+ return -EINVAL;
+
+ if (data->vco_freq) {
+ mfd = data->vco_freq / parent_rate;
+ lltmp = data->vco_freq % parent_rate;
+ lltmp *= MFDEN;
+ do_div(lltmp, parent_rate);
+ fracdiv = lltmp;
+ } else {
+ mfd = PLLDIG_DEFAULT_MFD;
+ data->vco_freq = parent_rate * mfd;
+ }
+
+ val = FIELD_PREP(PLLDIG_MFD_MASK, mfd);
+ writel(val, data->regs + PLLDIG_REG_PLLDV);
+
+ if (fracdiv) {
+ val = FIELD_PREP(PLLDIG_FRAC_MASK, fracdiv);
+ /* Enable fractional divider */
+ val |= PLLDIG_FDEN;
+ /* Disable dither */
+ val |= FIELD_PREP(PLLDIG_DTH_MASK, PLLDIG_DTH_DISABLE);
+ writel(val, data->regs + PLLDIG_REG_PLLFD);
+ }
+
+ return 0;
+}
+
+static int plldig_clk_probe(struct platform_device *pdev)
+{
+ struct clk_plldig *data;
+ struct resource *mem;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(data->regs))
+ return PTR_ERR(data->regs);
+
+ data->hw.init = CLK_HW_INIT_PARENTS_DATA("dpclk",
+ parent_data,
+ &plldig_clk_ops,
+ 0);
+
+ ret = devm_clk_hw_register(dev, &data->hw);
+ if (ret) {
+ dev_err(dev, "failed to register %s clock\n",
+ dev->of_node->name);
+ return ret;
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &data->hw);
+ if (ret) {
+ dev_err(dev, "unable to add clk provider\n");
+ return ret;
+ }
+
+ /*
+ * The frequency of the VCO cannot be changed during runtime.
+ * Therefore, let the user specify a desired frequency.
+ */
+ if (!of_property_read_u32(dev->of_node, "vco-frequency",
+ &data->vco_freq)) {
+ if (data->vco_freq < PLLDIG_MIN_VCO_FREQ ||
+ data->vco_freq > PLLDIG_MAX_VCO_FREQ)
+ return -EINVAL;
+ }
+
+ return plldig_init(&data->hw);
+}
+
+static const struct of_device_id plldig_clk_id[] = {
+ { .compatible = "fsl,ls1028a-plldig"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, plldig_clk_id);
+
+static struct platform_driver plldig_clk_driver = {
+ .driver = {
+ .name = "plldig-clock",
+ .of_match_table = plldig_clk_id,
+ },
+ .probe = plldig_clk_probe,
+};
+module_platform_driver(plldig_clk_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wen He <wen.he_1@nxp.com>");
+MODULE_DESCRIPTION("LS1028A Display output interface pixel clock driver");
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 1c677d7f7f53..c5c6ae99051d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2465,7 +2465,8 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
if (!core)
return 0;
- if (core->parent == parent)
+ if ((core->parent == parent) &&
+ !(core->flags & CLK_SET_PARENT_NOCACHE))
return 0;
/* verify ops for multi-parent clks */
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 77a3d714f1d5..1140f1c1a116 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -28,8 +28,8 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
-obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
-
+obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o clk-imx8qxp-acm.o \
+ clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o clk-imx8qm-acm.o
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/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c
index 060f8600ea0d..82eabd33e067 100644
--- a/drivers/clk/imx/clk-composite-7ulp.c
+++ b/drivers/clk/imx/clk-composite-7ulp.c
@@ -7,6 +7,7 @@
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/slab.h>
#include "clk.h"
@@ -32,6 +33,7 @@ struct clk_hw *imx7ulp_clk_composite(const char *name,
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
struct clk_hw *hw;
+ u32 val;
if (mux_present) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
@@ -70,6 +72,18 @@ struct clk_hw *imx7ulp_clk_composite(const char *name,
gate_hw = &gate->hw;
gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT;
+ /*
+ * make sure clock is gated during clock tree initialization,
+ * the HW ONLY allow clock parent/rate changed with clock gated,
+ * during clock tree initialization, clocks could be enabled
+ * by bootloader, so the HW status will mismatch with clock tree
+ * prepare count, then clock core driver will allow parent/rate
+ * change since the prepare count is zero, but HW actually
+ * prevent the parent/rate change due to the clock is enabled.
+ */
+ val = readl_relaxed(reg);
+ val &= ~(1 << PCG_CGC_SHIFT);
+ writel_relaxed(val, reg);
}
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
index 388bdb94f841..fd37389a84ef 100644
--- a/drivers/clk/imx/clk-composite-8m.c
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -154,13 +154,18 @@ struct clk *imx8m_clk_composite_flags(const char *name,
div->lock = &imx_ccm_lock;
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate)
- goto fail;
-
- gate_hw = &gate->hw;
- gate->reg = reg;
- gate->bit_idx = PCG_CGC_SHIFT;
+ /* skip registering the gate ops if M4 is enabled */
+ if (imx_src_is_m4_enabled()) {
+ gate_hw = NULL;
+ } else {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto fail;
+
+ gate_hw = &gate->hw;
+ gate->reg = reg;
+ gate->bit_idx = PCG_CGC_SHIFT;
+ }
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, div_hw,
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 7d44ce814806..d9a4487dd384 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -7,11 +7,13 @@
*/
#include <linux/clk-provider.h>
+#include <linux/imx_sema4.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <soc/imx/src.h>
#include "clk.h"
/**
@@ -35,11 +37,56 @@ struct clk_gate2 {
};
#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
+#define CCM_CCGR_FULL_ENABLE 0x3
+
+static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
+{
+ u32 reg;
+
+ reg = readl(gate->reg);
+ if (enable)
+ reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx;
+ else
+ reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx);
+ writel(reg, gate->reg);
+}
+
+static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate2 *gate = to_clk_gate2(hw);
+
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_gate2_do_hardware(gate, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_gate2_do_hardware(gate, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_gate2_do_hardware(gate, enable);
+ }
+}
static int clk_gate2_enable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
- u32 reg;
unsigned long flags = 0;
spin_lock_irqsave(gate->lock, flags);
@@ -47,11 +94,7 @@ static int clk_gate2_enable(struct clk_hw *hw)
if (gate->share_count && (*gate->share_count)++ > 0)
goto out;
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- reg |= gate->cgr_val << gate->bit_idx;
- writel(reg, gate->reg);
-
+ clk_gate2_do_shared_clks(hw, true);
out:
spin_unlock_irqrestore(gate->lock, flags);
@@ -61,7 +104,6 @@ out:
static void clk_gate2_disable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
- u32 reg;
unsigned long flags = 0;
spin_lock_irqsave(gate->lock, flags);
@@ -73,10 +115,7 @@ static void clk_gate2_disable(struct clk_hw *hw)
goto out;
}
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- writel(reg, gate->reg);
-
+ clk_gate2_do_shared_clks(hw, false);
out:
spin_unlock_irqrestore(gate->lock, flags);
}
@@ -102,15 +141,11 @@ static void clk_gate2_disable_unused(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
unsigned long flags = 0;
- u32 reg;
spin_lock_irqsave(gate->lock, flags);
- if (!gate->share_count || *gate->share_count == 0) {
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- writel(reg, gate->reg);
- }
+ if (!gate->share_count || *gate->share_count == 0)
+ clk_gate2_do_shared_clks(hw, false);
spin_unlock_irqrestore(gate->lock, flags);
}
diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index a66cabfbf94f..cc013b343e62 100644
--- a/drivers/clk/imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
@@ -73,16 +73,6 @@ enum mx25_clks {
static struct clk *clk[clk_max];
-static struct clk ** const uart_clks[] __initconst = {
- &clk[uart_ipg_per],
- &clk[uart1_ipg],
- &clk[uart2_ipg],
- &clk[uart3_ipg],
- &clk[uart4_ipg],
- &clk[uart5_ipg],
- NULL
-};
-
static int __init __mx25_clocks_init(void __iomem *ccm_base)
{
BUG_ON(!ccm_base);
@@ -228,7 +218,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base)
*/
clk_set_parent(clk[cko_sel], clk[ipg]);
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
return 0;
}
diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c
index a3753067fc12..ee9ef5079e40 100644
--- a/drivers/clk/imx/clk-imx27.c
+++ b/drivers/clk/imx/clk-imx27.c
@@ -49,17 +49,6 @@ static const char *ssi_sel_clks[] = { "spll_gate", "mpll", };
static struct clk *clk[IMX27_CLK_MAX];
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks[] __initconst = {
- &clk[IMX27_CLK_PER1_GATE],
- &clk[IMX27_CLK_UART1_IPG_GATE],
- &clk[IMX27_CLK_UART2_IPG_GATE],
- &clk[IMX27_CLK_UART3_IPG_GATE],
- &clk[IMX27_CLK_UART4_IPG_GATE],
- &clk[IMX27_CLK_UART5_IPG_GATE],
- &clk[IMX27_CLK_UART6_IPG_GATE],
- NULL
-};
-
static void __init _mx27_clocks_init(unsigned long fref)
{
BUG_ON(!ccm);
@@ -176,7 +165,7 @@ static void __init _mx27_clocks_init(unsigned long fref)
clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]);
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
imx_print_silicon_rev("i.MX27", mx27_revision());
}
diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
index 4bb05e440cdd..ae9ff78d45bf 100644
--- a/drivers/clk/imx/clk-imx31.c
+++ b/drivers/clk/imx/clk-imx31.c
@@ -51,16 +51,6 @@ enum mx31_clks {
static struct clk *clk[clk_max];
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks[] __initconst = {
- &clk[ipg],
- &clk[uart1_gate],
- &clk[uart2_gate],
- &clk[uart3_gate],
- &clk[uart4_gate],
- &clk[uart5_gate],
- NULL
-};
-
static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref)
{
clk[dummy] = imx_clk_fixed("dummy", 0);
@@ -197,7 +187,7 @@ int __init mx31_clocks_init(unsigned long fref)
clk_register_clkdev(clk[iim_gate], "iim", NULL);
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31);
return 0;
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index e595f559907f..c97511360e09 100644
--- a/drivers/clk/imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -82,14 +82,6 @@ enum mx35_clks {
static struct clk *clk[clk_max];
-static struct clk ** const uart_clks[] __initconst = {
- &clk[ipg],
- &clk[uart1_gate],
- &clk[uart2_gate],
- &clk[uart3_gate],
- NULL
-};
-
static void __init _mx35_clocks_init(void)
{
void __iomem *base;
@@ -243,7 +235,7 @@ static void __init _mx35_clocks_init(void)
*/
clk_prepare_enable(clk[scc_gate]);
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
imx_print_silicon_rev("i.MX35", mx35_revision());
}
diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
index 01e079b81026..b82044911603 100644
--- a/drivers/clk/imx/clk-imx5.c
+++ b/drivers/clk/imx/clk-imx5.c
@@ -128,30 +128,6 @@ static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_
static struct clk *clk[IMX5_CLK_END];
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks_mx51[] __initconst = {
- &clk[IMX5_CLK_UART1_IPG_GATE],
- &clk[IMX5_CLK_UART1_PER_GATE],
- &clk[IMX5_CLK_UART2_IPG_GATE],
- &clk[IMX5_CLK_UART2_PER_GATE],
- &clk[IMX5_CLK_UART3_IPG_GATE],
- &clk[IMX5_CLK_UART3_PER_GATE],
- NULL
-};
-
-static struct clk ** const uart_clks_mx50_mx53[] __initconst = {
- &clk[IMX5_CLK_UART1_IPG_GATE],
- &clk[IMX5_CLK_UART1_PER_GATE],
- &clk[IMX5_CLK_UART2_IPG_GATE],
- &clk[IMX5_CLK_UART2_PER_GATE],
- &clk[IMX5_CLK_UART3_IPG_GATE],
- &clk[IMX5_CLK_UART3_PER_GATE],
- &clk[IMX5_CLK_UART4_IPG_GATE],
- &clk[IMX5_CLK_UART4_PER_GATE],
- &clk[IMX5_CLK_UART5_IPG_GATE],
- &clk[IMX5_CLK_UART5_PER_GATE],
- NULL
-};
-
static void __init mx5_clocks_common_init(void __iomem *ccm_base)
{
clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@@ -382,7 +358,7 @@ static void __init mx50_clocks_init(struct device_node *np)
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
- imx_register_uart_clocks(uart_clks_mx50_mx53);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
@@ -488,7 +464,7 @@ static void __init mx51_clocks_init(struct device_node *np)
val |= 1 << 23;
writel(val, MXC_CCM_CLPCR);
- imx_register_uart_clocks(uart_clks_mx51);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);
@@ -633,6 +609,6 @@ static void __init mx53_clocks_init(struct device_node *np)
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
- imx_register_uart_clocks(uart_clks_mx50_mx53);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 60f2de851f39..f32c57d39d96 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -26,7 +26,8 @@ static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy",
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
-static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
+static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
+static const char *axi_sels[] = { "periph", "axi_alt_sel", };
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };
static const char *gpu_axi_sels[] = { "axi", "ahb", };
static const char *pre_axi_sels[] = { "axi", "ahb", };
@@ -36,15 +37,17 @@ static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_p
static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", };
static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };
static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
-static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
+static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", };
static const char *pcie_axi_sels[] = { "axi", "ahb", };
static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", };
@@ -90,6 +93,7 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
+static void __iomem *ccm_base;
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -139,13 +143,6 @@ static inline int clk_on_imx6dl(void)
return of_machine_is_compatible("fsl,imx6dl");
}
-static const int uart_clk_ids[] __initconst = {
- IMX6QDL_CLK_UART_IPG,
- IMX6QDL_CLK_UART_SERIAL,
-};
-
-static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
-
static int ldb_di_sel_by_clock_id(int clock_id)
{
switch (clock_id) {
@@ -258,6 +255,11 @@ static bool pll6_bypassed(struct device_node *node)
#define CCM_CCSR 0x0c
#define CCM_CS2CDR 0x2c
+#define CCM_CSCDR3 0x3c
+#define CCM_CCGR0 0x68
+#define CCM_CCGR3 0x74
+
+#define ANATOP_PLL3_PFD 0xf0
#define CCSR_PLL3_SW_CLK_SEL BIT(0)
@@ -394,6 +396,62 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
#define PFD2_CLKGATE BIT(23)
#define PFD3_CLKGATE BIT(31)
+/*
+ * workaround for ERR010579, when switching the clock source of IPU clock
+ * root in CCM. even setting CCGR3[CG0]=0x0 to gate off clock before
+ * switching, IPU may hang due to no IPU clock from CCM.
+ */
+static void __init init_ipu_clk(void __iomem *anatop_base)
+{
+ u32 val, origin_podf;
+
+ /* gate off the IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val &= ~0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* gate off IPU DCIC1/2 clocks */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val &= ~(0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+
+ /* set IPU_PODF to 3'b000 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ origin_podf = val & (0x7 << 11);
+ val &= ~(0x7 << 11);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* disable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val &= ~(0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* switch IPU_SEL clock to PLL3_PFD1 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= (0x3 << 9);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* restore the IPU PODF*/
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= origin_podf;
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* enable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val |= (0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* enable IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val |= 0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* enable IPU DCIC1/2 clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val |= (0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+}
+
static void disable_anatop_clocks(void __iomem *anatop_base)
{
unsigned int reg;
@@ -439,7 +497,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
struct device_node *np;
void __iomem *anatop_base, *base;
int ret;
- int i;
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6QDL_CLK_END), GFP_KERNEL);
@@ -604,6 +661,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
np = ccm_node;
base = of_iomap(np, 0);
+ ccm_base = base;
WARN_ON(!base);
/* name reg shift width parent_names num_parents */
@@ -613,7 +671,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
hws[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
+ hws[IMX6QDL_CLK_AXI_ALT_SEL] = imx_clk_hw_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels));
hws[IMX6QDL_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
hws[IMX6QDL_CLK_ASRC_SEL] = imx_clk_hw_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
hws[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
@@ -659,6 +718,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
}
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
@@ -727,6 +788,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0", 1, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1", 1, 7);
} else {
hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
@@ -734,6 +797,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
}
if (clk_on_imx6dl())
@@ -919,8 +984,19 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000);
- if (clk_on_imx6dl())
+ if (clk_on_imx6dl()) {
+ init_ipu_clk(anatop_base);
clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_AXI_SEL]->clk, hws[IMX6QDL_CLK_AXI_ALT_SEL]->clk);
+ /* set epdc/pxp axi clock to 200Mhz */
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk);
+ clk_set_rate(hws[IMX6QDL_CLK_IPU2]->clk, 200000000);
+ } else {
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_SEL]->clk, hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+ }
clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
@@ -978,12 +1054,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
}
- for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
- int index = uart_clk_ids[i];
-
- uart_clks[i] = &hws[index]->clk;
- }
-
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index 4bd44d89eaaa..f26435960784 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -177,19 +177,11 @@ void imx6sl_set_wait_clk(bool enter)
imx6sl_enable_pll_arm(false);
}
-static const int uart_clk_ids[] __initconst = {
- IMX6SL_CLK_UART,
- IMX6SL_CLK_UART_SERIAL,
-};
-
-static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
-
static void __init imx6sl_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int ret;
- int i;
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SL_CLK_END), GFP_KERNEL);
@@ -438,19 +430,23 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
/* Audio-related clocks configuration */
clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk);
+ /* Initialize Video PLLs to valid frequency (650MHz). */
+ clk_set_rate(hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk, 650000000);
+
/* set PLL5 video as lcdif pix parent clock */
clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk,
hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
+ /* Configure EPDC clocks */
+ clk_set_parent(hws[IMX6SL_CLK_EPDC_PIX_SEL]->clk,
+ hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6SL_CLK_EPDC_AXI_SEL]->clk,
+ hws[IMX6SL_CLK_PLL2_PFD2]->clk);
+ clk_set_rate(hws[IMX6SL_CLK_EPDC_AXI]->clk, 200000000);
+
clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
hws[IMX6SL_CLK_PLL2_PFD2]->clk);
- for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
- int index = uart_clk_ids[i];
-
- uart_clks[i] = &hws[index]->clk;
- }
-
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
index 5f3e92c09a5e..1035ef0e55a3 100644
--- a/drivers/clk/imx/clk-imx6sll.c
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -76,26 +76,10 @@ static u32 share_count_ssi1;
static u32 share_count_ssi2;
static u32 share_count_ssi3;
-static const int uart_clk_ids[] __initconst = {
- IMX6SLL_CLK_UART1_IPG,
- IMX6SLL_CLK_UART1_SERIAL,
- IMX6SLL_CLK_UART2_IPG,
- IMX6SLL_CLK_UART2_SERIAL,
- IMX6SLL_CLK_UART3_IPG,
- IMX6SLL_CLK_UART3_SERIAL,
- IMX6SLL_CLK_UART4_IPG,
- IMX6SLL_CLK_UART4_SERIAL,
- IMX6SLL_CLK_UART5_IPG,
- IMX6SLL_CLK_UART5_SERIAL,
-};
-
-static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
-
static void __init imx6sll_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
- int i;
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SLL_CLK_END), GFP_KERNEL);
@@ -356,13 +340,12 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
- for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
- int index = uart_clk_ids[i];
-
- uart_clks[i] = &hws[index]->clk;
- }
-
- imx_register_uart_clocks(uart_clks);
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ clk_set_parent(hws[IMX6SLL_CLK_UART_SEL]->clk, hws[IMX6SLL_CLK_OSC]->clk);
+ else
+ clk_set_parent(hws[IMX6SLL_CLK_UART_SEL]->clk, hws[IMX6SLL_CLK_PLL3_80M]->clk);
+ imx_register_uart_clocks();
/* Lower the AHB clock rate before changing the clock source. */
clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
@@ -372,6 +355,10 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk);
clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk);
+ /* Configure EPDC clocks */
+ clk_set_rate(hws[IMX6SLL_CLK_PLL3_PFD2]->clk, 320000000);
+ clk_set_parent(hws[IMX6SLL_CLK_EPDC_PRE_SEL]->clk,
+ hws[IMX6SLL_CLK_PLL3_PFD2]->clk);
clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000);
}
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index c4685c01929a..beed221ed4bd 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -10,13 +10,18 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/imx_sema4.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/gpc.h>
+#include <soc/imx/src.h>
#include "clk.h"
+#define CCM_CCGR_OFFSET(index) (index * 2)
+
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -83,6 +88,12 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
+struct imx_sema4_mutex *amp_power_mutex;
+
+static int clks_shared[MAX_SHARED_CLK_NUMBER];
+
+struct imx_shared_mem *shared_mem;
+static unsigned int shared_mem_paddr, shared_mem_size;
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -116,18 +127,43 @@ static u32 share_count_ssi3;
static u32 share_count_sai1;
static u32 share_count_sai2;
-static const int uart_clk_ids[] __initconst = {
- IMX6SX_CLK_UART_IPG,
- IMX6SX_CLK_UART_SERIAL,
-};
+/*
+ * As IMX6SX_CLK_M4_PRE_SEL is NOT a glitchless MUX, so when
+ * M4 is trying to change its clk parent, need to ask A9 to
+ * help do it, and M4 must be hold in wfi. To avoid glitch
+ * occur, need to gate M4 clk first before switching its parent.
+ */
+void imx6sx_set_m4_highfreq(bool high_freq)
+{
+ static struct clk *m4_high_freq_sel;
+
+ imx_gpc_hold_m4_in_sleep();
+
+ clk_disable_unprepare(hws[IMX6SX_CLK_M4]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk,
+ hws[IMX6SX_CLK_LDB_DI0]->clk);
+
+ if (high_freq) {
+ /* FIXME: m4_high_freq_sel possible used without intialization? */
+ clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk,
+ m4_high_freq_sel);
+ } else {
+ m4_high_freq_sel = clk_get_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_M4_PRE_SEL]->clk,
+ hws[IMX6SX_CLK_OSC]->clk);
+ }
+
+ clk_set_parent(hws[IMX6SX_CLK_M4_SEL]->clk,
+ hws[IMX6SX_CLK_M4_PRE_SEL]->clk);
+ clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk);
-static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+ imx_gpc_release_m4_in_sleep();
+}
static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
- int i;
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SX_CLK_CLK_END), GFP_KERNEL);
@@ -189,7 +225,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk);
clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk);
- hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
hws[IMX6SX_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
hws[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
hws[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
@@ -405,7 +441,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
hws[IMX6SX_CLK_GPT_BUS] = imx_clk_hw_gate2("gpt_bus", "perclk", base + 0x6c, 20);
hws[IMX6SX_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt_serial", "perclk", base + 0x6c, 22);
hws[IMX6SX_CLK_GPU] = imx_clk_hw_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
- hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2("ocram_s", "ahb", base + 0x6c, 28);
+ hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2_flags("ocram_s", "ahb", base + 0x6c, 28, CLK_IS_CRITICAL);
hws[IMX6SX_CLK_CANFD] = imx_clk_hw_gate2("canfd", "can_podf", base + 0x6c, 30);
/* CCGR2 */
@@ -489,13 +525,59 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
hws[IMX6SX_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7);
hws[IMX6SX_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24);
+ /* get those shared clk nodes if M4 is active */
+ if (imx_src_is_m4_enabled()) {
+ u32 num;
+
+ of_property_read_u32(np, "fsl,shared-clks-number", &num);
+ if (num > MAX_SHARED_CLK_NUMBER)
+ pr_err("clk: shared clk nodes exceed the max number!\n");
+ of_property_read_u32_array(np, "fsl,shared-clks-index",
+ clks_shared, num);
+ if (of_property_read_u32(np, "fsl,shared-mem-addr",
+ &shared_mem_paddr))
+ pr_err("clk: fsl,shared-mem-addr NOT found!\n");
+ if (of_property_read_u32(np, "fsl,shared-mem-size",
+ &shared_mem_size))
+ pr_err("clk: fsl,shared-mem-size NOT found!\n");
+ }
+
/* mask handshake of mmdc */
imx_mmdc_mask_handshake(base, 0);
imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
+ /*
+ * QSPI2/GPMI_IO share the same clock source but with the
+ * different gate, need explicitely gate the QSPI2 & GPMI_IO
+ * during the clock init phase according to the SOC design.
+ */
+ if (!imx_src_is_m4_enabled()) {
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(5)), base + 0x78);
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(14)), base + 0x78);
+ }
+
+
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+ /*
+ * As some of the modules need to access ocotp in MSL,
+ * need to make sure ocotp clk(CCM_CCGR2_CG6) is enabled
+ * during MSL, as on i.MX6SX, accessing OCOTP registers
+ * needs its clk on, it will be disabled by clk late
+ * init and managed by ocotp driver.
+ */
+ writel_relaxed(readl_relaxed(base + 0x70) | 1 << 12, base + 0x70);
+
+ /* maintain M4 usecount */
+ if (imx_src_is_m4_enabled())
+ clk_prepare_enable(hws[IMX6SX_CLK_M4]->clk);
+
+ /* set perclk to from OSC */
+ clk_set_parent(hws[IMX6SX_CLK_PERCLK_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk);
+
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk);
clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk);
@@ -542,6 +624,12 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000);
+ /* Set the UART parent if needed. */
+ if (uart_from_osc)
+ clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_OSC]->clk);
+ else
+ clk_set_parent(hws[IMX6SX_CLK_UART_SEL]->clk, hws[IMX6SX_CLK_PLL3_80M]->clk);
+
/* Set parent clock for vadc */
clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
@@ -551,16 +639,74 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* Update gpu clock from default 528M to 720M */
clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
+ if (!imx_src_is_m4_enabled())
+ /* default parent of can_sel clock is invalid, manually set it here */
+ clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
- for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
- int index = uart_clk_ids[i];
+ imx_register_uart_clocks();
+}
+CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
+
+int imx_update_shared_mem(struct clk_hw *hw, bool enable)
+{
+ int i;
- uart_clks[i] = &hws[index]->clk;
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ if (shared_mem->imx_clk[i].self == hw->clk)
+ break;
}
- imx_register_uart_clocks(uart_clks);
+ if (i >= ARRAY_SIZE(clks_shared))
+ return 1;
+
+ /* update ca9 clk status in shared memory */
+ if (enable)
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ else
+ shared_mem->imx_clk[i].ca9_enabled = 0;
+
+ if (shared_mem->imx_clk[i].cm4_enabled == 0)
+ return 1;
+
+ return 0;
}
-CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
+
+static int __init imx_amp_power_init(void)
+{
+ int i;
+ void __iomem *shared_mem_base;
+
+ if (!(imx_src_is_m4_enabled() && clk_on_imx6sx()))
+ return 0;
+
+ amp_power_mutex = imx_sema4_mutex_create(0, MCC_POWER_SHMEM_NUMBER);
+
+ shared_mem_base = ioremap_nocache(shared_mem_paddr, shared_mem_size);
+
+ if (!amp_power_mutex) {
+ pr_err("Failed to create sema4 mutex!\n");
+ return 0;
+ }
+
+ shared_mem = (struct imx_shared_mem *)shared_mem_base;
+
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ shared_mem->imx_clk[i].self = hws[clks_shared[i]]->clk;
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ pr_debug("%d: name %s, addr 0x%x\n", i,
+ __clk_get_name(shared_mem->imx_clk[i].self),
+ (u32)&(shared_mem->imx_clk[i]));
+ }
+ /* enable amp power management */
+ shared_mem->ca9_valid = SHARED_MEM_MAGIC_NUMBER;
+
+ pr_info("A9-M4 sema4 num %d, A9-M4 magic number 0x%x - 0x%x.\n",
+ amp_power_mutex->gate_num, shared_mem->ca9_valid,
+ shared_mem->cm4_valid);
+
+ return 0;
+}
+late_initcall(imx_amp_power_init);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index bc931988fe7b..6c0a8e0a7ef4 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -495,6 +495,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000);
clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000);
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
+ else
+ clk_set_parent(hws[IMX6UL_CLK_UART_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk);
+
if (clk_on_imx6ull())
clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index fbea774ef687..ed70a57e2e6d 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -14,6 +14,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/src.h>
#include "clk.h"
@@ -23,6 +24,7 @@ static u32 share_count_sai3;
static u32 share_count_nand;
static u32 share_count_enet1;
static u32 share_count_enet2;
+static u32 share_count_pxp;
static const struct clk_div_table test_div_table[] = {
{ .val = 3, .div = 1, },
@@ -376,23 +378,10 @@ static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;
-static const int uart_clk_ids[] __initconst = {
- IMX7D_UART1_ROOT_CLK,
- IMX7D_UART2_ROOT_CLK,
- IMX7D_UART3_ROOT_CLK,
- IMX7D_UART4_ROOT_CLK,
- IMX7D_UART5_ROOT_CLK,
- IMX7D_UART6_ROOT_CLK,
- IMX7D_UART7_ROOT_CLK,
-};
-
-static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
-
static void __init imx7d_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
- int i;
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX7D_CLK_END), GFP_KERNEL);
@@ -865,6 +854,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+ hws[IMX7D_PXP_IPG_CLK] = imx_clk_hw_gate2_shared2("pxp_ipg_clk", "ipg_root_clk", base + 0x44c0, 0, &share_count_pxp);
+ hws[IMX7D_PXP_AXI_CLK] = imx_clk_hw_gate2_shared2("pxp_axi_clk", "main_axi_root_clk", base + 0x44c0, 0, &share_count_pxp);
hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
@@ -887,6 +878,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
+ if (imx_src_is_m4_enabled()) {
+ clk_set_parent(hws[IMX7D_ARM_M4_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_240M_CLK]->clk);
+ clk_prepare_enable(hws[IMX7D_ARM_M4_ROOT_CLK]->clk);
+ clk_prepare_enable(hws[IMX7D_UART2_ROOT_CLK]->clk);
+ }
+
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
@@ -894,14 +891,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
- for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
- int index = uart_clk_ids[i];
-
- uart_clks[i] = &hws[index]->clk;
- }
-
+ /* set parent of EPDC pixel clock */
+ clk_set_parent(hws[IMX7D_EPDC_PIXEL_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_CLK]->clk);
- imx_register_uart_clocks(uart_clks);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c
index 2022d9bead91..7745ad3e1425 100644
--- a/drivers/clk/imx/clk-imx7ulp.c
+++ b/drivers/clk/imx/clk-imx7ulp.c
@@ -28,7 +28,7 @@ static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dumm
static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", };
static const char * const nic_sels[] = { "firc", "ddr_clk", };
static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
-static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
+static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "dummy", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
static const char * const arm_sels[] = { "divcore", "dummy", "dummy", "hsrun_divcore", };
/* used by sosc/sirc/firc/ddr/spll/apll dividers */
@@ -40,6 +40,7 @@ static const struct clk_div_table ulp_div_table[] = {
{ .val = 5, .div = 16, },
{ .val = 6, .div = 32, },
{ .val = 7, .div = 64, },
+ { /* sentinel */ },
};
static const int pcc2_uart_clk_ids[] __initconst = {
@@ -47,14 +48,6 @@ static const int pcc2_uart_clk_ids[] __initconst = {
IMX7ULP_CLK_LPUART5,
};
-static const int pcc3_uart_clk_ids[] __initconst = {
- IMX7ULP_CLK_LPUART6,
- IMX7ULP_CLK_LPUART7,
-};
-
-static struct clk **pcc2_uart_clks[ARRAY_SIZE(pcc2_uart_clk_ids) + 1] __initdata;
-static struct clk **pcc3_uart_clks[ARRAY_SIZE(pcc3_uart_clk_ids) + 1] __initdata;
-
static void __init imx7ulp_clk_scg1_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
@@ -75,7 +68,6 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc");
clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc");
clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc");
- clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll");
clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll");
/* SCG1 */
@@ -148,7 +140,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
- int i;
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END),
GFP_KERNEL);
@@ -187,14 +178,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
imx_check_clk_hws(clks, clk_data->num);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
-
- for (i = 0; i < ARRAY_SIZE(pcc2_uart_clk_ids); i++) {
- int index = pcc2_uart_clk_ids[i];
-
- pcc2_uart_clks[i] = &clks[index]->clk;
- }
-
- imx_register_uart_clocks(pcc2_uart_clks);
}
CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init);
@@ -203,7 +186,6 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
- int i;
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END),
GFP_KERNEL);
@@ -242,13 +224,7 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
- for (i = 0; i < ARRAY_SIZE(pcc3_uart_clk_ids); i++) {
- int index = pcc3_uart_clk_ids[i];
-
- pcc3_uart_clks[i] = &clks[index]->clk;
- }
-
- imx_register_uart_clocks(pcc3_uart_clks);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init);
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index 172589e94f60..f1e4e29a9107 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -12,7 +12,9 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/types.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -357,13 +359,31 @@ static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m",
static struct clk *clks[IMX8MM_CLK_END];
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks[] = {
- &clks[IMX8MM_CLK_UART1_ROOT],
- &clks[IMX8MM_CLK_UART2_ROOT],
- &clks[IMX8MM_CLK_UART3_ROOT],
- &clks[IMX8MM_CLK_UART4_ROOT],
- NULL
-};
+static int __init imx_clk_init_on(struct device_node *np,
+ struct clk * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(array))
+ return PTR_ERR(array);
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ return 0;
+}
static int imx8mm_clocks_probe(struct platform_device *pdev)
{
@@ -372,6 +392,8 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
+ check_m4_enabled();
+
clks[IMX8MM_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX8MM_CLK_24M] = of_clk_get_by_name(np, "osc_24m");
clks[IMX8MM_CLK_32K] = of_clk_get_by_name(np, "osc_32k");
@@ -477,7 +499,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* BUS */
clks[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800);
clks[IMX8MM_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
- clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
clks[IMX8MM_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
clks[IMX8MM_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
clks[IMX8MM_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
@@ -650,7 +672,16 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
goto unregister_clks;
}
- imx_register_uart_clocks(uart_clks);
+ imx_clk_init_on(np, clks);
+
+ clk_set_parent(clks[IMX8MM_CLK_PCIE1_CTRL], clks[IMX8MM_SYS_PLL2_250M]);
+ clk_set_parent(clks[IMX8MM_CLK_PCIE1_PHY], clks[IMX8MM_SYS_PLL2_100M]);
+
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_CORE], clks[IMX8MM_SYS_PLL2_1000M]);
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_PHY_REF], clks[IMX8MM_SYS_PLL2_1000M]);
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_ESC], clks[IMX8MM_SYS_PLL1_800M]);
+
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 58b5acee3830..d5f18731eea7 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -12,7 +12,9 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/types.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -368,13 +370,31 @@ static const char * const imx8mn_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sy
static struct clk *clks[IMX8MN_CLK_END];
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks[] = {
- &clks[IMX8MN_CLK_UART1_ROOT],
- &clks[IMX8MN_CLK_UART2_ROOT],
- &clks[IMX8MN_CLK_UART3_ROOT],
- &clks[IMX8MN_CLK_UART4_ROOT],
- NULL
-};
+static int __init imx_clk_init_on(struct device_node *np,
+ struct clk * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(array))
+ return PTR_ERR(array);
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ return 0;
+}
static int imx8mn_clocks_probe(struct platform_device *pdev)
{
@@ -383,6 +403,8 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
+ check_m4_enabled();
+
clks[IMX8MN_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX8MN_CLK_24M] = of_clk_get_by_name(np, "osc_24m");
clks[IMX8MN_CLK_32K] = of_clk_get_by_name(np, "osc_32k");
@@ -622,7 +644,13 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
goto unregister_clks;
}
- imx_register_uart_clocks(uart_clks);
+ imx_clk_init_on(np, clks);
+
+ clk_set_parent(clks[IMX8MN_CLK_AUDIO_AHB], clks[IMX8MN_SYS_PLL1_800M]);
+ clk_set_rate(clks[IMX8MN_CLK_AUDIO_AHB], 400000000);
+ clk_set_rate(clks[IMX8MN_CLK_IPG_AUDIO_ROOT], 400000000);
+
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 41fc9c63356e..02d863b4b32f 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -12,6 +12,8 @@
#include <linux/of_address.h>
#include <linux/types.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/imx/soc.h>
#include "clk.h"
@@ -26,7 +28,7 @@ static u32 share_count_nand;
static struct clk *clks[IMX8MQ_CLK_END];
-static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "phy_27m", "dummy", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
@@ -38,6 +40,7 @@ static const char * const sys1_pll_out_sels[] = {"sys1_pll1_ref_sel", };
static const char * const sys2_pll_out_sels[] = {"sys1_pll1_ref_sel", "sys2_pll1_ref_sel", };
static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", "sys2_pll1_ref_sel", };
static const char * const dram_pll_out_sels[] = {"dram_pll1_ref_sel", };
+static const char *video2_pll_out_sels[] = {"video2_pll1_ref_sel", };
/* CCM ROOT */
static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
@@ -272,13 +275,31 @@ static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sy
static struct clk_onecell_data clk_data;
-static struct clk ** const uart_clks[] = {
- &clks[IMX8MQ_CLK_UART1_ROOT],
- &clks[IMX8MQ_CLK_UART2_ROOT],
- &clks[IMX8MQ_CLK_UART3_ROOT],
- &clks[IMX8MQ_CLK_UART4_ROOT],
- NULL
-};
+static int __init imx_clk_init_on(struct device_node *np,
+ struct clk * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kzalloc(elems * sizeof(elems), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(array))
+ return PTR_ERR(array);
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ return 0;
+}
static int imx8mq_clocks_probe(struct platform_device *pdev)
{
@@ -287,6 +308,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
void __iomem *base;
int err;
+ check_m4_enabled();
+
clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
clks[IMX8MQ_CLK_25M] = of_clk_get_by_name(np, "osc_25m");
@@ -295,6 +318,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2");
clks[IMX8MQ_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3");
clks[IMX8MQ_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4");
+ clks[IMX8MQ_CLK_PHY_27MHZ] = imx_clk_fixed("phy_27m", 27000000);
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
base = of_iomap(np, 0);
@@ -311,6 +335,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_SYS2_PLL1_REF_SEL] = imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_SYS3_PLL1_REF_SEL] = imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_DRAM_PLL1_REF_SEL] = imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_VIDEO2_PLL1_REF_SEL] = imx_clk_mux("video2_pll1_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_ARM_PLL_REF_DIV] = imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
clks[IMX8MQ_GPU_PLL_REF_DIV] = imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
@@ -334,6 +359,13 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
+ /* unbypass all the plls */
+ clk_set_parent(clks[IMX8MQ_GPU_PLL_BYPASS], clks[IMX8MQ_GPU_PLL]);
+ clk_set_parent(clks[IMX8MQ_VPU_PLL_BYPASS], clks[IMX8MQ_VPU_PLL]);
+ clk_set_parent(clks[IMX8MQ_AUDIO_PLL1_BYPASS], clks[IMX8MQ_AUDIO_PLL1]);
+ clk_set_parent(clks[IMX8MQ_AUDIO_PLL2_BYPASS], clks[IMX8MQ_AUDIO_PLL2]);
+ clk_set_parent(clks[IMX8MQ_VIDEO_PLL1_BYPASS], clks[IMX8MQ_VIDEO_PLL1]);
+
/* PLL OUT GATE */
clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
@@ -346,6 +378,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_sccg_pll("sys2_pll_out", sys2_pll_out_sels, ARRAY_SIZE(sys2_pll_out_sels), 0, 0, 1, base + 0x3c, CLK_IS_CRITICAL);
clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_sccg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 1, base + 0x48, CLK_IS_CRITICAL);
clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_sccg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL);
+ clks[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_sccg_pll("video2_pll_out", video2_pll_out_sels, ARRAY_SIZE(video2_pll_out_sels), 0, 0, 0, base + 0x54, 0);
+
/* SYS PLL fixed output */
clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
@@ -567,7 +601,17 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
goto unregister_clks;
}
- imx_register_uart_clocks(uart_clks);
+ /* enable all the clocks just for bringup */
+ imx_clk_init_on(np, clks);
+
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_CORE], clks[IMX8MQ_SYS1_PLL_266M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_PHY_REF], clks[IMX8MQ_SYS2_PLL_1000M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_ESC], clks[IMX8MQ_SYS1_PLL_800M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_CORE], clks[IMX8MQ_SYS1_PLL_266M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_PHY_REF], clks[IMX8MQ_SYS2_PLL_1000M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_ESC], clks[IMX8MQ_SYS1_PLL_800M]);
+
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8qm-acm.c b/drivers/clk/imx/clk-imx8qm-acm.c
new file mode 100644
index 000000000000..325727efa356
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm-acm.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#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 <linux/pm_domain.h>
+
+#include "clk.h"
+#include "clk-scu.h"
+
+#include <dt-bindings/clock/imx8-clock.h>
+
+struct imx8qm_acm_priv {
+ void __iomem *reg;
+ u32 regs[32];
+};
+
+static const char *aud_clk_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "mlb_clk",
+ "hdmi_rx_mclk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "esai1_rx_clk",
+ "esai1_rx_hf_clk",
+ "esai1_tx_clk",
+ "esai1_tx_hf_clk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+ "sai4_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "mlb_clk",
+ "hdmi_rx_mclk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "sai4_rx_bclk",
+ "sai6_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *asrc_mux_clk_sels[] = {
+ "sai4_rx_bclk",
+ "sai5_tx_bclk",
+ "dummy",
+ "mlb_clk",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static int imx8qm_acm_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_onecell_data *clk_data;
+ struct imx8qm_acm_priv *priv;
+ struct resource *res;
+ struct clk **clks;
+ void __iomem *base;
+ int num_domains;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg = base;
+
+ platform_set_drvdata(pdev, priv);
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = kcalloc(IMX_ADMA_ACM_CLK_END,
+ sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk_data->clk_num = IMX_ADMA_ACM_CLK_END;
+
+ clks = clk_data->clks;
+
+ num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
+ "#power-domain-cells");
+ for (i = 0; i < num_domains; i++) {
+ struct device *pd_dev;
+ struct device_link *link;
+
+ pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(pd_dev))
+ return PTR_ERR(pd_dev);
+
+ link = device_link_add(&pdev->dev, pd_dev,
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(link))
+ return PTR_ERR(link);
+ }
+
+ clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI1_RX_CLK] = imx_clk_fixed("esai1_rx_clk", 0);
+ clks[IMX_ADMA_ESAI1_RX_HF_CLK] = imx_clk_fixed("esai1_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI1_TX_CLK] = imx_clk_fixed("esai1_tx_clk", 0);
+ clks[IMX_ADMA_ESAI1_TX_HF_CLK] = imx_clk_fixed("esai1_tx_hf_clk", 0);
+ clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX_ADMA_SPDIF1_RX] = imx_clk_fixed("spdif1_rx", 0);
+ clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0);
+ clks[IMX_ADMA_SAI5_TX_BCLK] = imx_clk_fixed("sai5_tx_bclk", 0);
+ clks[IMX_ADMA_SAI6_RX_BCLK] = imx_clk_fixed("sai6_rx_bclk", 0);
+ clks[IMX_ADMA_HDMI_RX_MCLK] = imx_clk_fixed("hdmi_rx_mclk", 0);
+ clks[IMX_ADMA_MLB_CLK] = imx_clk_fixed("mlb_clk", 0);
+
+
+ clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_clk_mux("acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+ clks[IMX_ADMA_ACM_AUD_CLK1_CLK] = imx_clk_mux("acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+
+ clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_clk_mux("acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+ clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_clk_mux("acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+
+ clks[IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL] = imx_clk_mux("acm_asrc0_mclk_sel", base+0x040000, 0, 2, asrc_mux_clk_sels, ARRAY_SIZE(asrc_mux_clk_sels));
+
+ clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_clk_mux("acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_ESAI1_MCLK_SEL] = imx_clk_mux("acm_esai1_mclk_sel", base+0x070000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_clk_mux("acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_clk_mux("acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_clk_mux("acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_clk_mux("acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_clk_mux("acm_sai4_mclk_sel", base+0x120000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_clk_mux("acm_sai5_mclk_sel", base+0x130000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI6_MCLK_SEL] = imx_clk_mux("acm_sai6_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI7_MCLK_SEL] = imx_clk_mux("acm_sai7_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+
+ clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux("acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL] = imx_clk_mux("acm_spdif1_mclk_sel", base+0x1B0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_clk_mux("acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels));
+
+ for (i = 0; i < clk_data->clk_num; i++) {
+ if (IS_ERR(clks[i]))
+ pr_warn("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+
+ return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+}
+
+static const struct of_device_id imx8qm_acm_match[] = {
+ { .compatible = "nxp,imx8qm-acm", },
+ { /* sentinel */ }
+};
+
+static int __maybe_unused imx8qm_acm_suspend(struct device *dev)
+{
+ struct imx8qm_acm_priv *priv = dev_get_drvdata(dev);
+
+ priv->regs[0] = readl_relaxed(priv->reg + 0x000000);
+ priv->regs[1] = readl_relaxed(priv->reg + 0x010000);
+ priv->regs[2] = readl_relaxed(priv->reg + 0x020000);
+ priv->regs[3] = readl_relaxed(priv->reg + 0x030000);
+ priv->regs[4] = readl_relaxed(priv->reg + 0x040000);
+ priv->regs[6] = readl_relaxed(priv->reg + 0x060000);
+ priv->regs[7] = readl_relaxed(priv->reg + 0x070000);
+ priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000);
+ priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000);
+ priv->regs[16] = readl_relaxed(priv->reg + 0x100000);
+ priv->regs[17] = readl_relaxed(priv->reg + 0x110000);
+ priv->regs[18] = readl_relaxed(priv->reg + 0x120000);
+ priv->regs[19] = readl_relaxed(priv->reg + 0x130000);
+ priv->regs[20] = readl_relaxed(priv->reg + 0x140000);
+ priv->regs[21] = readl_relaxed(priv->reg + 0x150000);
+ priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000);
+ priv->regs[27] = readl_relaxed(priv->reg + 0x1B0000);
+ priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static int __maybe_unused imx8qm_acm_resume(struct device *dev)
+{
+ struct imx8qm_acm_priv *priv = dev_get_drvdata(dev);
+
+ writel_relaxed(priv->regs[0], priv->reg + 0x000000);
+ writel_relaxed(priv->regs[1], priv->reg + 0x010000);
+ writel_relaxed(priv->regs[2], priv->reg + 0x020000);
+ writel_relaxed(priv->regs[3], priv->reg + 0x030000);
+ writel_relaxed(priv->regs[4], priv->reg + 0x040000);
+ writel_relaxed(priv->regs[6], priv->reg + 0x060000);
+ writel_relaxed(priv->regs[7], priv->reg + 0x070000);
+ writel_relaxed(priv->regs[14], priv->reg + 0x0E0000);
+ writel_relaxed(priv->regs[15], priv->reg + 0x0F0000);
+ writel_relaxed(priv->regs[16], priv->reg + 0x100000);
+ writel_relaxed(priv->regs[17], priv->reg + 0x110000);
+ writel_relaxed(priv->regs[18], priv->reg + 0x120000);
+ writel_relaxed(priv->regs[19], priv->reg + 0x130000);
+ writel_relaxed(priv->regs[20], priv->reg + 0x140000);
+ writel_relaxed(priv->regs[21], priv->reg + 0x150000);
+ writel_relaxed(priv->regs[26], priv->reg + 0x1A0000);
+ writel_relaxed(priv->regs[27], priv->reg + 0x1B0000);
+ writel_relaxed(priv->regs[28], priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx8qm_acm_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx8qm_acm_suspend,
+ imx8qm_acm_resume)
+};
+
+static struct platform_driver imx8qm_acm_clk_driver = {
+ .driver = {
+ .name = "imx8qm-acm",
+ .of_match_table = imx8qm_acm_match,
+ .pm = &imx8qm_acm_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8qm_acm_clk_probe,
+};
+
+static int __init imx8qm_acm_init(void)
+{
+ return platform_driver_register(&imx8qm_acm_clk_driver);
+}
+fs_initcall(imx8qm_acm_init);
diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c
new file mode 100644
index 000000000000..3f683f765e13
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm-rsrc.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+#include "clk-scu.h"
+
+/* Keep sorted in the ascending order */
+static u32 imx8qm_clk_scu_rsrc_table[] = {
+ IMX_SC_R_A53,
+ IMX_SC_R_A72,
+ IMX_SC_R_DC_0_VIDEO0,
+ IMX_SC_R_DC_0_VIDEO1,
+ IMX_SC_R_DC_0,
+ IMX_SC_R_DC_0_PLL_0,
+ IMX_SC_R_DC_0_PLL_1,
+ IMX_SC_R_DC_1_VIDEO0,
+ IMX_SC_R_DC_1_VIDEO1,
+ IMX_SC_R_DC_1,
+ IMX_SC_R_DC_1_PLL_0,
+ IMX_SC_R_DC_1_PLL_1,
+ IMX_SC_R_SPI_0,
+ IMX_SC_R_SPI_1,
+ IMX_SC_R_SPI_2,
+ IMX_SC_R_SPI_3,
+ IMX_SC_R_UART_0,
+ IMX_SC_R_UART_1,
+ IMX_SC_R_UART_2,
+ IMX_SC_R_UART_3,
+ IMX_SC_R_UART_4,
+ IMX_SC_R_EMVSIM_0,
+ IMX_SC_R_EMVSIM_1,
+ IMX_SC_R_I2C_0,
+ IMX_SC_R_I2C_1,
+ IMX_SC_R_I2C_2,
+ IMX_SC_R_I2C_3,
+ IMX_SC_R_I2C_4,
+ IMX_SC_R_ADC_0,
+ IMX_SC_R_ADC_1,
+ IMX_SC_R_FTM_0,
+ IMX_SC_R_FTM_1,
+ IMX_SC_R_CAN_0,
+ IMX_SC_R_CAN_1,
+ IMX_SC_R_CAN_2,
+ IMX_SC_R_GPU_0_PID0,
+ IMX_SC_R_GPU_1_PID0,
+ IMX_SC_R_PWM_0,
+ IMX_SC_R_PWM_1,
+ IMX_SC_R_PWM_2,
+ IMX_SC_R_PWM_3,
+ IMX_SC_R_PWM_4,
+ IMX_SC_R_PWM_5,
+ IMX_SC_R_PWM_6,
+ IMX_SC_R_PWM_7,
+ IMX_SC_R_GPT_0,
+ IMX_SC_R_GPT_1,
+ IMX_SC_R_GPT_2,
+ IMX_SC_R_GPT_3,
+ IMX_SC_R_GPT_4,
+ IMX_SC_R_FSPI_0,
+ IMX_SC_R_FSPI_1,
+ IMX_SC_R_SDHC_0,
+ IMX_SC_R_SDHC_1,
+ IMX_SC_R_SDHC_2,
+ IMX_SC_R_ENET_0,
+ IMX_SC_R_ENET_1,
+ IMX_SC_R_MLB_0,
+ IMX_SC_R_USB_2,
+ IMX_SC_R_NAND,
+ IMX_SC_R_LVDS_0,
+ IMX_SC_R_LVDS_0_PWM_0,
+ IMX_SC_R_LVDS_0_I2C_0,
+ IMX_SC_R_LVDS_0_I2C_1,
+ IMX_SC_R_LVDS_1,
+ IMX_SC_R_LVDS_1_PWM_0,
+ IMX_SC_R_LVDS_1_I2C_0,
+ IMX_SC_R_LVDS_1_I2C_1,
+ IMX_SC_R_M4_0_I2C,
+ IMX_SC_R_M4_1_I2C,
+ IMX_SC_R_AUDIO_PLL_0,
+ IMX_SC_R_VPU_UART,
+ IMX_SC_R_VPUCORE,
+ IMX_SC_R_MIPI_0,
+ IMX_SC_R_MIPI_0_PWM_0,
+ IMX_SC_R_MIPI_0_I2C_0,
+ IMX_SC_R_MIPI_0_I2C_1,
+ IMX_SC_R_MIPI_1,
+ IMX_SC_R_MIPI_1_PWM_0,
+ IMX_SC_R_MIPI_1_I2C_0,
+ IMX_SC_R_MIPI_1_I2C_1,
+ IMX_SC_R_CSI_0,
+ IMX_SC_R_CSI_0_PWM_0,
+ IMX_SC_R_CSI_0_I2C_0,
+ IMX_SC_R_CSI_1,
+ IMX_SC_R_CSI_1_PWM_0,
+ IMX_SC_R_CSI_1_I2C_0,
+ IMX_SC_R_HDMI,
+ IMX_SC_R_HDMI_I2S,
+ IMX_SC_R_HDMI_I2C_0,
+ IMX_SC_R_HDMI_PLL_0,
+ IMX_SC_R_HDMI_RX,
+ IMX_SC_R_HDMI_RX_BYPASS,
+ IMX_SC_R_HDMI_RX_I2C_0,
+ IMX_SC_R_AUDIO_PLL_1,
+ IMX_SC_R_AUDIO_CLK_0,
+ IMX_SC_R_AUDIO_CLK_1,
+ IMX_SC_R_HDMI_RX_PWM_0,
+ IMX_SC_R_HDMI_PLL_1,
+ IMX_SC_R_VPU,
+};
+
+const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm = {
+ .rsrc = imx8qm_clk_scu_rsrc_table,
+ .num = ARRAY_SIZE(imx8qm_clk_scu_rsrc_table),
+};
diff --git a/drivers/clk/imx/clk-imx8qxp-acm.c b/drivers/clk/imx/clk-imx8qxp-acm.c
new file mode 100644
index 000000000000..187c86067e50
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp-acm.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#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 <linux/pm_domain.h>
+
+#include "clk.h"
+#include "clk-scu.h"
+
+#include <dt-bindings/clock/imx8-clock.h>
+
+struct imx8qxp_acm_priv {
+ void __iomem *reg;
+ u32 regs[0x20];
+};
+
+static const char *aud_clk_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "spdif0_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_rec_clk0_lpcg_clk",
+ "aud_rec_clk1_lpcg_clk",
+ "dummy",
+ "dummy",
+ "spdif0_rx",
+ "dummy",
+ "dummy",
+ "sai4_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_pll_div_clk0_lpcg_clk",
+ "aud_pll_div_clk1_lpcg_clk",
+ "acm_aud_clk0_sel",
+ "acm_aud_clk1_sel",
+};
+
+static int imx8qxp_acm_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_onecell_data *clk_data;
+ struct imx8qxp_acm_priv *priv;
+ struct resource *res;
+ struct clk **clks;
+ void __iomem *base;
+ int num_domains;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg = base;
+
+ platform_set_drvdata(pdev, priv);
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = kcalloc(IMX_ADMA_ACM_CLK_END,
+ sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk_data->clk_num = IMX_ADMA_ACM_CLK_END;
+
+ clks = clk_data->clks;
+
+ num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
+ "#power-domain-cells");
+ for (i = 0; i < num_domains; i++) {
+ struct device *pd_dev;
+ struct device_link *link;
+
+ pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(pd_dev))
+ return PTR_ERR(pd_dev);
+
+ link = device_link_add(&pdev->dev, pd_dev,
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(link))
+ return PTR_ERR(link);
+ }
+
+ clks[IMX_ADMA_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX_ADMA_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX_ADMA_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX_ADMA_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX_ADMA_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX_ADMA_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX_ADMA_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX_ADMA_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX_ADMA_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX_ADMA_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX_ADMA_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX_ADMA_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX_ADMA_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0);
+
+
+ clks[IMX_ADMA_ACM_AUD_CLK0_SEL] = imx_clk_mux("acm_aud_clk0_sel", base+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+ clks[IMX_ADMA_ACM_AUD_CLK1_CLK] = imx_clk_mux("acm_aud_clk1_sel", base+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels));
+
+ clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_clk_mux("acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+ clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_clk_mux("acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels));
+
+ clks[IMX_ADMA_ACM_ESAI0_MCLK_SEL] = imx_clk_mux("acm_esai0_mclk_sel", base+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_clk_mux("acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_clk_mux("acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_clk_mux("acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI3_MCLK_SEL] = imx_clk_mux("acm_sai3_mclk_sel", base+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI4_MCLK_SEL] = imx_clk_mux("acm_sai4_mclk_sel", base+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+ clks[IMX_ADMA_ACM_SAI5_MCLK_SEL] = imx_clk_mux("acm_sai5_mclk_sel", base+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels));
+
+ clks[IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux("acm_spdif0_mclk_sel", base+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels));
+ clks[IMX_ADMA_ACM_MQS_TX_CLK_SEL] = imx_clk_mux("acm_mqs_mclk_sel", base+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels));
+
+ for (i = 0; i < clk_data->clk_num; i++) {
+ if (IS_ERR(clks[i]))
+ pr_warn("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+
+ return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+}
+
+static const struct of_device_id imx8qxp_acm_match[] = {
+ { .compatible = "nxp,imx8qxp-acm", },
+ { /* sentinel */ }
+};
+
+static int __maybe_unused imx8qxp_acm_suspend(struct device *dev)
+{
+ struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev);
+
+ priv->regs[0] = readl_relaxed(priv->reg + 0x000000);
+ priv->regs[1] = readl_relaxed(priv->reg + 0x010000);
+ priv->regs[2] = readl_relaxed(priv->reg + 0x020000);
+ priv->regs[3] = readl_relaxed(priv->reg + 0x030000);
+ priv->regs[6] = readl_relaxed(priv->reg + 0x060000);
+ priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000);
+ priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000);
+ priv->regs[16] = readl_relaxed(priv->reg + 0x100000);
+ priv->regs[17] = readl_relaxed(priv->reg + 0x110000);
+ priv->regs[20] = readl_relaxed(priv->reg + 0x140000);
+ priv->regs[21] = readl_relaxed(priv->reg + 0x150000);
+ priv->regs[26] = readl_relaxed(priv->reg + 0x1A0000);
+ priv->regs[28] = readl_relaxed(priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+static int __maybe_unused imx8qxp_acm_resume(struct device *dev)
+{
+ struct imx8qxp_acm_priv *priv = dev_get_drvdata(dev);
+
+ writel_relaxed(priv->regs[0], priv->reg + 0x000000);
+ writel_relaxed(priv->regs[1], priv->reg + 0x010000);
+ writel_relaxed(priv->regs[2], priv->reg + 0x020000);
+ writel_relaxed(priv->regs[3], priv->reg + 0x030000);
+ writel_relaxed(priv->regs[6], priv->reg + 0x060000);
+ writel_relaxed(priv->regs[14], priv->reg + 0x0E0000);
+ writel_relaxed(priv->regs[15], priv->reg + 0x0F0000);
+ writel_relaxed(priv->regs[16], priv->reg + 0x100000);
+ writel_relaxed(priv->regs[17], priv->reg + 0x110000);
+ writel_relaxed(priv->regs[20], priv->reg + 0x140000);
+ writel_relaxed(priv->regs[21], priv->reg + 0x150000);
+ writel_relaxed(priv->regs[26], priv->reg + 0x1A0000);
+ writel_relaxed(priv->regs[28], priv->reg + 0x1C0000);
+
+ return 0;
+}
+
+const struct dev_pm_ops imx8qxp_acm_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx8qxp_acm_suspend,
+ imx8qxp_acm_resume)
+};
+
+static struct platform_driver imx8qxp_acm_clk_driver = {
+ .driver = {
+ .name = "imx8qxp-acm",
+ .of_match_table = imx8qxp_acm_match,
+ .pm = &imx8qxp_acm_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8qxp_acm_clk_probe,
+};
+
+static int __init imx8qxp_acm_init(void)
+{
+ return platform_driver_register(&imx8qxp_acm_clk_driver);
+}
+fs_initcall(imx8qxp_acm_init);
diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c
index c0aff7ca6374..741b73e4c609 100644
--- a/drivers/clk/imx/clk-imx8qxp-lpcg.c
+++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c
@@ -9,205 +9,106 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include "clk-scu.h"
-#include "clk-imx8qxp-lpcg.h"
-#include <dt-bindings/clock/imx8-clock.h>
-
-/*
- * struct imx8qxp_lpcg_data - Description of one LPCG clock
- * @id: clock ID
- * @name: clock name
- * @parent: parent clock name
- * @flags: common clock flags
- * @offset: offset of this LPCG clock
- * @bit_idx: bit index of this LPCG clock
- * @hw_gate: whether supports HW autogate
- *
- * This structure describes one LPCG clock
- */
-struct imx8qxp_lpcg_data {
- int id;
- char *name;
- char *parent;
- unsigned long flags;
- u32 offset;
- u8 bit_idx;
- bool hw_gate;
-};
-
-/*
- * struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks
- * @lpcg: LPCG clocks array of one subsystem
- * @num_lpcg: the number of LPCG clocks
- * @num_max: the maximum number of LPCG clocks
- *
- * This structure describes each subsystem LPCG clocks information
- * which then will be used to create respective LPCGs clocks
- */
-struct imx8qxp_ss_lpcg {
- const struct imx8qxp_lpcg_data *lpcg;
- u8 num_lpcg;
- u8 num_max;
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
- { IMX_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, },
- { IMX_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, },
-
- { IMX_ADMA_LPCG_DSP_CORE_CLK, "dsp_lpcg_core_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 28, 0, },
- { IMX_ADMA_LPCG_DSP_IPG_CLK, "dsp_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 20, 0, },
- { IMX_ADMA_LPCG_DSP_ADB_CLK, "dsp_lpcg_adb_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 16, 0, },
- { IMX_ADMA_LPCG_OCRAM_IPG_CLK, "ocram_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_OCRAM_LPCG, 16, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = {
- .lpcg = imx8qxp_lpcg_adma,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma),
- .num_max = IMX_ADMA_LPCG_CLK_END,
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = {
- { IMX_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, },
- { IMX_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, },
- { IMX_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, },
- { IMX_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, },
- { IMX_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, },
- { IMX_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, },
- { IMX_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, },
- { IMX_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, },
- { IMX_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, },
- { IMX_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, },
- { IMX_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, },
- { IMX_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, },
- { IMX_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = {
- .lpcg = imx8qxp_lpcg_conn,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn),
- .num_max = IMX_CONN_LPCG_CLK_END,
-};
-
-static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = {
- { IMX_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, },
- { IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, },
-};
-
-static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
- .lpcg = imx8qxp_lpcg_lsio,
- .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio),
- .num_max = IMX_LSIO_LPCG_CLK_END,
-};
+#define IMX_LPCG_MAX_CLKS 8
static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ struct device_node *np = pdev->dev.of_node;
+ const char *output_names[IMX_LPCG_MAX_CLKS];
+ const char *parent_names[IMX_LPCG_MAX_CLKS];
+ unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
struct clk_hw_onecell_data *clk_data;
- const struct imx8qxp_ss_lpcg *ss_lpcg;
- const struct imx8qxp_lpcg_data *lpcg;
+ struct clk_hw **clk_hws;
struct resource *res;
- struct clk_hw **clks;
void __iomem *base;
+ bool autogate;
+ int count;
+ int ret;
int i;
- ss_lpcg = of_device_get_match_data(dev);
- if (!ss_lpcg)
- return -ENODEV;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ count = of_property_count_u32_elems(np, "bit-offset");
+ if (count < 0) {
+ dev_err(&pdev->dev, "failed to count clocks\n");
return -EINVAL;
- base = devm_ioremap(dev, res->start, resource_size(res));
- if (!base)
- return -ENOMEM;
+ }
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
- ss_lpcg->num_max), GFP_KERNEL);
+ clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, count),
+ GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
- clk_data->num = ss_lpcg->num_max;
- clks = clk_data->hws;
+ clk_data->num = count;
+ clk_hws = 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,
- lpcg->flags, base + lpcg->offset,
- lpcg->bit_idx, lpcg->hw_gate);
+ ret = of_property_read_u32_array(np, "bit-offset", bit_offset,
+ clk_data->num);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read clocks bit-offset\n");
+ return -EINVAL;
}
+ ret = of_clk_parent_fill(np, parent_names, clk_data->num);
+ if (ret != clk_data->num) {
+ dev_err(&pdev->dev, "failed to get clock parent names\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_string_array(np, "clock-output-names",
+ output_names, clk_data->num);
+ if (ret != clk_data->num) {
+ dev_err(&pdev->dev, "failed to read clock-output-names\n");
+ return -EINVAL;
+ }
+
+ autogate = of_property_read_bool(np, "hw-autogate");
+
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
for (i = 0; i < clk_data->num; i++) {
- if (IS_ERR(clks[i]))
- pr_warn("i.MX clk %u: register failed with %ld\n",
- i, PTR_ERR(clks[i]));
+ if (bit_offset[i] > 31) {
+ dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
+ i);
+ return -EINVAL;
+ }
+
+ clk_hws[i] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
+ parent_names[i], 0, base,
+ bit_offset[i], autogate);
+ if (IS_ERR(clk_hws[i])) {
+ dev_warn(&pdev->dev, "failed to register clock %d\n",
+ i);
+ return -EINVAL;
+ }
}
- return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
+ clk_data);
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ return ret;
}
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, },
+ { .compatible = "fsl,imx8qxp-lpcg", NULL },
{ /* sentinel */ }
};
@@ -215,6 +116,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
.driver = {
.name = "imx8qxp-lpcg-clk",
.of_match_table = imx8qxp_lpcg_match,
+ .pm = &imx_clk_lpcg_scu_pm_ops,
.suppress_bind_attrs = true,
},
.probe = imx8qxp_lpcg_clk_probe,
diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.h b/drivers/clk/imx/clk-imx8qxp-lpcg.h
index 2a37ce57c500..d435cd5c5713 100644
--- a/drivers/clk/imx/clk-imx8qxp-lpcg.h
+++ b/drivers/clk/imx/clk-imx8qxp-lpcg.h
@@ -99,4 +99,49 @@
#define ADMA_FLEXCAN_1_LPCG 0x1ce0000
#define ADMA_FLEXCAN_2_LPCG 0x1cf0000
+/* CM40 SS */
+#define CM40_I2C_LPCG 0x60000
+
+/* HSIO SS */
+#define HSIO_PCIEA_LPCG 0x00000
+#define HSIO_PCIEB_LPCG 0x10000
+#define HSIO_SATA0_LPCG 0x20000
+#define HSIO_PHYX2_LPCG 0x30000
+#define HSIO_PHYX1_LPCG 0x40000
+#define HSIO_CRR_0_LPCG 0x50000
+#define HSIO_CRR_1_LPCG 0x60000
+#define HSIO_CRR_2_LPCG 0x70000
+#define HSIO_CRR_3_LPCG 0x80000
+#define HSIO_CRR_4_LPCG 0x90000
+#define HSIO_CRR_5_LPCG 0xa0000
+#define HSIO_GPIO_LPCG 0xb0000
+
+/* IMG SS */
+#define IMG_PDMA0_LPCG 0x00000
+#define IMG_PDMA1_LPCG 0x10000
+#define IMG_PDMA2_LPCG 0x20000
+#define IMG_PDMA3_LPCG 0x30000
+#define IMG_PDMA4_LPCG 0x40000
+#define IMG_PDMA5_LPCG 0x50000
+#define IMG_PDMA6_LPCG 0x60000
+#define IMG_PDMA7_LPCG 0x70000
+#define IMG_MIPI_CSI0_LPCG 0x80000
+#define IMG_MIPI_CSI1_LPCG 0x90000
+
+/* CSI SS */
+#define CSI_CSI0_CORE_LPCG 0x18
+#define CSI_CSI0_ESC_LPCG 0x1C
+#define CSI_CSI0_I2C0_LPCG 0x14
+#define CSI_CSI1_CORE_LPCG 0x18
+#define CSI_CSI1_ESC_LPCG 0x1C
+#define CSI_CSI1_I2C0_LPCG 0x14
+
+/* Parallel Interface SS */
+#define PI_PI0_PIXEL_LPCG 0x18
+#define PI_PI0_IPG_LPCG 0x04
+#define PI_PI0_MISC_LPCG 0x1C
+
+/* DC0 SS */
+/* TODO: ADD DC LPCGs */
+
#endif /* _IMX8QXP_LPCG_H */
diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c
new file mode 100644
index 000000000000..e2295b8b99c8
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+#include "clk-scu.h"
+
+/* Keep sorted in the ascending order */
+static u32 imx8qxp_clk_scu_rsrc_table[] = {
+ IMX_SC_R_DC_0_VIDEO0,
+ IMX_SC_R_DC_0_VIDEO1,
+ IMX_SC_R_DC_0,
+ IMX_SC_R_DC_0_PLL_0,
+ IMX_SC_R_DC_0_PLL_1,
+ IMX_SC_R_SPI_0,
+ IMX_SC_R_SPI_1,
+ IMX_SC_R_SPI_2,
+ IMX_SC_R_SPI_3,
+ IMX_SC_R_UART_0,
+ IMX_SC_R_UART_1,
+ IMX_SC_R_UART_2,
+ IMX_SC_R_UART_3,
+ IMX_SC_R_I2C_0,
+ IMX_SC_R_I2C_1,
+ IMX_SC_R_I2C_2,
+ IMX_SC_R_I2C_3,
+ IMX_SC_R_ADC_0,
+ IMX_SC_R_FTM_0,
+ IMX_SC_R_FTM_1,
+ IMX_SC_R_CAN_0,
+ IMX_SC_R_GPU_0_PID0,
+ IMX_SC_R_LCD_0,
+ IMX_SC_R_LCD_0_PWM_0,
+ IMX_SC_R_PWM_0,
+ IMX_SC_R_PWM_1,
+ IMX_SC_R_PWM_2,
+ IMX_SC_R_PWM_3,
+ IMX_SC_R_PWM_4,
+ IMX_SC_R_PWM_5,
+ IMX_SC_R_PWM_6,
+ IMX_SC_R_PWM_7,
+ IMX_SC_R_GPT_0,
+ IMX_SC_R_GPT_1,
+ IMX_SC_R_GPT_2,
+ IMX_SC_R_GPT_3,
+ IMX_SC_R_GPT_4,
+ IMX_SC_R_FSPI_0,
+ IMX_SC_R_FSPI_1,
+ IMX_SC_R_SDHC_0,
+ IMX_SC_R_SDHC_1,
+ IMX_SC_R_SDHC_2,
+ IMX_SC_R_ENET_0,
+ IMX_SC_R_ENET_1,
+ IMX_SC_R_MLB_0,
+ IMX_SC_R_USB_2,
+ IMX_SC_R_NAND,
+ IMX_SC_R_LVDS_0,
+ IMX_SC_R_LVDS_1,
+ IMX_SC_R_M4_0_I2C,
+ IMX_SC_R_ELCDIF_PLL,
+ IMX_SC_R_AUDIO_PLL_0,
+ IMX_SC_R_PI_0,
+ IMX_SC_R_PI_0_PLL,
+ IMX_SC_R_MIPI_0,
+ IMX_SC_R_MIPI_0_PWM_0,
+ IMX_SC_R_MIPI_0_I2C_0,
+ IMX_SC_R_MIPI_0_I2C_1,
+ IMX_SC_R_MIPI_1,
+ IMX_SC_R_MIPI_1_PWM_0,
+ IMX_SC_R_MIPI_1_I2C_0,
+ IMX_SC_R_MIPI_1_I2C_1,
+ IMX_SC_R_CSI_0,
+ IMX_SC_R_CSI_0_PWM_0,
+ IMX_SC_R_CSI_0_I2C_0,
+ IMX_SC_R_AUDIO_PLL_1,
+ IMX_SC_R_AUDIO_CLK_0,
+ IMX_SC_R_AUDIO_CLK_1,
+ IMX_SC_R_A35,
+ IMX_SC_R_VPU_DEC_0,
+ IMX_SC_R_VPU_ENC_0,
+};
+
+const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp = {
+ .rsrc = imx8qxp_clk_scu_rsrc_table,
+ .num = ARRAY_SIZE(imx8qxp_clk_scu_rsrc_table),
+};
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index 5e2903efc488..57ad5c07476d 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -9,139 +9,244 @@
#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 <dt-bindings/firmware/imx/rsrc.h>
+
#include "clk-scu.h"
-#include <dt-bindings/clock/imx8-clock.h>
-#include <dt-bindings/firmware/imx/rsrc.h>
+static const char *sdhc0_sels[] = {
+ "dummy",
+ "conn_pll0_clk",
+ "conn_pll1_clk",
+ "dummy",
+ "dummy",
+};
+
+static const char *pll0_sels[] = {
+ "dummy",
+ "pi_dpll_clk",
+ "dummy",
+ "dummy",
+ "dummy",
+};
+
+static const char *enet0_rgmii_txc_sels[] = {
+ "enet0_ref_div",
+ "dummy",
+};
+
+static const char *enet1_rgmii_txc_sels[] = {
+ "enet1_ref_div",
+ "dummy",
+};
+
+static const char *dc0_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "dc0_pll0_clk",
+ "dc0_pll1_clk",
+ "dc0_bypass0_clk",
+};
+
+static const char *dc1_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "dc1_pll0_clk",
+ "dc1_pll1_clk",
+ "dc1_bypass0_clk",
+};
+
+static const char *hdmi_sels[] = {
+ "dummy",
+ "hdmi_dig_pll_clk",
+ "dummy",
+ "dummy",
+ "hdmi_av_pll_clk",
+};
+
+static const struct of_device_id imx8qxp_match[] = {
+ { .compatible = "fsl,scu-clk", },
+ { .compatible = "fsl,imx8qxp-clk", &imx_clk_scu_rsrc_imx8qxp, },
+ { .compatible = "fsl,imx8qm-clk", &imx_clk_scu_rsrc_imx8qm, },
+ { /* sentinel */ }
+};
static int imx8qxp_clk_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(imx8qxp_match, &pdev->dev);
struct device_node *ccm_node = pdev->dev.of_node;
- struct clk_hw_onecell_data *clk_data;
- struct clk_hw **clks;
- int ret, i;
+ int ret;
- ret = imx_clk_scu_init();
+ ret = imx_clk_scu_init(ccm_node, of_id->data);
if (ret)
return ret;
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
- IMX_SCU_CLK_END), GFP_KERNEL);
- if (!clk_data)
- return -ENOMEM;
-
- clk_data->num = IMX_SCU_CLK_END;
- clks = clk_data->hws;
-
- /* Fixed clocks */
- clks[IMX_CLK_DUMMY] = clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
- clks[IMX_ADMA_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "dma_ipg_clk_root", NULL, 0, 120000000);
- clks[IMX_CONN_AXI_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_axi_clk_root", NULL, 0, 333333333);
- clks[IMX_CONN_AHB_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ahb_clk_root", NULL, 0, 166666666);
- clks[IMX_CONN_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ipg_clk_root", NULL, 0, 83333333);
- clks[IMX_DC_AXI_EXT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_ext_clk_root", NULL, 0, 800000000);
- clks[IMX_DC_AXI_INT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_int_clk_root", NULL, 0, 400000000);
- clks[IMX_DC_CFG_CLK] = clk_hw_register_fixed_rate(NULL, "dc_cfg_clk_root", NULL, 0, 100000000);
- clks[IMX_MIPI_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "mipi_ipg_clk_root", NULL, 0, 120000000);
- clks[IMX_IMG_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "img_axi_clk_root", NULL, 0, 400000000);
- clks[IMX_IMG_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "img_ipg_clk_root", NULL, 0, 200000000);
- clks[IMX_IMG_PXL_CLK] = clk_hw_register_fixed_rate(NULL, "img_pxl_clk_root", NULL, 0, 600000000);
- clks[IMX_HSIO_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_axi_clk_root", NULL, 0, 400000000);
- clks[IMX_HSIO_PER_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_per_clk_root", NULL, 0, 133333333);
- clks[IMX_LSIO_MEM_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_mem_clk_root", NULL, 0, 200000000);
- clks[IMX_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
-
/* ARM core */
- clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+ imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+ imx_clk_scu("a53_clk", IMX_SC_R_A53, IMX_SC_PM_CLK_CPU);
+ imx_clk_scu("a72_clk", IMX_SC_R_A72, IMX_SC_PM_CLK_CPU);
/* LSIO SS */
- clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
- clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
-
- /* ADMA SS */
- clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
- clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
+
+ /* DMA SS */
+ imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart4_clk", IMX_SC_R_UART_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sim0_clk", IMX_SC_R_EMVSIM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can1_clk", IMX_SC_R_CAN_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can2_clk", IMX_SC_R_CAN_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+
+ /* Audio SS */
+ imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("audio_pll1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("audio_pll_div_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("audio_pll_div_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("audio_rec_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("audio_rec_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC1);
/* Connectivity */
- clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
- clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
- clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
- clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
- clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
- clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
- clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
- clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu2("sdhc0_clk", sdhc0_sels, ARRAY_SIZE(sdhc0_sels), IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
+ imx_clk_divider_gpr_scu("enet0_ref_div", "enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_C_CLKDIV);
+ imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK);
+ imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true);
+ imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
+ imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV);
+ imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK);
+ imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true);
+ imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
/* Display controller SS */
- clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
- clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS);
+
+ imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("dc1_pll0_clk", IMX_SC_R_DC_1_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc1_pll1_clk", IMX_SC_R_DC_1_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc1_bypass0_clk", IMX_SC_R_DC_1_VIDEO0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("dc1_bypass1_clk", IMX_SC_R_DC_1_VIDEO1, IMX_SC_PM_CLK_BYPASS);
/* MIPI-LVDS SS */
- clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
- clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds0_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("lvds0_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("lvds0_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu("mipi0_dsi_tx_esc_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("mipi0_dsi_rx_esc_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS);
+ imx_clk_scu("mipi0_dsi_phy_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY);
+ imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_pwm_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds1_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("lvds1_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("lvds1_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu("mipi1_dsi_tx_esc_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("mipi1_dsi_rx_esc_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS);
+ imx_clk_scu("mipi1_dsi_phy_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PHY);
+ imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi1_pwm_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("lvds0_i2c0_clk", IMX_SC_R_LVDS_0_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds0_pwm0_clk", IMX_SC_R_LVDS_0_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("lvds1_i2c0_clk", IMX_SC_R_LVDS_1_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds1_pwm0_clk", IMX_SC_R_LVDS_1_PWM_0, IMX_SC_PM_CLK_PER);
/* MIPI CSI SS */
- clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
- clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
- clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
- clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_core_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_esc_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu("mipi_csi1_i2c0_clk", IMX_SC_R_CSI_1_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_pwm0_clk", IMX_SC_R_CSI_1_PWM_0, IMX_SC_PM_CLK_PER);
+
+ /* Parallel Interface SS */
+ imx_clk_scu("pi_dpll_clk", IMX_SC_R_PI_0_PLL, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu2("pi_per_div_clk", pll0_sels, ARRAY_SIZE(pll0_sels), IMX_SC_R_PI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pi_mclk_div_clk", IMX_SC_R_PI_0, IMX_SC_PM_CLK_MISC0);
/* GPU SS */
- clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
- clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
- for (i = 0; i < clk_data->num; i++) {
- if (IS_ERR(clks[i]))
- pr_warn("i.MX clk %u: register failed with %ld\n",
- i, PTR_ERR(clks[i]));
- }
+ imx_clk_scu("gpu_core1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpu_shader1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_MISC);
+ /* CM40 SS */
+ imx_clk_scu("cm40_i2c_div", IMX_SC_R_M4_0_I2C, IMX_SC_PM_CLK_PER);
- return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
-}
+ /* CM41 SS */
+ imx_clk_scu("cm41_i2c_div", IMX_SC_R_M4_1_I2C, IMX_SC_PM_CLK_PER);
-static const struct of_device_id imx8qxp_match[] = {
- { .compatible = "fsl,scu-clk", },
- { .compatible = "fsl,imx8qxp-clk", },
- { /* sentinel */ }
-};
+ /* HDMI TX SS */
+ imx_clk_scu("hdmi_dig_pll_clk", IMX_SC_R_HDMI_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("hdmi_av_pll_clk", IMX_SC_R_HDMI_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu2("hdmi_pixel_mux_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("hdmi_pixel_link_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("hdmi_ipg_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC4);
+ imx_clk_scu("hdmi_i2c0_clk", IMX_SC_R_HDMI_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("hdmi_hdp_core_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu2("hdmi_pxl_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu("hdmi_i2s_bypass_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("hdmi_i2s_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_MISC0);
+
+ return of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
+}
static struct platform_driver imx8qxp_clk_driver = {
.driver = {
@@ -151,4 +256,8 @@ static struct platform_driver imx8qxp_clk_driver = {
},
.probe = imx8qxp_clk_probe,
};
-builtin_platform_driver(imx8qxp_clk_driver);
+static int __init imx8qxp_clk_driver_init(void)
+{
+ return platform_driver_register(&imx8qxp_clk_driver);
+}
+subsys_initcall_sync(imx8qxp_clk_driver_init);
diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c
index a73a799fb777..56b055e35db5 100644
--- a/drivers/clk/imx/clk-lpcg-scu.c
+++ b/drivers/clk/imx/clk-lpcg-scu.c
@@ -33,6 +33,9 @@ struct clk_lpcg_scu {
void __iomem *reg;
u8 bit_idx;
bool hw_gate;
+
+ /* for state save&restore */
+ u32 state;
};
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
@@ -80,9 +83,9 @@ static const struct clk_ops clk_lpcg_scu_ops = {
.disable = clk_lpcg_scu_disable,
};
-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)
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx, bool hw_gate)
{
struct clk_lpcg_scu *clk;
struct clk_init_data init;
@@ -106,11 +109,47 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
clk->hw.init = &init;
hw = &clk->hw;
- ret = clk_hw_register(NULL, hw);
+ ret = clk_hw_register(dev, hw);
if (ret) {
kfree(clk);
hw = ERR_PTR(ret);
}
+ if (dev)
+ dev_set_drvdata(dev, clk);
+
return hw;
}
+
+int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
+{
+ struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+ if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
+ return 0;
+
+ clk->state = readl_relaxed(clk->reg);
+ dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
+
+ return 0;
+}
+
+int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
+{
+ struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+ if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
+ return 0;
+
+ /* FIXME: double write in case a failure */
+ writel(clk->state, clk->reg);
+ writel(clk->state, clk->reg);
+ dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
+
+ return 0;
+}
+
+const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
+ imx_clk_lpcg_scu_resume)
+};
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 50b7c30296f7..fc2e0fe03bdd 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -5,9 +5,11 @@
*/
#include <linux/clk-provider.h>
+#include <linux/imx_sema4.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
/**
@@ -32,20 +34,57 @@ struct clk_pfd {
#define CLR 0x8
#define OTG 0xc
-static int clk_pfd_enable(struct clk_hw *hw)
+static void clk_pfd_do_hardware(struct clk_pfd *pfd, bool enable)
+{
+ if (enable)
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ else
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+}
+
+static void clk_pfd_do_shared_clks(struct clk_hw *hw, bool enable)
{
struct clk_pfd *pfd = to_clk_pfd(hw);
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pfd_do_hardware(pfd, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_pfd_do_hardware(pfd, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pfd_do_hardware(pfd, enable);
+ }
+}
+
+static int clk_pfd_enable(struct clk_hw *hw)
+{
+ clk_pfd_do_shared_clks(hw, true);
return 0;
}
static void clk_pfd_disable(struct clk_hw *hw)
{
- struct clk_pfd *pfd = to_clk_pfd(hw);
-
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+ clk_pfd_do_shared_clks(hw, false);
}
static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c
index a03bbed662c6..2a46b9b61b46 100644
--- a/drivers/clk/imx/clk-pfdv2.c
+++ b/drivers/clk/imx/clk-pfdv2.c
@@ -139,6 +139,12 @@ static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
u32 val;
u8 frac;
+ if (!rate)
+ return -EINVAL;
+
+ /* PFD can NOT change rate without gating */
+ WARN_ON(clk_pfdv2_is_enabled(hw));
+
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 7a815ec76aa5..5660865baae0 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -92,9 +92,12 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+ const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
short int kdiv;
u64 fvco = parent_rate;
+ long rate = 0;
+ int i;
pll_div_ctl0 = readl_relaxed(pll->base + 4);
pll_div_ctl1 = readl_relaxed(pll->base + 8);
@@ -103,13 +106,25 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
kdiv = pll_div_ctl1 & KDIV_MASK;
+ /*
+ * Sometimes, the recalculated rate has deviation due to
+ * the frac part. So find the accurate pll rate from the table
+ * first, if no match rate in the table, use the rate calculated
+ * from the equation below.
+ */
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate_table[i].pdiv == pdiv && rate_table[i].mdiv == mdiv &&
+ rate_table[i].sdiv == sdiv && rate_table[i].kdiv == kdiv)
+ rate = rate_table[i].rate;
+ }
+
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
fvco *= (mdiv * 65536 + kdiv);
pdiv *= 65536;
do_div(fvco, pdiv << sdiv);
- return fvco;
+ return rate ? (unsigned long) rate : (unsigned long)fvco;
}
static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index df91a8244fb4..24684853c8b4 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -7,9 +7,11 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/imx_sema4.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
#define PLL_NUM_OFFSET 0x10
@@ -72,32 +74,74 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
}
-static int clk_pllv3_prepare(struct clk_hw *hw)
+static int clk_pllv3_do_hardware(struct clk_hw *hw, bool enable)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
+ int ret;
u32 val;
val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val |= pll->power_bit;
- else
- val &= ~pll->power_bit;
- writel_relaxed(val, pll->base);
+ if (enable) {
+ if (pll->powerup_set)
+ val |= pll->power_bit;
+ else
+ val &= ~pll->power_bit;
+ writel_relaxed(val, pll->base);
+
+ ret = clk_pllv3_wait_lock(pll);
+ if (ret)
+ return ret;
+ } else {
+ if (pll->powerup_set)
+ val &= ~pll->power_bit;
+ else
+ val |= pll->power_bit;
+ writel_relaxed(val, pll->base);
+ }
- return clk_pllv3_wait_lock(pll);
+ return 0;
}
-static void clk_pllv3_unprepare(struct clk_hw *hw)
+static void clk_pllv3_do_shared_clks(struct clk_hw *hw, bool enable)
{
- struct clk_pllv3 *pll = to_clk_pllv3(hw);
- u32 val;
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pllv3_do_hardware(hw, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+ clk_pllv3_do_hardware(hw, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pllv3_do_hardware(hw, enable);
+ }
+}
- val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val &= ~pll->power_bit;
- else
- val |= pll->power_bit;
- writel_relaxed(val, pll->base);
+static int clk_pllv3_prepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, true);
+
+ return 0;
+}
+
+static void clk_pllv3_unprepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, false);
}
static int clk_pllv3_is_prepared(struct clk_hw *hw)
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index fbef740704d0..3334909a5f88 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -6,16 +6,42 @@
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
+#include <linux/bsearch.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/firmware/imx/svc/rm.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <xen/xen.h>
#include "clk-scu.h"
#define IMX_SIP_CPUFREQ 0xC2000001
#define IMX_SIP_SET_CPUFREQ 0x00
+#define MAX_CLUSTER_NUM 2
static struct imx_sc_ipc *ccm_ipc_handle;
+static const struct imx_clk_scu_rsrc_table *rsrc_table;
+static struct delayed_work cpufreq_governor_daemon;
+struct device_node *pd_np;
+u32 clock_cells;
+
+struct imx_scu_clk_node {
+ const char *name;
+ u32 rsrc;
+ u8 clk_type;
+ const char * const *parents;
+ int num_parents;
+
+ struct clk_hw *hw;
+ struct list_head node;
+};
+
+struct list_head imx_scu_clks[IMX_SC_R_LAST];
/*
* struct clk_scu - Description of one SCU clock
@@ -27,6 +53,26 @@ struct clk_scu {
struct clk_hw hw;
u16 rsrc_id;
u8 clk_type;
+
+ /* for state save&restore */
+ struct clk_hw *parent;
+ u8 parent_index;
+ bool is_enabled;
+ u32 rate;
+};
+
+/*
+ * struct clk_gpr_scu - Description of one gate SCU clock
+ * @hw: the common clk_hw
+ * @rsrc_id: resource ID of this SCU clock
+ * @gpr_id: GPR ID index to control the divider
+ */
+struct clk_gpr_scu {
+ struct clk_hw hw;
+ u16 rsrc_id;
+ u8 gpr_id;
+ u8 flags;
+ bool gate_invert;
};
/*
@@ -54,6 +100,9 @@ struct resp_get_clock_rate {
__le32 rate;
};
+#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct clk_mux_gpr_scu, hw)
+#define to_clk_gpr_scu(_hw) container_of(_hw, struct clk_gpr_scu, hw)
+
/*
* struct imx_sc_msg_get_clock_rate - clock get rate protocol
* @hdr: SCU protocol header
@@ -128,9 +177,48 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
return container_of(hw, struct clk_scu, hw);
}
-int imx_clk_scu_init(void)
+static int imx_scu_clk_search_cmp(const void *rsrc, const void *rsrc_p)
{
- return imx_scu_get_handle(&ccm_ipc_handle);
+ return *(u32 *)rsrc - *(u32 *)rsrc_p;
+}
+
+bool imx_scu_clk_is_valid(u32 rsrc_id)
+{
+ void *p;
+
+ if (!rsrc_table)
+ return true;
+
+ p = bsearch(&rsrc_id, rsrc_table->rsrc, rsrc_table->num,
+ sizeof(rsrc_table->rsrc[0]), imx_scu_clk_search_cmp);
+ return p != NULL;
+}
+
+int imx_clk_scu_init(struct device_node *np, const void *data)
+{
+ struct platform_device *pd_dev;
+ int ret, i;
+
+ ret = imx_scu_get_handle(&ccm_ipc_handle);
+ if (ret)
+ return ret;
+
+ if (of_property_read_u32(np, "#clock-cells", &clock_cells))
+ return -EINVAL;
+
+ if (clock_cells == 2) {
+ for (i = 0; i < IMX_SC_R_LAST; i++)
+ INIT_LIST_HEAD(&imx_scu_clks[i]);
+
+ pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
+ pd_dev = of_find_device_by_node(pd_np);
+ if (!pd_dev || !device_is_bound(&pd_dev->dev))
+ return -EPROBE_DEFER;
+
+ rsrc_table = data;
+ }
+
+ return 0;
}
/*
@@ -192,8 +280,10 @@ static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
struct arm_smccc_res res;
unsigned long cluster_id;
- if (clk->rsrc_id == IMX_SC_R_A35)
+ if (clk->rsrc_id == IMX_SC_R_A35 || clk->rsrc_id == IMX_SC_R_A53)
cluster_id = 0;
+ else if (clk->rsrc_id == IMX_SC_R_A72)
+ cluster_id = 1;
else
return -EINVAL;
@@ -254,6 +344,8 @@ static u8 clk_scu_get_parent(struct clk_hw *hw)
return 0;
}
+ clk->parent_index = msg.data.resp.parent;
+
return msg.data.resp.parent;
}
@@ -262,6 +354,7 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_set_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
+ int ret;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
@@ -272,7 +365,16 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
msg.clk = clk->clk_type;
msg.parent = index;
- return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+ ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+ if (ret) {
+ pr_err("%s: failed to set clock parent %d\n",
+ clk_hw_get_name(hw), ret);
+ return ret;
+ }
+
+ clk->parent_index = index;
+
+ return 0;
}
static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
@@ -344,8 +446,15 @@ static const struct clk_ops clk_scu_cpu_ops = {
.unprepare = clk_scu_unprepare,
};
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
- int num_parents, u32 rsrc_id, u8 clk_type)
+static const struct clk_ops clk_scu_pi_ops = {
+ .recalc_rate = clk_scu_recalc_rate,
+ .round_rate = clk_scu_round_rate,
+ .set_rate = clk_scu_set_rate,
+};
+
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+ const char * const *parents, int num_parents,
+ u32 rsrc_id, u8 clk_type)
{
struct clk_init_data init;
struct clk_scu *clk;
@@ -361,8 +470,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
init.name = name;
init.ops = &clk_scu_ops;
- if (rsrc_id == IMX_SC_R_A35)
+ if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || rsrc_id == IMX_SC_R_A72)
init.ops = &clk_scu_cpu_ops;
+ else if (rsrc_id == IMX_SC_R_PI_0_PLL)
+ init.ops = &clk_scu_pi_ops;
else
init.ops = &clk_scu_ops;
init.parent_names = parents;
@@ -375,15 +486,468 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
* clock status from HW instead of using the possible invalid
* cached rate.
*/
- init.flags = CLK_GET_RATE_NOCACHE;
+ init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_PARENT_NOCACHE;
+ clk->hw.init = &init;
+
+ hw = &clk->hw;
+ ret = clk_hw_register(dev, hw);
+ if (ret) {
+ kfree(clk);
+ hw = ERR_PTR(ret);
+ }
+
+ if (dev)
+ dev_set_drvdata(dev, clk);
+
+ return hw;
+}
+
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ unsigned int rsrc = clkspec->args[0];
+ unsigned int idx = clkspec->args[1];
+ struct list_head *scu_clks = data;
+ struct imx_scu_clk_node *clk;
+
+ list_for_each_entry(clk, &scu_clks[rsrc], node) {
+ if (clk->clk_type == idx)
+ return clk->hw;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+static int imx_clk_scu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct imx_scu_clk_node *clk = dev_get_platdata(dev);
+ struct clk_hw *hw;
+ int ret;
+
+ pm_runtime_set_suspended(dev);
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(dev);
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret) {
+ pm_genpd_remove_device(dev);
+ pm_runtime_disable(dev);
+ return ret;
+ }
+
+ hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents,
+ clk->rsrc, clk->clk_type);
+ if (IS_ERR(hw)) {
+ pm_runtime_disable(dev);
+ return PTR_ERR(hw);
+ }
+
+ clk->hw = hw;
+ list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
+ clk->clk_type);
+
+ return 0;
+}
+
+int __maybe_unused imx_clk_scu_suspend(struct device *dev)
+{
+ struct clk_scu *clk = dev_get_drvdata(dev);
+ u32 rsrc_id = clk->rsrc_id;
+
+ if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) ||
+ (rsrc_id == IMX_SC_R_A72))
+ return 0;
+
+ clk->parent = clk_hw_get_parent(&clk->hw);
+
+ /* DC SS needs to handle bypass clock using non-cached clock rate */
+ if (clk->rsrc_id == IMX_SC_R_DC_0_VIDEO0 ||
+ clk->rsrc_id == IMX_SC_R_DC_0_VIDEO1 ||
+ clk->rsrc_id == IMX_SC_R_DC_1_VIDEO0 ||
+ clk->rsrc_id == IMX_SC_R_DC_1_VIDEO1)
+ clk->rate = clk_scu_recalc_rate(&clk->hw, 0);
+ else
+ clk->rate = clk_hw_get_rate(&clk->hw);
+
+ clk->is_enabled = clk_hw_is_enabled(&clk->hw);
+
+ if (clk->parent)
+ dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent),
+ clk->parent_index);
+
+ if (clk->rate)
+ dev_dbg(dev, "save rate %d\n", clk->rate);
+
+ if (clk->is_enabled)
+ dev_dbg(dev, "save enabled state\n");
+
+ return 0;
+}
+
+int __maybe_unused imx_clk_scu_resume(struct device *dev)
+{
+ struct clk_scu *clk = dev_get_drvdata(dev);
+ u32 rsrc_id = clk->rsrc_id;
+ int ret = 0;
+
+ if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) ||
+ (rsrc_id == IMX_SC_R_A72))
+ return 0;
+
+ if (clk->parent) {
+ ret = clk_scu_set_parent(&clk->hw, clk->parent_index);
+ dev_dbg(dev, "restore parent %s idx %u %s\n",
+ clk_hw_get_name(clk->parent),
+ clk->parent_index, !ret ? "success" : "failed");
+ }
+
+ if (clk->rate) {
+ ret = clk_scu_set_rate(&clk->hw, clk->rate, 0);
+ dev_dbg(dev, "restore rate %d %s\n", clk->rate,
+ !ret ? "success" : "failed");
+ }
+
+ if (clk->is_enabled && rsrc_id != IMX_SC_R_PI_0_PLL) {
+ ret = clk_scu_prepare(&clk->hw);
+ dev_dbg(dev, "restore enabled state %s\n",
+ !ret ? "success" : "failed");
+ }
+
+ return ret;
+}
+
+const struct dev_pm_ops imx_clk_scu_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend,
+ imx_clk_scu_resume)
+};
+
+static struct platform_driver imx_clk_scu_driver = {
+ .driver = {
+ .name = "imx-scu-clk",
+ .suppress_bind_attrs = true,
+ .pm = &imx_clk_scu_pm_ops,
+ },
+ .probe = imx_clk_scu_probe,
+};
+
+static int __init imx_clk_scu_driver_init(void)
+{
+ return platform_driver_register(&imx_clk_scu_driver);
+}
+subsys_initcall_sync(imx_clk_scu_driver_init);
+
+static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
+{
+ struct of_phandle_args genpdspec = {
+ .np = pd_np,
+ .args_count = 1,
+ .args[0] = rsrc_id,
+ };
+
+ if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) ||
+ (rsrc_id == IMX_SC_R_A72))
+ return 0;
+
+ return of_genpd_add_device(&genpdspec, dev);
+}
+
+static bool imx_clk_is_resource_owned(u32 rsrc)
+{
+ /*
+ * A-core resources are special. SCFW reports they are not "owned" by
+ * current partition but linux can still adjust them for cpufreq.
+ *
+ * So force this to return false when running as a VM guest and always
+ * true otherwise.
+ */
+ if (rsrc == IMX_SC_R_A53 || rsrc == IMX_SC_R_A72 ||
+ rsrc == IMX_SC_R_A35) {
+ if (xen_domain() && !xen_initial_domain())
+ return false;
+ return true;
+ }
+
+ return imx_sc_rm_is_resource_owned(ccm_ipc_handle, rsrc);
+}
+
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+ const char * const *parents,
+ int num_parents, u32 rsrc_id, u8 clk_type)
+{
+ struct imx_scu_clk_node clk = {
+ .name = name,
+ .rsrc = rsrc_id,
+ .clk_type = clk_type,
+ .parents = parents,
+ .num_parents = num_parents,
+ };
+ struct platform_device *pdev;
+ int ret;
+
+ if (!imx_scu_clk_is_valid(rsrc_id))
+ return NULL;
+
+ if (!imx_clk_is_resource_owned(rsrc_id))
+ return NULL;
+
+ pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
+ if (!pdev) {
+ pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
+ name, rsrc_id, clk_type);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = platform_device_add_data(pdev, &clk, sizeof(clk));
+ if (ret) {
+ platform_device_put(pdev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdev->driver_override = "imx-scu-clk";
+
+ ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id);
+ if (ret)
+ pr_warn("%s: failed to attached the power domain %d\n",
+ name, ret);
+
+ platform_device_add(pdev);
+
+ /* For API backwards compatiblilty, simply return NULL for success */
+ return NULL;
+}
+
+static unsigned long clk_gpr_div_scu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ unsigned long rate = 0;
+ u32 val;
+ int err;
+
+ err = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+
+ rate = val ? parent_rate / 2 : parent_rate;
+
+ return err ? 0 : rate;
+}
+
+static long clk_gpr_div_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ if (rate < *prate)
+ rate = *prate / 2;
+ else
+ rate = *prate;
+
+ return rate;
+}
+
+static int clk_gpr_div_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ uint32_t val;
+ int err;
+
+ val = (rate < parent_rate) ? 1 : 0;
+ err = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, val);
+
+ return err ? -EINVAL : 0;
+}
+
+static const struct clk_ops clk_gpr_div_scu_ops = {
+ .recalc_rate = clk_gpr_div_scu_recalc_rate,
+ .round_rate = clk_gpr_div_scu_round_rate,
+ .set_rate = clk_gpr_div_scu_set_rate,
+};
+
+static u8 clk_gpr_mux_scu_get_parent(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk= to_clk_gpr_scu(hw);
+ u32 val = 0;
+
+ imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+
+ return (u8)val;
+}
+
+static int clk_gpr_mux_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_gpr_scu *clk= to_clk_gpr_scu(hw);
+
+ imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, index);
+
+ return 0;
+}
+
+static const struct clk_ops clk_gpr_mux_scu_ops = {
+ .get_parent = clk_gpr_mux_scu_get_parent,
+ .set_parent = clk_gpr_mux_scu_set_parent,
+};
+
+static int clk_gpr_gate_scu_prepare(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+
+ return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, !clk->gate_invert);
+}
+
+static void clk_gpr_gate_scu_unprepare(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ int ret;
+
+ ret = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, clk->gate_invert);
+ if (ret)
+ pr_err("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
+ ret);
+}
+
+static int clk_gpr_gate_scu_is_prepared(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk= to_clk_gpr_scu(hw);
+ int ret;
+ u32 val;
+
+ ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+ if (ret)
+ return ret;
+
+ return clk->gate_invert ? !val : val;
+}
+
+static struct clk_ops clk_gpr_gate_scu_ops = {
+ .prepare = clk_gpr_gate_scu_prepare,
+ .unprepare = clk_gpr_gate_scu_unprepare,
+ .is_prepared = clk_gpr_gate_scu_is_prepared,
+};
+
+struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name,
+ int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags,
+ bool invert)
+{
+ struct imx_scu_clk_node *clk_node;
+ struct clk_gpr_scu *clk;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ if (rsrc_id >= IMX_SC_R_LAST)
+ return NULL;
+
+ if (gpr_id >= IMX_SC_C_LAST)
+ return NULL;
+
+ if (!imx_scu_clk_is_valid(rsrc_id))
+ return ERR_PTR(-EINVAL);
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk_node = kzalloc(sizeof(*clk_node), GFP_KERNEL);
+ if (!clk_node) {
+ kfree(clk);
+ return ERR_PTR(-ENOMEM);
+ };
+
+ /* struct clk_gate_scu assignments */
+ clk->rsrc_id = rsrc_id;
+ clk->gpr_id = gpr_id;
+ clk->flags = flags;
+ clk->gate_invert = invert;
+
+ if (flags & IMX_SCU_GPR_CLK_GATE)
+ init.ops = &clk_gpr_gate_scu_ops;
+
+ if (flags & IMX_SCU_GPR_CLK_DIV)
+ init.ops = &clk_gpr_div_scu_ops;
+
+ if (flags & IMX_SCU_GPR_CLK_MUX)
+ init.ops = &clk_gpr_mux_scu_ops;
+
+ init.flags = 0;
+ init.name = name;
+ init.parent_names = parent_name;
+ init.num_parents = num_parents;
+
clk->hw.init = &init;
hw = &clk->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(clk);
+ kfree(clk_node);
hw = ERR_PTR(ret);
+ } else {
+ clk_node->hw = hw;
+ clk_node->clk_type = gpr_id;
+ list_add_tail(&clk_node->node, &imx_scu_clks[rsrc_id]);
}
return hw;
}
+
+static void cpufreq_governor_daemon_handler(struct work_struct *work)
+{
+ int fd, i;
+ unsigned char cluster_governor[MAX_CLUSTER_NUM][54] = {
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
+ "",
+ };
+
+ /* generate second cluster's cpufreq governor path */
+ sprintf(cluster_governor[MAX_CLUSTER_NUM - 1],
+ "%s%d%s", "/sys/devices/system/cpu/cpu", num_online_cpus() - 1,
+ "/cpufreq/scaling_governor");
+
+ for (i = 0; i < MAX_CLUSTER_NUM; i++) {
+ fd = ksys_open((const char __user __force *)cluster_governor[i],
+ O_RDWR, 0700);
+ if (fd >= 0) {
+ ksys_write(fd, "schedutil", strlen("schedutil"));
+ ksys_close(fd);
+ pr_info("switch cluster %d cpu-freq governor to schedutil\n",
+ i);
+ } else {
+ /* re-schedule if sys write is NOT ready */
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
+ break;
+ }
+ }
+}
+
+static int __init imx_scu_switch_cpufreq_governor(void)
+{
+ int i;
+
+ INIT_DELAYED_WORK(&cpufreq_governor_daemon,
+ cpufreq_governor_daemon_handler);
+
+ for (i = 1; i < num_online_cpus(); i++) {
+ if (topology_physical_package_id(i) == topology_physical_package_id(0))
+ continue;
+
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
+ break;
+ }
+
+ return 0;
+}
+late_initcall(imx_scu_switch_cpufreq_governor);
diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h
index 2bcfaf06a458..ff60767c6251 100644
--- a/drivers/clk/imx/clk-scu.h
+++ b/drivers/clk/imx/clk-scu.h
@@ -8,25 +8,94 @@
#define __IMX_CLK_SCU_H
#include <linux/firmware/imx/sci.h>
+#include <linux/of.h>
-int imx_clk_scu_init(void);
+#define IMX_SCU_GPR_CLK_GATE BIT(0)
+#define IMX_SCU_GPR_CLK_DIV BIT(1)
+#define IMX_SCU_GPR_CLK_MUX BIT(2)
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
- int num_parents, u32 rsrc_id, u8 clk_type);
+struct imx_clk_scu_rsrc_table {
+ const u32 *rsrc;
+ u8 num;
+};
+
+extern u32 clock_cells;
+extern struct list_head imx_scu_clks[];
+extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
+extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;
+extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm;
+
+int imx_clk_scu_init(struct device_node *np, const void *data);
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+ void *data);
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+ const char * const *parents,
+ int num_parents, u32 rsrc_id, u8 clk_type);
+
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+ const char * const *parents, int num_parents,
+ u32 rsrc_id, u8 clk_type);
+
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx, bool hw_gate);
+
+struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name,
+ int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags,
+ bool invert);
static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
u8 clk_type)
{
- return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
+ if (clock_cells == 2)
+ return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
+ else
+ return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type);
}
static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
{
- return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
+ if (clock_cells == 2)
+ return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
+ else
+ return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, 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);
+static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+ return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg,
+ bit_idx, hw_gate);
+}
+
+static inline 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)
+{
+ return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg,
+ bit_idx, hw_gate);
+}
+
+static inline struct clk_hw *imx_clk_gate_gpr_scu(const char *name, const char *parent_name,
+ u32 rsrc_id, u8 gpr_id, bool invert)
+{
+ return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id,
+ IMX_SCU_GPR_CLK_GATE, invert);
+}
+
+static inline struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
+ u32 rsrc_id, u8 gpr_id)
+{
+ return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id,
+ IMX_SCU_GPR_CLK_DIV, 0);
+}
+
+static inline struct clk_hw *imx_clk_mux_gpr_scu(const char *name, const char * const *parent_names,
+ int num_parents, u32 rsrc_id, u8 gpr_id)
+{
+ return __imx_clk_gpr_scu(name, parent_names, num_parents, rsrc_id,
+ gpr_id, IMX_SCU_GPR_CLK_MUX, 0);
+}
#endif
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index cfc05e43c343..6c0029950d38 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -14,6 +14,8 @@
DEFINE_SPINLOCK(imx_ccm_lock);
+bool uart_from_osc;
+
void imx_unregister_clocks(struct clk *clks[], unsigned int count)
{
unsigned int i;
@@ -133,7 +135,7 @@ void imx_cscmr1_fixup(u32 *val)
}
static int imx_keep_uart_clocks;
-static struct clk ** const *imx_uart_clocks;
+static bool imx_uart_clks_on;
static int __init imx_keep_uart_clocks_param(char *str)
{
@@ -146,26 +148,49 @@ __setup_param("earlycon", imx_keep_uart_earlycon,
__setup_param("earlyprintk", imx_keep_uart_earlyprintk,
imx_keep_uart_clocks_param, 0);
-void imx_register_uart_clocks(struct clk ** const clks[])
+static void imx_earlycon_uart_clks_onoff(bool is_on)
{
- if (imx_keep_uart_clocks) {
- int i;
+ struct clk *uart_clk;
+ int i = 0;
- imx_uart_clocks = clks;
- for (i = 0; imx_uart_clocks[i]; i++)
- clk_prepare_enable(*imx_uart_clocks[i]);
- }
+ if (!imx_keep_uart_clocks || (!is_on && !imx_uart_clks_on))
+ return;
+
+ /* only support dt */
+ if (!of_stdout)
+ return;
+
+ do {
+ uart_clk = of_clk_get(of_stdout, i++);
+ if (IS_ERR(uart_clk))
+ break;
+
+ if (is_on)
+ clk_prepare_enable(uart_clk);
+ else
+ clk_disable_unprepare(uart_clk);
+ } while (true);
+
+ if (is_on)
+ imx_uart_clks_on = true;
}
-static int __init imx_clk_disable_uart(void)
+void imx_register_uart_clocks(void)
{
- if (imx_keep_uart_clocks && imx_uart_clocks) {
- int i;
+ imx_earlycon_uart_clks_onoff(true);
+}
- for (i = 0; imx_uart_clocks[i]; i++)
- clk_disable_unprepare(*imx_uart_clocks[i]);
- }
+static int __init imx_clk_disable_uart(void)
+{
+ imx_earlycon_uart_clks_onoff(false);
return 0;
}
late_initcall_sync(imx_clk_disable_uart);
+
+static int __init setup_uart_clk(char *uart_rate)
+{
+ uart_from_osc = true;
+ return 1;
+}
+__setup("uart_from_osc", setup_uart_clk);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index f7a389a50401..362cb9e60699 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -4,16 +4,20 @@
#include <linux/spinlock.h>
#include <linux/clk-provider.h>
+#include <soc/imx/src.h>
extern spinlock_t imx_ccm_lock;
void imx_check_clocks(struct clk *clks[], unsigned int count);
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
-void imx_register_uart_clocks(struct clk ** const clks[]);
+void imx_register_uart_clocks(void);
void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn);
void imx_unregister_clocks(struct clk *clks[], unsigned int count);
extern void imx_cscmr1_fixup(u32 *val);
+extern struct imx_sema4_mutex *amp_power_mutex;
+extern struct imx_shared_mem *shared_mem;
+extern bool uart_from_osc;
enum imx_pllv1_type {
IMX_PLLV1_IMX1,
@@ -126,6 +130,25 @@ enum imx_pllv3_type {
IMX_PLLV3_AV_IMX7,
};
+#define MAX_SHARED_CLK_NUMBER 100
+#define SHARED_MEM_MAGIC_NUMBER 0x12345678
+#define MCC_POWER_SHMEM_NUMBER (6)
+
+struct imx_shared_clk {
+ struct clk *self;
+ struct clk *parent;
+ void *m4_clk;
+ void *m4_clk_parent;
+ u8 ca9_enabled;
+ u8 cm4_enabled;
+};
+
+struct imx_shared_mem {
+ u32 ca9_valid;
+ u32 cm4_valid;
+ struct imx_shared_clk imx_clk[MAX_SHARED_CLK_NUMBER];
+};
+
struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base, u32 div_mask);
@@ -181,6 +204,13 @@ struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char * const *parent_names, int num_parents);
+int imx_update_shared_mem(struct clk_hw *hw, bool enable);
+
+static inline int clk_on_imx6sx(void)
+{
+ return of_machine_is_compatible("fsl,imx6sx");
+}
+
struct clk_hw *imx7ulp_clk_composite(const char *name,
const char * const *parent_names,
int num_parents, bool mux_present,
@@ -347,7 +377,17 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_hw_register_gate(NULL, name, parent,
+ /*
+ * per design team's suggestion, clk root is NOT consuming
+ * much power, and clk root enable/disable does NOT have domain
+ * control, so they suggest to leave clk root always on when
+ * M4 is enabled.
+ */
+ if (imx_src_is_m4_enabled())
+ return clk_hw_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, 1, 1);
+ else
+ return clk_hw_register_gate(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
diff --git a/drivers/clk/s32/Kconfig b/drivers/clk/s32/Kconfig
new file mode 100644
index 000000000000..c28bdbbfaa3a
--- /dev/null
+++ b/drivers/clk/s32/Kconfig
@@ -0,0 +1,4 @@
+config ARCH_S32_CLK
+ bool "Enable S32 CLK Framework"
+ help
+ Support for the Clock Framework on S32 SoCs.
diff --git a/drivers/clk/s32/Makefile b/drivers/clk/s32/Makefile
new file mode 100644
index 000000000000..169b8b5900f9
--- /dev/null
+++ b/drivers/clk/s32/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_S32_CLK) += clk-core.o
+obj-$(CONFIG_ARCH_S32_CLK) += s32v234/
diff --git a/drivers/clk/s32/clk-core.c b/drivers/clk/s32/clk-core.c
new file mode 100644
index 000000000000..a8cca66f7959
--- /dev/null
+++ b/drivers/clk/s32/clk-core.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "clk.h"
+
+void __init s32_check_clocks(struct clk *clks[], unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++)
+ if (IS_ERR(clks[i]))
+ pr_err("S32 clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+}
+
+static struct clk * __init s32_obtain_fixed_clock_from_dt(const char *name)
+{
+ struct of_phandle_args phandle;
+ struct clk *clk = ERR_PTR(-ENODEV);
+ char *path;
+
+ path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+
+ phandle.np = of_find_node_by_path(path);
+ kfree(path);
+
+ if (phandle.np) {
+ clk = of_clk_get_from_provider(&phandle);
+ of_node_put(phandle.np);
+ }
+ return clk;
+}
+
+struct clk * __init s32_obtain_fixed_clock(
+ const char *name, unsigned long rate)
+{
+ struct clk *clk;
+
+ clk = s32_obtain_fixed_clock_from_dt(name);
+ if (IS_ERR(clk))
+ clk = s32_clk_fixed(name, rate);
+ return clk;
+}
diff --git a/drivers/clk/s32/clk.h b/drivers/clk/s32/clk.h
new file mode 100644
index 000000000000..83100641158f
--- /dev/null
+++ b/drivers/clk/s32/clk.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef __MACH_S32_CLK_H
+#define __MACH_S32_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+
+#define PNAME(x) \
+ static const char *x[] __initconst
+
+void s32_check_clocks(struct clk *clks[], unsigned int count);
+
+struct clk *s32_obtain_fixed_clock(
+ const char *name, unsigned long rate);
+
+static inline struct clk *s32_clk_fixed(const char *name, unsigned long rate)
+{
+ return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+static inline struct clk *s32_clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width,
+ spinlock_t *lock)
+{
+ struct clk *tmp_clk = clk_register_divider(NULL, name, parent,
+ CLK_SET_RATE_PARENT,
+ reg, shift, width, 0, lock);
+
+ return tmp_clk;
+}
+
+static inline struct clk *s32_clk_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents,
+ u8 num_parents, spinlock_t *lock)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0, lock);
+}
+
+static inline struct clk *s32_clk_fixed_factor(const char *name,
+ const char *parent,
+ unsigned int mult,
+ unsigned int div)
+{
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, mult, div);
+}
+
+#endif
diff --git a/drivers/clk/s32/s32v234/Makefile b/drivers/clk/s32/s32v234/Makefile
new file mode 100644
index 000000000000..7ddf9f4b5d81
--- /dev/null
+++ b/drivers/clk/s32/s32v234/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_S32_CLK) += clk.o clk-plldig.o clk-dfs.o
diff --git a/drivers/clk/s32/s32v234/clk-dfs.c b/drivers/clk/s32/s32v234/clk-dfs.c
new file mode 100644
index 000000000000..2bd569e13a18
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk-dfs.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "clk.h"
+
+/**
+ * struct clk_dfs - S32 DFS clock
+ * @clk_hw: clock source
+ * @reg: DFS register address
+ * @idx: the index of DFS encoded in the register
+ *
+ * DFS clock found on S32 series. Each register for DFS has 4 clk_dfs
+ * data encoded, and member idx is used to specify the one.
+ * Only ARMPLL(3 DFS), ENETPLL(4 DFS) and DDRPLL(3 DFS) has DFS outputs.
+ */
+struct clk_dfs {
+ struct clk_hw hw;
+ void __iomem *reg;
+ enum s32v234_plldig_type plltype;
+ u8 idx;
+ u32 mfn;
+};
+
+#define to_clk_dfs(_hw) container_of(_hw, struct clk_dfs, hw)
+
+static int get_pllx_dfs_nr(enum s32v234_plldig_type plltype)
+{
+ switch (plltype) {
+ case S32_PLLDIG_ARM:
+ return ARMPLL_DFS_NR;
+ case S32_PLLDIG_ENET:
+ return ENETPLL_DFS_NR;
+ case S32_PLLDIG_DDR:
+ return DDRPLL_DFS_NR;
+ case S32_PLLDIG_PERIPH:
+ case S32_PLLDIG_VIDEO:
+ pr_warn("Current selected PLL has no DFS\n");
+ break;
+ }
+
+ return -EINVAL;
+}
+static unsigned long get_pllx_dfsy_max_rate(enum s32v234_plldig_type plltype,
+ int dfsno)
+{
+ switch (plltype) {
+ case S32_PLLDIG_ARM:
+ switch (dfsno) {
+ case 0:
+ return ARMPLL_DFS0_MAX_RATE;
+ case 1:
+ return ARMPLL_DFS1_MAX_RATE;
+ case 2:
+ return ARMPLL_DFS2_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_ENET:
+ switch (dfsno) {
+ case 0:
+ return ENETPLL_DFS0_MAX_RATE;
+ case 1:
+ return ENETPLL_DFS1_MAX_RATE;
+ case 2:
+ return ENETPLL_DFS2_MAX_RATE;
+ case 3:
+ return ENETPLL_DFS3_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_DDR:
+ switch (dfsno) {
+ case 0:
+ return DDRPLL_DFS0_MAX_RATE;
+ case 1:
+ return DDRPLL_DFS1_MAX_RATE;
+ case 2:
+ return DDRPLL_DFS2_MAX_RATE;
+ }
+ break;
+ case S32_PLLDIG_PERIPH:
+ case S32_PLLDIG_VIDEO:
+ pr_warn("Current selected PLL has no DFS.");
+ break;
+ default:
+ pr_warn("Unsupported PLL. Use %d or %d\n",
+ S32_PLLDIG_ARM, S32_PLLDIG_VIDEO);
+ break;
+ }
+
+ return -EINVAL;
+}
+static int clk_dfs_enable(struct clk_hw *hw)
+{
+ /*
+ * TODO: When SOC is available, this function
+ * should be tested and implemented for DFS
+ * if it is possible
+ */
+ return 0;
+}
+
+static void clk_dfs_disable(struct clk_hw *hw)
+{
+ /*
+ * TODO: When SOC is available, this function
+ * should be tested and implemented for DFS
+ * if it is possible
+ */
+}
+
+static unsigned long clk_dfs_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ u32 mfn, mfi, rate;
+ u32 dvport = readl_relaxed(DFS_DVPORTn(dfs->reg, dfs->idx));
+
+ mfn = (dvport & DFS_DVPORTn_MFN_MASK) >> DFS_DVPORTn_MFN_OFFSET;
+ mfi = (dvport & DFS_DVPORTn_MFI_MASK) >> DFS_DVPORTn_MFI_OFFSET;
+ mfi <<= 8;
+ rate = parent_rate / (mfi + mfn);
+ rate <<= 8;
+
+ return rate;
+}
+
+static long clk_dfs_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ unsigned long max_allowed_rate;
+
+ max_allowed_rate = get_pllx_dfsy_max_rate(dfs->plltype, dfs->idx);
+
+ if (rate > max_allowed_rate)
+ rate = max_allowed_rate;
+
+ return rate;
+}
+
+static int clk_dfs_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+ u32 mfi;
+ u32 portreset = readl_relaxed(DFS_PORTRESET(dfs->reg));
+
+ writel_relaxed(DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg));
+ writel_relaxed(portreset | ~DFS_PORTRESET_PORTRESET_SET(dfs->idx),
+ DFS_PORTRESET(dfs->reg));
+
+ mfi = parent_rate/rate;
+ writel_relaxed(DFS_DVPORTn_MFI_SET(mfi) |
+ DFS_DVPORTn_MFN_SET(dfs->mfn),
+ DFS_DVPORTn(dfs->reg, dfs->idx));
+
+ writel_relaxed(~DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg));
+
+ while (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx)))
+ ;
+
+ return 0;
+}
+
+static int clk_dfs_is_enabled(struct clk_hw *hw)
+{
+ struct clk_dfs *dfs = to_clk_dfs(hw);
+
+ /* Check if current DFS output port is locked */
+ if (readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx)))
+ return 0;
+
+ return 1;
+}
+
+static const struct clk_ops clk_dfs_ops = {
+ .enable = clk_dfs_enable,
+ .disable = clk_dfs_disable,
+ .recalc_rate = clk_dfs_recalc_rate,
+ .round_rate = clk_dfs_round_rate,
+ .set_rate = clk_dfs_set_rate,
+ .is_enabled = clk_dfs_is_enabled,
+};
+
+struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *reg,
+ u8 idx, u32 mfn)
+{
+ struct clk_dfs *dfs;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* PERIPH and VIDEO PLL do not have DFS */
+ if (type == S32_PLLDIG_PERIPH || type == S32_PLLDIG_VIDEO)
+ return ERR_PTR(-EINVAL);
+
+ /* check if DFS index is valid for current pll */
+ if (idx >= get_pllx_dfs_nr(type))
+ return ERR_PTR(-EINVAL);
+
+ dfs = kzalloc(sizeof(*dfs), GFP_KERNEL);
+ if (!dfs)
+ return ERR_PTR(-ENOMEM);
+
+ dfs->reg = reg;
+ dfs->idx = idx;
+ dfs->mfn = mfn;
+ dfs->plltype = type;
+
+ init.name = name;
+ init.ops = &clk_dfs_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ dfs->hw.init = &init;
+
+ clk = clk_register(NULL, &dfs->hw);
+ if (IS_ERR(clk))
+ kfree(dfs);
+
+ return clk;
+}
diff --git a/drivers/clk/s32/s32v234/clk-plldig.c b/drivers/clk/s32/s32v234/clk-plldig.c
new file mode 100644
index 000000000000..6ed23974ee63
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk-plldig.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include "clk.h"
+
+/*
+ * struct clk_plldig - S32 PLLDIG clock
+ * @clk_hw: clock source
+ * @base: base address of PLL registers
+ * @plldv_mfd: multiplication loop factor divider
+ * @plldv_rfdphi: PHI reduced frequency divider
+ * @plldv_rfdphi1: PHI reduced frequency divider
+ *
+ * PLLDIG clock version 1, found on S32 series.
+ */
+struct clk_plldig {
+ struct clk_hw hw;
+ void __iomem *base;
+ enum s32v234_plldig_type type;
+ u32 plldv_mfd;
+ u32 pllfd_mfn;
+ u32 plldv_rfdphi;
+ u32 plldv_rfdphi1;
+};
+
+#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw)
+
+static unsigned long get_pllx_max_vco_rate(enum s32v234_plldig_type plltype)
+{
+ switch (plltype) {
+ case S32_PLLDIG_PERIPH:
+ return PERIPHPLL_MAX_VCO_RATE;
+ default:
+ pr_warn("Unsupported PLL.\n");
+ return -EINVAL;
+ }
+}
+
+static unsigned long get_pllx_phiy_max_rate(enum s32v234_plldig_type plltype,
+ unsigned int phino)
+{
+ switch (plltype) {
+ case S32_PLLDIG_PERIPH:
+ switch (phino) {
+ case 0:
+ return PERIPHPLL_MAX_PHI0_MAX_RATE;
+ case 1:
+ return PERIPHPLL_MAX_PHI1_MAX_RATE;
+ default:
+ break;
+ }
+ break;
+ default:
+ pr_warn("Unsupported PLL.\n");
+ break;
+ }
+ return -EINVAL;
+}
+
+static int clk_plldig_prepare(struct clk_hw *hw)
+{
+ return 0;
+}
+
+static void clk_plldig_unprepare(struct clk_hw *hw)
+{
+}
+
+static unsigned long clk_plldig_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ u32 plldv = readl_relaxed(PLLDIG_PLLDV(pll->base));
+ u32 pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base));
+ u32 prediv, mfd, mfn, vco;
+
+ prediv = (plldv & PLLDIG_PLLDV_PREDIV_MASK)
+ >> PLLDIG_PLLDV_PREDIV_OFFSET;
+ mfd = (plldv & PLLDIG_PLLDV_MFD_MASK);
+
+ mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK);
+
+ if (prediv == 0)
+ prediv = 1;
+
+ /*
+ * This formula is from platform reference manual
+ * (Rev. 1, 6/2015), PLLDIG chapter.
+ */
+ vco = (parent_rate / prediv) * (mfd + mfn / 20480);
+
+ return vco;
+}
+
+static long clk_plldig_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type);
+
+ if (rate > max_allowed_rate)
+ rate = max_allowed_rate;
+ else if (rate < MIN_VCO_RATE)
+ rate = MIN_VCO_RATE;
+
+ return rate;
+}
+
+static int clk_plldig_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_plldig *pll = to_clk_plldig(hw);
+ u32 pllfd, prediv;
+
+ unsigned long max_allowed_rate = get_pllx_max_vco_rate(pll->type);
+ unsigned long phi0_max_rate = get_pllx_phiy_max_rate(pll->type, 0);
+ unsigned long phi1_max_rate = get_pllx_phiy_max_rate(pll->type, 1);
+
+ if (rate < MIN_VCO_RATE || rate > max_allowed_rate)
+ return -EINVAL;
+
+ if (((rate / pll->plldv_rfdphi) > phi0_max_rate) ||
+ ((rate / pll->plldv_rfdphi) > phi1_max_rate))
+ return -EINVAL;
+
+ pllfd = readl_relaxed(PLLDIG_PLLFD(pll->base));
+ prediv = (parent_rate / rate) *
+ (pll->plldv_mfd + pll->pllfd_mfn / 20480);
+
+ writel_relaxed(PLLDIG_PLLDV_RFDPHI1_SET(pll->plldv_rfdphi1) |
+ PLLDIG_PLLDV_RFDPHI_SET(pll->plldv_rfdphi) |
+ PLLDIG_PLLDV_PREDIV_SET(prediv) |
+ PLLDIG_PLLDV_MFD_SET(pll->plldv_mfd),
+ PLLDIG_PLLDV(pll->base));
+
+ writel_relaxed(pllfd | PLLDIG_PLLFD_MFN_SET(pll->pllfd_mfn),
+ PLLDIG_PLLFD(pll->base));
+
+ /*
+ * To be implemented the wait_lock or an equivalent state
+ * return clk_plldig_wait_lock(pll);
+ */
+ return 0;
+}
+
+static const struct clk_ops clk_plldig_ops = {
+ .prepare = clk_plldig_prepare,
+ .unprepare = clk_plldig_unprepare,
+ .recalc_rate = clk_plldig_recalc_rate,
+ .round_rate = clk_plldig_round_rate,
+ .set_rate = clk_plldig_set_rate,
+};
+
+struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type,
+ const char *name, const char *parent,
+ void __iomem *base, u32 phi)
+{
+ u32 plldv, rfd_phi;
+
+ if (!base)
+ return ERR_PTR(-ENOMEM);
+
+ plldv = readl_relaxed(PLLDIG_PLLDV(base));
+
+ switch (phi) {
+ /* PHI0 */
+ case 0:
+ rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI_MASK)
+ >> PLLDIG_PLLDV_RFDPHI_OFFSET;
+ break;
+ /* PHI1 */
+ case 1:
+ rfd_phi = (plldv & PLLDIG_PLLDV_RFDPHI1_MASK)
+ >> PLLDIG_PLLDV_RFDPHI1_OFFSET;
+
+ if (rfd_phi == 0)
+ rfd_phi = 1;
+
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, 1, rfd_phi);
+}
+
+struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 plldv_mfd, u32 pllfd_mfn,
+ u32 plldv_rfdphi, u32 plldv_rfdphi1)
+{
+ struct clk_plldig *pll;
+ const struct clk_ops *ops;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (plldv_rfdphi > PLLDIG_PLLDV_RFDPHI_MAXVALUE)
+ return ERR_PTR(-EINVAL);
+
+ if (plldv_rfdphi1 > PLLDIG_PLLDV_RFDPHI1_MAXVALUE)
+ return ERR_PTR(-EINVAL);
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ ops = &clk_plldig_ops;
+
+ pll->base = base;
+ pll->type = type;
+ pll->plldv_mfd = plldv_mfd;
+ pll->pllfd_mfn = pllfd_mfn;
+ pll->plldv_rfdphi = plldv_rfdphi;
+ pll->plldv_rfdphi1 = plldv_rfdphi1;
+
+ init.name = name;
+ init.ops = ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
diff --git a/drivers/clk/s32/s32v234/clk.c b/drivers/clk/s32/s32v234/clk.c
new file mode 100644
index 000000000000..cb5abd54fa2c
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <dt-bindings/clock/s32v234-clock.h>
+
+#include "clk.h"
+
+static void __iomem *mc_cgm0_base;
+static void __iomem *mc_cgm1_base;
+static void __iomem *mc_cgm2_base;
+static void __iomem *mc_cgm3_base;
+static void __iomem *mc_me_base;
+static void __iomem *src_base;
+
+DEFINE_SPINLOCK(s32v234_lock);
+
+/* sources for multiplexer clocks, this is used multiple times */
+PNAME(osc_sels) = {"firc", "fxosc", };
+
+PNAME(sys_sels) = {"firc", "fxosc", "armpll_dfs0", };
+
+PNAME(can_sels) = {"firc", "fxosc", "dummy",
+ "periphpll_phi0_div5", };
+
+PNAME(lin_sels) = {"firc", "fxosc", "dummy",
+ "periphpll_phi0_div3", "dummy", "dummy",
+ "dummy", "dummy", "sys6",};
+
+PNAME(sdhc_sels) = {"firc", "fxosc", "dummy",
+ "enetpll_dfs3",};
+
+PNAME(enet_sels) = {"firc", "fxosc", "dummy",
+ "dummy", "enetpll_phi0",};
+
+PNAME(enet_time_sels) = {"firc", "fxosc", "dummy",
+ "dummy", "enetpll_phi0",};
+
+static struct clk *clk[S32V234_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static void __init s32v234_clocks_init(struct device_node *mc_cgm0_node)
+{
+ struct device_node *np;
+
+ clk[S32V234_CLK_DUMMY] = s32_clk_fixed("dummy", 0);
+ clk[S32V234_CLK_FXOSC] = s32_obtain_fixed_clock("fxosc", 0);
+ clk[S32V234_CLK_FIRC] = s32_obtain_fixed_clock("firc", 0);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_me");
+ mc_me_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_me_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-src");
+ src_base = of_iomap(np, 0);
+ if (WARN_ON(!src_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm1");
+ mc_cgm1_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm1_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm2");
+ mc_cgm2_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm2_base))
+ return;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm3");
+ mc_cgm3_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm3_base))
+ return;
+
+ np = mc_cgm0_node;
+ mc_cgm0_base = of_iomap(np, 0);
+ if (WARN_ON(!mc_cgm0_base))
+ return;
+
+ enable_cpumodes_onperipheralconfig(mc_me_base, MC_ME_RUN_PCn_DRUN |
+ MC_ME_RUN_PCn_RUN0 |
+ MC_ME_RUN_PCn_RUN1 |
+ MC_ME_RUN_PCn_RUN2 |
+ MC_ME_RUN_PCn_RUN3,
+ 0);
+
+ /* turn on XOSC and FIRC */
+ enable_clocks_sources(MC_ME_MODE_MC_MVRON, MC_ME_MODE_MC_XOSCON |
+ MC_ME_MODE_MC_FIRCON,
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* transition the core to RUN0 mode */
+ entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
+
+ clk[S32V234_CLK_ARMPLL_SRC_SEL] = s32_clk_mux("armpll_sel",
+ SRC_GPR1, SRC_GPR1_ARMPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_PERIPHPLL_SRC_SEL] = s32_clk_mux("periphpll_sel",
+ SRC_GPR1, SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENETPLL_SRC_SEL] = s32_clk_mux("enetpll_sel",
+ SRC_GPR1, SRC_GPR1_ENETPLL_SRC_SEL_OFFSET,
+ SRC_GPR1_XPLL_SRC_SEL_SIZE,
+ osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
+
+ /* ARM_PLL */
+ clk[S32V234_CLK_ARMPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ARM,
+ "armpll_vco", "armpll_sel", ARMPLL_PLLDIG(mc_cgm0_base),
+ ARMPLL_PLLDIG_PLLDV_MFD, ARMPLL_PLLDIG_PLLDV_MFN,
+ ARMPLL_PLLDIG_PLLDV_RFDPHI0, ARMPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_ARMPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
+ "armpll_phi0", "armpll_vco",
+ ARMPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_ARMPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
+ "armpll_phi1", "armpll_vco",
+ ARMPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_ARMPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs0", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 0,
+ ARMPLL_PLLDIG_DFS0_MFN);
+
+ clk[S32V234_CLK_ARMPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs1", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 1,
+ ARMPLL_PLLDIG_DFS1_MFN);
+
+ clk[S32V234_CLK_ARMPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ARM,
+ "armpll_dfs2", "armpll_phi1",
+ ARMPLL_PLLDIG_DFS(mc_cgm0_base), 2,
+ ARMPLL_PLLDIG_DFS2_MFN);
+
+ clk[S32V234_CLK_SYS_SEL] = s32_clk_mux("sys_sel",
+ MC_ME_RUNn_MC(mc_me_base, 0),
+ MC_ME_MODE_MC_SYSCLK_OFFSET,
+ MC_ME_MODE_MC_SYSCLK_SIZE,
+ sys_sels, ARRAY_SIZE(sys_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_SYS3] = s32_clk_divider("sys3", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 0), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_SYS6] = s32_clk_divider("sys6", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 1), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_SYS6_DIV2] = s32_clk_divider("sys6_div2", "sys_sel",
+ CGM_SC_DCn(mc_cgm0_base, 2), MC_CGM_SC_DCn_PREDIV_OFFSET,
+ MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
+
+ /* PERIPH_PLL */
+ clk[S32V234_CLK_PERIPHPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_PERIPH,
+ "periphpll_vco", "periphpll_sel",
+ PERIPHPLL_PLLDIG(mc_cgm0_base),
+ PERIPHPLL_PLLDIG_PLLDV_MFD, PERIPHPLL_PLLDIG_PLLDV_MFN,
+ PERIPHPLL_PLLDIG_PLLDV_RFDPHI0,
+ PERIPHPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0] =
+ s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
+ "periphpll_phi0", "periphpll_vco",
+ PERIPHPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI1] =
+ s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
+ "periphpll_phi1", "periphpll_vco",
+ PERIPHPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0_DIV3] = s32_clk_fixed_factor(
+ "periphpll_phi0_div3", "periphpll_phi0", 1, 3);
+
+ clk[S32V234_CLK_PERIPHPLL_PHI0_DIV5] = s32_clk_fixed_factor(
+ "periphpll_phi0_div5", "periphpll_phi0", 1, 5);
+
+ clk[S32V234_CLK_CAN_SEL] = s32_clk_mux("can_sel",
+ CGM_ACn_SC(mc_cgm0_base, 6),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ can_sels, ARRAY_SIZE(can_sels), &s32v234_lock);
+
+ /* CAN Clock */
+ clk[S32V234_CLK_CAN] = s32_clk_divider("can", "can_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 6, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* Lin Clock */
+ clk[S32V234_CLK_LIN_SEL] = s32_clk_mux("lin_sel",
+ CGM_ACn_SC(mc_cgm0_base, 3),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ lin_sels, ARRAY_SIZE(lin_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_LIN] = s32_clk_divider("lin", "lin_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 3, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_LIN_IPG] = s32_clk_fixed_factor("lin_ipg",
+ "lin", 1, 2);
+
+ /* enable PERIPHPLL */
+ enable_clocks_sources(0, MC_ME_MODE_MC_PERIPHPLL,
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* ENET_PLL */
+ clk[S32V234_CLK_ENETPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ENET,
+ "enetpll_vco", "enetpll_sel", ENETPLL_PLLDIG(mc_cgm0_base),
+ ENETPLL_PLLDIG_PLLDV_MFD, ENETPLL_PLLDIG_PLLDV_MFN,
+ ENETPLL_PLLDIG_PLLDV_RFDPHI0, ENETPLL_PLLDIG_PLLDV_RFDPHI1);
+
+ clk[S32V234_CLK_ENETPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
+ "enetpll_phi0", "enetpll_vco",
+ ENETPLL_PLLDIG(mc_cgm0_base), 0);
+
+ clk[S32V234_CLK_ENETPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
+ "enetpll_phi1", "enetpll_vco",
+ ENETPLL_PLLDIG(mc_cgm0_base), 1);
+
+ clk[S32V234_CLK_ENETPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs0", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 0,
+ ENETPLL_PLLDIG_DFS0_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs1", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 1,
+ ENETPLL_PLLDIG_DFS1_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs2", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 2,
+ ENETPLL_PLLDIG_DFS2_MFN);
+
+ clk[S32V234_CLK_ENETPLL_DFS3] = s32v234_clk_dfs(S32_PLLDIG_ENET,
+ "enetpll_dfs3", "enetpll_phi1",
+ ENETPLL_PLLDIG_DFS(mc_cgm0_base), 3,
+ ENETPLL_PLLDIG_DFS3_MFN);
+
+ /* ENET Clock */
+ clk[S32V234_CLK_ENET_SEL] = s32_clk_mux("enet_sel",
+ CGM_ACn_SC(mc_cgm2_base, 2),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ enet_sels, ARRAY_SIZE(enet_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENET_TIME_SEL] = s32_clk_mux("enet_time_sel",
+ CGM_ACn_SC(mc_cgm0_base, 7),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ enet_time_sels, ARRAY_SIZE(enet_time_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_ENET] = s32_clk_divider("enet", "enet_sel",
+ CGM_ACn_DCm(mc_cgm2_base, 2, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ clk[S32V234_CLK_ENET_TIME] = s32_clk_divider("enet_time",
+ "enet_time_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 7, 1),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* SDHC Clock */
+ clk[S32V234_CLK_SDHC_SEL] = s32_clk_mux("sdhc_sel",
+ CGM_ACn_SC(mc_cgm0_base, 15),
+ MC_CGM_ACn_SEL_OFFSET,
+ MC_CGM_ACn_SEL_SIZE,
+ sdhc_sels, ARRAY_SIZE(sdhc_sels), &s32v234_lock);
+
+ clk[S32V234_CLK_SDHC] = s32_clk_divider("sdhc", "sdhc_sel",
+ CGM_ACn_DCm(mc_cgm0_base, 15, 0),
+ MC_CGM_ACn_DCm_PREDIV_OFFSET,
+ MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
+
+ /* set the system clock */
+ enable_sysclock(MC_ME_MODE_MC_SYSCLK(0x2),
+ MC_ME_RUNn_MC(mc_me_base, 0));
+
+ /* transition the core to RUN0 mode */
+ entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
+
+ /* Add the clocks to provider list */
+ clk_data.clks = clk;
+ clk_data.clk_num = ARRAY_SIZE(clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(S32V234, "fsl,s32v234-mc_cgm0", s32v234_clocks_init);
diff --git a/drivers/clk/s32/s32v234/clk.h b/drivers/clk/s32/s32v234/clk.h
new file mode 100644
index 000000000000..82a222483394
--- /dev/null
+++ b/drivers/clk/s32/s32v234/clk.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef __MACH_S32V234_CLK_H
+#define __MACH_S32V234_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+#include "mc_cgm.h"
+#include "mc_me.h"
+#include "pll.h"
+#include "src.h"
+#include "dfs.h"
+#include "../clk.h"
+
+struct clk *s32v234_clk_plldig(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 plldv_mfd, u32 plldv_mfn,
+ u32 plldv_rfdphi, u32 plldv_rfdphi1);
+
+struct clk *s32v234_clk_plldig_phi(enum s32v234_plldig_type type,
+ const char *name, const char *parent,
+ void __iomem *base, u32 phi);
+
+struct clk *s32v234_clk_dfs(enum s32v234_plldig_type type, const char *name,
+ const char *parent_name,
+ void __iomem *reg, u8 idx, u32 mfn);
+#endif
diff --git a/drivers/clk/s32/s32v234/dfs.h b/drivers/clk/s32/s32v234/dfs.h
new file mode 100644
index 000000000000..be3104f7ae51
--- /dev/null
+++ b/drivers/clk/s32/s32v234/dfs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _DFS_S32V234_H
+#define _DFS_S32V234_H
+
+/* DFS Control Register (DFS_CTRL) */
+#define DFS_CTRL(base) ((base) + 0x00000018)
+#define DFS_CTRL_DLL_LOLIE (1 << 0)
+#define DFS_CTRL_DLL_RESET (1 << 1)
+
+/* DFS Port Status (DFS_PORTSR) */
+#define DFS_PORTSR(base) ((base) + 0x0000000C)
+#define DFS_PORTSR_MASK (0x0000000F)
+#define DFS_PORTSR_OFFSET (28)
+
+/* DFS Port Reset Register (DFS_PORTRESET) */
+#define DFS_PORTRESET(base) ((base) + 0x00000014)
+#define DFS_PORTRESET_PORTRESET_SET(val) \
+ (DFS_PORTRESET_PORTRESET_MASK | \
+ (((val) & DFS_PORTRESET_PORTRESET_MAXVAL) \
+ << DFS_PORTRESET_PORTRESET_OFFSET))
+#define DFS_PORTRESET_PORTRESET_MAXVAL (0xF)
+#define DFS_PORTRESET_PORTRESET_MASK (0x0000000F)
+#define DFS_PORTRESET_PORTRESET_OFFSET (28)
+
+/* DFS Divide Register Portn (DFS_DVPORTn) */
+#define DFS_DVPORTn(base, n) ((base) + (0x0000001C + \
+ ((n) * sizeof(u32))))
+#define DFS_DVPORTn_MFI_SET(val) (DFS_DVPORTn_MFI_MASK & \
+ (((val) & DFS_DVPORTn_MFI_MAXVAL) \
+ << DFS_DVPORTn_MFI_OFFSET))
+#define DFS_DVPORTn_MFN_SET(val) (DFS_DVPORTn_MFN_MASK & \
+ (((val) & DFS_DVPORTn_MFN_MAXVAL) \
+ << DFS_DVPORTn_MFN_OFFSET))
+#define DFS_DVPORTn_MFI_MASK (0x0000FF00)
+#define DFS_DVPORTn_MFN_MASK (0x000000FF)
+#define DFS_DVPORTn_MFI_MAXVAL (0xFF)
+#define DFS_DVPORTn_MFN_MAXVAL (0xFF)
+#define DFS_DVPORTn_MFI_OFFSET (8)
+#define DFS_DVPORTn_MFN_OFFSET (0)
+#define DFS_MAXNUMBER (4)
+
+/*
+ * Naming convention for PLL:
+ * ARMPLL - PLL0
+ * PERIPHPLL - PLL1
+ * ENETPLL - PLL2
+ * DDRPLL - PLL3
+ * VIDEOPLL - PLL4
+ */
+
+/* The max values for PLL DFS is in Hz */
+/* ARMPLL */
+#define ARMPLL_DFS0_MAX_RATE (266000000)
+#define ARMPLL_DFS1_MAX_RATE (600000000)
+#define ARMPLL_DFS2_MAX_RATE (600000000)
+/* ENETPLL */
+#define ENETPLL_DFS0_MAX_RATE (350000000)
+#define ENETPLL_DFS1_MAX_RATE (350000000)
+#define ENETPLL_DFS2_MAX_RATE (416000000)
+#define ENETPLL_DFS3_MAX_RATE (104000000)
+/* DDRPLL */
+#define DDRPLL_DFS0_MAX_RATE (500000000)
+#define DDRPLL_DFS1_MAX_RATE (500000000)
+#define DDRPLL_DFS2_MAX_RATE (350000000)
+
+#define ARMPLL_DFS_NR (3)
+#define ENETPLL_DFS_NR (4)
+#define DDRPLL_DFS_NR (3)
+
+#endif
diff --git a/drivers/clk/s32/s32v234/mc_cgm.h b/drivers/clk/s32/s32v234/mc_cgm.h
new file mode 100644
index 000000000000..aeac68771890
--- /dev/null
+++ b/drivers/clk/s32/s32v234/mc_cgm.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+#ifndef _MC_CGM_H
+#define _MC_CGM_H
+
+#define ARMPLL_PLLDIG(mc_cgm) (mc_cgm)
+#define ARMPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x40)
+#define ARMPLL_PLLDIG_PLLDV_MFD (50)
+#define ARMPLL_PLLDIG_PLLDV_MFN (0)
+#define ARMPLL_PLLDIG_PLLDV_RFDPHI0 (1)
+#define ARMPLL_PLLDIG_PLLDV_RFDPHI1 (1)
+#define ARMPLL_PLLDIG_DFS0_MFN (195)
+#define ARMPLL_PLLDIG_DFS1_MFN (171)
+#define ARMPLL_PLLDIG_DFS2_MFN (171)
+
+#define PERIPHPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x80)
+#define PERIPHPLL_PLLDIG_PLLDV_MFD (30)
+#define PERIPHPLL_PLLDIG_PLLDV_MFN (0)
+#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI0 (0x1)
+#define PERIPHPLL_PLLDIG_PLLDV_RFDPHI1 (0x1)
+
+#define ENETPLL_PLLDIG(mc_cgm) ((mc_cgm) + 0x100)
+#define ENETPLL_PLLDIG_DFS(mc_cgm) ((mc_cgm) + 0x100 + 0x40)
+#define ENETPLL_PLLDIG_PLLDV_MFD (50)
+#define ENETPLL_PLLDIG_PLLDV_MFN (0)
+#define ENETPLL_PLLDIG_PLLDV_RFDPHI0 (0x1)
+#define ENETPLL_PLLDIG_PLLDV_RFDPHI1 (0x1)
+#define ENETPLL_PLLDIG_DFS0_MFN (220)
+#define ENETPLL_PLLDIG_DFS1_MFN (220)
+#define ENETPLL_PLLDIG_DFS2_MFN (33)
+#define ENETPLL_PLLDIG_DFS3_MFN (1)
+
+/* MC_CGM_SC_SS */
+#define CGM_SC_SS(mc_cgm) (((mc_cgm) + 0x7E4))
+
+/* MC_CGM_SC_DCn */
+#define CGM_SC_DCn(mc_cgm, dc) (((mc_cgm) + 0x7E8) + ((dc) * 0x4))
+
+#define MC_CGM_SC_DCn_PREDIV_OFFSET (16)
+#define MC_CGM_SC_DCn_PREDIV_SIZE (3)
+#define MC_CGM_SC_DCn_DE (1 << 31)
+#define MC_CGM_SC_SEL_OFFSET (24)
+#define MC_CGM_SC_SEL_SIZE (4)
+
+/* MC_CGM_ACn_DCm */
+#define CGM_ACn_DCm(mc_cgm, ac, dc) (((mc_cgm) + 0x808) + ((ac) * 0x20)\
+ + ((dc) * 0x4))
+
+#define MC_CGM_ACn_DCm_PREDIV(val) (MC_CGM_ACn_DCm_PREDIV_MASK & \
+ ((val) \
+ << MC_CGM_ACn_DCm_PREDIV_OFFSET))
+#define MC_CGM_ACn_DCm_PREDIV_MASK (0x001F0000)
+#define MC_CGM_ACn_DCm_PREDIV_OFFSET (16)
+#define MC_CGM_ACn_DCm_PREDIV_SIZE (5)
+#define MC_CGM_ACn_DCm_DE (1 << 31)
+
+/* MC_CGM_ACn_SC/MC_CGM_ACn_SS */
+#define CGM_ACn_SC(mc_cgm, ac) (((mc_cgm) + 0x800) + ((ac) * 0x20))
+#define CGM_ACn_SS(mc_cgm, ac) (((mc_cgm) + 0x804) + ((ac) * 0x24))
+#define MC_CGM_ACn_SEL_MASK (0x07000000)
+#define MC_CGM_ACn_SEL_SET(source) (MC_CGM_ACn_SEL_MASK & \
+ (((source) & 0x7) \
+ << MC_CGM_ACn_SEL_OFFSET))
+#define MC_CGM_ACn_SEL_OFFSET (24)
+#define MC_CGM_ACn_SEL_SIZE (4)
+
+#endif
diff --git a/drivers/clk/s32/s32v234/mc_me.h b/drivers/clk/s32/s32v234/mc_me.h
new file mode 100644
index 000000000000..718f1d1a0c30
--- /dev/null
+++ b/drivers/clk/s32/s32v234/mc_me.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+
+#ifndef _MC_ME_H
+#define _MC_ME_H
+
+/* MC_ME registers definitions */
+/* MC_ME_GS */
+ #define MC_ME_GS(mc_me) ((mc_me) + 0x00000000)
+
+/* MC_ME_MCTL */
+#define MC_ME_MCTL(mc_me) ((mc_me) + 0x00000004)
+#define MC_ME_MCTL_RESET (0x0 << 28)
+#define MC_ME_MCTL_TEST (0x1 << 28)
+#define MC_ME_MCTL_DRUN (0x3 << 28)
+#define MC_ME_MCTL_RUN0 (0x4 << 28)
+#define MC_ME_MCTL_RUN1 (0x5 << 28)
+#define MC_ME_MCTL_RUN2 (0x6 << 28)
+#define MC_ME_MCTL_RUN3 (0x7 << 28)
+
+#define MC_ME_GS_S_MTRANS (1 << 27)
+
+#define MC_ME_MCTL_KEY (0x00005AF0)
+#define MC_ME_MCTL_INVERTEDKEY (0x0000A50F)
+
+/*
+ * MC_ME_RESET_MC/MC_ME_TEST_MC
+ * MC_ME_DRUN_MC
+ * MC_ME_RUNn_MC
+ */
+#define MC_ME_RESET_MC(mc_me) ((mc_me) + 0x00000020)
+#define MC_ME_TEST_MC(mc_me) ((mc_me) + 0x00000024)
+#define MC_ME_DRUN_MC(mc_me) ((mc_me) + 0x0000002C)
+#define MC_ME_RUNn_MC(mc_me, n) ((mc_me) + 0x00000030 + 0x4 * (n))
+#define MC_ME_MODE_MC_SYSCLK_OFFSET (0)
+#define MC_ME_MODE_MC_SYSCLK_SIZE (0x3)
+#define MC_ME_MODE_MC_SYSCLK(val) (MC_ME_MODE_MC_SYSCLK_MASK & (val))
+#define MC_ME_MODE_MC_SYSCLK_MASK (0x0000000F)
+#define MC_ME_MODE_MC_FIRCON (1 << 4)
+#define MC_ME_MODE_MC_XOSCON (1 << 5)
+#define MC_ME_MODE_MC_ARMPLL (1 << 6)
+#define MC_ME_MODE_MC_PERIPHPLL (1 << 7)
+#define MC_ME_MODE_MC_ENETPLL (1 << 8)
+#define MC_ME_MODE_MC_DDRPLL (1 << 9)
+#define MC_ME_MODE_MC_VIDEOPLL (1 << 10)
+#define MC_ME_MODE_MC_MVRON (1 << 20)
+
+/* MC_ME_DRUN_SEC_CC_I */
+#define MC_ME_DRUN_SEC_CC_I(mc_me) ((mc_me) + 0x260)
+/* MC_ME_RUNn_SEC_CC_I */
+#define MC_ME_RUNn_SEC_CC_I(mc_me, n) ((mc_me) + 0x270 + (n) * 0x10)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK1_OFFSET (4)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK2_OFFSET (8)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK3_OFFSET (12)
+/* Consider only the defined clocks */
+#define MC_ME_MODE_SEC_CC_I_SYSCLK1_SIZE (0x3)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK2_SIZE (0x3)
+#define MC_ME_MODE_SEC_CC_I_SYSCLK3_SIZE (0x3)
+
+/* MC_ME_RUN_PCn */
+#define MC_ME_RUN_PCn(mc_me, n) (mc_me + 0x00000080 + 0x4 * (n))
+
+#define MC_ME_RUN_PCn_MAX_IDX (7)
+#define MC_ME_RUN_PCn_RESET (1 << 0)
+#define MC_ME_RUN_PCn_TEST (1 << 1)
+#define MC_ME_RUN_PCn_DRUN (1 << 3)
+#define MC_ME_RUN_PCn_RUN0 (1 << 4)
+#define MC_ME_RUN_PCn_RUN1 (1 << 5)
+#define MC_ME_RUN_PCn_RUN2 (1 << 6)
+#define MC_ME_RUN_PCn_RUN3 (1 << 7)
+
+#define MC_ME_PCTLn(mc_me, n) (mc_me + 0xC0 + 4 * (n >> 2) + \
+ (3 - (n) % 4))
+
+static inline void entry_to_target_mode(void __iomem *mc_me, u32 mode)
+{
+ writel_relaxed(mode | MC_ME_MCTL_KEY, MC_ME_MCTL(mc_me));
+ writel_relaxed(mode | MC_ME_MCTL_INVERTEDKEY, MC_ME_MCTL(mc_me));
+ while ((readl_relaxed(MC_ME_GS(mc_me)) &
+ MC_ME_GS_S_MTRANS) != 0x00000000)
+ ;
+}
+
+static inline void enable_cpumodes_onperipheralconfig(void __iomem *mc_me,
+ u32 modes, u32 run_pc_idx)
+{
+ WARN_ON(run_pc_idx > MC_ME_RUN_PCn_MAX_IDX);
+ if (run_pc_idx > MC_ME_RUN_PCn_MAX_IDX)
+ return;
+
+ writel_relaxed(modes, MC_ME_RUN_PCn(mc_me, run_pc_idx));
+}
+
+static inline void enable_clocks_sources(u32 flags, u32 clks,
+ void __iomem *xrun_mc_addr)
+{
+ writel_relaxed(readl_relaxed(xrun_mc_addr) | flags | clks,
+ xrun_mc_addr);
+}
+
+static inline void enable_sysclock(u32 clk, void __iomem *xrun_mc_addr)
+{
+ writel_relaxed(readl_relaxed(xrun_mc_addr) & clk,
+ xrun_mc_addr);
+}
+
+#endif
diff --git a/drivers/clk/s32/s32v234/pll.h b/drivers/clk/s32/s32v234/pll.h
new file mode 100644
index 000000000000..b7bcc50f0a22
--- /dev/null
+++ b/drivers/clk/s32/s32v234/pll.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017-2018 NXP
+ */
+#ifndef _PLL_S32V234_H
+#define _PLL_S32V234_H
+
+/* PLLDIG PLL Divider Register (PLLDIG_PLLDV) */
+#define PLLDIG_PLLDV(base) ((base) + 0x00000028)
+#define PLLDIG_PLLDV_MFD_SET(val) (PLLDIG_PLLDV_MFD_MASK & (val))
+#define PLLDIG_PLLDV_MFD_MASK (0x000000FF)
+
+#define PLLDIG_PLLDV_RFDPHI_SET(val) (PLLDIG_PLLDV_RFDPHI_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_RFDPHI_MAXVALUE) \
+ << PLLDIG_PLLDV_RFDPHI_OFFSET))
+#define PLLDIG_PLLDV_RFDPHI_MASK (0x003F0000)
+#define PLLDIG_PLLDV_RFDPHI_MAXVALUE (0x3F)
+
+#define PLLDIG_PLLDV_RFDPHI_OFFSET (16)
+
+#define PLLDIG_PLLDV_RFDPHI1_SET(val) (PLLDIG_PLLDV_RFDPHI1_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_RFDPHI1_MAXVALUE) \
+ << PLLDIG_PLLDV_RFDPHI1_OFFSET))
+#define PLLDIG_PLLDV_RFDPHI1_MASK (0x7E000000)
+#define PLLDIG_PLLDV_RFDPHI1_MAXVALUE (0x3F)
+#define PLLDIG_PLLDV_RFDPHI1_OFFSET (25)
+
+#define PLLDIG_PLLDV_PREDIV_SET(val) (PLLDIG_PLLDV_PREDIV_MASK & \
+ (((val) & \
+ PLLDIG_PLLDV_PREDIV_MAXVALUE) \
+ << PLLDIG_PLLDV_PREDIV_OFFSET))
+#define PLLDIG_PLLDV_PREDIV_MASK (0x00007000)
+#define PLLDIG_PLLDV_PREDIV_MAXVALUE (0x7)
+#define PLLDIG_PLLDV_PREDIV_OFFSET (12)
+
+/* PLLDIG PLL Fractional Divide Register (PLLDIG_PLLFD) */
+#define PLLDIG_PLLFD(base) ((base) + 0x00000030)
+#define PLLDIG_PLLFD_MFN_SET(val) (PLLDIG_PLLFD_MFN_MASK & (val))
+#define PLLDIG_PLLFD_MFN_MASK (0x00007FFF)
+
+/* PLL Calibration Register 1 (PLLDIG_PLLCAL1) */
+#define PLLDIG_PLLCAL1(base) ((base) + 0x00000038)
+#define PLLDIG_PLLCAL1_NDAC1_SET(val) (PLLDIG_PLLCAL1_NDAC1_MASK & \
+ ((val) \
+ << PLLDIG_PLLCAL1_NDAC1_OFFSET))
+#define PLLDIG_PLLCAL1_NDAC1_OFFSET (24)
+#define PLLDIG_PLLCAL1_NDAC1_MASK (0x7F000000)
+
+/* Naming convention for PLL:
+ * ARMPLL - PLL0
+ * PERIPHPLL - PLL1
+ * ENETPLL - PLL2
+ * DDRPLL - PLL3
+ * VIDEOPLL - PLL4
+ */
+/* The min,max values for PLL VCO (Hz) */
+#define PERIPHPLL_MAX_VCO_RATE (1200000000)
+
+/* The min,max values for PLL PHI0 and PHI1 outputs (Hz) */
+#define PERIPHPLL_MAX_PHI0_MAX_RATE (400000000)
+#define PERIPHPLL_MAX_PHI1_MAX_RATE (100000000)
+
+/* The maximum value for PLL VCO according to data sheet */
+#define MAX_VCO_RATE (1300000000)
+#define MIN_VCO_RATE (650000000)
+
+enum s32v234_plldig_type {
+ S32_PLLDIG_ARM,
+ S32_PLLDIG_PERIPH,
+ S32_PLLDIG_ENET,
+ S32_PLLDIG_DDR,
+ S32_PLLDIG_VIDEO,
+};
+
+#endif
diff --git a/drivers/clk/s32/s32v234/src.h b/drivers/clk/s32/s32v234/src.h
new file mode 100644
index 000000000000..39fa973b7c3c
--- /dev/null
+++ b/drivers/clk/s32/s32v234/src.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ */
+#ifndef _SRC_H
+#define _SRC_H
+
+/* Source Reset Control: General Purpose Register 1 */
+#define SRC_GPR1 (src_base + 0x100)
+#define SRC_GPR1_ARMPLL_SRC_SEL_OFFSET (27)
+#define SRC_GPR1_ENETPLL_SRC_SEL_OFFSET (28)
+#define SRC_GPR1_DDRPLL_SRC_SEL_OFFSET (29)
+#define SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET (30)
+#define SRC_GPR1_VIDEOPLL_SRC_SEL_OFFSET (31)
+#define SRC_GPR1_XPLL_SRC_SEL_SIZE (1)
+
+#endif
diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h
index e20c43cc36f6..15118e76e353 100644
--- a/include/dt-bindings/clock/imx6qdl-clock.h
+++ b/include/dt-bindings/clock/imx6qdl-clock.h
@@ -273,6 +273,11 @@
#define IMX6QDL_CLK_MMDC_P0_IPG 263
#define IMX6QDL_CLK_DCIC1 264
#define IMX6QDL_CLK_DCIC2 265
-#define IMX6QDL_CLK_END 266
+#define IMX6QDL_CLK_AXI_ALT_SEL 266
+#define IMX6QDL_CLK_LDB_DI0_DIV_7 267
+#define IMX6QDL_CLK_LDB_DI1_DIV_7 268
+#define IMX6QDL_CLK_LDB_DI0_DIV_SEL 269
+#define IMX6QDL_CLK_LDB_DI1_DIV_SEL 270
+#define IMX6QDL_CLK_END 271
#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h
index e6a670e1a3f8..8ee3b08a7c37 100644
--- a/include/dt-bindings/clock/imx7d-clock.h
+++ b/include/dt-bindings/clock/imx7d-clock.h
@@ -451,5 +451,8 @@
#define IMX7D_SNVS_CLK 442
#define IMX7D_CAAM_CLK 443
#define IMX7D_KPP_ROOT_CLK 444
-#define IMX7D_CLK_END 445
+#define IMX7D_PXP_IPG_CLK 445
+#define IMX7D_PXP_AXI_CLK 446
+#define IMX7D_CLK_END 447
+
#endif /* __DT_BINDINGS_CLOCK_IMX7D_H */
diff --git a/include/dt-bindings/clock/imx7ulp-clock.h b/include/dt-bindings/clock/imx7ulp-clock.h
index 6f66f9005c81..f8d34fb4378f 100644
--- a/include/dt-bindings/clock/imx7ulp-clock.h
+++ b/include/dt-bindings/clock/imx7ulp-clock.h
@@ -49,15 +49,14 @@
#define IMX7ULP_CLK_NIC1_DIV 36
#define IMX7ULP_CLK_NIC1_BUS_DIV 37
#define IMX7ULP_CLK_NIC1_EXT_DIV 38
-#define IMX7ULP_CLK_MIPI_PLL 39
-#define IMX7ULP_CLK_SIRC 40
-#define IMX7ULP_CLK_SOSC_BUS_CLK 41
-#define IMX7ULP_CLK_FIRC_BUS_CLK 42
-#define IMX7ULP_CLK_SPLL_BUS_CLK 43
-#define IMX7ULP_CLK_HSRUN_SYS_SEL 44
-#define IMX7ULP_CLK_HSRUN_CORE_DIV 45
+#define IMX7ULP_CLK_SIRC 39
+#define IMX7ULP_CLK_SOSC_BUS_CLK 40
+#define IMX7ULP_CLK_FIRC_BUS_CLK 41
+#define IMX7ULP_CLK_SPLL_BUS_CLK 42
+#define IMX7ULP_CLK_HSRUN_SYS_SEL 43
+#define IMX7ULP_CLK_HSRUN_CORE_DIV 44
-#define IMX7ULP_CLK_SCG1_END 46
+#define IMX7ULP_CLK_SCG1_END 45
/* PCC2 */
#define IMX7ULP_CLK_DMA1 0
diff --git a/include/dt-bindings/clock/imx8-clock.h b/include/dt-bindings/clock/imx8-clock.h
index 673a8c662340..d7d2a8f3d49e 100644
--- a/include/dt-bindings/clock/imx8-clock.h
+++ b/include/dt-bindings/clock/imx8-clock.h
@@ -7,287 +7,59 @@
#ifndef __DT_BINDINGS_CLOCK_IMX_H
#define __DT_BINDINGS_CLOCK_IMX_H
-/* SCU Clocks */
-
-#define IMX_CLK_DUMMY 0
-
-/* CPU */
-#define IMX_A35_CLK 1
-
-/* LSIO SS */
-#define IMX_LSIO_MEM_CLK 2
-#define IMX_LSIO_BUS_CLK 3
-#define IMX_LSIO_PWM0_CLK 10
-#define IMX_LSIO_PWM1_CLK 11
-#define IMX_LSIO_PWM2_CLK 12
-#define IMX_LSIO_PWM3_CLK 13
-#define IMX_LSIO_PWM4_CLK 14
-#define IMX_LSIO_PWM5_CLK 15
-#define IMX_LSIO_PWM6_CLK 16
-#define IMX_LSIO_PWM7_CLK 17
-#define IMX_LSIO_GPT0_CLK 18
-#define IMX_LSIO_GPT1_CLK 19
-#define IMX_LSIO_GPT2_CLK 20
-#define IMX_LSIO_GPT3_CLK 21
-#define IMX_LSIO_GPT4_CLK 22
-#define IMX_LSIO_FSPI0_CLK 23
-#define IMX_LSIO_FSPI1_CLK 24
-
-/* Connectivity SS */
-#define IMX_CONN_AXI_CLK_ROOT 30
-#define IMX_CONN_AHB_CLK_ROOT 31
-#define IMX_CONN_IPG_CLK_ROOT 32
-#define IMX_CONN_SDHC0_CLK 40
-#define IMX_CONN_SDHC1_CLK 41
-#define IMX_CONN_SDHC2_CLK 42
-#define IMX_CONN_ENET0_ROOT_CLK 43
-#define IMX_CONN_ENET0_BYPASS_CLK 44
-#define IMX_CONN_ENET0_RGMII_CLK 45
-#define IMX_CONN_ENET1_ROOT_CLK 46
-#define IMX_CONN_ENET1_BYPASS_CLK 47
-#define IMX_CONN_ENET1_RGMII_CLK 48
-#define IMX_CONN_GPMI_BCH_IO_CLK 49
-#define IMX_CONN_GPMI_BCH_CLK 50
-#define IMX_CONN_USB2_ACLK 51
-#define IMX_CONN_USB2_BUS_CLK 52
-#define IMX_CONN_USB2_LPM_CLK 53
-
-/* HSIO SS */
-#define IMX_HSIO_AXI_CLK 60
-#define IMX_HSIO_PER_CLK 61
-
-/* Display controller SS */
-#define IMX_DC_AXI_EXT_CLK 70
-#define IMX_DC_AXI_INT_CLK 71
-#define IMX_DC_CFG_CLK 72
-#define IMX_DC0_PLL0_CLK 80
-#define IMX_DC0_PLL1_CLK 81
-#define IMX_DC0_DISP0_CLK 82
-#define IMX_DC0_DISP1_CLK 83
-
-/* MIPI-LVDS SS */
-#define IMX_MIPI_IPG_CLK 90
-#define IMX_MIPI0_PIXEL_CLK 100
-#define IMX_MIPI0_BYPASS_CLK 101
-#define IMX_MIPI0_LVDS_PIXEL_CLK 102
-#define IMX_MIPI0_LVDS_BYPASS_CLK 103
-#define IMX_MIPI0_LVDS_PHY_CLK 104
-#define IMX_MIPI0_I2C0_CLK 105
-#define IMX_MIPI0_I2C1_CLK 106
-#define IMX_MIPI0_PWM0_CLK 107
-#define IMX_MIPI1_PIXEL_CLK 108
-#define IMX_MIPI1_BYPASS_CLK 109
-#define IMX_MIPI1_LVDS_PIXEL_CLK 110
-#define IMX_MIPI1_LVDS_BYPASS_CLK 111
-#define IMX_MIPI1_LVDS_PHY_CLK 112
-#define IMX_MIPI1_I2C0_CLK 113
-#define IMX_MIPI1_I2C1_CLK 114
-#define IMX_MIPI1_PWM0_CLK 115
-
-/* IMG SS */
-#define IMX_IMG_AXI_CLK 120
-#define IMX_IMG_IPG_CLK 121
-#define IMX_IMG_PXL_CLK 122
-
-/* MIPI-CSI SS */
-#define IMX_CSI0_CORE_CLK 130
-#define IMX_CSI0_ESC_CLK 131
-#define IMX_CSI0_PWM0_CLK 132
-#define IMX_CSI0_I2C0_CLK 133
-
-/* PARALLER CSI SS */
-#define IMX_PARALLEL_CSI_DPLL_CLK 140
-#define IMX_PARALLEL_CSI_PIXEL_CLK 141
-#define IMX_PARALLEL_CSI_MCLK_CLK 142
-
-/* VPU SS */
-#define IMX_VPU_ENC_CLK 150
-#define IMX_VPU_DEC_CLK 151
-
-/* GPU SS */
-#define IMX_GPU0_CORE_CLK 160
-#define IMX_GPU0_SHADER_CLK 161
-
-/* ADMA SS */
-#define IMX_ADMA_IPG_CLK_ROOT 165
-#define IMX_ADMA_UART0_CLK 170
-#define IMX_ADMA_UART1_CLK 171
-#define IMX_ADMA_UART2_CLK 172
-#define IMX_ADMA_UART3_CLK 173
-#define IMX_ADMA_SPI0_CLK 174
-#define IMX_ADMA_SPI1_CLK 175
-#define IMX_ADMA_SPI2_CLK 176
-#define IMX_ADMA_SPI3_CLK 177
-#define IMX_ADMA_CAN0_CLK 178
-#define IMX_ADMA_CAN1_CLK 179
-#define IMX_ADMA_CAN2_CLK 180
-#define IMX_ADMA_I2C0_CLK 181
-#define IMX_ADMA_I2C1_CLK 182
-#define IMX_ADMA_I2C2_CLK 183
-#define IMX_ADMA_I2C3_CLK 184
-#define IMX_ADMA_FTM0_CLK 185
-#define IMX_ADMA_FTM1_CLK 186
-#define IMX_ADMA_ADC0_CLK 187
-#define IMX_ADMA_PWM_CLK 188
-#define IMX_ADMA_LCD_CLK 189
-
-#define IMX_SCU_CLK_END 190
-
-/* LPCG clocks */
-
-/* LSIO SS LPCG */
-#define IMX_LSIO_LPCG_PWM0_IPG_CLK 0
-#define IMX_LSIO_LPCG_PWM0_IPG_S_CLK 1
-#define IMX_LSIO_LPCG_PWM0_IPG_HF_CLK 2
-#define IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK 3
-#define IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK 4
-#define IMX_LSIO_LPCG_PWM1_IPG_CLK 5
-#define IMX_LSIO_LPCG_PWM1_IPG_S_CLK 6
-#define IMX_LSIO_LPCG_PWM1_IPG_HF_CLK 7
-#define IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK 8
-#define IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK 9
-#define IMX_LSIO_LPCG_PWM2_IPG_CLK 10
-#define IMX_LSIO_LPCG_PWM2_IPG_S_CLK 11
-#define IMX_LSIO_LPCG_PWM2_IPG_HF_CLK 12
-#define IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK 13
-#define IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK 14
-#define IMX_LSIO_LPCG_PWM3_IPG_CLK 15
-#define IMX_LSIO_LPCG_PWM3_IPG_S_CLK 16
-#define IMX_LSIO_LPCG_PWM3_IPG_HF_CLK 17
-#define IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK 18
-#define IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK 19
-#define IMX_LSIO_LPCG_PWM4_IPG_CLK 20
-#define IMX_LSIO_LPCG_PWM4_IPG_S_CLK 21
-#define IMX_LSIO_LPCG_PWM4_IPG_HF_CLK 22
-#define IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK 23
-#define IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK 24
-#define IMX_LSIO_LPCG_PWM5_IPG_CLK 25
-#define IMX_LSIO_LPCG_PWM5_IPG_S_CLK 26
-#define IMX_LSIO_LPCG_PWM5_IPG_HF_CLK 27
-#define IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK 28
-#define IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK 29
-#define IMX_LSIO_LPCG_PWM6_IPG_CLK 30
-#define IMX_LSIO_LPCG_PWM6_IPG_S_CLK 31
-#define IMX_LSIO_LPCG_PWM6_IPG_HF_CLK 32
-#define IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK 33
-#define IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK 34
-#define IMX_LSIO_LPCG_PWM7_IPG_CLK 35
-#define IMX_LSIO_LPCG_PWM7_IPG_S_CLK 36
-#define IMX_LSIO_LPCG_PWM7_IPG_HF_CLK 37
-#define IMX_LSIO_LPCG_PWM7_IPG_SLV_CLK 38
-#define IMX_LSIO_LPCG_PWM7_IPG_MSTR_CLK 39
-#define IMX_LSIO_LPCG_GPT0_IPG_CLK 40
-#define IMX_LSIO_LPCG_GPT0_IPG_S_CLK 41
-#define IMX_LSIO_LPCG_GPT0_IPG_HF_CLK 42
-#define IMX_LSIO_LPCG_GPT0_IPG_SLV_CLK 43
-#define IMX_LSIO_LPCG_GPT0_IPG_MSTR_CLK 44
-#define IMX_LSIO_LPCG_GPT1_IPG_CLK 45
-#define IMX_LSIO_LPCG_GPT1_IPG_S_CLK 46
-#define IMX_LSIO_LPCG_GPT1_IPG_HF_CLK 47
-#define IMX_LSIO_LPCG_GPT1_IPG_SLV_CLK 48
-#define IMX_LSIO_LPCG_GPT1_IPG_MSTR_CLK 49
-#define IMX_LSIO_LPCG_GPT2_IPG_CLK 50
-#define IMX_LSIO_LPCG_GPT2_IPG_S_CLK 51
-#define IMX_LSIO_LPCG_GPT2_IPG_HF_CLK 52
-#define IMX_LSIO_LPCG_GPT2_IPG_SLV_CLK 53
-#define IMX_LSIO_LPCG_GPT2_IPG_MSTR_CLK 54
-#define IMX_LSIO_LPCG_GPT3_IPG_CLK 55
-#define IMX_LSIO_LPCG_GPT3_IPG_S_CLK 56
-#define IMX_LSIO_LPCG_GPT3_IPG_HF_CLK 57
-#define IMX_LSIO_LPCG_GPT3_IPG_SLV_CLK 58
-#define IMX_LSIO_LPCG_GPT3_IPG_MSTR_CLK 59
-#define IMX_LSIO_LPCG_GPT4_IPG_CLK 60
-#define IMX_LSIO_LPCG_GPT4_IPG_S_CLK 61
-#define IMX_LSIO_LPCG_GPT4_IPG_HF_CLK 62
-#define IMX_LSIO_LPCG_GPT4_IPG_SLV_CLK 63
-#define IMX_LSIO_LPCG_GPT4_IPG_MSTR_CLK 64
-#define IMX_LSIO_LPCG_FSPI0_HCLK 65
-#define IMX_LSIO_LPCG_FSPI0_IPG_CLK 66
-#define IMX_LSIO_LPCG_FSPI0_IPG_S_CLK 67
-#define IMX_LSIO_LPCG_FSPI0_IPG_SFCK 68
-#define IMX_LSIO_LPCG_FSPI1_HCLK 69
-#define IMX_LSIO_LPCG_FSPI1_IPG_CLK 70
-#define IMX_LSIO_LPCG_FSPI1_IPG_S_CLK 71
-#define IMX_LSIO_LPCG_FSPI1_IPG_SFCK 72
-
-#define IMX_LSIO_LPCG_CLK_END 73
-
-/* Connectivity SS LPCG */
-#define IMX_CONN_LPCG_SDHC0_IPG_CLK 0
-#define IMX_CONN_LPCG_SDHC0_PER_CLK 1
-#define IMX_CONN_LPCG_SDHC0_HCLK 2
-#define IMX_CONN_LPCG_SDHC1_IPG_CLK 3
-#define IMX_CONN_LPCG_SDHC1_PER_CLK 4
-#define IMX_CONN_LPCG_SDHC1_HCLK 5
-#define IMX_CONN_LPCG_SDHC2_IPG_CLK 6
-#define IMX_CONN_LPCG_SDHC2_PER_CLK 7
-#define IMX_CONN_LPCG_SDHC2_HCLK 8
-#define IMX_CONN_LPCG_GPMI_APB_CLK 9
-#define IMX_CONN_LPCG_GPMI_BCH_APB_CLK 10
-#define IMX_CONN_LPCG_GPMI_BCH_IO_CLK 11
-#define IMX_CONN_LPCG_GPMI_BCH_CLK 12
-#define IMX_CONN_LPCG_APBHDMA_CLK 13
-#define IMX_CONN_LPCG_ENET0_ROOT_CLK 14
-#define IMX_CONN_LPCG_ENET0_TX_CLK 15
-#define IMX_CONN_LPCG_ENET0_AHB_CLK 16
-#define IMX_CONN_LPCG_ENET0_IPG_S_CLK 17
-#define IMX_CONN_LPCG_ENET0_IPG_CLK 18
-
-#define IMX_CONN_LPCG_ENET1_ROOT_CLK 19
-#define IMX_CONN_LPCG_ENET1_TX_CLK 20
-#define IMX_CONN_LPCG_ENET1_AHB_CLK 21
-#define IMX_CONN_LPCG_ENET1_IPG_S_CLK 22
-#define IMX_CONN_LPCG_ENET1_IPG_CLK 23
-
-#define IMX_CONN_LPCG_CLK_END 24
-
-/* ADMA SS LPCG */
-#define IMX_ADMA_LPCG_UART0_IPG_CLK 0
-#define IMX_ADMA_LPCG_UART0_BAUD_CLK 1
-#define IMX_ADMA_LPCG_UART1_IPG_CLK 2
-#define IMX_ADMA_LPCG_UART1_BAUD_CLK 3
-#define IMX_ADMA_LPCG_UART2_IPG_CLK 4
-#define IMX_ADMA_LPCG_UART2_BAUD_CLK 5
-#define IMX_ADMA_LPCG_UART3_IPG_CLK 6
-#define IMX_ADMA_LPCG_UART3_BAUD_CLK 7
-#define IMX_ADMA_LPCG_SPI0_IPG_CLK 8
-#define IMX_ADMA_LPCG_SPI1_IPG_CLK 9
-#define IMX_ADMA_LPCG_SPI2_IPG_CLK 10
-#define IMX_ADMA_LPCG_SPI3_IPG_CLK 11
-#define IMX_ADMA_LPCG_SPI0_CLK 12
-#define IMX_ADMA_LPCG_SPI1_CLK 13
-#define IMX_ADMA_LPCG_SPI2_CLK 14
-#define IMX_ADMA_LPCG_SPI3_CLK 15
-#define IMX_ADMA_LPCG_CAN0_IPG_CLK 16
-#define IMX_ADMA_LPCG_CAN0_IPG_PE_CLK 17
-#define IMX_ADMA_LPCG_CAN0_IPG_CHI_CLK 18
-#define IMX_ADMA_LPCG_CAN1_IPG_CLK 19
-#define IMX_ADMA_LPCG_CAN1_IPG_PE_CLK 20
-#define IMX_ADMA_LPCG_CAN1_IPG_CHI_CLK 21
-#define IMX_ADMA_LPCG_CAN2_IPG_CLK 22
-#define IMX_ADMA_LPCG_CAN2_IPG_PE_CLK 23
-#define IMX_ADMA_LPCG_CAN2_IPG_CHI_CLK 24
-#define IMX_ADMA_LPCG_I2C0_CLK 25
-#define IMX_ADMA_LPCG_I2C1_CLK 26
-#define IMX_ADMA_LPCG_I2C2_CLK 27
-#define IMX_ADMA_LPCG_I2C3_CLK 28
-#define IMX_ADMA_LPCG_I2C0_IPG_CLK 29
-#define IMX_ADMA_LPCG_I2C1_IPG_CLK 30
-#define IMX_ADMA_LPCG_I2C2_IPG_CLK 31
-#define IMX_ADMA_LPCG_I2C3_IPG_CLK 32
-#define IMX_ADMA_LPCG_FTM0_CLK 33
-#define IMX_ADMA_LPCG_FTM1_CLK 34
-#define IMX_ADMA_LPCG_FTM0_IPG_CLK 35
-#define IMX_ADMA_LPCG_FTM1_IPG_CLK 36
-#define IMX_ADMA_LPCG_PWM_HI_CLK 37
-#define IMX_ADMA_LPCG_PWM_IPG_CLK 38
-#define IMX_ADMA_LPCG_LCD_PIX_CLK 39
-#define IMX_ADMA_LPCG_LCD_APB_CLK 40
-#define IMX_ADMA_LPCG_DSP_ADB_CLK 41
-#define IMX_ADMA_LPCG_DSP_IPG_CLK 42
-#define IMX_ADMA_LPCG_DSP_CORE_CLK 43
-#define IMX_ADMA_LPCG_OCRAM_IPG_CLK 44
-
-#define IMX_ADMA_LPCG_CLK_END 45
+#define IMX_ADMA_ACM_AUD_CLK0_SEL 0
+#define IMX_ADMA_ACM_AUD_CLK0_CLK 1
+#define IMX_ADMA_ACM_AUD_CLK1_SEL 2
+#define IMX_ADMA_ACM_AUD_CLK1_CLK 3
+#define IMX_ADMA_ACM_MCLKOUT0_SEL 4
+#define IMX_ADMA_ACM_MCLKOUT1_SEL 5
+#define IMX_ADMA_ACM_ESAI0_MCLK_SEL 6
+#define IMX_ADMA_ACM_GPT0_MUX_CLK_SEL 7
+#define IMX_ADMA_ACM_GPT1_MUX_CLK_SEL 8
+#define IMX_ADMA_ACM_GPT2_MUX_CLK_SEL 9
+#define IMX_ADMA_ACM_GPT3_MUX_CLK_SEL 10
+#define IMX_ADMA_ACM_GPT4_MUX_CLK_SEL 11
+#define IMX_ADMA_ACM_GPT5_MUX_CLK_SEL 12
+#define IMX_ADMA_ACM_SAI0_MCLK_SEL 13
+#define IMX_ADMA_ACM_SAI1_MCLK_SEL 14
+#define IMX_ADMA_ACM_SAI2_MCLK_SEL 15
+#define IMX_ADMA_ACM_SAI3_MCLK_SEL 16
+#define IMX_ADMA_ACM_SAI4_MCLK_SEL 17
+#define IMX_ADMA_ACM_SAI5_MCLK_SEL 18
+#define IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL 19
+#define IMX_ADMA_ACM_MQS_TX_CLK_SEL 20
+#define IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL 21
+#define IMX_ADMA_ACM_ASRC1_MUX_CLK_SEL 22
+
+#define IMX_ADMA_EXT_AUD_MCLK0 23
+#define IMX_ADMA_EXT_AUD_MCLK1 24
+#define IMX_ADMA_ESAI0_RX_CLK 25
+#define IMX_ADMA_ESAI0_RX_HF_CLK 26
+#define IMX_ADMA_ESAI0_TX_CLK 27
+#define IMX_ADMA_ESAI0_TX_HF_CLK 28
+#define IMX_ADMA_SPDIF0_RX 29
+#define IMX_ADMA_SAI0_RX_BCLK 30
+#define IMX_ADMA_SAI0_TX_BCLK 31
+#define IMX_ADMA_SAI1_RX_BCLK 32
+#define IMX_ADMA_SAI1_TX_BCLK 33
+#define IMX_ADMA_SAI2_RX_BCLK 34
+#define IMX_ADMA_SAI3_RX_BCLK 35
+#define IMX_ADMA_SAI4_RX_BCLK 36
+#define IMX_ADMA_SAI5_TX_BCLK 37
+#define IMX_ADMA_SAI6_RX_BCLK 38
+#define IMX_ADMA_HDMI_RX_MCLK 39
+#define IMX_ADMA_MLB_CLK 40
+#define IMX_ADMA_SPDIF1_RX 41
+#define IMX_ADMA_ESAI1_RX_CLK 42
+#define IMX_ADMA_ESAI1_RX_HF_CLK 43
+#define IMX_ADMA_ESAI1_TX_CLK 44
+#define IMX_ADMA_ESAI1_TX_HF_CLK 45
+
+#define IMX_ADMA_ACM_ESAI1_MCLK_SEL 46
+#define IMX_ADMA_ACM_SAI6_MCLK_SEL 47
+#define IMX_ADMA_ACM_SAI7_MCLK_SEL 48
+#define IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL 49
+
+#define IMX_ADMA_ACM_CLK_END 50
#endif /* __DT_BINDINGS_CLOCK_IMX_H */
diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h
index 65463673d25e..ee2eb2bef7c1 100644
--- a/include/dt-bindings/clock/imx8mq-clock.h
+++ b/include/dt-bindings/clock/imx8mq-clock.h
@@ -403,5 +403,9 @@
#define IMX8MQ_CLK_SNVS_ROOT 264
#define IMX8MQ_CLK_GIC 265
-#define IMX8MQ_CLK_END 266
+#define IMX8MQ_VIDEO2_PLL1_REF_SEL 266
+
+#define IMX8MQ_CLK_PHY_27MHZ 267
+
+#define IMX8MQ_CLK_END 268
#endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */
diff --git a/include/dt-bindings/clock/s32v234-clock.h b/include/dt-bindings/clock/s32v234-clock.h
new file mode 100644
index 000000000000..1ddfae5c1422
--- /dev/null
+++ b/include/dt-bindings/clock/s32v234-clock.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_S32V234_H
+#define __DT_BINDINGS_CLOCK_S32V234_H
+
+#define S32V234_CLK_DUMMY 0
+#define S32V234_CLK_FXOSC 1
+#define S32V234_CLK_FIRC 2
+/* PERIPH PLL */
+#define S32V234_CLK_PERIPHPLL_SRC_SEL 3
+#define S32V234_CLK_PERIPHPLL_VCO 4
+#define S32V234_CLK_PERIPHPLL_PHI0 5
+#define S32V234_CLK_PERIPHPLL_PHI0_DIV3 6
+#define S32V234_CLK_PERIPHPLL_PHI0_DIV5 7
+#define S32V234_CLK_PERIPHPLL_PHI1 8
+/* LINFlexD Clock */
+#define S32V234_CLK_LIN 9
+#define S32V234_CLK_LIN_SEL 10
+#define S32V234_CLK_LIN_IPG 11
+/* SDHC Clock */
+#define S32V234_CLK_SDHC 12
+#define S32V234_CLK_SDHC_SEL 13
+/* ENET PLL */
+#define S32V234_CLK_ENETPLL_SRC_SEL 14
+#define S32V234_CLK_ENETPLL_VCO 15
+#define S32V234_CLK_ENETPLL_PHI0 16
+#define S32V234_CLK_ENETPLL_PHI1 17
+#define S32V234_CLK_ENETPLL_DFS0 18
+#define S32V234_CLK_ENETPLL_DFS1 19
+#define S32V234_CLK_ENETPLL_DFS2 20
+#define S32V234_CLK_ENETPLL_DFS3 21
+/* System Clock */
+#define S32V234_CLK_SYS_SEL 22
+#define S32V234_CLK_SYS3 23
+#define S32V234_CLK_SYS6 24
+#define S32V234_CLK_SYS6_DIV2 25
+/* ENET Clock */
+#define S32V234_CLK_ENET_TIME_DIV 26
+#define S32V234_CLK_ENET_TIME_SEL 27
+#define S32V234_CLK_ENET_DIV 28
+#define S32V234_CLK_ENET_SEL 29
+
+#define S32V234_CLK_ENET 30
+#define S32V234_CLK_ENET_TIME 31
+
+/* ARM PLL */
+#define S32V234_CLK_ARMPLL_SRC_SEL 32
+#define S32V234_CLK_ARMPLL_VCO 33
+#define S32V234_CLK_ARMPLL_PHI0 34
+#define S32V234_CLK_ARMPLL_PHI1 35
+#define S32V234_CLK_ARMPLL_DFS0 35
+#define S32V234_CLK_ARMPLL_DFS1 36
+#define S32V234_CLK_ARMPLL_DFS2 37
+
+/* CAN Clock */
+#define S32V234_CLK_CAN 38
+#define S32V234_CLK_CAN_SEL 39
+
+#define S32V234_CLK_END 40
+
+#endif /* __DT_BINDINGS_CLOCK_S32V234_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 2fdfe8061363..30b61ec0e167 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -32,6 +32,7 @@
#define CLK_OPS_PARENT_ENABLE BIT(12)
/* duty cycle call may be forwarded to the parent clock */
#define CLK_DUTY_CYCLE_PARENT BIT(13)
+#define CLK_SET_PARENT_NOCACHE BIT(14) /* do not use the cached clk parent */
struct clk;
struct clk_hw;
diff --git a/include/soc/imx/gpc.h b/include/soc/imx/gpc.h
new file mode 100644
index 000000000000..6a976e6aa3fe
--- /dev/null
+++ b/include/soc/imx/gpc.h
@@ -0,0 +1,7 @@
+#ifndef __SOC_IMX_GPC_H
+#define __SOC_IMX_GPC_H
+
+void imx_gpc_hold_m4_in_sleep(void);
+void imx_gpc_release_m4_in_sleep(void);
+
+#endif /* __SOC_IMX_GPC_H */
diff --git a/include/soc/imx/src.h b/include/soc/imx/src.h
new file mode 100644
index 000000000000..c55c34cd2366
--- /dev/null
+++ b/include/soc/imx/src.h
@@ -0,0 +1,6 @@
+#ifndef __SOC_IMX_SRC_H
+#define __SOC_IMX_SRC_H
+
+bool imx_src_is_m4_enabled(void);
+
+#endif /* __SOC_IMX_SRC_H */