uboot-ramips: add support for MT7621, merge into uboot-mediatek
authorDaniel Golle <daniel@makrotopia.org>
Mon, 11 Jul 2022 20:15:32 +0000 (21:15 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Mon, 11 Jul 2022 20:27:24 +0000 (21:27 +0100)
* Merge uboot-ramips into uboot-mediatek.
* Port support for the RAVPower RP WD009 to U-Boot 2022.07.
* Add support for MT7621 and add builds for the reference boards.
* Add builds for MT7620 and MT7628 reference boards.

This should help to make development of U-Boot-level board support for
all MediaTek targets much easier.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
30 files changed:
package/boot/uboot-mediatek/Makefile
package/boot/uboot-mediatek/patches/001-mtk-0001-mips-add-asm-mipsmtregs.h-for-MIPS-multi-threading.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0002-mips-add-more-definitions-for-asm-cm.h.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0003-mips-add-__image_copy_len-for-SPL-linker-script.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0004-mips-add-support-for-noncached_alloc.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0005-mips-mtmips-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0006-mips-mtmips-add-two-reference-boards-for-mt7621.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0007-doc-mediatek-add-documentation-for-mt7621-reference-.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0008-clk-mtmips-add-clock-driver-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0009-reset-mtmips-add-reset-controller-support-for-MediaT.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0010-pinctrl-mtmips-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0011-usb-xhci-mtk-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0012-phy-mtk-tphy-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0013-spi-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0014-gpio-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0015-watchdog-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0016-mmc-mediatek-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0017-net-mediatek-remap-iobase-address.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0018-net-mediatek-use-regmap-api-to-modify-ethsys-registe.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0019-net-mediatek-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0020-nand-raw-add-support-for-MediaTek-MT7621-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0021-spl-allow-using-nand-base-without-standard-nand-driv.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0022-spl-spl_legacy-fix-the-use-of-SPL_COPY_PAYLOAD_ONLY.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0023-spl-nand-support-loading-legacy-image-with-payload-c.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0024-tools-mtk_image-add-support-for-MT7621-NAND-images.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/001-mtk-0025-MAINTAINERS-update-maintainer-for-MediaTek-MIPS-plat.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch
package/boot/uboot-mediatek/patches/420-add-support-for-RAVPower-RP-WD009.patch [new file with mode: 0644]
package/boot/uboot-ramips/Makefile [deleted file]
package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch [deleted file]

index aeaf8bc14b29942a4801eab2604f750cfe56cac4..a994b8be4dbcecfb0c70de3fdc510410cef7b670 100644 (file)
@@ -9,11 +9,59 @@ include $(INCLUDE_DIR)/u-boot.mk
 include $(INCLUDE_DIR)/package.mk
 include $(INCLUDE_DIR)/host-build.mk
 
+MT7621_LOWLEVEL_PRELOADER_URL:=https://raw.githubusercontent.com/mtk-openwrt/mt7621-lowlevel-preloader/master/
+
+define Download/mt7621-stage-sram
+  FILE:=mt7621_stage_sram.bin
+  URL:=$(MT7621_LOWLEVEL_PRELOADER_URL)
+  HASH:=1dda68aa089f0ff262e01539b990dea478952e9fb68bcc0a8cd6f76f0135c62e
+endef
+
+ifdef CONFIG_TARGET_ramips_mt7621
+$(eval $(call Download,mt7621-stage-sram))
+endif
+
 define U-Boot/Default
   BUILD_TARGET:=mediatek
   UBOOT_IMAGE:=u-boot-mtk.bin
 endef
 
+define U-Boot/mt7620_rfb
+  NAME:=MT7620 Reference Board
+  UBOOT_CONFIG:=mt7620_rfb
+  BUILD_DEVICES:=ralink_mt7620a-evb
+  BUILD_TARGET:=ramips
+  BUILD_SUBTARGET:=mt7620
+  UBOOT_IMAGE:=u-boot-with-spl.bin
+endef
+
+define U-Boot/mt7620_mt7530_rfb
+  NAME:=MT7620+MT7530 Reference Board
+  UBOOT_CONFIG:=mt7620_mt7530_rfb
+  BUILD_DEVICES:=ralink_mt7620a-mt7530-evb
+  BUILD_TARGET:=ramips
+  BUILD_SUBTARGET:=mt7620
+  UBOOT_IMAGE:=u-boot-with-spl.bin
+endef
+
+define U-Boot/mt7621_rfb
+  NAME:=MT7621 Reference Board
+  UBOOT_CONFIG:=mt7621_rfb
+  BUILD_DEVICES:=mediatek_mt7621-eval-board
+  BUILD_TARGET:=ramips
+  BUILD_SUBTARGET:=mt7621
+  UBOOT_IMAGE:=u-boot-mt7621.bin
+endef
+
+define U-Boot/mt7621_nand_rfb
+  NAME:=MT7621 Reference Board (NAND)
+  UBOOT_CONFIG:=mt7621_nand_rfb
+  BUILD_DEVICES:=mediatek_mt7621-eval-board
+  BUILD_TARGET:=ramips
+  BUILD_SUBTARGET:=mt7621
+  UBOOT_IMAGE:=u-boot-mt7621.bin
+endef
+
 define U-Boot/mt7622_rfb1
   NAME:=MT7622 Reference Board 1
   UBOOT_CONFIG:=mt7622_rfb
@@ -91,6 +139,24 @@ define U-Boot/mt7623n_bpir2
   UBOOT_CONFIG:=mt7623n_bpir2
 endef
 
+define U-Boot/mt7628_rfb
+  NAME:=MT7628 Reference Board
+  BUILD_DEVICES:=mediatek_mt7628an-eval-board
+  BUILD_TARGET:=ramips
+  BUILD_SUBTARGET:=mt76x8
+  UBOOT_CONFIG:=mt7628_rfb
+  UBOOT_IMAGE:=u-boot-with-spl.bin
+endef
+
+define U-Boot/ravpower_rp-wd009
+  NAME:=RAVPower RP-WD009
+  BUILD_TARGET:=ramips
+  BUILD_DEVICES:=ravpower_rp-wd009
+  BUILD_SUBTARGET:=mt76x8
+  UBOOT_CONFIG:=ravpower-rp-wd009-ram
+  UBOOT_IMAGE:=u-boot.bin
+endef
+
 define U-Boot/mt7629_rfb
   NAME:=MT7629 Reference Board
   BUILD_SUBTARGET:=mt7629
@@ -99,6 +165,10 @@ define U-Boot/mt7629_rfb
 endef
 
 UBOOT_TARGETS := \
+       mt7620_mt7530_rfb \
+       mt7620_rfb \
+       mt7621_nand_rfb \
+       mt7621_rfb \
        mt7622_bananapi_bpi-r64-emmc \
        mt7622_bananapi_bpi-r64-sdmmc \
        mt7622_bananapi_bpi-r64-snand \
@@ -107,9 +177,13 @@ UBOOT_TARGETS := \
        mt7622_ubnt_unifi-6-lr \
        mt7623n_bpir2 \
        mt7623a_unielec_u7623 \
+       mt7628_rfb \
+       ravpower_rp-wd009 \
        mt7629_rfb
 
+ifdef CONFIG_TARGET_mediatek
 UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE:.fip=.bin)
+endif
 
 define Build/fip-image
        $(STAGING_DIR_HOST)/bin/fiptool create \
@@ -118,6 +192,13 @@ define Build/fip-image
                $(PKG_BUILD_DIR)/u-boot.fip
 endef
 
+ifdef CONFIG_TARGET_ramips_mt7621
+define Build/Prepare
+       $(call Build/Prepare/Default)
+       $(CP) $(DL_DIR)/mt7621_stage_sram.bin $(PKG_BUILD_DIR)/
+endef
+endif
+
 define Build/Configure
        $(call Build/Configure/U-Boot)
        sed -i 's/CONFIG_TOOLS_LIBCRYPTO=y/# CONFIG_TOOLS_LIBCRYPTO is not set/' $(PKG_BUILD_DIR)/.config
@@ -131,8 +212,10 @@ endif
 endef
 
 # don't stage files to bindir, let target/linux/mediatek/image/*.mk do that
+ifdef CONFIG_TARGET_mediatek
 define Package/u-boot/install
 endef
+endif
 
 define Build/InstallDev
        $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0001-mips-add-asm-mipsmtregs.h-for-MIPS-multi-threading.patch b/package/boot/uboot-mediatek/patches/001-mtk-0001-mips-add-asm-mipsmtregs.h-for-MIPS-multi-threading.patch
new file mode 100644 (file)
index 0000000..1a054c1
--- /dev/null
@@ -0,0 +1,169 @@
+From 65a4a80157bacde3cf86ce8cbc9a08f5f05ad9bb Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:21:34 +0800
+Subject: [PATCH 01/25] mips: add asm/mipsmtregs.h for MIPS multi-threading
+
+To be compatible with old u-boot used by lots of MT7621 devices, the u-boot
+needs to boot-up MT7621's all cores, and all VPES of each core.
+
+This patch adds asm/mipsmtregs.h from linux kernel which is need for
+boot-up VPEs.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/include/asm/mipsmtregs.h | 142 +++++++++++++++++++++++++++++
+ 1 file changed, 142 insertions(+)
+ create mode 100644 arch/mips/include/asm/mipsmtregs.h
+
+diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h
+new file mode 100644
+index 0000000000..ba82e2bd97
+--- /dev/null
++++ b/arch/mips/include/asm/mipsmtregs.h
+@@ -0,0 +1,142 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * MT regs definitions, follows on from mipsregs.h
++ * Copyright (C) 2004 - 2005 MIPS Technologies, Inc.  All rights reserved.
++ * Elizabeth Clarke et. al.
++ *
++ */
++#ifndef _ASM_MIPSMTREGS_H
++#define _ASM_MIPSMTREGS_H
++
++#include <asm/mipsregs.h>
++
++/*
++ * Macros for use in assembly language code
++ */
++
++#define CP0_MVPCONTROL                $0, 1
++#define CP0_MVPCONF0          $0, 2
++#define CP0_MVPCONF1          $0, 3
++#define CP0_VPECONTROL                $1, 1
++#define CP0_VPECONF0          $1, 2
++#define CP0_VPECONF1          $1, 3
++#define CP0_YQMASK            $1, 4
++#define CP0_VPESCHEDULE               $1, 5
++#define CP0_VPESCHEFBK                $1, 6
++#define CP0_TCSTATUS          $2, 1
++#define CP0_TCBIND            $2, 2
++#define CP0_TCRESTART         $2, 3
++#define CP0_TCHALT            $2, 4
++#define CP0_TCCONTEXT         $2, 5
++#define CP0_TCSCHEDULE                $2, 6
++#define CP0_TCSCHEFBK         $2, 7
++#define CP0_SRSCONF0          $6, 1
++#define CP0_SRSCONF1          $6, 2
++#define CP0_SRSCONF2          $6, 3
++#define CP0_SRSCONF3          $6, 4
++#define CP0_SRSCONF4          $6, 5
++
++/* MVPControl fields */
++#define MVPCONTROL_EVP                (_ULCAST_(1))
++
++#define MVPCONTROL_VPC_SHIFT  1
++#define MVPCONTROL_VPC                (_ULCAST_(1) << MVPCONTROL_VPC_SHIFT)
++
++#define MVPCONTROL_STLB_SHIFT 2
++#define MVPCONTROL_STLB               (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT)
++
++/* MVPConf0 fields */
++#define MVPCONF0_PTC_SHIFT    0
++#define MVPCONF0_PTC          (_ULCAST_(0xff))
++#define MVPCONF0_PVPE_SHIFT   10
++#define MVPCONF0_PVPE         (_ULCAST_(0xf) << MVPCONF0_PVPE_SHIFT)
++#define MVPCONF0_TCA_SHIFT    15
++#define MVPCONF0_TCA          (_ULCAST_(1) << MVPCONF0_TCA_SHIFT)
++#define MVPCONF0_PTLBE_SHIFT  16
++#define MVPCONF0_PTLBE                (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT)
++#define MVPCONF0_TLBS_SHIFT   29
++#define MVPCONF0_TLBS         (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT)
++#define MVPCONF0_M_SHIFT      31
++#define MVPCONF0_M            (_ULCAST_(0x1) << MVPCONF0_M_SHIFT)
++
++/* config3 fields */
++#define CONFIG3_MT_SHIFT      2
++#define CONFIG3_MT            (_ULCAST_(1) << CONFIG3_MT_SHIFT)
++
++/* VPEControl fields (per VPE) */
++#define VPECONTROL_TARGTC     (_ULCAST_(0xff))
++
++#define VPECONTROL_TE_SHIFT   15
++#define VPECONTROL_TE         (_ULCAST_(1) << VPECONTROL_TE_SHIFT)
++#define VPECONTROL_EXCPT_SHIFT        16
++#define VPECONTROL_EXCPT      (_ULCAST_(0x7) << VPECONTROL_EXCPT_SHIFT)
++
++/* Thread Exception Codes for EXCPT field */
++#define THREX_TU              0
++#define THREX_TO              1
++#define THREX_IYQ             2
++#define THREX_GSX             3
++#define THREX_YSCH            4
++#define THREX_GSSCH           5
++
++#define VPECONTROL_GSI_SHIFT  20
++#define VPECONTROL_GSI                (_ULCAST_(1) << VPECONTROL_GSI_SHIFT)
++#define VPECONTROL_YSI_SHIFT  21
++#define VPECONTROL_YSI                (_ULCAST_(1) << VPECONTROL_YSI_SHIFT)
++
++/* VPEConf0 fields (per VPE) */
++#define VPECONF0_VPA_SHIFT    0
++#define VPECONF0_VPA          (_ULCAST_(1) << VPECONF0_VPA_SHIFT)
++#define VPECONF0_MVP_SHIFT    1
++#define VPECONF0_MVP          (_ULCAST_(1) << VPECONF0_MVP_SHIFT)
++#define VPECONF0_XTC_SHIFT    21
++#define VPECONF0_XTC          (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT)
++
++/* VPEConf1 fields (per VPE) */
++#define VPECONF1_NCP1_SHIFT   0
++#define VPECONF1_NCP1         (_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT)
++#define VPECONF1_NCP2_SHIFT   10
++#define VPECONF1_NCP2         (_ULCAST_(0xff) << VPECONF1_NCP2_SHIFT)
++#define VPECONF1_NCX_SHIFT    20
++#define VPECONF1_NCX          (_ULCAST_(0xff) << VPECONF1_NCX_SHIFT)
++
++/* TCStatus fields (per TC) */
++#define TCSTATUS_TASID                (_ULCAST_(0xff))
++#define TCSTATUS_IXMT_SHIFT   10
++#define TCSTATUS_IXMT         (_ULCAST_(1) << TCSTATUS_IXMT_SHIFT)
++#define TCSTATUS_TKSU_SHIFT   11
++#define TCSTATUS_TKSU         (_ULCAST_(3) << TCSTATUS_TKSU_SHIFT)
++#define TCSTATUS_A_SHIFT      13
++#define TCSTATUS_A            (_ULCAST_(1) << TCSTATUS_A_SHIFT)
++#define TCSTATUS_DA_SHIFT     15
++#define TCSTATUS_DA           (_ULCAST_(1) << TCSTATUS_DA_SHIFT)
++#define TCSTATUS_DT_SHIFT     20
++#define TCSTATUS_DT           (_ULCAST_(1) << TCSTATUS_DT_SHIFT)
++#define TCSTATUS_TDS_SHIFT    21
++#define TCSTATUS_TDS          (_ULCAST_(1) << TCSTATUS_TDS_SHIFT)
++#define TCSTATUS_TSST_SHIFT   22
++#define TCSTATUS_TSST         (_ULCAST_(1) << TCSTATUS_TSST_SHIFT)
++#define TCSTATUS_RNST_SHIFT   23
++#define TCSTATUS_RNST         (_ULCAST_(3) << TCSTATUS_RNST_SHIFT)
++/* Codes for RNST */
++#define TC_RUNNING            0
++#define TC_WAITING            1
++#define TC_YIELDING           2
++#define TC_GATED              3
++
++#define TCSTATUS_TMX_SHIFT    27
++#define TCSTATUS_TMX          (_ULCAST_(1) << TCSTATUS_TMX_SHIFT)
++/* TCStatus TCU bits can use same definitions/offsets as CU bits in Status */
++
++/* TCBind */
++#define TCBIND_CURVPE_SHIFT   0
++#define TCBIND_CURVPE         (_ULCAST_(0xf))
++
++#define TCBIND_CURTC_SHIFT    21
++
++#define TCBIND_CURTC          (_ULCAST_(0xff) << TCBIND_CURTC_SHIFT)
++
++/* TCHalt */
++#define TCHALT_H              (_ULCAST_(1))
++
++#endif
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0002-mips-add-more-definitions-for-asm-cm.h.patch b/package/boot/uboot-mediatek/patches/001-mtk-0002-mips-add-more-definitions-for-asm-cm.h.patch
new file mode 100644 (file)
index 0000000..0a3a0a1
--- /dev/null
@@ -0,0 +1,116 @@
+From be570e7b0ce004127a7cc97bfae30037fc42a340 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:21:39 +0800
+Subject: [PATCH 02/25] mips: add more definitions for asm/cm.h
+
+This patch add more definitions needed for MT7621 initialization.
+MT7621 needs to initialize GIC/CPC and other related parts.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/include/asm/cm.h | 67 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 67 insertions(+)
+
+diff --git a/arch/mips/include/asm/cm.h b/arch/mips/include/asm/cm.h
+index 99ddbccd80..5cc8c09621 100644
+--- a/arch/mips/include/asm/cm.h
++++ b/arch/mips/include/asm/cm.h
+@@ -8,9 +8,23 @@
+ #define __MIPS_ASM_CM_H__
+ /* Global Control Register (GCR) offsets */
++#define GCR_CONFIG                    0x0000
+ #define GCR_BASE                      0x0008
+ #define GCR_BASE_UPPER                        0x000c
++#define GCR_CONTROL                   0x0010
++#define GCR_ACCESS                    0x0020
+ #define GCR_REV                               0x0030
++#define GCR_GIC_BASE                  0x0080
++#define GCR_CPC_BASE                  0x0088
++#define GCR_REG0_BASE                 0x0090
++#define GCR_REG0_MASK                 0x0098
++#define GCR_REG1_BASE                 0x00a0
++#define GCR_REG1_MASK                 0x00a8
++#define GCR_REG2_BASE                 0x00b0
++#define GCR_REG2_MASK                 0x00b8
++#define GCR_REG3_BASE                 0x00c0
++#define GCR_REG3_MASK                 0x00c8
++#define GCR_CPC_STATUS                        0x00f0
+ #define GCR_L2_CONFIG                 0x0130
+ #define GCR_L2_TAG_ADDR                       0x0600
+ #define GCR_L2_TAG_ADDR_UPPER         0x0604
+@@ -19,10 +33,59 @@
+ #define GCR_L2_DATA                   0x0610
+ #define GCR_L2_DATA_UPPER             0x0614
+ #define GCR_Cx_COHERENCE              0x2008
++#define GCR_Cx_OTHER                  0x2018
++#define GCR_Cx_ID                     0x2028
++#define GCR_CO_COHERENCE              0x4008
++
++/* GCR_CONFIG fields */
++#define GCR_CONFIG_NUM_CLUSTERS_SHIFT 23
++#define GCR_CONFIG_NUM_CLUSTERS               (0x7f << 23)
++#define GCR_CONFIG_NUMIOCU_SHIFT      8
++#define GCR_CONFIG_NUMIOCU            (0xff << 8)
++#define GCR_CONFIG_PCORES_SHIFT               0
++#define GCR_CONFIG_PCORES             (0xff << 0)
++
++/* GCR_BASE fields */
++#define GCR_BASE_SHIFT                        15
++#define CCA_DEFAULT_OVR_SHIFT         5
++#define CCA_DEFAULT_OVR_MASK          (0x7 << 5)
++#define CCA_DEFAULT_OVREN             (0x1 << 4)
++#define CM_DEFAULT_TARGET_SHIFT               0
++#define CM_DEFAULT_TARGET_MASK                (0x3 << 0)
++
++/* GCR_CONTROL fields */
++#define GCR_CONTROL_SYNCCTL           (0x1 << 16)
+ /* GCR_REV CM versions */
+ #define GCR_REV_CM3                   0x0800
++/* GCR_GIC_BASE fields */
++#define GCR_GIC_BASE_ADDRMASK_SHIFT   7
++#define GCR_GIC_BASE_ADDRMASK         (0x1ffffff << 7)
++#define GCR_GIC_EN                    (0x1 << 0)
++
++/* GCR_CPC_BASE fields */
++#define GCR_CPC_BASE_ADDRMASK_SHIFT   15
++#define GCR_CPC_BASE_ADDRMASK         (0x1ffff << 15)
++#define GCR_CPC_EN                    (0x1 << 0)
++
++/* GCR_REGn_MASK fields */
++#define GCR_REGn_MASK_ADDRMASK_SHIFT  16
++#define GCR_REGn_MASK_ADDRMASK                (0xffff << 16)
++#define GCR_REGn_MASK_CCAOVR_SHIFT    5
++#define GCR_REGn_MASK_CCAOVR          (0x7 << 5)
++#define GCR_REGn_MASK_CCAOVREN                (1 << 4)
++#define GCR_REGn_MASK_DROPL2          (1 << 2)
++#define GCR_REGn_MASK_CMTGT_SHIFT     0
++#define GCR_REGn_MASK_CMTGT           (0x3 << 0)
++#define  GCR_REGn_MASK_CMTGT_DISABLED 0x0
++#define  GCR_REGn_MASK_CMTGT_MEM      0x1
++#define  GCR_REGn_MASK_CMTGT_IOCU0    0x2
++#define  GCR_REGn_MASK_CMTGT_IOCU1    0x3
++
++/* GCR_CPC_STATUS fields */
++#define GCR_CPC_EX                    (0x1 << 0)
++
+ /* GCR_L2_CONFIG fields */
+ #define GCR_L2_CONFIG_ASSOC_SHIFT     0
+ #define GCR_L2_CONFIG_ASSOC_BITS      8
+@@ -36,6 +99,10 @@
+ #define GCR_Cx_COHERENCE_DOM_EN               (0xff << 0)
+ #define GCR_Cx_COHERENCE_EN           (0x1 << 0)
++/* GCR_Cx_OTHER fields */
++#define GCR_Cx_OTHER_CORENUM_SHIFT    16
++#define GCR_Cx_OTHER_CORENUM          (0xffff << 16)
++
+ #ifndef __ASSEMBLY__
+ #include <asm/io.h>
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0003-mips-add-__image_copy_len-for-SPL-linker-script.patch b/package/boot/uboot-mediatek/patches/001-mtk-0003-mips-add-__image_copy_len-for-SPL-linker-script.patch
new file mode 100644 (file)
index 0000000..42339bd
--- /dev/null
@@ -0,0 +1,40 @@
+From 71ebc3d25147172e219ea87bec061f751257395b Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:21:45 +0800
+Subject: [PATCH 03/25] mips: add __image_copy_len for SPL linker script
+
+This patch adds __image_copy_len needed by TPL of MT7621 SoC.
+The __image_copy_len represents the binary blob size of both SPL/TPL
+binaries. To achieve this, __text_start/end are added for calculation.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/cpu/u-boot-spl.lds | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/mips/cpu/u-boot-spl.lds b/arch/mips/cpu/u-boot-spl.lds
+index 28ea4f2a48..f88754ab56 100644
+--- a/arch/mips/cpu/u-boot-spl.lds
++++ b/arch/mips/cpu/u-boot-spl.lds
+@@ -13,7 +13,9 @@ SECTIONS
+       . = ALIGN(4);
+       .text : {
++              __text_start = .;
+               *(.text*)
++              __text_end = .;
+       } > .spl_mem
+       . = ALIGN(4);
+@@ -36,6 +38,7 @@ SECTIONS
+       . = ALIGN(4);
+       __image_copy_end = .;
++      __image_copy_len = __image_copy_end - __text_start;
+       _image_binary_end = .;
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0004-mips-add-support-for-noncached_alloc.patch b/package/boot/uboot-mediatek/patches/001-mtk-0004-mips-add-support-for-noncached_alloc.patch
new file mode 100644 (file)
index 0000000..ef46bee
--- /dev/null
@@ -0,0 +1,111 @@
+From d7cfa1cb5602a1d936df36ee70869753835de28e Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:21:51 +0800
+Subject: [PATCH 04/25] mips: add support for noncached_alloc()
+
+This patch adds support for noncached_alloc() which was only supported by
+ARM platform.
+
+Unlike the ARM platform, MMU is not used in u-boot for MIPS. Instead, KSEG
+is provided to access uncached memory. So most code of this patch is copied
+from cache.c of ARM platform, with only two differences:
+1. MMU is untouched in noncached_set_region()
+2. Address returned by noncached_alloc() is converted using KSEG1ADDR()
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/include/asm/system.h | 20 ++++++++++++++++
+ arch/mips/lib/cache.c          | 43 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+)
+
+diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h
+index 79e638844b..89a2ac209f 100644
+--- a/arch/mips/include/asm/system.h
++++ b/arch/mips/include/asm/system.h
+@@ -282,4 +282,24 @@ static inline void instruction_hazard_barrier(void)
+       : "=&r"(tmp));
+ }
++#ifdef CONFIG_SYS_NONCACHED_MEMORY
++/* 1MB granularity */
++#define MMU_SECTION_SHIFT     20
++#define MMU_SECTION_SIZE      (1 << MMU_SECTION_SHIFT)
++
++/**
++ * noncached_init() - Initialize non-cached memory region
++ *
++ * Initialize non-cached memory area. This memory region will be typically
++ * located right below the malloc() area and be accessed from KSEG1.
++ *
++ * It is called during the generic post-relocation init sequence.
++ *
++ * Return: 0 if OK
++ */
++int noncached_init(void);
++
++phys_addr_t noncached_alloc(size_t size, size_t align);
++#endif /* CONFIG_SYS_NONCACHED_MEMORY */
++
+ #endif /* _ASM_SYSTEM_H */
+diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c
+index ec652f0fba..d23b38d6b9 100644
+--- a/arch/mips/lib/cache.c
++++ b/arch/mips/lib/cache.c
+@@ -6,6 +6,7 @@
+ #include <common.h>
+ #include <cpu_func.h>
++#include <malloc.h>
+ #include <asm/cache.h>
+ #include <asm/cacheops.h>
+ #include <asm/cm.h>
+@@ -197,3 +198,45 @@ void dcache_disable(void)
+       /* ensure the pipeline doesn't contain now-invalid instructions */
+       instruction_hazard_barrier();
+ }
++
++#ifdef CONFIG_SYS_NONCACHED_MEMORY
++static unsigned long noncached_start;
++static unsigned long noncached_end;
++static unsigned long noncached_next;
++
++void noncached_set_region(void)
++{
++}
++
++int noncached_init(void)
++{
++      phys_addr_t start, end;
++      size_t size;
++
++      /* If this calculation changes, update board_f.c:reserve_noncached() */
++      end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE;
++      size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE);
++      start = end - size;
++
++      debug("mapping memory %pa-%pa non-cached\n", &start, &end);
++
++      noncached_start = start;
++      noncached_end = end;
++      noncached_next = start;
++
++      return 0;
++}
++
++phys_addr_t noncached_alloc(size_t size, size_t align)
++{
++      phys_addr_t next = ALIGN(noncached_next, align);
++
++      if (next >= noncached_end || (noncached_end - next) < size)
++              return 0;
++
++      debug("allocated %zu bytes of uncached memory @%pa\n", size, &next);
++      noncached_next = next + size;
++
++      return CKSEG1ADDR(next);
++}
++#endif /* CONFIG_SYS_NONCACHED_MEMORY */
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0005-mips-mtmips-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0005-mips-mtmips-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..2c4c57e
--- /dev/null
@@ -0,0 +1,2979 @@
+From e0c82f36ad5180d9582d353407ff1bf34a2734bb Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:21 +0800
+Subject: [PATCH 05/25] mips: mtmips: add support for MediaTek MT7621 SoC
+
+This patch adds support for MediaTek MT7621 SoC.
+All files are dedicated for u-boot.
+
+The default build target is u-boot-mt7621.bin.
+
+The specification of this chip:
+https://www.mediatek.com/products/homenetworking/mt7621
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/dts/mt7621-u-boot.dtsi             | 111 ++++++
+ arch/mips/dts/mt7621.dtsi                    | 349 +++++++++++++++++++
+ arch/mips/mach-mtmips/Kconfig                |  49 ++-
+ arch/mips/mach-mtmips/Makefile               |   4 +
+ arch/mips/mach-mtmips/cpu.c                  |   2 +-
+ arch/mips/mach-mtmips/mt7621/Kconfig         |  95 +++++
+ arch/mips/mach-mtmips/mt7621/Makefile        |  14 +
+ arch/mips/mach-mtmips/mt7621/init.c          | 246 +++++++++++++
+ arch/mips/mach-mtmips/mt7621/mt7621.h        | 229 ++++++++++++
+ arch/mips/mach-mtmips/mt7621/serial.c        |  23 ++
+ arch/mips/mach-mtmips/mt7621/spl/Makefile    |   9 +
+ arch/mips/mach-mtmips/mt7621/spl/cps.c       | 153 ++++++++
+ arch/mips/mach-mtmips/mt7621/spl/dram.c      | 153 ++++++++
+ arch/mips/mach-mtmips/mt7621/spl/dram.h      |  39 +++
+ arch/mips/mach-mtmips/mt7621/spl/launch.c    | 100 ++++++
+ arch/mips/mach-mtmips/mt7621/spl/launch.h    |  52 +++
+ arch/mips/mach-mtmips/mt7621/spl/launch_ll.S | 339 ++++++++++++++++++
+ arch/mips/mach-mtmips/mt7621/spl/serial.c    |  24 ++
+ arch/mips/mach-mtmips/mt7621/spl/spl.c       |  95 +++++
+ arch/mips/mach-mtmips/mt7621/spl/start.S     | 226 ++++++++++++
+ arch/mips/mach-mtmips/mt7621/sram_init.S     |  22 ++
+ arch/mips/mach-mtmips/mt7621/tpl/Makefile    |   4 +
+ arch/mips/mach-mtmips/mt7621/tpl/start.S     | 161 +++++++++
+ arch/mips/mach-mtmips/mt7621/tpl/tpl.c       | 144 ++++++++
+ include/configs/mt7621.h                     |  65 ++++
+ 25 files changed, 2702 insertions(+), 6 deletions(-)
+ create mode 100644 arch/mips/dts/mt7621-u-boot.dtsi
+ create mode 100644 arch/mips/dts/mt7621.dtsi
+ create mode 100644 arch/mips/mach-mtmips/mt7621/Kconfig
+ create mode 100644 arch/mips/mach-mtmips/mt7621/Makefile
+ create mode 100644 arch/mips/mach-mtmips/mt7621/init.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/mt7621.h
+ create mode 100644 arch/mips/mach-mtmips/mt7621/serial.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/Makefile
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/cps.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/dram.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/dram.h
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/launch.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/launch.h
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/launch_ll.S
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/serial.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/spl.c
+ create mode 100644 arch/mips/mach-mtmips/mt7621/spl/start.S
+ create mode 100644 arch/mips/mach-mtmips/mt7621/sram_init.S
+ create mode 100644 arch/mips/mach-mtmips/mt7621/tpl/Makefile
+ create mode 100644 arch/mips/mach-mtmips/mt7621/tpl/start.S
+ create mode 100644 arch/mips/mach-mtmips/mt7621/tpl/tpl.c
+ create mode 100644 include/configs/mt7621.h
+
+diff --git a/arch/mips/dts/mt7621-u-boot.dtsi b/arch/mips/dts/mt7621-u-boot.dtsi
+new file mode 100644
+index 0000000000..c5a8aa357f
+--- /dev/null
++++ b/arch/mips/dts/mt7621-u-boot.dtsi
+@@ -0,0 +1,111 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <linux/stringify.h>
++
++/ {
++      binman: binman {
++              multiple-images;
++      };
++};
++
++&sysc {
++      u-boot,dm-pre-reloc;
++};
++
++&reboot {
++      u-boot,dm-pre-reloc;
++};
++
++&clkctrl {
++      u-boot,dm-pre-reloc;
++};
++
++&rstctrl {
++      u-boot,dm-pre-reloc;
++};
++
++&pinctrl {
++      u-boot,dm-pre-reloc;
++};
++
++&uart0 {
++      u-boot,dm-pre-reloc;
++};
++
++&uart1 {
++      u-boot,dm-pre-reloc;
++};
++
++&uart2 {
++      u-boot,dm-pre-reloc;
++};
++
++&binman {
++      u-boot-spl-ddr {
++              align = <4>;
++              align-size = <4>;
++              filename = "u-boot-spl-ddr.bin";
++              pad-byte = <0xff>;
++
++              u-boot-spl {
++                      align-end = <4>;
++                      filename = "u-boot-spl.bin";
++              };
++
++              stage_bin {
++                      filename = "mt7621_stage_sram.bin";
++                      type = "blob-ext";
++              };
++      };
++
++      spl-img {
++              filename = "u-boot-spl-ddr.img";
++
++              mkimage {
++#ifdef CONFIG_MT7621_BOOT_FROM_NAND
++                      args = "-T", "mtk_image", "-n", "mt7621=1",
++                             "-a", __stringify(CONFIG_SPL_TEXT_BASE),
++                             "-e", __stringify(CONFIG_SPL_TEXT_BASE);
++#else
++                      args = "-A", "mips", "-T", "standalone", "-O", "u-boot",
++                             "-C", "none", "-n", "MT7621 U-Boot SPL",
++                             "-a", __stringify(CONFIG_SPL_TEXT_BASE),
++                             "-e", __stringify(CONFIG_SPL_TEXT_BASE);
++#endif
++
++                      blob {
++                              filename = "u-boot-spl-ddr.bin";
++                      };
++              };
++      };
++
++      mt7621-uboot {
++              filename = "u-boot-mt7621.bin";
++              pad-byte = <0xff>;
++
++#ifndef CONFIG_MT7621_BOOT_FROM_NAND
++              u-boot-tpl {
++                      align-end = <4>;
++                      filename = "u-boot-tpl.bin";
++              };
++#endif
++
++              spl {
++#ifdef CONFIG_MT7621_BOOT_FROM_NAND
++                      align-end = <0x1000>;
++#endif
++                      filename = "u-boot-spl-ddr.img";
++                      type = "blob";
++              };
++
++              u-boot {
++                      filename = "u-boot-lzma.img";
++                      type = "blob";
++              };
++      };
++};
+diff --git a/arch/mips/dts/mt7621.dtsi b/arch/mips/dts/mt7621.dtsi
+new file mode 100644
+index 0000000000..c32b6095e9
+--- /dev/null
++++ b/arch/mips/dts/mt7621.dtsi
+@@ -0,0 +1,349 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <dt-bindings/clock/mt7621-clk.h>
++#include <dt-bindings/reset/mt7621-reset.h>
++#include <dt-bindings/phy/phy.h>
++
++/ {
++      #address-cells = <1>;
++      #size-cells = <1>;
++      compatible = "mediatek,mt7621-soc";
++
++      cpus {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              cpu@0 {
++                      device_type = "cpu";
++                      compatible = "mips,mips1004Kc";
++                      reg = <0>;
++              };
++
++              cpu@1 {
++                      device_type = "cpu";
++                      compatible = "mips,mips1004Kc";
++                      reg = <1>;
++              };
++      };
++
++      clk48m: clk48m {
++              compatible = "fixed-clock";
++
++              clock-frequency = <48000000>;
++
++              #clock-cells = <0>;
++      };
++
++      clk50m: clk50m {
++              compatible = "fixed-clock";
++
++              clock-frequency = <50000000>;
++
++              #clock-cells = <0>;
++      };
++
++      sysc: sysctrl@1e000000 {
++              compatible = "mediatek,mt7621-sysc", "syscon";
++              reg = <0x1e000000 0x100>;
++
++              clkctrl: clock-controller@1e000030 {
++                      compatible = "mediatek,mt7621-clk";
++                      mediatek,memc = <&memc>;
++
++                      #clock-cells = <1>;
++              };
++      };
++
++      rstctrl: reset-controller@1e000034 {
++              compatible = "mediatek,mtmips-reset";
++              reg = <0x1e000034 0x4>;
++              #reset-cells = <1>;
++      };
++
++      reboot: resetctl-reboot {
++              compatible = "resetctl-reboot";
++
++              resets = <&rstctrl RST_SYS>;
++              reset-names = "sysreset";
++      };
++
++      memc: memctrl@1e005000 {
++              compatible = "mediatek,mt7621-memc", "syscon";
++              reg = <0x1e005000 0x1000>;
++      };
++
++      pinctrl: pinctrl@1e000060 {
++              compatible = "mediatek,mt7621-pinctrl";
++              reg = <0x1e000048 0x30>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&state_default>;
++
++              state_default: pin_state {
++              };
++
++              uart1_pins: uart1_pins {
++                      groups = "uart1";
++                      function = "uart";
++              };
++
++              uart2_pins: uart2_pins {
++                      groups = "uart2";
++                      function = "uart";
++              };
++
++              uart3_pins: uart3_pins {
++                      groups = "uart3";
++                      function = "uart";
++              };
++
++              sdxc_pins: sdxc_pins {
++                      groups = "sdxc";
++                      function = "sdxc";
++              };
++
++              spi_pins: spi_pins {
++                      groups = "spi";
++                      function = "spi";
++              };
++
++              eth_pins: eth_pins {
++                      mdio_pins {
++                              groups = "mdio";
++                              function = "mdio";
++                      };
++
++                      rgmii1_pins {
++                              groups = "rgmii1";
++                              function = "rgmii";
++                      };
++
++                      esw_pins {
++                              groups = "esw int";
++                              function = "esw int";
++                      };
++
++                      mdio_pconf {
++                              groups = "mdio";
++                              drive-strength = <2>;
++                      };
++              };
++      };
++
++      watchdog: watchdog@1e000100 {
++              compatible = "mediatek,mt7621-wdt";
++              reg = <0x1e000100 0x40>;
++
++              resets = <&rstctrl RST_TIMER>;
++              reset-names = "wdt";
++
++              status = "disabled";
++      };
++
++      gpio: gpio@1e000600 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              compatible = "mtk,mt7621-gpio";
++              reg = <0x1e000600 0x100>;
++
++              resets = <&rstctrl RST_PIO>;
++              reset-names = "pio";
++
++              gpio0: bank@0 {
++                      reg = <0>;
++                      compatible = "mtk,mt7621-gpio-bank";
++                      gpio-controller;
++                      #gpio-cells = <2>;
++              };
++
++              gpio1: bank@1 {
++                      reg = <1>;
++                      compatible = "mtk,mt7621-gpio-bank";
++                      gpio-controller;
++                      #gpio-cells = <2>;
++              };
++
++              gpio2: bank@2 {
++                      reg = <2>;
++                      compatible = "mtk,mt7621-gpio-bank";
++                      gpio-controller;
++                      #gpio-cells = <2>;
++              };
++      };
++
++      spi: spi@1e000b00 {
++              compatible = "ralink,mt7621-spi";
++              reg = <0x1e000b00 0x40>;
++
++              status = "disabled";
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&spi_pins>;
++
++              resets = <&rstctrl RST_SPI>;
++              reset-names = "spi";
++
++              clocks = <&clkctrl MT7621_CLK_SPI>;
++
++              #address-cells = <1>;
++              #size-cells = <0>;
++      };
++
++      uart0: uart1@1e000c00 {
++              compatible = "mediatek,hsuart", "ns16550a";
++              reg = <0x1e000c00 0x100>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&uart1_pins>;
++
++              clocks = <&clkctrl MT7621_CLK_UART1>;
++
++              resets = <&rstctrl RST_UART1>;
++
++              reg-shift = <2>;
++      };
++
++      uart1: uart2@1e000d00 {
++              compatible = "mediatek,hsuart", "ns16550a";
++              reg = <0x1e000d00 0x100>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&uart2_pins>;
++
++              clocks = <&clkctrl MT7621_CLK_UART2>;
++
++              resets = <&rstctrl RST_UART2>;
++
++              reg-shift = <2>;
++
++              status = "disabled";
++      };
++
++      uart2: uart3@1e000e00 {
++              compatible = "mediatek,hsuart", "ns16550a";
++              reg = <0x1e000e00 0x100>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&uart3_pins>;
++
++              clocks = <&clkctrl MT7621_CLK_UART3>;
++
++              resets = <&rstctrl RST_UART3>;
++
++              reg-shift = <2>;
++
++              status = "disabled";
++      };
++
++      eth: eth@1e100000 {
++              compatible = "mediatek,mt7621-eth";
++              reg = <0x1e100000 0x20000>;
++              mediatek,ethsys = <&sysc>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&eth_pins>;
++
++              resets = <&rstctrl RST_FE>, <&rstctrl RST_GMAC>, <&rstctrl RST_MCM>;
++              reset-names = "fe", "gmac", "mcm";
++
++              clocks = <&clkctrl MT7621_CLK_GDMA>,
++                       <&clkctrl MT7621_CLK_ETH>;
++              clock-names = "gmac", "fe";
++
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              mediatek,gmac-id = <0>;
++              phy-mode = "rgmii";
++              mediatek,switch = "mt7530";
++              mediatek,mcm;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++
++      mmc: mmc@1e130000 {
++              compatible = "mediatek,mt7621-mmc";
++              reg = <0x1e130000 0x4000>;
++
++              status = "disabled";
++
++              bus-width = <4>;
++              builtin-cd = <1>;
++              r_smpl = <1>;
++
++              pinctrl-names = "default";
++              pinctrl-0 = <&sdxc_pins>;
++
++              clocks = <&clk50m>, <&clkctrl MT7621_CLK_SHXC>;
++              clock-names = "source", "hclk";
++
++              resets = <&rstctrl RST_SDXC>;
++      };
++
++      ssusb: usb@1e1c0000 {
++              compatible = "mediatek,mt7621-xhci", "mediatek,mtk-xhci";
++              reg = <0x1e1c0000 0x1000>, <0x1e1d0700 0x100>;
++              reg-names = "mac", "ippc";
++
++              clocks = <&clk48m>, <&clk48m>;
++              clock-names = "sys_ck", "ref_ck";
++
++              phys = <&u2port0 PHY_TYPE_USB2>,
++                     <&u3port0 PHY_TYPE_USB3>,
++                     <&u2port1 PHY_TYPE_USB2>;
++
++              status = "disabled";
++      };
++
++      u3phy: usb-phy@1e1d0000 {
++              compatible = "mediatek,mt7621-u3phy",
++                           "mediatek,generic-tphy-v1";
++              reg = <0x1e1d0000 0x700>;
++              #address-cells = <1>;
++              #size-cells = <1>;
++              ranges;
++              status = "disabled";
++
++              u2port0: usb-phy@1e1d0800 {
++                      reg = <0x1e1d0800 0x0100>;
++                      #phy-cells = <1>;
++                      clocks = <&clk48m>;
++                      clock-names = "ref";
++              };
++
++              u3port0: usb-phy@1e1d0900 {
++                      reg = <0x1e1d0900 0x0100>;
++                      #phy-cells = <1>;
++              };
++
++              u2port1: usb-phy@1e1d1000 {
++                      reg = <0x1e1d1000 0x0100>;
++                      #phy-cells = <1>;
++                      clocks = <&clk48m>;
++                      clock-names = "ref";
++              };
++      };
++
++      i2c: i2c@1e000900 {
++              compatible = "i2c-gpio";
++
++              status = "disabled";
++
++              i2c-gpio,delay-us = <3>;
++
++              gpios = <&gpio0 3 1>, /* PIN3 as SDA */
++                      <&gpio0 4 1>; /* PIN4 as CLK */
++
++              #address-cells = <1>;
++              #size-cells = <0>;
++      };
++};
+diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig
+index 151b004603..d46be503a2 100644
+--- a/arch/mips/mach-mtmips/Kconfig
++++ b/arch/mips/mach-mtmips/Kconfig
+@@ -9,6 +9,7 @@ config SYS_MALLOC_F_LEN
+ config SYS_SOC
+       default "mt7620" if SOC_MT7620
++      default "mt7621" if SOC_MT7621
+       default "mt7628" if SOC_MT7628
+ config SYS_DCACHE_SIZE
+@@ -18,25 +19,45 @@ config SYS_DCACHE_LINE_SIZE
+       default 32
+ config SYS_ICACHE_SIZE
+-      default 65536
++      default 65536 if SOC_MT7620 || SOC_MT7628
++      default 32768 if SOC_MT7621
+ config SYS_ICACHE_LINE_SIZE
+       default 32
++config SYS_SCACHE_LINE_SIZE
++      default 32 if SOC_MT7621
++
+ config SYS_TEXT_BASE
+-      default 0x9c000000 if !SPL
+-      default 0x80200000 if SPL
++      default 0x9c000000 if !SPL && !SOC_MT7621
++      default 0x80200000 if SPL || SOC_MT7621
+ config SPL_TEXT_BASE
+-      default 0x9c000000
++      default 0x9c000000 if !SOC_MT7621
++      default 0x80100000 if SOC_MT7621
++
++config SPL_SIZE_LIMIT
++      default 0x30000 if SOC_MT7621
++
++config TPL_TEXT_BASE
++      default 0xbfc00000 if SOC_MT7621
++
++config TPL_MAX_SIZE
++      default 4096 if SOC_MT7621
+ config SPL_PAYLOAD
+       default "u-boot-lzma.img" if SPL_LZMA
+ config BUILD_TARGET
+-      default "u-boot-with-spl.bin" if SPL
++      default "u-boot-with-spl.bin" if SPL && !SOC_MT7621
++      default "u-boot-lzma.img" if SOC_MT7621
+       default "u-boot.bin"
++config MAX_MEM_SIZE
++      int
++      default 256 if SOC_MT7620 || SOC_MT7628
++      default 512 if SOC_MT7621
++
+ choice
+       prompt "MediaTek MIPS SoC select"
+@@ -55,6 +76,23 @@ config SOC_MT7620
+       help
+         This supports MediaTek MT7620.
++config SOC_MT7621
++      bool "MT7621"
++      select MIPS_CM
++      select MIPS_L2_CACHE
++      select SYS_CACHE_SHIFT_5
++      select SYS_MIPS_CACHE_INIT_RAM_LOAD
++      select PINCTRL_MT7621
++      select MTK_SERIAL
++      select REGMAP
++      select SYSCON
++      select BINMAN
++      select SUPPORT_TPL
++      select SPL_LOADER_SUPPORT if SPL
++      select SPL_INIT_STACK_WITHOUT_MALLOC_F if SPL
++      help
++        This supports MediaTek MT7621.
++
+ config SOC_MT7628
+       bool "MT7628"
+       select SYS_CACHE_SHIFT_5
+@@ -80,6 +118,7 @@ config SOC_MT7628
+ endchoice
+ source "arch/mips/mach-mtmips/mt7620/Kconfig"
++source "arch/mips/mach-mtmips/mt7621/Kconfig"
+ source "arch/mips/mach-mtmips/mt7628/Kconfig"
+ endmenu
+diff --git a/arch/mips/mach-mtmips/Makefile b/arch/mips/mach-mtmips/Makefile
+index 4909b47ef2..19f1e07033 100644
+--- a/arch/mips/mach-mtmips/Makefile
++++ b/arch/mips/mach-mtmips/Makefile
+@@ -1,9 +1,13 @@
+ # SPDX-License-Identifier: GPL-2.0+
+ obj-y += cpu.o
++
++ifneq ($(CONFIG_SOC_MT7621),y)
+ obj-y += ddr_init.o
+ obj-y += ddr_cal.o
+ obj-$(CONFIG_SPL_BUILD) += spl.o
++endif
+ obj-$(CONFIG_SOC_MT7620) += mt7620/
++obj-$(CONFIG_SOC_MT7621) += mt7621/
+ obj-$(CONFIG_SOC_MT7628) += mt7628/
+diff --git a/arch/mips/mach-mtmips/cpu.c b/arch/mips/mach-mtmips/cpu.c
+index a4b5cff61d..f1e9022738 100644
+--- a/arch/mips/mach-mtmips/cpu.c
++++ b/arch/mips/mach-mtmips/cpu.c
+@@ -16,7 +16,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ int dram_init(void)
+ {
+-      gd->ram_size = get_ram_size((void *)KSEG1, SZ_256M);
++      gd->ram_size = get_ram_size((void *)KSEG1, CONFIG_MAX_MEM_SIZE << 20);
+       return 0;
+ }
+diff --git a/arch/mips/mach-mtmips/mt7621/Kconfig b/arch/mips/mach-mtmips/mt7621/Kconfig
+new file mode 100644
+index 0000000000..37d512c68f
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/Kconfig
+@@ -0,0 +1,95 @@
++
++if SOC_MT7621
++
++menu "CPU & DDR configuration"
++
++config MT7621_CPU_FREQ
++      int "CPU Frequency (MHz)"
++      range 400 1200
++      default 880
++
++choice
++      prompt "DRAM Frequency"
++      default MT7621_DRAM_FREQ_1200
++
++config MT7621_DRAM_FREQ_400
++      bool "400MHz"
++
++config MT7621_DRAM_FREQ_800
++      bool "800MHz"
++
++config MT7621_DRAM_FREQ_1066
++      bool "1066MHz"
++
++config MT7621_DRAM_FREQ_1200
++      bool "1200MHz"
++
++endchoice
++
++choice
++      prompt "DDR2 timing parameters"
++      default MT7621_DRAM_DDR2_1024M
++
++config MT7621_DRAM_DDR2_512M
++      bool "64MB"
++
++config MT7621_DRAM_DDR2_1024M
++      bool "128MB"
++
++config MT7621_DRAM_DDR2_512M_W9751G6KB_A02_1066MHZ
++      bool "W9751G6KB_A02 @ 1066MHz (64MB)"
++
++config MT7621_DRAM_DDR2_1024M_W971GG6KB25_800MHZ
++      bool "W971GG6KB25 @ 800MHz (128MB)"
++
++config MT7621_DRAM_DDR2_1024M_W971GG6KB18_1066MHZ
++      bool "W971GG6KB18 @ 1066MHz (128MB)"
++
++endchoice
++
++choice
++      prompt "DDR3 timing parameters"
++      default MT7621_DRAM_DDR3_2048M
++
++config MT7621_DRAM_DDR3_1024M
++      bool "128MB"
++
++config MT7621_DRAM_DDR3_1024M_KGD
++      bool "128MB KGD (MT7621DA)"
++
++config MT7621_DRAM_DDR3_2048M
++      bool "256MB"
++
++config MT7621_DRAM_DDR3_4096M
++      bool "512MB"
++
++endchoice
++
++endmenu
++
++config DEBUG_UART_BOARD_INIT
++      default y
++
++config MT7621_BOOT_FROM_NAND
++      bool "Boot from NAND"
++      help
++        Select this if u-boot will boot from NAND flash. When booting from
++        NAND, SPL will be loaded by bootrom directly and no TPL is needed.
++
++choice
++      prompt "Board select"
++
++endchoice
++
++config SYS_CONFIG_NAME
++      string "Board configuration name"
++      default "mt7621" if  BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB
++
++config SYS_BOARD
++      string "Board name"
++      default "mt7621" if  BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB
++
++config SYS_VENDOR
++      default "mediatek" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB
++
++endif
+diff --git a/arch/mips/mach-mtmips/mt7621/Makefile b/arch/mips/mach-mtmips/mt7621/Makefile
+new file mode 100644
+index 0000000000..bf1b0bb688
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/Makefile
+@@ -0,0 +1,14 @@
++# SPDX-License-Identifier: GPL-2.0
++
++obj-y += init.o
++obj-y += serial.o
++
++ifeq ($(CONFIG_SPL_BUILD),y)
++ifeq ($(CONFIG_TPL_BUILD),y)
++obj-y += tpl/
++else
++obj-y += spl/
++endif
++
++obj-y += sram_init.o
++endif
+diff --git a/arch/mips/mach-mtmips/mt7621/init.c b/arch/mips/mach-mtmips/mt7621/init.c
+new file mode 100644
+index 0000000000..d21848ad23
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/init.c
+@@ -0,0 +1,246 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <clk.h>
++#include <dm.h>
++#include <dm/uclass.h>
++#include <dt-bindings/clock/mt7621-clk.h>
++#include <asm/global_data.h>
++#include <linux/io.h>
++#include <linux/bitfield.h>
++#include "mt7621.h"
++
++DECLARE_GLOBAL_DATA_PTR;
++
++static const char *const boot_mode[(CHIP_MODE_M >> CHIP_MODE_S) + 1] = {
++      [1] = "NAND 2K+64",
++      [2] = "SPI-NOR 3-Byte Addr",
++      [3] = "SPI-NOR 4-Byte Addr",
++      [10] = "NAND 2K+128",
++      [11] = "NAND 4K+128",
++      [12] = "NAND 4K+256",
++};
++
++int print_cpuinfo(void)
++{
++      void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
++      u32 val, ver, eco, pkg, core, dram, chipmode;
++      u32 cpu_clk, ddr_clk, bus_clk, xtal_clk;
++      struct udevice *clkdev;
++      const char *bootdev;
++      struct clk clk;
++      int ret;
++
++      val = readl(sysc + SYSCTL_CHIP_REV_ID_REG);
++      ver = FIELD_GET(VER_ID_M, val);
++      eco = FIELD_GET(ECO_ID_M, val);
++      pkg = FIELD_GET(PKG_ID, val);
++      core = FIELD_GET(CPU_ID, val);
++
++      val = readl(sysc + SYSCTL_SYSCFG0_REG);
++      dram = FIELD_GET(DRAM_TYPE, val);
++      chipmode = FIELD_GET(CHIP_MODE_M, val);
++
++      bootdev = boot_mode[chipmode];
++      if (!bootdev)
++              bootdev = "Unsupported boot mode";
++
++      printf("CPU:   MediaTek MT7621%c ver %u, eco %u\n",
++             core ? (pkg ? 'A' : 'N') : 'S', ver, eco);
++
++      printf("Boot:  DDR%u, %s\n", dram ? 2 : 3, bootdev);
++
++      ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(mt7621_clk),
++                                        &clkdev);
++      if (ret)
++              return ret;
++
++      clk.dev = clkdev;
++
++      clk.id = MT7621_CLK_CPU;
++      cpu_clk = clk_get_rate(&clk);
++
++      clk.id = MT7621_CLK_BUS;
++      bus_clk = clk_get_rate(&clk);
++
++      clk.id = MT7621_CLK_DDR;
++      ddr_clk = clk_get_rate(&clk);
++
++      clk.id = MT7621_CLK_XTAL;
++      xtal_clk = clk_get_rate(&clk);
++
++      /* Set final timer frequency */
++      if (cpu_clk)
++              gd->arch.timer_freq = cpu_clk / 2;
++
++      printf("Clock: CPU: %uMHz, DDR: %uMT/s, Bus: %uMHz, XTAL: %uMHz\n",
++             cpu_clk / 1000000, ddr_clk / 500000, bus_clk / 1000000,
++             xtal_clk / 1000000);
++
++      return 0;
++}
++
++unsigned long get_xtal_mhz(void)
++{
++      void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
++      u32 bs, xtal_sel;
++
++      bs = readl(sysc + SYSCTL_SYSCFG0_REG);
++      xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, bs);
++
++      if (xtal_sel <= 2)
++              return 20;
++      else if (xtal_sel <= 5)
++              return 40;
++      else
++              return 25;
++}
++
++static void xhci_config_40mhz(void __iomem *usbh)
++{
++      writel(FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M, 0x20) |
++             FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M, 0x20) |
++             FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MODE_M, 2) |
++             FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MODE_M, 2) | 0x10,
++             usbh + SSUSB_MAC_CK_CTRL_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_PREDIV_PE1D_M, 2) |
++             FIELD_PREP(SSUSB_PLL_PREDIV_U3_M, 1) |
++             FIELD_PREP(SSUSB_PLL_FBKDI_M, 4),
++             usbh + DA_SSUSB_U3PHYA_10_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_FBKDIV_PE2H_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_PE1D_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_PE1H_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_U3_M, 0x1e),
++             usbh + DA_SSUSB_PLL_FBKDIV_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_PCW_NCPO_U3_M, 0x1e400000),
++             usbh + DA_SSUSB_PLL_PCW_NCPO_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE1H_M, 0x25) |
++             FIELD_PREP(SSUSB_PLL_SSC_DELTA1_U3_M, 0x73),
++             usbh + DA_SSUSB_PLL_SSC_DELTA1_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA_U3_M, 0x71) |
++             FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE2D_M, 0x4a),
++             usbh + DA_SSUSB_U3PHYA_21_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_PRD_M, 0x140),
++             usbh + SSUSB_U3PHYA_9_REG);
++
++      writel(FIELD_PREP(SSUSB_SYSPLL_PCW_NCPO_M, 0x11c00000),
++             usbh + SSUSB_U3PHYA_3_REG);
++
++      writel(FIELD_PREP(SSUSB_PCIE_CLKDRV_AMP_M, 4) |
++             FIELD_PREP(SSUSB_SYSPLL_FBSEL_M, 1) |
++             FIELD_PREP(SSUSB_SYSPLL_PREDIV_M, 1),
++             usbh + SSUSB_U3PHYA_1_REG);
++
++      writel(FIELD_PREP(SSUSB_SYSPLL_FBDIV_M, 0x12) |
++             SSUSB_SYSPLL_VCO_DIV_SEL | SSUSB_SYSPLL_FPEN |
++             SSUSB_SYSPLL_MONCK_EN | SSUSB_SYSPLL_VOD_EN,
++             usbh + SSUSB_U3PHYA_2_REG);
++
++      writel(SSUSB_EQ_CURSEL | FIELD_PREP(SSUSB_RX_DAC_MUX_M, 8) |
++             FIELD_PREP(SSUSB_PCIE_SIGDET_VTH_M, 1) |
++             FIELD_PREP(SSUSB_PCIE_SIGDET_LPF_M, 1),
++             usbh + SSUSB_U3PHYA_11_REG);
++
++      writel(FIELD_PREP(SSUSB_RING_OSC_CNTEND_M, 0x1ff) |
++             FIELD_PREP(SSUSB_XTAL_OSC_CNTEND_M, 0x7f) |
++             SSUSB_RING_BYPASS_DET,
++             usbh + SSUSB_B2_ROSC_0_REG);
++
++      writel(FIELD_PREP(SSUSB_RING_OSC_FRC_RECAL_M, 3) |
++             SSUSB_RING_OSC_FRC_SEL,
++             usbh + SSUSB_B2_ROSC_1_REG);
++}
++
++static void xhci_config_25mhz(void __iomem *usbh)
++{
++      writel(FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M, 0x20) |
++             FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M, 0x20) |
++             FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MODE_M, 2) |
++             FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MODE_M, 2) | 0x10,
++             usbh + SSUSB_MAC_CK_CTRL_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_PREDIV_PE1D_M, 2) |
++             FIELD_PREP(SSUSB_PLL_FBKDI_M, 4),
++             usbh + DA_SSUSB_U3PHYA_10_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_FBKDIV_PE2H_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_PE1D_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_PE1H_M, 0x18) |
++             FIELD_PREP(SSUSB_PLL_FBKDIV_U3_M, 0x19),
++             usbh + DA_SSUSB_PLL_FBKDIV_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_PCW_NCPO_U3_M, 0x18000000),
++             usbh + DA_SSUSB_PLL_PCW_NCPO_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE1H_M, 0x25) |
++             FIELD_PREP(SSUSB_PLL_SSC_DELTA1_U3_M, 0x4a),
++             usbh + DA_SSUSB_PLL_SSC_DELTA1_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA_U3_M, 0x48) |
++             FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE2D_M, 0x4a),
++             usbh + DA_SSUSB_U3PHYA_21_REG);
++
++      writel(FIELD_PREP(SSUSB_PLL_SSC_PRD_M, 0x190),
++             usbh + SSUSB_U3PHYA_9_REG);
++
++      writel(FIELD_PREP(SSUSB_SYSPLL_PCW_NCPO_M, 0xe000000),
++             usbh + SSUSB_U3PHYA_3_REG);
++
++      writel(FIELD_PREP(SSUSB_PCIE_CLKDRV_AMP_M, 4) |
++             FIELD_PREP(SSUSB_SYSPLL_FBSEL_M, 1),
++             usbh + SSUSB_U3PHYA_1_REG);
++
++      writel(FIELD_PREP(SSUSB_SYSPLL_FBDIV_M, 0xf) |
++             SSUSB_SYSPLL_VCO_DIV_SEL | SSUSB_SYSPLL_FPEN |
++             SSUSB_SYSPLL_MONCK_EN | SSUSB_SYSPLL_VOD_EN,
++             usbh + SSUSB_U3PHYA_2_REG);
++
++      writel(SSUSB_EQ_CURSEL | FIELD_PREP(SSUSB_RX_DAC_MUX_M, 8) |
++             FIELD_PREP(SSUSB_PCIE_SIGDET_VTH_M, 1) |
++             FIELD_PREP(SSUSB_PCIE_SIGDET_LPF_M, 1),
++             usbh + SSUSB_U3PHYA_11_REG);
++
++      writel(FIELD_PREP(SSUSB_RING_OSC_CNTEND_M, 0x1ff) |
++             FIELD_PREP(SSUSB_XTAL_OSC_CNTEND_M, 0x7f) |
++             SSUSB_RING_BYPASS_DET,
++             usbh + SSUSB_B2_ROSC_0_REG);
++
++      writel(FIELD_PREP(SSUSB_RING_OSC_FRC_RECAL_M, 3) |
++             SSUSB_RING_OSC_FRC_SEL,
++             usbh + SSUSB_B2_ROSC_1_REG);
++}
++
++void lowlevel_init(void)
++{
++      void __iomem *usbh = ioremap_nocache(SSUSB_BASE, SSUSB_SIZE);
++      u32 xtal = get_xtal_mhz();
++
++      /* Setup USB xHCI */
++      if (xtal == 40)
++              xhci_config_40mhz(usbh);
++      else if (xtal == 25)
++              xhci_config_25mhz(usbh);
++}
++
++ulong notrace get_tbclk(void)
++{
++      return gd->arch.timer_freq;
++}
++
++void _machine_restart(void)
++{
++      void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
++
++      while (1)
++              writel(SYS_RST, sysc + SYSCTL_RSTCTL_REG);
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/mt7621.h b/arch/mips/mach-mtmips/mt7621/mt7621.h
+new file mode 100644
+index 0000000000..916cc993b4
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/mt7621.h
+@@ -0,0 +1,229 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _MT7621_H_
++#define _MT7621_H_
++
++#define SYSCTL_BASE                           0x1e000000
++#define SYSCTL_SIZE                           0x100
++#define TIMER_BASE                            0x1e000100
++#define TIMER_SIZE                            0x100
++#define RBUS_BASE                             0x1e000400
++#define RBUS_SIZE                             0x100
++#define GPIO_BASE                             0x1e000600
++#define GPIO_SIZE                             0x100
++#define DMA_CFG_ARB_BASE                      0x1e000800
++#define DMA_CFG_ARB_SIZE                      0x100
++#define SPI_BASE                              0x1e000b00
++#define SPI_SIZE                              0x100
++#define UART1_BASE                            0x1e000c00
++#define UART1_SIZE                            0x100
++#define UART2_BASE                            0x1e000d00
++#define UART2_SIZE                            0x100
++#define UART3_BASE                            0x1e000e00
++#define UART3_SIZE                            0x100
++#define NFI_BASE                              0x1e003000
++#define NFI_SIZE                              0x800
++#define NFI_ECC_BASE                          0x1e003800
++#define NFI_ECC_SIZE                          0x800
++#define DRAMC_BASE                            0x1e005000
++#define DRAMC_SIZE                            0x1000
++#define FE_BASE                                       0x1e100000
++#define FE_SIZE                                       0xe000
++#define GMAC_BASE                             0x1e110000
++#define GMAC_SIZE                             0x8000
++#define SSUSB_BASE                            0x1e1c0000
++#define SSUSB_SIZE                            0x40000
++
++ /* GIC Base Address */
++#define MIPS_GIC_BASE                         0x1fbc0000
++
++ /* CPC Base Address */
++#define MIPS_CPC_BASE                         0x1fbf0000
++
++ /* Flash Memory-mapped Base Address */
++#define FLASH_MMAP_BASE                               0x1fc00000
++#define TPL_INFO_OFFSET                               0x40
++#define TPL_INFO_MAGIC                                0x31323637 /* Magic "7621" */
++
++/* SRAM */
++#define FE_SRAM_BASE1                         0x8000
++#define FE_SRAM_BASE2                         0xa000
++
++/* SYSCTL_BASE */
++#define SYSCTL_CHIP_REV_ID_REG                        0x0c
++#define CPU_ID                                        0x20000
++#define PKG_ID                                        0x10000
++#define VER_ID_S                              8
++#define VER_ID_M                              0xf00
++#define ECO_ID_S                              0
++#define ECO_ID_M                              0x0f
++
++#define SYSCTL_SYSCFG0_REG                    0x10
++#define XTAL_MODE_SEL_S                               6
++#define XTAL_MODE_SEL_M                               0x1c0
++#define DRAM_TYPE                             0x10
++#define CHIP_MODE_S                           0
++#define CHIP_MODE_M                           0x0f
++
++#define BOOT_SRAM_BASE_REG                    0x20
++
++#define SYSCTL_CLKCFG0_REG                    0x2c
++#define CPU_CLK_SEL_S                         30
++#define CPU_CLK_SEL_M                         0xc0000000
++#define MPLL_CFG_SEL_S                                23
++#define MPLL_CFG_SEL_M                                0x800000
++
++#define SYSCTL_RSTCTL_REG                     0x34
++#define MCM_RST                                       0x04
++#define SYS_RST                                       0x01
++
++#define SYSCTL_CUR_CLK_STS_REG                        0x44
++#define CUR_CPU_FDIV_S                                8
++#define CUR_CPU_FDIV_M                                0x1f00
++#define CUR_CPU_FFRAC_S                               0
++#define CUR_CPU_FFRAC_M                               0x1f
++
++#define SYSCTL_GPIOMODE_REG                   0x60
++#define UART2_MODE_S                          5
++#define UART2_MODE_M                          0x60
++#define UART3_MODE_S                          3
++#define UART3_MODE_M                          0x18
++#define UART1_MODE                            0x02
++
++/* RBUS_BASE */
++#define RBUS_DYN_CFG0_REG                     0x0010
++#define CPU_FDIV_S                            8
++#define CPU_FDIV_M                            0x1f00
++#define CPU_FFRAC_S                           0
++#define CPU_FFRAC_M                           0x1f
++
++/* DMA_CFG_ARB_BASE */
++#define DMA_ROUTE_REG                         0x000c
++
++/* SPI_BASE */
++#define SPI_SPACE_REG                         0x003c
++#define FS_SLAVE_SEL_S                                12
++#define FS_SLAVE_SEL_M                                0x70000
++#define FS_CLK_SEL_S                          0
++#define FS_CLK_SEL_M                          0xfff
++
++/* FE_BASE */
++#define FE_RST_GLO_REG                                0x0004
++#define FE_PSE_RAM                            0x04
++#define FE_PSE_MEM_EN                         0x02
++#define FE_PSE_RESET                          0x01
++
++/* SSUSB_BASE */
++#define SSUSB_MAC_CK_CTRL_REG                 0x10784
++#define SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_S    16
++#define SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M    0xff0000
++#define SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_S    8
++#define SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M    0xff00
++#define SSUSB_MAC3_SYS_CK_GATE_MODE_S         2
++#define SSUSB_MAC3_SYS_CK_GATE_MODE_M         0x0c
++#define SSUSB_MAC2_SYS_CK_GATE_MODE_S         0
++#define SSUSB_MAC2_SYS_CK_GATE_MODE_M         0x03
++
++#define SSUSB_B2_ROSC_0_REG                   0x10a40
++#define SSUSB_RING_OSC_CNTEND_S                       23
++#define SSUSB_RING_OSC_CNTEND_M                       0xff800000
++#define SSUSB_XTAL_OSC_CNTEND_S                       16
++#define SSUSB_XTAL_OSC_CNTEND_M                       0x7f0000
++#define SSUSB_RING_BYPASS_DET                 0x01
++
++#define SSUSB_B2_ROSC_1_REG                   0x10a44
++#define SSUSB_RING_OSC_FRC_RECAL_S            17
++#define SSUSB_RING_OSC_FRC_RECAL_M            0x60000
++#define SSUSB_RING_OSC_FRC_SEL                        0x01
++
++#define SSUSB_U3PHYA_1_REG                    0x10b04
++#define SSUSB_PCIE_CLKDRV_AMP_S                       27
++#define SSUSB_PCIE_CLKDRV_AMP_M                       0x38000000
++#define SSUSB_SYSPLL_FBSEL_S                  2
++#define SSUSB_SYSPLL_FBSEL_M                  0x0c
++#define SSUSB_SYSPLL_PREDIV_S                 0
++#define SSUSB_SYSPLL_PREDIV_M                 0x03
++
++#define SSUSB_U3PHYA_2_REG                    0x10b08
++#define SSUSB_SYSPLL_FBDIV_S                  24
++#define SSUSB_SYSPLL_FBDIV_M                  0x7f000000
++#define SSUSB_SYSPLL_VCO_DIV_SEL              0x200000
++#define SSUSB_SYSPLL_FPEN                     0x2000
++#define SSUSB_SYSPLL_MONCK_EN                 0x1000
++#define SSUSB_SYSPLL_VOD_EN                   0x200
++
++#define SSUSB_U3PHYA_3_REG                    0x10b10
++#define SSUSB_SYSPLL_PCW_NCPO_S                       1
++#define SSUSB_SYSPLL_PCW_NCPO_M                       0xfffffffe
++
++#define SSUSB_U3PHYA_9_REG                    0x10b24
++#define SSUSB_PLL_SSC_PRD_S                   0
++#define SSUSB_PLL_SSC_PRD_M                   0xffff
++
++#define SSUSB_U3PHYA_11_REG                   0x10b2c
++#define SSUSB_EQ_CURSEL                               0x1000000
++#define SSUSB_RX_DAC_MUX_S                    19
++#define SSUSB_RX_DAC_MUX_M                    0xf80000
++#define SSUSB_PCIE_SIGDET_VTH_S                       5
++#define SSUSB_PCIE_SIGDET_VTH_M                       0x60
++#define SSUSB_PCIE_SIGDET_LPF_S                       3
++#define SSUSB_PCIE_SIGDET_LPF_M                       0x18
++
++#define DA_SSUSB_PLL_FBKDIV_REG                       0x10c1c
++#define SSUSB_PLL_FBKDIV_PE2H_S                       24
++#define SSUSB_PLL_FBKDIV_PE2H_M                       0x7f000000
++#define SSUSB_PLL_FBKDIV_PE1D_S                       16
++#define SSUSB_PLL_FBKDIV_PE1D_M                       0x7f0000
++#define SSUSB_PLL_FBKDIV_PE1H_S                       8
++#define SSUSB_PLL_FBKDIV_PE1H_M                       0x7f00
++#define SSUSB_PLL_FBKDIV_U3_S                 0
++#define SSUSB_PLL_FBKDIV_U3_M                 0x7f
++
++#define DA_SSUSB_U3PHYA_10_REG                        0x10c20
++#define SSUSB_PLL_PREDIV_PE1D_S                       18
++#define SSUSB_PLL_PREDIV_PE1D_M                       0xc0000
++#define SSUSB_PLL_PREDIV_U3_S                 8
++#define SSUSB_PLL_PREDIV_U3_M                 0x300
++#define SSUSB_PLL_FBKDI_S                     0
++#define SSUSB_PLL_FBKDI_M                     0x07
++
++#define DA_SSUSB_PLL_PCW_NCPO_REG             0x10c24
++#define SSUSB_PLL_PCW_NCPO_U3_S                       0
++#define SSUSB_PLL_PCW_NCPO_U3_M                       0x7fffffff
++
++#define DA_SSUSB_PLL_SSC_DELTA1_REG           0x10c38
++#define SSUSB_PLL_SSC_DELTA1_PE1H_S           16
++#define SSUSB_PLL_SSC_DELTA1_PE1H_M           0xffff0000
++#define SSUSB_PLL_SSC_DELTA1_U3_S             0
++#define SSUSB_PLL_SSC_DELTA1_U3_M             0xffff
++
++#define DA_SSUSB_U3PHYA_21_REG                        0x10c40
++#define SSUSB_PLL_SSC_DELTA_U3_S              16
++#define SSUSB_PLL_SSC_DELTA_U3_M              0xffff0000
++#define SSUSB_PLL_SSC_DELTA1_PE2D_S           0
++#define SSUSB_PLL_SSC_DELTA1_PE2D_M           0xffff
++
++/* MT7621 specific CM values */
++
++/* GCR_REGx_BASE */
++#define GCR_REG0_BASE_VALUE                   0x1c000000
++#define GCR_REG1_BASE_VALUE                   0x60000000
++#define GCR_REG2_BASE_VALUE                   0x1c000000
++#define GCR_REG3_BASE_VALUE                   0x1c000000
++
++/* GCR_REGx_MASK */
++#define GCR_REG0_MASK_VALUE                   0x0000fc00 /* 64M Bus */
++#define GCR_REG1_MASK_VALUE                   0x0000f000 /* 256M PCI Mem */
++#define GCR_REG2_MASK_VALUE                   0x0000fc00 /* unused */
++#define GCR_REG3_MASK_VALUE                   0x0000fc00 /* unused */
++
++#ifndef __ASSEMBLY__
++unsigned long get_xtal_mhz(void);
++#endif
++
++#endif /* _MT7621_H_ */
+diff --git a/arch/mips/mach-mtmips/mt7621/serial.c b/arch/mips/mach-mtmips/mt7621/serial.c
+new file mode 100644
+index 0000000000..0ccc71dc75
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/serial.c
+@@ -0,0 +1,23 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/io.h>
++#include <asm/addrspace.h>
++#include "mt7621.h"
++
++void board_debug_uart_init(void)
++{
++      void __iomem *base = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
++
++#if CONFIG_DEBUG_UART_BASE == 0xbe000c00 /* KSEG1ADDR(UART1_BASE) */
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART1_MODE);
++#elif CONFIG_DEBUG_UART_BASE == 0xbe000d00 /* KSEG1ADDR(UART2_BASE) */
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART2_MODE_M);
++#elif CONFIG_DEBUG_UART_BASE == 0xbe000e00 /* KSEG1ADDR(UART3_BASE) */
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART3_MODE_M);
++#endif
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/Makefile b/arch/mips/mach-mtmips/mt7621/spl/Makefile
+new file mode 100644
+index 0000000000..ebe54e79b9
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/Makefile
+@@ -0,0 +1,9 @@
++
++extra-y += start.o
++
++obj-y += spl.o
++obj-y += cps.o
++obj-y += dram.o
++obj-y += serial.o
++obj-y += launch.o
++obj-y += launch_ll.o
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/cps.c b/arch/mips/mach-mtmips/mt7621/spl/cps.c
+new file mode 100644
+index 0000000000..779e646c12
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/cps.c
+@@ -0,0 +1,153 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/io.h>
++#include <asm/addrspace.h>
++#include <asm/mipsregs.h>
++#include <asm/cm.h>
++#include <linux/bitfield.h>
++#include "../mt7621.h"
++
++/* GIC Shared Register Bases */
++#define GIC_SH_POL_BASE               0x100
++#define GIC_SH_TRIG_BASE      0x180
++#define GIC_SH_RMASK_BASE     0x300
++#define GIC_SH_SMASK_BASE     0x380
++#define GIC_SH_MASK_BASE      0x400
++#define GIC_SH_PEND_BASE      0x480
++#define GIC_SH_MAP_PIN_BASE   0x500
++#define GIC_SH_MAP_VPE_BASE   0x2000
++
++/* GIC Registers */
++#define GIC_SH_POL31_0                (GIC_SH_POL_BASE + 0x00)
++#define GIC_SH_POL63_32               (GIC_SH_POL_BASE + 0x04)
++
++#define GIC_SH_TRIG31_0               (GIC_SH_TRIG_BASE + 0x00)
++#define GIC_SH_TRIG63_32      (GIC_SH_TRIG_BASE + 0x04)
++
++#define GIC_SH_RMASK31_0      (GIC_SH_RMASK_BASE + 0x00)
++#define GIC_SH_RMASK63_32     (GIC_SH_RMASK_BASE + 0x04)
++
++#define GIC_SH_SMASK31_0      (GIC_SH_SMASK_BASE + 0x00)
++#define GIC_SH_SMASK63_32     (GIC_SH_SMASK_BASE + 0x04)
++
++#define GIC_SH_MAP_PIN(n)     (GIC_SH_MAP_PIN_BASE + (n) * 4)
++
++#define GIC_SH_MAP_VPE(n, v)  (GIC_SH_MAP_VPE_BASE + (n) * 0x20 + ((v) / 32) * 4)
++#define GIC_SH_MAP_VPE31_0(n) GIC_SH_MAP_VPE(n, 0)
++
++/* GIC_SH_MAP_PIN fields */
++#define GIC_MAP_TO_PIN                BIT(31)
++#define GIC_MAP_TO_NMI                BIT(30)
++#define GIC_MAP                       GENMASK(5, 0)
++#define GIC_MAP_SHIFT         0
++
++static void cm_init(void __iomem *cm_base)
++{
++      u32 gcrcfg, num_cores;
++
++      gcrcfg = readl(cm_base + GCR_CONFIG);
++      num_cores = FIELD_GET(GCR_CONFIG_PCORES, gcrcfg) + 1;
++
++      writel((1 << num_cores) - 1, cm_base + GCR_ACCESS);
++
++      writel(GCR_REG0_BASE_VALUE, cm_base + GCR_REG0_BASE);
++      writel(GCR_REG1_BASE_VALUE, cm_base + GCR_REG1_BASE);
++      writel(GCR_REG2_BASE_VALUE, cm_base + GCR_REG2_BASE);
++      writel(GCR_REG3_BASE_VALUE, cm_base + GCR_REG3_BASE);
++
++      clrsetbits_32(cm_base + GCR_REG0_MASK,
++                    GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
++                    FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG0_MASK_VALUE) |
++                    GCR_REGn_MASK_CMTGT_IOCU0);
++
++      clrsetbits_32(cm_base + GCR_REG1_MASK,
++                    GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
++                    FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG1_MASK_VALUE) |
++                    GCR_REGn_MASK_CMTGT_IOCU0);
++
++      clrsetbits_32(cm_base + GCR_REG2_MASK,
++                    GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
++                    FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG2_MASK_VALUE) |
++                    GCR_REGn_MASK_CMTGT_IOCU0);
++
++      clrsetbits_32(cm_base + GCR_REG3_MASK,
++                    GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
++                    FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG3_MASK_VALUE) |
++                    GCR_REGn_MASK_CMTGT_IOCU0);
++
++      clrbits_32(cm_base + GCR_BASE, CM_DEFAULT_TARGET_MASK);
++      setbits_32(cm_base + GCR_CONTROL, GCR_CONTROL_SYNCCTL);
++}
++
++static void gic_init(void)
++{
++      void __iomem *gic_base = (void *)KSEG1ADDR(MIPS_GIC_BASE);
++      int i;
++
++      /* Interrupt 0..5: Level Trigger, Active High */
++      writel(0, gic_base + GIC_SH_TRIG31_0);
++      writel(0x3f, gic_base + GIC_SH_RMASK31_0);
++      writel(0x3f, gic_base + GIC_SH_POL31_0);
++      writel(0x3f, gic_base + GIC_SH_SMASK31_0);
++
++      /* Interrupt 56..63: Edge Trigger, Rising Edge */
++      /* Hardcoded to set up the last 8 external interrupts for IPI. */
++      writel(0xff000000, gic_base + GIC_SH_TRIG63_32);
++      writel(0xff000000, gic_base + GIC_SH_RMASK63_32);
++      writel(0xff000000, gic_base + GIC_SH_POL63_32);
++      writel(0xff000000, gic_base + GIC_SH_SMASK63_32);
++
++      /* Map interrupt source to particular hardware interrupt pin */
++      /* source {0,1,2,3,4,5} -> pin {0,0,4,3,0,5} */
++      writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(0));
++      writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(1));
++      writel(GIC_MAP_TO_PIN | 4, gic_base + GIC_SH_MAP_PIN(2));
++      writel(GIC_MAP_TO_PIN | 3, gic_base + GIC_SH_MAP_PIN(3));
++      writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(4));
++      writel(GIC_MAP_TO_PIN | 5, gic_base + GIC_SH_MAP_PIN(5));
++
++      /* source 56~59 -> pin 1, 60~63 -> pin 2 */
++      writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(56));
++      writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(57));
++      writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(58));
++      writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(59));
++      writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(60));
++      writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(61));
++      writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(62));
++      writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(63));
++
++      /* Interrupt map to VPE (bit mask) */
++      for (i = 0; i < 32; i++)
++              writel(BIT(0), gic_base + GIC_SH_MAP_VPE31_0(i));
++
++      /*
++       * Direct GIC_int 56..63 to vpe 0..3
++       * MIPS Linux convention that last 16 interrupts implemented be set
++       * aside for IPI signaling.
++       * The actual interrupts are tied low and software sends interrupts
++       * via GIC_SH_WEDGE writes.
++       */
++      for (i = 0; i < 4; i++) {
++              writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 56));
++              writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 60));
++      }
++}
++
++void mt7621_cps_init(void)
++{
++      void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE);
++
++      /* Enable GIC */
++      writel(MIPS_GIC_BASE | GCR_GIC_EN, cm_base + GCR_GIC_BASE);
++
++      /* Enable CPC */
++      writel(MIPS_CPC_BASE | GCR_CPC_EN, cm_base + GCR_CPC_BASE);
++
++      gic_init();
++      cm_init(cm_base);
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/dram.c b/arch/mips/mach-mtmips/mt7621/spl/dram.c
+new file mode 100644
+index 0000000000..100adfb93a
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/dram.c
+@@ -0,0 +1,153 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <vsprintf.h>
++#include <asm/io.h>
++#include <asm/sections.h>
++#include <asm/byteorder.h>
++#include <asm/addrspace.h>
++#include <linux/string.h>
++#include "../mt7621.h"
++#include "dram.h"
++
++static const u32 ddr2_act[DDR_PARAM_SIZE] = {
++#if defined(CONFIG_MT7621_DRAM_DDR2_512M)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441,
++      0x00000000, 0xF0748661, 0x40001273, 0x9F0A0481,
++      0x0304692F, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000000, 0x07100000,
++      0x00001B63, 0x00002000, 0x00004000, 0x00006000,
++      0x00000000, 0x00000000, 0x00000000, 0x00000000,
++#elif defined(CONFIG_MT7621_DRAM_DDR2_512M_W9751G6KB_A02_1066MHZ)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584,
++      0x00000000, 0xF07486A1, 0x50001273, 0x9F010481,
++      0x0304693F, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000010, 0x07100000,
++      0x00001F73, 0x00002000, 0x00004000, 0x00006000,
++      0x00000000, 0x00000000, 0x00000000, 0x00000000,
++#elif defined(CONFIG_MT7621_DRAM_DDR2_1024M_W971GG6KB25_800MHZ)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174430,
++      0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481,
++      0x0304692F, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000000, 0x07100000,
++      0x00001B63, 0x00002000, 0x00004000, 0x00006000,
++      0x00000000, 0x00000000, 0x00000000, 0x00000000,
++#elif defined(CONFIG_MT7621_DRAM_DDR2_1024M_W971GG6KB18_1066MHZ)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584,
++      0x01000000, 0xF07486A1, 0x50001273, 0x9F070481,
++      0x0304693F, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000010, 0x07100000,
++      0x00001F73, 0x00002000, 0x00004000, 0x00006000,
++      0x00000000, 0x00000000, 0x00000000, 0x00000000,
++#else /* CONFIG_MT7621_DRAM_DDR2_1024M */
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441,
++      0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481,
++      0x0304692F, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000000, 0x07100000,
++      0x00001B63, 0x00002000, 0x00004000, 0x00006000,
++      0x00000000, 0x00000000, 0x00000000, 0x00000000,
++#endif
++};
++
++static const u32 ddr3_act[DDR_PARAM_SIZE] = {
++#if defined(CONFIG_MT7621_DRAM_DDR3_1024M)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683,
++      0x01000000, 0xF07486A1, 0xC287221D, 0x9F060481,
++      0x03046948, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000210, 0x07100000,
++      0x00001B61, 0x00002040, 0x00004010, 0x00006000,
++      0x0C000000, 0x07070000, 0x00000000, 0x00000000,
++#elif defined(CONFIG_MT7621_DRAM_DDR3_4096M)
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683,
++      0x01000000, 0xF07486A1, 0xC287221D, 0x9F0F0481,
++      0x03046948, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000240, 0x07100000,
++      0x00001B61, 0x00002040, 0x00004010, 0x00006000,
++      0x0C000000, 0x07070000, 0x00000000, 0x00000000,
++#elif defined(CONFIG_MT7621_DRAM_DDR3_1024M_KGD)
++      0xFF00FF00, 0xFF00FF00, 0x00000007, 0x44694683,
++      0x01000000, 0xF07406A1, 0xC287221D, 0x9F060481,
++      0x03046923, 0x152f2842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000210, 0x07100000,
++      0x00001B61, 0x00002040, 0x00004010, 0x00006000,
++      0x0C000000, 0x07070000, 0x000C0000, 0x00000000,
++#else /* CONFIG_MT7621_DRAM_DDR3_2048M */
++      0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694673,
++      0x01000000, 0xF07486A1, 0xC287221D, 0x9F050481,
++      0x03046948, 0x15602842, 0x00008888, 0x88888888,
++      0x00000000, 0x00000000, 0x00000220, 0x07100000,
++      0x00001B61, 0x00002040, 0x00004010, 0x00006000,
++      0x0C000000, 0x07070000, 0x00000000, 0x00000000,
++#endif
++};
++
++#if defined(CONFIG_MT7621_DRAM_FREQ_400)
++#define DDR_FREQ_PARAM                0x41000000
++#elif defined(CONFIG_MT7621_DRAM_FREQ_1066)
++#define DDR_FREQ_PARAM                0x21000000
++#elif defined(CONFIG_MT7621_DRAM_FREQ_1200)
++#define DDR_FREQ_PARAM                0x11000000
++#else /* CONFIG_MT7621_DRAM_FREQ_800 */
++#define DDR_FREQ_PARAM                0x31000000
++#endif
++
++#define RG_MEPL_FBDIV_S               4
++#define RG_MEPL_FBDIV_M               0x7f
++
++static inline void word_copy(u32 *dest, const u32 *src, u32 count)
++{
++      u32 i;
++
++      for (i = 0; i < count; i++)
++              dest[i] = src[i];
++}
++
++static u32 calc_cpu_pll_val(void)
++{
++      u32 div, baseval, fb;
++
++      div = get_xtal_mhz();
++
++      if (div == 40) {
++              div /= 2;
++              baseval = 0xc0005802;
++      } else {
++              baseval = 0xc0004802;
++      }
++
++      fb = CONFIG_MT7621_CPU_FREQ / div - 1;
++      if (fb > RG_MEPL_FBDIV_M)
++              fb = RG_MEPL_FBDIV_M;
++
++      return baseval | (fb << RG_MEPL_FBDIV_S);
++}
++
++void prepare_stage_bin(void)
++{
++      u32 stage_size;
++
++      const struct stage_header *stock_stage_bin =
++              (const struct stage_header *)__image_copy_end;
++
++      struct stage_header *new_stage_bin =
++              (struct stage_header *)STAGE_LOAD_ADDR;
++
++      if (be32_to_cpu(stock_stage_bin->ep) != STAGE_LOAD_ADDR)
++              panic("Invalid DDR stage binary blob\n");
++
++      stage_size = be32_to_cpu(stock_stage_bin->stage_size);
++
++      word_copy((u32 *)new_stage_bin, (const u32 *)stock_stage_bin,
++                (stage_size + sizeof(u32) - 1) / sizeof(u32));
++
++      word_copy(new_stage_bin->ddr2_act, ddr2_act, DDR_PARAM_SIZE);
++      word_copy(new_stage_bin->ddr3_act, ddr3_act, DDR_PARAM_SIZE);
++
++      new_stage_bin->cpu_pll_cfg = calc_cpu_pll_val();
++      new_stage_bin->ddr_pll_cfg = DDR_FREQ_PARAM;
++      new_stage_bin->baudrate = CONFIG_BAUDRATE;
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/dram.h b/arch/mips/mach-mtmips/mt7621/spl/dram.h
+new file mode 100644
+index 0000000000..7322c58276
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/dram.h
+@@ -0,0 +1,39 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _MT7621_DRAM_H_
++#define _MT7621_DRAM_H_
++
++#define STAGE_LOAD_ADDR                       0xBE108800
++
++#ifndef __ASSEMBLY__
++#include <linux/types.h>
++
++#define DDR_PARAM_SIZE                        24
++
++struct stage_header {
++      u32 jump_insn[2];
++      u32 ep;
++      u32 stage_size;
++      u32 has_stage2;
++      u32 next_ep;
++      u32 next_size;
++      u32 next_offset;
++      u32 cpu_pll_cfg;
++      u32 ddr_pll_cfg;
++      u32 reserved2[6];
++      char build_tag[32];
++      u32 ddr3_act[DDR_PARAM_SIZE];
++      u32 padding1[2];
++      u32 ddr2_act[DDR_PARAM_SIZE];
++      u32 padding2[2];
++      u32 baudrate;
++      u32 padding3;
++};
++#endif
++
++#endif /* _MT7621_DRAM_H_ */
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch.c b/arch/mips/mach-mtmips/mt7621/spl/launch.c
+new file mode 100644
+index 0000000000..37c20a5f56
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/launch.c
+@@ -0,0 +1,100 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/io.h>
++#include <asm/cm.h>
++#include <asm/sections.h>
++#include <asm/addrspace.h>
++#include <asm/mipsmtregs.h>
++#include <linux/sizes.h>
++#include <time.h>
++#include <cpu_func.h>
++#include "launch.h"
++#include "../mt7621.h"
++
++/* Cluster Power Controller (CPC) offsets */
++#define CPC_CL_OTHER                  0x2010
++#define CPC_CO_CMD                    0x4000
++
++/* CPC_CL_OTHER fields */
++#define CPC_CL_OTHER_CORENUM_SHIFT    16
++#define CPC_CL_OTHER_CORENUM          GENMASK(23, 16)
++
++/* CPC_CO_CMD */
++#define PWR_UP                                3
++
++#define NUM_CORES                     2
++#define NUM_CPUS                      4
++#define WAIT_CPUS_TIMEOUT             4000
++
++static void copy_launch_wait_code(void)
++{
++      memset((void *)KSEG1, 0, SZ_4K);
++
++      memcpy((void *)KSEG1ADDR(LAUNCH_WAITCODE),
++             &launch_wait_code_start,
++             &launch_wait_code_end - &launch_wait_code_start);
++
++      invalidate_dcache_range(KSEG0, SZ_4K);
++}
++
++static void bootup_secondary_core(void)
++{
++      void __iomem *cpcbase = (void __iomem *)KSEG1ADDR(MIPS_CPC_BASE);
++      int i;
++
++      for (i = 1; i < NUM_CORES; i++) {
++              writel(i << CPC_CL_OTHER_CORENUM_SHIFT, cpcbase + CPC_CL_OTHER);
++              writel(PWR_UP, cpcbase + CPC_CO_CMD);
++      }
++}
++
++void secondary_cpu_init(void)
++{
++      void __iomem *sysc = (void __iomem *)KSEG1ADDR(SYSCTL_BASE);
++      u32 i, dual_core = 0, cpuready = 1, cpumask = 0x03;
++      ulong wait_tick;
++      struct cpulaunch_t *c;
++
++      /* Copy LAUNCH wait code used by other VPEs */
++      copy_launch_wait_code();
++
++      dual_core = readl(sysc + SYSCTL_CHIP_REV_ID_REG) & CPU_ID;
++
++      if (dual_core) {
++              /* Bootup secondary core for MT7621A */
++              cpumask = 0x0f;
++
++              /* Make BootROM/TPL redirect Core1's bootup flow to our entry point */
++              writel((uintptr_t)&_start, sysc + BOOT_SRAM_BASE_REG);
++
++              bootup_secondary_core();
++      }
++
++      /* Join the coherent domain */
++      join_coherent_domain(dual_core ? 2 : 1);
++
++      /* Bootup Core0/VPE1 */
++      boot_vpe1();
++
++      /* Wait for all CPU ready */
++      wait_tick = get_timer(0) + WAIT_CPUS_TIMEOUT;
++
++      while (time_before(get_timer(0), wait_tick)) {
++              /* CPU0 is obviously ready */
++              for (i = 1; i < NUM_CPUS; i++) {
++                      c = (struct cpulaunch_t *)(KSEG0ADDR(CPULAUNCH) +
++                                                 (i << LOG2CPULAUNCH));
++
++                      if (c->flags & LAUNCH_FREADY)
++                              cpuready |= BIT(i);
++              }
++
++              if ((cpuready & cpumask) == cpumask)
++                      break;
++      }
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch.h b/arch/mips/mach-mtmips/mt7621/spl/launch.h
+new file mode 100644
+index 0000000000..f34250d605
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/launch.h
+@@ -0,0 +1,52 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _LAUNCH_H_
++#define _LAUNCH_H_
++
++#ifndef __ASSEMBLY__
++
++struct cpulaunch_t {
++      unsigned long pc;
++      unsigned long gp;
++      unsigned long sp;
++      unsigned long a0;
++      unsigned long _pad[3]; /* pad to cache line size to avoid thrashing */
++      unsigned long flags;
++};
++
++extern char launch_wait_code_start;
++extern char launch_wait_code_end;
++
++void join_coherent_domain(int ncores);
++void boot_vpe1(void);
++
++#else
++
++#define       LAUNCH_PC               0
++#define       LAUNCH_GP               4
++#define       LAUNCH_SP               8
++#define       LAUNCH_A0               12
++#define       LAUNCH_FLAGS            28
++
++#endif
++
++#define LOG2CPULAUNCH         5
++
++#define LAUNCH_FREADY         1
++#define LAUNCH_FGO            2
++#define LAUNCH_FGONE          4
++
++#define LAUNCH_WAITCODE               0x00000d00
++#define SCRLAUNCH             0x00000e00
++#define CPULAUNCH             0x00000f00
++#define NCPULAUNCH            8
++
++/* Polling period in count cycles for secondary CPU's */
++#define LAUNCHPERIOD          10000
++
++#endif /* _LAUNCH_H_ */
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S b/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S
+new file mode 100644
+index 0000000000..32d28c7539
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S
+@@ -0,0 +1,339 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/cm.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/cacheops.h>
++#include <asm/mipsregs.h>
++#include <asm/addrspace.h>
++#include <asm/mipsmtregs.h>
++#include "launch.h"
++
++      .macro cache_loop       curr, end, line_sz, op
++10:   cache           \op, 0(\curr)
++      PTR_ADDU        \curr, \curr, \line_sz
++      bne             \curr, \end, 10b
++      .endm
++
++      .set    mt
++
++/*
++ * Join the coherent domain
++ * a0 = number of cores
++ */
++LEAF(join_coherent_domain)
++      /*
++       * Enable coherence and allow interventions from all other cores.
++       * (Write access enabled via GCR_ACCESS by core 0.)
++       */
++      li      t1, 1
++      sll     t1, a0
++      addiu   t1, -1
++
++      li      t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE)
++      sw      t1, GCR_Cx_COHERENCE(t0)
++      ehb
++
++      move    t2, zero
++
++_next_coherent_core:
++      sll     t1, t2, GCR_Cx_OTHER_CORENUM_SHIFT
++      sw      t1, GCR_Cx_OTHER(t0)
++
++_busy_wait_coherent_core:
++      lw      t1, GCR_CO_COHERENCE(t0)
++      beqz    t1, _busy_wait_coherent_core
++
++      addiu   t2, 1
++      bne     t2, a0, _next_coherent_core
++
++      jr      ra
++      END(join_coherent_domain)
++
++/*
++ * All VPEs other than VPE0 will go here.
++ */
++LEAF(launch_vpe_entry)
++      mfc0    t0, CP0_EBASE
++      and     t0, t0, MIPS_EBASE_CPUNUM
++
++      /* per-VPE cpulaunch_t */
++      li      a0, KSEG0ADDR(CPULAUNCH)
++      sll     t1, t0, LOG2CPULAUNCH
++      addu    a0, t1
++
++      /* Set CPU online flag */
++      li      t0, LAUNCH_FREADY
++      sw      t0, LAUNCH_FLAGS(a0)
++
++      /* Enable count interrupt in mask, but do not enable interrupts */
++      mfc0    t0, CP0_STATUS
++      ori     t0, STATUSF_IP7
++      mtc0    t0, CP0_STATUS
++
++      /* VPEs executing in wait code do not need a stack */
++      li      t9, KSEG0ADDR(LAUNCH_WAITCODE)
++      jr      t9
++      END(launch_vpe_entry)
++
++/*
++ * This function will not be executed in place.
++ * It will be copied into memory, and VPEs other than VPE0 will be
++ * started to run into this in-memory function.
++ */
++LEAF(launch_wait_code)
++      .globl  launch_wait_code_start
++launch_wait_code_start:
++
++      move    t0, a0
++
++start_poll:
++      /* Poll CPU go flag */
++      mtc0    zero, CP0_COUNT
++      li      t1, LAUNCHPERIOD
++      mtc0    t1, CP0_COMPARE
++
++time_wait:
++      /* Software wait */
++      mfc0    t2, CP0_COUNT
++      subu    t2, t1
++      bltz    t2, time_wait
++
++      /* Check the launch flag */
++      lw      t3, LAUNCH_FLAGS(t0)
++      and     t3, LAUNCH_FGO
++      beqz    t3, start_poll
++
++      /* Reset the counter and interrupts to give naive clients a chance */
++      mfc0    t1, CP0_STATUS
++      ins     t1, zero, STATUSB_IP7, 1
++      mtc0    t1, CP0_STATUS
++
++      mfc0    t1, CP0_COUNT
++      subu    t1, 1
++      mtc0    t1, CP0_COMPARE
++
++      /* Jump to kernel */
++      lw      t9, LAUNCH_PC(t0)
++      lw      gp, LAUNCH_GP(t0)
++      lw      sp, LAUNCH_SP(t0)
++      lw      a0, LAUNCH_A0(t0)
++      move    a1, zero
++      move    a2, zero
++      move    a3, zero
++      ori     t3, LAUNCH_FGONE
++      sw      t3, LAUNCH_FLAGS(t0)
++
++      jr      t9
++
++      .globl  launch_wait_code_end
++launch_wait_code_end:
++      END(launch_wait_code)
++
++/*
++ * Core1 will go here.
++ */
++LEAF(launch_core_entry)
++      /* Disable caches */
++      bal     mips_cache_disable
++
++      /* Initialize L1 cache only */
++      li      a0, CONFIG_SYS_ICACHE_SIZE
++      li      a1, CONFIG_SYS_ICACHE_LINE_SIZE
++      li      a2, CONFIG_SYS_DCACHE_SIZE
++      li      a3, CONFIG_SYS_DCACHE_LINE_SIZE
++
++      mtc0    zero, CP0_TAGLO
++      mtc0    zero, CP0_TAGLO, 2
++      ehb
++
++      /*
++       * Initialize the I-cache first,
++       */
++      li              t0, KSEG0
++      addu            t1, t0, a0
++      /* clear tag to invalidate */
++      cache_loop      t0, t1, a1, INDEX_STORE_TAG_I
++#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
++      /* fill once, so data field parity is correct */
++      PTR_LI          t0, KSEG0
++      cache_loop      t0, t1, a1, FILL
++      /* invalidate again - prudent but not strictly necessary */
++      PTR_LI          t0, KSEG0
++      cache_loop      t0, t1, a1, INDEX_STORE_TAG_I
++#endif
++
++      /*
++       * then initialize D-cache.
++       */
++      PTR_LI          t0, KSEG0
++      PTR_ADDU        t1, t0, a2
++      /* clear all tags */
++      cache_loop      t0, t1, a3, INDEX_STORE_TAG_D
++#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
++      /* load from each line (in cached space) */
++      PTR_LI          t0, KSEG0
++2:    LONG_L          zero, 0(t0)
++      PTR_ADDU        t0, a3
++       bne            t0, t1, 2b
++      /* clear all tags */
++      PTR_LI          t0, KSEG0
++      cache_loop      t0, t1, a3, INDEX_STORE_TAG_D
++#endif
++
++      /* Set Cache Mode */
++      mfc0    t0, CP0_CONFIG
++      li      t1, CONF_CM_CACHABLE_COW
++      ins     t0, t1, 0, 3
++      mtc0    t0, CP0_CONFIG
++
++      /* Join the coherent domain */
++      li      a0, 2
++      bal     join_coherent_domain
++
++      /* Bootup Core0/VPE1 */
++      bal     boot_vpe1
++
++      b       launch_vpe_entry
++      END(launch_core_entry)
++
++/*
++ * Bootup VPE1.
++ * This subroutine must be executed from VPE0 with VPECONF0[MVP] already set.
++ */
++LEAF(boot_vpe1)
++      mfc0    t0, CP0_MVPCONF0
++
++      /* a0 = number of TCs - 1 */
++      ext     a0, t0, MVPCONF0_PTC_SHIFT, 8
++      beqz    a0, _vpe1_init_done
++
++      /* a1 = number of VPEs - 1 */
++      ext     a1, t0, MVPCONF0_PVPE_SHIFT, 4
++      beqz    a1, _vpe1_init_done
++
++      /* a2 = current TC No. */
++      move    a2, zero
++
++      /* Enter VPE Configuration State */
++      mfc0    t0, CP0_MVPCONTROL
++      or      t0, MVPCONTROL_VPC
++      mtc0    t0, CP0_MVPCONTROL
++      ehb
++
++_next_tc:
++      /* Set the TC number to be used on MTTR and MFTR instructions */
++      mfc0    t0, CP0_VPECONTROL
++      ins     t0, a2, 0, 8
++      mtc0    t0, CP0_VPECONTROL
++      ehb
++
++      /* TC0 is already bound */
++      beqz    a2, _next_vpe
++
++      /* Halt current TC */
++      li      t0, TCHALT_H
++      mttc0   t0, CP0_TCHALT
++      ehb
++
++      /* If there is spare TC, bind it to the last VPE (VPE[a1]) */
++      slt     t1, a1, a2
++      bnez    t1, _vpe_bind_tc
++       move   t1, a1
++
++      /* Set Exclusive TC for active TC */
++      mftc0   t0, CP0_VPECONF0
++      ins     t0, a2, VPECONF0_XTC_SHIFT, 8
++      mttc0   t0, CP0_VPECONF0
++
++      move    t1, a2
++_vpe_bind_tc:
++      /* Bind TC to a VPE */
++      mftc0   t0, CP0_TCBIND
++      ins     t0, t1, TCBIND_CURVPE_SHIFT, 4
++      mttc0   t0, CP0_TCBIND
++
++      /*
++       * Set up CP0_TCSTATUS register:
++       * Disable Coprocessor Usable bits
++       * Disable MDMX/DSP ASE
++       * Clear Dirty TC
++       * not dynamically allocatable
++       * not allocated
++       * Kernel mode
++       * interrupt exempt
++       * ASID 0
++       */
++      li      t0, TCSTATUS_IXMT
++      mttc0   t0, CP0_TCSTATUS
++
++_next_vpe:
++      slt     t1, a1, a2
++      bnez    t1, _done_vpe   # No more VPEs
++
++      /* Disable TC multi-threading */
++      mftc0   t0, CP0_VPECONTROL
++      ins     t0, zero, VPECONTROL_TE_SHIFT, 1
++      mttc0   t0, CP0_VPECONTROL
++
++      /* Skip following configuration for TC0 */
++      beqz    a2, _done_vpe
++
++      /* Deactivate VPE, set Master VPE */
++      mftc0   t0, CP0_VPECONF0
++      ins     t0, zero, VPECONF0_VPA_SHIFT, 1
++      or      t0, VPECONF0_MVP
++      mttc0   t0, CP0_VPECONF0
++
++      mfc0    t0, CP0_STATUS
++      mttc0   t0, CP0_STATUS
++
++      mttc0   zero, CP0_EPC
++      mttc0   zero, CP0_CAUSE
++
++      mfc0    t0, CP0_CONFIG
++      mttc0   t0, CP0_CONFIG
++
++      /*
++       * VPE1 of each core can execute cached as its L1 I$ has already
++       * been initialized.
++       * and the L2$ has been initialized or "disabled" via CCA override.
++       */
++      PTR_LA  t0, _start
++      mttc0   t0, CP0_TCRESTART
++
++      /* Unset Interrupt Exempt, set Activate Thread */
++      mftc0   t0, CP0_TCSTATUS
++      ins     t0, zero, TCSTATUS_IXMT_SHIFT, 1
++      ori     t0, TCSTATUS_A
++      mttc0   t0, CP0_TCSTATUS
++
++      /* Resume TC */
++      mttc0   zero, CP0_TCHALT
++
++      /* Activate VPE */
++      mftc0   t0, CP0_VPECONF0
++      ori     t0, VPECONF0_VPA
++      mttc0   t0, CP0_VPECONF0
++
++_done_vpe:
++      addu    a2, 1
++      sltu    t0, a0, a2
++      beqz    t0, _next_tc
++
++      mfc0    t0, CP0_MVPCONTROL
++      /* Enable all activated VPE to execute */
++      ori     t0, MVPCONTROL_EVP
++      /* Exit VPE Configuration State */
++      ins     t0, zero, MVPCONTROL_VPC_SHIFT, 1
++      mtc0    t0, CP0_MVPCONTROL
++      ehb
++
++_vpe1_init_done:
++      jr      ra
++      END(boot_vpe1)
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/serial.c b/arch/mips/mach-mtmips/mt7621/spl/serial.c
+new file mode 100644
+index 0000000000..5cf093a078
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/serial.c
+@@ -0,0 +1,24 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/io.h>
++#include "../mt7621.h"
++
++void mtmips_spl_serial_init(void)
++{
++#ifdef CONFIG_SPL_SERIAL
++      void __iomem *base = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
++
++#if CONFIG_CONS_INDEX == 1
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART1_MODE);
++#elif CONFIG_CONS_INDEX == 2
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART2_MODE_M);
++#elif CONFIG_CONS_INDEX == 3
++      clrbits_32(base + SYSCTL_GPIOMODE_REG, UART3_MODE_M);
++#endif /* CONFIG_CONS_INDEX */
++#endif /* CONFIG_SPL_SERIAL */
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/spl.c b/arch/mips/mach-mtmips/mt7621/spl/spl.c
+new file mode 100644
+index 0000000000..71d01aa7f5
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/spl.c
+@@ -0,0 +1,95 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <spl.h>
++#include <init.h>
++#include <image.h>
++#include <vsprintf.h>
++#include <malloc.h>
++#include <asm/io.h>
++#include <asm/sections.h>
++#include <asm/addrspace.h>
++#include <asm/byteorder.h>
++#include <asm/global_data.h>
++#include <linux/sizes.h>
++#include <mach/serial.h>
++#include "../mt7621.h"
++#include "dram.h"
++
++DECLARE_GLOBAL_DATA_PTR;
++
++struct tpl_info {
++      u32 magic;
++      u32 size;
++};
++
++void set_timer_freq_simple(void)
++{
++      u32 div = get_xtal_mhz();
++
++      /* Round down cpu freq */
++      gd->arch.timer_freq = rounddown(CONFIG_MT7621_CPU_FREQ, div) * 500000;
++}
++
++void __noreturn board_init_f(ulong dummy)
++{
++      spl_init();
++
++#ifdef CONFIG_SPL_SERIAL
++      /*
++       * mtmips_spl_serial_init() is useful if debug uart is enabled,
++       * or DM based serial is not enabled.
++       */
++      mtmips_spl_serial_init();
++      preloader_console_init();
++#endif
++
++      board_init_r(NULL, 0);
++}
++
++void board_boot_order(u32 *spl_boot_list)
++{
++#ifdef CONFIG_MT7621_BOOT_FROM_NAND
++      spl_boot_list[0] = BOOT_DEVICE_NAND;
++#else
++      spl_boot_list[0] = BOOT_DEVICE_NOR;
++#endif
++}
++
++unsigned long spl_nor_get_uboot_base(void)
++{
++      const struct tpl_info *tpli;
++      const image_header_t *hdr;
++      u32 addr;
++
++      addr = FLASH_MMAP_BASE + TPL_INFO_OFFSET;
++      tpli = (const struct tpl_info *)KSEG1ADDR(addr);
++
++      if (tpli->magic == TPL_INFO_MAGIC) {
++              addr = FLASH_MMAP_BASE + tpli->size;
++              hdr = (const image_header_t *)KSEG1ADDR(addr);
++
++              if (image_get_magic(hdr) == IH_MAGIC) {
++                      addr += sizeof(*hdr) + image_get_size(hdr);
++                      return KSEG1ADDR(addr);
++              }
++      }
++
++      panic("Unable to locate SPL payload\n");
++      return 0;
++}
++
++uint32_t spl_nand_get_uboot_raw_page(void)
++{
++      const struct stage_header *sh = (const struct stage_header *)&_start;
++      u32 addr;
++
++      addr = image_get_header_size() + be32_to_cpu(sh->stage_size);
++      addr = ALIGN(addr, SZ_4K);
++
++      return addr;
++}
+diff --git a/arch/mips/mach-mtmips/mt7621/spl/start.S b/arch/mips/mach-mtmips/mt7621/spl/start.S
+new file mode 100644
+index 0000000000..3cad3567e7
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/spl/start.S
+@@ -0,0 +1,226 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm-offsets.h>
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/mipsregs.h>
++#include <asm/cacheops.h>
++#include <asm/addrspace.h>
++#include <asm/mipsmtregs.h>
++#include <asm/cm.h>
++#include "../mt7621.h"
++#include "dram.h"
++
++#ifndef CONFIG_SYS_INIT_SP_ADDR
++#define CONFIG_SYS_INIT_SP_ADDR       (CONFIG_SYS_SDRAM_BASE + \
++                              CONFIG_SYS_INIT_SP_OFFSET)
++#endif
++
++#define SP_ADDR_TEMP          0xbe10dff0
++
++      .macro init_wr sel
++      MTC0    zero, CP0_WATCHLO,\sel
++      mtc0    t1, CP0_WATCHHI,\sel
++      .endm
++
++      .macro setup_stack_gd
++      li      t0, -16
++      PTR_LI  t1, CONFIG_SYS_INIT_SP_ADDR
++      and     sp, t1, t0              # force 16 byte alignment
++      PTR_SUBU \
++              sp, sp, GD_SIZE         # reserve space for gd
++      and     sp, sp, t0              # force 16 byte alignment
++      move    k0, sp                  # save gd pointer
++#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
++    !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
++      li      t2, CONFIG_VAL(SYS_MALLOC_F_LEN)
++      PTR_SUBU \
++              sp, sp, t2              # reserve space for early malloc
++      and     sp, sp, t0              # force 16 byte alignment
++#endif
++      move    fp, sp
++
++      /* Clear gd */
++      move    t0, k0
++1:
++      PTR_S   zero, 0(t0)
++      PTR_ADDIU t0, PTRSIZE
++      blt     t0, t1, 1b
++       nop
++
++#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
++    !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
++      PTR_S   sp, GD_MALLOC_BASE(k0)  # gd->malloc_base offset
++#endif
++      .endm
++
++      .set    noreorder
++
++ENTRY(_start)
++      b       1f
++       mtc0   zero, CP0_COUNT
++
++      /* Stage header required by BootROM */
++      .org    0x8
++      .word   0               # ep, filled by mkimage
++      .word   0               # stage_size, filled by mkimage
++      .word   0               # has_stage2
++      .word   0               # next_ep
++      .word   0               # next_size
++      .word   0               # next_offset
++
++1:
++      /* Init CP0 Status */
++      mfc0    t0, CP0_STATUS
++      and     t0, ST0_IMPL
++      or      t0, ST0_BEV | ST0_ERL
++      mtc0    t0, CP0_STATUS
++      ehb
++
++      /* Clear Watch Status bits and disable watch exceptions */
++      li      t1, 0x7         # Clear I, R and W conditions
++      init_wr 0
++      init_wr 1
++      init_wr 2
++      init_wr 3
++
++      /* Clear WP, IV and SW interrupts */
++      mtc0    zero, CP0_CAUSE
++
++      /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */
++      mtc0    zero, CP0_COMPARE
++
++      /* VPE1 goes to wait code directly */
++      mfc0    t0, CP0_TCBIND
++      andi    t0, TCBIND_CURVPE
++      bnez    t0, launch_vpe_entry
++       nop
++
++      /* Core1 goes to specific launch entry */
++      PTR_LI  t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE)
++      lw      t1, GCR_Cx_ID(t0)
++      bnez    t1, launch_core_entry
++       nop
++
++      /* MT7530 reset */
++      li      t0, KSEG1ADDR(SYSCTL_BASE)
++      lw      t1, SYSCTL_RSTCTL_REG(t0)
++      ori     t1, MCM_RST
++      sw      t1, SYSCTL_RSTCTL_REG(t0)
++
++      /* Disable DMA route for PSE SRAM set by BootROM */
++      PTR_LI  t0, KSEG1ADDR(DMA_CFG_ARB_BASE)
++      sw      zero, DMA_ROUTE_REG(t0)
++
++      /* Set CPU clock to 500MHz (Required if boot from NAND) */
++      li      t0, KSEG1ADDR(SYSCTL_BASE)
++      lw      t1, SYSCTL_CLKCFG0_REG(t0)
++      ins     t1, zero, 30, 2         # CPU_CLK_SEL
++      sw      t1, SYSCTL_CLKCFG0_REG(t0)
++
++      /* Set CPU clock divider to 1/1 */
++      li      t0, KSEG1ADDR(RBUS_BASE)
++      li      t1, 0x101
++      sw      t1, RBUS_DYN_CFG0_REG(t0)
++
++      /* (Re-)initialize the SRAM */
++      bal     mips_sram_init
++       nop
++
++      /* Set up temporary stack */
++      li      sp, SP_ADDR_TEMP
++
++      /* Setup full CPS */
++      bal     mips_cm_map
++       nop
++
++      bal     mt7621_cps_init
++       nop
++
++      /* Prepare for CPU/DDR initialization binary blob */
++      bal     prepare_stage_bin
++       nop
++
++      /* Call CPU/DDR initialization binary blob */
++      li      t9, STAGE_LOAD_ADDR
++      jalr    t9
++       nop
++
++      /* Switch CPU PLL source */
++      li      t0, KSEG1ADDR(SYSCTL_BASE)
++      lw      t1, SYSCTL_CLKCFG0_REG(t0)
++      li      t2, 1
++      ins     t1, t2, CPU_CLK_SEL_S, 2
++      sw      t1, SYSCTL_CLKCFG0_REG(t0)
++
++      /*
++       * Currently SPL is running on locked L2 cache (on KSEG0).
++       * To reset the entire cache, we have to writeback SPL to DRAM first.
++       * Cache flush won't work here. Use memcpy instead.
++       */
++
++      la      a0, __text_start
++      move    a1, a0
++      la      a2, __image_copy_end
++      sub     a2, a2, a1
++      li      a3, 5
++      ins     a0, a3, 29, 3   # convert to KSEG1
++
++      bal     memcpy
++       nop
++
++      /* Disable caches */
++      bal     mips_cache_disable
++       nop
++
++      /* Reset caches */
++      bal     mips_cache_reset
++       nop
++
++      /* Disable SRAM */
++      li      t0, KSEG1ADDR(FE_BASE)
++      li      t1, FE_PSE_RESET
++      sw      t1, FE_RST_GLO_REG(t0)
++
++      /* Clear the .bss section */
++      la      a0, __bss_start
++      la      a1, __bss_end
++1:    sw      zero, 0(a0)
++      addiu   a0, 4
++      ble     a0, a1, 1b
++       nop
++
++      /* Set up initial stack and global data */
++      setup_stack_gd
++
++#if CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
++      /* Set malloc base */
++      li      t0, (CONFIG_SYS_INIT_SP_ADDR + 15) & (~15)
++      PTR_S   t0, GD_MALLOC_BASE(k0)  # gd->malloc_base offset
++#endif
++
++#if defined(CONFIG_DEBUG_UART) && defined(CONFIG_SPL_SERIAL)
++      /* Earliest point to set up debug uart */
++      bal     debug_uart_init
++       nop
++#endif
++
++      /* Setup timer */
++      bal     set_timer_freq_simple
++       nop
++
++      /* Bootup secondary CPUs */
++      bal     secondary_cpu_init
++       nop
++
++      move    a0, zero                # a0 <-- boot_flags = 0
++      bal board_init_f
++       move   ra, zero
++
++      END(_start)
+diff --git a/arch/mips/mach-mtmips/mt7621/sram_init.S b/arch/mips/mach-mtmips/mt7621/sram_init.S
+new file mode 100644
+index 0000000000..03b9eab10b
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/sram_init.S
+@@ -0,0 +1,22 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm/addrspace.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include "mt7621.h"
++
++LEAF(mips_sram_init)
++      li      t0, KSEG1ADDR(FE_BASE)
++      li      t1, FE_PSE_RESET
++      sw      t1, FE_RST_GLO_REG(t0)
++
++      li      t1, (FE_PSE_RAM | FE_PSE_MEM_EN)
++      sw      t1, FE_RST_GLO_REG(t0)
++
++      jr      ra
++      END(mips_sram_init)
+diff --git a/arch/mips/mach-mtmips/mt7621/tpl/Makefile b/arch/mips/mach-mtmips/mt7621/tpl/Makefile
+new file mode 100644
+index 0000000000..471ad74249
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/tpl/Makefile
+@@ -0,0 +1,4 @@
++
++extra-y += start.o
++
++obj-y += tpl.o
+diff --git a/arch/mips/mach-mtmips/mt7621/tpl/start.S b/arch/mips/mach-mtmips/mt7621/tpl/start.S
+new file mode 100644
+index 0000000000..19b09f7251
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/tpl/start.S
+@@ -0,0 +1,161 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <asm-offsets.h>
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/mipsregs.h>
++#include <asm/cm.h>
++#include "../mt7621.h"
++
++#define SP_ADDR_TEMP          0xbe10dff0
++
++      .set noreorder
++
++      .macro init_wr sel
++      MTC0    zero, CP0_WATCHLO,\sel
++      mtc0    t1, CP0_WATCHHI,\sel
++      .endm
++
++      .macro uhi_mips_exception
++      move    k0, t9          # preserve t9 in k0
++      move    k1, a0          # preserve a0 in k1
++      li      t9, 15          # UHI exception operation
++      li      a0, 0           # Use hard register context
++      sdbbp   1               # Invoke UHI operation
++      .endm
++
++ENTRY(_start)
++      b       reset
++       mtc0   zero, CP0_COUNT
++
++      /*
++       * Store TPL size here.
++       * This will be used by SPL to locate u-boot payload.
++       */
++      .org    TPL_INFO_OFFSET
++      .word   TPL_INFO_MAGIC
++      .word   __image_copy_len
++
++      /* Exception vector */
++      .org 0x200
++      /* TLB refill, 32 bit task */
++      uhi_mips_exception
++
++      .org 0x280
++      /* XTLB refill, 64 bit task */
++      uhi_mips_exception
++
++      .org 0x300
++      /* Cache error exception */
++      uhi_mips_exception
++
++      .org 0x380
++      /* General exception */
++      uhi_mips_exception
++
++      .org 0x400
++      /* Catch interrupt exceptions */
++      uhi_mips_exception
++
++      .org 0x480
++      /* EJTAG debug exception */
++1:    b       1b
++       nop
++
++      .org 0x500
++
++reset:
++      /* Set KSEG0 to Uncached */
++      mfc0    t0, CP0_CONFIG
++      ins     t0, zero, 0, 3
++      ori     t0, t0, CONF_CM_UNCACHED
++      mtc0    t0, CP0_CONFIG
++      ehb
++
++      /* Check for CPU number */
++      mfc0    t0, CP0_EBASE
++      and     t0, t0, MIPS_EBASE_CPUNUM
++      beqz    t0, 1f
++       nop
++
++      /* Secondary core goes to specified SPL entry address */
++      li      t0, KSEG1ADDR(SYSCTL_BASE)
++      lw      t0, BOOT_SRAM_BASE_REG(t0)
++      jr      t0
++       nop
++
++      /* Init CP0 Status */
++1:    mfc0    t0, CP0_STATUS
++      and     t0, ST0_IMPL
++      or      t0, ST0_BEV | ST0_ERL
++      mtc0    t0, CP0_STATUS
++       nop
++
++      /* Clear Watch Status bits and disable watch exceptions */
++      li      t1, 0x7         # Clear I, R and W conditions
++      init_wr 0
++      init_wr 1
++      init_wr 2
++      init_wr 3
++
++      /* Clear WP, IV and SW interrupts */
++      mtc0    zero, CP0_CAUSE
++
++      /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */
++      mtc0    zero, CP0_COMPARE
++
++      /* Setup basic CPS */
++      bal     mips_cm_map
++       nop
++
++      li      t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE)
++      li      t1, GCR_REG0_BASE_VALUE
++      sw      t1, GCR_REG0_BASE(t0)
++
++      li      t1, ((GCR_REG0_MASK_VALUE << GCR_REGn_MASK_ADDRMASK_SHIFT) | \
++                  GCR_REGn_MASK_CMTGT_IOCU0)
++      sw      t1, GCR_REG0_MASK(t0)
++
++      lw      t1, GCR_BASE(t0)
++      ins     t1, zero, 0, 2          # CM_DEFAULT_TARGET
++      sw      t1, GCR_BASE(t0)
++
++      lw      t1, GCR_CONTROL(t0)
++      li      t2, GCR_CONTROL_SYNCCTL
++      or      t1, t1, t2
++      sw      t1, GCR_CONTROL(t0)
++
++      /* Increase SPI frequency */
++      li      t0, KSEG1ADDR(SPI_BASE)
++      li      t1, 5
++      sw      t1, SPI_SPACE_REG(t0)
++
++      /* Set CPU clock to 500MHz */
++      li      t0, KSEG1ADDR(SYSCTL_BASE)
++      lw      t1, SYSCTL_CLKCFG0_REG(t0)
++      ins     t1, zero, 30, 2         # CPU_CLK_SEL
++      sw      t1, SYSCTL_CLKCFG0_REG(t0)
++
++      /* Set CPU clock divider to 1/1 */
++      li      t0, KSEG1ADDR(RBUS_BASE)
++      li      t1, 0x101
++      sw      t1, RBUS_DYN_CFG0_REG(t0)
++
++      /* Initialize the SRAM */
++      bal     mips_sram_init
++       nop
++
++      /* Set up initial stack */
++      li      sp, SP_ADDR_TEMP
++
++      bal     tpl_main
++       nop
++
++      END(_start)
+diff --git a/arch/mips/mach-mtmips/mt7621/tpl/tpl.c b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c
+new file mode 100644
+index 0000000000..2a828907a3
+--- /dev/null
++++ b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c
+@@ -0,0 +1,144 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <image.h>
++#include <asm/system.h>
++#include <asm/sections.h>
++#include <asm/cacheops.h>
++#include <asm/mipsregs.h>
++#include <asm/cm.h>
++
++#define INDEX_STORE_DATA_SD   0x0f
++
++typedef void __noreturn (*image_entry_noargs_t)(void);
++
++/*
++ * Lock L2 cache and fill data
++ * Assume that data is 4-byte aligned and start_addr/size is 32-byte aligned
++ */
++static void fill_lock_l2cache(uintptr_t dataptr, ulong start_addr, ulong size)
++{
++      ulong slsize = CONFIG_SYS_DCACHE_LINE_SIZE;
++      ulong end_addr = start_addr + size;
++      const u32 *data = (u32 *)dataptr;
++      ulong i, addr;
++      u32 val;
++
++      /* Clear WSC & SPR bit in ErrCtl */
++      val = read_c0_ecc();
++      val &= 0xcfffffff;
++      write_c0_ecc(val);
++      execution_hazard_barrier();
++
++      for (addr = start_addr; addr < end_addr; addr += slsize) {
++              /* Set STagLo to lock cache line */
++              write_c0_staglo((addr & 0x1ffff800) | 0xa0);
++              mips_cache(INDEX_STORE_TAG_SD, (void *)addr);
++
++              /* Fill data */
++              for (i = 0; i < slsize; i += 8) {
++                      val = *data++;
++                      __write_32bit_c0_register($28, 5, val); /* sdtaglo */
++                      val = *data++;
++                      __write_32bit_c0_register($29, 5, val); /* sdtaghi */
++                      mips_cache(INDEX_STORE_DATA_SD, (void *)(addr + i));
++              }
++      }
++
++      sync();
++}
++
++/* A simple function to initialize MT7621's cache */
++static void mt7621_cache_init(void)
++{
++      void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE);
++      ulong lsize = CONFIG_SYS_DCACHE_LINE_SIZE;
++      ulong addr;
++      u32 val;
++
++      /* Enable CCA override. Set to uncached */
++      val = readl(cm_base + GCR_BASE);
++      val &= ~CCA_DEFAULT_OVR_MASK;
++      val |= CCA_DEFAULT_OVREN | (2 << CCA_DEFAULT_OVR_SHIFT);
++      writel(val, cm_base + GCR_BASE);
++
++      /* Initialize L1 I-Cache */
++      write_c0_taglo(0);
++      write_c0_taghi(0);
++
++      for (addr = 0; addr < CONFIG_SYS_ICACHE_SIZE; addr += lsize)
++              mips_cache(INDEX_STORE_TAG_I, (void *)addr);
++
++      /* Initialize L1 D-Cache */
++      write_c0_dtaglo(0);
++      __write_32bit_c0_register($29, 2, 0); /* dtaghi */
++
++      for (addr = 0; addr < CONFIG_SYS_DCACHE_SIZE; addr += lsize)
++              mips_cache(INDEX_STORE_TAG_D, (void *)addr);
++
++      /* Initialize L2 Cache */
++      write_c0_staglo(0);
++      __write_32bit_c0_register($29, 4, 0); /* staghi */
++
++      for (addr = 0; addr < (256 << 10); addr += lsize)
++              mips_cache(INDEX_STORE_TAG_SD, (void *)addr);
++
++      /* Dsiable CCA override */
++      val = readl(cm_base + GCR_BASE);
++      val &= ~(CCA_DEFAULT_OVR_MASK | CCA_DEFAULT_OVREN);
++      writel(val, cm_base + GCR_BASE);
++
++      /* Set KSEG0 to non-coherent cached (important!) */
++      val = read_c0_config();
++      val &= ~CONF_CM_CMASK;
++      val |= CONF_CM_CACHABLE_NONCOHERENT;
++      write_c0_config(val);
++      execution_hazard_barrier();
++
++      /* Again, invalidate L1 D-Cache */
++      for (addr = 0; addr < CONFIG_SYS_DCACHE_SIZE; addr += lsize)
++              mips_cache(INDEX_WRITEBACK_INV_D, (void *)addr);
++
++      /* Invalidate L1 I-Cache */
++      for (addr = 0; addr < CONFIG_SYS_ICACHE_SIZE; addr += lsize)
++              mips_cache(INDEX_INVALIDATE_I, (void *)addr);
++
++      /* Disable L2 cache bypass */
++      val = read_c0_config2();
++      val &= ~MIPS_CONF_IMPL;
++      write_c0_config2(val);
++      execution_hazard_barrier();
++}
++
++void __noreturn tpl_main(void)
++{
++      const image_header_t *hdr = (const image_header_t *)__image_copy_end;
++      image_entry_noargs_t image_entry;
++      u32 loadaddr, size;
++      uintptr_t data;
++
++      /* Initialize the cache first */
++      mt7621_cache_init();
++
++      if (image_get_magic(hdr) != IH_MAGIC)
++              goto failed;
++
++      loadaddr = image_get_load(hdr);
++      size = image_get_size(hdr);
++      image_entry = (image_entry_noargs_t)image_get_ep(hdr);
++
++      /* Load TPL image to L2 cache */
++      data = (uintptr_t)__image_copy_end + sizeof(struct image_header);
++      fill_lock_l2cache(data, loadaddr, size);
++
++      /* Jump to SPL */
++      image_entry();
++
++failed:
++      for (;;)
++              ;
++}
+diff --git a/include/configs/mt7621.h b/include/configs/mt7621.h
+new file mode 100644
+index 0000000000..dac6aa4afb
+--- /dev/null
++++ b/include/configs/mt7621.h
+@@ -0,0 +1,65 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef __CONFIG_MT7621_H
++#define __CONFIG_MT7621_H
++
++#define CONFIG_SYS_MIPS_TIMER_FREQ    440000000
++
++#define CONFIG_SYS_BOOTPARAMS_LEN     0x20000
++
++#define CONFIG_SYS_SDRAM_BASE         0x80000000
++
++#define CONFIG_VERY_BIG_RAM
++#define CONFIG_MAX_MEM_MAPPED         0x1c000000
++
++#define CONFIG_SYS_INIT_SP_OFFSET     0x800000
++
++#define CONFIG_SYS_BOOTM_LEN          0x2000000
++
++#define CONFIG_SYS_MAXARGS            16
++#define CONFIG_SYS_CBSIZE             1024
++
++#define CONFIG_SYS_NONCACHED_MEMORY   0x100000
++
++/* MMC */
++#define MMC_SUPPORTS_TUNING
++
++/* NAND */
++#define CONFIG_SYS_MAX_NAND_DEVICE    1
++
++/* Serial SPL */
++#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL)
++#define CONFIG_SYS_NS16550_MEM32
++#define CONFIG_SYS_NS16550_CLK                50000000
++#define CONFIG_SYS_NS16550_REG_SIZE   -4
++#define CONFIG_SYS_NS16550_COM1               0xbe000c00
++#endif
++
++/* Serial common */
++#define CONFIG_SYS_BAUDRATE_TABLE     { 9600, 19200, 38400, 57600, 115200, \
++                                        230400, 460800, 921600 }
++
++/* SPL */
++#define CONFIG_SYS_UBOOT_START                CONFIG_SYS_TEXT_BASE
++
++#ifdef CONFIG_TPL_BUILD
++#define CONFIG_SPL_START_S_PATH               "arch/mips/mach-mtmips/mt7621/tpl"
++/* .bss will not be used by TPL */
++#define CONFIG_SPL_BSS_START_ADDR     0x80000000
++#define CONFIG_SPL_BSS_MAX_SIZE               0
++#else
++#define CONFIG_SPL_START_S_PATH               "arch/mips/mach-mtmips/mt7621/spl"
++#define CONFIG_SPL_BSS_START_ADDR     0x80140000
++#define CONFIG_SPL_BSS_MAX_SIZE               0x80000
++#define CONFIG_SPL_MAX_SIZE           0x30000
++#endif
++
++/* Dummy value */
++#define CONFIG_SYS_UBOOT_BASE         0
++
++#endif /* __CONFIG_MT7621_H */
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0006-mips-mtmips-add-two-reference-boards-for-mt7621.patch b/package/boot/uboot-mediatek/patches/001-mtk-0006-mips-mtmips-add-two-reference-boards-for-mt7621.patch
new file mode 100644 (file)
index 0000000..d45670f
--- /dev/null
@@ -0,0 +1,456 @@
+From b1549087ecd1eb53f6173b17b473134fd6cca157 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:26 +0800
+Subject: [PATCH 06/25] mips: mtmips: add two reference boards for mt7621
+
+The mt7621_rfb board supports integrated giga PHYs plus one external
+giga PHYs. It also has up to 512MiB DDR3, 16MB SPI-NOR, 3 mini PCI-e x1
+slots, SDXC and USB.
+
+The mt7621_nand_rfb board is almost the same as mt7621_rfb board, but it
+uses NAND flash and SDXC is not available.
+
+Reviewed-by: Stefan Roese <sr@denx.de>
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/mips/dts/Makefile                     |  2 +
+ arch/mips/dts/mediatek,mt7621-nand-rfb.dts | 67 +++++++++++++++++
+ arch/mips/dts/mediatek,mt7621-rfb.dts      | 82 +++++++++++++++++++++
+ arch/mips/mach-mtmips/mt7621/Kconfig       | 20 +++++
+ board/mediatek/mt7621/MAINTAINERS          |  8 ++
+ board/mediatek/mt7621/Makefile             |  3 +
+ board/mediatek/mt7621/board.c              |  6 ++
+ configs/mt7621_nand_rfb_defconfig          | 85 ++++++++++++++++++++++
+ configs/mt7621_rfb_defconfig               | 82 +++++++++++++++++++++
+ 9 files changed, 355 insertions(+)
+ create mode 100644 arch/mips/dts/mediatek,mt7621-nand-rfb.dts
+ create mode 100644 arch/mips/dts/mediatek,mt7621-rfb.dts
+ create mode 100644 board/mediatek/mt7621/MAINTAINERS
+ create mode 100644 board/mediatek/mt7621/Makefile
+ create mode 100644 board/mediatek/mt7621/board.c
+ create mode 100644 configs/mt7621_nand_rfb_defconfig
+ create mode 100644 configs/mt7621_rfb_defconfig
+
+diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
+index 95144b24dc..1b179116c9 100644
+--- a/arch/mips/dts/Makefile
++++ b/arch/mips/dts/Makefile
+@@ -16,6 +16,8 @@ dtb-$(CONFIG_BOARD_COMTREND_WAP5813N) += comtrend,wap-5813n.dtb
+ dtb-$(CONFIG_BOARD_HUAWEI_HG556A) += huawei,hg556a.dtb
+ dtb-$(CONFIG_BOARD_MT7620_RFB) += mediatek,mt7620-rfb.dtb
+ dtb-$(CONFIG_BOARD_MT7620_MT7530_RFB) += mediatek,mt7620-mt7530-rfb.dtb
++dtb-$(CONFIG_BOARD_MT7621_RFB) += mediatek,mt7621-rfb.dtb
++dtb-$(CONFIG_BOARD_MT7621_NAND_RFB) += mediatek,mt7621-nand-rfb.dtb
+ dtb-$(CONFIG_BOARD_MT7628_RFB) += mediatek,mt7628-rfb.dtb
+ dtb-$(CONFIG_BOARD_GARDENA_SMART_GATEWAY_MT7688) += gardena-smart-gateway-mt7688.dtb
+ dtb-$(CONFIG_BOARD_LINKIT_SMART_7688) += linkit-smart-7688.dtb
+diff --git a/arch/mips/dts/mediatek,mt7621-nand-rfb.dts b/arch/mips/dts/mediatek,mt7621-nand-rfb.dts
+new file mode 100644
+index 0000000000..67ba298b0a
+--- /dev/null
++++ b/arch/mips/dts/mediatek,mt7621-nand-rfb.dts
+@@ -0,0 +1,67 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++/dts-v1/;
++
++#include "mt7621.dtsi"
++
++/ {
++      compatible = "mediatek,mt7621-nand-rfb", "mediatek,mt7621-soc";
++      model = "MediaTek MT7621 RFB (NAND)";
++
++      aliases {
++              serial0 = &uart0;
++      };
++
++      chosen {
++              stdout-path = &uart0;
++      };
++};
++
++&pinctrl {
++      state_default: pin_state {
++              nand {
++                      groups = "spi", "sdxc";
++                      function = "nand";
++              };
++
++              gpios {
++                      groups = "i2c", "uart3", "pcie reset";
++                      function = "gpio";
++              };
++
++              wdt {
++                      groups = "wdt";
++                      function = "wdt rst";
++              };
++
++              jtag {
++                      groups = "jtag";
++                      function = "jtag";
++              };
++      };
++};
++
++&uart0 {
++      status = "okay";
++};
++
++&gpio {
++      status = "okay";
++};
++
++&eth {
++      status = "okay";
++};
++
++&ssusb {
++      status = "okay";
++};
++
++&u3phy {
++      status = "okay";
++};
+diff --git a/arch/mips/dts/mediatek,mt7621-rfb.dts b/arch/mips/dts/mediatek,mt7621-rfb.dts
+new file mode 100644
+index 0000000000..ff7eaf0f20
+--- /dev/null
++++ b/arch/mips/dts/mediatek,mt7621-rfb.dts
+@@ -0,0 +1,82 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++/dts-v1/;
++
++#include "mt7621.dtsi"
++
++/ {
++      compatible = "mediatek,mt7621-rfb", "mediatek,mt7621-soc";
++      model = "MediaTek MT7621 RFB (SPI-NOR)";
++
++      aliases {
++              serial0 = &uart0;
++              spi0 = &spi;
++      };
++
++      chosen {
++              stdout-path = &uart0;
++      };
++};
++
++&pinctrl {
++      state_default: pin_state {
++              gpios {
++                      groups = "i2c", "uart3", "pcie reset";
++                      function = "gpio";
++              };
++
++              wdt {
++                      groups = "wdt";
++                      function = "wdt rst";
++              };
++
++              jtag {
++                      groups = "jtag";
++                      function = "jtag";
++              };
++      };
++};
++
++&uart0 {
++      status = "okay";
++};
++
++&gpio {
++      status = "okay";
++};
++
++&spi {
++      status = "okay";
++      num-cs = <2>;
++
++      spi-flash@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "jedec,spi-nor";
++              spi-max-frequency = <25000000>;
++              reg = <0>;
++      };
++};
++
++&eth {
++      status = "okay";
++};
++
++&mmc {
++      cap-sd-highspeed;
++
++      status = "okay";
++};
++
++&ssusb {
++      status = "okay";
++};
++
++&u3phy {
++      status = "okay";
++};
+diff --git a/arch/mips/mach-mtmips/mt7621/Kconfig b/arch/mips/mach-mtmips/mt7621/Kconfig
+index 37d512c68f..008a28f991 100644
+--- a/arch/mips/mach-mtmips/mt7621/Kconfig
++++ b/arch/mips/mach-mtmips/mt7621/Kconfig
+@@ -79,6 +79,26 @@ config MT7621_BOOT_FROM_NAND
+ choice
+       prompt "Board select"
++config BOARD_MT7621_RFB
++      bool "MediaTek MT7621 RFB (SPI-NOR)"
++      help
++        The reference design of MT7621A (WS3010) booting from SPI-NOR flash.
++        The board can be configured with DDR2 (64MiB~256MiB) or DDR3
++        (128MiB~512MiB). The board has 16 MiB SPI-NOR flash, built-in MT7530
++        GbE switch, 1 UART, 1 USB 2.0 host, 1 USB 3.0 host, 1 SDXC, 3 PCIe
++        sockets, 1 RGMII to external GbE PHY, 2 audio jacks (in/out),
++        JTAG pins and expansion GPIO pins.
++
++config BOARD_MT7621_NAND_RFB
++      bool "MediaTek MT7621 RFB (NAND)"
++      help
++        The reference design of MT7621A (WS3010) booting from NAND flash.
++        The board can be configured with DDR2 (64MiB~256MiB) or DDR3
++        (128MiB~512MiB). The board has 128 MiB parallel NAND flash, built-in
++        MT7530 GbE switch, 1 UART, 1 USB 2.0 host, 1 USB 3.0 host, 3 PCIe
++        sockets, 1 RGMII to external GbE PHY, 2 audio jacks (in/out),
++        JTAG pins and expansion GPIO pins.
++
+ endchoice
+ config SYS_CONFIG_NAME
+diff --git a/board/mediatek/mt7621/MAINTAINERS b/board/mediatek/mt7621/MAINTAINERS
+new file mode 100644
+index 0000000000..f83141cea1
+--- /dev/null
++++ b/board/mediatek/mt7621/MAINTAINERS
+@@ -0,0 +1,8 @@
++MT7621_RFB BOARD
++M:    Weijie Gao <weijie.gao@mediatek.com>
++S:    Maintained
++F:    board/mediatek/mt7621
++F:    configs/mt7621_rfb_defconfig
++F:    configs/mt7621_nand_rfb_defconfig
++F:    arch/mips/dts/mediatek,mt7621-rfb.dts
++F:    arch/mips/dts/mediatek,mt7621-nand-rfb.dts
+diff --git a/board/mediatek/mt7621/Makefile b/board/mediatek/mt7621/Makefile
+new file mode 100644
+index 0000000000..db129c5aba
+--- /dev/null
++++ b/board/mediatek/mt7621/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++
++obj-y += board.o
+diff --git a/board/mediatek/mt7621/board.c b/board/mediatek/mt7621/board.c
+new file mode 100644
+index 0000000000..0496f3f806
+--- /dev/null
++++ b/board/mediatek/mt7621/board.c
+@@ -0,0 +1,6 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
+diff --git a/configs/mt7621_nand_rfb_defconfig b/configs/mt7621_nand_rfb_defconfig
+new file mode 100644
+index 0000000000..fe8543df49
+--- /dev/null
++++ b/configs/mt7621_nand_rfb_defconfig
+@@ -0,0 +1,85 @@
++CONFIG_MIPS=y
++CONFIG_SYS_MALLOC_LEN=0x100000
++CONFIG_SPL_LIBCOMMON_SUPPORT=y
++CONFIG_SPL_LIBGENERIC_SUPPORT=y
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_ENV_SIZE=0x1000
++CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-nand-rfb"
++CONFIG_SPL_SERIAL=y
++CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
++CONFIG_SPL=y
++CONFIG_DEBUG_UART_BASE=0xbe000c00
++CONFIG_DEBUG_UART_CLOCK=50000000
++CONFIG_SYS_LOAD_ADDR=0x83000000
++CONFIG_ARCH_MTMIPS=y
++CONFIG_SOC_MT7621=y
++CONFIG_MT7621_BOOT_FROM_NAND=y
++CONFIG_BOARD_MT7621_NAND_RFB=y
++# CONFIG_MIPS_CACHE_SETUP is not set
++# CONFIG_MIPS_CACHE_DISABLE is not set
++CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
++CONFIG_MIPS_BOOT_FDT=y
++CONFIG_DEBUG_UART=y
++CONFIG_FIT=y
++# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
++CONFIG_SYS_CONSOLE_INFO_QUIET=y
++CONFIG_SPL_SYS_MALLOC_SIMPLE=y
++CONFIG_SPL_NAND_SUPPORT=y
++CONFIG_SPL_NAND_BASE=y
++CONFIG_SPL_NAND_IDENT=y
++# CONFIG_BOOTM_NETBSD is not set
++# CONFIG_BOOTM_PLAN9 is not set
++# CONFIG_BOOTM_RTEMS is not set
++# CONFIG_BOOTM_VXWORKS is not set
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_XIMG is not set
++# CONFIG_CMD_CRC32 is not set
++# CONFIG_CMD_DM is not set
++# CONFIG_CMD_FLASH is not set
++CONFIG_CMD_GPIO=y
++# CONFIG_CMD_LOADS is not set
++CONFIG_CMD_MMC=y
++CONFIG_CMD_MTD=y
++CONFIG_CMD_PART=y
++# CONFIG_CMD_PINMUX is not set
++CONFIG_CMD_USB=y
++# CONFIG_CMD_NFS is not set
++CONFIG_CMD_FAT=y
++CONFIG_CMD_FS_GENERIC=y
++# CONFIG_SPL_DOS_PARTITION is not set
++# CONFIG_ISO_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SPL_EFI_PARTITION is not set
++CONFIG_PARTITION_TYPE_GUID=y
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_I2C is not set
++# CONFIG_INPUT is not set
++CONFIG_MMC=y
++# CONFIG_MMC_QUIRKS is not set
++# CONFIG_MMC_HW_PARTITIONING is not set
++CONFIG_MMC_MTK=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_MTD_RAW_NAND=y
++CONFIG_NAND_MT7621=y
++CONFIG_SYS_NAND_ONFI_DETECTION=y
++CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
++CONFIG_SYS_NAND_U_BOOT_OFFS=0x0
++CONFIG_MEDIATEK_ETH=y
++CONFIG_PHY=y
++CONFIG_PHY_MTK_TPHY=y
++CONFIG_DEBUG_UART_SHIFT=2
++CONFIG_SYSRESET=y
++CONFIG_SYSRESET_RESETCTL=y
++CONFIG_USB=y
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_MTK=y
++CONFIG_USB_STORAGE=y
++CONFIG_WDT=y
++CONFIG_WDT_MT7621=y
++CONFIG_FAT_WRITE=y
++# CONFIG_BINMAN_FDT is not set
++CONFIG_LZMA=y
++# CONFIG_GZIP is not set
++CONFIG_SPL_LZMA=y
+diff --git a/configs/mt7621_rfb_defconfig b/configs/mt7621_rfb_defconfig
+new file mode 100644
+index 0000000000..ae62360e63
+--- /dev/null
++++ b/configs/mt7621_rfb_defconfig
+@@ -0,0 +1,82 @@
++CONFIG_MIPS=y
++CONFIG_SYS_MALLOC_LEN=0x100000
++CONFIG_SPL_LIBCOMMON_SUPPORT=y
++CONFIG_SPL_LIBGENERIC_SUPPORT=y
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_ENV_SIZE=0x1000
++CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-rfb"
++CONFIG_SPL_SERIAL=y
++CONFIG_SPL_SYS_MALLOC_F_LEN=0x40000
++CONFIG_SPL=y
++CONFIG_DEBUG_UART_BASE=0xbe000c00
++CONFIG_DEBUG_UART_CLOCK=50000000
++CONFIG_SYS_LOAD_ADDR=0x83000000
++CONFIG_ARCH_MTMIPS=y
++CONFIG_SOC_MT7621=y
++# CONFIG_MIPS_CACHE_SETUP is not set
++# CONFIG_MIPS_CACHE_DISABLE is not set
++CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
++CONFIG_MIPS_BOOT_FDT=y
++CONFIG_DEBUG_UART=y
++CONFIG_TPL_SYS_MALLOC_F_LEN=0x1000
++CONFIG_FIT=y
++# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
++CONFIG_SYS_CONSOLE_INFO_QUIET=y
++CONFIG_SPL_SYS_MALLOC_SIMPLE=y
++CONFIG_SPL_NOR_SUPPORT=y
++CONFIG_TPL=y
++# CONFIG_TPL_FRAMEWORK is not set
++# CONFIG_BOOTM_NETBSD is not set
++# CONFIG_BOOTM_PLAN9 is not set
++# CONFIG_BOOTM_RTEMS is not set
++# CONFIG_BOOTM_VXWORKS is not set
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_XIMG is not set
++# CONFIG_CMD_CRC32 is not set
++# CONFIG_CMD_DM is not set
++CONFIG_CMD_GPIO=y
++# CONFIG_CMD_LOADS is not set
++CONFIG_CMD_MMC=y
++CONFIG_CMD_PART=y
++# CONFIG_CMD_PINMUX is not set
++CONFIG_CMD_SPI=y
++# CONFIG_CMD_NFS is not set
++CONFIG_DOS_PARTITION=y
++# CONFIG_SPL_DOS_PARTITION is not set
++# CONFIG_ISO_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SPL_EFI_PARTITION is not set
++CONFIG_PARTITION_TYPE_GUID=y
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_I2C is not set
++# CONFIG_INPUT is not set
++CONFIG_MMC=y
++# CONFIG_MMC_QUIRKS is not set
++# CONFIG_MMC_HW_PARTITIONING is not set
++CONFIG_MMC_MTK=y
++CONFIG_SF_DEFAULT_SPEED=20000000
++CONFIG_SPI_FLASH_BAR=y
++CONFIG_SPI_FLASH_EON=y
++CONFIG_SPI_FLASH_GIGADEVICE=y
++CONFIG_SPI_FLASH_ISSI=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_SPANSION=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_SPI_FLASH_WINBOND=y
++CONFIG_SPI_FLASH_XMC=y
++CONFIG_SPI_FLASH_XTX=y
++CONFIG_MEDIATEK_ETH=y
++CONFIG_PHY=y
++CONFIG_PHY_MTK_TPHY=y
++CONFIG_DEBUG_UART_SHIFT=2
++CONFIG_SPI=y
++CONFIG_MT7621_SPI=y
++CONFIG_SYSRESET=y
++CONFIG_SYSRESET_RESETCTL=y
++CONFIG_WDT=y
++CONFIG_WDT_MT7621=y
++# CONFIG_BINMAN_FDT is not set
++CONFIG_LZMA=y
++# CONFIG_GZIP is not set
++CONFIG_SPL_LZMA=y
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0007-doc-mediatek-add-documentation-for-mt7621-reference-.patch b/package/boot/uboot-mediatek/patches/001-mtk-0007-doc-mediatek-add-documentation-for-mt7621-reference-.patch
new file mode 100644 (file)
index 0000000..294740a
--- /dev/null
@@ -0,0 +1,104 @@
+From 3fed02d930597c53f1c8500aff14581bb87a1e3d Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:31 +0800
+Subject: [PATCH 07/25] doc: mediatek: add documentation for mt7621 reference
+ boards
+
+The MT7621 requires external binary blob being executed during u-boot's
+boot-up flow. It's necessary to provide a guide here for users to correctly
+build the u-boot.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ doc/board/index.rst           |  1 +
+ doc/board/mediatek/index.rst  |  9 +++++++
+ doc/board/mediatek/mt7621.rst | 48 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 58 insertions(+)
+ create mode 100644 doc/board/mediatek/index.rst
+ create mode 100644 doc/board/mediatek/mt7621.rst
+
+diff --git a/doc/board/index.rst b/doc/board/index.rst
+index f90a9cad45..01b99f9cf5 100644
+--- a/doc/board/index.rst
++++ b/doc/board/index.rst
+@@ -23,6 +23,7 @@ Board-specific doc
+    highbank/index
+    intel/index
+    kontron/index
++   mediatek/index
+    microchip/index
+    nokia/index
+    nxp/index
+diff --git a/doc/board/mediatek/index.rst b/doc/board/mediatek/index.rst
+new file mode 100644
+index 0000000000..38cd8cb5b2
+--- /dev/null
++++ b/doc/board/mediatek/index.rst
+@@ -0,0 +1,9 @@
++.. SPDX-License-Identifier: GPL-2.0+
++
++Mediatek
++=========
++
++.. toctree::
++   :maxdepth: 2
++
++   mt7621
+diff --git a/doc/board/mediatek/mt7621.rst b/doc/board/mediatek/mt7621.rst
+new file mode 100644
+index 0000000000..1662255546
+--- /dev/null
++++ b/doc/board/mediatek/mt7621.rst
+@@ -0,0 +1,48 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++mt7621_rfb/mt7621_nand_rfb
++==========================
++
++U-Boot for the MediaTek MT7621 boards
++
++Quick Start
++-----------
++
++- Get the DDR initialization binary blob
++- Configure CPU and DDR parameters
++- Build U-Boot
++
++Get the DDR initialization binary blob
++--------------------------------------
++
++Download one from:
++ - https://raw.githubusercontent.com/mtk-openwrt/mt7621-lowlevel-preloader/master/mt7621_stage_sram.bin
++ - https://raw.githubusercontent.com/mtk-openwrt/mt7621-lowlevel-preloader/master/mt7621_stage_sram_noprint.bin
++
++mt7621_stage_sram_noprint.bin has removed all output logs. To use this one,
++download and rename it to mt7621_stage_sram.bin
++
++Put the binary blob to the u-boot build directory.
++
++Configure CPU and DDR parameters
++--------------------------------
++
++menuconfig > MIPS architecture > MediaTek MIPS platforms > CPU & DDR configuration
++
++Select the correct DDR timing parameters for your board. The size shown here
++must match the DDR size of you board.
++
++The frequency of CPU and DDR can also be adjusted.
++
++Build U-Boot
++------------
++
++.. code-block:: bash
++
++   $ export CROSS_COMPILE=mipsel-linux-
++   $ make O=build mt7621_rfb_defconfig # or mt7621_nand_rfb_defconfig
++   $ cp mt7621_stage_sram.bin ./build/mt7621_stage_sram.bin
++   $ # or cp mt7621_stage_sram_noprint.bin ./build/mt7621_stage_sram.bin
++   $ make O=build
++
++Burn the u-boot-mt7621.bin to the SPI-NOR or NAND flash.
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0008-clk-mtmips-add-clock-driver-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0008-clk-mtmips-add-clock-driver-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..02d97e9
--- /dev/null
@@ -0,0 +1,378 @@
+From c2e579662748cb5d3bf3e31f58d99c4db4d102c1 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:36 +0800
+Subject: [PATCH 08/25] clk: mtmips: add clock driver for MediaTek MT7621 SoC
+
+This patch adds a clock driver for MediaTek MT7621 SoC.
+This driver provides clock gate control as well as getting clock frequency
+for CPU/SYS/XTAL and some peripherals.
+
+Reviewed-by: Sean Anderson <seanga2@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/clk/mtmips/Makefile            |   1 +
+ drivers/clk/mtmips/clk-mt7621.c        | 288 +++++++++++++++++++++++++
+ include/dt-bindings/clock/mt7621-clk.h |  46 ++++
+ 3 files changed, 335 insertions(+)
+ create mode 100644 drivers/clk/mtmips/clk-mt7621.c
+ create mode 100644 include/dt-bindings/clock/mt7621-clk.h
+
+diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile
+index 732e7f2545..ee8b5afe87 100644
+--- a/drivers/clk/mtmips/Makefile
++++ b/drivers/clk/mtmips/Makefile
+@@ -1,4 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_SOC_MT7620) += clk-mt7620.o
++obj-$(CONFIG_SOC_MT7621) += clk-mt7621.o
+ obj-$(CONFIG_SOC_MT7628) += clk-mt7628.o
+diff --git a/drivers/clk/mtmips/clk-mt7621.c b/drivers/clk/mtmips/clk-mt7621.c
+new file mode 100644
+index 0000000000..03363b70d7
+--- /dev/null
++++ b/drivers/clk/mtmips/clk-mt7621.c
+@@ -0,0 +1,288 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <clk-uclass.h>
++#include <dm.h>
++#include <dm/device_compat.h>
++#include <regmap.h>
++#include <syscon.h>
++#include <dt-bindings/clock/mt7621-clk.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++#include <linux/bitfield.h>
++
++#define SYSC_MAP_SIZE                 0x100
++#define MEMC_MAP_SIZE                 0x1000
++
++/* SYSC */
++#define SYSCFG0_REG                   0x10
++#define XTAL_MODE_SEL                 GENMASK(8, 6)
++
++#define CLKCFG0_REG                   0x2c
++#define CPU_CLK_SEL                   GENMASK(31, 30)
++#define PERI_CLK_SEL                  BIT(4)
++
++#define CLKCFG1_REG                   0x30
++
++#define CUR_CLK_STS_REG                       0x44
++#define CUR_CPU_FDIV                  GENMASK(12, 8)
++#define CUR_CPU_FFRAC                 GENMASK(4, 0)
++
++/* MEMC */
++#define MEMPLL1_REG                   0x0604
++#define RG_MEPL_DIV2_SEL              GENMASK(2, 1)
++
++#define MEMPLL6_REG                   0x0618
++#define MEMPLL18_REG                  0x0648
++#define RG_MEPL_PREDIV                        GENMASK(13, 12)
++#define RG_MEPL_FBDIV                 GENMASK(10, 4)
++
++/* Fixed 500M clock */
++#define GMPLL_CLK                     500000000
++
++struct mt7621_clk_priv {
++      void __iomem *sysc_base;
++      int cpu_clk;
++      int ddr_clk;
++      int sys_clk;
++      int xtal_clk;
++};
++
++enum mt7621_clk_src {
++      CLK_SRC_CPU,
++      CLK_SRC_DDR,
++      CLK_SRC_SYS,
++      CLK_SRC_XTAL,
++      CLK_SRC_PERI,
++      CLK_SRC_125M,
++      CLK_SRC_150M,
++      CLK_SRC_250M,
++      CLK_SRC_270M,
++
++      __CLK_SRC_MAX
++};
++
++struct mt7621_clk_map {
++      u32 cgbit;
++      enum mt7621_clk_src clksrc;
++};
++
++#define CLK_MAP(_id, _cg, _src) \
++      [_id] = { .cgbit = (_cg), .clksrc = (_src) }
++
++#define CLK_MAP_SRC(_id, _src) \
++      [_id] = { .cgbit = UINT32_MAX, .clksrc = (_src) }
++
++static const struct mt7621_clk_map mt7621_clk_mappings[] = {
++      CLK_MAP_SRC(MT7621_CLK_XTAL, CLK_SRC_XTAL),
++      CLK_MAP_SRC(MT7621_CLK_CPU, CLK_SRC_CPU),
++      CLK_MAP_SRC(MT7621_CLK_BUS, CLK_SRC_SYS),
++      CLK_MAP_SRC(MT7621_CLK_50M, CLK_SRC_PERI),
++      CLK_MAP_SRC(MT7621_CLK_125M, CLK_SRC_125M),
++      CLK_MAP_SRC(MT7621_CLK_150M, CLK_SRC_150M),
++      CLK_MAP_SRC(MT7621_CLK_250M, CLK_SRC_250M),
++      CLK_MAP_SRC(MT7621_CLK_270M, CLK_SRC_270M),
++
++      CLK_MAP(MT7621_CLK_HSDMA, 5, CLK_SRC_150M),
++      CLK_MAP(MT7621_CLK_FE, 6, CLK_SRC_250M),
++      CLK_MAP(MT7621_CLK_SP_DIVTX, 7, CLK_SRC_270M),
++      CLK_MAP(MT7621_CLK_TIMER, 8, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_PCM, 11, CLK_SRC_270M),
++      CLK_MAP(MT7621_CLK_PIO, 13, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_GDMA, 14, CLK_SRC_SYS),
++      CLK_MAP(MT7621_CLK_NAND, 15, CLK_SRC_125M),
++      CLK_MAP(MT7621_CLK_I2C, 16, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_I2S, 17, CLK_SRC_270M),
++      CLK_MAP(MT7621_CLK_SPI, 18, CLK_SRC_SYS),
++      CLK_MAP(MT7621_CLK_UART1, 19, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_UART2, 20, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_UART3, 21, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_ETH, 23, CLK_SRC_PERI),
++      CLK_MAP(MT7621_CLK_PCIE0, 24, CLK_SRC_125M),
++      CLK_MAP(MT7621_CLK_PCIE1, 25, CLK_SRC_125M),
++      CLK_MAP(MT7621_CLK_PCIE2, 26, CLK_SRC_125M),
++      CLK_MAP(MT7621_CLK_CRYPTO, 29, CLK_SRC_250M),
++      CLK_MAP(MT7621_CLK_SHXC, 30, CLK_SRC_PERI),
++
++      CLK_MAP_SRC(MT7621_CLK_MAX, __CLK_SRC_MAX),
++
++      CLK_MAP_SRC(MT7621_CLK_DDR, CLK_SRC_DDR),
++};
++
++static ulong mt7621_clk_get_rate(struct clk *clk)
++{
++      struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
++      u32 val;
++
++      switch (mt7621_clk_mappings[clk->id].clksrc) {
++      case CLK_SRC_CPU:
++              return priv->cpu_clk;
++      case CLK_SRC_DDR:
++              return priv->ddr_clk;
++      case CLK_SRC_SYS:
++              return priv->sys_clk;
++      case CLK_SRC_XTAL:
++              return priv->xtal_clk;
++      case CLK_SRC_PERI:
++              val = readl(priv->sysc_base + CLKCFG0_REG);
++              if (val & PERI_CLK_SEL)
++                      return priv->xtal_clk;
++              else
++                      return GMPLL_CLK / 10;
++      case CLK_SRC_125M:
++              return 125000000;
++      case CLK_SRC_150M:
++              return 150000000;
++      case CLK_SRC_250M:
++              return 250000000;
++      case CLK_SRC_270M:
++              return 270000000;
++      default:
++              return 0;
++      }
++}
++
++static int mt7621_clk_enable(struct clk *clk)
++{
++      struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
++      u32 cgbit;
++
++      cgbit = mt7621_clk_mappings[clk->id].cgbit;
++      if (cgbit == UINT32_MAX)
++              return -ENOSYS;
++
++      setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(cgbit));
++
++      return 0;
++}
++
++static int mt7621_clk_disable(struct clk *clk)
++{
++      struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
++      u32 cgbit;
++
++      cgbit = mt7621_clk_mappings[clk->id].cgbit;
++      if (cgbit == UINT32_MAX)
++              return -ENOSYS;
++
++      clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(cgbit));
++
++      return 0;
++}
++
++static int mt7621_clk_request(struct clk *clk)
++{
++      if (clk->id >= ARRAY_SIZE(mt7621_clk_mappings))
++              return -EINVAL;
++      return 0;
++}
++
++const struct clk_ops mt7621_clk_ops = {
++      .request = mt7621_clk_request,
++      .enable = mt7621_clk_enable,
++      .disable = mt7621_clk_disable,
++      .get_rate = mt7621_clk_get_rate,
++};
++
++static void mt7621_get_clocks(struct mt7621_clk_priv *priv, struct regmap *memc)
++{
++      u32 bs, xtal_sel, clkcfg0, cur_clk, mempll, dividx, fb;
++      u32 xtal_clk, xtal_div, ffiv, ffrac, cpu_clk, ddr_clk;
++      static const u32 xtal_div_tbl[] = {0, 1, 2, 2};
++
++      bs = readl(priv->sysc_base + SYSCFG0_REG);
++      clkcfg0 = readl(priv->sysc_base + CLKCFG0_REG);
++      cur_clk = readl(priv->sysc_base + CUR_CLK_STS_REG);
++
++      xtal_sel = FIELD_GET(XTAL_MODE_SEL, bs);
++
++      if (xtal_sel <= 2)
++              xtal_clk = 20 * 1000 * 1000;
++      else if (xtal_sel <= 5)
++              xtal_clk = 40 * 1000 * 1000;
++      else
++              xtal_clk = 25 * 1000 * 1000;
++
++      switch (FIELD_GET(CPU_CLK_SEL, clkcfg0)) {
++      case 0:
++              cpu_clk = GMPLL_CLK;
++              break;
++      case 1:
++              regmap_read(memc, MEMPLL18_REG, &mempll);
++              dividx = FIELD_GET(RG_MEPL_PREDIV, mempll);
++              fb = FIELD_GET(RG_MEPL_FBDIV, mempll);
++              xtal_div = 1 << xtal_div_tbl[dividx];
++              cpu_clk = (fb + 1) * xtal_clk / xtal_div;
++              break;
++      default:
++              cpu_clk = xtal_clk;
++      }
++
++      ffiv = FIELD_GET(CUR_CPU_FDIV, cur_clk);
++      ffrac = FIELD_GET(CUR_CPU_FFRAC, cur_clk);
++      cpu_clk = cpu_clk / ffiv * ffrac;
++
++      regmap_read(memc, MEMPLL6_REG, &mempll);
++      dividx = FIELD_GET(RG_MEPL_PREDIV, mempll);
++      fb = FIELD_GET(RG_MEPL_FBDIV, mempll);
++      xtal_div = 1 << xtal_div_tbl[dividx];
++      ddr_clk = fb * xtal_clk / xtal_div;
++
++      regmap_read(memc, MEMPLL1_REG, &bs);
++      if (!FIELD_GET(RG_MEPL_DIV2_SEL, bs))
++              ddr_clk *= 2;
++
++      priv->cpu_clk = cpu_clk;
++      priv->sys_clk = cpu_clk / 4;
++      priv->ddr_clk = ddr_clk;
++      priv->xtal_clk = xtal_clk;
++}
++
++static int mt7621_clk_probe(struct udevice *dev)
++{
++      struct mt7621_clk_priv *priv = dev_get_priv(dev);
++      struct ofnode_phandle_args args;
++      struct udevice *pdev;
++      struct regmap *memc;
++      int ret;
++
++      pdev = dev_get_parent(dev);
++      if (!pdev)
++              return -ENODEV;
++
++      priv->sysc_base = dev_remap_addr(pdev);
++      if (!priv->sysc_base)
++              return -EINVAL;
++
++      /* get corresponding memc phandle */
++      ret = dev_read_phandle_with_args(dev, "mediatek,memc", NULL, 0, 0,
++                                       &args);
++      if (ret)
++              return ret;
++
++      memc = syscon_node_to_regmap(args.node);
++      if (IS_ERR(memc))
++              return PTR_ERR(memc);
++
++      mt7621_get_clocks(priv, memc);
++
++      return 0;
++}
++
++static const struct udevice_id mt7621_clk_ids[] = {
++      { .compatible = "mediatek,mt7621-clk" },
++      { }
++};
++
++U_BOOT_DRIVER(mt7621_clk) = {
++      .name = "mt7621-clk",
++      .id = UCLASS_CLK,
++      .of_match = mt7621_clk_ids,
++      .probe = mt7621_clk_probe,
++      .priv_auto = sizeof(struct mt7621_clk_priv),
++      .ops = &mt7621_clk_ops,
++};
+diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h
+new file mode 100644
+index 0000000000..978c67951b
+--- /dev/null
++++ b/include/dt-bindings/clock/mt7621-clk.h
+@@ -0,0 +1,46 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _DT_BINDINGS_MT7621_CLK_H_
++#define _DT_BINDINGS_MT7621_CLK_H_
++
++#define MT7621_CLK_XTAL               0
++#define MT7621_CLK_CPU                1
++#define MT7621_CLK_BUS                2
++#define MT7621_CLK_50M                3
++#define MT7621_CLK_125M               4
++#define MT7621_CLK_150M               5
++#define MT7621_CLK_250M               6
++#define MT7621_CLK_270M               7
++
++#define MT7621_CLK_HSDMA      8
++#define MT7621_CLK_FE         9
++#define MT7621_CLK_SP_DIVTX   10
++#define MT7621_CLK_TIMER      11
++#define MT7621_CLK_PCM                12
++#define MT7621_CLK_PIO                13
++#define MT7621_CLK_GDMA               14
++#define MT7621_CLK_NAND               15
++#define MT7621_CLK_I2C                16
++#define MT7621_CLK_I2S                17
++#define MT7621_CLK_SPI                18
++#define MT7621_CLK_UART1      19
++#define MT7621_CLK_UART2      20
++#define MT7621_CLK_UART3      21
++#define MT7621_CLK_ETH                22
++#define MT7621_CLK_PCIE0      23
++#define MT7621_CLK_PCIE1      24
++#define MT7621_CLK_PCIE2      25
++#define MT7621_CLK_CRYPTO     26
++#define MT7621_CLK_SHXC               27
++
++#define MT7621_CLK_MAX                28
++
++/* for u-boot only */
++#define MT7621_CLK_DDR                29
++
++#endif /* _DT_BINDINGS_MT7621_CLK_H_ */
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0009-reset-mtmips-add-reset-controller-support-for-MediaT.patch b/package/boot/uboot-mediatek/patches/001-mtk-0009-reset-mtmips-add-reset-controller-support-for-MediaT.patch
new file mode 100644 (file)
index 0000000..a6f61a6
--- /dev/null
@@ -0,0 +1,62 @@
+From 03035a6566300808c8845799b2f9ceca471aa61a Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:41 +0800
+Subject: [PATCH 09/25] reset: mtmips: add reset controller support for
+ MediaTek MT7621 SoC
+
+This patch adds reset controller bits definition header file for MediaTek
+MT7621 SoC
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ include/dt-bindings/reset/mt7621-reset.h | 38 ++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+ create mode 100644 include/dt-bindings/reset/mt7621-reset.h
+
+diff --git a/include/dt-bindings/reset/mt7621-reset.h b/include/dt-bindings/reset/mt7621-reset.h
+new file mode 100644
+index 0000000000..8e4341f040
+--- /dev/null
++++ b/include/dt-bindings/reset/mt7621-reset.h
+@@ -0,0 +1,38 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _DT_BINDINGS_MT7621_RESET_H_
++#define _DT_BINDINGS_MT7621_RESET_H_
++
++#define RST_PPE                       31
++#define RST_SDXC              30
++#define RST_CRYPTO            29
++#define RST_AUX_STCK          28
++#define RST_PCIE2             26
++#define RST_PCIE1             25
++#define RST_PCIE0             24
++#define RST_GMAC              23
++#define RST_UART3             21
++#define RST_UART2             20
++#define RST_UART1             19
++#define RST_SPI                       18
++#define RST_I2S                       17
++#define RST_I2C                       16
++#define RST_NFI                       15
++#define RST_GDMA              14
++#define RST_PIO                       13
++#define RST_PCM                       11
++#define RST_MC                        10
++#define RST_INTC              9
++#define RST_TIMER             8
++#define RST_SPDIFTX           7
++#define RST_FE                        6
++#define RST_HSDMA             5
++#define RST_MCM                       2
++#define RST_SYS                       0
++
++#endif /* _DT_BINDINGS_MT7621_RESET_H_ */
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0010-pinctrl-mtmips-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0010-pinctrl-mtmips-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..8bafc86
--- /dev/null
@@ -0,0 +1,409 @@
+From 3cf9e2daca330a0ba89d3793ceb09037c788db46 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:49 +0800
+Subject: [PATCH 10/25] pinctrl: mtmips: add support for MediaTek MT7621 SoC
+
+This patch adds pinctrl support for MediaTek MT7621 SoC.
+The MT7621 SoC supports pinconf, but it is not the same as mt7628.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/pinctrl/mtmips/Kconfig                |   9 +
+ drivers/pinctrl/mtmips/Makefile               |   1 +
+ drivers/pinctrl/mtmips/pinctrl-mt7621.c       | 306 ++++++++++++++++++
+ .../pinctrl/mtmips/pinctrl-mtmips-common.c    |   4 +-
+ .../pinctrl/mtmips/pinctrl-mtmips-common.h    |  12 +
+ 5 files changed, 330 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/pinctrl/mtmips/pinctrl-mt7621.c
+
+diff --git a/drivers/pinctrl/mtmips/Kconfig b/drivers/pinctrl/mtmips/Kconfig
+index 844d5b743f..456f3ea25d 100644
+--- a/drivers/pinctrl/mtmips/Kconfig
++++ b/drivers/pinctrl/mtmips/Kconfig
+@@ -12,6 +12,15 @@ config PINCTRL_MT7620
+         The driver is controlled by a device tree node which contains
+         the pin mux functions for each available pin groups.
++config PINCTRL_MT7621
++      bool "MediaTek MT7621 pin control driver"
++      select PINCTRL_MTMIPS
++      depends on SOC_MT7621 && PINCTRL_GENERIC
++      help
++        Support pin multiplexing control on MediaTek MT7621.
++        The driver is controlled by a device tree node which contains
++        the pin mux functions for each available pin groups.
++
+ config PINCTRL_MT7628
+       bool "MediaTek MT7628 pin control driver"
+       select PINCTRL_MTMIPS
+diff --git a/drivers/pinctrl/mtmips/Makefile b/drivers/pinctrl/mtmips/Makefile
+index ba945a89a7..8fece4f5fa 100644
+--- a/drivers/pinctrl/mtmips/Makefile
++++ b/drivers/pinctrl/mtmips/Makefile
+@@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_MTMIPS) += pinctrl-mtmips-common.o
+ # SoC Drivers
+ obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o
++obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o
+ obj-$(CONFIG_PINCTRL_MT7628) += pinctrl-mt7628.o
+diff --git a/drivers/pinctrl/mtmips/pinctrl-mt7621.c b/drivers/pinctrl/mtmips/pinctrl-mt7621.c
+new file mode 100644
+index 0000000000..3e98a01bad
+--- /dev/null
++++ b/drivers/pinctrl/mtmips/pinctrl-mt7621.c
+@@ -0,0 +1,306 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <dm.h>
++#include <dm/pinctrl.h>
++#include <dm/device_compat.h>
++#include <linux/bitops.h>
++#include <linux/io.h>
++
++#include "pinctrl-mtmips-common.h"
++
++#define SYSC_MAP_SIZE                 0x100
++
++#define PAD_UART1_GPIO0_OFS           0x00
++#define PAD_UART3_I2C_OFS             0x04
++#define PAD_UART2_JTAG_OFS            0x08
++#define PAD_PERST_WDT_OFS             0x0c
++#define PAD_RGMII2_MDIO_OFS           0x10
++#define PAD_SDXC_SPI_OFS              0x14
++#define GPIOMODE_OFS                  0x18
++#define PAD_BOPT_ESWINT_OFS           0x28
++
++#define ESWINT_SHIFT                  20
++#define SDXC_SHIFT                    18
++#define SPI_SHIFT                     16
++#define RGMII2_SHIFT                  15
++#define RGMII1_SHIFT                  14
++#define MDIO_SHIFT                    12
++#define PERST_SHIFT                   10
++#define WDT_SHIFT                     8
++#define JTAG_SHIFT                    7
++#define UART2_SHIFT                   5
++#define UART3_SHIFT                   3
++#define I2C_SHIFT                     2
++#define UART1_SHIFT                   1
++#define GPIO0_SHIFT                   0 /* Dummy */
++
++#define GM4_MASK                      3
++
++#define E4_E2_M                               0x03
++#define E4_E2_S                               4
++#define PULL_UP                               BIT(3)
++#define PULL_DOWN                     BIT(2)
++#define SMT                           BIT(1)
++#define SR                            BIT(0)
++
++struct mt7621_pinctrl_priv {
++      struct mtmips_pinctrl_priv mp;
++};
++
++#if CONFIG_IS_ENABLED(PINMUX)
++static const struct mtmips_pmx_func esw_int_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("esw int", 0),
++};
++
++static const struct mtmips_pmx_func sdxc_grp[] = {
++      FUNC("nand", 2),
++      FUNC("gpio", 1),
++      FUNC("sdxc", 0),
++};
++
++static const struct mtmips_pmx_func spi_grp[] = {
++      FUNC("nand", 2),
++      FUNC("gpio", 1),
++      FUNC("spi", 0),
++};
++
++static const struct mtmips_pmx_func rgmii2_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("rgmii", 0),
++};
++
++static const struct mtmips_pmx_func rgmii1_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("rgmii", 0),
++};
++
++static const struct mtmips_pmx_func mdio_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("mdio", 0),
++};
++
++static const struct mtmips_pmx_func perst_grp[] = {
++      FUNC("refclk", 2),
++      FUNC("gpio", 1),
++      FUNC("pcie reset", 0),
++};
++
++static const struct mtmips_pmx_func wdt_grp[] = {
++      FUNC("refclk", 2),
++      FUNC("gpio", 1),
++      FUNC("wdt rst", 0),
++};
++
++static const struct mtmips_pmx_func jtag_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("jtag", 0),
++};
++
++static const struct mtmips_pmx_func uart2_grp[] = {
++      FUNC("spdif", 3),
++      FUNC("pcm", 2),
++      FUNC("gpio", 1),
++      FUNC("uart", 0),
++};
++
++static const struct mtmips_pmx_func uart3_grp[] = {
++      FUNC("spdif", 3),
++      FUNC("i2s", 2),
++      FUNC("gpio", 1),
++      FUNC("uart", 0),
++};
++
++static const struct mtmips_pmx_func i2c_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("i2c", 0),
++};
++
++static const struct mtmips_pmx_func uart1_grp[] = {
++      FUNC("gpio", 1),
++      FUNC("uart", 0),
++};
++
++static const struct mtmips_pmx_func gpio0_grp[] = {
++      FUNC("gpio", 0),
++};
++
++static const struct mtmips_pmx_group mt7621_pmx_data[] = {
++      GRP_PCONF("esw int", esw_int_grp, GPIOMODE_OFS, ESWINT_SHIFT, 1,
++                PAD_BOPT_ESWINT_OFS, 0),
++      GRP_PCONF("sdxc", sdxc_grp, GPIOMODE_OFS, SDXC_SHIFT, GM4_MASK,
++                PAD_SDXC_SPI_OFS, 16),
++      GRP_PCONF("spi", spi_grp, GPIOMODE_OFS, SPI_SHIFT, GM4_MASK,
++                PAD_SDXC_SPI_OFS, 0),
++      GRP_PCONF("rgmii2", rgmii2_grp, GPIOMODE_OFS, RGMII2_SHIFT, 1,
++                PAD_RGMII2_MDIO_OFS, 16),
++      GRP("rgmii1", rgmii1_grp, GPIOMODE_OFS, RGMII1_SHIFT, 1),
++      GRP_PCONF("mdio", mdio_grp, GPIOMODE_OFS, MDIO_SHIFT, GM4_MASK,
++                PAD_RGMII2_MDIO_OFS, 0),
++      GRP_PCONF("pcie reset", perst_grp, GPIOMODE_OFS, PERST_SHIFT, GM4_MASK,
++                PAD_PERST_WDT_OFS, 16),
++      GRP_PCONF("wdt", wdt_grp, GPIOMODE_OFS, WDT_SHIFT, GM4_MASK,
++                PAD_PERST_WDT_OFS, 0),
++      GRP_PCONF("jtag", jtag_grp, GPIOMODE_OFS, JTAG_SHIFT, 1,
++                PAD_UART2_JTAG_OFS, 16),
++      GRP_PCONF("uart2", uart2_grp, GPIOMODE_OFS, UART2_SHIFT, GM4_MASK,
++                PAD_UART2_JTAG_OFS, 0),
++      GRP_PCONF("uart3", uart3_grp, GPIOMODE_OFS, UART3_SHIFT, GM4_MASK,
++                PAD_UART3_I2C_OFS, 16),
++      GRP_PCONF("i2c", i2c_grp, GPIOMODE_OFS, I2C_SHIFT, 1,
++                PAD_UART3_I2C_OFS, 0),
++      GRP_PCONF("uart1", uart1_grp, GPIOMODE_OFS, UART1_SHIFT, 1,
++                PAD_UART1_GPIO0_OFS, 16),
++      GRP_PCONF("gpio0", gpio0_grp, GPIOMODE_OFS, GPIO0_SHIFT, 1,
++                PAD_UART1_GPIO0_OFS, 0),
++};
++
++static int mt7621_get_groups_count(struct udevice *dev)
++{
++      return ARRAY_SIZE(mt7621_pmx_data);
++}
++
++static const char *mt7621_get_group_name(struct udevice *dev,
++                                       unsigned int selector)
++{
++      return mt7621_pmx_data[selector].name;
++}
++#endif /* CONFIG_IS_ENABLED(PINMUX) */
++
++#if CONFIG_IS_ENABLED(PINCONF)
++static const struct pinconf_param mt7621_conf_params[] = {
++      { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
++      { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
++      { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
++      { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
++      { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
++      { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
++      { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
++};
++
++static const u32 mt7621_pconf_drv_strength_tbl[] = {2, 4, 6, 8};
++
++static int mt7621_pinconf_group_set(struct udevice *dev,
++                                  unsigned int group_selector,
++                                  unsigned int param, unsigned int arg)
++{
++      struct mt7621_pinctrl_priv *priv = dev_get_priv(dev);
++      const struct mtmips_pmx_group *grp = &mt7621_pmx_data[group_selector];
++      u32 clr = 0, set = 0;
++      int i;
++
++      if (!grp->pconf_avail)
++              return 0;
++
++      switch (param) {
++      case PIN_CONFIG_BIAS_DISABLE:
++              clr = PULL_UP | PULL_DOWN;
++              break;
++
++      case PIN_CONFIG_BIAS_PULL_UP:
++              clr = PULL_DOWN;
++              set = PULL_UP;
++              break;
++
++      case PIN_CONFIG_BIAS_PULL_DOWN:
++              clr = PULL_UP;
++              set = PULL_DOWN;
++              break;
++
++      case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
++              if (arg)
++                      set = SMT;
++              else
++                      clr = SMT;
++              break;
++
++      case PIN_CONFIG_DRIVE_STRENGTH:
++              for (i = 0; i < ARRAY_SIZE(mt7621_pconf_drv_strength_tbl); i++)
++                      if (mt7621_pconf_drv_strength_tbl[i] == arg)
++                              break;
++
++              if (i >= ARRAY_SIZE(mt7621_pconf_drv_strength_tbl))
++                      return -EINVAL;
++
++              clr = E4_E2_M << E4_E2_S;
++              set = i << E4_E2_S;
++              break;
++
++      case PIN_CONFIG_SLEW_RATE:
++              if (arg)
++                      set = SR;
++              else
++                      clr = SR;
++              break;
++
++      default:
++              return -EINVAL;
++      }
++
++      mtmips_pinctrl_reg_set(&priv->mp, grp->pconf_reg, grp->pconf_shift,
++                             clr, set);
++
++      return 0;
++}
++#endif
++
++static int mt7621_pinctrl_probe(struct udevice *dev)
++{
++      struct mt7621_pinctrl_priv *priv = dev_get_priv(dev);
++      int ret = 0;
++
++#if CONFIG_IS_ENABLED(PINMUX)
++      ret = mtmips_pinctrl_probe(&priv->mp, ARRAY_SIZE(mt7621_pmx_data),
++                                 mt7621_pmx_data);
++#endif /* CONFIG_IS_ENABLED(PINMUX) */
++
++      return ret;
++}
++
++static int mt7621_pinctrl_of_to_plat(struct udevice *dev)
++{
++      struct mt7621_pinctrl_priv *priv = dev_get_priv(dev);
++
++      priv->mp.base = (void __iomem *)dev_remap_addr_index(dev, 0);
++
++      if (!priv->mp.base)
++              return -EINVAL;
++
++      return 0;
++}
++
++static const struct pinctrl_ops mt7621_pinctrl_ops = {
++#if CONFIG_IS_ENABLED(PINMUX)
++      .get_groups_count = mt7621_get_groups_count,
++      .get_group_name = mt7621_get_group_name,
++      .get_functions_count = mtmips_get_functions_count,
++      .get_function_name = mtmips_get_function_name,
++      .pinmux_group_set = mtmips_pinmux_group_set,
++#endif /* CONFIG_IS_ENABLED(PINMUX) */
++#if CONFIG_IS_ENABLED(PINCONF)
++      .pinconf_num_params = ARRAY_SIZE(mt7621_conf_params),
++      .pinconf_params = mt7621_conf_params,
++      .pinconf_group_set = mt7621_pinconf_group_set,
++#endif /* CONFIG_IS_ENABLED(PINCONF) */
++      .set_state = pinctrl_generic_set_state,
++};
++
++static const struct udevice_id mt7621_pinctrl_ids[] = {
++      { .compatible = "mediatek,mt7621-pinctrl" },
++      { }
++};
++
++U_BOOT_DRIVER(mt7621_pinctrl) = {
++      .name = "mt7621-pinctrl",
++      .id = UCLASS_PINCTRL,
++      .of_match = mt7621_pinctrl_ids,
++      .of_to_plat = mt7621_pinctrl_of_to_plat,
++      .ops = &mt7621_pinctrl_ops,
++      .probe = mt7621_pinctrl_probe,
++      .priv_auto = sizeof(struct mt7621_pinctrl_priv),
++};
+diff --git a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c
+index e361916eb2..869b781068 100644
+--- a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c
++++ b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c
+@@ -13,8 +13,8 @@
+ #include "pinctrl-mtmips-common.h"
+-static void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv,
+-                                 u32 reg, u32 shift, u32 mask, u32 value)
++void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv,
++                          u32 reg, u32 shift, u32 mask, u32 value)
+ {
+       u32 val;
+diff --git a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h
+index b51d8f009c..1f1023ef42 100644
+--- a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h
++++ b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h
+@@ -22,6 +22,10 @@ struct mtmips_pmx_group {
+       u32 shift;
+       char mask;
++      int pconf_avail;
++      u32 pconf_reg;
++      u32 pconf_shift;
++
+       int nfuncs;
+       const struct mtmips_pmx_func *funcs;
+ };
+@@ -42,6 +46,14 @@ struct mtmips_pinctrl_priv {
+       { .name = (_name), .reg = (_reg), .shift = (_shift), .mask = (_mask), \
+         .funcs = (_funcs), .nfuncs = ARRAY_SIZE(_funcs) }
++#define GRP_PCONF(_name, _funcs, _reg, _shift, _mask, _pconf_reg, _pconf_shift) \
++      { .name = (_name), .reg = (_reg), .shift = (_shift), .mask = (_mask), \
++        .funcs = (_funcs), .nfuncs = ARRAY_SIZE(_funcs), .pconf_avail = 1, \
++        .pconf_reg = (_pconf_reg), .pconf_shift = (_pconf_shift) }
++
++void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv,
++                          u32 reg, u32 shift, u32 mask, u32 value);
++
+ int mtmips_get_functions_count(struct udevice *dev);
+ const char *mtmips_get_function_name(struct udevice *dev,
+                                    unsigned int selector);
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0011-usb-xhci-mtk-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0011-usb-xhci-mtk-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..e917166
--- /dev/null
@@ -0,0 +1,28 @@
+From ab59bb14a0efd40c12a967f73bd08ba2f27da3be Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:22:56 +0800
+Subject: [PATCH 11/25] usb: xhci-mtk: add support for MediaTek MT7621 SoC
+
+This patch makes xhci-mtk driver available for MediaTek MT7621 SoC
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/usb/host/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 8f77412cc7..8f7bfe1602 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -34,7 +34,7 @@ config USB_XHCI_DWC3_OF_SIMPLE
+ config USB_XHCI_MTK
+       bool "Support for MediaTek on-chip xHCI USB controller"
+-      depends on ARCH_MEDIATEK
++      depends on ARCH_MEDIATEK || SOC_MT7621
+       help
+         Enables support for the on-chip xHCI controller on MediaTek SoCs.
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0012-phy-mtk-tphy-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0012-phy-mtk-tphy-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..6d7adbc
--- /dev/null
@@ -0,0 +1,28 @@
+From 23c19fa476929b6e94cc7f1a55f5ed4d3ab03934 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:01 +0800
+Subject: [PATCH 12/25] phy: mtk-tphy: add support for MediaTek MT7621 SoC
+
+This patch makes mtk-tphy driver available for MediaTek MT7621 SoC
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/phy/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
+index c01d9e09b9..1708d4f533 100644
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -266,7 +266,7 @@ config MT76X8_USB_PHY
+ config PHY_MTK_TPHY
+       bool "MediaTek T-PHY Driver"
+       depends on PHY
+-      depends on ARCH_MEDIATEK
++      depends on ARCH_MEDIATEK || SOC_MT7621
+       help
+         MediaTek T-PHY driver supports usb2.0, usb3.0 ports, PCIe and
+         SATA, and meanwhile supports two version T-PHY which have
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0013-spi-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0013-spi-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..f20fe91
--- /dev/null
@@ -0,0 +1,28 @@
+From 34b623ccfd135e846b8464729a8b0e8df4b77a66 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:08 +0800
+Subject: [PATCH 13/25] spi: add support for MediaTek MT7621 SoC
+
+This patch makes mt7621_spi driver available for MediaTek MT7621 SoC
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/spi/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index a1e515cb2b..2923ed8db3 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -240,7 +240,7 @@ config MT7620_SPI
+ config MT7621_SPI
+       bool "MediaTek MT7621 SPI driver"
+-      depends on SOC_MT7628
++      depends on SOC_MT7621 || SOC_MT7628
+       help
+         Enable the MT7621 SPI driver. This driver can be used to access
+         the SPI NOR flash on platforms embedding this Ralink / MediaTek
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0014-gpio-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0014-gpio-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..c2bff6e
--- /dev/null
@@ -0,0 +1,29 @@
+From f265423a441a3bcb51e25238544adb69f74becc7 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:14 +0800
+Subject: [PATCH 14/25] gpio: add support for MediaTek MT7621 SoC
+
+This patch makes mt7621_gpio driver available for MediaTek MT7621 SoC
+
+Reviewed-by: Stefan Roese <sr@denx.de>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/gpio/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index d7f37f0471..8f7e630098 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -553,7 +553,7 @@ config MT7620_GPIO
+ config MT7621_GPIO
+       bool "MediaTek MT7621 GPIO driver"
+-      depends on DM_GPIO && SOC_MT7628
++      depends on DM_GPIO && (SOC_MT7621 || SOC_MT7628)
+       default y
+       help
+         Say yes here to support MediaTek MT7621 compatible GPIOs.
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0015-watchdog-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0015-watchdog-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..c24c835
--- /dev/null
@@ -0,0 +1,29 @@
+From eb1806fbf65c60b2ce462a0ebe39d9f9e652235a Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:19 +0800
+Subject: [PATCH 15/25] watchdog: add support for MediaTek MT7621 SoC
+
+This patch makes mt7621_wdt driver available for MediaTek MT7621 SoC
+
+Reviewed-by: Stefan Roese <sr@denx.de>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/watchdog/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index c3eb8a8aec..dfb02aa468 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -191,7 +191,7 @@ config WDT_MT7620
+ config WDT_MT7621
+       bool "MediaTek MT7621 watchdog timer support"
+-      depends on WDT && SOC_MT7628
++      depends on WDT && (SOC_MT7621 || SOC_MT7628)
+       help
+         Select this to enable Ralink / Mediatek watchdog timer,
+         which can be found on some MediaTek chips.
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0016-mmc-mediatek-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0016-mmc-mediatek-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..c21b625
--- /dev/null
@@ -0,0 +1,47 @@
+From 4339ec44313e85dd1f6d3d708dd2e594855ce25d Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:26 +0800
+Subject: [PATCH 16/25] mmc: mediatek: add support for MediaTek MT7621 SoC
+
+This patch adds SDXC support for MediaTek MT7621 SoC
+
+Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/mmc/mtk-sd.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
+index 97182ffd7f..e61e8cf4b9 100644
+--- a/drivers/mmc/mtk-sd.c
++++ b/drivers/mmc/mtk-sd.c
+@@ -1761,6 +1761,18 @@ static const struct msdc_compatible mt7620_compat = {
+       .default_pad_dly = true,
+ };
++static const struct msdc_compatible mt7621_compat = {
++      .clk_div_bits = 8,
++      .pad_tune0 = false,
++      .async_fifo = true,
++      .data_tune = true,
++      .busy_check = false,
++      .stop_clk_fix = false,
++      .enhance_rx = false,
++      .builtin_pad_ctrl = true,
++      .default_pad_dly = true,
++};
++
+ static const struct msdc_compatible mt7622_compat = {
+       .clk_div_bits = 12,
+       .pad_tune0 = true,
+@@ -1809,6 +1821,7 @@ static const struct msdc_compatible mt8183_compat = {
+ static const struct udevice_id msdc_ids[] = {
+       { .compatible = "mediatek,mt7620-mmc", .data = (ulong)&mt7620_compat },
++      { .compatible = "mediatek,mt7621-mmc", .data = (ulong)&mt7621_compat },
+       { .compatible = "mediatek,mt7622-mmc", .data = (ulong)&mt7622_compat },
+       { .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat },
+       { .compatible = "mediatek,mt8512-mmc", .data = (ulong)&mt8512_compat },
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0017-net-mediatek-remap-iobase-address.patch b/package/boot/uboot-mediatek/patches/001-mtk-0017-net-mediatek-remap-iobase-address.patch
new file mode 100644 (file)
index 0000000..72b3849
--- /dev/null
@@ -0,0 +1,38 @@
+From 391785398f61c85e6b55b1e9edbab94e3ba1b783 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:31 +0800
+Subject: [PATCH 17/25] net: mediatek: remap iobase address
+
+The iobase address from dts node is actually physical address. It's
+identical to the virtual address in ARM platform. This is ok because this
+driver was used only by ARM platforms (mt7622/mt7623 ...).
+
+But now this driver will be used by mt7621 which is a MIPS SoC. For MIPS
+platform the physical address space is mapped to KSEG0 and KSEG1 and this
+makes the virtual address apparently not idential to its physical address.
+
+To solve this issue, this patch replaces dev_read_addr with dev_remap_addr
+to get the remapped iobase address.
+
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
+index 666ddeb10d..caa83b7cec 100644
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1419,7 +1419,7 @@ static int mtk_eth_of_to_plat(struct udevice *dev)
+       priv->soc = dev_get_driver_data(dev);
+-      pdata->iobase = dev_read_addr(dev);
++      pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
+       /* get corresponding ethsys phandle */
+       ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0018-net-mediatek-use-regmap-api-to-modify-ethsys-registe.patch b/package/boot/uboot-mediatek/patches/001-mtk-0018-net-mediatek-use-regmap-api-to-modify-ethsys-registe.patch
new file mode 100644 (file)
index 0000000..ab5c2a7
--- /dev/null
@@ -0,0 +1,72 @@
+From 955cc76d8074df943d59d559895007f91de8eed5 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:37 +0800
+Subject: [PATCH 18/25] net: mediatek: use regmap api to modify ethsys
+ registers
+
+The address returned by regmap_get_range() is not remapped. Directly r/w
+to this address is ok for ARM platforms since it's idential to the virtual
+address.
+
+But for MIPS platform only virtual address should be used for access.
+To solve this issue, the regmap api regmap_read/regmap_write should be used
+since they will remap address before accessing.
+
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
+index caa83b7cec..ac1e8abd71 100644
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -159,9 +159,10 @@ struct mtk_eth_priv {
+       void __iomem *fe_base;
+       void __iomem *gmac_base;
+-      void __iomem *ethsys_base;
+       void __iomem *sgmii_base;
++      struct regmap *ethsys_regmap;
++
+       struct mii_dev *mdio_bus;
+       int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg);
+       int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val);
+@@ -233,7 +234,12 @@ static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+ static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+                          u32 set)
+ {
+-      clrsetbits_le32(priv->ethsys_base + reg, clr, set);
++      uint val;
++
++      regmap_read(priv->ethsys_regmap, reg, &val);
++      val &= ~clr;
++      val |= set;
++      regmap_write(priv->ethsys_regmap, reg, val);
+ }
+ /* Direct MDIO clause 22/45 access via SoC */
+@@ -1427,15 +1433,9 @@ static int mtk_eth_of_to_plat(struct udevice *dev)
+       if (ret)
+               return ret;
+-      regmap = syscon_node_to_regmap(args.node);
+-      if (IS_ERR(regmap))
+-              return PTR_ERR(regmap);
+-
+-      priv->ethsys_base = regmap_get_range(regmap, 0);
+-      if (!priv->ethsys_base) {
+-              dev_err(dev, "Unable to find ethsys\n");
+-              return -ENODEV;
+-      }
++      priv->ethsys_regmap = syscon_node_to_regmap(args.node);
++      if (IS_ERR(priv->ethsys_regmap))
++              return PTR_ERR(priv->ethsys_regmap);
+       /* Reset controllers */
+       ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0019-net-mediatek-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0019-net-mediatek-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..ce087fe
--- /dev/null
@@ -0,0 +1,72 @@
+From 7237a6a0c020c05bb819774391154b40b2cfaabd Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:42 +0800
+Subject: [PATCH 19/25] net: mediatek: add support for MediaTek MT7621 SoC
+
+This patch adds GMAC support for MediaTek MT7621 SoC.
+MT7621 has the same GMAC/Switch configuration as MT7623.
+
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
+index ac1e8abd71..4fe7ee0d36 100644
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -145,7 +145,8 @@ enum mtk_switch {
+ enum mtk_soc {
+       SOC_MT7623,
+       SOC_MT7629,
+-      SOC_MT7622
++      SOC_MT7622,
++      SOC_MT7621
+ };
+ struct mtk_eth_priv {
+@@ -675,12 +676,18 @@ static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode)
+ static int mt7530_setup(struct mtk_eth_priv *priv)
+ {
+       u16 phy_addr, phy_val;
+-      u32 val;
++      u32 val, txdrv;
+       int i;
+-      /* Select 250MHz clk for RGMII mode */
+-      mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
+-                     ETHSYS_TRGMII_CLK_SEL362_5, 0);
++      if (priv->soc != SOC_MT7621) {
++              /* Select 250MHz clk for RGMII mode */
++              mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
++                             ETHSYS_TRGMII_CLK_SEL362_5, 0);
++
++              txdrv = 8;
++      } else {
++              txdrv = 4;
++      }
+       /* Modify HWTRAP first to allow direct access to internal PHYs */
+       mt753x_reg_read(priv, HWTRAP_REG, &val);
+@@ -738,7 +745,8 @@ static int mt7530_setup(struct mtk_eth_priv *priv)
+       /* Lower Tx Driving for TRGMII path */
+       for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
+               mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
+-                               (8 << TD_DM_DRVP_S) | (8 << TD_DM_DRVN_S));
++                               (txdrv << TD_DM_DRVP_S) |
++                               (txdrv << TD_DM_DRVN_S));
+       for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+               mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
+@@ -1540,6 +1548,7 @@ static const struct udevice_id mtk_eth_ids[] = {
+       { .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 },
+       { .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 },
+       { .compatible = "mediatek,mt7622-eth", .data = SOC_MT7622 },
++      { .compatible = "mediatek,mt7621-eth", .data = SOC_MT7621 },
+       {}
+ };
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0020-nand-raw-add-support-for-MediaTek-MT7621-SoC.patch b/package/boot/uboot-mediatek/patches/001-mtk-0020-nand-raw-add-support-for-MediaTek-MT7621-SoC.patch
new file mode 100644 (file)
index 0000000..1644468
--- /dev/null
@@ -0,0 +1,1572 @@
+From 8d94833f13ccd7e1dfea605cfdf9a8eb53505515 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:47 +0800
+Subject: [PATCH 20/25] nand: raw: add support for MediaTek MT7621 SoC
+
+This patch adds NAND flash controller driver for MediaTek MT7621 SoC.
+The NAND flash controller of MT7621 supports only SLC NAND flashes.
+It supports 4~12 bits correction with maximum 4KB page size.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/mtd/nand/raw/Kconfig           |   17 +-
+ drivers/mtd/nand/raw/Makefile          |    2 +
+ drivers/mtd/nand/raw/mt7621_nand.c     | 1205 ++++++++++++++++++++++++
+ drivers/mtd/nand/raw/mt7621_nand.h     |   29 +
+ drivers/mtd/nand/raw/mt7621_nand_spl.c |  237 +++++
+ 5 files changed, 1488 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c
+ create mode 100644 drivers/mtd/nand/raw/mt7621_nand.h
+ create mode 100644 drivers/mtd/nand/raw/mt7621_nand_spl.c
+
+diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
+index d75f371c95..1663f1941c 100644
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -521,12 +521,25 @@ config TEGRA_NAND
+       help
+         Enables support for NAND Flash chips on Tegra SoCs platforms.
++config NAND_MT7621
++      bool "Support for MediaTek MT7621 NAND flash controller"
++      depends on SOC_MT7621
++      select SYS_NAND_SELF_INIT
++      select SPL_SYS_NAND_SELF_INIT
++      imply CMD_NAND
++      help
++        This enables NAND driver for the NAND flash controller on MediaTek
++        MT7621 platform.
++        The controller supports 4~12 bits correction per 512 bytes with a
++        maximum 4KB page size.
++
+ comment "Generic NAND options"
+ config SYS_NAND_BLOCK_SIZE
+       hex "NAND chip eraseblock size"
+       depends on ARCH_SUNXI || SPL_NAND_SUPPORT || TPL_NAND_SUPPORT
+-      depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_FSL_IFC
++      depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && \
++              !NAND_FSL_IFC && !NAND_MT7621
+       help
+         Number of data bytes in one eraseblock for the NAND chip on the
+         board. This is the multiple of NAND_PAGE_SIZE and the number of
+@@ -551,7 +564,7 @@ config SYS_NAND_PAGE_SIZE
+       depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \
+               SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \
+               (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER
+-      depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC
++      depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621
+       help
+         Number of data bytes in one page for the NAND chip on the
+         board, not including the OOB area.
+diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
+index 6ec3581d20..cfc9c0fff0 100644
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -72,6 +72,7 @@ obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
+ obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o
+ obj-$(CONFIG_CORTINA_NAND) += cortina_nand.o
+ obj-$(CONFIG_ROCKCHIP_NAND) += rockchip_nfc.o
++obj-$(CONFIG_NAND_MT7621) += mt7621_nand.o
+ else  # minimal SPL drivers
+@@ -80,5 +81,6 @@ obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
+ obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
+ obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
+ obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
++obj-$(CONFIG_NAND_MT7621) += mt7621_nand_spl.o mt7621_nand.o
+ endif # drivers
+diff --git a/drivers/mtd/nand/raw/mt7621_nand.c b/drivers/mtd/nand/raw/mt7621_nand.c
+new file mode 100644
+index 0000000000..2fd8934939
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mt7621_nand.c
+@@ -0,0 +1,1205 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <log.h>
++#include <nand.h>
++#include <malloc.h>
++#include <asm/addrspace.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/sizes.h>
++#include <linux/bitops.h>
++#include <linux/bitfield.h>
++#include "mt7621_nand.h"
++
++/* NFI core registers */
++#define NFI_CNFG                      0x000
++#define   CNFG_OP_MODE                        GENMASK(14, 12)
++#define     CNFG_OP_CUSTOM            6
++#define   CNFG_AUTO_FMT_EN            BIT(9)
++#define   CNFG_HW_ECC_EN              BIT(8)
++#define   CNFG_BYTE_RW                        BIT(6)
++#define   CNFG_READ_MODE              BIT(1)
++
++#define NFI_PAGEFMT                   0x004
++#define   PAGEFMT_FDM_ECC             GENMASK(15, 12)
++#define   PAGEFMT_FDM                 GENMASK(11, 8)
++#define   PAGEFMT_SPARE                       GENMASK(5, 4)
++#define   PAGEFMT_PAGE                        GENMASK(1, 0)
++
++#define NFI_CON                               0x008
++#define   CON_NFI_SEC                 GENMASK(15, 12)
++#define   CON_NFI_BWR                 BIT(9)
++#define   CON_NFI_BRD                 BIT(8)
++#define   CON_NFI_RST                 BIT(1)
++#define   CON_FIFO_FLUSH              BIT(0)
++
++#define NFI_ACCCON                    0x00c
++#define   ACCCON_POECS                        GENMASK(31, 28)
++#define   ACCCON_POECS_DEF            3
++#define   ACCCON_PRECS                        GENMASK(27, 22)
++#define   ACCCON_PRECS_DEF            3
++#define   ACCCON_C2R                  GENMASK(21, 16)
++#define   ACCCON_C2R_DEF              7
++#define   ACCCON_W2R                  GENMASK(15, 12)
++#define   ACCCON_W2R_DEF              7
++#define   ACCCON_WH                   GENMASK(11, 8)
++#define   ACCCON_WH_DEF                       15
++#define   ACCCON_WST                  GENMASK(7, 4)
++#define   ACCCON_WST_DEF              15
++#define   ACCCON_WST_MIN              3
++#define   ACCCON_RLT                  GENMASK(3, 0)
++#define   ACCCON_RLT_DEF              15
++#define   ACCCON_RLT_MIN              3
++
++#define NFI_CMD                               0x020
++
++#define NFI_ADDRNOB                   0x030
++#define   ADDR_ROW_NOB                        GENMASK(6, 4)
++#define   ADDR_COL_NOB                        GENMASK(2, 0)
++
++#define NFI_COLADDR                   0x034
++#define NFI_ROWADDR                   0x038
++
++#define NFI_STRDATA                   0x040
++#define   STR_DATA                    BIT(0)
++
++#define NFI_CNRNB                     0x044
++#define   CB2R_TIME                   GENMASK(7, 4)
++#define   STR_CNRNB                   BIT(0)
++
++#define NFI_DATAW                     0x050
++#define NFI_DATAR                     0x054
++
++#define NFI_PIO_DIRDY                 0x058
++#define   PIO_DIRDY                   BIT(0)
++
++#define NFI_STA                               0x060
++#define   STA_NFI_FSM                 GENMASK(19, 16)
++#define     STA_FSM_CUSTOM_DATA               14
++#define   STA_BUSY                    BIT(8)
++#define   STA_ADDR                    BIT(1)
++#define   STA_CMD                     BIT(0)
++
++#define NFI_ADDRCNTR                  0x070
++#define   SEC_CNTR                    GENMASK(15, 12)
++#define   SEC_ADDR                    GENMASK(9, 0)
++
++#define NFI_CSEL                      0x090
++#define   CSEL                                GENMASK(1, 0)
++
++#define NFI_FDM0L                     0x0a0
++#define NFI_FDML(n)                   (0x0a0 + ((n) << 3))
++
++#define NFI_FDM0M                     0x0a4
++#define NFI_FDMM(n)                   (0x0a4 + ((n) << 3))
++
++#define NFI_MASTER_STA                        0x210
++#define   MAS_ADDR                    GENMASK(11, 9)
++#define   MAS_RD                      GENMASK(8, 6)
++#define   MAS_WR                      GENMASK(5, 3)
++#define   MAS_RDDLY                   GENMASK(2, 0)
++
++/* ECC engine registers */
++#define ECC_ENCCON                    0x000
++#define   ENC_EN                      BIT(0)
++
++#define ECC_ENCCNFG                   0x004
++#define   ENC_CNFG_MSG                        GENMASK(28, 16)
++#define   ENC_MODE                    GENMASK(5, 4)
++#define     ENC_MODE_NFI              1
++#define   ENC_TNUM                    GENMASK(2, 0)
++
++#define ECC_ENCIDLE                   0x00c
++#define   ENC_IDLE                    BIT(0)
++
++#define ECC_DECCON                    0x100
++#define   DEC_EN                      BIT(0)
++
++#define ECC_DECCNFG                   0x104
++#define   DEC_EMPTY_EN                        BIT(31)
++#define   DEC_CS                      GENMASK(28, 16)
++#define   DEC_CON                     GENMASK(13, 12)
++#define     DEC_CON_EL                        2
++#define   DEC_MODE                    GENMASK(5, 4)
++#define     DEC_MODE_NFI              1
++#define   DEC_TNUM                    GENMASK(2, 0)
++
++#define ECC_DECIDLE                   0x10c
++#define   DEC_IDLE                    BIT(1)
++
++#define ECC_DECENUM                   0x114
++#define   ERRNUM_S                    2
++#define   ERRNUM_M                    GENMASK(3, 0)
++
++#define ECC_DECDONE                   0x118
++#define   DEC_DONE7                   BIT(7)
++#define   DEC_DONE6                   BIT(6)
++#define   DEC_DONE5                   BIT(5)
++#define   DEC_DONE4                   BIT(4)
++#define   DEC_DONE3                   BIT(3)
++#define   DEC_DONE2                   BIT(2)
++#define   DEC_DONE1                   BIT(1)
++#define   DEC_DONE0                   BIT(0)
++
++#define ECC_DECEL(n)                  (0x11c + (n) * 4)
++#define   DEC_EL_ODD_S                        16
++#define   DEC_EL_M                    0x1fff
++#define   DEC_EL_BYTE_POS_S           3
++#define   DEC_EL_BIT_POS_M            GENMASK(2, 0)
++
++#define ECC_FDMADDR                   0x13c
++
++/* ENCIDLE and DECIDLE */
++#define   ECC_IDLE                    BIT(0)
++
++#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
++      (FIELD_PREP(ACCCON_POECS, tpoecs) | \
++       FIELD_PREP(ACCCON_PRECS, tprecs) | \
++       FIELD_PREP(ACCCON_C2R, tc2r) | \
++       FIELD_PREP(ACCCON_W2R, tw2r) | \
++       FIELD_PREP(ACCCON_WH, twh) | \
++       FIELD_PREP(ACCCON_WST, twst) | \
++       FIELD_PREP(ACCCON_RLT, trlt))
++
++#define MASTER_STA_MASK                       (MAS_ADDR | MAS_RD | MAS_WR | \
++                                       MAS_RDDLY)
++#define NFI_RESET_TIMEOUT             1000000
++#define NFI_CORE_TIMEOUT              500000
++#define ECC_ENGINE_TIMEOUT            500000
++
++#define ECC_SECTOR_SIZE                       512
++#define ECC_PARITY_BITS                       13
++
++#define NFI_FDM_SIZE                  8
++
++/* Register base */
++#define NFI_BASE                      0x1e003000
++#define NFI_ECC_BASE                  0x1e003800
++
++static struct mt7621_nfc nfc_dev;
++
++static const u16 mt7621_nfi_page_size[] = { SZ_512, SZ_2K, SZ_4K };
++static const u8 mt7621_nfi_spare_size[] = { 16, 26, 27, 28 };
++static const u8 mt7621_ecc_strength[] = { 4, 6, 8, 10, 12 };
++
++static inline u32 nfi_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readl(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++      writel(val, nfc->nfi_regs + reg);
++}
++
++static inline u16 nfi_read16(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readw(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++      writew(val, nfc->nfi_regs + reg);
++}
++
++static inline void ecc_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++      writew(val, nfc->ecc_regs + reg);
++}
++
++static inline u32 ecc_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readl(nfc->ecc_regs + reg);
++}
++
++static inline void ecc_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++      return writel(val, nfc->ecc_regs + reg);
++}
++
++static inline u8 *oob_fdm_ptr(struct nand_chip *nand, int sect)
++{
++      return nand->oob_poi + sect * NFI_FDM_SIZE;
++}
++
++static inline u8 *oob_ecc_ptr(struct mt7621_nfc *nfc, int sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++
++      return nand->oob_poi + nand->ecc.steps * NFI_FDM_SIZE +
++              sect * (nfc->spare_per_sector - NFI_FDM_SIZE);
++}
++
++static inline u8 *page_data_ptr(struct nand_chip *nand, const u8 *buf,
++                              int sect)
++{
++      return (u8 *)buf + sect * nand->ecc.size;
++}
++
++static int mt7621_ecc_wait_idle(struct mt7621_nfc *nfc, u32 reg)
++{
++      u32 val;
++      int ret;
++
++      ret = readw_poll_timeout(nfc->ecc_regs + reg, val, val & ECC_IDLE,
++                               ECC_ENGINE_TIMEOUT);
++      if (ret) {
++              pr_warn("ECC engine timed out entering idle mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt7621_ecc_decoder_wait_done(struct mt7621_nfc *nfc, u32 sect)
++{
++      u32 val;
++      int ret;
++
++      ret = readw_poll_timeout(nfc->ecc_regs + ECC_DECDONE, val,
++                               val & (1 << sect), ECC_ENGINE_TIMEOUT);
++      if (ret) {
++              pr_warn("ECC decoder for sector %d timed out\n", sect);
++              return -ETIMEDOUT;
++      }
++
++      return 0;
++}
++
++static void mt7621_ecc_encoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++      mt7621_ecc_wait_idle(nfc, ECC_ENCIDLE);
++      ecc_write16(nfc, ECC_ENCCON, enable ? ENC_EN : 0);
++}
++
++static void mt7621_ecc_decoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++      mt7621_ecc_wait_idle(nfc, ECC_DECIDLE);
++      ecc_write16(nfc, ECC_DECCON, enable ? DEC_EN : 0);
++}
++
++static int mt7621_ecc_correct_check(struct mt7621_nfc *nfc, u8 *sector_buf,
++                                  u8 *fdm_buf, u32 sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 decnum, num_error_bits, fdm_end_bits;
++      u32 error_locations, error_bit_loc;
++      u32 error_byte_pos, error_bit_pos;
++      int bitflips = 0;
++      u32 i;
++
++      decnum = ecc_read32(nfc, ECC_DECENUM);
++      num_error_bits = (decnum >> (sect << ERRNUM_S)) & ERRNUM_M;
++      fdm_end_bits = (nand->ecc.size + NFI_FDM_SIZE) << 3;
++
++      if (!num_error_bits)
++              return 0;
++
++      if (num_error_bits == ERRNUM_M)
++              return -1;
++
++      for (i = 0; i < num_error_bits; i++) {
++              error_locations = ecc_read32(nfc, ECC_DECEL(i / 2));
++              error_bit_loc = (error_locations >> ((i % 2) * DEC_EL_ODD_S)) &
++                              DEC_EL_M;
++              error_byte_pos = error_bit_loc >> DEC_EL_BYTE_POS_S;
++              error_bit_pos = error_bit_loc & DEC_EL_BIT_POS_M;
++
++              if (error_bit_loc < (nand->ecc.size << 3)) {
++                      if (sector_buf) {
++                              sector_buf[error_byte_pos] ^=
++                                      (1 << error_bit_pos);
++                      }
++              } else if (error_bit_loc < fdm_end_bits) {
++                      if (fdm_buf) {
++                              fdm_buf[error_byte_pos - nand->ecc.size] ^=
++                                      (1 << error_bit_pos);
++                      }
++              }
++
++              bitflips++;
++      }
++
++      return bitflips;
++}
++
++static int mt7621_nfc_wait_write_completion(struct mt7621_nfc *nfc,
++                                          struct nand_chip *nand)
++{
++      u16 val;
++      int ret;
++
++      ret = readw_poll_timeout(nfc->nfi_regs + NFI_ADDRCNTR, val,
++                               FIELD_GET(SEC_CNTR, val) >= nand->ecc.steps,
++                               NFI_CORE_TIMEOUT);
++
++      if (ret) {
++              pr_warn("NFI core write operation timed out\n");
++              return -ETIMEDOUT;
++      }
++
++      return ret;
++}
++
++static void mt7621_nfc_hw_reset(struct mt7621_nfc *nfc)
++{
++      u32 val;
++      int ret;
++
++      /* reset all registers and force the NFI master to terminate */
++      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++
++      /* wait for the master to finish the last transaction */
++      ret = readw_poll_timeout(nfc->nfi_regs + NFI_MASTER_STA, val,
++                               !(val & MASTER_STA_MASK), NFI_RESET_TIMEOUT);
++      if (ret) {
++              pr_warn("Failed to reset NFI master in %dms\n",
++                      NFI_RESET_TIMEOUT);
++      }
++
++      /* ensure any status register affected by the NFI master is reset */
++      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++      nfi_write16(nfc, NFI_STRDATA, 0);
++}
++
++static inline void mt7621_nfc_hw_init(struct mt7621_nfc *nfc)
++{
++      u32 acccon;
++
++      /*
++       * CNRNB: nand ready/busy register
++       * -------------------------------
++       * 7:4: timeout register for polling the NAND busy/ready signal
++       * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
++       */
++      nfi_write16(nfc, NFI_CNRNB, CB2R_TIME | STR_CNRNB);
++
++      mt7621_nfc_hw_reset(nfc);
++
++      /* Apply default access timing */
++      acccon = ACCTIMING(ACCCON_POECS_DEF, ACCCON_PRECS_DEF, ACCCON_C2R_DEF,
++                         ACCCON_W2R_DEF, ACCCON_WH_DEF, ACCCON_WST_DEF,
++                         ACCCON_RLT_DEF);
++
++      nfi_write32(nfc, NFI_ACCCON, acccon);
++}
++
++static int mt7621_nfc_send_command(struct mt7621_nfc *nfc, u8 command)
++{
++      u32 val;
++      int ret;
++
++      nfi_write32(nfc, NFI_CMD, command);
++
++      ret = readl_poll_timeout(nfc->nfi_regs + NFI_STA, val, !(val & STA_CMD),
++                               NFI_CORE_TIMEOUT);
++      if (ret) {
++              pr_warn("NFI core timed out entering command mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt7621_nfc_send_address_byte(struct mt7621_nfc *nfc, int addr)
++{
++      u32 val;
++      int ret;
++
++      nfi_write32(nfc, NFI_COLADDR, addr);
++      nfi_write32(nfc, NFI_ROWADDR, 0);
++      nfi_write16(nfc, NFI_ADDRNOB, 1);
++
++      ret = readl_poll_timeout(nfc->nfi_regs + NFI_STA, val,
++                               !(val & STA_ADDR), NFI_CORE_TIMEOUT);
++      if (ret) {
++              pr_warn("NFI core timed out entering address mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static void mt7621_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
++                              unsigned int ctrl)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      if (ctrl & NAND_ALE) {
++              mt7621_nfc_send_address_byte(nfc, dat & 0xff);
++      } else if (ctrl & NAND_CLE) {
++              mt7621_nfc_hw_reset(nfc);
++              nfi_write16(nfc, NFI_CNFG,
++                          FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM));
++              mt7621_nfc_send_command(nfc, dat);
++      }
++}
++
++static int mt7621_nfc_dev_ready(struct mtd_info *mtd)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      if (nfi_read32(nfc, NFI_STA) & STA_BUSY)
++              return 0;
++
++      return 1;
++}
++
++static void mt7621_nfc_select_chip(struct mtd_info *mtd, int chipnr)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      nfi_write16(nfc, NFI_CSEL, 0);
++}
++
++static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc)
++{
++      int ret;
++      u16 val;
++
++      ret = readw_poll_timeout(nfc->nfi_regs + NFI_PIO_DIRDY, val,
++                               val & PIO_DIRDY, NFI_CORE_TIMEOUT);
++      if (ret < 0)
++              pr_err("NFI core PIO mode not ready\n");
++}
++
++static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br)
++{
++      u32 reg, fsm;
++
++      /* after each byte read, the NFI_STA reg is reset by the hardware */
++      reg = nfi_read32(nfc, NFI_STA);
++      fsm = FIELD_GET(STA_NFI_FSM, reg);
++
++      if (fsm != STA_FSM_CUSTOM_DATA) {
++              reg = nfi_read16(nfc, NFI_CNFG);
++              reg |= CNFG_READ_MODE | CNFG_BYTE_RW;
++              if (!br)
++                      reg &= ~CNFG_BYTE_RW;
++              nfi_write16(nfc, NFI_CNFG, reg);
++
++              /*
++               * set to max sector to allow the HW to continue reading over
++               * unaligned accesses
++               */
++              nfi_write16(nfc, NFI_CON, CON_NFI_SEC | CON_NFI_BRD);
++
++              /* trigger to fetch data */
++              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++      }
++
++      mt7621_nfc_wait_pio_ready(nfc);
++
++      return nfi_read32(nfc, NFI_DATAR);
++}
++
++static void mt7621_nfc_read_data(struct mt7621_nfc *nfc, u8 *buf, u32 len)
++{
++      while (((uintptr_t)buf & 3) && len) {
++              *buf = mt7621_nfc_pio_read(nfc, true);
++              buf++;
++              len--;
++      }
++
++      while (len >= 4) {
++              *(u32 *)buf = mt7621_nfc_pio_read(nfc, false);
++              buf += 4;
++              len -= 4;
++      }
++
++      while (len) {
++              *buf = mt7621_nfc_pio_read(nfc, true);
++              buf++;
++              len--;
++      }
++}
++
++static void mt7621_nfc_read_data_discard(struct mt7621_nfc *nfc, u32 len)
++{
++      while (len >= 4) {
++              mt7621_nfc_pio_read(nfc, false);
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_read(nfc, true);
++              len--;
++      }
++}
++
++static void mt7621_nfc_pio_write(struct mt7621_nfc *nfc, u32 val, bool bw)
++{
++      u32 reg, fsm;
++
++      reg = nfi_read32(nfc, NFI_STA);
++      fsm = FIELD_GET(STA_NFI_FSM, reg);
++
++      if (fsm != STA_FSM_CUSTOM_DATA) {
++              reg = nfi_read16(nfc, NFI_CNFG);
++              reg &= ~(CNFG_READ_MODE | CNFG_BYTE_RW);
++              if (bw)
++                      reg |= CNFG_BYTE_RW;
++              nfi_write16(nfc, NFI_CNFG, reg);
++
++              nfi_write16(nfc, NFI_CON, CON_NFI_SEC | CON_NFI_BWR);
++              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++      }
++
++      mt7621_nfc_wait_pio_ready(nfc);
++      nfi_write32(nfc, NFI_DATAW, val);
++}
++
++static void mt7621_nfc_write_data(struct mt7621_nfc *nfc, const u8 *buf,
++                                u32 len)
++{
++      while (((uintptr_t)buf & 3) && len) {
++              mt7621_nfc_pio_write(nfc, *buf, true);
++              buf++;
++              len--;
++      }
++
++      while (len >= 4) {
++              mt7621_nfc_pio_write(nfc, *(const u32 *)buf, false);
++              buf += 4;
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_write(nfc, *buf, true);
++              buf++;
++              len--;
++      }
++}
++
++static void mt7621_nfc_write_data_empty(struct mt7621_nfc *nfc, u32 len)
++{
++      while (len >= 4) {
++              mt7621_nfc_pio_write(nfc, 0xffffffff, false);
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_write(nfc, 0xff, true);
++              len--;
++      }
++}
++
++static void mt7621_nfc_write_byte(struct mtd_info *mtd, u8 byte)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      mt7621_nfc_pio_write(nfc, byte, true);
++}
++
++static void mt7621_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      return mt7621_nfc_write_data(nfc, buf, len);
++}
++
++static u8 mt7621_nfc_read_byte(struct mtd_info *mtd)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      return mt7621_nfc_pio_read(nfc, true);
++}
++
++static void mt7621_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++      mt7621_nfc_read_data(nfc, buf, len);
++}
++
++static int mt7621_nfc_calc_ecc_strength(struct mt7621_nfc *nfc,
++                                      u32 avail_ecc_bytes)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 strength;
++      int i;
++
++      strength = avail_ecc_bytes * 8 / ECC_PARITY_BITS;
++
++      /* Find the closest supported ecc strength */
++      for (i = ARRAY_SIZE(mt7621_ecc_strength) - 1; i >= 0; i--) {
++              if (mt7621_ecc_strength[i] <= strength)
++                      break;
++      }
++
++      if (unlikely(i < 0)) {
++              pr_err("OOB size (%u) is not supported\n", mtd->oobsize);
++              return -EINVAL;
++      }
++
++      nand->ecc.strength = mt7621_ecc_strength[i];
++      nand->ecc.bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++      pr_debug("ECC strength adjusted to %u bits\n", nand->ecc.strength);
++
++      return i;
++}
++
++static int mt7621_nfc_set_spare_per_sector(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 size;
++      int i;
++
++      size = nand->ecc.bytes + NFI_FDM_SIZE;
++
++      /* Find the closest supported spare size */
++      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_spare_size); i++) {
++              if (mt7621_nfi_spare_size[i] >= size)
++                      break;
++      }
++
++      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_spare_size))) {
++              pr_err("OOB size (%u) is not supported\n", mtd->oobsize);
++              return -EINVAL;
++      }
++
++      nfc->spare_per_sector = mt7621_nfi_spare_size[i];
++
++      return i;
++}
++
++static int mt7621_nfc_ecc_init(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 avail_ecc_bytes, encode_block_size, decode_block_size;
++      u32 ecc_enccfg, ecc_deccfg;
++      int ecc_cap;
++
++      nand->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
++
++      nand->ecc.size = ECC_SECTOR_SIZE;
++      nand->ecc.steps = mtd->writesize / nand->ecc.size;
++
++      avail_ecc_bytes = mtd->oobsize / nand->ecc.steps - NFI_FDM_SIZE;
++
++      ecc_cap = mt7621_nfc_calc_ecc_strength(nfc, avail_ecc_bytes);
++      if (ecc_cap < 0)
++              return ecc_cap;
++
++      /* Sector + FDM */
++      encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8;
++      ecc_enccfg = ecc_cap | FIELD_PREP(ENC_MODE, ENC_MODE_NFI) |
++                   FIELD_PREP(ENC_CNFG_MSG, encode_block_size);
++
++      /* Sector + FDM + ECC parity bits */
++      decode_block_size = ((nand->ecc.size + NFI_FDM_SIZE) * 8) +
++                          nand->ecc.strength * ECC_PARITY_BITS;
++      ecc_deccfg = ecc_cap | FIELD_PREP(DEC_MODE, DEC_MODE_NFI) |
++                   FIELD_PREP(DEC_CS, decode_block_size) |
++                   FIELD_PREP(DEC_CON, DEC_CON_EL) | DEC_EMPTY_EN;
++
++      mt7621_ecc_encoder_op(nfc, false);
++      ecc_write32(nfc, ECC_ENCCNFG, ecc_enccfg);
++
++      mt7621_ecc_decoder_op(nfc, false);
++      ecc_write32(nfc, ECC_DECCNFG, ecc_deccfg);
++
++      return 0;
++}
++
++static int mt7621_nfc_set_page_format(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      int i, spare_size;
++      u32 pagefmt;
++
++      spare_size = mt7621_nfc_set_spare_per_sector(nfc);
++      if (spare_size < 0)
++              return spare_size;
++
++      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_page_size); i++) {
++              if (mt7621_nfi_page_size[i] == mtd->writesize)
++                      break;
++      }
++
++      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_page_size))) {
++              pr_err("Page size (%u) is not supported\n", mtd->writesize);
++              return -EINVAL;
++      }
++
++      pagefmt = FIELD_PREP(PAGEFMT_PAGE, i) |
++                FIELD_PREP(PAGEFMT_SPARE, spare_size) |
++                FIELD_PREP(PAGEFMT_FDM, NFI_FDM_SIZE) |
++                FIELD_PREP(PAGEFMT_FDM_ECC, NFI_FDM_SIZE);
++
++      nfi_write16(nfc, NFI_PAGEFMT, pagefmt);
++
++      return 0;
++}
++
++static int mt7621_nfc_attach_chip(struct nand_chip *nand)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int ret;
++
++      if (nand->options & NAND_BUSWIDTH_16) {
++              pr_err("16-bit buswidth is not supported");
++              return -EINVAL;
++      }
++
++      ret = mt7621_nfc_ecc_init(nfc);
++      if (ret)
++              return ret;
++
++      return mt7621_nfc_set_page_format(nfc);
++}
++
++static void mt7621_nfc_write_fdm(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 vall, valm;
++      u8 *oobptr;
++      int i, j;
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              vall = 0;
++              valm = 0;
++              oobptr = oob_fdm_ptr(nand, i);
++
++              for (j = 0; j < 4; j++)
++                      vall |= (u32)oobptr[j] << (j * 8);
++
++              for (j = 0; j < 4; j++)
++                      valm |= (u32)oobptr[j + 4] << (j * 8);
++
++              nfi_write32(nfc, NFI_FDML(i), vall);
++              nfi_write32(nfc, NFI_FDMM(i), valm);
++      }
++}
++
++static void mt7621_nfc_read_sector_fdm(struct mt7621_nfc *nfc, u32 sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 vall, valm;
++      u8 *oobptr;
++      int i;
++
++      vall = nfi_read32(nfc, NFI_FDML(sect));
++      valm = nfi_read32(nfc, NFI_FDMM(sect));
++      oobptr = oob_fdm_ptr(nand, sect);
++
++      for (i = 0; i < 4; i++)
++              oobptr[i] = (vall >> (i * 8)) & 0xff;
++
++      for (i = 0; i < 4; i++)
++              oobptr[i + 4] = (valm >> (i * 8)) & 0xff;
++}
++
++static int mt7621_nfc_read_page_hwecc(struct mtd_info *mtd,
++                                    struct nand_chip *nand, uint8_t *buf,
++                                    int oob_required, int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int bitflips = 0, ret = 0;
++      int rc, i;
++
++      nand_read_page_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) |
++                  CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++      mt7621_ecc_decoder_op(nfc, true);
++
++      nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) |
++                  CON_NFI_BRD);
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              if (buf)
++                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++                                           nand->ecc.size);
++              else
++                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++              rc = mt7621_ecc_decoder_wait_done(nfc, i);
++
++              mt7621_nfc_read_sector_fdm(nfc, i);
++
++              if (rc < 0) {
++                      ret = -EIO;
++                      continue;
++              }
++
++              rc = mt7621_ecc_correct_check(nfc,
++                      buf ? page_data_ptr(nand, buf, i) : NULL,
++                      oob_fdm_ptr(nand, i), i);
++
++              if (rc < 0) {
++                      pr_warn("Uncorrectable ECC error at page %d step %d\n",
++                              page, i);
++                      bitflips = nand->ecc.strength + 1;
++                      mtd->ecc_stats.failed++;
++              } else {
++                      if (rc > bitflips)
++                              bitflips = rc;
++                      mtd->ecc_stats.corrected += rc;
++              }
++      }
++
++      mt7621_ecc_decoder_op(nfc, false);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      if (ret < 0)
++              return ret;
++
++      return bitflips;
++}
++
++static int mt7621_nfc_read_page_raw(struct mtd_info *mtd,
++                                  struct nand_chip *nand, uint8_t *buf,
++                                  int oob_required, int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int i;
++
++      nand_read_page_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) |
++                  CNFG_READ_MODE);
++
++      nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) |
++                  CON_NFI_BRD);
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              /* Read data */
++              if (buf)
++                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++                                           nand->ecc.size);
++              else
++                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++              /* Read FDM */
++              mt7621_nfc_read_data(nfc, oob_fdm_ptr(nand, i), NFI_FDM_SIZE);
++
++              /* Read ECC parity data */
++              mt7621_nfc_read_data(nfc, oob_ecc_ptr(nfc, i),
++                                   nfc->spare_per_sector - NFI_FDM_SIZE);
++      }
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return 0;
++}
++
++static int mt7621_nfc_read_oob_hwecc(struct mtd_info *mtd,
++                                   struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_read_page_hwecc(mtd, nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_read_oob_raw(struct mtd_info *mtd,
++                                 struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_read_page_raw(mtd, nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_check_empty_page(struct nand_chip *nand, const u8 *buf)
++{
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u8 *oobptr;
++      u32 i, j;
++
++      if (buf) {
++              for (i = 0; i < mtd->writesize; i++)
++                      if (buf[i] != 0xff)
++                              return 0;
++      }
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              oobptr = oob_fdm_ptr(nand, i);
++              for (j = 0; j < NFI_FDM_SIZE; j++)
++                      if (oobptr[j] != 0xff)
++                              return 0;
++      }
++
++      return 1;
++}
++
++static int mt7621_nfc_write_page_hwecc(struct mtd_info *mtd,
++                                     struct nand_chip *nand,
++                                     const u8 *buf, int oob_required,
++                                     int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++
++      if (mt7621_nfc_check_empty_page(nand, buf)) {
++              /*
++               * MT7621 ECC engine always generates parity code for input
++               * pages, even for empty pages. Doing so will write back ECC
++               * parity code to the oob region, which means such pages will
++               * no longer be empty pages.
++               *
++               * To avoid this, stop write operation if current page is an
++               * empty page.
++               */
++              return 0;
++      }
++
++      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) |
++                  CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++      mt7621_ecc_encoder_op(nfc, true);
++
++      mt7621_nfc_write_fdm(nfc);
++
++      nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) |
++                  CON_NFI_BWR);
++
++      if (buf)
++              mt7621_nfc_write_data(nfc, buf, mtd->writesize);
++      else
++              mt7621_nfc_write_data_empty(nfc, mtd->writesize);
++
++      mt7621_nfc_wait_write_completion(nfc, nand);
++
++      mt7621_ecc_encoder_op(nfc, false);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_page_raw(struct mtd_info *mtd,
++                                   struct nand_chip *nand,
++                                   const u8 *buf, int oob_required,
++                                   int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int i;
++
++      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM));
++
++      nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) |
++                  CON_NFI_BWR);
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              /* Write data */
++              if (buf)
++                      mt7621_nfc_write_data(nfc, page_data_ptr(nand, buf, i),
++                                            nand->ecc.size);
++              else
++                      mt7621_nfc_write_data_empty(nfc, nand->ecc.size);
++
++              /* Write FDM */
++              mt7621_nfc_write_data(nfc, oob_fdm_ptr(nand, i),
++                                    NFI_FDM_SIZE);
++
++              /* Write dummy ECC parity data */
++              mt7621_nfc_write_data_empty(nfc, nfc->spare_per_sector -
++                                          NFI_FDM_SIZE);
++      }
++
++      mt7621_nfc_wait_write_completion(nfc, nand);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_oob_hwecc(struct mtd_info *mtd,
++                                    struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_write_page_hwecc(mtd, nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_write_oob_raw(struct mtd_info *mtd,
++                                  struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_write_page_raw(mtd, nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++                                   struct mtd_oob_region *oob_region)
++{
++      struct nand_chip *nand = mtd_to_nand(mtd);
++
++      if (section >= nand->ecc.steps)
++              return -ERANGE;
++
++      oob_region->length = NFI_FDM_SIZE - 1;
++      oob_region->offset = section * NFI_FDM_SIZE + 1;
++
++      return 0;
++}
++
++static int mt7621_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                  struct mtd_oob_region *oob_region)
++{
++      struct nand_chip *nand = mtd_to_nand(mtd);
++
++      if (section)
++              return -ERANGE;
++
++      oob_region->offset = NFI_FDM_SIZE * nand->ecc.steps;
++      oob_region->length = mtd->oobsize - oob_region->offset;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops mt7621_nfc_ooblayout_ops = {
++      .rfree = mt7621_nfc_ooblayout_free,
++      .ecc = mt7621_nfc_ooblayout_ecc,
++};
++
++/*
++ * This function will override the default one which is not supposed to be
++ * used for ECC syndrome based pages.
++ */
++static int mt7621_nfc_block_bad(struct mtd_info *mtd, loff_t ofs)
++{
++      struct nand_chip *nand = mtd_to_nand(mtd);
++      struct mtd_oob_ops ops;
++      int ret, i = 0;
++      u16 bad;
++
++      memset(&ops, 0, sizeof(ops));
++      ops.oobbuf = (uint8_t *)&bad;
++      ops.ooboffs = nand->badblockpos;
++      if (nand->options & NAND_BUSWIDTH_16) {
++              ops.ooboffs &= ~0x01;
++              ops.ooblen = 2;
++      } else {
++              ops.ooblen = 1;
++      }
++      ops.mode = MTD_OPS_RAW;
++
++      /* Read from first/last page(s) if necessary */
++      if (nand->bbt_options & NAND_BBT_SCANLASTPAGE)
++              ofs += mtd->erasesize - mtd->writesize;
++
++      do {
++              ret = mtd_read_oob(mtd, ofs, &ops);
++              if (ret)
++                      return ret;
++
++              if (likely(nand->badblockbits == 8))
++                      ret = bad != 0xFF;
++              else
++                      ret = hweight8(bad) < nand->badblockbits;
++
++              i++;
++              ofs += mtd->writesize;
++      } while (!ret && (nand->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
++
++      return ret;
++}
++
++static void mt7621_nfc_init_chip(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd;
++      int ret;
++
++      nand_set_controller_data(nand, nfc);
++
++      nand->options |= NAND_NO_SUBPAGE_WRITE;
++
++      nand->ecc.mode = NAND_ECC_HW_SYNDROME;
++      nand->ecc.read_page = mt7621_nfc_read_page_hwecc;
++      nand->ecc.read_page_raw = mt7621_nfc_read_page_raw;
++      nand->ecc.write_page = mt7621_nfc_write_page_hwecc;
++      nand->ecc.write_page_raw = mt7621_nfc_write_page_raw;
++      nand->ecc.read_oob = mt7621_nfc_read_oob_hwecc;
++      nand->ecc.read_oob_raw = mt7621_nfc_read_oob_raw;
++      nand->ecc.write_oob = mt7621_nfc_write_oob_hwecc;
++      nand->ecc.write_oob_raw = mt7621_nfc_write_oob_raw;
++
++      nand->dev_ready = mt7621_nfc_dev_ready;
++      nand->select_chip = mt7621_nfc_select_chip;
++      nand->write_byte = mt7621_nfc_write_byte;
++      nand->write_buf = mt7621_nfc_write_buf;
++      nand->read_byte = mt7621_nfc_read_byte;
++      nand->read_buf = mt7621_nfc_read_buf;
++      nand->cmd_ctrl = mt7621_nfc_cmd_ctrl;
++      nand->block_bad = mt7621_nfc_block_bad;
++
++      mtd = nand_to_mtd(nand);
++      mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops);
++
++      /* Reset NFI master */
++      mt7621_nfc_hw_init(nfc);
++
++      ret = nand_scan_ident(mtd, 1, NULL);
++      if (ret)
++              return;
++
++      mt7621_nfc_attach_chip(nand);
++
++      ret = nand_scan_tail(mtd);
++      if (ret)
++              return;
++
++      nand_register(0, mtd);
++}
++
++static void mt7621_nfc_set_regs(struct mt7621_nfc *nfc)
++{
++      nfc->nfi_regs = (void __iomem *)CKSEG1ADDR(NFI_BASE);
++      nfc->ecc_regs = (void __iomem *)CKSEG1ADDR(NFI_ECC_BASE);
++}
++
++void mt7621_nfc_spl_init(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++
++      mt7621_nfc_set_regs(nfc);
++
++      nand_set_controller_data(nand, nfc);
++
++      nand->options |= NAND_NO_SUBPAGE_WRITE;
++
++      nand->ecc.mode = NAND_ECC_HW_SYNDROME;
++      nand->ecc.read_page = mt7621_nfc_read_page_hwecc;
++
++      nand->dev_ready = mt7621_nfc_dev_ready;
++      nand->select_chip = mt7621_nfc_select_chip;
++      nand->read_byte = mt7621_nfc_read_byte;
++      nand->read_buf = mt7621_nfc_read_buf;
++      nand->cmd_ctrl = mt7621_nfc_cmd_ctrl;
++
++      /* Reset NFI master */
++      mt7621_nfc_hw_init(nfc);
++}
++
++int mt7621_nfc_spl_post_init(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      int nand_maf_id, nand_dev_id;
++      struct nand_flash_dev *type;
++
++      type = nand_get_flash_type(&nand->mtd, nand, &nand_maf_id,
++                                 &nand_dev_id, NULL);
++
++      if (IS_ERR(type))
++              return PTR_ERR(type);
++
++      nand->numchips = 1;
++      nand->mtd.size = nand->chipsize;
++
++      return mt7621_nfc_attach_chip(nand);
++}
++
++void board_nand_init(void)
++{
++      mt7621_nfc_set_regs(&nfc_dev);
++      mt7621_nfc_init_chip(&nfc_dev);
++}
+diff --git a/drivers/mtd/nand/raw/mt7621_nand.h b/drivers/mtd/nand/raw/mt7621_nand.h
+new file mode 100644
+index 0000000000..af4bc55961
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mt7621_nand.h
+@@ -0,0 +1,29 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _MT7621_NAND_H_
++#define _MT7621_NAND_H_
++
++#include <linux/types.h>
++#include <linux/mtd/mtd.h>
++#include <linux/compiler.h>
++#include <linux/mtd/rawnand.h>
++
++struct mt7621_nfc {
++      struct nand_chip nand;
++
++      void __iomem *nfi_regs;
++      void __iomem *ecc_regs;
++
++      u32 spare_per_sector;
++};
++
++/* for SPL */
++void mt7621_nfc_spl_init(struct mt7621_nfc *nfc);
++int mt7621_nfc_spl_post_init(struct mt7621_nfc *nfc);
++
++#endif /* _MT7621_NAND_H_ */
+diff --git a/drivers/mtd/nand/raw/mt7621_nand_spl.c b/drivers/mtd/nand/raw/mt7621_nand_spl.c
+new file mode 100644
+index 0000000000..114fc8b7ce
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mt7621_nand_spl.c
+@@ -0,0 +1,237 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <image.h>
++#include <malloc.h>
++#include <linux/sizes.h>
++#include <linux/delay.h>
++#include <linux/mtd/rawnand.h>
++#include "mt7621_nand.h"
++
++static struct mt7621_nfc nfc_dev;
++static u8 *buffer;
++static int nand_valid;
++
++static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
++                          int column, int page_addr)
++{
++      register struct nand_chip *chip = mtd_to_nand(mtd);
++
++      /* Command latch cycle */
++      chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
++
++      if (column != -1 || page_addr != -1) {
++              int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
++
++              /* Serially input address */
++              if (column != -1) {
++                      chip->cmd_ctrl(mtd, column, ctrl);
++                      ctrl &= ~NAND_CTRL_CHANGE;
++                      if (command != NAND_CMD_READID)
++                              chip->cmd_ctrl(mtd, column >> 8, ctrl);
++              }
++              if (page_addr != -1) {
++                      chip->cmd_ctrl(mtd, page_addr, ctrl);
++                      chip->cmd_ctrl(mtd, page_addr >> 8,
++                                     NAND_NCE | NAND_ALE);
++                      if (chip->options & NAND_ROW_ADDR_3)
++                              chip->cmd_ctrl(mtd, page_addr >> 16,
++                                             NAND_NCE | NAND_ALE);
++              }
++      }
++      chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++
++      /*
++       * Program and erase have their own busy handlers status, sequential
++       * in and status need no delay.
++       */
++      switch (command) {
++      case NAND_CMD_STATUS:
++      case NAND_CMD_READID:
++      case NAND_CMD_SET_FEATURES:
++              return;
++
++      case NAND_CMD_READ0:
++              chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
++                             NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
++              chip->cmd_ctrl(mtd, NAND_CMD_NONE,
++                             NAND_NCE | NAND_CTRL_CHANGE);
++      }
++
++      /*
++       * Apply this short delay always to ensure that we do wait tWB in
++       * any case on any machine.
++       */
++      ndelay(100);
++
++      nand_wait_ready(mtd);
++}
++
++static int nfc_read_page_hwecc(struct mtd_info *mtd, void *buf,
++                             unsigned int page)
++{
++      struct nand_chip *chip = mtd_to_nand(mtd);
++      int ret;
++
++      chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
++
++      ret = chip->ecc.read_page(mtd, chip, buf, 1, page);
++      if (ret < 0 || ret > chip->ecc.strength)
++              return -1;
++
++      return 0;
++}
++
++static int nfc_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len,
++                            unsigned int page)
++{
++      struct nand_chip *chip = mtd_to_nand(mtd);
++      int ret;
++
++      chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
++
++      ret = chip->ecc.read_page(mtd, chip, NULL, 1, page);
++      if (ret < 0)
++              return -1;
++
++      if (len > mtd->oobsize)
++              len = mtd->oobsize;
++
++      memcpy(buf, chip->oob_poi, len);
++
++      return 0;
++}
++
++static int nfc_check_bad_block(struct mtd_info *mtd, unsigned int page)
++{
++      struct nand_chip *chip = mtd_to_nand(mtd);
++      u32 pages_per_block, i = 0;
++      int ret;
++      u8 bad;
++
++      pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift);
++
++      /* Read from first/last page(s) if necessary */
++      if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) {
++              page += pages_per_block - 1;
++              if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)
++                      page--;
++      }
++
++      do {
++              ret = nfc_read_oob_hwecc(mtd, &bad, 1, page);
++              if (ret)
++                      return ret;
++
++              ret = bad != 0xFF;
++
++              i++;
++              page++;
++      } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
++
++      return ret;
++}
++
++int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
++{
++      struct mt7621_nfc *nfc = &nfc_dev;
++      struct nand_chip *chip = &nfc->nand;
++      struct mtd_info *mtd = &chip->mtd;
++      u32 addr, col, page, chksz;
++      bool check_bad = true;
++
++      if (!nand_valid)
++              return -ENODEV;
++
++      while (size) {
++              if (check_bad || !(offs & mtd->erasesize_mask)) {
++                      addr = offs & (~mtd->erasesize_mask);
++                      page = addr >> mtd->writesize_shift;
++                      if (nfc_check_bad_block(mtd, page)) {
++                              /* Skip bad block */
++                              if (addr >= mtd->size - mtd->erasesize)
++                                      return -1;
++
++                              offs += mtd->erasesize;
++                              continue;
++                      }
++
++                      check_bad = false;
++              }
++
++              col = offs & mtd->writesize_mask;
++              page = offs >> mtd->writesize_shift;
++              chksz = min(mtd->writesize - col, (uint32_t)size);
++
++              if (unlikely(chksz < mtd->writesize)) {
++                      /* Not reading a full page */
++                      if (nfc_read_page_hwecc(mtd, buffer, page))
++                              return -1;
++
++                      memcpy(dest, buffer + col, chksz);
++              } else {
++                      if (nfc_read_page_hwecc(mtd, dest, page))
++                              return -1;
++              }
++
++              dest += chksz;
++              offs += chksz;
++              size -= chksz;
++      }
++
++      return 0;
++}
++
++int nand_default_bbt(struct mtd_info *mtd)
++{
++      return 0;
++}
++
++unsigned long nand_size(void)
++{
++      if (!nand_valid)
++              return 0;
++
++      /* Unlikely that NAND size > 2GBytes */
++      if (nfc_dev.nand.chipsize <= SZ_2G)
++              return nfc_dev.nand.chipsize;
++
++      return SZ_2G;
++}
++
++void nand_deselect(void)
++{
++}
++
++void nand_init(void)
++{
++      struct mtd_info *mtd;
++      struct nand_chip *chip;
++
++      if (nand_valid)
++              return;
++
++      mt7621_nfc_spl_init(&nfc_dev);
++
++      chip = &nfc_dev.nand;
++      mtd = &chip->mtd;
++      chip->cmdfunc = nand_command_lp;
++
++      if (mt7621_nfc_spl_post_init(&nfc_dev))
++              return;
++
++      mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
++      mtd->writesize_shift = ffs(mtd->writesize) - 1;
++      mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
++      mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
++
++      buffer = malloc(mtd->writesize);
++      if (!buffer)
++              return;
++
++      nand_valid = 1;
++}
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0021-spl-allow-using-nand-base-without-standard-nand-driv.patch b/package/boot/uboot-mediatek/patches/001-mtk-0021-spl-allow-using-nand-base-without-standard-nand-driv.patch
new file mode 100644 (file)
index 0000000..d3f24f7
--- /dev/null
@@ -0,0 +1,29 @@
+From 474082b03ae2b569f9daf43f78b91b57f7a1ae50 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:53 +0800
+Subject: [PATCH 21/25] spl: allow using nand base without standard nand driver
+
+This patch removes the dependency to SPL_NAND_DRIVERS for SPL_NAND_BASE to
+allow minimal spl nand driver to use nand base for probing NAND chips.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ common/spl/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/common/spl/Kconfig b/common/spl/Kconfig
+index 50ff113cab..eee9315e43 100644
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -764,7 +764,7 @@ config SPL_NAND_SIMPLE
+         expose the cmd_ctrl() interface.
+ config SPL_NAND_BASE
+-      depends on SPL_NAND_DRIVERS
++      depends on SPL_NAND_SUPPORT
+       bool "Use Base NAND Driver"
+       help
+         Include nand_base.c in the SPL.
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0022-spl-spl_legacy-fix-the-use-of-SPL_COPY_PAYLOAD_ONLY.patch b/package/boot/uboot-mediatek/patches/001-mtk-0022-spl-spl_legacy-fix-the-use-of-SPL_COPY_PAYLOAD_ONLY.patch
new file mode 100644 (file)
index 0000000..9181067
--- /dev/null
@@ -0,0 +1,69 @@
+From ba9c81e720f39b5dbc14592252bfc9402afee79d Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:23:58 +0800
+Subject: [PATCH 22/25] spl: spl_legacy: fix the use of SPL_COPY_PAYLOAD_ONLY
+
+If the payload is compressed, SPL_COPY_PAYLOAD_ONLY should always be set
+since the payload will not be directly read to its load address. The
+payload will first be read to a temporary buffer, and then be decompressed
+to its load address, without image header.
+
+If the payload is not compressed, and SPL_COPY_PAYLOAD_ONLY is set, image
+header should be skipped on loading. Otherwise image header should also be
+read to its load address.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ common/spl/spl_legacy.c | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c
+index 2ec7154423..ae8731c782 100644
+--- a/common/spl/spl_legacy.c
++++ b/common/spl/spl_legacy.c
+@@ -88,15 +88,29 @@ int spl_load_legacy_img(struct spl_image_info *spl_image,
+       /* Read header into local struct */
+       load->read(load, header, sizeof(hdr), &hdr);
++      /*
++       * If the payload is compressed, the decompressed data should be
++       * directly write to its load address.
++       */
++      if (spl_image_get_comp(&hdr) != IH_COMP_NONE)
++              spl_image->flags |= SPL_COPY_PAYLOAD_ONLY;
++
+       ret = spl_parse_image_header(spl_image, bootdev, &hdr);
+       if (ret)
+               return ret;
+-      dataptr = header + sizeof(hdr);
+-
+       /* Read image */
+       switch (spl_image_get_comp(&hdr)) {
+       case IH_COMP_NONE:
++              dataptr = header;
++
++              /*
++               * Image header will be skipped only if SPL_COPY_PAYLOAD_ONLY
++               * is set
++               */
++              if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY)
++                      dataptr += sizeof(hdr);
++
+               load->read(load, dataptr, spl_image->size,
+                          (void *)(unsigned long)spl_image->load_addr);
+               break;
+@@ -104,6 +118,9 @@ int spl_load_legacy_img(struct spl_image_info *spl_image,
+       case IH_COMP_LZMA:
+               lzma_len = LZMA_LEN;
++              /* dataptr points to compressed payload  */
++              dataptr = header + sizeof(hdr);
++
+               debug("LZMA: Decompressing %08lx to %08lx\n",
+                     dataptr, spl_image->load_addr);
+               src = malloc(spl_image->size);
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0023-spl-nand-support-loading-legacy-image-with-payload-c.patch b/package/boot/uboot-mediatek/patches/001-mtk-0023-spl-nand-support-loading-legacy-image-with-payload-c.patch
new file mode 100644 (file)
index 0000000..7bcc896
--- /dev/null
@@ -0,0 +1,64 @@
+From b4e5137067d34a099efd921532ece177560789ca Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:24:04 +0800
+Subject: [PATCH 23/25] spl: nand: support loading legacy image with payload
+ compressed
+
+Add support to load legacy image with payload compressed. This redirects
+the boot flow for all legacy images. If the payload is not compressed, the
+actual behavior will remain unchanged.
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ common/spl/spl_nand.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c
+index 82a10ffa63..7b7579a2df 100644
+--- a/common/spl/spl_nand.c
++++ b/common/spl/spl_nand.c
+@@ -56,6 +56,21 @@ static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
+       return size / load->bl_len;
+ }
++static ulong spl_nand_legacy_read(struct spl_load_info *load, ulong offs,
++                                ulong size, void *dst)
++{
++      int err;
++
++      debug("%s: offs %lx, size %lx, dst %p\n",
++            __func__, offs, size, dst);
++
++      err = nand_spl_load_image(offs, size, dst);
++      if (err)
++              return 0;
++
++      return size;
++}
++
+ struct mtd_info * __weak nand_get_mtd(void)
+ {
+       return NULL;
+@@ -93,6 +108,18 @@ static int spl_nand_load_element(struct spl_image_info *spl_image,
+               load.bl_len = bl_len;
+               load.read = spl_nand_fit_read;
+               return spl_load_imx_container(spl_image, &load, offset / bl_len);
++      } else if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT) &&
++                 image_get_magic(header) == IH_MAGIC) {
++              struct spl_load_info load;
++
++              debug("Found legacy image\n");
++              load.dev = NULL;
++              load.priv = NULL;
++              load.filename = NULL;
++              load.bl_len = 1;
++              load.read = spl_nand_legacy_read;
++
++              return spl_load_legacy_img(spl_image, bootdev, &load, offset);
+       } else {
+               err = spl_parse_image_header(spl_image, bootdev, header);
+               if (err)
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0024-tools-mtk_image-add-support-for-MT7621-NAND-images.patch b/package/boot/uboot-mediatek/patches/001-mtk-0024-tools-mtk_image-add-support-for-MT7621-NAND-images.patch
new file mode 100644 (file)
index 0000000..e317cc4
--- /dev/null
@@ -0,0 +1,340 @@
+From 18dd1ef9417d0880f2f492b55bd4d9ede499f137 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:24:10 +0800
+Subject: [PATCH 24/25] tools: mtk_image: add support for MT7621 NAND images
+
+The BootROM of MT7621 requires a image header for SPL to record its size
+and load address when booting from NAND.
+
+To create such an image, one can use the following command line:
+mkimage -T mtk_image -a 0x80200000 -e 0x80200000 -n "mt7621=1"
+-d u-boot-spl-ddr.bin u-boot-spl-ddr.img
+
+Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ tools/mtk_image.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++
+ tools/mtk_image.h |  24 ++++++
+ 2 files changed, 206 insertions(+)
+
+diff --git a/tools/mtk_image.c b/tools/mtk_image.c
+index 418c5fd54b..de5ce4d964 100644
+--- a/tools/mtk_image.c
++++ b/tools/mtk_image.c
+@@ -6,7 +6,9 @@
+  * Author: Weijie Gao <weijie.gao@mediatek.com>
+  */
++#include <time.h>
+ #include <image.h>
++#include <u-boot/crc.h>
+ #include <u-boot/sha256.h>
+ #include "imagetool.h"
+ #include "mtk_image.h"
+@@ -251,17 +253,45 @@ static uint32_t img_size;
+ static enum brlyt_img_type hdr_media;
+ static uint32_t hdr_offset;
+ static int use_lk_hdr;
++static int use_mt7621_hdr;
+ static bool is_arm64_image;
+ /* LK image name */
+ static char lk_name[32] = "U-Boot";
++/* CRC32 normal table required by MT7621 image */
++static uint32_t crc32tbl[256];
++
+ /* NAND header selected by user */
+ static const union nand_boot_header *hdr_nand;
+ /* GFH header + 2 * 4KB pages of NAND */
+ static char hdr_tmp[sizeof(struct gfh_header) + 0x2000];
++static uint32_t crc32_normal_cal(uint32_t crc, const void *data, size_t length,
++                               const uint32_t *crc32c_table)
++{
++      const uint8_t *p = data;
++
++      while (length--)
++              crc = crc32c_table[(uint8_t)((crc >> 24) ^ *p++)] ^ (crc << 8);
++
++      return crc;
++}
++
++static void crc32_normal_init(uint32_t *crc32c_table, uint32_t poly)
++{
++      uint32_t v, i, j;
++
++      for (i = 0; i < 256; i++) {
++              v = i << 24;
++              for (j = 0; j < 8; j++)
++                      v = (v << 1) ^ ((v & (1 << 31)) ? poly : 0);
++
++              crc32c_table[i] = v;
++      }
++}
++
+ static int mtk_image_check_image_types(uint8_t type)
+ {
+       if (type == IH_TYPE_MTKIMAGE)
+@@ -283,6 +313,7 @@ static int mtk_brom_parse_imagename(const char *imagename)
+       static const char *hdr_offs = "";
+       static const char *nandinfo = "";
+       static const char *lk = "";
++      static const char *mt7621 = "";
+       static const char *arm64_param = "";
+       key = buf;
+@@ -332,6 +363,9 @@ static int mtk_brom_parse_imagename(const char *imagename)
+                       if (!strcmp(key, "lk"))
+                               lk = val;
++                      if (!strcmp(key, "mt7621"))
++                              mt7621 = val;
++
+                       if (!strcmp(key, "lkname"))
+                               snprintf(lk_name, sizeof(lk_name), "%s", val);
+@@ -352,6 +386,13 @@ static int mtk_brom_parse_imagename(const char *imagename)
+               return 0;
+       }
++      /* if user specified MT7621 image header, skip following checks */
++      if (mt7621 && mt7621[0] == '1') {
++              use_mt7621_hdr = 1;
++              free(buf);
++              return 0;
++      }
++
+       /* parse media type */
+       for (i = 0; i < ARRAY_SIZE(brom_images); i++) {
+               if (!strcmp(brom_images[i].name, media)) {
+@@ -419,6 +460,13 @@ static int mtk_image_vrec_header(struct image_tool_params *params,
+               return 0;
+       }
++      if (use_mt7621_hdr) {
++              tparams->header_size = image_get_header_size();
++              tparams->hdr = &hdr_tmp;
++              memset(&hdr_tmp, 0, tparams->header_size);
++              return 0;
++      }
++
+       if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
+               tparams->header_size = 2 * le16_to_cpu(hdr_nand->pagesize);
+       else
+@@ -579,9 +627,90 @@ static int mtk_image_verify_nand_header(const uint8_t *ptr, int print)
+       return 0;
+ }
++static uint32_t crc32be_cal(const void *data, size_t length)
++{
++      uint32_t crc = 0;
++      uint8_t c;
++
++      if (crc32tbl[1] != MT7621_IH_CRC_POLYNOMIAL)
++              crc32_normal_init(crc32tbl, MT7621_IH_CRC_POLYNOMIAL);
++
++      crc = crc32_normal_cal(crc, data, length, crc32tbl);
++
++      for (; length; length >>= 8) {
++              c = length & 0xff;
++              crc = crc32_normal_cal(crc, &c, 1, crc32tbl);
++      }
++
++      return ~crc;
++}
++
++static int mtk_image_verify_mt7621_header(const uint8_t *ptr, int print)
++{
++      const image_header_t *hdr = (const image_header_t *)ptr;
++      struct mt7621_nand_header *nhdr;
++      uint32_t spl_size, crcval;
++      image_header_t header;
++      int ret;
++
++      spl_size = image_get_size(hdr);
++
++      if (spl_size > img_size) {
++              if (print)
++                      printf("Incomplete SPL image\n");
++              return -1;
++      }
++
++      ret = image_check_hcrc(hdr);
++      if (!ret) {
++              if (print)
++                      printf("Bad header CRC\n");
++              return -1;
++      }
++
++      ret = image_check_dcrc(hdr);
++      if (!ret) {
++              if (print)
++                      printf("Bad data CRC\n");
++              return -1;
++      }
++
++      /* Copy header so we can blank CRC field for re-calculation */
++      memmove(&header, hdr, image_get_header_size());
++      image_set_hcrc(&header, 0);
++
++      nhdr = (struct mt7621_nand_header *)header.ih_name;
++      crcval = be32_to_cpu(nhdr->crc);
++      nhdr->crc = 0;
++
++      if (crcval != crc32be_cal(&header, image_get_header_size())) {
++              if (print)
++                      printf("Bad NAND header CRC\n");
++              return -1;
++      }
++
++      if (print) {
++              printf("Load Address: %08x\n", image_get_load(hdr));
++
++              printf("Image Name:   %.*s\n", MT7621_IH_NMLEN,
++                     image_get_name(hdr));
++
++              if (IMAGE_ENABLE_TIMESTAMP) {
++                      printf("Created:      ");
++                      genimg_print_time((time_t)image_get_time(hdr));
++              }
++
++              printf("Data Size:    ");
++              genimg_print_size(image_get_data_size(hdr));
++      }
++
++      return 0;
++}
++
+ static int mtk_image_verify_header(unsigned char *ptr, int image_size,
+                                  struct image_tool_params *params)
+ {
++      image_header_t *hdr = (image_header_t *)ptr;
+       union lk_hdr *lk = (union lk_hdr *)ptr;
+       /* nothing to verify for LK image header */
+@@ -590,6 +719,9 @@ static int mtk_image_verify_header(unsigned char *ptr, int image_size,
+       img_size = image_size;
++      if (image_get_magic(hdr) == IH_MAGIC)
++              return mtk_image_verify_mt7621_header(ptr, 0);
++
+       if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+               return mtk_image_verify_nand_header(ptr, 0);
+       else
+@@ -600,6 +732,7 @@ static int mtk_image_verify_header(unsigned char *ptr, int image_size,
+ static void mtk_image_print_header(const void *ptr)
+ {
++      image_header_t *hdr = (image_header_t *)ptr;
+       union lk_hdr *lk = (union lk_hdr *)ptr;
+       if (le32_to_cpu(lk->magic) == LK_PART_MAGIC) {
+@@ -610,6 +743,11 @@ static void mtk_image_print_header(const void *ptr)
+       printf("Image Type:   MediaTek BootROM Loadable Image\n");
++      if (image_get_magic(hdr) == IH_MAGIC) {
++              mtk_image_verify_mt7621_header(ptr, 1);
++              return;
++      }
++
+       if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+               mtk_image_verify_nand_header(ptr, 1);
+       else
+@@ -773,6 +911,45 @@ static void mtk_image_set_nand_header(void *ptr, off_t filesize,
+                filesize - 2 * le16_to_cpu(hdr_nand->pagesize) - SHA256_SUM_LEN);
+ }
++static void mtk_image_set_mt7621_header(void *ptr, off_t filesize,
++                                      uint32_t loadaddr)
++{
++      image_header_t *hdr = (image_header_t *)ptr;
++      struct mt7621_stage1_header *shdr;
++      struct mt7621_nand_header *nhdr;
++      uint32_t datasize, crcval;
++
++      datasize = filesize - image_get_header_size();
++      nhdr = (struct mt7621_nand_header *)hdr->ih_name;
++      shdr = (struct mt7621_stage1_header *)(ptr + image_get_header_size());
++
++      shdr->ep = cpu_to_be32(loadaddr);
++      shdr->stage_size = cpu_to_be32(datasize);
++
++      image_set_magic(hdr, IH_MAGIC);
++      image_set_time(hdr, time(NULL));
++      image_set_size(hdr, datasize);
++      image_set_load(hdr, loadaddr);
++      image_set_ep(hdr, loadaddr);
++      image_set_os(hdr, IH_OS_U_BOOT);
++      image_set_arch(hdr, IH_ARCH_MIPS);
++      image_set_type(hdr, IH_TYPE_STANDALONE);
++      image_set_comp(hdr, IH_COMP_NONE);
++
++      crcval = crc32(0, (uint8_t *)shdr, datasize);
++      image_set_dcrc(hdr, crcval);
++
++      strncpy(nhdr->ih_name, "MT7621 NAND", MT7621_IH_NMLEN);
++
++      nhdr->ih_stage_offset = cpu_to_be32(image_get_header_size());
++
++      crcval = crc32be_cal(hdr, image_get_header_size());
++      nhdr->crc = cpu_to_be32(crcval);
++
++      crcval = crc32(0, (uint8_t *)hdr, image_get_header_size());
++      image_set_hcrc(hdr, crcval);
++}
++
+ static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd,
+                                struct image_tool_params *params)
+ {
+@@ -791,6 +968,11 @@ static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd,
+       img_gen = true;
+       img_size = sbuf->st_size;
++      if (use_mt7621_hdr) {
++              mtk_image_set_mt7621_header(ptr, sbuf->st_size, params->addr);
++              return;
++      }
++
+       if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
+               mtk_image_set_nand_header(ptr, sbuf->st_size, params->addr);
+       else
+diff --git a/tools/mtk_image.h b/tools/mtk_image.h
+index 7dda71ce88..d868545a33 100644
+--- a/tools/mtk_image.h
++++ b/tools/mtk_image.h
+@@ -200,4 +200,28 @@ union lk_hdr {
+ #define LK_PART_MAGIC         0x58881688
++/* MT7621 NAND SPL image header */
++
++#define MT7621_IH_NMLEN                       12
++#define MT7621_IH_CRC_POLYNOMIAL      0x04c11db7
++
++struct mt7621_nand_header {
++      char ih_name[MT7621_IH_NMLEN];
++      uint32_t nand_ac_timing;
++      uint32_t ih_stage_offset;
++      uint32_t ih_bootloader_offset;
++      uint32_t nand_info_1_data;
++      uint32_t crc;
++};
++
++struct mt7621_stage1_header {
++      uint32_t jump_insn[2];
++      uint32_t ep;
++      uint32_t stage_size;
++      uint32_t has_stage2;
++      uint32_t next_ep;
++      uint32_t next_size;
++      uint32_t next_offset;
++};
++
+ #endif /* _MTK_IMAGE_H */
+-- 
+2.36.1
+
diff --git a/package/boot/uboot-mediatek/patches/001-mtk-0025-MAINTAINERS-update-maintainer-for-MediaTek-MIPS-plat.patch b/package/boot/uboot-mediatek/patches/001-mtk-0025-MAINTAINERS-update-maintainer-for-MediaTek-MIPS-plat.patch
new file mode 100644 (file)
index 0000000..1b6d19a
--- /dev/null
@@ -0,0 +1,44 @@
+From e5fc4022af3cfd59e3459276305671a595ac5ff0 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 20 May 2022 11:24:16 +0800
+Subject: [PATCH 25/25] MAINTAINERS: update maintainer for MediaTek MIPS
+ platform
+
+Update maintainer for MediaTek MIPS platform
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ MAINTAINERS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 7f27ff4c20..d8d060bd92 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1007,15 +1007,23 @@ R:     GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com>
+ S:    Maintained
+ F:    arch/mips/mach-mtmips/
+ F:    arch/mips/dts/mt7620.dtsi
++F:    arch/mips/dts/mt7621.dtsi
+ F:    arch/mips/dts/mt7620-u-boot.dtsi
++F:    arch/mips/dts/mt7621-u-boot.dtsi
+ F:    include/configs/mt7620.h
++F:    include/configs/mt7621.h
+ F:    include/dt-bindings/clock/mt7620-clk.h
++F:    include/dt-bindings/clock/mt7621-clk.h
+ F:    include/dt-bindings/clock/mt7628-clk.h
+ F:    include/dt-bindings/reset/mt7620-reset.h
++F:    include/dt-bindings/reset/mt7621-reset.h
+ F:    include/dt-bindings/reset/mt7628-reset.h
+ F:    drivers/clk/mtmips/
+ F:    drivers/pinctrl/mtmips/
+ F:    drivers/gpio/mt7620_gpio.c
++F:    drivers/mtd/nand/raw/mt7621_nand.c
++F:    drivers/mtd/nand/raw/mt7621_nand.h
++F:    drivers/mtd/nand/raw/mt7621_nand_spl.c
+ F:    drivers/net/mt7620-eth.c
+ F:    drivers/phy/mt7620-usb-phy.c
+ F:    drivers/reset/reset-mtmips.c
+-- 
+2.36.1
+
index bb7045916ff2e83645aa122b97499d8013ff158e..a784f32f34bff1e4d7c04c75c80eb8ebbd41d52e 100644 (file)
  
  DECLARE_GLOBAL_DATA_PTR;
  
-@@ -392,6 +393,21 @@ static int initr_onenand(void)
+@@ -392,6 +393,20 @@ static int initr_onenand(void)
  }
  #endif
  
 +{
 +      struct udevice *new;
 +
-+      spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS,
-+                              CONFIG_SF_DEFAULT_CS,
-+                              CONFIG_SF_DEFAULT_SPEED,
-+                              CONFIG_SF_DEFAULT_MODE,
-+                              &new);
++spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS,
++                      CONFIG_SF_DEFAULT_CS,
++                      &new);
++
 +      return 0;
 +}
 +#endif
diff --git a/package/boot/uboot-mediatek/patches/420-add-support-for-RAVPower-RP-WD009.patch b/package/boot/uboot-mediatek/patches/420-add-support-for-RAVPower-RP-WD009.patch
new file mode 100644 (file)
index 0000000..80af85a
--- /dev/null
@@ -0,0 +1,259 @@
+From 593db38363297247df731566c2aa307a5d795005 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Thu, 18 Jun 2020 00:13:11 +0200
+Subject: [PATCH] add support for RAVPower RP-WD009
+
+---
+ arch/mips/dts/Makefile                  |  3 +-
+ arch/mips/dts/ravpower-rp-wd009.dts     | 50 +++++++++++++++++++++
+ arch/mips/mach-mtmips/Kconfig           |  9 ++++
+ board/ravpower/rp-wd009/Kconfig         | 12 +++++
+ board/ravpower/rp-wd009/Makefile        |  3 ++
+ board/ravpower/rp-wd009/board.c         | 16 +++++++
+ configs/ravpower-rp-wd009-ram_defconfig | 59 +++++++++++++++++++++++++
+ include/configs/ravpower-rp-wd009.h     | 48 ++++++++++++++++++++
+ 8 files changed, 199 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/dts/ravpower-rp-wd009.dts
+ create mode 100644 board/ravpower/rp-wd009/Kconfig
+ create mode 100644 board/ravpower/rp-wd009/Makefile
+ create mode 100644 board/ravpower/rp-wd009/board.c
+ create mode 100644 configs/ravpower-rp-wd009-ram_defconfig
+ create mode 100644 include/configs/ravpower-rp-wd009.h
+
+--- a/arch/mips/dts/Makefile
++++ b/arch/mips/dts/Makefile
+@@ -25,6 +25,7 @@ dtb-$(CONFIG_TARGET_OCTEON_EBB7304) += m
+ dtb-$(CONFIG_TARGET_OCTEON_NIC23) += mrvl,octeon-nic23.dtb
+ dtb-$(CONFIG_BOARD_NETGEAR_CG3100D) += netgear,cg3100d.dtb
+ dtb-$(CONFIG_BOARD_NETGEAR_DGND3700V2) += netgear,dgnd3700v2.dtb
++dtb-$(CONFIG_BOARD_RAVPOWER_RP_WD009) += ravpower-rp-wd009.dtb
+ dtb-$(CONFIG_BOARD_SAGEM_FAST1704) += sagem,f@st1704.dtb
+ dtb-$(CONFIG_BOARD_SFR_NB4_SER) += sfr,nb4-ser.dtb
+ dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb
+--- /dev/null
++++ b/arch/mips/dts/ravpower-rp-wd009.dts
+@@ -0,0 +1,50 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++/dts-v1/;
++
++#include "mt7628a.dtsi"
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++      compatible = "ravpower,rp-wd009", "ralink,mt7628a-soc";
++      model = "RAVPower RP-WD009";
++
++      aliases {
++              serial0 = &uart0;
++              spi0 = &spi0;
++      };
++
++      memory@0 {
++              device_type = "memory";
++              reg = <0x0 0x4000000>;
++      };
++
++      chosen {
++              stdout-path = "serial0:115200n8";
++      };
++};
++
++&uart0 {
++      status = "okay";
++};
++
++&spi0 {
++      status = "okay";
++      num-cs = <2>;
++
++      spi-flash@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "jedec,spi-nor";
++              spi-max-frequency = <40000000>;
++              reg = <0>;
++      };
++};
++
++&eth {
++      pinctrl-names = "default";
++      pinctrl-0 = <&ephy_router_mode>;
++};
+--- /dev/null
++++ b/board/ravpower/rp-wd009/Kconfig
+@@ -0,0 +1,12 @@
++if BOARD_RAVPOWER_RP_WD009
++
++config SYS_BOARD
++      default "rp-wd009"
++
++config SYS_VENDOR
++      default "ravpower"
++
++config SYS_CONFIG_NAME
++      default "ravpower-rp-wd009"
++
++endif
+--- /dev/null
++++ b/board/ravpower/rp-wd009/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0+
++
++obj-y += board.o
+--- /dev/null
++++ b/board/ravpower/rp-wd009/board.c
+@@ -0,0 +1,16 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++
++int board_early_init_f(void)
++{
++      return 0;
++}
++
++
++int board_late_init(void)
++{
++      return 0;
++}
+--- /dev/null
++++ b/configs/ravpower-rp-wd009-ram_defconfig
+@@ -0,0 +1,61 @@
++CONFIG_MIPS=y
++CONFIG_SYS_LOAD_ADDR=0x80010000
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_ARCH_MTMIPS=y
++CONFIG_SOC_MT7628=y
++CONFIG_MIPS_BOOT_FDT=y
++CONFIG_LEGACY_IMAGE_FORMAT=y
++CONFIG_OF_STDOUT_VIA_ALIAS=y
++CONFIG_USE_BOOTCOMMAND=y
++CONFIG_BOOTCOMMAND="sf probe && mtd read firmware 82000000 && bootm 82000000"
++CONFIG_USE_PREBOOT=y
++CONFIG_SYS_CONSOLE_INFO_QUIET=y
++CONFIG_VERSION_VARIABLE=y
++CONFIG_BOARD_RAVPOWER_RP_WD009=y
++CONFIG_HUSH_PARSER=y
++CONFIG_CMD_LICENSE=y
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_XIMG is not set
++CONFIG_CMD_MEMINFO=y
++# CONFIG_CMD_FLASH is not set
++CONFIG_CMD_GPIO=y
++# CONFIG_CMD_LOADS is not set
++CONFIG_CMD_MTD=y
++CONFIG_CMD_SPI=y
++CONFIG_CMD_WDT=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_TIME=y
++CONFIG_CMD_UUID=y
++CONFIG_CMD_MTDPARTS=y
++CONFIG_FIT=y
++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y
++CONFIG_MTDIDS_DEFAULT="nor0=spi0.0"
++CONFIG_MTDPARTS_DEFAULT="spi0.0:192k(factory-uboot),64k(config),64k(factory),1536k(loader),64k(params),64k(user_backup),64k(user),14272k(firmware),64k(mode)"
++CONFIG_DEFAULT_DEVICE_TREE="ravpower-rp-wd009"
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_DM_DEVICE_REMOVE is not set
++CONFIG_HAVE_BLOCK_DEVICE=y
++CONFIG_LED=y
++CONFIG_LED_BLINK=y
++CONFIG_LED_GPIO=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_SPI_FLASH_GIGADEVICE=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_SPANSION=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_SPI_FLASH_WINBOND=y
++CONFIG_SPI_FLASH_XMC=y
++CONFIG_SPI_FLASH_MTD=y
++CONFIG_MTD_UBI_BEB_LIMIT=22
++CONFIG_MT7628_ETH=y
++CONFIG_PHY=y
++CONFIG_SPI=y
++CONFIG_MT7621_SPI=y
++CONFIG_SYSRESET_SYSCON=y
++CONFIG_WDT=y
++CONFIG_WDT_MT7621=y
++CONFIG_LZMA=y
++CONFIG_BAUDRATE=57600
+--- /dev/null
++++ b/include/configs/ravpower-rp-wd009.h
+@@ -0,0 +1,42 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++#ifndef __CONFIG_RAVPOWER_RP_WD009_H
++#define __CONFIG_RAVPOWER_RP_WD009_H
++
++/* CPU */
++#define CONFIG_SYS_MIPS_TIMER_FREQ    290000000
++
++/* RAM */
++#define CONFIG_SYS_SDRAM_BASE         0x80000000
++
++#define CONFIG_SYS_INIT_SP_OFFSET     0x400000
++
++#ifdef CONFIG_BOOT_RAM
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#endif
++
++/* UART */
++#define CONFIG_SYS_BAUDRATE_TABLE     { 9600, 19200, 38400, 57600, 115200, \
++                                        230400, 460800, 921600 }
++
++/* RAM */
++#define CONFIG_SYS_MEMTEST_START      0x80100000
++#define CONFIG_SYS_MEMTEST_END                0x80400000
++
++/* Memory usage */
++#define CONFIG_SYS_MAXARGS            64
++#define CONFIG_SYS_BOOTPARAMS_LEN     (128 * 1024)
++#define CONFIG_SYS_CBSIZE             512
++
++/* Environment settings */
++
++/*
++ * Environment is right behind U-Boot in flash. Make sure U-Boot
++ * doesn't grow into the environment area.
++ */
++#define CONFIG_BOARD_SIZE_LIMIT               CONFIG_ENV_OFFSET
++
++#endif /* __CONFIG_RAVPOWER_RP_WD009_H */
+--- a/arch/mips/mach-mtmips/mt7628/Kconfig
++++ b/arch/mips/mach-mtmips/mt7628/Kconfig
+@@ -27,6 +27,14 @@ config BOARD_MT7628_RFB
+         SPI-NOR flash, 1 built-in switch with 5 ports, 1 UART, 1 USB host,
+         1 SDXC, 1 PCIe socket and JTAG pins.
++config BOARD_RAVPOWER_RP_WD009
++      bool "RAVPower RP-WD009"
++      depends on SOC_MT7628
++      select BOARD_LATE_INIT
++      select SUPPORTS_BOOT_RAM
++      help
++        RAVPower RP-WD009
++
+ config BOARD_VOCORE2
+       bool "VoCore2"
+       select SPL_SERIAL
+@@ -53,6 +61,7 @@ config SYS_CONFIG_NAME
+       default "mt7628" if BOARD_MT7628_RFB
+ source "board/gardena/smart-gateway-mt7688/Kconfig"
++source "board/ravpower/rp-wd009/Kconfig"
+ source "board/seeed/linkit-smart-7688/Kconfig"
+ source "board/vocore/vocore2/Kconfig"
diff --git a/package/boot/uboot-ramips/Makefile b/package/boot/uboot-ramips/Makefile
deleted file mode 100644 (file)
index 337ea00..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-include $(TOPDIR)/rules.mk
-include $(INCLUDE_DIR)/kernel.mk
-
-PKG_VERSION:=2020.04
-PKG_RELEASE:=$(AUTORELEASE)
-
-PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
-
-include $(INCLUDE_DIR)/u-boot.mk
-include $(INCLUDE_DIR)/package.mk
-
-define U-Boot/Default
-  BUILD_TARGET:=ramips
-  UBOOT_IMAGE:=u-boot.bin
-endef
-
-define U-Boot/ravpower_rp-wd009
-  BUILD_DEVICES:=ravpower_rp-wd009
-  BUILD_SUBTARGET:=mt76x8
-  NAME:=RAVPower RP-WD009
-  UBOOT_CONFIG:=ravpower-rp-wd009-ram
-endef
-
-UBOOT_TARGETS := \
-       ravpower_rp-wd009
-
-define Build/InstallDev
-       $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(VARIANT)-$(UBOOT_IMAGE)
-endef
-
-$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch b/package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch
deleted file mode 100644 (file)
index 1833a62..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-From 593db38363297247df731566c2aa307a5d795005 Mon Sep 17 00:00:00 2001
-From: David Bauer <mail@david-bauer.net>
-Date: Thu, 18 Jun 2020 00:13:11 +0200
-Subject: [PATCH] add support for RAVPower RP-WD009
-
----
- arch/mips/dts/Makefile                  |  3 +-
- arch/mips/dts/ravpower-rp-wd009.dts     | 50 +++++++++++++++++++++
- arch/mips/mach-mtmips/Kconfig           |  9 ++++
- board/ravpower/rp-wd009/Kconfig         | 12 +++++
- board/ravpower/rp-wd009/Makefile        |  3 ++
- board/ravpower/rp-wd009/board.c         | 16 +++++++
- configs/ravpower-rp-wd009-ram_defconfig | 59 +++++++++++++++++++++++++
- include/configs/ravpower-rp-wd009.h     | 48 ++++++++++++++++++++
- 8 files changed, 199 insertions(+), 1 deletion(-)
- create mode 100644 arch/mips/dts/ravpower-rp-wd009.dts
- create mode 100644 board/ravpower/rp-wd009/Kconfig
- create mode 100644 board/ravpower/rp-wd009/Makefile
- create mode 100644 board/ravpower/rp-wd009/board.c
- create mode 100644 configs/ravpower-rp-wd009-ram_defconfig
- create mode 100644 include/configs/ravpower-rp-wd009.h
-
-diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
-index c9d75596f2..23868ae1d2 100644
---- a/arch/mips/dts/Makefile
-+++ b/arch/mips/dts/Makefile
-@@ -2,7 +2,8 @@
- dtb-$(CONFIG_ARCH_MTMIPS) += \
-       gardena-smart-gateway-mt7688.dtb \
--      linkit-smart-7688.dtb
-+      linkit-smart-7688.dtb \
-+      ravpower-rp-wd009.dtb
- dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
- dtb-$(CONFIG_TARGET_AP143) += ap143.dtb
- dtb-$(CONFIG_TARGET_AP152) += ap152.dtb
-diff --git a/arch/mips/dts/ravpower-rp-wd009.dts b/arch/mips/dts/ravpower-rp-wd009.dts
-new file mode 100644
-index 0000000000..b271d5bfbc
---- /dev/null
-+++ b/arch/mips/dts/ravpower-rp-wd009.dts
-@@ -0,0 +1,50 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
-+ */
-+
-+/dts-v1/;
-+
-+#include "mt7628a.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-+
-+/ {
-+      compatible = "ravpower,rp-wd009", "ralink,mt7628a-soc";
-+      model = "RAVPower RP-WD009";
-+
-+      aliases {
-+              serial0 = &uart0;
-+              spi0 = &spi0;
-+      };
-+
-+      memory@0 {
-+              device_type = "memory";
-+              reg = <0x0 0x4000000>;
-+      };
-+
-+      chosen {
-+              stdout-path = "serial0:115200n8";
-+      };
-+};
-+
-+&uart0 {
-+      status = "okay";
-+};
-+
-+&spi0 {
-+      status = "okay";
-+      num-cs = <2>;
-+
-+      spi-flash@0 {
-+              #address-cells = <1>;
-+              #size-cells = <1>;
-+              compatible = "jedec,spi-nor";
-+              spi-max-frequency = <40000000>;
-+              reg = <0>;
-+      };
-+};
-+
-+&eth {
-+      pinctrl-names = "default";
-+      pinctrl-0 = <&ephy_router_mode>;
-+};
-diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig
-index c8dcf19c0d..85ac8878ab 100644
---- a/arch/mips/mach-mtmips/Kconfig
-+++ b/arch/mips/mach-mtmips/Kconfig
-@@ -32,6 +32,14 @@ config BOARD_GARDENA_SMART_GATEWAY_MT7688
-         GARDENA smart Gateway boards have a MT7688 SoC with 128 MiB of RAM
-         and 8 MiB of flash (SPI NOR) and additional SPI NAND storage.
-+config BOARD_RAVPOWER_RP_WD009
-+      bool "RAVPower RP-WD009"
-+      depends on SOC_MT7628
-+      select BOARD_LATE_INIT
-+      select SUPPORTS_BOOT_RAM
-+      help
-+        RAVPower RP-WD009
-+
- config BOARD_LINKIT_SMART_7688
-       bool "LinkIt Smart 7688"
-       depends on SOC_MT7628
-@@ -133,6 +141,7 @@ config SUPPORTS_BOOT_RAM
-       bool
- source "board/gardena/smart-gateway-mt7688/Kconfig"
-+source "board/ravpower/rp-wd009/Kconfig"
- source "board/seeed/linkit-smart-7688/Kconfig"
- endmenu
-diff --git a/board/ravpower/rp-wd009/Kconfig b/board/ravpower/rp-wd009/Kconfig
-new file mode 100644
-index 0000000000..111f8e4478
---- /dev/null
-+++ b/board/ravpower/rp-wd009/Kconfig
-@@ -0,0 +1,12 @@
-+if BOARD_RAVPOWER_RP_WD009
-+
-+config SYS_BOARD
-+      default "rp-wd009"
-+
-+config SYS_VENDOR
-+      default "ravpower"
-+
-+config SYS_CONFIG_NAME
-+      default "ravpower-rp-wd009"
-+
-+endif
-diff --git a/board/ravpower/rp-wd009/Makefile b/board/ravpower/rp-wd009/Makefile
-new file mode 100644
-index 0000000000..70cd7a8e56
---- /dev/null
-+++ b/board/ravpower/rp-wd009/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0+
-+
-+obj-y += board.o
-diff --git a/board/ravpower/rp-wd009/board.c b/board/ravpower/rp-wd009/board.c
-new file mode 100644
-index 0000000000..eabcf85735
---- /dev/null
-+++ b/board/ravpower/rp-wd009/board.c
-@@ -0,0 +1,16 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
-+ */
-+
-+
-+int board_early_init_f(void)
-+{
-+      return 0;
-+}
-+
-+
-+int board_late_init(void)
-+{
-+      return 0;
-+}
-diff --git a/configs/ravpower-rp-wd009-ram_defconfig b/configs/ravpower-rp-wd009-ram_defconfig
-new file mode 100644
-index 0000000000..08cbf40638
---- /dev/null
-+++ b/configs/ravpower-rp-wd009-ram_defconfig
-@@ -0,0 +1,59 @@
-+CONFIG_MIPS=y
-+CONFIG_SYS_TEXT_BASE=0x80010000
-+CONFIG_NR_DRAM_BANKS=1
-+CONFIG_ARCH_MTMIPS=y
-+CONFIG_MIPS_BOOT_FDT=y
-+CONFIG_LEGACY_IMAGE_FORMAT=y
-+CONFIG_OF_STDOUT_VIA_ALIAS=y
-+CONFIG_USE_BOOTCOMMAND=y
-+CONFIG_BOOTCOMMAND="sf probe && mtd read firmware 82000000 && bootm 82000000"
-+CONFIG_USE_PREBOOT=y
-+CONFIG_SYS_CONSOLE_INFO_QUIET=y
-+CONFIG_VERSION_VARIABLE=y
-+CONFIG_BOARD_RAVPOWER_RP_WD009=y
-+CONFIG_BOARD_EARLY_INIT_F=y
-+CONFIG_HUSH_PARSER=y
-+CONFIG_CMD_LICENSE=y
-+# CONFIG_CMD_ELF is not set
-+# CONFIG_CMD_XIMG is not set
-+CONFIG_CMD_MEMINFO=y
-+# CONFIG_CMD_FLASH is not set
-+CONFIG_CMD_GPIO=y
-+# CONFIG_CMD_LOADS is not set
-+CONFIG_CMD_MTD=y
-+CONFIG_CMD_SPI=y
-+CONFIG_CMD_WDT=y
-+CONFIG_CMD_DHCP=y
-+CONFIG_CMD_MII=y
-+CONFIG_CMD_PING=y
-+CONFIG_CMD_TIME=y
-+CONFIG_CMD_UUID=y
-+CONFIG_CMD_MTDPARTS=y
-+CONFIG_MTDIDS_DEFAULT="nor0=spi0.0"
-+CONFIG_MTDPARTS_DEFAULT="spi0.0:192k(factory-uboot),64k(config),64k(factory),1536k(loader),64k(params),64k(user_backup),64k(user),14272k(firmware),64k(mode)"
-+CONFIG_DEFAULT_DEVICE_TREE="ravpower-rp-wd009"
-+CONFIG_NET_RANDOM_ETHADDR=y
-+# CONFIG_DM_DEVICE_REMOVE is not set
-+CONFIG_HAVE_BLOCK_DEVICE=y
-+CONFIG_LED=y
-+CONFIG_LED_BLINK=y
-+CONFIG_LED_GPIO=y
-+CONFIG_MTD=y
-+CONFIG_DM_MTD=y
-+CONFIG_SPI_FLASH_GIGADEVICE=y
-+CONFIG_SPI_FLASH_MACRONIX=y
-+CONFIG_SPI_FLASH_SPANSION=y
-+CONFIG_SPI_FLASH_STMICRO=y
-+CONFIG_SPI_FLASH_WINBOND=y
-+CONFIG_SPI_FLASH_XMC=y
-+CONFIG_SPI_FLASH_MTD=y
-+CONFIG_MTD_UBI_BEB_LIMIT=22
-+CONFIG_MT7628_ETH=y
-+CONFIG_PHY=y
-+CONFIG_SPI=y
-+CONFIG_MT7621_SPI=y
-+CONFIG_SYSRESET_SYSCON=y
-+CONFIG_WDT=y
-+CONFIG_WDT_MT7621=y
-+CONFIG_LZMA=y
-+CONFIG_BAUDRATE=57600
-diff --git a/include/configs/ravpower-rp-wd009.h b/include/configs/ravpower-rp-wd009.h
-new file mode 100644
-index 0000000000..bb4145197c
---- /dev/null
-+++ b/include/configs/ravpower-rp-wd009.h
-@@ -0,0 +1,48 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
-+ */
-+
-+#ifndef __CONFIG_RAVPOWER_RP_WD009_H
-+#define __CONFIG_RAVPOWER_RP_WD009_H
-+
-+/* CPU */
-+#define CONFIG_SYS_MIPS_TIMER_FREQ    290000000
-+
-+/* RAM */
-+#define CONFIG_SYS_SDRAM_BASE         0x80000000
-+
-+#define CONFIG_SYS_LOAD_ADDR          CONFIG_SYS_SDRAM_BASE + 0x100000
-+
-+#define CONFIG_SYS_INIT_SP_OFFSET     0x400000
-+
-+#ifdef CONFIG_BOOT_RAM
-+#define CONFIG_SKIP_LOWLEVEL_INIT
-+#endif
-+
-+/* UART */
-+#define CONFIG_SYS_BAUDRATE_TABLE     { 9600, 19200, 38400, 57600, 115200, \
-+                                        230400, 460800, 921600 }
-+
-+/* RAM */
-+#define CONFIG_SYS_MEMTEST_START      0x80100000
-+#define CONFIG_SYS_MEMTEST_END                0x80400000
-+
-+/* Memory usage */
-+#define CONFIG_SYS_MAXARGS            64
-+#define CONFIG_SYS_MALLOC_LEN         (16 * 1024 * 1024)
-+#define CONFIG_SYS_BOOTPARAMS_LEN     (128 * 1024)
-+#define CONFIG_SYS_CBSIZE             512
-+
-+/* U-Boot */
-+#define CONFIG_SYS_MONITOR_BASE               CONFIG_SYS_TEXT_BASE
-+
-+/* Environment settings */
-+
-+/*
-+ * Environment is right behind U-Boot in flash. Make sure U-Boot
-+ * doesn't grow into the environment area.
-+ */
-+#define CONFIG_BOARD_SIZE_LIMIT               CONFIG_ENV_OFFSET
-+
-+#endif /* __CONFIG_RAVPOWER_RP_WD009_H */
--- 
-2.27.0
-