[PATCH] imx: add imx8 support

Tim Harvey tharvey at gateworks.com
Wed Mar 8 16:20:31 PST 2023


Add imx8 support:
 - add a cortexa53 subtarget
 - move ARCH, KERNELNAME, and some FEATURES to cortexa7/cortexa9 subtargets
 - add a small series of backports from 6.2 to fix hang on USB init and
   add PCIe support

No device-specific targets or firmware images are created yet.

The resulting openwrt-imx-cortexa53-vmlinux-initramfs has been booted on
Gateworks Venice boards and the imx8mm-evk using dtb's from $LINUX_DIR
and verifying usb, pci, mmc, and fec networking work.

Signed-off-by: Tim Harvey <tharvey at gateworks.com>
---
 target/linux/imx/Makefile                     |   7 +-
 target/linux/imx/config-5.15                  |   2 +
 target/linux/imx/cortexa53/config-default     |  89 ++++
 target/linux/imx/cortexa53/target.mk          |   8 +
 target/linux/imx/cortexa7/target.mk           |   3 +
 target/linux/imx/cortexa9/target.mk           |   3 +
 target/linux/imx/image/cortexa53.mk           |  10 +
 ...low-to-disable-individual-power-doma.patch |  35 ++
 ...-gpcv2-Turn-domain-pgc-into-bitfield.patch | 327 +++++++++++++
 ...t-both-GPC_PGC_nCTRL-GPU_2D-GPU_3D-f.patch |  40 ++
 ...soc-imx-gpcv2-add-lockdep-annotation.patch |  36 ++
 ...d-domain-option-to-keep-domain-clock.patch |  60 +++
 ...gpcv2-keep-i.MX8M-bus-clocks-enabled.patch |  69 +++
 ...-gpcv2-support-system-suspend-resume.patch |  74 +++
 .../0008-arm64-dts-imx8mm-add-GPC-node.patch  | 142 ++++++
 ...-put-USB-controllers-into-power-doma.patch |  38 ++
 ...add-PGC-control-register-indirection.patch | 187 ++++++++
 ...ie-Initialize-the-imx8-pcie-standalo.patch | 285 ++++++++++++
 ...x8m-pcie-Add-iMX8MP-PCIe-PHY-support.patch | 305 ++++++++++++
 ...phy-imx8-pcie-Add-binding-for-the-pa.patch |  38 ++
 ...-PCI-imx-Add-the-imx8mm-pcie-support.patch | 211 +++++++++
 ...-dts-imx8mm-Add-the-pcie-phy-support.patch |  40 ++
 ...rm64-dts-imx8mm-Add-the-pcie-support.patch |  67 +++
 ...4-dts-imx8mm-venice-add-PCIe-support.patch | 437 ++++++++++++++++++
 24 files changed, 2508 insertions(+), 5 deletions(-)
 create mode 100644 target/linux/imx/cortexa53/config-default
 create mode 100644 target/linux/imx/cortexa53/target.mk
 create mode 100644 target/linux/imx/image/cortexa53.mk
 create mode 100644 target/linux/imx/patches-5.15/0001-soc-imx-gpcv2-allow-to-disable-individual-power-doma.patch
 create mode 100644 target/linux/imx/patches-5.15/0002-soc-imx-gpcv2-Turn-domain-pgc-into-bitfield.patch
 create mode 100644 target/linux/imx/patches-5.15/0003-soc-imx-gpcv2-Set-both-GPC_PGC_nCTRL-GPU_2D-GPU_3D-f.patch
 create mode 100644 target/linux/imx/patches-5.15/0004-soc-imx-gpcv2-add-lockdep-annotation.patch
 create mode 100644 target/linux/imx/patches-5.15/0005-soc-imx-gpcv2-add-domain-option-to-keep-domain-clock.patch
 create mode 100644 target/linux/imx/patches-5.15/0006-soc-imx-gpcv2-keep-i.MX8M-bus-clocks-enabled.patch
 create mode 100644 target/linux/imx/patches-5.15/0007-soc-imx-gpcv2-support-system-suspend-resume.patch
 create mode 100644 target/linux/imx/patches-5.15/0008-arm64-dts-imx8mm-add-GPC-node.patch
 create mode 100644 target/linux/imx/patches-5.15/0009-arm64-dts-imx8mm-put-USB-controllers-into-power-doma.patch
 create mode 100644 target/linux/imx/patches-5.15/0010-soc-imx-gpcv2-add-PGC-control-register-indirection.patch
 create mode 100644 target/linux/imx/patches-5.15/0011-phy-freescale-pcie-Initialize-the-imx8-pcie-standalo.patch
 create mode 100644 target/linux/imx/patches-5.15/0012-phy-freescale-imx8m-pcie-Add-iMX8MP-PCIe-PHY-support.patch
 create mode 100644 target/linux/imx/patches-5.15/0013-dt-bindings-phy-phy-imx8-pcie-Add-binding-for-the-pa.patch
 create mode 100644 target/linux/imx/patches-5.15/0014-PCI-imx-Add-the-imx8mm-pcie-support.patch
 create mode 100644 target/linux/imx/patches-5.15/0015-arm64-dts-imx8mm-Add-the-pcie-phy-support.patch
 create mode 100644 target/linux/imx/patches-5.15/0016-arm64-dts-imx8mm-Add-the-pcie-support.patch
 create mode 100644 target/linux/imx/patches-5.15/0017-arm64-dts-imx8mm-venice-add-PCIe-support.patch

diff --git a/target/linux/imx/Makefile b/target/linux/imx/Makefile
index 5fb7a4d339ef..1263484316c4 100644
--- a/target/linux/imx/Makefile
+++ b/target/linux/imx/Makefile
@@ -4,18 +4,15 @@
 
 include $(TOPDIR)/rules.mk
 
-ARCH:=arm
 BOARD:=imx
 BOARDNAME:=NXP i.MX
-FEATURES:=audio display fpu gpio pcie rtc usb usbgadget squashfs targz nand ubifs boot-part rootfs-part
-SUBTARGETS:=cortexa7 cortexa9
+FEATURES:=audio display fpu gpio pcie rtc usb usbgadget squashfs targz boot-part rootfs-part
+SUBTARGETS:=cortexa7 cortexa9 cortexa53
 
 KERNEL_PATCHVER:=5.15
 
 include $(INCLUDE_DIR)/target.mk
 
-KERNELNAME:=zImage dtbs
-
 DEFAULT_PACKAGES += uboot-envtools mkf2fs e2fsprogs blkid
 
 $(eval $(call BuildTarget))
diff --git a/target/linux/imx/config-5.15 b/target/linux/imx/config-5.15
index 0c9b7d22b4e5..c45872d19c40 100644
--- a/target/linux/imx/config-5.15
+++ b/target/linux/imx/config-5.15
@@ -441,3 +441,5 @@ CONFIG_ZLIB_DEFLATE=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZSTD_COMPRESS=y
 CONFIG_ZSTD_DECOMPRESS=y
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_PHY_FSL_IMX8M_PCIE is not set
diff --git a/target/linux/imx/cortexa53/config-default b/target/linux/imx/cortexa53/config-default
new file mode 100644
index 000000000000..b91928f8ec1a
--- /dev/null
+++ b/target/linux/imx/cortexa53/config-default
@@ -0,0 +1,89 @@
+CONFIG_64BIT=y
+CONFIG_ARM64=y
+CONFIG_ARM64_4K_PAGES=y
+CONFIG_ARM64_VA_BITS_39=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_AES_ARM64=y
+CONFIG_CRYPTO_AES_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_BLAKE2S=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA256_ARM64=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_SHA512_ARM64=y
+CONFIG_CRYPTO_SHA512_ARM64_CE=y
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_UNMAP_KERNEL_AT_EL0=y
+CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
+CONFIG_ARM64_TAGGED_ADDR_ABI=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_VMAP_STACK=y
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_CMA=y
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+# CONFIG_CMA_SYSFS is not set
+CONFIG_CONTIG_ALLOC=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ARM_IMX_CPUFREQ_DT=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_EXTRA_FIRMWARE="imx/sdma/sdma-imx7d.bin"
+CONFIG_EXTRA_FIRMWARE_DIR="firmware"
+CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_PME=y
+CONFIG_PHY_FSL_IMX8M_PCIE=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_DW=y
+CONFIG_PCIE_DW_HOST=y
+CONFIG_PCIE_PME=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_IMX6=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PINCTRL_IMX=y
+CONFIG_DWMAC_DWC_QOS_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINCTRL_IMX=y
+CONFIG_PINCTRL_IMX8MM=y
+CONFIG_PINCTRL_IMX8MN=y
+CONFIG_PINCTRL_IMX8MP=y
+CONFIG_PINCTRL_IMX8MQ=y
+CONFIG_THERMAL=y
+CONFIG_IMX8MM_THERMAL=y
+CONFIG_REGULATOR_MP5416=y
+CONFIG_REGULATOR_PCA9450=y
+CONFIG_USB_CONN_GPIO=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_OTG=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_DUAL_ROLE=y
+# CONFIG_USB_DWC3_GADGET is not set
+# CONFIG_USB_DWC3_HOST is not set
+CONFIG_USB_DWC3_IMX8MP=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_CLK_IMX8MM=y
+CONFIG_CLK_IMX8MN=y
+CONFIG_CLK_IMX8MP=y
+CONFIG_CLK_IMX8MQ=y
+CONFIG_CLK_IMX8QXP=y
+CONFIG_SOC_IMX8M=y
+# CONFIG_IMX_DSP is not set
+# CONFIG_IMX_SCU is not set
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_PHY_FSL_IMX8MQ_USB=y
+CONFIG_RESET_IMX7=y
+CONFIG_INTERCONNECT=y
+CONFIG_INTERCONNECT_IMX=y
+CONFIG_INTERCONNECT_IMX8MM=y
+CONFIG_INTERCONNECT_IMX8MN=y
+CONFIG_INTERCONNECT_IMX8MQ=y
+# CONFIG_DMA_CMA is not set
diff --git a/target/linux/imx/cortexa53/target.mk b/target/linux/imx/cortexa53/target.mk
new file mode 100644
index 000000000000..b9b32d182905
--- /dev/null
+++ b/target/linux/imx/cortexa53/target.mk
@@ -0,0 +1,8 @@
+ARCH:=aarch64
+BOARDNAME:=NXP i.MX with Cortex-A53 (ARM64)
+CPU_TYPE:=cortex-a53
+KERNELNAME:=Image dtbs
+
+define Target/Description
+	Build firmware images for NXP i.MX (Cortex-A53) based boards.
+endef
diff --git a/target/linux/imx/cortexa7/target.mk b/target/linux/imx/cortexa7/target.mk
index 11de87507d3f..708c6e2bfbb5 100644
--- a/target/linux/imx/cortexa7/target.mk
+++ b/target/linux/imx/cortexa7/target.mk
@@ -1,6 +1,9 @@
+ARCH:=arm
 BOARDNAME:=NXP i.MX with Cortex-A7
 CPU_TYPE:=cortex-a7
 CPU_SUBTYPE:=neon-vfpv4
+KERNELNAME:=zImage dtbs
+FEATURES+=nand ubifs
 
 define Target/Description
 	Build firmware images for NXP i.MX (Cortex-A7) based boards.
diff --git a/target/linux/imx/cortexa9/target.mk b/target/linux/imx/cortexa9/target.mk
index 9bd63c7be1cf..fc88486ca3cd 100644
--- a/target/linux/imx/cortexa9/target.mk
+++ b/target/linux/imx/cortexa9/target.mk
@@ -1,6 +1,9 @@
+ARCH:=arm
 BOARDNAME:=NXP i.MX with Cortex-A9
 CPU_TYPE:=cortex-a9
 CPU_SUBTYPE:=neon
+KERNELNAME:=zImage dtbs
+FEATURES+=nand ubifs
 
 define Target/Description
 	Build firmware images for NXP i.MX (Cortex-A9) based boards.
diff --git a/target/linux/imx/image/cortexa53.mk b/target/linux/imx/image/cortexa53.mk
new file mode 100644
index 000000000000..8a5ca8a46c02
--- /dev/null
+++ b/target/linux/imx/image/cortexa53.mk
@@ -0,0 +1,10 @@
+define Image/Build/Initramfs
+	$(CP) $(KERNEL_BUILD_DIR)/vmlinux $(BIN_DIR)/$(IMG_PREFIX)-vmlinux
+	$(CP) $(KERNEL_BUILD_DIR)/vmlinux-initramfs $(BIN_DIR)/$(IMG_PREFIX)-vmlinux-initramfs
+endef
+
+define Image/Build
+	$(call Image/Build/$(1))
+	cp $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).img
+	cp $(KDIR)/vmlinux $(BIN_DIR)/$(IMG_PREFIX)-vmlinux
+endef
diff --git a/target/linux/imx/patches-5.15/0001-soc-imx-gpcv2-allow-to-disable-individual-power-doma.patch b/target/linux/imx/patches-5.15/0001-soc-imx-gpcv2-allow-to-disable-individual-power-doma.patch
new file mode 100644
index 000000000000..a092ba497edc
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0001-soc-imx-gpcv2-allow-to-disable-individual-power-doma.patch
@@ -0,0 +1,35 @@
+From 43ae58d3793a9275d45d9735d012ed7455fbafbb Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 14:48:52 +0200
+Subject: [PATCH 01/17] soc: imx: gpcv2: allow to disable individual power
+ domains
+
+Some board designs don't supply power to all of the power domains,
+as they are not used anyways. In that case we must make sure to
+not touch those power domains at all, as trying to power up a
+domain that has no power supplied to it will obviously end in a
+system crash. Allow to disable those domains via the standard DT
+status property.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+---
+ drivers/soc/imx/gpcv2.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 4dc3a3f73511..60566bdcb51f 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -989,6 +989,9 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
+ 		struct imx_pgc_domain *domain;
+ 		u32 domain_index;
+ 
++		if (!of_device_is_available(np))
++			continue;
++
+ 		ret = of_property_read_u32(np, "reg", &domain_index);
+ 		if (ret) {
+ 			dev_err(dev, "Failed to read 'reg' property\n");
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0002-soc-imx-gpcv2-Turn-domain-pgc-into-bitfield.patch b/target/linux/imx/patches-5.15/0002-soc-imx-gpcv2-Turn-domain-pgc-into-bitfield.patch
new file mode 100644
index 000000000000..b1ec4c7beaa2
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0002-soc-imx-gpcv2-Turn-domain-pgc-into-bitfield.patch
@@ -0,0 +1,327 @@
+From 6dbb5cd7006a5382ab02282b7b39e0edc8e15331 Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marex at denx.de>
+Date: Sat, 2 Oct 2021 02:59:38 +0200
+Subject: [PATCH 02/17] soc: imx: gpcv2: Turn domain->pgc into bitfield
+
+There is currently the MX8MM GPU domain, which is in fact a composite domain
+for both GPU2D and GPU3D. To correctly configure this domain, it is necessary
+to control both GPC_PGC_nCTRL(GPU_2D) and GPC_PGC_nCTRL(GPU_3D) at the same
+time. This is currently not possible.
+
+Turn the domain->pgc from value into bitfield and use for_each_set_bit() to
+iterate over all bits set in domain->pgc when configuring GPC_PGC_nCTRL
+register array. This way it is possible to configure all GPC_PGC_nCTRL
+registers required in a particular domain.
+
+This is a preparatory patch, no functional change.
+
+Signed-off-by: Marek Vasut <marex at denx.de>
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 72 ++++++++++++++++++++++-------------------
+ 1 file changed, 38 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 60566bdcb51f..8341b03eec92 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -192,7 +192,7 @@ struct imx_pgc_domain {
+ 	struct clk_bulk_data *clks;
+ 	int num_clks;
+ 
+-	unsigned int pgc;
++	unsigned long pgc;
+ 
+ 	const struct {
+ 		u32 pxx;
+@@ -220,7 +220,7 @@ to_imx_pgc_domain(struct generic_pm_domain *genpd)
+ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ {
+ 	struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
+-	u32 reg_val;
++	u32 reg_val, pgc;
+ 	int ret;
+ 
+ 	ret = pm_runtime_get_sync(domain->dev);
+@@ -267,8 +267,10 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ 		}
+ 
+ 		/* disable power control */
+-		regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
+-				  GPC_PGC_CTRL_PCR);
++		for_each_set_bit(pgc, &domain->pgc, 32) {
++			regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(pgc),
++					  GPC_PGC_CTRL_PCR);
++		}
+ 	}
+ 
+ 	/* delay for reset to propagate */
+@@ -314,7 +316,7 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
+ {
+ 	struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
+-	u32 reg_val;
++	u32 reg_val, pgc;
+ 	int ret;
+ 
+ 	/* Enable reset clocks for all devices in the domain */
+@@ -341,8 +343,10 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
+ 
+ 	if (domain->bits.pxx) {
+ 		/* enable power control */
+-		regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
+-				   GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
++		for_each_set_bit(pgc, &domain->pgc, 32) {
++			regmap_update_bits(domain->regmap, GPC_PGC_CTRL(pgc),
++					   GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
++		}
+ 
+ 		/* request the domain to power down */
+ 		regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ,
+@@ -392,7 +396,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
+ 			.map = IMX7_MIPI_PHY_A_CORE_DOMAIN,
+ 		},
+ 		.voltage   = 1000000,
+-		.pgc	   = IMX7_PGC_MIPI,
++		.pgc	   = BIT(IMX7_PGC_MIPI),
+ 	},
+ 
+ 	[IMX7_POWER_DOMAIN_PCIE_PHY] = {
+@@ -404,7 +408,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
+ 			.map = IMX7_PCIE_PHY_A_CORE_DOMAIN,
+ 		},
+ 		.voltage   = 1000000,
+-		.pgc	   = IMX7_PGC_PCIE,
++		.pgc	   = BIT(IMX7_PGC_PCIE),
+ 	},
+ 
+ 	[IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
+@@ -416,7 +420,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
+ 			.map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,
+ 		},
+ 		.voltage   = 1200000,
+-		.pgc	   = IMX7_PGC_USB_HSIC,
++		.pgc	   = BIT(IMX7_PGC_USB_HSIC),
+ 	},
+ };
+ 
+@@ -451,7 +455,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_MIPI_SW_Pxx_REQ,
+ 			.map = IMX8M_MIPI_A53_DOMAIN,
+ 		},
+-		.pgc	   = IMX8M_PGC_MIPI,
++		.pgc	   = BIT(IMX8M_PGC_MIPI),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_PCIE1] = {
+@@ -462,7 +466,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_PCIE1_SW_Pxx_REQ,
+ 			.map = IMX8M_PCIE1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_PCIE1,
++		.pgc   = BIT(IMX8M_PGC_PCIE1),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_USB_OTG1] = {
+@@ -473,7 +477,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_OTG1_SW_Pxx_REQ,
+ 			.map = IMX8M_OTG1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_OTG1,
++		.pgc   = BIT(IMX8M_PGC_OTG1),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_USB_OTG2] = {
+@@ -484,7 +488,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_OTG2_SW_Pxx_REQ,
+ 			.map = IMX8M_OTG2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_OTG2,
++		.pgc   = BIT(IMX8M_PGC_OTG2),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_DDR1] = {
+@@ -495,7 +499,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_DDR1_SW_Pxx_REQ,
+ 			.map = IMX8M_DDR2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_DDR1,
++		.pgc   = BIT(IMX8M_PGC_DDR1),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_GPU] = {
+@@ -508,7 +512,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.hskreq = IMX8M_GPU_HSK_PWRDNREQN,
+ 			.hskack = IMX8M_GPU_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8M_PGC_GPU,
++		.pgc   = BIT(IMX8M_PGC_GPU),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_VPU] = {
+@@ -521,7 +525,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.hskreq = IMX8M_VPU_HSK_PWRDNREQN,
+ 			.hskack = IMX8M_VPU_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8M_PGC_VPU,
++		.pgc   = BIT(IMX8M_PGC_VPU),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_DISP] = {
+@@ -534,7 +538,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.hskreq = IMX8M_DISP_HSK_PWRDNREQN,
+ 			.hskack = IMX8M_DISP_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8M_PGC_DISP,
++		.pgc   = BIT(IMX8M_PGC_DISP),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
+@@ -545,7 +549,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
+ 			.map = IMX8M_MIPI_CSI1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_MIPI_CSI1,
++		.pgc   = BIT(IMX8M_PGC_MIPI_CSI1),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
+@@ -556,7 +560,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
+ 			.map = IMX8M_MIPI_CSI2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_MIPI_CSI2,
++		.pgc   = BIT(IMX8M_PGC_MIPI_CSI2),
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_PCIE2] = {
+@@ -567,7 +571,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.pxx = IMX8M_PCIE2_SW_Pxx_REQ,
+ 			.map = IMX8M_PCIE2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8M_PGC_PCIE2,
++		.pgc   = BIT(IMX8M_PGC_PCIE2),
+ 	},
+ };
+ 
+@@ -630,7 +634,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_PCIE_SW_Pxx_REQ,
+ 			.map = IMX8MM_PCIE_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_PCIE,
++		.pgc   = BIT(IMX8MM_PGC_PCIE),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_OTG1] = {
+@@ -641,7 +645,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_OTG1_SW_Pxx_REQ,
+ 			.map = IMX8MM_OTG1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_OTG1,
++		.pgc   = BIT(IMX8MM_PGC_OTG1),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_OTG2] = {
+@@ -652,7 +656,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_OTG2_SW_Pxx_REQ,
+ 			.map = IMX8MM_OTG2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_OTG2,
++		.pgc   = BIT(IMX8MM_PGC_OTG2),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_GPUMIX] = {
+@@ -665,7 +669,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8MM_PGC_GPUMIX,
++		.pgc   = BIT(IMX8MM_PGC_GPUMIX),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_GPU] = {
+@@ -678,7 +682,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_GPU_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8MM_PGC_GPU2D,
++		.pgc   = BIT(IMX8MM_PGC_GPU2D),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUMIX] = {
+@@ -691,7 +695,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8MM_PGC_VPUMIX,
++		.pgc   = BIT(IMX8MM_PGC_VPUMIX),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUG1] = {
+@@ -702,7 +706,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_VPUG1_SW_Pxx_REQ,
+ 			.map = IMX8MM_VPUG1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_VPUG1,
++		.pgc   = BIT(IMX8MM_PGC_VPUG1),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUG2] = {
+@@ -713,7 +717,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_VPUG2_SW_Pxx_REQ,
+ 			.map = IMX8MM_VPUG2_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_VPUG2,
++		.pgc   = BIT(IMX8MM_PGC_VPUG2),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUH1] = {
+@@ -724,7 +728,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_VPUH1_SW_Pxx_REQ,
+ 			.map = IMX8MM_VPUH1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_VPUH1,
++		.pgc   = BIT(IMX8MM_PGC_VPUH1),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_DISPMIX] = {
+@@ -737,7 +741,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8MM_PGC_DISPMIX,
++		.pgc   = BIT(IMX8MM_PGC_DISPMIX),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_MIPI] = {
+@@ -748,7 +752,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.pxx = IMX8MM_MIPI_SW_Pxx_REQ,
+ 			.map = IMX8MM_MIPI_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MM_PGC_MIPI,
++		.pgc   = BIT(IMX8MM_PGC_MIPI),
+ 	},
+ };
+ 
+@@ -815,7 +819,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
+ 			.pxx = IMX8MN_OTG1_SW_Pxx_REQ,
+ 			.map = IMX8MN_OTG1_A53_DOMAIN,
+ 		},
+-		.pgc   = IMX8MN_PGC_OTG1,
++		.pgc   = BIT(IMX8MN_PGC_OTG1),
+ 	},
+ 
+ 	[IMX8MN_POWER_DOMAIN_GPUMIX] = {
+@@ -828,7 +832,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
+ 			.hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,
+ 			.hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = IMX8MN_PGC_GPUMIX,
++		.pgc   = BIT(IMX8MN_PGC_GPUMIX),
+ 	},
+ };
+ 
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0003-soc-imx-gpcv2-Set-both-GPC_PGC_nCTRL-GPU_2D-GPU_3D-f.patch b/target/linux/imx/patches-5.15/0003-soc-imx-gpcv2-Set-both-GPC_PGC_nCTRL-GPU_2D-GPU_3D-f.patch
new file mode 100644
index 000000000000..4ea5b3b0b0ff
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0003-soc-imx-gpcv2-Set-both-GPC_PGC_nCTRL-GPU_2D-GPU_3D-f.patch
@@ -0,0 +1,40 @@
+From f05c5d9450c83ab64a7e313ada06129721f29c7f Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marex at denx.de>
+Date: Sat, 2 Oct 2021 02:59:39 +0200
+Subject: [PATCH 03/17] soc: imx: gpcv2: Set both GPC_PGC_nCTRL(GPU_2D|GPU_3D)
+ for MX8MM GPU domain
+
+To bring up the MX8MM GPU domain, it is necessary to configure both
+GPC_PGC_nCTRL(GPU_2D) and GPC_PGC_nCTRL(GPU_3D) registers. Without
+this configuration, the system might hang on boot when bringing up
+the GPU power domain. This is sporadically observed on multiple
+disparate systems.
+
+Add the GPU3D bit into MX8MM GPU domain pgc bitfield, so that both
+GPC_PGC_nCTRL(GPU_2D) and GPC_PGC_nCTRL(GPU_3D) registers are
+configured when bringing up the GPU domain. This fixes the sporadic
+hang.
+
+Signed-off-by: Marek Vasut <marex at denx.de>
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 8341b03eec92..afc309aff0f0 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -682,7 +682,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_GPU_HSK_PWRDNACKN,
+ 		},
+-		.pgc   = BIT(IMX8MM_PGC_GPU2D),
++		.pgc   = BIT(IMX8MM_PGC_GPU2D) | BIT(IMX8MM_PGC_GPU3D),
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUMIX] = {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0004-soc-imx-gpcv2-add-lockdep-annotation.patch b/target/linux/imx/patches-5.15/0004-soc-imx-gpcv2-add-lockdep-annotation.patch
new file mode 100644
index 000000000000..6da19e0be772
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0004-soc-imx-gpcv2-add-lockdep-annotation.patch
@@ -0,0 +1,36 @@
+From 9cdd2d0a39b60929a30b1642e67441ef748509cc Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:40 +0200
+Subject: [PATCH 04/17] soc: imx: gpcv2: add lockdep annotation
+
+Some of the GPCv2 power domains are nested inside each other without
+visibility to lockdep at the genpd level, as they are in separate
+driver instances and don't have a parent/child power-domain relationship.
+
+Add a subclass annotation to the nested domains to let lockdep know that
+it is okay to take the genpd lock in a nested fashion.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index afc309aff0f0..2761e81abb40 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -901,6 +901,10 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
+ 		goto out_domain_unmap;
+ 	}
+ 
++	if (IS_ENABLED(CONFIG_LOCKDEP) &&
++	    of_property_read_bool(domain->dev->of_node, "power-domains"))
++		lockdep_set_subclass(&domain->genpd.mlock, 1);
++
+ 	ret = of_genpd_add_provider_simple(domain->dev->of_node,
+ 					   &domain->genpd);
+ 	if (ret) {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0005-soc-imx-gpcv2-add-domain-option-to-keep-domain-clock.patch b/target/linux/imx/patches-5.15/0005-soc-imx-gpcv2-add-domain-option-to-keep-domain-clock.patch
new file mode 100644
index 000000000000..b14fe8b90467
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0005-soc-imx-gpcv2-add-domain-option-to-keep-domain-clock.patch
@@ -0,0 +1,60 @@
+From a6ac7c30d1664e6b7336b6bee44c97347c916af4 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:41 +0200
+Subject: [PATCH 05/17] soc: imx: gpcv2: add domain option to keep domain
+ clocks enabled
+
+Some of the MIX domains are using clocks to drive the bus bridges. Those
+must be enabled at all times, as long as the domain is powered up and
+they don't have any other consumer than the power domain. Add an option
+to keep the clocks attached to a domain enabled as long as the domain
+is power up and only disable them after the domain is powered down.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 2761e81abb40..7e7826bbd3dc 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -202,6 +202,7 @@ struct imx_pgc_domain {
+ 	} bits;
+ 
+ 	const int voltage;
++	const bool keep_clocks;
+ 	struct device *dev;
+ };
+ 
+@@ -298,7 +299,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ 	}
+ 
+ 	/* Disable reset clocks for all devices in the domain */
+-	clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
++	if (!domain->keep_clocks)
++		clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+ 
+ 	return 0;
+ 
+@@ -320,10 +322,12 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
+ 	int ret;
+ 
+ 	/* Enable reset clocks for all devices in the domain */
+-	ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
+-	if (ret) {
+-		dev_err(domain->dev, "failed to enable reset clocks\n");
+-		return ret;
++	if (!domain->keep_clocks) {
++		ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
++		if (ret) {
++			dev_err(domain->dev, "failed to enable reset clocks\n");
++			return ret;
++		}
+ 	}
+ 
+ 	/* request the ADB400 to power down */
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0006-soc-imx-gpcv2-keep-i.MX8M-bus-clocks-enabled.patch b/target/linux/imx/patches-5.15/0006-soc-imx-gpcv2-keep-i.MX8M-bus-clocks-enabled.patch
new file mode 100644
index 000000000000..9abf099ae915
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0006-soc-imx-gpcv2-keep-i.MX8M-bus-clocks-enabled.patch
@@ -0,0 +1,69 @@
+From b2a1ee027619413d42cdb3a02459500c9f6f035a Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:42 +0200
+Subject: [PATCH 06/17] soc: imx: gpcv2: keep i.MX8M* bus clocks enabled
+
+Annotate the domains with bus clocks to keep those clocks enabled
+as long as the domain is active.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 7e7826bbd3dc..85a922e36f0f 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -530,6 +530,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ 			.hskack = IMX8M_VPU_HSK_PWRDNACKN,
+ 		},
+ 		.pgc   = BIT(IMX8M_PGC_VPU),
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8M_POWER_DOMAIN_DISP] = {
+@@ -628,6 +629,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,
+ 			.hskack = IMX8MM_HSIO_HSK_PWRDNACKN,
+ 		},
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_PCIE] = {
+@@ -674,6 +676,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
+ 		},
+ 		.pgc   = BIT(IMX8MM_PGC_GPUMIX),
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_GPU] = {
+@@ -700,6 +703,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
+ 		},
+ 		.pgc   = BIT(IMX8MM_PGC_VPUMIX),
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_VPUG1] = {
+@@ -746,6 +750,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ 			.hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
+ 		},
+ 		.pgc   = BIT(IMX8MM_PGC_DISPMIX),
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8MM_POWER_DOMAIN_MIPI] = {
+@@ -813,6 +818,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
+ 			.hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,
+ 			.hskack = IMX8MN_HSIO_HSK_PWRDNACKN,
+ 		},
++		.keep_clocks = true,
+ 	},
+ 
+ 	[IMX8MN_POWER_DOMAIN_OTG1] = {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0007-soc-imx-gpcv2-support-system-suspend-resume.patch b/target/linux/imx/patches-5.15/0007-soc-imx-gpcv2-support-system-suspend-resume.patch
new file mode 100644
index 000000000000..6ba284d2aba9
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0007-soc-imx-gpcv2-support-system-suspend-resume.patch
@@ -0,0 +1,74 @@
+From e651a2a4d3ea18fbcee49ff87902625b70644c24 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:43 +0200
+Subject: [PATCH 07/17] soc: imx: gpcv2: support system suspend/resume
+
+Our usage of runtime PM to control the hierarchy of power domains is
+slightly unusual and means that powering up a domain may fail in early
+system resume, as runtime PM is still disallowed at this stage.
+
+However the system suspend/resume path takes care of powering down/up
+the power domains in the order defined by the device parent/child and
+power-domain provider/consumer hierarachy. So we can just runtime
+resume all our power-domain devices to allow the power-up to work
+properly in the resume path. System suspend will still disable all
+domains as intended.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Acked-by: Peng Fan <peng.fan at nxp.com>
+---
+ drivers/soc/imx/gpcv2.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 85a922e36f0f..89e25e123c52 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -951,6 +951,36 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_PM_SLEEP
++static int imx_pgc_domain_suspend(struct device *dev)
++{
++	int ret;
++
++	/*
++	 * This may look strange, but is done so the generic PM_SLEEP code
++	 * can power down our domain and more importantly power it up again
++	 * after resume, without tripping over our usage of runtime PM to
++	 * power up/down the nested domains.
++	 */
++	ret = pm_runtime_get_sync(dev);
++	if (ret < 0) {
++		pm_runtime_put_noidle(dev);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int imx_pgc_domain_resume(struct device *dev)
++{
++	return pm_runtime_put(dev);
++}
++#endif
++
++static const struct dev_pm_ops imx_pgc_domain_pm_ops = {
++	SET_SYSTEM_SLEEP_PM_OPS(imx_pgc_domain_suspend, imx_pgc_domain_resume)
++};
++
+ static const struct platform_device_id imx_pgc_domain_id[] = {
+ 	{ "imx-pgc-domain", },
+ 	{ },
+@@ -959,6 +989,7 @@ static const struct platform_device_id imx_pgc_domain_id[] = {
+ static struct platform_driver imx_pgc_domain_driver = {
+ 	.driver = {
+ 		.name = "imx-pgc",
++		.pm = &imx_pgc_domain_pm_ops,
+ 	},
+ 	.probe    = imx_pgc_domain_probe,
+ 	.remove   = imx_pgc_domain_remove,
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0008-arm64-dts-imx8mm-add-GPC-node.patch b/target/linux/imx/patches-5.15/0008-arm64-dts-imx8mm-add-GPC-node.patch
new file mode 100644
index 000000000000..d7bb478745cc
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0008-arm64-dts-imx8mm-add-GPC-node.patch
@@ -0,0 +1,142 @@
+From 744143a80acaeeb10ab6cb1e703b78448ec25c16 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:50 +0200
+Subject: [PATCH 08/17] arm64: dts: imx8mm: add GPC node
+
+Add the DT node for the GPC, including all the PGC power domains,
+some of them are not fully functional yet, as they require interaction
+with the blk-ctrls to properly power up/down the peripherals.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+---
+ arch/arm64/boot/dts/freescale/imx8mm.dtsi | 107 ++++++++++++++++++++++
+ 1 file changed, 107 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+index 67e91fdfaf52..b339da5e0b02 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+@@ -7,6 +7,8 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/power/imx8mm-power.h>
++#include <dt-bindings/reset/imx8mq-reset.h>
+ #include <dt-bindings/thermal/thermal.h>
+ 
+ #include "imx8mm-pinfunc.h"
+@@ -610,6 +612,111 @@ src: reset-controller at 30390000 {
+ 				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ 				#reset-cells = <1>;
+ 			};
++
++			gpc: gpc at 303a0000 {
++				compatible = "fsl,imx8mm-gpc";
++				reg = <0x303a0000 0x10000>;
++				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
++				interrupt-parent = <&gic>;
++				interrupt-controller;
++				#interrupt-cells = <3>;
++
++				pgc {
++					#address-cells = <1>;
++					#size-cells = <0>;
++
++					pgc_hsiomix: power-domain at 0 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_HSIOMIX>;
++						clocks = <&clk IMX8MM_CLK_USB_BUS>;
++						assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>;
++						assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
++					};
++
++					pgc_pcie: power-domain at 1 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_PCIE>;
++						power-domains = <&pgc_hsiomix>;
++						clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>;
++					};
++
++					pgc_otg1: power-domain at 2 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_OTG1>;
++						power-domains = <&pgc_hsiomix>;
++					};
++
++					pgc_otg2: power-domain at 3 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_OTG2>;
++						power-domains = <&pgc_hsiomix>;
++					};
++
++					pgc_gpumix: power-domain at 4 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_GPUMIX>;
++						clocks = <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
++							 <&clk IMX8MM_CLK_GPU_AHB>;
++						assigned-clocks = <&clk IMX8MM_CLK_GPU_AXI>,
++								  <&clk IMX8MM_CLK_GPU_AHB>;
++						assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>,
++									 <&clk IMX8MM_SYS_PLL1_800M>;
++						assigned-clock-rates = <800000000>, <400000000>;
++					};
++
++					pgc_gpu: power-domain at 5 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_GPU>;
++						clocks = <&clk IMX8MM_CLK_GPU_AHB>,
++							 <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
++							 <&clk IMX8MM_CLK_GPU2D_ROOT>,
++							 <&clk IMX8MM_CLK_GPU3D_ROOT>;
++						resets = <&src IMX8MQ_RESET_GPU_RESET>;
++						power-domains = <&pgc_gpumix>;
++					};
++
++					pgc_vpumix: power-domain at 6 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_VPUMIX>;
++						clocks = <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
++						assigned-clocks = <&clk IMX8MM_CLK_VPU_BUS>;
++						assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>;
++						resets = <&src IMX8MQ_RESET_VPU_RESET>;
++					};
++
++					pgc_vpu_g1: power-domain at 7 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_VPUG1>;
++					};
++
++					pgc_vpu_g2: power-domain at 8 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_VPUG2>;
++					};
++
++					pgc_vpu_h1: power-domain at 9 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_VPUH1>;
++					};
++
++					pgc_dispmix: power-domain at 10 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_DISPMIX>;
++						clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>,
++							 <&clk IMX8MM_CLK_DISP_AXI_ROOT>;
++						assigned-clocks = <&clk IMX8MM_CLK_DISP_AXI>,
++								  <&clk IMX8MM_CLK_DISP_APB>;
++						assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_1000M>,
++									 <&clk IMX8MM_SYS_PLL1_800M>;
++						assigned-clock-rates = <500000000>, <200000000>;
++					};
++
++					pgc_mipi: power-domain at 11 {
++						#power-domain-cells = <0>;
++						reg = <IMX8MM_POWER_DOMAIN_MIPI>;
++					};
++				};
++			};
+ 		};
+ 
+ 		aips2: bus at 30400000 {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0009-arm64-dts-imx8mm-put-USB-controllers-into-power-doma.patch b/target/linux/imx/patches-5.15/0009-arm64-dts-imx8mm-put-USB-controllers-into-power-doma.patch
new file mode 100644
index 000000000000..c2d1f577f6a1
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0009-arm64-dts-imx8mm-put-USB-controllers-into-power-doma.patch
@@ -0,0 +1,38 @@
+From 69f9867bcd9c3f956f292e2783e08aa01fef76f4 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Sat, 2 Oct 2021 02:59:51 +0200
+Subject: [PATCH 09/17] arm64: dts: imx8mm: put USB controllers into
+ power-domains
+
+Now that we have support for the power domain controller on the i.MX8MM
+we can put the USB controllers in their respective power domains to allow
+them to power down the PHY when possible.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+---
+ arch/arm64/boot/dts/freescale/imx8mm.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+index b339da5e0b02..6708b1bebf5c 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+@@ -1078,6 +1078,7 @@ usbotg1: usb at 32e40000 {
+ 				assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
+ 				phys = <&usbphynop1>;
+ 				fsl,usbmisc = <&usbmisc1 0>;
++				power-domains = <&pgc_otg1>;
+ 				status = "disabled";
+ 			};
+ 
+@@ -1097,6 +1098,7 @@ usbotg2: usb at 32e50000 {
+ 				assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
+ 				phys = <&usbphynop2>;
+ 				fsl,usbmisc = <&usbmisc2 0>;
++				power-domains = <&pgc_otg2>;
+ 				status = "disabled";
+ 			};
+ 
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0010-soc-imx-gpcv2-add-PGC-control-register-indirection.patch b/target/linux/imx/patches-5.15/0010-soc-imx-gpcv2-add-PGC-control-register-indirection.patch
new file mode 100644
index 000000000000..e5d4ddead71c
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0010-soc-imx-gpcv2-add-PGC-control-register-indirection.patch
@@ -0,0 +1,187 @@
+From fdb04e435edbe614e3565381d85a7e8a3d70f0a4 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach at pengutronix.de>
+Date: Mon, 28 Feb 2022 21:17:25 +0100
+Subject: [PATCH 10/17] soc: imx: gpcv2: add PGC control register indirection
+
+The PGC control registers in the shared (not per-PGC) region of the
+GPC address space have different offsets on i.MX8MP to make space for
+additional interrupt control registers.
+
+Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
+Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
+---
+ drivers/soc/imx/gpcv2.c | 43 ++++++++++++++++++++++++++++++-----------
+ 1 file changed, 32 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 89e25e123c52..80ba59811a75 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -184,9 +184,17 @@
+ 
+ #define GPC_PGC_CTRL_PCR		BIT(0)
+ 
++struct imx_pgc_regs {
++	u16 map;
++	u16 pup;
++	u16 pdn;
++	u16 hsk;
++};
++
+ struct imx_pgc_domain {
+ 	struct generic_pm_domain genpd;
+ 	struct regmap *regmap;
++	const struct imx_pgc_regs *regs;
+ 	struct regulator *regulator;
+ 	struct reset_control *reset;
+ 	struct clk_bulk_data *clks;
+@@ -210,6 +218,7 @@ struct imx_pgc_domain_data {
+ 	const struct imx_pgc_domain *domains;
+ 	size_t domains_num;
+ 	const struct regmap_access_table *reg_access_table;
++	const struct imx_pgc_regs *pgc_regs;
+ };
+ 
+ static inline struct imx_pgc_domain *
+@@ -252,14 +261,14 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ 
+ 	if (domain->bits.pxx) {
+ 		/* request the domain to power up */
+-		regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ,
++		regmap_update_bits(domain->regmap, domain->regs->pup,
+ 				   domain->bits.pxx, domain->bits.pxx);
+ 		/*
+ 		 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+ 		 * for PUP_REQ/PDN_REQ bit to be cleared
+ 		 */
+ 		ret = regmap_read_poll_timeout(domain->regmap,
+-					       GPC_PU_PGC_SW_PUP_REQ, reg_val,
++					       domain->regs->pup, reg_val,
+ 					       !(reg_val & domain->bits.pxx),
+ 					       0, USEC_PER_MSEC);
+ 		if (ret) {
+@@ -281,11 +290,11 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ 
+ 	/* request the ADB400 to power up */
+ 	if (domain->bits.hskreq) {
+-		regmap_update_bits(domain->regmap, GPC_PU_PWRHSK,
++		regmap_update_bits(domain->regmap, domain->regs->hsk,
+ 				   domain->bits.hskreq, domain->bits.hskreq);
+ 
+ 		/*
+-		 * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val,
++		 * ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk, reg_val,
+ 		 *				  (reg_val & domain->bits.hskack), 0,
+ 		 *				  USEC_PER_MSEC);
+ 		 * Technically we need the commented code to wait handshake. But that needs
+@@ -332,10 +341,10 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
+ 
+ 	/* request the ADB400 to power down */
+ 	if (domain->bits.hskreq) {
+-		regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK,
++		regmap_clear_bits(domain->regmap, domain->regs->hsk,
+ 				  domain->bits.hskreq);
+ 
+-		ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK,
++		ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk,
+ 					       reg_val,
+ 					       !(reg_val & domain->bits.hskack),
+ 					       0, USEC_PER_MSEC);
+@@ -353,14 +362,14 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
+ 		}
+ 
+ 		/* request the domain to power down */
+-		regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ,
++		regmap_update_bits(domain->regmap, domain->regs->pdn,
+ 				   domain->bits.pxx, domain->bits.pxx);
+ 		/*
+ 		 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+ 		 * for PUP_REQ/PDN_REQ bit to be cleared
+ 		 */
+ 		ret = regmap_read_poll_timeout(domain->regmap,
+-					       GPC_PU_PGC_SW_PDN_REQ, reg_val,
++					       domain->regs->pdn, reg_val,
+ 					       !(reg_val & domain->bits.pxx),
+ 					       0, USEC_PER_MSEC);
+ 		if (ret) {
+@@ -444,10 +453,18 @@ static const struct regmap_access_table imx7_access_table = {
+ 	.n_yes_ranges	= ARRAY_SIZE(imx7_yes_ranges),
+ };
+ 
++static const struct imx_pgc_regs imx7_pgc_regs = {
++	.map = GPC_PGC_CPU_MAPPING,
++	.pup = GPC_PU_PGC_SW_PUP_REQ,
++	.pdn = GPC_PU_PGC_SW_PDN_REQ,
++	.hsk = GPC_PU_PWRHSK,
++};
++
+ static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
+ 	.domains = imx7_pgc_domains,
+ 	.domains_num = ARRAY_SIZE(imx7_pgc_domains),
+ 	.reg_access_table = &imx7_access_table,
++	.pgc_regs = &imx7_pgc_regs,
+ };
+ 
+ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+@@ -616,6 +633,7 @@ static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
+ 	.domains = imx8m_pgc_domains,
+ 	.domains_num = ARRAY_SIZE(imx8m_pgc_domains),
+ 	.reg_access_table = &imx8m_access_table,
++	.pgc_regs = &imx7_pgc_regs,
+ };
+ 
+ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+@@ -805,6 +823,7 @@ static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = {
+ 	.domains = imx8mm_pgc_domains,
+ 	.domains_num = ARRAY_SIZE(imx8mm_pgc_domains),
+ 	.reg_access_table = &imx8mm_access_table,
++	.pgc_regs = &imx7_pgc_regs,
+ };
+ 
+ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
+@@ -870,6 +889,7 @@ static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = {
+ 	.domains = imx8mn_pgc_domains,
+ 	.domains_num = ARRAY_SIZE(imx8mn_pgc_domains),
+ 	.reg_access_table = &imx8mn_access_table,
++	.pgc_regs = &imx7_pgc_regs,
+ };
+ 
+ static int imx_pgc_domain_probe(struct platform_device *pdev)
+@@ -902,7 +922,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
+ 	pm_runtime_enable(domain->dev);
+ 
+ 	if (domain->bits.map)
+-		regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
++		regmap_update_bits(domain->regmap, domain->regs->map,
+ 				   domain->bits.map, domain->bits.map);
+ 
+ 	ret = pm_genpd_init(&domain->genpd, NULL, true);
+@@ -928,7 +948,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
+ 	pm_genpd_remove(&domain->genpd);
+ out_domain_unmap:
+ 	if (domain->bits.map)
+-		regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
++		regmap_update_bits(domain->regmap, domain->regs->map,
+ 				   domain->bits.map, 0);
+ 	pm_runtime_disable(domain->dev);
+ 
+@@ -943,7 +963,7 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
+ 	pm_genpd_remove(&domain->genpd);
+ 
+ 	if (domain->bits.map)
+-		regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
++		regmap_update_bits(domain->regmap, domain->regs->map,
+ 				   domain->bits.map, 0);
+ 
+ 	pm_runtime_disable(domain->dev);
+@@ -1074,6 +1094,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
+ 
+ 		domain = pd_pdev->dev.platform_data;
+ 		domain->regmap = regmap;
++		domain->regs = domain_data->pgc_regs;
+ 		domain->genpd.power_on  = imx_pgc_power_up;
+ 		domain->genpd.power_off = imx_pgc_power_down;
+ 
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0011-phy-freescale-pcie-Initialize-the-imx8-pcie-standalo.patch b/target/linux/imx/patches-5.15/0011-phy-freescale-pcie-Initialize-the-imx8-pcie-standalo.patch
new file mode 100644
index 000000000000..022f3c0c5b44
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0011-phy-freescale-pcie-Initialize-the-imx8-pcie-standalo.patch
@@ -0,0 +1,285 @@
+From b90c3fd61d15182da871afb435fc8e72067478f9 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Thu, 28 Oct 2021 15:27:14 +0800
+Subject: [PATCH 11/17] phy: freescale: pcie: Initialize the imx8 pcie
+ standalone phy driver
+
+Add the standalone i.MX8 PCIe PHY driver.
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+Tested-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
+---
+ drivers/phy/freescale/Kconfig              |   9 +
+ drivers/phy/freescale/Makefile             |   1 +
+ drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 233 +++++++++++++++++++++
+ 3 files changed, 243 insertions(+)
+ create mode 100644 drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+
+diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
+index 320630ffe3cd..de9ee7020f76 100644
+--- a/drivers/phy/freescale/Kconfig
++++ b/drivers/phy/freescale/Kconfig
+@@ -14,3 +14,12 @@ config PHY_MIXEL_MIPI_DPHY
+ 	help
+ 	  Enable this to add support for the Mixel DSI PHY as found
+ 	  on NXP's i.MX8 family of SOCs.
++
++config PHY_FSL_IMX8M_PCIE
++	tristate "Freescale i.MX8 PCIE PHY"
++	depends on OF && HAS_IOMEM
++	select GENERIC_PHY
++	default ARCH_MXC && ARM64
++	help
++	  Enable this to add support for the PCIE PHY as found on
++	  i.MX8M family of SOCs.
+diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
+index 1d02e3869b45..55d07c742ab0 100644
+--- a/drivers/phy/freescale/Makefile
++++ b/drivers/phy/freescale/Makefile
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)	+= phy-fsl-imx8mq-usb.o
+ obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)	+= phy-fsl-imx8-mipi-dphy.o
++obj-$(CONFIG_PHY_FSL_IMX8M_PCIE)	+= phy-fsl-imx8m-pcie.o
+diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+new file mode 100644
+index 000000000000..003f575b36f0
+--- /dev/null
++++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+@@ -0,0 +1,233 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright 2021 NXP
++ */
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/delay.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
++
++#define IMX8MM_PCIE_PHY_CMN_REG061	0x184
++#define  ANA_PLL_CLK_OUT_TO_EXT_IO_EN	BIT(0)
++#define IMX8MM_PCIE_PHY_CMN_REG062	0x188
++#define  ANA_PLL_CLK_OUT_TO_EXT_IO_SEL	BIT(3)
++#define IMX8MM_PCIE_PHY_CMN_REG063	0x18C
++#define  AUX_PLL_REFCLK_SEL_SYS_PLL	GENMASK(7, 6)
++#define IMX8MM_PCIE_PHY_CMN_REG064	0x190
++#define  ANA_AUX_RX_TX_SEL_TX		BIT(7)
++#define  ANA_AUX_RX_TERM_GND_EN		BIT(3)
++#define  ANA_AUX_TX_TERM		BIT(2)
++#define IMX8MM_PCIE_PHY_CMN_REG065	0x194
++#define  ANA_AUX_RX_TERM		(BIT(7) | BIT(4))
++#define  ANA_AUX_TX_LVL			GENMASK(3, 0)
++#define IMX8MM_PCIE_PHY_CMN_REG75	0x1D4
++#define  PCIE_PHY_CMN_REG75_PLL_DONE	0x3
++#define PCIE_PHY_TRSV_REG5		0x414
++#define  PCIE_PHY_TRSV_REG5_GEN1_DEEMP	0x2D
++#define PCIE_PHY_TRSV_REG6		0x418
++#define  PCIE_PHY_TRSV_REG6_GEN2_DEEMP	0xF
++
++#define IMX8MM_GPR_PCIE_REF_CLK_SEL	GENMASK(25, 24)
++#define IMX8MM_GPR_PCIE_REF_CLK_PLL	FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)
++#define IMX8MM_GPR_PCIE_REF_CLK_EXT	FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x2)
++#define IMX8MM_GPR_PCIE_AUX_EN		BIT(19)
++#define IMX8MM_GPR_PCIE_CMN_RST		BIT(18)
++#define IMX8MM_GPR_PCIE_POWER_OFF	BIT(17)
++#define IMX8MM_GPR_PCIE_SSC_EN		BIT(16)
++#define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE	BIT(9)
++
++struct imx8_pcie_phy {
++	void __iomem		*base;
++	struct clk		*clk;
++	struct phy		*phy;
++	struct regmap		*iomuxc_gpr;
++	struct reset_control	*reset;
++	u32			refclk_pad_mode;
++	u32			tx_deemph_gen1;
++	u32			tx_deemph_gen2;
++	bool			clkreq_unused;
++};
++
++static int imx8_pcie_phy_init(struct phy *phy)
++{
++	int ret;
++	u32 val, pad_mode;
++	struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
++
++	reset_control_assert(imx8_phy->reset);
++
++	pad_mode = imx8_phy->refclk_pad_mode;
++	/* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
++			   imx8_phy->clkreq_unused ?
++			   0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE);
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_AUX_EN,
++			   IMX8MM_GPR_PCIE_AUX_EN);
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_POWER_OFF, 0);
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_SSC_EN, 0);
++
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_REF_CLK_SEL,
++			   pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ?
++			   IMX8MM_GPR_PCIE_REF_CLK_EXT :
++			   IMX8MM_GPR_PCIE_REF_CLK_PLL);
++	usleep_range(100, 200);
++
++	/* Do the PHY common block reset */
++	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
++			   IMX8MM_GPR_PCIE_CMN_RST,
++			   IMX8MM_GPR_PCIE_CMN_RST);
++	usleep_range(200, 500);
++
++
++	if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT) {
++		/* Configure the pad as input */
++		val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++		writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++	} else if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
++		/* Configure the PHY to output the refclock via pad */
++		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
++		writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063);
++		val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM;
++		writel(val | ANA_AUX_RX_TERM_GND_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064);
++		writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
++	}
++
++	/* Tune PHY de-emphasis setting to pass PCIe compliance. */
++	writel(imx8_phy->tx_deemph_gen1, imx8_phy->base + PCIE_PHY_TRSV_REG5);
++	writel(imx8_phy->tx_deemph_gen2, imx8_phy->base + PCIE_PHY_TRSV_REG6);
++
++	reset_control_deassert(imx8_phy->reset);
++
++	/* Polling to check the phy is ready or not. */
++	ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG75,
++				 val, val == PCIE_PHY_CMN_REG75_PLL_DONE,
++				 10, 20000);
++	return ret;
++}
++
++static int imx8_pcie_phy_power_on(struct phy *phy)
++{
++	struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
++
++	return clk_prepare_enable(imx8_phy->clk);
++}
++
++static int imx8_pcie_phy_power_off(struct phy *phy)
++{
++	struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
++
++	clk_disable_unprepare(imx8_phy->clk);
++
++	return 0;
++}
++
++static const struct phy_ops imx8_pcie_phy_ops = {
++	.init		= imx8_pcie_phy_init,
++	.power_on	= imx8_pcie_phy_power_on,
++	.power_off	= imx8_pcie_phy_power_off,
++	.owner		= THIS_MODULE,
++};
++
++static int imx8_pcie_phy_probe(struct platform_device *pdev)
++{
++	struct phy_provider *phy_provider;
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct imx8_pcie_phy *imx8_phy;
++	struct resource *res;
++
++	imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL);
++	if (!imx8_phy)
++		return -ENOMEM;
++
++	/* get PHY refclk pad mode */
++	of_property_read_u32(np, "fsl,refclk-pad-mode",
++			     &imx8_phy->refclk_pad_mode);
++
++	if (of_property_read_u32(np, "fsl,tx-deemph-gen1",
++				 &imx8_phy->tx_deemph_gen1))
++		imx8_phy->tx_deemph_gen1 = 0;
++
++	if (of_property_read_u32(np, "fsl,tx-deemph-gen2",
++				 &imx8_phy->tx_deemph_gen2))
++		imx8_phy->tx_deemph_gen2 = 0;
++
++	if (of_property_read_bool(np, "fsl,clkreq-unsupported"))
++		imx8_phy->clkreq_unused = true;
++	else
++		imx8_phy->clkreq_unused = false;
++
++	imx8_phy->clk = devm_clk_get(dev, "ref");
++	if (IS_ERR(imx8_phy->clk)) {
++		dev_err(dev, "failed to get imx pcie phy clock\n");
++		return PTR_ERR(imx8_phy->clk);
++	}
++
++	/* Grab GPR config register range */
++	imx8_phy->iomuxc_gpr =
++		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
++	if (IS_ERR(imx8_phy->iomuxc_gpr)) {
++		dev_err(dev, "unable to find iomuxc registers\n");
++		return PTR_ERR(imx8_phy->iomuxc_gpr);
++	}
++
++	imx8_phy->reset = devm_reset_control_get_exclusive(dev, "pciephy");
++	if (IS_ERR(imx8_phy->reset)) {
++		dev_err(dev, "Failed to get PCIEPHY reset control\n");
++		return PTR_ERR(imx8_phy->reset);
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	imx8_phy->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(imx8_phy->base))
++		return PTR_ERR(imx8_phy->base);
++
++	imx8_phy->phy = devm_phy_create(dev, NULL, &imx8_pcie_phy_ops);
++	if (IS_ERR(imx8_phy->phy))
++		return PTR_ERR(imx8_phy->phy);
++
++	phy_set_drvdata(imx8_phy->phy, imx8_phy);
++
++	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
++
++	return PTR_ERR_OR_ZERO(phy_provider);
++}
++
++static const struct of_device_id imx8_pcie_phy_of_match[] = {
++	{.compatible = "fsl,imx8mm-pcie-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
++
++static struct platform_driver imx8_pcie_phy_driver = {
++	.probe	= imx8_pcie_phy_probe,
++	.driver = {
++		.name	= "imx8-pcie-phy",
++		.of_match_table	= imx8_pcie_phy_of_match,
++	}
++};
++module_platform_driver(imx8_pcie_phy_driver);
++
++MODULE_DESCRIPTION("FSL IMX8 PCIE PHY driver");
++MODULE_LICENSE("GPL");
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0012-phy-freescale-imx8m-pcie-Add-iMX8MP-PCIe-PHY-support.patch b/target/linux/imx/patches-5.15/0012-phy-freescale-imx8m-pcie-Add-iMX8MP-PCIe-PHY-support.patch
new file mode 100644
index 000000000000..de484006f77e
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0012-phy-freescale-imx8m-pcie-Add-iMX8MP-PCIe-PHY-support.patch
@@ -0,0 +1,305 @@
+From c34c47978eed63a520915fb7e45ef34fe5a551e7 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Mon, 7 Mar 2022 17:07:30 +0800
+Subject: [PATCH 12/17] phy: freescale: imx8m-pcie: Add iMX8MP PCIe PHY support
+
+Add the i.MX8MP PCIe PHY support
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+---
+ drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 202 +++++++++++++++++----
+ 1 file changed, 163 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+index 003f575b36f0..0b9d006a983b 100644
+--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
++++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+@@ -10,6 +10,8 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
+ #include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+@@ -29,12 +31,10 @@
+ #define IMX8MM_PCIE_PHY_CMN_REG065	0x194
+ #define  ANA_AUX_RX_TERM		(BIT(7) | BIT(4))
+ #define  ANA_AUX_TX_LVL			GENMASK(3, 0)
+-#define IMX8MM_PCIE_PHY_CMN_REG75	0x1D4
+-#define  PCIE_PHY_CMN_REG75_PLL_DONE	0x3
++#define IMX8MM_PCIE_PHY_CMN_REG075	0x1D4
++#define  ANA_PLL_DONE			0x3
+ #define PCIE_PHY_TRSV_REG5		0x414
+-#define  PCIE_PHY_TRSV_REG5_GEN1_DEEMP	0x2D
+ #define PCIE_PHY_TRSV_REG6		0x418
+-#define  PCIE_PHY_TRSV_REG6_GEN2_DEEMP	0xF
+ 
+ #define IMX8MM_GPR_PCIE_REF_CLK_SEL	GENMASK(25, 24)
+ #define IMX8MM_GPR_PCIE_REF_CLK_PLL	FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)
+@@ -45,16 +45,43 @@
+ #define IMX8MM_GPR_PCIE_SSC_EN		BIT(16)
+ #define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE	BIT(9)
+ 
++#define IMX8MP_GPR_REG0			0x0
++#define IMX8MP_GPR_CLK_MOD_EN		BIT(0)
++#define IMX8MP_GPR_PHY_APB_RST		BIT(4)
++#define IMX8MP_GPR_PHY_INIT_RST		BIT(5)
++#define IMX8MP_GPR_REG1			0x4
++#define IMX8MP_GPR_PM_EN_CORE_CLK	BIT(0)
++#define IMX8MP_GPR_PLL_LOCK		BIT(13)
++#define IMX8MP_GPR_REG2			0x8
++#define IMX8MP_GPR_P_PLL_MASK		GENMASK(5, 0)
++#define IMX8MP_GPR_M_PLL_MASK		GENMASK(15, 6)
++#define IMX8MP_GPR_S_PLL_MASK		GENMASK(18, 16)
++#define IMX8MP_GPR_P_PLL		(0xc << 0)
++#define IMX8MP_GPR_M_PLL		(0x320 << 6)
++#define IMX8MP_GPR_S_PLL		(0x4 << 16)
++#define IMX8MP_GPR_REG3			0xc
++#define IMX8MP_GPR_PLL_CKE		BIT(17)
++#define IMX8MP_GPR_PLL_RST		BIT(31)
++
++enum imx8_pcie_phy_type {
++	IMX8MM,
++	IMX8MP,
++};
++
+ struct imx8_pcie_phy {
+ 	void __iomem		*base;
++	struct device		*dev;
+ 	struct clk		*clk;
+ 	struct phy		*phy;
++	struct regmap		*hsio_blk_ctrl;
+ 	struct regmap		*iomuxc_gpr;
+ 	struct reset_control	*reset;
++	struct reset_control	*perst;
+ 	u32			refclk_pad_mode;
+ 	u32			tx_deemph_gen1;
+ 	u32			tx_deemph_gen2;
+ 	bool			clkreq_unused;
++	enum imx8_pcie_phy_type	variant;
+ };
+ 
+ static int imx8_pcie_phy_init(struct phy *phy)
+@@ -66,6 +93,87 @@ static int imx8_pcie_phy_init(struct phy *phy)
+ 	reset_control_assert(imx8_phy->reset);
+ 
+ 	pad_mode = imx8_phy->refclk_pad_mode;
++	switch (imx8_phy->variant) {
++	case IMX8MM:
++		/* Tune PHY de-emphasis setting to pass PCIe compliance. */
++		if (imx8_phy->tx_deemph_gen1)
++			writel(imx8_phy->tx_deemph_gen1,
++			       imx8_phy->base + PCIE_PHY_TRSV_REG5);
++		if (imx8_phy->tx_deemph_gen2)
++			writel(imx8_phy->tx_deemph_gen2,
++			       imx8_phy->base + PCIE_PHY_TRSV_REG6);
++		break;
++	case IMX8MP:
++		reset_control_assert(imx8_phy->perst);
++		/* Set P=12,M=800,S=4 and must set ICP=2'b01. */
++		regmap_update_bits(imx8_phy->hsio_blk_ctrl, IMX8MP_GPR_REG2,
++				   IMX8MP_GPR_P_PLL_MASK |
++				   IMX8MP_GPR_M_PLL_MASK |
++				   IMX8MP_GPR_S_PLL_MASK,
++				   IMX8MP_GPR_P_PLL |
++				   IMX8MP_GPR_M_PLL |
++				   IMX8MP_GPR_S_PLL);
++		/* wait greater than 1/F_FREF =1/2MHZ=0.5us */
++		udelay(1);
++
++		regmap_update_bits(imx8_phy->hsio_blk_ctrl, IMX8MP_GPR_REG3,
++				   IMX8MP_GPR_PLL_RST,
++				   IMX8MP_GPR_PLL_RST);
++		udelay(10);
++
++		/* Set 1 to pll_cke of GPR_REG3 */
++		regmap_update_bits(imx8_phy->hsio_blk_ctrl, IMX8MP_GPR_REG3,
++				   IMX8MP_GPR_PLL_CKE,
++				   IMX8MP_GPR_PLL_CKE);
++
++		/* Lock time should be greater than 300cycle=300*0.5us=150us */
++		ret = regmap_read_poll_timeout(imx8_phy->hsio_blk_ctrl,
++					     IMX8MP_GPR_REG1, val,
++					     val & IMX8MP_GPR_PLL_LOCK,
++					     10, 1000);
++		if (ret) {
++			dev_err(imx8_phy->dev, "PCIe PLL lock timeout\n");
++			return ret;
++		}
++
++		/* pcie_clock_module_en */
++		regmap_update_bits(imx8_phy->hsio_blk_ctrl, IMX8MP_GPR_REG0,
++				   IMX8MP_GPR_CLK_MOD_EN,
++				   IMX8MP_GPR_CLK_MOD_EN);
++		udelay(10);
++
++		reset_control_deassert(imx8_phy->reset);
++		reset_control_deassert(imx8_phy->perst);
++
++		/* release pcie_phy_apb_reset and pcie_phy_init_resetn */
++		regmap_update_bits(imx8_phy->hsio_blk_ctrl, IMX8MP_GPR_REG0,
++				   IMX8MP_GPR_PHY_APB_RST |
++				   IMX8MP_GPR_PHY_INIT_RST,
++				   IMX8MP_GPR_PHY_APB_RST |
++				   IMX8MP_GPR_PHY_INIT_RST);
++		break;
++	}
++
++	if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT) {
++		/* Configure the pad as input */
++		val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++		writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++	} else if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
++		/* Configure the PHY to output the refclock via pad */
++		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
++		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
++		writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063);
++		val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM;
++		writel(val | ANA_AUX_RX_TERM_GND_EN,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064);
++		writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL,
++		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
++	}
++
+ 	/* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
+ 	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+ 			   IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
+@@ -90,39 +198,30 @@ static int imx8_pcie_phy_init(struct phy *phy)
+ 	regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+ 			   IMX8MM_GPR_PCIE_CMN_RST,
+ 			   IMX8MM_GPR_PCIE_CMN_RST);
+-	usleep_range(200, 500);
+ 
+-
+-	if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT) {
+-		/* Configure the pad as input */
+-		val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
+-		writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
+-	} else if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
+-		/* Configure the PHY to output the refclock via pad */
+-		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
+-		writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
+-		writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063);
+-		val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM;
+-		writel(val | ANA_AUX_RX_TERM_GND_EN,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064);
+-		writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL,
+-		       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
++	switch (imx8_phy->variant) {
++	case IMX8MM:
++		reset_control_deassert(imx8_phy->reset);
++		usleep_range(200, 500);
++		break;
++
++	case IMX8MP:
++		/* wait for core_clk enabled */
++		ret = regmap_read_poll_timeout(imx8_phy->hsio_blk_ctrl,
++					     IMX8MP_GPR_REG1, val,
++					     val & IMX8MP_GPR_PM_EN_CORE_CLK,
++					     10, 20000);
++		if (ret) {
++			dev_err(imx8_phy->dev, "PCIe CORE CLK enable failed\n");
++			return ret;
++		}
++
++		break;
+ 	}
+ 
+-	/* Tune PHY de-emphasis setting to pass PCIe compliance. */
+-	writel(imx8_phy->tx_deemph_gen1, imx8_phy->base + PCIE_PHY_TRSV_REG5);
+-	writel(imx8_phy->tx_deemph_gen2, imx8_phy->base + PCIE_PHY_TRSV_REG6);
+-
+-	reset_control_deassert(imx8_phy->reset);
+-
+ 	/* Polling to check the phy is ready or not. */
+-	ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG75,
+-				 val, val == PCIE_PHY_CMN_REG75_PLL_DONE,
+-				 10, 20000);
++	ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG075,
++				 val, val == ANA_PLL_DONE, 10, 20000);
+ 	return ret;
+ }
+ 
+@@ -149,18 +248,33 @@ static const struct phy_ops imx8_pcie_phy_ops = {
+ 	.owner		= THIS_MODULE,
+ };
+ 
++static const struct of_device_id imx8_pcie_phy_of_match[] = {
++	{.compatible = "fsl,imx8mm-pcie-phy", .data = (void *)IMX8MM},
++	{.compatible = "fsl,imx8mp-pcie-phy", .data = (void *)IMX8MP},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
++
+ static int imx8_pcie_phy_probe(struct platform_device *pdev)
+ {
+ 	struct phy_provider *phy_provider;
+ 	struct device *dev = &pdev->dev;
++	const struct of_device_id *of_id;
+ 	struct device_node *np = dev->of_node;
+ 	struct imx8_pcie_phy *imx8_phy;
+ 	struct resource *res;
+ 
++	of_id = of_match_device(imx8_pcie_phy_of_match, dev);
++	if (!of_id)
++		return -EINVAL;
++
+ 	imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL);
+ 	if (!imx8_phy)
+ 		return -ENOMEM;
+ 
++	imx8_phy->dev = dev;
++	imx8_phy->variant = (enum imx8_pcie_phy_type)of_id->data;
++
+ 	/* get PHY refclk pad mode */
+ 	of_property_read_u32(np, "fsl,refclk-pad-mode",
+ 			     &imx8_phy->refclk_pad_mode);
+@@ -197,6 +311,22 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
+ 		dev_err(dev, "Failed to get PCIEPHY reset control\n");
+ 		return PTR_ERR(imx8_phy->reset);
+ 	}
++	if (imx8_phy->variant == IMX8MP) {
++		/* Grab HSIO MIX config register range */
++		imx8_phy->hsio_blk_ctrl =
++			 syscon_regmap_lookup_by_compatible("fsl,imx8mp-hsio-blk-ctrl");
++		if (IS_ERR(imx8_phy->hsio_blk_ctrl)) {
++			dev_err(dev, "unable to find hsio mix registers\n");
++			return PTR_ERR(imx8_phy->hsio_blk_ctrl);
++		}
++
++		imx8_phy->perst =
++			devm_reset_control_get_exclusive(dev, "perst");
++		if (IS_ERR(imx8_phy->perst)) {
++			dev_err(dev, "Failed to get PCIEPHY perst control\n");
++			return PTR_ERR(imx8_phy->perst);
++		}
++	}
+ 
+ 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	imx8_phy->base = devm_ioremap_resource(dev, res);
+@@ -214,12 +344,6 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
+ 	return PTR_ERR_OR_ZERO(phy_provider);
+ }
+ 
+-static const struct of_device_id imx8_pcie_phy_of_match[] = {
+-	{.compatible = "fsl,imx8mm-pcie-phy",},
+-	{ },
+-};
+-MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
+-
+ static struct platform_driver imx8_pcie_phy_driver = {
+ 	.probe	= imx8_pcie_phy_probe,
+ 	.driver = {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0013-dt-bindings-phy-phy-imx8-pcie-Add-binding-for-the-pa.patch b/target/linux/imx/patches-5.15/0013-dt-bindings-phy-phy-imx8-pcie-Add-binding-for-the-pa.patch
new file mode 100644
index 000000000000..f0989b205ee9
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0013-dt-bindings-phy-phy-imx8-pcie-Add-binding-for-the-pa.patch
@@ -0,0 +1,38 @@
+From 9870dee7766a6b646cc59675b66ed1f70b1c33d4 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Thu, 28 Oct 2021 15:27:10 +0800
+Subject: [PATCH 13/17] dt-bindings: phy: phy-imx8-pcie: Add binding for the
+ pad modes of imx8 pcie phy
+
+Add binding for reference clock PAD modes of the i.MX8 PCIe PHY.
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+Tested-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
+---
+ include/dt-bindings/phy/phy-imx8-pcie.h | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+ create mode 100644 include/dt-bindings/phy/phy-imx8-pcie.h
+
+diff --git a/include/dt-bindings/phy/phy-imx8-pcie.h b/include/dt-bindings/phy/phy-imx8-pcie.h
+new file mode 100644
+index 000000000000..8bbe2d6538d8
+--- /dev/null
++++ b/include/dt-bindings/phy/phy-imx8-pcie.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
++/*
++ * This header provides constants for i.MX8 PCIe.
++ */
++
++#ifndef _DT_BINDINGS_IMX8_PCIE_H
++#define _DT_BINDINGS_IMX8_PCIE_H
++
++/* Reference clock PAD mode */
++#define IMX8_PCIE_REFCLK_PAD_UNUSED	0
++#define IMX8_PCIE_REFCLK_PAD_INPUT	1
++#define IMX8_PCIE_REFCLK_PAD_OUTPUT	2
++
++#endif /* _DT_BINDINGS_IMX8_PCIE_H */
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0014-PCI-imx-Add-the-imx8mm-pcie-support.patch b/target/linux/imx/patches-5.15/0014-PCI-imx-Add-the-imx8mm-pcie-support.patch
new file mode 100644
index 000000000000..1d53a9224238
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0014-PCI-imx-Add-the-imx8mm-pcie-support.patch
@@ -0,0 +1,211 @@
+From cfde3f23ce2fb5a1a1f9d1f841af67110ecefede Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Thu, 28 Oct 2021 15:27:17 +0800
+Subject: [PATCH 14/17] PCI: imx: Add the imx8mm pcie support
+
+i.MX8MM PCIe works mostly like the i.MX8MQ one, but has a different PHY
+and allows to output the internal PHY reference clock via the refclk pad.
+Add the i.MX8MM PCIe support based on the standalone PHY driver.
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+Tested-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
+---
+ drivers/pci/controller/dwc/pci-imx6.c | 73 ++++++++++++++++++++++++---
+ 1 file changed, 66 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
+index 67dbf9d88d22..8cc016cea3c4 100644
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -29,6 +29,7 @@
+ #include <linux/types.h>
+ #include <linux/interrupt.h>
+ #include <linux/reset.h>
++#include <linux/phy/phy.h>
+ #include <linux/pm_domain.h>
+ #include <linux/pm_runtime.h>
+ 
+@@ -49,6 +50,7 @@ enum imx6_pcie_variants {
+ 	IMX6QP,
+ 	IMX7D,
+ 	IMX8MQ,
++	IMX8MM,
+ };
+ 
+ #define IMX6_PCIE_FLAG_IMX6_PHY			BIT(0)
+@@ -88,6 +90,7 @@ struct imx6_pcie {
+ 	struct device		*pd_pcie;
+ 	/* power domain for pcie phy */
+ 	struct device		*pd_pcie_phy;
++	struct phy		*phy;
+ 	const struct imx6_pcie_drvdata *drvdata;
+ };
+ 
+@@ -372,6 +375,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
+ 	case IMX7D:
+ 	case IMX8MQ:
+ 		reset_control_assert(imx6_pcie->pciephy_reset);
++		fallthrough;
++	case IMX8MM:
+ 		reset_control_assert(imx6_pcie->apps_reset);
+ 		break;
+ 	case IMX6SX:
+@@ -412,7 +417,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
+ 
+ static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
+ {
+-	WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ);
++	WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ &&
++		imx6_pcie->drvdata->variant != IMX8MM);
+ 	return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
+ }
+ 
+@@ -451,6 +457,13 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
+ 		break;
+ 	case IMX7D:
+ 		break;
++	case IMX8MM:
++		ret = clk_prepare_enable(imx6_pcie->pcie_aux);
++		if (ret) {
++			dev_err(dev, "unable to enable pcie_aux clock\n");
++			break;
++		}
++		break;
+ 	case IMX8MQ:
+ 		ret = clk_prepare_enable(imx6_pcie->pcie_aux);
+ 		if (ret) {
+@@ -527,6 +540,14 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
+ 		goto err_ref_clk;
+ 	}
+ 
++	switch (imx6_pcie->drvdata->variant) {
++	case IMX8MM:
++		if (phy_power_on(imx6_pcie->phy))
++			dev_err(dev, "unable to power on PHY\n");
++		break;
++	default:
++		break;
++	}
+ 	/* allow the clocks to stabilize */
+ 	usleep_range(200, 500);
+ 
+@@ -534,6 +555,10 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
+ 	case IMX8MQ:
+ 		reset_control_deassert(imx6_pcie->pciephy_reset);
+ 		break;
++	case IMX8MM:
++		if (phy_init(imx6_pcie->phy) != 0)
++			dev_err(dev, "Waiting for PHY ready timeout!\n");
++		break;
+ 	case IMX7D:
+ 		reset_control_deassert(imx6_pcie->pciephy_reset);
+ 
+@@ -619,6 +644,8 @@ static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
+ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
+ {
+ 	switch (imx6_pcie->drvdata->variant) {
++	case IMX8MM:
++		break;
+ 	case IMX8MQ:
+ 		/*
+ 		 * TODO: Currently this code assumes external
+@@ -758,6 +785,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
+ 		break;
+ 	case IMX7D:
+ 	case IMX8MQ:
++	case IMX8MM:
+ 		reset_control_deassert(imx6_pcie->apps_reset);
+ 		break;
+ 	}
+@@ -870,6 +898,7 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
+ 				   IMX6Q_GPR12_PCIE_CTL_2, 0);
+ 		break;
+ 	case IMX7D:
++	case IMX8MM:
+ 		reset_control_assert(imx6_pcie->apps_reset);
+ 		break;
+ 	default:
+@@ -929,6 +958,7 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
+ 				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
+ 		break;
+ 	case IMX8MQ:
++	case IMX8MM:
+ 		clk_disable_unprepare(imx6_pcie->pcie_aux);
+ 		break;
+ 	default:
+@@ -1042,11 +1072,6 @@ static int imx6_pcie_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	/* Fetch clocks */
+-	imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
+-	if (IS_ERR(imx6_pcie->pcie_phy))
+-		return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy),
+-				     "pcie_phy clock source missing or invalid\n");
+-
+ 	imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
+ 	if (IS_ERR(imx6_pcie->pcie_bus))
+ 		return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus),
+@@ -1088,10 +1113,39 @@ static int imx6_pcie_probe(struct platform_device *pdev)
+ 			dev_err(dev, "Failed to get PCIE APPS reset control\n");
+ 			return PTR_ERR(imx6_pcie->apps_reset);
+ 		}
++		break;
++	case IMX8MM:
++		imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
++		if (IS_ERR(imx6_pcie->pcie_aux))
++			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
++					     "pcie_aux clock source missing or invalid\n");
++		imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev,
++									 "apps");
++		if (IS_ERR(imx6_pcie->apps_reset)) {
++			dev_err(dev, "Failed to get PCIE APPS reset control\n");
++			return PTR_ERR(imx6_pcie->apps_reset);
++		}
++
++		imx6_pcie->phy = devm_phy_get(dev, "pcie-phy");
++		if (IS_ERR(imx6_pcie->phy)) {
++			if (PTR_ERR(imx6_pcie->phy) == -EPROBE_DEFER)
++				return -EPROBE_DEFER;
++			dev_err(dev, "Failed to get PCIE PHY\n");
++			return PTR_ERR(imx6_pcie->phy);
++		}
++
+ 		break;
+ 	default:
+ 		break;
+ 	}
++	/* Don't fetch the pcie_phy clock, if it has abstract PHY driver */
++	if (imx6_pcie->phy == NULL) {
++		imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
++		if (IS_ERR(imx6_pcie->pcie_phy))
++			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy),
++					     "pcie_phy clock source missing or invalid\n");
++	}
++
+ 
+ 	/* Grab turnoff reset */
+ 	imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
+@@ -1201,6 +1255,10 @@ static const struct imx6_pcie_drvdata drvdata[] = {
+ 	[IMX8MQ] = {
+ 		.variant = IMX8MQ,
+ 	},
++	[IMX8MM] = {
++		.variant = IMX8MM,
++		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
++	},
+ };
+ 
+ static const struct of_device_id imx6_pcie_of_match[] = {
+@@ -1208,7 +1266,8 @@ static const struct of_device_id imx6_pcie_of_match[] = {
+ 	{ .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], },
+ 	{ .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], },
+ 	{ .compatible = "fsl,imx7d-pcie",  .data = &drvdata[IMX7D],  },
+-	{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } ,
++	{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], },
++	{ .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], },
+ 	{},
+ };
+ 
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0015-arm64-dts-imx8mm-Add-the-pcie-phy-support.patch b/target/linux/imx/patches-5.15/0015-arm64-dts-imx8mm-Add-the-pcie-phy-support.patch
new file mode 100644
index 000000000000..0b2a1be05c58
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0015-arm64-dts-imx8mm-Add-the-pcie-phy-support.patch
@@ -0,0 +1,40 @@
+From c488e4b57b69682cf4adb7809d5482165984acc6 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Thu, 28 Oct 2021 15:27:13 +0800
+Subject: [PATCH 15/17] arm64: dts: imx8mm: Add the pcie phy support
+
+Add the PCIe PHY support on iMX8MM platforms.
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+Tested-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
+---
+ arch/arm64/boot/dts/freescale/imx8mm.dtsi | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+index 6708b1bebf5c..ec083d3f68d5 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+@@ -1108,6 +1108,19 @@ usbmisc2: usbmisc at 32e50200 {
+ 				reg = <0x32e50200 0x200>;
+ 			};
+ 
++			pcie_phy: pcie-phy at 32f00000 {
++				compatible = "fsl,imx8mm-pcie-phy";
++				reg = <0x32f00000 0x10000>;
++				clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
++				clock-names = "ref";
++				assigned-clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
++				assigned-clock-rates = <100000000>;
++				assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_100M>;
++				resets = <&src IMX8MQ_RESET_PCIEPHY>;
++				reset-names = "pciephy";
++				#phy-cells = <0>;
++				status = "disabled";
++			};
+ 		};
+ 
+ 		dma_apbh: dma-controller at 33000000 {
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0016-arm64-dts-imx8mm-Add-the-pcie-support.patch b/target/linux/imx/patches-5.15/0016-arm64-dts-imx8mm-Add-the-pcie-support.patch
new file mode 100644
index 000000000000..74156015624a
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0016-arm64-dts-imx8mm-Add-the-pcie-support.patch
@@ -0,0 +1,67 @@
+From 527ed85dbb8b89dced54f207cc181062e327f3f8 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu at nxp.com>
+Date: Thu, 28 Oct 2021 15:27:15 +0800
+Subject: [PATCH 16/17] arm64: dts: imx8mm: Add the pcie support
+
+Add the PCIe support on i.MX8MM platforms.
+
+Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
+Tested-by: Marcel Ziswiler <marcel.ziswiler at toradex.com>
+---
+ arch/arm64/boot/dts/freescale/imx8mm.dtsi | 33 ++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+index ec083d3f68d5..de6b2992f6c3 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+@@ -520,7 +520,7 @@ iomuxc: pinctrl at 30330000 {
+ 			};
+ 
+ 			gpr: iomuxc-gpr at 30340000 {
+-				compatible = "fsl,imx8mm-iomuxc-gpr", "syscon";
++				compatible = "fsl,imx8mm-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", "syscon";
+ 				reg = <0x30340000 0x10000>;
+ 			};
+ 
+@@ -1152,6 +1152,37 @@ gpmi: nand-controller at 33002000 {
+ 			status = "disabled";
+ 		};
+ 
++		pcie0: pcie at 33800000 {
++			compatible = "fsl,imx8mm-pcie";
++			reg = <0x33800000 0x400000>, <0x1ff00000 0x80000>;
++			reg-names = "dbi", "config";
++			#address-cells = <3>;
++			#size-cells = <2>;
++			device_type = "pci";
++			bus-range = <0x00 0xff>;
++			ranges =  <0x81000000 0 0x00000000 0x1ff80000 0 0x00010000 /* downstream I/O 64KB */
++				   0x82000000 0 0x18000000 0x18000000 0 0x07f00000>; /* non-prefetchable memory */
++			num-lanes = <1>;
++			num-viewport = <4>;
++			interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
++			interrupt-names = "msi";
++			#interrupt-cells = <1>;
++			interrupt-map-mask = <0 0 0 0x7>;
++			interrupt-map = <0 0 0 1 &gic GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
++					<0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
++					<0 0 0 3 &gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
++					<0 0 0 4 &gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
++			fsl,max-link-speed = <2>;
++			linux,pci-domain = <0>;
++			power-domains = <&pgc_pcie>;
++			resets = <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
++				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
++			reset-names = "apps", "turnoff";
++			phys = <&pcie_phy>;
++			phy-names = "pcie-phy";
++			status = "disabled";
++		};
++
+ 		gic: interrupt-controller at 38800000 {
+ 			compatible = "arm,gic-v3";
+ 			reg = <0x38800000 0x10000>, /* GIC Dist */
+-- 
+2.25.1
+
diff --git a/target/linux/imx/patches-5.15/0017-arm64-dts-imx8mm-venice-add-PCIe-support.patch b/target/linux/imx/patches-5.15/0017-arm64-dts-imx8mm-venice-add-PCIe-support.patch
new file mode 100644
index 000000000000..7d873280f848
--- /dev/null
+++ b/target/linux/imx/patches-5.15/0017-arm64-dts-imx8mm-venice-add-PCIe-support.patch
@@ -0,0 +1,437 @@
+From d44610e534d7c978e782b1ba0a5bdb065b4fa3bb Mon Sep 17 00:00:00 2001
+From: Tim Harvey <tharvey at gateworks.com>
+Date: Wed, 13 Jan 2021 14:05:03 -0800
+Subject: [PATCH 17/17] arm64: dts: imx8mm-venice*: add PCIe support
+
+Add PCIe support to GW71xx/GW72xx/GW73xx/GW7901/GW7902
+
+Signed-off-by: Tim Harvey <tharvey at gateworks.com>
+---
+ .../dts/freescale/imx8mm-venice-gw71xx.dtsi   | 35 +++++++++++
+ .../dts/freescale/imx8mm-venice-gw72xx.dtsi   | 62 +++++++++++++++++++
+ .../dts/freescale/imx8mm-venice-gw73xx.dtsi   | 62 +++++++++++++++++++
+ .../dts/freescale/imx8mm-venice-gw7901.dts    | 36 +++++++++++
+ .../dts/freescale/imx8mm-venice-gw7902.dts    | 50 +++++++++++++++
+ 5 files changed, 245 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
+index 7ea909a4c1d5..c2315d3ef4d0 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
+@@ -5,6 +5,7 @@
+ 
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/leds/common.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
+ 
+ / {
+ 	aliases {
+@@ -33,6 +34,12 @@ led-1 {
+ 		};
+ 	};
+ 
++	pcie0_refclk: pcie0-refclk {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++	};
++
+ 	pps {
+ 		compatible = "pps-gpio";
+ 		pinctrl-names = "default";
+@@ -87,6 +94,28 @@ &i2c3 {
+ 	status = "okay";
+ };
+ 
++&pcie_phy {
++	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
++	fsl,clkreq-unsupported;
++	clocks = <&pcie0_refclk>;
++	status = "okay";
++};
++
++&pcie0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pinctrl_pcie0>;
++	reset-gpio = <&gpio4 6 GPIO_ACTIVE_LOW>;
++	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
++		 <&pcie0_refclk>;
++	clock-names = "pcie", "pcie_aux", "pcie_bus";
++	assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
++			  <&clk IMX8MM_CLK_PCIE1_CTRL>;
++	assigned-clock-rates = <10000000>, <250000000>;
++	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
++				 <&clk IMX8MM_SYS_PLL2_250M>;
++	status = "okay";
++};
++
+ /* GPS */
+ &uart1 {
+ 	pinctrl-names = "default";
+@@ -150,6 +179,12 @@ MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+ 		>;
+ 	};
+ 
++	pinctrl_pcie0: pcie0grp {
++		fsl,pins = <
++			MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6	0x41
++		>;
++	};
++
+ 	pinctrl_pps: ppsgrp {
+ 		fsl,pins = <
+ 			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x41
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
+index 806ee21651d1..84638edbd155 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
+@@ -5,9 +5,11 @@
+ 
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/leds/common.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
+ 
+ / {
+ 	aliases {
++		ethernet1 = &eth1;
+ 		usb0 = &usbotg1;
+ 		usb1 = &usbotg2;
+ 	};
+@@ -33,6 +35,12 @@ led-1 {
+ 		};
+ 	};
+ 
++	pcie0_refclk: pcie0-refclk {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++	};
++
+ 	pps {
+ 		compatible = "pps-gpio";
+ 		pinctrl-names = "default";
+@@ -106,6 +114,54 @@ &i2c3 {
+ 	status = "okay";
+ };
+ 
++&pcie_phy {
++	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
++	fsl,clkreq-unsupported;
++	clocks = <&pcie0_refclk>;
++	status = "okay";
++};
++
++&pcie0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pinctrl_pcie0>;
++	reset-gpio = <&gpio4 6 GPIO_ACTIVE_LOW>;
++	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
++		 <&pcie0_refclk>;
++	clock-names = "pcie", "pcie_aux", "pcie_bus";
++	assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
++			  <&clk IMX8MM_CLK_PCIE1_CTRL>;
++	assigned-clock-rates = <10000000>, <250000000>;
++	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
++				 <&clk IMX8MM_SYS_PLL2_250M>;
++	status = "okay";
++
++	pcie at 0,0 {
++		reg = <0x0000 0 0 0 0>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		pcie at 1,0 {
++			reg = <0x0000 0 0 0 0>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			pcie at 2,3 {
++				reg = <0x1800 0 0 0 0>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				eth1: pcie at 5,0 {
++					reg = <0x0000 0 0 0 0>;
++					#address-cells = <1>;
++					#size-cells = <0>;
++
++					local-mac-address = [00 00 00 00 00 00];
++				};
++			};
++		};
++	};
++};
++
+ /* off-board header */
+ &sai3 {
+ 	pinctrl-names = "default";
+@@ -200,6 +256,12 @@ MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+ 		>;
+ 	};
+ 
++	pinctrl_pcie0: pcie0grp {
++		fsl,pins = <
++			MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6	0x41
++		>;
++	};
++
+ 	pinctrl_pps: ppsgrp {
+ 		fsl,pins = <
+ 			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x41
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
+index 942fed2eed64..457ba82523b6 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
+@@ -5,9 +5,11 @@
+ 
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/leds/common.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
+ 
+ / {
+ 	aliases {
++		ethernet1 = &eth1;
+ 		usb0 = &usbotg1;
+ 		usb1 = &usbotg2;
+ 	};
+@@ -33,6 +35,12 @@ led-1 {
+ 		};
+ 	};
+ 
++	pcie0_refclk: pcie0-refclk {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++	};
++
+ 	pps {
+ 		compatible = "pps-gpio";
+ 		pinctrl-names = "default";
+@@ -126,6 +134,54 @@ &i2c3 {
+ 	status = "okay";
+ };
+ 
++&pcie_phy {
++	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
++	fsl,clkreq-unsupported;
++	clocks = <&pcie0_refclk>;
++	status = "okay";
++};
++
++&pcie0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pinctrl_pcie0>;
++	reset-gpio = <&gpio4 6 GPIO_ACTIVE_LOW>;
++	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
++		 <&pcie0_refclk>;
++	clock-names = "pcie", "pcie_aux", "pcie_bus";
++	assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
++			  <&clk IMX8MM_CLK_PCIE1_CTRL>;
++	assigned-clock-rates = <10000000>, <250000000>;
++	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
++				 <&clk IMX8MM_SYS_PLL2_250M>;
++	status = "okay";
++
++	pcie at 0,0 {
++		reg = <0x0000 0 0 0 0>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		pcie at 1,0 {
++			reg = <0x0000 0 0 0 0>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			pcie at 2,4 {
++				reg = <0x2000 0 0 0 0>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				eth1: pcie at 6,0 {
++					reg = <0x0000 0 0 0 0>;
++					#address-cells = <1>;
++					#size-cells = <0>;
++
++					local-mac-address = [00 00 00 00 00 00];
++				};
++			};
++		};
++	};
++};
++
+ /* off-board header */
+ &sai3 {
+ 	pinctrl-names = "default";
+@@ -243,6 +299,12 @@ MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+ 		>;
+ 	};
+ 
++	pinctrl_pcie0: pcie0grp {
++		fsl,pins = <
++			MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6	0x41
++		>;
++	};
++
+ 	pinctrl_pps: ppsgrp {
+ 		fsl,pins = <
+ 			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x41
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
+index f7e41e5c2c7b..da576f02fa31 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
+@@ -8,6 +8,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/linux-event-codes.h>
+ #include <dt-bindings/leds/common.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
+ 
+ #include "imx8mm.dtsi"
+ 
+@@ -179,6 +180,12 @@ led-b {
+ 		};
+ 	};
+ 
++	pcie0_refclk: pcie0-refclk {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++	};
++
+ 	reg_3p3v: regulator-3p3v {
+ 		compatible = "regulator-fixed";
+ 		regulator-name = "3P3V";
+@@ -632,6 +639,28 @@ &i2c4 {
+ 	status = "okay";
+ };
+ 
++&pcie_phy {
++	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
++	fsl,clkreq-unsupported;
++	clocks = <&pcie0_refclk>;
++	status = "okay";
++};
++
++&pcie0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pinctrl_pcie0>;
++	reset-gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;
++	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
++		 <&pcie0_refclk>;
++	clock-names = "pcie", "pcie_aux", "pcie_bus";
++	assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
++			  <&clk IMX8MM_CLK_PCIE1_CTRL>;
++	assigned-clock-rates = <10000000>, <250000000>;
++	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
++				 <&clk IMX8MM_SYS_PLL2_250M>;
++	status = "okay";
++};
++
+ &uart1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>;
+@@ -797,6 +826,13 @@ MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19	0x41 /* RST# */
+ 		>;
+ 	};
+ 
++	pinctrl_pcie0: pciegrp {
++		fsl,pins = <
++			MX8MM_IOMUXC_SAI3_TXFS_GPIO4_IO31	0x40000041 /* WDIS# */
++			MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2	0x41
++		>;
++	};
++
+ 	pinctrl_pmic: pmicgrp {
+ 		fsl,pins = <
+ 			MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20	0x41
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
+index d52686f4c059..1b2aaf299b24 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
+@@ -9,6 +9,7 @@
+ #include <dt-bindings/input/linux-event-codes.h>
+ #include <dt-bindings/leds/common.h>
+ #include <dt-bindings/net/ti-dp83867.h>
++#include <dt-bindings/phy/phy-imx8-pcie.h>
+ 
+ #include "imx8mm.dtsi"
+ 
+@@ -17,6 +18,7 @@ / {
+ 	compatible = "gw,imx8mm-gw7902", "fsl,imx8mm";
+ 
+ 	aliases {
++		ethernet1 = &eth1;
+ 		usb0 = &usbotg1;
+ 		usb1 = &usbotg2;
+ 	};
+@@ -128,6 +130,12 @@ led-4 {
+ 		};
+ 	};
+ 
++	pcie0_refclk: pcie0-refclk {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++	};
++
+ 	pps {
+ 		compatible = "pps-gpio";
+ 		pinctrl-names = "default";
+@@ -547,6 +555,42 @@ &i2c4 {
+ 	status = "okay";
+ };
+ 
++&pcie_phy {
++	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
++	fsl,clkreq-unsupported;
++	clocks = <&clk IMX8MM_CLK_DUMMY>;
++	status = "okay";
++};
++
++&pcie0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pinctrl_pcie0>;
++	reset-gpio = <&gpio4 5 GPIO_ACTIVE_LOW>;
++	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
++		 <&clk IMX8MM_CLK_DUMMY>, <&pcie0_refclk>;
++	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
++	assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
++			  <&clk IMX8MM_CLK_PCIE1_CTRL>;
++	assigned-clock-rates = <10000000>, <250000000>;
++	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
++				 <&clk IMX8MM_SYS_PLL2_250M>;
++	status = "okay";
++
++	pcie at 0,0 {
++		reg = <0x0000 0 0 0 0>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		eth1: pcie at 1,0 {
++			reg = <0x0000 0 0 0 0>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			local-mac-address = [00 00 00 00 00 00];
++		};
++	};
++};
++
+ /* off-board header */
+ &sai3 {
+ 	pinctrl-names = "default";
+@@ -737,6 +781,12 @@ MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25	0x19
+ 		>;
+ 	};
+ 
++	pinctrl_pcie0: pciegrp {
++		fsl,pins = <
++			MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5	0x41
++		>;
++	};
++
+ 	pinctrl_pmic: pmicgrp {
+ 		fsl,pins = <
+ 			MX8MM_IOMUXC_NAND_DATA02_GPIO3_IO8	0x41
+-- 
+2.25.1
+
-- 
2.25.1




More information about the openwrt-devel mailing list