diff mbox series

airoha: Add new target platform

Message ID 20220727115723.2890210-1-daniel@dd-wrt.com
State Superseded
Delegated to: Hauke Mehrtens
Headers show
Series airoha: Add new target platform | expand

Commit Message

Daniel Danzberger July 27, 2022, 11:57 a.m. UTC
Airoha is a new ARM platform based on Cortex A7 which has recently been
merged into linux-next.

This support is based mostly on those linux-next commits backported
for kernel 5.15.

Patches:
1 - platform support = linux-next
2 - clock driver = linux-next
3 - gpio driver = linux-next
4 - linux,usable-memory-range dts support = linux-next
5 - mtd spinand driver
6 - spi driver
7 - pci driver (kconfig only, uses mediatek PCI) = linux-next

Still missing:
- Ethernet driver
- Sysupgrade support

A.t.m there exists one subtarget EN7523 with only one evaluation
board.

The initramfs can be run with the following commands from u-boot:
-
u-boot> setenv bootfile \
	openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
u-boot> tftpboot
u-boot> bootm 0x81800000
-

Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
---
 target/linux/airoha/Makefile                  |  15 +
 target/linux/airoha/config-5.15               | 278 ++++++++++++++
 target/linux/airoha/dts/en7523-evb.dts        |  73 ++++
 target/linux/airoha/dts/en7523.dtsi           | 219 +++++++++++
 .../files/arch/arm/mach-airoha/Makefile       |   2 +
 .../files/arch/arm/mach-airoha/airoha.c       |  16 +
 .../airoha/files/drivers/clk/clk-en7523.c     | 351 ++++++++++++++++++
 .../airoha/files/drivers/gpio/gpio-en7523.c   | 137 +++++++
 .../include/dt-bindings/clock/en7523-clk.h    |  17 +
 target/linux/airoha/image/Makefile            |  37 ++
 target/linux/airoha/image/en7523.mk           |   0
 .../0001-add-airoha-platform.patch            |  35 ++
 .../0002-add-airoha-en7523-clk-driver.patch   |  32 ++
 .../0003-add-airoha-en7523-gpio-driver.patch  |  33 ++
 ...press-Parse-linux-usable-memory-rang.patch | 111 ++++++
 ...nd-Add-support-for-Etron-EM73D044VCx.patch | 137 +++++++
 ...for-the-Airoha-EN7523-SoC-SPI-contro.patch | 346 +++++++++++++++++
 ...iatek-Allow-building-for-ARCH_AIROHA.patch |  35 ++
 18 files changed, 1874 insertions(+)
 create mode 100644 target/linux/airoha/Makefile
 create mode 100644 target/linux/airoha/config-5.15
 create mode 100644 target/linux/airoha/dts/en7523-evb.dts
 create mode 100644 target/linux/airoha/dts/en7523.dtsi
 create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/Makefile
 create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/airoha.c
 create mode 100644 target/linux/airoha/files/drivers/clk/clk-en7523.c
 create mode 100644 target/linux/airoha/files/drivers/gpio/gpio-en7523.c
 create mode 100644 target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h
 create mode 100644 target/linux/airoha/image/Makefile
 create mode 100644 target/linux/airoha/image/en7523.mk
 create mode 100644 target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch
 create mode 100644 target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch
 create mode 100644 target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch
 create mode 100644 target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch
 create mode 100644 target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
 create mode 100644 target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch
 create mode 100644 target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch

Comments

Hauke Mehrtens July 27, 2022, 12:49 p.m. UTC | #1
Hi Daniel,

Is it possible to buy devices with this SoC in the retail market or on ebay?

On 7/27/22 13:57, Daniel Danzberger wrote:
> Airoha is a new ARM platform based on Cortex A7 which has recently been
> merged into linux-next.

The device tree says it is a arm,cortex-a53, see 
target/linux/airoha/dts/en7523.dtsi

> This support is based mostly on those linux-next commits backported
> for kernel 5.15.
> 
> Patches:
> 1 - platform support = linux-next
> 2 - clock driver = linux-next
> 3 - gpio driver = linux-next
> 4 - linux,usable-memory-range dts support = linux-next
> 5 - mtd spinand driver
> 6 - spi driver
> 7 - pci driver (kconfig only, uses mediatek PCI) = linux-next
> 
> Still missing:
> - Ethernet driver
> - Sysupgrade support
> 
> A.t.m there exists one subtarget EN7523 with only one evaluation
> board.

How close is the hardware to other medaitek SoCs? Should we add this as 
a subtarget to mediatek?

> 
> The initramfs can be run with the following commands from u-boot:
> -
> u-boot> setenv bootfile \
> 	openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
> u-boot> tftpboot
> u-boot> bootm 0x81800000
> -
> 
> Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
> ---
>   target/linux/airoha/Makefile                  |  15 +
>   target/linux/airoha/config-5.15               | 278 ++++++++++++++
>   target/linux/airoha/dts/en7523-evb.dts        |  73 ++++
>   target/linux/airoha/dts/en7523.dtsi           | 219 +++++++++++
>   .../files/arch/arm/mach-airoha/Makefile       |   2 +
>   .../files/arch/arm/mach-airoha/airoha.c       |  16 +
>   .../airoha/files/drivers/clk/clk-en7523.c     | 351 ++++++++++++++++++
>   .../airoha/files/drivers/gpio/gpio-en7523.c   | 137 +++++++
>   .../include/dt-bindings/clock/en7523-clk.h    |  17 +
>   target/linux/airoha/image/Makefile            |  37 ++
>   target/linux/airoha/image/en7523.mk           |   0
>   .../0001-add-airoha-platform.patch            |  35 ++
>   .../0002-add-airoha-en7523-clk-driver.patch   |  32 ++
>   .../0003-add-airoha-en7523-gpio-driver.patch  |  33 ++
>   ...press-Parse-linux-usable-memory-rang.patch | 111 ++++++
>   ...nd-Add-support-for-Etron-EM73D044VCx.patch | 137 +++++++
>   ...for-the-Airoha-EN7523-SoC-SPI-contro.patch | 346 +++++++++++++++++
>   ...iatek-Allow-building-for-ARCH_AIROHA.patch |  35 ++
>   18 files changed, 1874 insertions(+)
>   create mode 100644 target/linux/airoha/Makefile
>   create mode 100644 target/linux/airoha/config-5.15
>   create mode 100644 target/linux/airoha/dts/en7523-evb.dts
>   create mode 100644 target/linux/airoha/dts/en7523.dtsi
>   create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/Makefile
>   create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/airoha.c
>   create mode 100644 target/linux/airoha/files/drivers/clk/clk-en7523.c
>   create mode 100644 target/linux/airoha/files/drivers/gpio/gpio-en7523.c
>   create mode 100644 target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h
>   create mode 100644 target/linux/airoha/image/Makefile
>   create mode 100644 target/linux/airoha/image/en7523.mk
>   create mode 100644 target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch
>   create mode 100644 target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch
> 
> diff --git a/target/linux/airoha/Makefile b/target/linux/airoha/Makefile
> new file mode 100644
> index 0000000000..723bec8cd4
> --- /dev/null
> +++ b/target/linux/airoha/Makefile
> @@ -0,0 +1,15 @@
> +include $(TOPDIR)/rules.mk
> +
> +ARCH:=arm
> +BOARD:=airoha
> +BOARDNAME:=Airoha ARM
> +CPU_TYPE:=cortex-a7
> +FEATURES:=dt squashfs nand ramdisk gpio source-only
> +
> +KERNEL_PATCHVER:=5.15
> +
> +include $(INCLUDE_DIR)/target.mk
> +
> +KERNELNAME:=Image dtbs
> +
> +$(eval $(call BuildTarget))
> diff --git a/target/linux/airoha/config-5.15 b/target/linux/airoha/config-5.15
> new file mode 100644
> index 0000000000..6717e8d19b
> --- /dev/null
> +++ b/target/linux/airoha/config-5.15
> @@ -0,0 +1,278 @@
.....
> +CONFIG_CACHE_L2X0=y
> +# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
> +CONFIG_CC_OPTIMIZE_FOR_SIZE=y

Why do you select CONFIG_CC_OPTIMIZE_FOR_SIZE ? all other targets except 
the mediatek/mt7629 use CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE.

> +CONFIG_CHR_DEV_SCH=y
Why do you need CONFIG_CHR_DEV_SCH?

> +CONFIG_CLONE_BACKWARDS=y
> +CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
> +CONFIG_CMDLINE_FROM_BOOTLOADER=y
.....
> +CONFIG_DCACHE_WORD_ACCESS=y
> +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
> +CONFIG_DEBUG_MISC=y
> +CONFIG_DEFAULT_HOSTNAME="(airoha)"

Setting CONFIG_DEFAULT_HOSTNAME looks wrong.

> +CONFIG_DMA_OPS=y
....
> +CONFIG_HANDLE_DOMAIN_IRQ=y
> +# CONFIG_HARDENED_USERCOPY is not set

Please activate CONFIG_HARDENED_USERCOPY.

> +CONFIG_HARDEN_BRANCH_PREDICTOR=y
> +CONFIG_HARDIRQS_SW_RESEND=y
....
> +CONFIG_NEED_DMA_MAP_STATE=y
> +CONFIG_NETFILTER=y
> +CONFIG_NET_FLOW_LIMIT=y
> +CONFIG_NET_SELFTESTS=y

Please do not activate these CONFIG_NET options here.

> +CONFIG_NLS=y
....
> +CONFIG_OF_MDIO=y
> +CONFIG_OLD_SIGACTION=y
> +CONFIG_OLD_SIGSUSPEND3=y

I think we do not need these CONFIG_OLT_* options.

> +CONFIG_OUTER_CACHE=y
.....
> +CONFIG_SRCU=y
> +CONFIG_STACKTRACE=y

This should not be activated for only one target.

> +# CONFIG_SWAP is not set
> +CONFIG_SWCONFIG=y

Do you really need CONFIG_SWCONFIG?

> +CONFIG_SWPHY=y
.....
> diff --git a/target/linux/airoha/dts/en7523.dtsi b/target/linux/airoha/dts/en7523.dtsi
> new file mode 100644
> index 0000000000..72478b225c
> --- /dev/null
> +++ b/target/linux/airoha/dts/en7523.dtsi
> @@ -0,0 +1,219 @@
.....
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		cpu-map {
> +			cluster0 {
> +				core0 {
> +					cpu = <&cpu0>;
> +				};
> +				core1 {
> +					cpu = <&cpu1>;
> +				};
> +			};
> +		};
> +
> +		cpu0: cpu@0 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a53";
> +			reg = <0x0>;
> +			enable-method = "psci";
> +			clock-frequency = <80000000>;
> +			next-level-cache = <&L2_0>;
> +		};

Here it says cortex a53

> +
> +		cpu1: cpu@1 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a53";
> +			reg = <0x1>;
> +			enable-method = "psci";
> +			clock-frequency = <80000000>;
> +			next-level-cache = <&L2_0>;
> +		};
> +
> +		L2_0: l2-cache0 {
> +			compatible = "cache";
> +		};
> +	};
> +

.....

> diff --git a/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> new file mode 100644
> index 0000000000..a48e02fc08
> --- /dev/null
> +++ b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> @@ -0,0 +1,137 @@
> +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> +index 9c64d9fc..5f99ea72 100644
> +--- a/drivers/mtd/nand/spi/Makefile
> ++++ b/drivers/mtd/nand/spi/Makefile

Please move this patch to generic in OpenWrt and try to get it upstream 
too. It is likely that we will see this choip on other boards soon too.

> +@@ -1,3 +1,3 @@
> + # SPDX-License-Identifier: GPL-2.0
> +-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
> ++spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
> + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
> +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> +index 9839ee44..9ab44217 100644
> +--- a/drivers/mtd/nand/spi/core.c
> ++++ b/drivers/mtd/nand/spi/core.c
> +@@ -898,6 +898,7 @@ static const struct nand_ops spinand_ops = {
> + static const struct spinand_manufacturer *spinand_manufacturers[] = {
> +	&esmt_c8_spinand_manufacturer,
> +	&gigadevice_spinand_manufacturer,
> ++	&etron_spinand_manufacturer,
> +	&macronix_spinand_manufacturer,
> +	&micron_spinand_manufacturer,
> +	&paragon_spinand_manufacturer,
> +diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c
> +new file mode 100644
> +index 00000000..653092be
> +--- /dev/null
> ++++ b/drivers/mtd/nand/spi/etron.c
> +@@ -0,0 +1,98 @@
> ++// SPDX-License-Identifier: GPL-2.0
> ++
> ++#include <linux/device.h>
> ++#include <linux/kernel.h>
> ++#include <linux/mtd/spinand.h>
> ++
> ++#define SPINAND_MFR_ETRON			0xd5
> ++
> ++
> ++static SPINAND_OP_VARIANTS(read_cache_variants,
> ++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
> ++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
> ++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
> ++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
> ++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> ++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
> ++
> ++static SPINAND_OP_VARIANTS(write_cache_variants,
> ++		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
> ++		SPINAND_PROG_LOAD(true, 0, NULL, 0));
> ++
> ++static SPINAND_OP_VARIANTS(update_cache_variants,
> ++		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
> ++		SPINAND_PROG_LOAD(false, 0, NULL, 0));
> ++
> ++static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
> ++					struct mtd_oob_region *oobregion)
> ++{
> ++	if (section)
> ++		return -ERANGE;
> ++
> ++	oobregion->offset = 72;
> ++	oobregion->length = 56;
> ++
> ++	return 0;
> ++}
> ++
> ++static int etron_ooblayout_free(struct mtd_info *mtd, int section,
> ++			   struct mtd_oob_region *oobregion)
> ++{
> ++	if (section)
> ++		return -ERANGE;
> ++
> ++	oobregion->offset = 1;
> ++	oobregion->length = 71;
> ++
> ++	return 0;
> ++}
> ++
> ++static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
> ++{
> ++	switch (status & STATUS_ECC_MASK) {
> ++	case STATUS_ECC_NO_BITFLIPS:
> ++		return 0;
> ++
> ++	case STATUS_ECC_HAS_BITFLIPS:
> ++		/* Between 1-7 bitflips were corrected */
> ++		return 7;
> ++
> ++	case STATUS_ECC_MASK:
> ++		/* Maximum bitflips were corrected */
> ++		return 8;
> ++
> ++	case STATUS_ECC_UNCOR_ERROR:
> ++		return -EBADMSG;
> ++	}
> ++
> ++	return -EINVAL;
> ++}
> ++
> ++static const struct mtd_ooblayout_ops etron_ooblayout = {
> ++	.ecc = etron_ooblayout_ecc,
> ++	.free = etron_ooblayout_free,
> ++};
> ++
> ++static const struct spinand_info etron_spinand_table[] = {
> ++	SPINAND_INFO("EM73D044VCx",
> ++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
> ++		     // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
> ++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
> ++		     NAND_ECCREQ(8, 512),
> ++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
> ++					      &write_cache_variants,
> ++					      &update_cache_variants),
> ++		     SPINAND_HAS_QE_BIT,
> ++		     SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
> ++};
> ++
> ++static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
> ++};
> ++
> ++const struct spinand_manufacturer etron_spinand_manufacturer = {
> ++	.id = SPINAND_MFR_ETRON,
> ++	.name = "Etron",
> ++	.chips = etron_spinand_table,
> ++	.nchips = ARRAY_SIZE(etron_spinand_table),
> ++	.ops = &etron_spinand_manuf_ops,
> ++};
> +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> +index 2066962d..11d38d2f 100644
> +--- a/include/linux/mtd/spinand.h
> ++++ b/include/linux/mtd/spinand.h
> +@@ -261,6 +261,7 @@ struct spinand_manufacturer {
> +
> + /* SPI NAND manufacturers */
> + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
> ++extern const struct spinand_manufacturer etron_spinand_manufacturer;
> + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
> + extern const struct spinand_manufacturer macronix_spinand_manufacturer;
> + extern const struct spinand_manufacturer micron_spinand_manufacturer;
.....
Robert Marko July 27, 2022, 12:53 p.m. UTC | #2
On Wed, 27 Jul 2022 at 14:50, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>
> Hi Daniel,
>
> Is it possible to buy devices with this SoC in the retail market or on ebay?
>
> On 7/27/22 13:57, Daniel Danzberger wrote:
> > Airoha is a new ARM platform based on Cortex A7 which has recently been
> > merged into linux-next.

Is this the one where A53 core is being limited to AArch32 by the BootROM?

Regards,
Robert
>
> The device tree says it is a arm,cortex-a53, see
> target/linux/airoha/dts/en7523.dtsi
>
> > This support is based mostly on those linux-next commits backported
> > for kernel 5.15.
> >
> > Patches:
> > 1 - platform support = linux-next
> > 2 - clock driver = linux-next
> > 3 - gpio driver = linux-next
> > 4 - linux,usable-memory-range dts support = linux-next
> > 5 - mtd spinand driver
> > 6 - spi driver
> > 7 - pci driver (kconfig only, uses mediatek PCI) = linux-next
> >
> > Still missing:
> > - Ethernet driver
> > - Sysupgrade support
> >
> > A.t.m there exists one subtarget EN7523 with only one evaluation
> > board.
>
> How close is the hardware to other medaitek SoCs? Should we add this as
> a subtarget to mediatek?
>
> >
> > The initramfs can be run with the following commands from u-boot:
> > -
> > u-boot> setenv bootfile \
> >       openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
> > u-boot> tftpboot
> > u-boot> bootm 0x81800000
> > -
> >
> > Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
> > ---
> >   target/linux/airoha/Makefile                  |  15 +
> >   target/linux/airoha/config-5.15               | 278 ++++++++++++++
> >   target/linux/airoha/dts/en7523-evb.dts        |  73 ++++
> >   target/linux/airoha/dts/en7523.dtsi           | 219 +++++++++++
> >   .../files/arch/arm/mach-airoha/Makefile       |   2 +
> >   .../files/arch/arm/mach-airoha/airoha.c       |  16 +
> >   .../airoha/files/drivers/clk/clk-en7523.c     | 351 ++++++++++++++++++
> >   .../airoha/files/drivers/gpio/gpio-en7523.c   | 137 +++++++
> >   .../include/dt-bindings/clock/en7523-clk.h    |  17 +
> >   target/linux/airoha/image/Makefile            |  37 ++
> >   target/linux/airoha/image/en7523.mk           |   0
> >   .../0001-add-airoha-platform.patch            |  35 ++
> >   .../0002-add-airoha-en7523-clk-driver.patch   |  32 ++
> >   .../0003-add-airoha-en7523-gpio-driver.patch  |  33 ++
> >   ...press-Parse-linux-usable-memory-rang.patch | 111 ++++++
> >   ...nd-Add-support-for-Etron-EM73D044VCx.patch | 137 +++++++
> >   ...for-the-Airoha-EN7523-SoC-SPI-contro.patch | 346 +++++++++++++++++
> >   ...iatek-Allow-building-for-ARCH_AIROHA.patch |  35 ++
> >   18 files changed, 1874 insertions(+)
> >   create mode 100644 target/linux/airoha/Makefile
> >   create mode 100644 target/linux/airoha/config-5.15
> >   create mode 100644 target/linux/airoha/dts/en7523-evb.dts
> >   create mode 100644 target/linux/airoha/dts/en7523.dtsi
> >   create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/Makefile
> >   create mode 100644 target/linux/airoha/files/arch/arm/mach-airoha/airoha.c
> >   create mode 100644 target/linux/airoha/files/drivers/clk/clk-en7523.c
> >   create mode 100644 target/linux/airoha/files/drivers/gpio/gpio-en7523.c
> >   create mode 100644 target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h
> >   create mode 100644 target/linux/airoha/image/Makefile
> >   create mode 100644 target/linux/airoha/image/en7523.mk
> >   create mode 100644 target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch
> >   create mode 100644 target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch
> >
> > diff --git a/target/linux/airoha/Makefile b/target/linux/airoha/Makefile
> > new file mode 100644
> > index 0000000000..723bec8cd4
> > --- /dev/null
> > +++ b/target/linux/airoha/Makefile
> > @@ -0,0 +1,15 @@
> > +include $(TOPDIR)/rules.mk
> > +
> > +ARCH:=arm
> > +BOARD:=airoha
> > +BOARDNAME:=Airoha ARM
> > +CPU_TYPE:=cortex-a7
> > +FEATURES:=dt squashfs nand ramdisk gpio source-only
> > +
> > +KERNEL_PATCHVER:=5.15
> > +
> > +include $(INCLUDE_DIR)/target.mk
> > +
> > +KERNELNAME:=Image dtbs
> > +
> > +$(eval $(call BuildTarget))
> > diff --git a/target/linux/airoha/config-5.15 b/target/linux/airoha/config-5.15
> > new file mode 100644
> > index 0000000000..6717e8d19b
> > --- /dev/null
> > +++ b/target/linux/airoha/config-5.15
> > @@ -0,0 +1,278 @@
> .....
> > +CONFIG_CACHE_L2X0=y
> > +# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
> > +CONFIG_CC_OPTIMIZE_FOR_SIZE=y
>
> Why do you select CONFIG_CC_OPTIMIZE_FOR_SIZE ? all other targets except
> the mediatek/mt7629 use CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE.
>
> > +CONFIG_CHR_DEV_SCH=y
> Why do you need CONFIG_CHR_DEV_SCH?
>
> > +CONFIG_CLONE_BACKWARDS=y
> > +CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
> > +CONFIG_CMDLINE_FROM_BOOTLOADER=y
> .....
> > +CONFIG_DCACHE_WORD_ACCESS=y
> > +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
> > +CONFIG_DEBUG_MISC=y
> > +CONFIG_DEFAULT_HOSTNAME="(airoha)"
>
> Setting CONFIG_DEFAULT_HOSTNAME looks wrong.
>
> > +CONFIG_DMA_OPS=y
> ....
> > +CONFIG_HANDLE_DOMAIN_IRQ=y
> > +# CONFIG_HARDENED_USERCOPY is not set
>
> Please activate CONFIG_HARDENED_USERCOPY.
>
> > +CONFIG_HARDEN_BRANCH_PREDICTOR=y
> > +CONFIG_HARDIRQS_SW_RESEND=y
> ....
> > +CONFIG_NEED_DMA_MAP_STATE=y
> > +CONFIG_NETFILTER=y
> > +CONFIG_NET_FLOW_LIMIT=y
> > +CONFIG_NET_SELFTESTS=y
>
> Please do not activate these CONFIG_NET options here.
>
> > +CONFIG_NLS=y
> ....
> > +CONFIG_OF_MDIO=y
> > +CONFIG_OLD_SIGACTION=y
> > +CONFIG_OLD_SIGSUSPEND3=y
>
> I think we do not need these CONFIG_OLT_* options.
>
> > +CONFIG_OUTER_CACHE=y
> .....
> > +CONFIG_SRCU=y
> > +CONFIG_STACKTRACE=y
>
> This should not be activated for only one target.
>
> > +# CONFIG_SWAP is not set
> > +CONFIG_SWCONFIG=y
>
> Do you really need CONFIG_SWCONFIG?
>
> > +CONFIG_SWPHY=y
> .....
> > diff --git a/target/linux/airoha/dts/en7523.dtsi b/target/linux/airoha/dts/en7523.dtsi
> > new file mode 100644
> > index 0000000000..72478b225c
> > --- /dev/null
> > +++ b/target/linux/airoha/dts/en7523.dtsi
> > @@ -0,0 +1,219 @@
> .....
> > +     cpus {
> > +             #address-cells = <1>;
> > +             #size-cells = <0>;
> > +
> > +             cpu-map {
> > +                     cluster0 {
> > +                             core0 {
> > +                                     cpu = <&cpu0>;
> > +                             };
> > +                             core1 {
> > +                                     cpu = <&cpu1>;
> > +                             };
> > +                     };
> > +             };
> > +
> > +             cpu0: cpu@0 {
> > +                     device_type = "cpu";
> > +                     compatible = "arm,cortex-a53";
> > +                     reg = <0x0>;
> > +                     enable-method = "psci";
> > +                     clock-frequency = <80000000>;
> > +                     next-level-cache = <&L2_0>;
> > +             };
>
> Here it says cortex a53
>
> > +
> > +             cpu1: cpu@1 {
> > +                     device_type = "cpu";
> > +                     compatible = "arm,cortex-a53";
> > +                     reg = <0x1>;
> > +                     enable-method = "psci";
> > +                     clock-frequency = <80000000>;
> > +                     next-level-cache = <&L2_0>;
> > +             };
> > +
> > +             L2_0: l2-cache0 {
> > +                     compatible = "cache";
> > +             };
> > +     };
> > +
>
> .....
>
> > diff --git a/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> > new file mode 100644
> > index 0000000000..a48e02fc08
> > --- /dev/null
> > +++ b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> > @@ -0,0 +1,137 @@
> > +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> > +index 9c64d9fc..5f99ea72 100644
> > +--- a/drivers/mtd/nand/spi/Makefile
> > ++++ b/drivers/mtd/nand/spi/Makefile
>
> Please move this patch to generic in OpenWrt and try to get it upstream
> too. It is likely that we will see this choip on other boards soon too.
>
> > +@@ -1,3 +1,3 @@
> > + # SPDX-License-Identifier: GPL-2.0
> > +-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
> > ++spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
> > + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
> > +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> > +index 9839ee44..9ab44217 100644
> > +--- a/drivers/mtd/nand/spi/core.c
> > ++++ b/drivers/mtd/nand/spi/core.c
> > +@@ -898,6 +898,7 @@ static const struct nand_ops spinand_ops = {
> > + static const struct spinand_manufacturer *spinand_manufacturers[] = {
> > +     &esmt_c8_spinand_manufacturer,
> > +     &gigadevice_spinand_manufacturer,
> > ++    &etron_spinand_manufacturer,
> > +     &macronix_spinand_manufacturer,
> > +     &micron_spinand_manufacturer,
> > +     &paragon_spinand_manufacturer,
> > +diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c
> > +new file mode 100644
> > +index 00000000..653092be
> > +--- /dev/null
> > ++++ b/drivers/mtd/nand/spi/etron.c
> > +@@ -0,0 +1,98 @@
> > ++// SPDX-License-Identifier: GPL-2.0
> > ++
> > ++#include <linux/device.h>
> > ++#include <linux/kernel.h>
> > ++#include <linux/mtd/spinand.h>
> > ++
> > ++#define SPINAND_MFR_ETRON                   0xd5
> > ++
> > ++
> > ++static SPINAND_OP_VARIANTS(read_cache_variants,
> > ++            SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
> > ++            SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
> > ++            SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
> > ++            SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
> > ++            SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> > ++            SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
> > ++
> > ++static SPINAND_OP_VARIANTS(write_cache_variants,
> > ++            SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
> > ++            SPINAND_PROG_LOAD(true, 0, NULL, 0));
> > ++
> > ++static SPINAND_OP_VARIANTS(update_cache_variants,
> > ++            SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
> > ++            SPINAND_PROG_LOAD(false, 0, NULL, 0));
> > ++
> > ++static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
> > ++                                    struct mtd_oob_region *oobregion)
> > ++{
> > ++    if (section)
> > ++            return -ERANGE;
> > ++
> > ++    oobregion->offset = 72;
> > ++    oobregion->length = 56;
> > ++
> > ++    return 0;
> > ++}
> > ++
> > ++static int etron_ooblayout_free(struct mtd_info *mtd, int section,
> > ++                       struct mtd_oob_region *oobregion)
> > ++{
> > ++    if (section)
> > ++            return -ERANGE;
> > ++
> > ++    oobregion->offset = 1;
> > ++    oobregion->length = 71;
> > ++
> > ++    return 0;
> > ++}
> > ++
> > ++static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
> > ++{
> > ++    switch (status & STATUS_ECC_MASK) {
> > ++    case STATUS_ECC_NO_BITFLIPS:
> > ++            return 0;
> > ++
> > ++    case STATUS_ECC_HAS_BITFLIPS:
> > ++            /* Between 1-7 bitflips were corrected */
> > ++            return 7;
> > ++
> > ++    case STATUS_ECC_MASK:
> > ++            /* Maximum bitflips were corrected */
> > ++            return 8;
> > ++
> > ++    case STATUS_ECC_UNCOR_ERROR:
> > ++            return -EBADMSG;
> > ++    }
> > ++
> > ++    return -EINVAL;
> > ++}
> > ++
> > ++static const struct mtd_ooblayout_ops etron_ooblayout = {
> > ++    .ecc = etron_ooblayout_ecc,
> > ++    .free = etron_ooblayout_free,
> > ++};
> > ++
> > ++static const struct spinand_info etron_spinand_table[] = {
> > ++    SPINAND_INFO("EM73D044VCx",
> > ++                 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
> > ++                 // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
> > ++                 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
> > ++                 NAND_ECCREQ(8, 512),
> > ++                 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
> > ++                                          &write_cache_variants,
> > ++                                          &update_cache_variants),
> > ++                 SPINAND_HAS_QE_BIT,
> > ++                 SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
> > ++};
> > ++
> > ++static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
> > ++};
> > ++
> > ++const struct spinand_manufacturer etron_spinand_manufacturer = {
> > ++    .id = SPINAND_MFR_ETRON,
> > ++    .name = "Etron",
> > ++    .chips = etron_spinand_table,
> > ++    .nchips = ARRAY_SIZE(etron_spinand_table),
> > ++    .ops = &etron_spinand_manuf_ops,
> > ++};
> > +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> > +index 2066962d..11d38d2f 100644
> > +--- a/include/linux/mtd/spinand.h
> > ++++ b/include/linux/mtd/spinand.h
> > +@@ -261,6 +261,7 @@ struct spinand_manufacturer {
> > +
> > + /* SPI NAND manufacturers */
> > + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
> > ++extern const struct spinand_manufacturer etron_spinand_manufacturer;
> > + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
> > + extern const struct spinand_manufacturer macronix_spinand_manufacturer;
> > + extern const struct spinand_manufacturer micron_spinand_manufacturer;
> .....
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Daniel Danzberger July 31, 2022, 7:04 a.m. UTC | #3
On Wed, 2022-07-27 at 14:49 +0200, Hauke Mehrtens wrote:
> Hi Daniel,
> 
> Is it possible to buy devices with this SoC in the retail market or on ebay?
Hi, not yet. At least I don't know of any. Maybe @john knows ?
> 
> Why do you select CONFIG_CC_OPTIMIZE_FOR_SIZE ? all other targets except 
> the mediatek/mt7629 use CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE.
I used mt7629 as a reference, but CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE works as well.
Once there is Wifi/Ethernet support, I will do some benchmarks and figure out which option works best.
> 
> > +CONFIG_CHR_DEV_SCH=y
> Why do you need CONFIG_CHR_DEV_SCH?
> 
> > +CONFIG_CLONE_BACKWARDS=y
> > +CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
> > +CONFIG_CMDLINE_FROM_BOOTLOADER=y
> .....
> > +CONFIG_DCACHE_WORD_ACCESS=y
> > +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
> > +CONFIG_DEBUG_MISC=y
> > +CONFIG_DEFAULT_HOSTNAME="(airoha)"
> 
> Setting CONFIG_DEFAULT_HOSTNAME looks wrong.
> 
> > +CONFIG_DMA_OPS=y
> ....
> > +CONFIG_HANDLE_DOMAIN_IRQ=y
> > +# CONFIG_HARDENED_USERCOPY is not set
> 
> Please activate CONFIG_HARDENED_USERCOPY.
> 
> > +CONFIG_HARDEN_BRANCH_PREDICTOR=y
> > +CONFIG_HARDIRQS_SW_RESEND=y
> ....
> > +CONFIG_NEED_DMA_MAP_STATE=y
> > +CONFIG_NETFILTER=y
> > +CONFIG_NET_FLOW_LIMIT=y
> > +CONFIG_NET_SELFTESTS=y
> 
> Please do not activate these CONFIG_NET options here.
> 
> > +CONFIG_NLS=y
> ....
> > +CONFIG_OF_MDIO=y
> > +CONFIG_OLD_SIGACTION=y
> > +CONFIG_OLD_SIGSUSPEND3=y
> 
> I think we do not need these CONFIG_OLT_* options.
> 
> > +CONFIG_OUTER_CACHE=y
> .....
> > +CONFIG_SRCU=y
> > +CONFIG_STACKTRACE=y
> 
> This should not be activated for only one target.
> 
> > +# CONFIG_SWAP is not set
> > +CONFIG_SWCONFIG=y
> 
> Do you really need CONFIG_SWCONFIG?
I cleaned up the kernel config.
Removed all configs you mentioned and enabled CONFIG_HARDENED_USERCOPY.
Daniel Danzberger July 31, 2022, 7:14 a.m. UTC | #4
On Wed, 2022-07-27 at 14:49 +0200, Hauke Mehrtens wrote

> > diff --git a/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/airoha/patches-5.15/0005-
> > mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> > new file mode 100644
> > index 0000000000..a48e02fc08
> > --- /dev/null
> > +++ b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
> > @@ -0,0 +1,137 @@
> > +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> > +index 9c64d9fc..5f99ea72 100644
> > +--- a/drivers/mtd/nand/spi/Makefile
> > ++++ b/drivers/mtd/nand/spi/Makefile
> 
> Please move this patch to generic in OpenWrt and try to get it upstream 
> too. It is likely that we will see this choip on other boards soon too.
Moved it to gerneric.
Daniel Danzberger Aug. 1, 2022, 4:16 p.m. UTC | #5
On Wed, 2022-07-27 at 14:53 +0200, Robert Marko wrote:
> On Wed, 27 Jul 2022 at 14:50, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> > 
> > Hi Daniel,
> > 
> > Is it possible to buy devices with this SoC in the retail market or on ebay?
> > 
> > On 7/27/22 13:57, Daniel Danzberger wrote:
> > > Airoha is a new ARM platform based on Cortex A7 which has recently been
> > > merged into linux-next.
> 
> Is this the one where A53 core is being limited to AArch32 by the BootROM?
> 
Yes, that's the case.
Daniel Danzberger Aug. 1, 2022, 4:27 p.m. UTC | #6
On Wed, 2022-07-27 at 14:49 +0200, Hauke Mehrtens wrote:
> Hi Daniel,
> 
> Is it possible to buy devices with this SoC in the retail market or on ebay?
> 
> On 7/27/22 13:57, Daniel Danzberger wrote:
> > Airoha is a new ARM platform based on Cortex A7 which has recently been
> > merged into linux-next.
> 
> The device tree says it is a arm,cortex-a53, see 
> target/linux/airoha/dts/en7523.dtsi
> > 
> .....
> > diff --git a/target/linux/airoha/dts/en7523.dtsi b/target/linux/airoha/dts/en7523.dtsi
> > new file mode 100644
> > index 0000000000..72478b225c
> > --- /dev/null
> > +++ b/target/linux/airoha/dts/en7523.dtsi
> > @@ -0,0 +1,219 @@
> .....
> > +       cpus {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +
> > +               cpu-map {
> > +                       cluster0 {
> > +                               core0 {
> > +                                       cpu = <&cpu0>;
> > +                               };
> > +                               core1 {
> > +                                       cpu = <&cpu1>;
> > +                               };
> > +                       };
> > +               };
> > +
> > +               cpu0: cpu@0 {
> > +                       device_type = "cpu";
> > +                       compatible = "arm,cortex-a53";
> > +                       reg = <0x0>;
> > +                       enable-method = "psci";
> > +                       clock-frequency = <80000000>;
> > +                       next-level-cache = <&L2_0>;
> > +               };
> 
> Here it says cortex a53

Yes, that's correct. It is a cortex a53. The description in the commit message is wong.
Even though it's an ARMv8-A with arm64, it needs to run in 32 bit mode due to the BootROM limitations.

The commit message will be corrected in the version of that patch.
Hauke Mehrtens Aug. 3, 2022, 6:56 p.m. UTC | #7
On 8/1/22 18:16, Daniel Danzberger wrote:
> On Wed, 2022-07-27 at 14:53 +0200, Robert Marko wrote:
>> On Wed, 27 Jul 2022 at 14:50, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>>>
>>> Hi Daniel,
>>>
>>> Is it possible to buy devices with this SoC in the retail market or on ebay?
>>>
>>> On 7/27/22 13:57, Daniel Danzberger wrote:
>>>> Airoha is a new ARM platform based on Cortex A7 which has recently been
>>>> merged into linux-next.
>>
>> Is this the one where A53 core is being limited to AArch32 by the BootROM?
>>
> Yes, that's the case.

Why would anyone do this?

I trust you that this SoC is strange, but I do not understand why 
someone would do this. Is aarch64 broken in this SoC and this is their 
software workaround?

Hauke
diff mbox series

Patch

diff --git a/target/linux/airoha/Makefile b/target/linux/airoha/Makefile
new file mode 100644
index 0000000000..723bec8cd4
--- /dev/null
+++ b/target/linux/airoha/Makefile
@@ -0,0 +1,15 @@ 
+include $(TOPDIR)/rules.mk
+
+ARCH:=arm
+BOARD:=airoha
+BOARDNAME:=Airoha ARM
+CPU_TYPE:=cortex-a7
+FEATURES:=dt squashfs nand ramdisk gpio source-only
+
+KERNEL_PATCHVER:=5.15
+
+include $(INCLUDE_DIR)/target.mk
+
+KERNELNAME:=Image dtbs
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/airoha/config-5.15 b/target/linux/airoha/config-5.15
new file mode 100644
index 0000000000..6717e8d19b
--- /dev/null
+++ b/target/linux/airoha/config-5.15
@@ -0,0 +1,278 @@ 
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_AIROHA=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_ARM_GIC_V3_ITS=y
+CONFIG_ARM_GIC_V3_ITS_PCI=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_HEAVY_MB=y
+# CONFIG_ARM_HIGHBANK_CPUIDLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_PATCH_IDIV=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_PSCI=y
+CONFIG_ARM_PSCI_FW=y
+# CONFIG_ARM_SMMU is not set
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATAGS=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_PM=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_CACHE_L2X0=y
+# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_EN7523=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SPECTRE=y
+CONFIG_CPU_THUMB_CAPABLE=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+CONFIG_DEBUG_MISC=y
+CONFIG_DEFAULT_HOSTNAME="(airoha)"
+CONFIG_DMA_OPS=y
+CONFIG_DMA_REMAP=y
+CONFIG_DTC=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_VDSO_32=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_EN7523=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+# CONFIG_HARDENED_USERCOPY is not set
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAVE_SMP=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HW_RANDOM=y
+CONFIG_HZ_FIXED=0
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_IOMMU_DEBUGFS is not set
+# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_IO_URING=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IRQ_WORK=y
+# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGRATION=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NETFILTER=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NLS=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=2
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PARTITION_PERCPU=y
+CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_MEDIATEK=y
+CONFIG_PCIE_PME=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PINCTRL=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SCSI=y
+CONFIG_SCSI_COMMON=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_FSL=y
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_AIROHA_EN7523=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SRCU=y
+CONFIG_STACKTRACE=y
+# CONFIG_SWAP is not set
+CONFIG_SWCONFIG=y
+CONFIG_SWPHY=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNWINDER_ARM=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_XHCI_HCD=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+CONFIG_USE_OF=y
+# CONFIG_VFP is not set
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_XPS=y
+CONFIG_XXHASH=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
diff --git a/target/linux/airoha/dts/en7523-evb.dts b/target/linux/airoha/dts/en7523-evb.dts
new file mode 100644
index 0000000000..f311c840e0
--- /dev/null
+++ b/target/linux/airoha/dts/en7523-evb.dts
@@ -0,0 +1,73 @@ 
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/dts-v1/;
+
+/* Bootloader installs ATF here */
+/memreserve/ 0x80000000 0x200000;
+
+#include "en7523.dtsi"
+
+/ {
+	model = "Airoha EN7523 Evaluation Board";
+	compatible = "airoha,en7523-evb", "airoha,en7523";
+
+	aliases {
+		serial0 = &uart1;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlycon";
+		stdout-path = "serial0:115200n8";
+		linux,usable-memory-range = <0x80200000 0x1fe00000>;
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x20000000>;
+	};
+};
+
+&gpio0 {
+	status = "okay";
+};
+
+&gpio1 {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "okay";
+};
+
+&pcie1 {
+	status = "okay";
+};
+
+&nand {
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "u-boot";
+			reg = <0x0 0x7C000>;
+			read-only;
+		};
+
+		partition@1 {
+			label = "u-boot-env";
+			reg = <0x7C000 0x4000>;
+		};
+
+		partition@2 {
+			label = "art";
+			reg = <0x80000 0x40000>;
+			read-only;
+		};
+
+		partition@3 {
+			label = "firmware";
+			reg = <0xC0000 0xDF40000>;
+		};
+	};
+};
diff --git a/target/linux/airoha/dts/en7523.dtsi b/target/linux/airoha/dts/en7523.dtsi
new file mode 100644
index 0000000000..72478b225c
--- /dev/null
+++ b/target/linux/airoha/dts/en7523.dtsi
@@ -0,0 +1,219 @@ 
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/en7523-clk.h>
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		npu_binary@84000000 {
+			no-map;
+			reg = <0x84000000 0xA00000>;
+		};
+
+		npu_flag@84B0000 {
+			no-map;
+			reg = <0x84B00000 0x100000>;
+		};
+
+		npu_pkt@85000000 {
+			no-map;
+			reg = <0x85000000 0x1A00000>;
+		};
+
+		npu_phyaddr@86B00000 {
+			no-map;
+			reg = <0x86B00000 0x100000>;
+		};
+
+		npu_rxdesc@86D00000 {
+			no-map;
+			reg = <0x86D00000 0x100000>;
+		};
+	};
+
+	psci {
+		compatible = "arm,psci-0.2";
+		method = "smc";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&cpu0>;
+				};
+				core1 {
+					cpu = <&cpu1>;
+				};
+			};
+		};
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			enable-method = "psci";
+			clock-frequency = <80000000>;
+			next-level-cache = <&L2_0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			enable-method = "psci";
+			clock-frequency = <80000000>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	scu: system-controller@1fa20000 {
+		compatible = "airoha,en7523-scu";
+		reg = <0x1fa20000 0x400>,
+		      <0x1fb00000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	gic: interrupt-controller@9000000 {
+		compatible = "arm,gic-v3";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x09000000 0x20000>,
+		      <0x09080000 0x80000>,
+		      <0x09400000 0x2000>,
+		      <0x09500000 0x2000>,
+		      <0x09600000 0x20000>;
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	uart1: serial@1fbf0000 {
+		compatible = "ns16550";
+		reg = <0x1fbf0000 0x30>;
+		reg-io-width = <4>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <1843200>;
+		status = "okay";
+	};
+
+	gpio0: gpio@1fbf0200 {
+		compatible = "airoha,en7523-gpio";
+		reg = <0x1fbf0204 0x4>,
+		      <0x1fbf0200 0x4>,
+		      <0x1fbf0220 0x4>,
+		      <0x1fbf0214 0x4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpio1: gpio@1fbf0270 {
+		compatible = "airoha,en7523-gpio";
+		reg = <0x1fbf0270 0x4>,
+		      <0x1fbf0260 0x4>,
+		      <0x1fbf0264 0x4>,
+		      <0x1fbf0278 0x4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	pcie0: pcie@1fa91000 {
+		compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
+		device_type = "pci";
+		reg = <0x1fa91000 0x1000>;
+		reg-names = "port0";
+		linux,pci-domain = <0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "pcie_irq";
+		clocks = <&scu EN7523_CLK_PCIE>;
+		clock-names = "sys_ck0";
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000  0x20000000  0 0x8000000>;
+		status = "disabled";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+				<0 0 0 2 &pcie_intc0 1>,
+				<0 0 0 3 &pcie_intc0 2>,
+				<0 0 0 4 &pcie_intc0 3>;
+		pcie_intc0: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	pcie1: pcie@1fa92000 {
+		compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
+		device_type = "pci";
+		reg = <0x1fa92000 0x1000>;
+		reg-names = "port1";
+		linux,pci-domain = <1>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "pcie_irq";
+		clocks = <&scu EN7523_CLK_PCIE>;
+		clock-names = "sys_ck1";
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x28000000  0x28000000  0 0x8000000>;
+		status = "disabled";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+				<0 0 0 2 &pcie_intc1 1>,
+				<0 0 0 3 &pcie_intc1 2>,
+				<0 0 0 4 &pcie_intc1 3>;
+		pcie_intc1: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	spi_ctrl: spi_controller@1fa10000 {
+		compatible = "airoha,en7523-spi";
+		reg = <0x1fa10000 0x140>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-rx-bus-width = <2>;
+		spi-tx-bus-width = <2>;
+
+		nand: nand@0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			nand-ecc-engine = <&nand>;
+		};
+	};
+};
diff --git a/target/linux/airoha/files/arch/arm/mach-airoha/Makefile b/target/linux/airoha/files/arch/arm/mach-airoha/Makefile
new file mode 100644
index 0000000000..a5857d0d02
--- /dev/null
+++ b/target/linux/airoha/files/arch/arm/mach-airoha/Makefile
@@ -0,0 +1,2 @@ 
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y			+= airoha.o
diff --git a/target/linux/airoha/files/arch/arm/mach-airoha/airoha.c b/target/linux/airoha/files/arch/arm/mach-airoha/airoha.c
new file mode 100644
index 0000000000..ea23b5abb4
--- /dev/null
+++ b/target/linux/airoha/files/arch/arm/mach-airoha/airoha.c
@@ -0,0 +1,16 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Device Tree support for Airoha SoCs
+ *
+ * Copyright (c) 2022 Felix Fietkau <nbd@nbd.name>
+ */
+#include <asm/mach/arch.h>
+
+static const char * const airoha_board_dt_compat[] = {
+	"airoha,en7523",
+	NULL,
+};
+
+DT_MACHINE_START(MEDIATEK_DT, "Airoha Cortex-A53 (Device Tree)")
+	.dt_compat	= airoha_board_dt_compat,
+MACHINE_END
diff --git a/target/linux/airoha/files/drivers/clk/clk-en7523.c b/target/linux/airoha/files/drivers/clk/clk-en7523.c
new file mode 100644
index 0000000000..29f0126cbd
--- /dev/null
+++ b/target/linux/airoha/files/drivers/clk/clk-en7523.c
@@ -0,0 +1,351 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/en7523-clk.h>
+
+#define REG_PCI_CONTROL			0x88
+#define   REG_PCI_CONTROL_PERSTOUT	BIT(29)
+#define   REG_PCI_CONTROL_PERSTOUT1	BIT(26)
+#define   REG_PCI_CONTROL_REFCLK_EN1	BIT(22)
+#define REG_GSW_CLK_DIV_SEL		0x1b4
+#define REG_EMI_CLK_DIV_SEL		0x1b8
+#define REG_BUS_CLK_DIV_SEL		0x1bc
+#define REG_SPI_CLK_DIV_SEL		0x1c4
+#define REG_SPI_CLK_FREQ_SEL		0x1c8
+#define REG_NPU_CLK_DIV_SEL		0x1fc
+#define REG_CRYPTO_CLKSRC		0x200
+#define REG_RESET_CONTROL		0x834
+#define   REG_RESET_CONTROL_PCIEHB	BIT(29)
+#define   REG_RESET_CONTROL_PCIE1	BIT(27)
+#define   REG_RESET_CONTROL_PCIE2	BIT(26)
+
+struct en_clk_desc {
+	int id;
+	const char *name;
+	u32 base_reg;
+	u8 base_bits;
+	u8 base_shift;
+	union {
+		const unsigned int *base_values;
+		unsigned int base_value;
+	};
+	size_t n_base_values;
+
+	u16 div_reg;
+	u8 div_bits;
+	u8 div_shift;
+	u16 div_val0;
+	u8 div_step;
+};
+
+struct en_clk_gate {
+	void __iomem *base;
+	struct clk_hw hw;
+};
+
+static const u32 gsw_base[] = { 400000000, 500000000 };
+static const u32 emi_base[] = { 333000000, 400000000 };
+static const u32 bus_base[] = { 500000000, 540000000 };
+static const u32 slic_base[] = { 100000000, 3125000 };
+static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
+
+static const struct en_clk_desc en7523_base_clks[] = {
+	{
+		.id = EN7523_CLK_GSW,
+		.name = "gsw",
+
+		.base_reg = REG_GSW_CLK_DIV_SEL,
+		.base_bits = 1,
+		.base_shift = 8,
+		.base_values = gsw_base,
+		.n_base_values = ARRAY_SIZE(gsw_base),
+
+		.div_bits = 3,
+		.div_shift = 0,
+		.div_step = 1,
+	}, {
+		.id = EN7523_CLK_EMI,
+		.name = "emi",
+
+		.base_reg = REG_EMI_CLK_DIV_SEL,
+		.base_bits = 1,
+		.base_shift = 8,
+		.base_values = emi_base,
+		.n_base_values = ARRAY_SIZE(emi_base),
+
+		.div_bits = 3,
+		.div_shift = 0,
+		.div_step = 1,
+	}, {
+		.id = EN7523_CLK_BUS,
+		.name = "bus",
+
+		.base_reg = REG_BUS_CLK_DIV_SEL,
+		.base_bits = 1,
+		.base_shift = 8,
+		.base_values = bus_base,
+		.n_base_values = ARRAY_SIZE(bus_base),
+
+		.div_bits = 3,
+		.div_shift = 0,
+		.div_step = 1,
+	}, {
+		.id = EN7523_CLK_SLIC,
+		.name = "slic",
+
+		.base_reg = REG_SPI_CLK_FREQ_SEL,
+		.base_bits = 1,
+		.base_shift = 0,
+		.base_values = slic_base,
+		.n_base_values = ARRAY_SIZE(slic_base),
+
+		.div_reg = REG_SPI_CLK_DIV_SEL,
+		.div_bits = 5,
+		.div_shift = 24,
+		.div_val0 = 20,
+		.div_step = 2,
+	}, {
+		.id = EN7523_CLK_SPI,
+		.name = "spi",
+
+		.base_reg = REG_SPI_CLK_DIV_SEL,
+
+		.base_value = 400000000,
+
+		.div_bits = 5,
+		.div_shift = 8,
+		.div_val0 = 40,
+		.div_step = 2,
+	}, {
+		.id = EN7523_CLK_NPU,
+		.name = "npu",
+
+		.base_reg = REG_NPU_CLK_DIV_SEL,
+		.base_bits = 2,
+		.base_shift = 8,
+		.base_values = npu_base,
+		.n_base_values = ARRAY_SIZE(npu_base),
+
+		.div_bits = 3,
+		.div_shift = 0,
+		.div_step = 1,
+	}, {
+		.id = EN7523_CLK_CRYPTO,
+		.name = "crypto",
+
+		.base_reg = REG_CRYPTO_CLKSRC,
+		.base_bits = 1,
+		.base_shift = 8,
+		.base_values = emi_base,
+		.n_base_values = ARRAY_SIZE(emi_base),
+	}
+};
+
+static const struct of_device_id of_match_clk_en7523[] = {
+	{ .compatible = "airoha,en7523-scu", },
+	{ /* sentinel */ }
+};
+
+static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
+{
+	const struct en_clk_desc *desc = &en7523_base_clks[i];
+	u32 val;
+
+	if (!desc->base_bits)
+		return desc->base_value;
+
+	val = readl(base + desc->base_reg);
+	val >>= desc->base_shift;
+	val &= (1 << desc->base_bits) - 1;
+
+	if (val >= desc->n_base_values)
+		return 0;
+
+	return desc->base_values[val];
+}
+
+static u32 en7523_get_div(void __iomem *base, int i)
+{
+	const struct en_clk_desc *desc = &en7523_base_clks[i];
+	u32 reg, val;
+
+	if (!desc->div_bits)
+		return 1;
+
+	reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+	val = readl(base + reg);
+	val >>= desc->div_shift;
+	val &= (1 << desc->div_bits) - 1;
+
+	if (!val && desc->div_val0)
+		return desc->div_val0;
+
+	return (val + 1) * desc->div_step;
+}
+
+static int en7523_pci_is_enabled(struct clk_hw *hw)
+{
+	struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+
+	return !!(readl(cg->base + REG_PCI_CONTROL) & REG_PCI_CONTROL_REFCLK_EN1);
+}
+
+static int en7523_pci_prepare(struct clk_hw *hw)
+{
+	struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+	void __iomem *np_base = cg->base;
+	u32 val, mask;
+
+	/* Need to pull device low before reset */
+	val = readl(np_base + REG_PCI_CONTROL);
+	val &= ~(REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT);
+	writel(val, np_base + REG_PCI_CONTROL);
+	usleep_range(1000, 2000);
+
+	/* Enable PCIe port 1 */
+	val |= REG_PCI_CONTROL_REFCLK_EN1;
+	writel(val, np_base + REG_PCI_CONTROL);
+	usleep_range(1000, 2000);
+
+	/* Reset to default */
+	val = readl(np_base + REG_RESET_CONTROL);
+	mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
+	       REG_RESET_CONTROL_PCIEHB;
+	writel(val & ~mask, np_base + REG_RESET_CONTROL);
+	usleep_range(1000, 2000);
+	writel(val | mask, np_base + REG_RESET_CONTROL);
+	msleep(100);
+	writel(val & ~mask, np_base + REG_RESET_CONTROL);
+	usleep_range(5000, 10000);
+
+	/* Release device */
+	mask = REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT;
+	val = readl(np_base + REG_PCI_CONTROL);
+	writel(val & ~mask, np_base + REG_PCI_CONTROL);
+	usleep_range(1000, 2000);
+	writel(val | mask, np_base + REG_PCI_CONTROL);
+	msleep(250);
+
+	return 0;
+}
+
+static void en7523_pci_unprepare(struct clk_hw *hw)
+{
+	struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+	void __iomem *np_base = cg->base;
+	u32 val;
+
+	val = readl(np_base + REG_PCI_CONTROL);
+	val &= ~REG_PCI_CONTROL_REFCLK_EN1;
+	writel(val, np_base + REG_PCI_CONTROL);
+}
+
+static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
+					       void __iomem *np_base)
+{
+	static const struct clk_ops pcie_gate_ops = {
+		.is_enabled = en7523_pci_is_enabled,
+		.prepare = en7523_pci_prepare,
+		.unprepare = en7523_pci_unprepare,
+	};
+	struct clk_init_data init = {
+		.name = "pcie",
+		.ops = &pcie_gate_ops,
+	};
+	struct en_clk_gate *cg;
+
+	cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
+	if (!cg)
+		return NULL;
+
+	cg->base = np_base;
+	cg->hw.init = &init;
+	en7523_pci_unprepare(&cg->hw);
+
+	if (clk_hw_register(dev, &cg->hw))
+		return NULL;
+
+	return &cg->hw;
+}
+
+static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
+				   void __iomem *base, void __iomem *np_base)
+{
+	struct clk_hw *hw;
+	u32 rate;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
+		const struct en_clk_desc *desc = &en7523_base_clks[i];
+
+		rate = en7523_get_base_rate(base, i);
+		rate /= en7523_get_div(base, i);
+
+		hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
+		if (IS_ERR(hw)) {
+			pr_err("Failed to register clk %s: %ld\n",
+			       desc->name, PTR_ERR(hw));
+			continue;
+		}
+
+		clk_data->hws[desc->id] = hw;
+	}
+
+	hw = en7523_register_pcie_clk(dev, np_base);
+	clk_data->hws[EN7523_CLK_PCIE] = hw;
+
+	clk_data->num = EN7523_NUM_CLOCKS;
+}
+
+static int en7523_clk_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct clk_hw_onecell_data *clk_data;
+	void __iomem *base, *np_base;
+	int r;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	np_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(np_base))
+		return PTR_ERR(np_base);
+
+	clk_data = devm_kzalloc(&pdev->dev,
+				struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
+				GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
+
+	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+	if (r)
+		dev_err(&pdev->dev,
+			"could not register clock provider: %s: %d\n",
+			pdev->name, r);
+
+	return r;
+}
+
+static struct platform_driver clk_en7523_drv = {
+	.probe = en7523_clk_probe,
+	.driver = {
+		.name = "clk-en7523",
+		.of_match_table = of_match_clk_en7523,
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init clk_en7523_init(void)
+{
+	return platform_driver_register(&clk_en7523_drv);
+}
+
+arch_initcall(clk_en7523_init);
diff --git a/target/linux/airoha/files/drivers/gpio/gpio-en7523.c b/target/linux/airoha/files/drivers/gpio/gpio-en7523.c
new file mode 100644
index 0000000000..f836a8db4c
--- /dev/null
+++ b/target/linux/airoha/files/drivers/gpio/gpio-en7523.c
@@ -0,0 +1,137 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/bits.h>
+#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define AIROHA_GPIO_MAX		32
+
+/**
+ * airoha_gpio_ctrl - Airoha GPIO driver data
+ * @gc: Associated gpio_chip instance.
+ * @data: The data register.
+ * @dir0: The direction register for the lower 16 pins.
+ * @dir1: The direction register for the higher 16 pins.
+ * @output: The output enable register.
+ */
+struct airoha_gpio_ctrl {
+	struct gpio_chip gc;
+	void __iomem *data;
+	void __iomem *dir[2];
+	void __iomem *output;
+};
+
+static struct airoha_gpio_ctrl *gc_to_ctrl(struct gpio_chip *gc)
+{
+	return container_of(gc, struct airoha_gpio_ctrl, gc);
+}
+
+static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
+			  int val, int out)
+{
+	struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
+	u32 dir = ioread32(ctrl->dir[gpio / 16]);
+	u32 output = ioread32(ctrl->output);
+	u32 mask = BIT((gpio % 16) * 2);
+
+	if (out) {
+		dir |= mask;
+		output |= BIT(gpio);
+	} else {
+		dir &= ~mask;
+		output &= ~BIT(gpio);
+	}
+
+	iowrite32(dir, ctrl->dir[gpio / 16]);
+
+	if (out)
+		gc->set(gc, gpio, val);
+
+	iowrite32(output, ctrl->output);
+
+	return 0;
+}
+
+static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
+			  int val)
+{
+	return airoha_dir_set(gc, gpio, val, 1);
+}
+
+static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	return airoha_dir_set(gc, gpio, 0, 0);
+}
+
+static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
+	u32 dir = ioread32(ctrl->dir[gpio / 16]);
+	u32 mask = BIT((gpio % 16) * 2);
+
+	return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int airoha_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct airoha_gpio_ctrl *ctrl;
+	int err;
+
+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	ctrl->data = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(ctrl->data))
+		return PTR_ERR(ctrl->data);
+
+	ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(ctrl->dir[0]))
+		return PTR_ERR(ctrl->dir[0]);
+
+	ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
+	if (IS_ERR(ctrl->dir[1]))
+		return PTR_ERR(ctrl->dir[1]);
+
+	ctrl->output = devm_platform_ioremap_resource(pdev, 3);
+	if (IS_ERR(ctrl->output))
+		return PTR_ERR(ctrl->output);
+
+	err = bgpio_init(&ctrl->gc, dev, 4, ctrl->data, NULL,
+			 NULL, NULL, NULL, 0);
+	if (err)
+		return dev_err_probe(dev, err, "unable to init generic GPIO");
+
+	ctrl->gc.ngpio = AIROHA_GPIO_MAX;
+	ctrl->gc.owner = THIS_MODULE;
+	ctrl->gc.direction_output = airoha_dir_out;
+	ctrl->gc.direction_input = airoha_dir_in;
+	ctrl->gc.get_direction = airoha_get_dir;
+
+	return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
+}
+
+static const struct of_device_id airoha_gpio_of_match[] = {
+	{ .compatible = "airoha,en7523-gpio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
+
+static struct platform_driver airoha_gpio_driver = {
+	.driver = {
+		.name = "airoha-gpio",
+		.of_match_table	= airoha_gpio_of_match,
+	},
+	.probe = airoha_gpio_probe,
+};
+module_platform_driver(airoha_gpio_driver);
+
+MODULE_DESCRIPTION("Airoha GPIO support");
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h b/target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h
new file mode 100644
index 0000000000..717d23a5e5
--- /dev/null
+++ b/target/linux/airoha/files/include/dt-bindings/clock/en7523-clk.h
@@ -0,0 +1,17 @@ 
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_
+#define _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_
+
+#define EN7523_CLK_GSW		0
+#define EN7523_CLK_EMI		1
+#define EN7523_CLK_BUS		2
+#define EN7523_CLK_SLIC		3
+#define EN7523_CLK_SPI		4
+#define EN7523_CLK_NPU		5
+#define EN7523_CLK_CRYPTO	6
+#define EN7523_CLK_PCIE		7
+
+#define EN7523_NUM_CLOCKS	8
+
+#endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */
diff --git a/target/linux/airoha/image/Makefile b/target/linux/airoha/image/Makefile
new file mode 100644
index 0000000000..c6def5ad65
--- /dev/null
+++ b/target/linux/airoha/image/Makefile
@@ -0,0 +1,37 @@ 
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+KERNEL_LOADADDR := 0x80208000
+
+define Target/Description
+	Build firmware images for Airoha EN7523 ARM based boards.
+endef
+
+# default all platform image(fit) build
+define Device/Default
+  PROFILES = Default $$(DEVICE_NAME)
+  KERNEL_NAME := Image
+  KERNEL = kernel-bin | lzma | \
+	fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
+  KERNEL_INITRAMFS = kernel-bin | lzma | \
+	fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd
+  FILESYSTEMS := squashfs
+  DEVICE_DTS_DIR := $(DTS_DIR)
+  IMAGES := sysupgrade.bin
+  IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \
+	pad-rootfs | append-metadata
+endef
+
+define Image/Build
+	$(call Image/Build/$(1),$(1))
+endef
+
+define Device/airoha_en7523-evb
+  DEVICE_VENDOR := Airoha
+  DEVICE_MODEL := EN7523 Evaluation Board
+  DEVICE_DTS := en7523-evb
+  DEVICE_DTS_DIR := ../dts
+endef
+TARGET_DEVICES += airoha_en7523-evb
+
+$(eval $(call BuildImage))
diff --git a/target/linux/airoha/image/en7523.mk b/target/linux/airoha/image/en7523.mk
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch b/target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch
new file mode 100644
index 0000000000..b1f88a6ac7
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0001-add-airoha-platform.patch
@@ -0,0 +1,35 @@ 
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 66f5d6c3..05cd3385 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -571,6 +571,18 @@ config ARCH_VIRT
+	select HAVE_ARM_ARCH_TIMER
+	select ARCH_SUPPORTS_BIG_ENDIAN
+
++config ARCH_AIROHA
++	bool "Airoha SoC Support"
++	depends on ARCH_MULTI_V7
++	select ARM_AMBA
++	select ARM_GIC
++	select ARM_GIC_V3
++	select ARM_PSCI
++	select HAVE_ARM_ARCH_TIMER
++	select COMMON_CLK
++	help
++	  Support for Airoha EN7523 SoCs
++
+ #
+ # This is sorted alphabetically by mach-* pathname.  However, plat-*
+ # Kconfigs may be included either alphabetically (according to the
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index fa45837b..c34f7463 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -156,6 +156,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
+ # Machine directory name.  This list is sorted alphanumerically
+ # by CONFIG_* macro name.
+ machine-$(CONFIG_ARCH_ACTIONS)		+= actions
++machine-$(CONFIG_ARCH_AIROHA)		+= airoha
+ machine-$(CONFIG_ARCH_ALPINE)		+= alpine
+ machine-$(CONFIG_ARCH_ARTPEC)		+= artpec
+ machine-$(CONFIG_ARCH_ASPEED)           += aspeed
diff --git a/target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch b/target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch
new file mode 100644
index 0000000000..676e0f40bb
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0002-add-airoha-en7523-clk-driver.patch
@@ -0,0 +1,32 @@ 
+diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
+index c5b3dc97..c973ac1a 100644
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -192,6 +192,15 @@ config COMMON_CLK_CS2000_CP
+	help
+	  If you say yes here you get support for the CS2000 clock multiplier.
+
++config COMMON_CLK_EN7523
++	bool "Clock driver for Airoha EN7523 SoC system clocks"
++	depends on OF
++	depends on ARCH_AIROHA || COMPILE_TEST
++	default ARCH_AIROHA
++	help
++	  This driver provides the fixed clocks and gates present on Airoha
++	  ARM silicon.
++
+ config COMMON_CLK_FSL_FLEXSPI
+	tristate "Clock driver for FlexSPI on Layerscape SoCs"
+	depends on ARCH_LAYERSCAPE || COMPILE_TEST
+diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
+index e4231212..be11d88c 100644
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925)	+= clk-cdce925.o
+ obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
+ obj-$(CONFIG_COMMON_CLK_CS2000_CP)	+= clk-cs2000-cp.o
+ obj-$(CONFIG_ARCH_SPARX5)		+= clk-sparx5.o
++obj-$(CONFIG_COMMON_CLK_EN7523)		+= clk-en7523.o
+ obj-$(CONFIG_COMMON_CLK_FIXED_MMIO)	+= clk-fixed-mmio.o
+ obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI)	+= clk-fsl-flexspi.o
+ obj-$(CONFIG_COMMON_CLK_FSL_SAI)	+= clk-fsl-sai.o
diff --git a/target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch b/target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch
new file mode 100644
index 0000000000..1d95e6b2c8
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0003-add-airoha-en7523-gpio-driver.patch
@@ -0,0 +1,33 @@ 
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index cbfb6f13..b3106df6 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -247,6 +247,16 @@ config GPIO_EM
+	help
+	  Say yes here to support GPIO on Renesas Emma Mobile SoCs.
+
++config GPIO_EN7523
++	tristate "Airoha GPIO support"
++	depends on ARCH_AIROHA
++	default ARCH_AIROHA
++	select GPIO_GENERIC
++	select GPIOLIB_IRQCHIP
++	help
++	  Say Y or M here to support the GPIO controller block on the
++	  Airoha EN7523 SoC. It supports two banks of 32 GPIOs.
++
+ config GPIO_EP93XX
+	def_bool y
+	depends on ARCH_EP93XX
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 61202717..4c73ce82 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -57,6 +57,7 @@ obj-$(CONFIG_GPIO_DLN2)			+= gpio-dln2.o
+ obj-$(CONFIG_GPIO_DWAPB)		+= gpio-dwapb.o
+ obj-$(CONFIG_GPIO_EIC_SPRD)		+= gpio-eic-sprd.o
+ obj-$(CONFIG_GPIO_EM)			+= gpio-em.o
++obj-$(CONFIG_GPIO_EN7523)		+= gpio-en7523.o
+ obj-$(CONFIG_GPIO_EP93XX)		+= gpio-ep93xx.o
+ obj-$(CONFIG_GPIO_EXAR)			+= gpio-exar.o
+ obj-$(CONFIG_GPIO_F7188X)		+= gpio-f7188x.o
diff --git a/target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch b/target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch
new file mode 100644
index 0000000000..f13ab2b0ed
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0004-ARM-9124-1-uncompress-Parse-linux-usable-memory-rang.patch
@@ -0,0 +1,111 @@ 
+From 48342ae751c797ac73ac9c894b3f312df18ffd21 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Wed, 15 Sep 2021 13:46:20 +0100
+Subject: [PATCH] ARM: 9124/1: uncompress: Parse "linux,usable-memory-range" DT
+ property
+
+Add support for parsing the "linux,usable-memory-range" DT property.
+This property is used to describe the usable memory reserved for the
+crash dump kernel, and thus makes the memory reservation explicit.
+If present, Linux no longer needs to mask the program counter, and rely
+on the "mem=" kernel parameter to obtain the start and size of usable
+memory.
+
+For backwards compatibility, the traditional method to derive the start
+of memory is still used if "linux,usable-memory-range" is absent.
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
+---
+ .../arm/boot/compressed/fdt_check_mem_start.c | 48 ++++++++++++++++---
+ 1 file changed, 42 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/boot/compressed/fdt_check_mem_start.c b/arch/arm/boot/compressed/fdt_check_mem_start.c
+index 62450d824c3c..9291a2661bdf 100644
+--- a/arch/arm/boot/compressed/fdt_check_mem_start.c
++++ b/arch/arm/boot/compressed/fdt_check_mem_start.c
+@@ -55,16 +55,17 @@ static uint64_t get_val(const fdt32_t *cells, uint32_t ncells)
+  * DTB, and, if out-of-range, replace it by the real start address.
+  * To preserve backwards compatibility (systems reserving a block of memory
+  * at the start of physical memory, kdump, ...), the traditional method is
+- * always used if it yields a valid address.
++ * used if it yields a valid address, unless the "linux,usable-memory-range"
++ * property is present.
+  *
+  * Return value: start address of physical memory to use
+  */
+ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
+ {
+-	uint32_t addr_cells, size_cells, base;
++	uint32_t addr_cells, size_cells, usable_base, base;
+	uint32_t fdt_mem_start = 0xffffffff;
+-	const fdt32_t *reg, *endp;
+-	uint64_t size, end;
++	const fdt32_t *usable, *reg, *endp;
++	uint64_t size, usable_end, end;
+	const char *type;
+	int offset, len;
+
+@@ -80,6 +81,27 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
+	if (addr_cells > 2 || size_cells > 2)
+		return mem_start;
+
++	/*
++	 * Usable memory in case of a crash dump kernel
++	 * This property describes a limitation: memory within this range is
++	 * only valid when also described through another mechanism
++	 */
++	usable = get_prop(fdt, "/chosen", "linux,usable-memory-range",
++			  (addr_cells + size_cells) * sizeof(fdt32_t));
++	if (usable) {
++		size = get_val(usable + addr_cells, size_cells);
++		if (!size)
++			return mem_start;
++
++		if (addr_cells > 1 && fdt32_ld(usable)) {
++			/* Outside 32-bit address space */
++			return mem_start;
++		}
++
++		usable_base = fdt32_ld(usable + addr_cells - 1);
++		usable_end = usable_base + size;
++	}
++
+	/* Walk all memory nodes and regions */
+	for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+@@ -107,7 +129,20 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
+
+			base = fdt32_ld(reg + addr_cells - 1);
+			end = base + size;
+-			if (mem_start >= base && mem_start < end) {
++			if (usable) {
++				/*
++				 * Clip to usable range, which takes precedence
++				 * over mem_start
++				 */
++				if (base < usable_base)
++					base = usable_base;
++
++				if (end > usable_end)
++					end = usable_end;
++
++				if (end <= base)
++					continue;
++			} else if (mem_start >= base && mem_start < end) {
+				/* Calculated address is valid, use it */
+				return mem_start;
+			}
+@@ -123,7 +158,8 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
+	}
+
+	/*
+-	 * The calculated address is not usable.
++	 * The calculated address is not usable, or was overridden by the
++	 * "linux,usable-memory-range" property.
+	 * Use the lowest usable physical memory address from the DTB instead,
+	 * and make sure this is a multiple of 2 MiB for phys/virt patching.
+	 */
+--
+2.35.1
diff --git a/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
new file mode 100644
index 0000000000..a48e02fc08
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0005-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch
@@ -0,0 +1,137 @@ 
+diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
+index 9c64d9fc..5f99ea72 100644
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
++spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index 9839ee44..9ab44217 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -898,6 +898,7 @@ static const struct nand_ops spinand_ops = {
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+	&esmt_c8_spinand_manufacturer,
+	&gigadevice_spinand_manufacturer,
++	&etron_spinand_manufacturer,
+	&macronix_spinand_manufacturer,
+	&micron_spinand_manufacturer,
+	&paragon_spinand_manufacturer,
+diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c
+new file mode 100644
+index 00000000..653092be
+--- /dev/null
++++ b/drivers/mtd/nand/spi/etron.c
+@@ -0,0 +1,98 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_ETRON			0xd5
++
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++		SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++		SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
++					struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 72;
++	oobregion->length = 56;
++
++	return 0;
++}
++
++static int etron_ooblayout_free(struct mtd_info *mtd, int section,
++			   struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 1;
++	oobregion->length = 71;
++
++	return 0;
++}
++
++static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
++{
++	switch (status & STATUS_ECC_MASK) {
++	case STATUS_ECC_NO_BITFLIPS:
++		return 0;
++
++	case STATUS_ECC_HAS_BITFLIPS:
++		/* Between 1-7 bitflips were corrected */
++		return 7;
++
++	case STATUS_ECC_MASK:
++		/* Maximum bitflips were corrected */
++		return 8;
++
++	case STATUS_ECC_UNCOR_ERROR:
++		return -EBADMSG;
++	}
++
++	return -EINVAL;
++}
++
++static const struct mtd_ooblayout_ops etron_ooblayout = {
++	.ecc = etron_ooblayout_ecc,
++	.free = etron_ooblayout_free,
++};
++
++static const struct spinand_info etron_spinand_table[] = {
++	SPINAND_INFO("EM73D044VCx",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
++		     // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
++};
++
++static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
++};
++
++const struct spinand_manufacturer etron_spinand_manufacturer = {
++	.id = SPINAND_MFR_ETRON,
++	.name = "Etron",
++	.chips = etron_spinand_table,
++	.nchips = ARRAY_SIZE(etron_spinand_table),
++	.ops = &etron_spinand_manuf_ops,
++};
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 2066962d..11d38d2f 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -261,6 +261,7 @@ struct spinand_manufacturer {
+
+ /* SPI NAND manufacturers */
+ extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
++extern const struct spinand_manufacturer etron_spinand_manufacturer;
+ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
diff --git a/target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch b/target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch
new file mode 100644
index 0000000000..e368acc0cf
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0006-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch
@@ -0,0 +1,346 @@ 
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 83e352b0..5f7defe4 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -308,6 +308,12 @@ config SPI_DLN2
+	 This driver can also be built as a module.  If so, the module
+	 will be called spi-dln2.
+
++config SPI_AIROHA_EN7523
++	bool "Airoha EN7523 SPI controller support"
++	depends on ARCH_AIROHA
++	help
++	  This enables SPI controller support for the Airoha EN7523 SoC.
++
+ config SPI_EP93XX
+	tristate "Cirrus Logic EP93xx SPI controller"
+	depends on ARCH_EP93XX || COMPILE_TEST
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 699db95c..6c9460f7 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_DW_BT1)		+= spi-dw-bt1.o
+ obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
+ obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-pci.o
+ obj-$(CONFIG_SPI_EP93XX)		+= spi-ep93xx.o
++obj-$(CONFIG_SPI_AIROHA_EN7523)		+= spi-en7523.o
+ obj-$(CONFIG_SPI_FALCON)		+= spi-falcon.o
+ obj-$(CONFIG_SPI_FSI)			+= spi-fsi.o
+ obj-$(CONFIG_SPI_FSL_CPM)		+= spi-fsl-cpm.o
+diff --git a/drivers/spi/spi-en7523.c b/drivers/spi/spi-en7523.c
+new file mode 100644
+index 00000000..322bf2eb
+--- /dev/null
++++ b/drivers/spi/spi-en7523.c
+@@ -0,0 +1,311 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mod_devicetable.h>
++#include <linux/spi/spi.h>
++
++
++#define ENSPI_READ_IDLE_EN			0x0004
++#define ENSPI_MTX_MODE_TOG			0x0014
++#define ENSPI_RDCTL_FSM				0x0018
++#define ENSPI_MANUAL_EN				0x0020
++#define ENSPI_MANUAL_OPFIFO_EMPTY		0x0024
++#define ENSPI_MANUAL_OPFIFO_WDATA		0x0028
++#define ENSPI_MANUAL_OPFIFO_FULL		0x002C
++#define ENSPI_MANUAL_OPFIFO_WR			0x0030
++#define ENSPI_MANUAL_DFIFO_FULL			0x0034
++#define ENSPI_MANUAL_DFIFO_WDATA		0x0038
++#define ENSPI_MANUAL_DFIFO_EMPTY		0x003C
++#define ENSPI_MANUAL_DFIFO_RD			0x0040
++#define ENSPI_MANUAL_DFIFO_RDATA		0x0044
++#define ENSPI_IER				0x0090
++#define ENSPI_NFI2SPI_EN			0x0130
++
++// TODO not in spi block
++#define ENSPI_CLOCK_DIVIDER			((void __iomem *)0x1fa201c4)
++
++#define	OP_CSH					0x00
++#define	OP_CSL					0x01
++#define	OP_CK					0x02
++#define	OP_OUTS					0x08
++#define	OP_OUTD					0x09
++#define	OP_OUTQ					0x0A
++#define	OP_INS					0x0C
++#define	OP_INS0					0x0D
++#define	OP_IND					0x0E
++#define	OP_INQ					0x0F
++#define	OP_OS2IS				0x10
++#define	OP_OS2ID				0x11
++#define	OP_OS2IQ				0x12
++#define	OP_OD2IS				0x13
++#define	OP_OD2ID				0x14
++#define	OP_OD2IQ				0x15
++#define	OP_OQ2IS				0x16
++#define	OP_OQ2ID				0x17
++#define	OP_OQ2IQ				0x18
++#define	OP_OSNIS				0x19
++#define	OP_ODNID				0x1A
++
++#define MATRIX_MODE_AUTO		1
++#define   CONF_MTX_MODE_AUTO		0
++#define   MANUALEN_AUTO			0
++#define MATRIX_MODE_MANUAL		0
++#define   CONF_MTX_MODE_MANUAL		9
++#define   MANUALEN_MANUAL		1
++
++#define _ENSPI_MAX_XFER			0x1ff
++
++#define REG(x)			(iobase + x)
++
++
++static void __iomem *iobase;
++
++
++static void opfifo_write(u32 cmd, u32 len)
++{
++	u32 tmp = ((cmd & 0x1f) << 9) | (len & 0x1ff);
++
++	writel(tmp, REG(ENSPI_MANUAL_OPFIFO_WDATA));
++
++	/* Wait for room in OPFIFO */
++	while (readl(REG(ENSPI_MANUAL_OPFIFO_FULL)))
++		;
++
++	/* Shift command into OPFIFO */
++	writel(1, REG(ENSPI_MANUAL_OPFIFO_WR));
++
++	/* Wait for command to finish */
++	while (!readl(REG(ENSPI_MANUAL_OPFIFO_EMPTY)))
++		;
++}
++
++static void set_cs(int state)
++{
++	if (state)
++		opfifo_write(OP_CSH, 1);
++	else
++		opfifo_write(OP_CSL, 1);
++}
++
++static void manual_begin_cmd(void)
++{
++	/* Disable read idle state */
++	writel(0, REG(ENSPI_READ_IDLE_EN));
++
++	/* Wait for FSM to reach idle state */
++	while (readl(REG(ENSPI_RDCTL_FSM)))
++		;
++
++	/* Set SPI core to manual mode */
++	writel(CONF_MTX_MODE_MANUAL, REG(ENSPI_MTX_MODE_TOG));
++	writel(MANUALEN_MANUAL, REG(ENSPI_MANUAL_EN));
++}
++
++static void manual_end_cmd(void)
++{
++	/* Set SPI core to auto mode */
++	writel(CONF_MTX_MODE_AUTO, REG(ENSPI_MTX_MODE_TOG));
++	writel(MANUALEN_AUTO, REG(ENSPI_MANUAL_EN));
++
++	/* Enable read idle state */
++	writel(1, REG(ENSPI_READ_IDLE_EN));
++}
++
++static void dfifo_read(u8 *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		/* Wait for requested data to show up in DFIFO */
++		while (readl(REG(ENSPI_MANUAL_DFIFO_EMPTY)))
++			;
++		buf[i] = readl(REG(ENSPI_MANUAL_DFIFO_RDATA));
++		/* Queue up next byte */
++		writel(1, REG(ENSPI_MANUAL_DFIFO_RD));
++	}
++}
++
++static void dfifo_write(const u8 *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		/* Wait for room in DFIFO */
++		while (readl(REG(ENSPI_MANUAL_DFIFO_FULL)))
++			;
++		writel(buf[i], REG(ENSPI_MANUAL_DFIFO_WDATA));
++	}
++}
++
++static void set_spi_clock_speed(int freq_mhz)
++{
++	u32 tmp, val;
++
++	tmp = readl(ENSPI_CLOCK_DIVIDER);
++	tmp &= 0xffff0000;
++	writel(tmp, ENSPI_CLOCK_DIVIDER);
++
++	val = (400 / (freq_mhz * 2));
++	tmp |= (val << 8) | 1;
++	writel(tmp, ENSPI_CLOCK_DIVIDER);
++}
++
++static void init_hw(void)
++{
++	/* Disable manual/auto mode clash interrupt */
++	writel(0, REG(ENSPI_IER));
++
++	// TODO via clk framework
++	// set_spi_clock_speed(50);
++
++	/* Disable DMA */
++	writel(0, REG(ENSPI_NFI2SPI_EN));
++}
++
++static int xfer_read(struct spi_transfer *xfer)
++{
++	int opcode;
++	uint8_t *buf = xfer->rx_buf;
++
++	switch (xfer->rx_nbits) {
++	case SPI_NBITS_SINGLE:
++		opcode = OP_INS;
++		break;
++	case SPI_NBITS_DUAL:
++		opcode = OP_IND;
++		break;
++	case SPI_NBITS_QUAD:
++		opcode = OP_INQ;
++		break;
++	}
++
++	opfifo_write(opcode, xfer->len);
++	dfifo_read(buf, xfer->len);
++
++	return xfer->len;
++}
++
++static int xfer_write(struct spi_transfer *xfer, int next_xfer_is_rx)
++{
++	int opcode;
++	const uint8_t *buf = xfer->tx_buf;
++
++	if (next_xfer_is_rx) {
++		/* need to use Ox2Ix opcode to set the core to input afterwards */
++		switch (xfer->tx_nbits) {
++		case SPI_NBITS_SINGLE:
++			opcode = OP_OS2IS;
++			break;
++		case SPI_NBITS_DUAL:
++			opcode = OP_OS2ID;
++			break;
++		case SPI_NBITS_QUAD:
++			opcode = OP_OS2IQ;
++			break;
++		}
++	} else {
++		switch (xfer->tx_nbits) {
++		case SPI_NBITS_SINGLE:
++			opcode = OP_OUTS;
++			break;
++		case SPI_NBITS_DUAL:
++			opcode = OP_OUTD;
++			break;
++		case SPI_NBITS_QUAD:
++			opcode = OP_OUTQ;
++			break;
++		}
++	}
++
++	opfifo_write(opcode, xfer->len);
++	dfifo_write(buf, xfer->len);
++
++	return xfer->len;
++}
++
++size_t max_transfer_size(struct spi_device *spi)
++{
++	return _ENSPI_MAX_XFER;
++}
++
++int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg)
++{
++	struct spi_transfer *xfer;
++	int next_xfer_is_rx = 0;
++
++	manual_begin_cmd();
++	set_cs(0);
++	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
++		if (xfer->tx_buf) {
++			if (!list_is_last(&xfer->transfer_list, &msg->transfers)
++			    && list_next_entry(xfer, transfer_list)->rx_buf != NULL)
++				next_xfer_is_rx = 1;
++			else
++				next_xfer_is_rx = 0;
++			msg->actual_length += xfer_write(xfer, next_xfer_is_rx);
++		} else if (xfer->rx_buf) {
++			msg->actual_length += xfer_read(xfer);
++		}
++	}
++	set_cs(1);
++	manual_end_cmd();
++
++	msg->status = 0;
++	spi_finalize_current_message(ctrl);
++
++	return 0;
++}
++
++static int spi_probe(struct platform_device *pdev)
++{
++	struct spi_controller *ctrl;
++	int err;
++
++	ctrl = devm_spi_alloc_master(&pdev->dev, 0);
++	if (!ctrl) {
++		dev_err(&pdev->dev, "Error allocating SPI controller\n");
++		return -ENOMEM;
++	}
++
++	iobase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
++	if (IS_ERR(iobase)) {
++		dev_err(&pdev->dev, "Could not map SPI register address");
++		return -ENOMEM;
++	}
++
++	init_hw();
++
++	ctrl->dev.of_node = pdev->dev.of_node;
++	ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX;
++	ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL;
++	ctrl->max_transfer_size = max_transfer_size;
++	ctrl->transfer_one_message = transfer_one_message;
++	err = devm_spi_register_controller(&pdev->dev, ctrl);
++	if (err) {
++		dev_err(&pdev->dev, "Could not register SPI controller\n");
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++static const struct of_device_id spi_of_ids[] = {
++	{ .compatible = "airoha,en7523-spi" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, spi_of_ids);
++
++static struct platform_driver spi_driver = {
++	.probe = spi_probe,
++	.driver = {
++		.name = "airoha-en7523-spi",
++		.of_match_table = spi_of_ids,
++	},
++};
++
++module_platform_driver(spi_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
++MODULE_DESCRIPTION("Airoha EN7523 SPI driver");
diff --git a/target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch b/target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch
new file mode 100644
index 0000000000..9f51f281bc
--- /dev/null
+++ b/target/linux/airoha/patches-5.15/0007-PCI-mediatek-Allow-building-for-ARCH_AIROHA.patch
@@ -0,0 +1,35 @@ 
+From b3b76fc86f0fb4d98918f48c784138bfa950dff6 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 15 Jun 2022 14:53:34 +0200
+Subject: [PATCH] PCI: mediatek: Allow building for ARCH_AIROHA
+
+Allow selecting the pcie-mediatek driver if ARCH_AIROHA is set, because the
+Airoha EN7523 SoC uses the same controller as MT7622.
+
+The driver itself is not modified. The PCIe controller DT node should use
+mediatek,mt7622-pcie after airoha,en7523-pcie.
+
+Link: https://lore.kernel.org/r/20220615125335.96089-2-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
+---
+ drivers/pci/controller/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
+index b8d96d38064d..2f6806dc2a20 100644
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -237,7 +237,7 @@ config PCIE_ROCKCHIP_EP
+
+ config PCIE_MEDIATEK
+	tristate "MediaTek PCIe controller"
+-	depends on ARCH_MEDIATEK || COMPILE_TEST
++	depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
+	depends on OF
+	depends on PCI_MSI_IRQ_DOMAIN
+	help
+--
+2.35.1