diff --git a/build.sh b/build.sh index 56ab959b..e92075f0 100755 --- a/build.sh +++ b/build.sh @@ -133,6 +133,8 @@ fi rm -rf "$OMR_TARGET/source/files" "$OMR_TARGET/source/tmp" #rm -rf "$OMR_TARGET/source/target/linux/mediatek/patches-4.14" rm -rf "$OMR_TARGET/source/target/linux/mediatek/patches-5.4" +rm -rf "$OMR_TARGET/source/package/boot/uboot-mediatek" +rm -rf "$OMR_TARGET/source/package/boot/arm-trusted-firmware-mediatek" cp -rf root/* "$OMR_TARGET/source" cat >> "$OMR_TARGET/source/package/base-files/files/etc/banner" < + +include $(INCLUDE_DIR)/trusted-firmware-a.mk +include $(INCLUDE_DIR)/package.mk + +define Trusted-Firmware-A/Default + BUILD_TARGET:=mediatek + BUILD_SUBTARGET:=mt7622 + PLAT:=mt7622 + TFA_IMAGE:=bl2.img bl31.bin + BOOT_DEVICE:= + DDR3_FLYBY:= +endef + +define Trusted-Firmware-A/mt7622-nor-1ddr + NAME:=MediaTek MT7622 (SPI-NOR, 1x DDR3) + BOOT_DEVICE:=nor +endef + +define Trusted-Firmware-A/mt7622-nor-2ddr + NAME:=MediaTek MT7622 (SPI-NOR, 2x DDR3) + BOOT_DEVICE:=nor + DDR3_FLYBY:=1 +endef + +define Trusted-Firmware-A/mt7622-snand-1ddr + NAME:=MediaTek MT7622 (SPI-NAND, 1x DDR3) + BOOT_DEVICE:=snand +endef + +define Trusted-Firmware-A/mt7622-snand-2ddr + NAME:=MediaTek MT7622 (SPI-NAND, 2x DDR3) + BOOT_DEVICE:=snand + DDR3_FLYBY:=1 +endef + +define Trusted-Firmware-A/mt7622-emmc-1ddr + NAME:=MediaTek MT7622 (eMMC, 1x DDR3) + BOOT_DEVICE:=emmc +endef + +define Trusted-Firmware-A/mt7622-emmc-2ddr + NAME:=MediaTek MT7622 (eMMC, 2x DDR3) + BOOT_DEVICE:=emmc + DDR3_FLYBY:=1 +endef + +define Trusted-Firmware-A/mt7622-sdmmc-1ddr + NAME:=MediaTek MT7622 (SDcard, 1x DDR3) + BOOT_DEVICE:=sdmmc +endef + +define Trusted-Firmware-A/mt7622-sdmmc-2ddr + NAME:=MediaTek MT7622 (SDcard, 2x DDR3) + BOOT_DEVICE:=sdmmc + DDR3_FLYBY:=1 +endef + +TFA_TARGETS:= \ + mt7622-nor-1ddr \ + mt7622-nor-2ddr \ + mt7622-snand-1ddr \ + mt7622-snand-2ddr \ + mt7622-emmc-1ddr \ + mt7622-emmc-2ddr \ + mt7622-sdmmc-1ddr \ + mt7622-sdmmc-2ddr + +TFA_MAKE_FLAGS += \ + BOOT_DEVICE=$(BOOT_DEVICE) \ + USE_MKIMAGE=1 MKIMAGE=$(STAGING_DIR_HOST)/bin/mkimage \ + $(if $(DDR3_FLYBY),DDR3_FLYBY=1) \ + all + +define Package/trusted-firmware-a/install + $(INSTALL_DIR) $(STAGING_DIR_IMAGE) + $(INSTALL_DATA) $(PKG_BUILD_DIR)/build/mt7622/release/bl2.img $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl2.img + $(INSTALL_DATA) $(PKG_BUILD_DIR)/build/mt7622/release/bl31.bin $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl31.bin +endef + +$(eval $(call BuildPackage/Trusted-Firmware-A)) diff --git a/root/package/boot/arm-trusted-firmware-mediatek/patches/100-increase-nor-bl3-size.patch b/root/package/boot/arm-trusted-firmware-mediatek/patches/100-increase-nor-bl3-size.patch new file mode 100644 index 00000000..8de3cd77 --- /dev/null +++ b/root/package/boot/arm-trusted-firmware-mediatek/patches/100-increase-nor-bl3-size.patch @@ -0,0 +1,11 @@ +--- a/plat/mediatek/mt7622/bl2_boot_nor.c ++++ b/plat/mediatek/mt7622/bl2_boot_nor.c +@@ -12,7 +12,7 @@ + #define MT7622_NOR_MAP_BASE 0x30000000 + + #define FIP_BASE 0x20000 +-#define FIP_SIZE 0x80000 ++#define FIP_SIZE 0xa0000 + + const io_block_spec_t mtk_boot_dev_fip_spec = { + .offset = MT7622_NOR_MAP_BASE + FIP_BASE, diff --git a/root/package/boot/uboot-mediatek/Makefile b/root/package/boot/uboot-mediatek/Makefile new file mode 100644 index 00000000..bd380702 --- /dev/null +++ b/root/package/boot/uboot-mediatek/Makefile @@ -0,0 +1,142 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_VERSION:=2022.01 +PKG_HASH:=81b4543227db228c03f8a1bf5ddbc813b0bb8f6555ce46064ef721a6fc680413 +PKG_BUILD_DEPENDS:=arm-trusted-firmware-tools/host + +include $(INCLUDE_DIR)/u-boot.mk +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/host-build.mk + +define U-Boot/Default + BUILD_TARGET:=mediatek + UBOOT_IMAGE:=u-boot-mtk.bin +endef + +define U-Boot/mt7622_rfb1 + NAME:=MT7622 Reference Board 1 + UBOOT_CONFIG:=mt7622_rfb + BUILD_DEVICES:=mediatek_mt7622-rfb1 mediatek_mt7622-rfb1-ubi + BUILD_SUBTARGET:=mt7622 +endef + +define U-Boot/mt7622_linksys_e8450 + NAME:=Linksys E8450 + UBOOT_CONFIG:=mt7622_linksys_e8450 + BUILD_DEVICES:=linksys_e8450-ubi + BUILD_SUBTARGET:=mt7622 + UBOOT_IMAGE:=u-boot.fip + BL2_BOOTDEV:=snand + BL2_DDRBLOB:=1 + DEPENDS:=+trusted-firmware-a-mt7622-snand-1ddr +endef + +define U-Boot/mt7622_bananapi_bpi-r64-emmc + NAME:=BananaPi R64 (eMMC) + UBOOT_CONFIG:=mt7622_bananapi_bpi-r64-emmc + BUILD_DEVICES:=bananapi_bpi-r64 + BUILD_SUBTARGET:=mt7622 + UBOOT_IMAGE:=u-boot.fip + BL2_BOOTDEV:=emmc + BL2_DDRBLOB:=2 + DEPENDS:=+trusted-firmware-a-mt7622-emmc-2ddr +endef + +define U-Boot/mt7622_bananapi_bpi-r64-sdmmc + NAME:=BananaPi R64 (SDMMC) + UBOOT_CONFIG:=mt7622_bananapi_bpi-r64-sdmmc + BUILD_DEVICES:=bananapi_bpi-r64 + BUILD_SUBTARGET:=mt7622 + UBOOT_IMAGE:=u-boot.fip + BL2_BOOTDEV:=sdmmc + BL2_DDRBLOB:=2 + DEPENDS:=+trusted-firmware-a-mt7622-sdmmc-2ddr +endef + +define U-Boot/mt7622_bananapi_bpi-r64-snand + NAME:=BananaPi R64 (SNAND) + UBOOT_CONFIG:=mt7622_bananapi_bpi-r64-snand + BUILD_DEVICES:=bananapi_bpi-r64 + BUILD_SUBTARGET:=mt7622 + UBOOT_IMAGE:=u-boot.fip + BL2_BOOTDEV:=snand + BL2_DDRBLOB:=2 + DEPENDS:=+trusted-firmware-a-mt7622-snand-2ddr +endef + +define U-Boot/mt7622_ubnt_unifi-6-lr + NAME:=Ubiquiti UniFi 6 LR + UBOOT_CONFIG:=mt7622_ubnt_unifi-6-lr + BUILD_DEVICES:=ubnt_unifi-6-lr-ubootmod + BUILD_SUBTARGET:=mt7622 + UBOOT_IMAGE:=u-boot.fip + BL2_BOOTDEV:=nor + BL2_DDRBLOB:=2 + DEPENDS:=+trusted-firmware-a-mt7622-nor-2ddr +endef + +define U-Boot/mt7623a_unielec_u7623 + NAME:=UniElec U7623 (mt7623) + BUILD_DEVICES:=unielec_u7623-02 + BUILD_SUBTARGET:=mt7623 + UBOOT_CONFIG:=mt7623a_unielec_u7623_02 +endef + +define U-Boot/mt7623n_bpir2 + NAME:=Banana Pi R2 (mt7623) + BUILD_DEVICES:=bananapi_bpi-r2 + BUILD_SUBTARGET:=mt7623 + UBOOT_IMAGE:=u-boot.bin + UBOOT_CONFIG:=mt7623n_bpir2 +endef + +define U-Boot/mt7629_rfb + NAME:=MT7629 Reference Board + BUILD_SUBTARGET:=mt7629 + BUILD_DEVICES:=mediatek_mt7629-rfb + UBOOT_CONFIG:=mt7629_rfb +endef + +UBOOT_TARGETS := \ + mt7622_bananapi_bpi-r64-emmc \ + mt7622_bananapi_bpi-r64-sdmmc \ + mt7622_bananapi_bpi-r64-snand \ + mt7622_linksys_e8450 \ + mt7622_rfb1 \ + mt7622_ubnt_unifi-6-lr \ + mt7623n_bpir2 \ + mt7623a_unielec_u7623 \ + mt7629_rfb + +UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE:.fip=.bin) + +define Build/fip-image + $(STAGING_DIR_HOST)/bin/fiptool create \ + --soc-fw $(STAGING_DIR_IMAGE)/$(BUILD_SUBTARGET)-$(BL2_BOOTDEV)-$(BL2_DDRBLOB)ddr-bl31.bin \ + --nt-fw $(PKG_BUILD_DIR)/u-boot.bin \ + $(PKG_BUILD_DIR)/u-boot.fip +endef + +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 +endef + +define Build/Compile + $(call Build/Compile/U-Boot) +ifeq ($(UBOOT_IMAGE),u-boot.fip)) + $(call Build/fip-image) +endif +endef + +# don't stage files to bindir, let target/linux/mediatek/image/*.mk do that +define Package/u-boot/install +endef + +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR_IMAGE) + $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE) +endef + +$(eval $(call BuildPackage/U-Boot)) diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch new file mode 100644 index 00000000..1a0c1ce5 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch @@ -0,0 +1,69 @@ +From 34ed9f6d3018d32c7c015e57c9985d3c4c07b706 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 11 Mar 2021 10:28:53 +0000 +Subject: [PATCH 01/12] Revert "clk: Add debugging for return values" + +This reverts commit 5c5992cb90cf9ca4d51e38d9a95a13c293904df5. +--- + drivers/clk/clk-uclass.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +--- a/drivers/clk/clk-uclass.c ++++ b/drivers/clk/clk-uclass.c +@@ -88,7 +88,7 @@ static int clk_get_by_index_tail(int ret + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); +- return log_msg_ret("get", ret); ++ return ret; + } + + clk->dev = dev_clk; +@@ -101,15 +101,14 @@ static int clk_get_by_index_tail(int ret + ret = clk_of_xlate_default(clk, args); + if (ret) { + debug("of_xlate() failed: %d\n", ret); +- return log_msg_ret("xlate", ret); ++ return ret; + } + + return clk_request(dev_clk, clk); + err: + debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n", + __func__, ofnode_get_name(node), list_name, index, ret); +- +- return log_msg_ret("prop", ret); ++ return ret; + } + + static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name, +@@ -128,7 +127,7 @@ static int clk_get_by_indexed_prop(struc + if (ret) { + debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", + __func__, ret); +- return log_ret(ret); ++ return ret; + } + + +@@ -501,7 +500,6 @@ int clk_free(struct clk *clk) + ulong clk_get_rate(struct clk *clk) + { + const struct clk_ops *ops; +- int ret; + + debug("%s(clk=%p)\n", __func__, clk); + if (!clk_valid(clk)) +@@ -511,11 +509,7 @@ ulong clk_get_rate(struct clk *clk) + if (!ops->get_rate) + return -ENOSYS; + +- ret = ops->get_rate(clk); +- if (ret) +- return log_ret(ret); +- +- return 0; ++ return ops->get_rate(clk); + } + + struct clk *clk_get_parent(struct clk *clk) diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch new file mode 100644 index 00000000..50c2ac2e --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch @@ -0,0 +1,44 @@ +From 938ba7ed996a86c9cc7af08b69df57b8b4c09510 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:47:45 +0800 +Subject: [PATCH 02/12] board: mediatek: add more network configurations + +Make the network configurations uniform for mediatek boards + +Signed-off-by: Weijie Gao +--- + include/configs/mt7622.h | 3 ++- + include/configs/mt7623.h | 1 + + include/configs/mt7629.h | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + +--- a/include/configs/mt7622.h ++++ b/include/configs/mt7622.h +@@ -30,6 +30,7 @@ + + /* Ethernet */ + #define CONFIG_IPADDR 192.168.1.1 +-#define CONFIG_SERVERIP 192.168.1.3 ++#define CONFIG_SERVERIP 192.168.1.2 ++#define CONFIG_NETMASK 255.255.255.0 + + #endif +--- a/include/configs/mt7623.h ++++ b/include/configs/mt7623.h +@@ -45,6 +45,7 @@ + /* Ethernet */ + #define CONFIG_IPADDR 192.168.1.1 + #define CONFIG_SERVERIP 192.168.1.2 ++#define CONFIG_NETMASK 255.255.255.0 + + #ifdef CONFIG_DISTRO_DEFAULTS + +--- a/include/configs/mt7629.h ++++ b/include/configs/mt7629.h +@@ -45,5 +45,6 @@ + /* Ethernet */ + #define CONFIG_IPADDR 192.168.1.1 + #define CONFIG_SERVERIP 192.168.1.2 ++#define CONFIG_NETMASK 255.255.255.0 + + #endif diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch new file mode 100644 index 00000000..8f14a98f --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch @@ -0,0 +1,28 @@ +From 1d4fcea788e579934a1ad0a90cecd6e1761127d1 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:56:17 +0800 +Subject: [PATCH 03/12] mmc: mtk-sd: increase the minimum bus frequency + +With a 48MHz input clock, the lowest bus frequency can be as low as +48000000 / (4 * 4095) = 2930Hz. Such an extremely low frequency will cause +the mmc framework take seconds to finish the initialization. + +Limiting the minimum bus frequency to a slightly higher value can solve the +issue without any side effects. + +Signed-off-by: Weijie Gao +--- + drivers/mmc/mtk-sd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mmc/mtk-sd.c ++++ b/drivers/mmc/mtk-sd.c +@@ -232,7 +232,7 @@ + + #define SCLK_CYCLES_SHIFT 20 + +-#define MIN_BUS_CLK 200000 ++#define MIN_BUS_CLK 260000 + + #define CMD_INTS_MASK \ + (MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO) diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch new file mode 100644 index 00000000..dead0db1 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch @@ -0,0 +1,3696 @@ +From d6c5309185aae3d9ecf80eae8b248522d11a6136 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 16:58:01 +0800 +Subject: [PATCH 04/12] drivers: mtd: add support for MediaTek SPI-NAND flash + controller + +Add mtd driver for MediaTek SPI-NAND flash controller + +This driver is written from scratch, and uses standard mtd framework, not +the nand framework which only applies for raw parallel nand flashes so that +this driver can have a smaller size in binary. + +Signed-off-by: Weijie Gao +--- + drivers/mtd/Kconfig | 2 + + drivers/mtd/Makefile | 2 + + drivers/mtd/mtk-snand/Kconfig | 21 + + drivers/mtd/mtk-snand/Makefile | 11 + + drivers/mtd/mtk-snand/mtk-snand-def.h | 266 ++++ + drivers/mtd/mtk-snand/mtk-snand-ecc.c | 264 ++++ + drivers/mtd/mtk-snand/mtk-snand-ids.c | 511 +++++++ + drivers/mtd/mtk-snand/mtk-snand-mtd.c | 526 ++++++++ + drivers/mtd/mtk-snand/mtk-snand-os.c | 39 + + drivers/mtd/mtk-snand/mtk-snand-os.h | 120 ++ + drivers/mtd/mtk-snand/mtk-snand.c | 1776 +++++++++++++++++++++++++ + drivers/mtd/mtk-snand/mtk-snand.h | 77 ++ + 12 files changed, 3615 insertions(+) + create mode 100644 drivers/mtd/mtk-snand/Kconfig + create mode 100644 drivers/mtd/mtk-snand/Makefile + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-def.h + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-ecc.c + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-ids.c + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-mtd.c + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-os.c + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-os.h + create mode 100644 drivers/mtd/mtk-snand/mtk-snand.c + create mode 100644 drivers/mtd/mtk-snand/mtk-snand.h + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -116,6 +116,8 @@ config STM32_FLASH + This is the driver of embedded flash for some STMicroelectronics + STM32 MCU. + ++source "drivers/mtd/mtk-snand/Kconfig" ++ + source "drivers/mtd/nand/Kconfig" + + config SYS_NAND_MAX_CHIPS +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -39,3 +39,5 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPOR + obj-$(CONFIG_SPL_UBI) += ubispl/ + + endif ++ ++obj-$(CONFIG_MTK_SPI_NAND) += mtk-snand/ +--- /dev/null ++++ b/drivers/mtd/mtk-snand/Kconfig +@@ -0,0 +1,21 @@ ++# ++# Copyright (C) 2020 MediaTek Inc. All rights reserved. ++# Author: Weijie Gao ++# ++# SPDX-License-Identifier: GPL-2.0 ++# ++ ++config MTK_SPI_NAND ++ tristate "MediaTek SPI NAND flash controller driver" ++ depends on !MTD_SPI_NAND ++ help ++ This option enables access to SPI-NAND flashes through the ++ MediaTek SPI NAND Flash Controller ++ ++config MTK_SPI_NAND_MTD ++ tristate "MTD support for MediaTek SPI NAND flash controller" ++ depends on DM_MTD ++ depends on MTK_SPI_NAND ++ help ++ This option enables access to SPI-NAND flashes through the ++ MTD interface of MediaTek SPI NAND Flash Controller +--- /dev/null ++++ b/drivers/mtd/mtk-snand/Makefile +@@ -0,0 +1,11 @@ ++# ++# Copyright (C) 2020 MediaTek Inc. All rights reserved. ++# Author: Weijie Gao ++# ++# SPDX-License-Identifier: GPL-2.0 ++# ++ ++obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o ++obj-$(CONFIG_MTK_SPI_NAND_MTD) += mtk-snand-mtd.o ++ ++ccflags-y += -DPRIVATE_MTK_SNAND_HEADER +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-def.h +@@ -0,0 +1,266 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#ifndef _MTK_SNAND_DEF_H_ ++#define _MTK_SNAND_DEF_H_ ++ ++#include "mtk-snand-os.h" ++ ++#ifdef PRIVATE_MTK_SNAND_HEADER ++#include "mtk-snand.h" ++#else ++#include ++#endif ++ ++struct mtk_snand_plat_dev; ++ ++enum snand_flash_io { ++ SNAND_IO_1_1_1, ++ SNAND_IO_1_1_2, ++ SNAND_IO_1_2_2, ++ SNAND_IO_1_1_4, ++ SNAND_IO_1_4_4, ++ ++ __SNAND_IO_MAX ++}; ++ ++#define SPI_IO_1_1_1 BIT(SNAND_IO_1_1_1) ++#define SPI_IO_1_1_2 BIT(SNAND_IO_1_1_2) ++#define SPI_IO_1_2_2 BIT(SNAND_IO_1_2_2) ++#define SPI_IO_1_1_4 BIT(SNAND_IO_1_1_4) ++#define SPI_IO_1_4_4 BIT(SNAND_IO_1_4_4) ++ ++struct snand_opcode { ++ uint8_t opcode; ++ uint8_t dummy; ++}; ++ ++struct snand_io_cap { ++ uint8_t caps; ++ struct snand_opcode opcodes[__SNAND_IO_MAX]; ++}; ++ ++#define SNAND_OP(_io, _opcode, _dummy) [_io] = { .opcode = (_opcode), \ ++ .dummy = (_dummy) } ++ ++#define SNAND_IO_CAP(_name, _caps, ...) \ ++ struct snand_io_cap _name = { .caps = (_caps), \ ++ .opcodes = { __VA_ARGS__ } } ++ ++#define SNAND_MAX_ID_LEN 4 ++ ++enum snand_id_type { ++ SNAND_ID_DYMMY, ++ SNAND_ID_ADDR = SNAND_ID_DYMMY, ++ SNAND_ID_DIRECT, ++ ++ __SNAND_ID_TYPE_MAX ++}; ++ ++struct snand_id { ++ uint8_t type; /* enum snand_id_type */ ++ uint8_t len; ++ uint8_t id[SNAND_MAX_ID_LEN]; ++}; ++ ++#define SNAND_ID(_type, ...) \ ++ { .type = (_type), .id = { __VA_ARGS__ }, \ ++ .len = sizeof((uint8_t[]) { __VA_ARGS__ }) } ++ ++struct snand_mem_org { ++ uint16_t pagesize; ++ uint16_t sparesize; ++ uint16_t pages_per_block; ++ uint16_t blocks_per_die; ++ uint16_t planes_per_die; ++ uint16_t ndies; ++}; ++ ++#define SNAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \ ++ { .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \ ++ .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd) } ++ ++typedef int (*snand_select_die_t)(struct mtk_snand *snf, uint32_t dieidx); ++ ++struct snand_flash_info { ++ const char *model; ++ struct snand_id id; ++ const struct snand_mem_org memorg; ++ const struct snand_io_cap *cap_rd; ++ const struct snand_io_cap *cap_pl; ++ snand_select_die_t select_die; ++}; ++ ++#define SNAND_INFO(_model, _id, _memorg, _cap_rd, _cap_pl, ...) \ ++ { .model = (_model), .id = _id, .memorg = _memorg, \ ++ .cap_rd = (_cap_rd), .cap_pl = (_cap_pl), __VA_ARGS__ } ++ ++const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type, ++ const uint8_t *id); ++ ++struct mtk_snand_soc_data { ++ uint16_t sector_size; ++ uint16_t max_sectors; ++ uint16_t fdm_size; ++ uint16_t fdm_ecc_size; ++ uint16_t fifo_size; ++ ++ bool bbm_swap; ++ bool empty_page_check; ++ uint32_t mastersta_mask; ++ ++ const uint8_t *spare_sizes; ++ uint32_t num_spare_size; ++}; ++ ++enum mtk_ecc_regs { ++ ECC_DECDONE, ++}; ++ ++struct mtk_ecc_soc_data { ++ const uint8_t *ecc_caps; ++ uint32_t num_ecc_cap; ++ const uint32_t *regs; ++ uint16_t mode_shift; ++ uint8_t errnum_bits; ++ uint8_t errnum_shift; ++}; ++ ++struct mtk_snand { ++ struct mtk_snand_plat_dev *pdev; ++ ++ void __iomem *nfi_base; ++ void __iomem *ecc_base; ++ ++ enum mtk_snand_soc soc; ++ const struct mtk_snand_soc_data *nfi_soc; ++ const struct mtk_ecc_soc_data *ecc_soc; ++ bool snfi_quad_spi; ++ bool quad_spi_op; ++ ++ const char *model; ++ uint64_t size; ++ uint64_t die_size; ++ uint32_t erasesize; ++ uint32_t writesize; ++ uint32_t oobsize; ++ ++ uint32_t num_dies; ++ snand_select_die_t select_die; ++ ++ uint8_t opcode_rfc; ++ uint8_t opcode_pl; ++ uint8_t dummy_rfc; ++ uint8_t mode_rfc; ++ uint8_t mode_pl; ++ ++ uint32_t writesize_mask; ++ uint32_t writesize_shift; ++ uint32_t erasesize_mask; ++ uint32_t erasesize_shift; ++ uint64_t die_mask; ++ uint32_t die_shift; ++ ++ uint32_t spare_per_sector; ++ uint32_t raw_sector_size; ++ uint32_t ecc_strength; ++ uint32_t ecc_steps; ++ uint32_t ecc_bytes; ++ uint32_t ecc_parity_bits; ++ ++ uint8_t *page_cache; /* Used by read/write page */ ++ uint8_t *buf_cache; /* Used by block bad/markbad & auto_oob */ ++}; ++ ++enum mtk_snand_log_category { ++ SNAND_LOG_NFI, ++ SNAND_LOG_SNFI, ++ SNAND_LOG_ECC, ++ SNAND_LOG_CHIP, ++ ++ __SNAND_LOG_CAT_MAX ++}; ++ ++int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes, ++ uint32_t msg_size); ++int mtk_snand_ecc_encoder_start(struct mtk_snand *snf); ++void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf); ++int mtk_snand_ecc_decoder_start(struct mtk_snand *snf); ++void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf); ++int mtk_ecc_wait_decoder_done(struct mtk_snand *snf); ++int mtk_ecc_check_decode_error(struct mtk_snand *snf, uint32_t page); ++ ++int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen, ++ uint8_t *in, uint32_t inlen); ++int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val); ++ ++int mtk_snand_log(struct mtk_snand_plat_dev *pdev, ++ enum mtk_snand_log_category cat, const char *fmt, ...); ++ ++#define snand_log_nfi(pdev, fmt, ...) \ ++ mtk_snand_log(pdev, SNAND_LOG_NFI, fmt, ##__VA_ARGS__) ++ ++#define snand_log_snfi(pdev, fmt, ...) \ ++ mtk_snand_log(pdev, SNAND_LOG_SNFI, fmt, ##__VA_ARGS__) ++ ++#define snand_log_ecc(pdev, fmt, ...) \ ++ mtk_snand_log(pdev, SNAND_LOG_ECC, fmt, ##__VA_ARGS__) ++ ++#define snand_log_chip(pdev, fmt, ...) \ ++ mtk_snand_log(pdev, SNAND_LOG_CHIP, fmt, ##__VA_ARGS__) ++ ++/* ffs64 */ ++static inline int mtk_snand_ffs64(uint64_t x) ++{ ++ if (!x) ++ return 0; ++ ++ if (!(x & 0xffffffff)) ++ return ffs((uint32_t)(x >> 32)) + 32; ++ ++ return ffs((uint32_t)(x & 0xffffffff)); ++} ++ ++/* NFI dummy commands */ ++#define NFI_CMD_DUMMY_READ 0x00 ++#define NFI_CMD_DUMMY_WRITE 0x80 ++ ++/* SPI-NAND opcodes */ ++#define SNAND_CMD_RESET 0xff ++#define SNAND_CMD_BLOCK_ERASE 0xd8 ++#define SNAND_CMD_READ_FROM_CACHE_QUAD 0xeb ++#define SNAND_CMD_WINBOND_SELECT_DIE 0xc2 ++#define SNAND_CMD_READ_FROM_CACHE_DUAL 0xbb ++#define SNAND_CMD_READID 0x9f ++#define SNAND_CMD_READ_FROM_CACHE_X4 0x6b ++#define SNAND_CMD_READ_FROM_CACHE_X2 0x3b ++#define SNAND_CMD_PROGRAM_LOAD_X4 0x32 ++#define SNAND_CMD_SET_FEATURE 0x1f ++#define SNAND_CMD_READ_TO_CACHE 0x13 ++#define SNAND_CMD_PROGRAM_EXECUTE 0x10 ++#define SNAND_CMD_GET_FEATURE 0x0f ++#define SNAND_CMD_READ_FROM_CACHE 0x0b ++#define SNAND_CMD_WRITE_ENABLE 0x06 ++#define SNAND_CMD_PROGRAM_LOAD 0x02 ++ ++/* SPI-NAND feature addresses */ ++#define SNAND_FEATURE_MICRON_DIE_ADDR 0xd0 ++#define SNAND_MICRON_DIE_SEL_1 BIT(6) ++ ++#define SNAND_FEATURE_STATUS_ADDR 0xc0 ++#define SNAND_STATUS_OIP BIT(0) ++#define SNAND_STATUS_WEL BIT(1) ++#define SNAND_STATUS_ERASE_FAIL BIT(2) ++#define SNAND_STATUS_PROGRAM_FAIL BIT(3) ++ ++#define SNAND_FEATURE_CONFIG_ADDR 0xb0 ++#define SNAND_FEATURE_QUAD_ENABLE BIT(0) ++#define SNAND_FEATURE_ECC_EN BIT(4) ++ ++#define SNAND_FEATURE_PROTECT_ADDR 0xa0 ++ ++#endif /* _MTK_SNAND_DEF_H_ */ +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-ecc.c +@@ -0,0 +1,264 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include "mtk-snand-def.h" ++ ++/* ECC registers */ ++#define ECC_ENCCON 0x000 ++#define ENC_EN BIT(0) ++ ++#define ECC_ENCCNFG 0x004 ++#define ENC_MS_S 16 ++#define ENC_BURST_EN BIT(8) ++#define ENC_TNUM_S 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_S 16 ++#define DEC_CON_S 12 ++#define DEC_CON_CORRECT 3 ++#define DEC_BURST_EN BIT(8) ++#define DEC_TNUM_S 0 ++ ++#define ECC_DECIDLE 0x10c ++#define DEC_IDLE BIT(0) ++ ++#define ECC_DECENUM0 0x114 ++#define ECC_DECENUM(n) (ECC_DECENUM0 + (n) * 4) ++ ++/* ECC_ENCIDLE & ECC_DECIDLE */ ++#define ECC_IDLE BIT(0) ++ ++/* ENC_MODE & DEC_MODE */ ++#define ECC_MODE_NFI 1 ++ ++#define ECC_TIMEOUT 500000 ++ ++static const uint8_t mt7622_ecc_caps[] = { 4, 6, 8, 10, 12 }; ++ ++static const uint8_t mt7986_ecc_caps[] = { ++ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 ++}; ++ ++static const uint32_t mt7622_ecc_regs[] = { ++ [ECC_DECDONE] = 0x11c, ++}; ++ ++static const uint32_t mt7986_ecc_regs[] = { ++ [ECC_DECDONE] = 0x124, ++}; ++ ++static const struct mtk_ecc_soc_data mtk_ecc_socs[__SNAND_SOC_MAX] = { ++ [SNAND_SOC_MT7622] = { ++ .ecc_caps = mt7622_ecc_caps, ++ .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps), ++ .regs = mt7622_ecc_regs, ++ .mode_shift = 4, ++ .errnum_bits = 5, ++ .errnum_shift = 5, ++ }, ++ [SNAND_SOC_MT7629] = { ++ .ecc_caps = mt7622_ecc_caps, ++ .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps), ++ .regs = mt7622_ecc_regs, ++ .mode_shift = 4, ++ .errnum_bits = 5, ++ .errnum_shift = 5, ++ }, ++ [SNAND_SOC_MT7986] = { ++ .ecc_caps = mt7986_ecc_caps, ++ .num_ecc_cap = ARRAY_SIZE(mt7986_ecc_caps), ++ .regs = mt7986_ecc_regs, ++ .mode_shift = 5, ++ .errnum_bits = 5, ++ .errnum_shift = 8, ++ }, ++}; ++ ++static inline uint32_t ecc_read32(struct mtk_snand *snf, uint32_t reg) ++{ ++ return readl(snf->ecc_base + reg); ++} ++ ++static inline void ecc_write32(struct mtk_snand *snf, uint32_t reg, ++ uint32_t val) ++{ ++ writel(val, snf->ecc_base + reg); ++} ++ ++static inline void ecc_write16(struct mtk_snand *snf, uint32_t reg, ++ uint16_t val) ++{ ++ writew(val, snf->ecc_base + reg); ++} ++ ++static int mtk_ecc_poll(struct mtk_snand *snf, uint32_t reg, uint32_t bits) ++{ ++ uint32_t val; ++ ++ return read16_poll_timeout(snf->ecc_base + reg, val, (val & bits), 0, ++ ECC_TIMEOUT); ++} ++ ++static int mtk_ecc_wait_idle(struct mtk_snand *snf, uint32_t reg) ++{ ++ int ret; ++ ++ ret = mtk_ecc_poll(snf, reg, ECC_IDLE); ++ if (ret) { ++ snand_log_ecc(snf->pdev, "ECC engine is busy\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes, ++ uint32_t msg_size) ++{ ++ uint32_t i, val, ecc_msg_bits, ecc_strength; ++ int ret; ++ ++ snf->ecc_soc = &mtk_ecc_socs[snf->soc]; ++ ++ snf->ecc_parity_bits = fls(1 + 8 * msg_size); ++ ecc_strength = max_ecc_bytes * 8 / snf->ecc_parity_bits; ++ ++ for (i = snf->ecc_soc->num_ecc_cap - 1; i >= 0; i--) { ++ if (snf->ecc_soc->ecc_caps[i] <= ecc_strength) ++ break; ++ } ++ ++ if (unlikely(i < 0)) { ++ snand_log_ecc(snf->pdev, "Page size %u+%u is not supported\n", ++ snf->writesize, snf->oobsize); ++ return -ENOTSUPP; ++ } ++ ++ snf->ecc_strength = snf->ecc_soc->ecc_caps[i]; ++ snf->ecc_bytes = DIV_ROUND_UP(snf->ecc_strength * snf->ecc_parity_bits, ++ 8); ++ ++ /* Encoder config */ ++ ecc_write16(snf, ECC_ENCCON, 0); ++ ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE); ++ if (ret) ++ return ret; ++ ++ ecc_msg_bits = msg_size * 8; ++ val = (ecc_msg_bits << ENC_MS_S) | ++ (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i; ++ ecc_write32(snf, ECC_ENCCNFG, val); ++ ++ /* Decoder config */ ++ ecc_write16(snf, ECC_DECCON, 0); ++ ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE); ++ if (ret) ++ return ret; ++ ++ ecc_msg_bits += snf->ecc_strength * snf->ecc_parity_bits; ++ val = DEC_EMPTY_EN | (ecc_msg_bits << DEC_CS_S) | ++ (DEC_CON_CORRECT << DEC_CON_S) | ++ (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i; ++ ecc_write32(snf, ECC_DECCNFG, val); ++ ++ return 0; ++} ++ ++int mtk_snand_ecc_encoder_start(struct mtk_snand *snf) ++{ ++ int ret; ++ ++ ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE); ++ if (ret) { ++ ecc_write16(snf, ECC_ENCCON, 0); ++ mtk_ecc_wait_idle(snf, ECC_ENCIDLE); ++ } ++ ++ ecc_write16(snf, ECC_ENCCON, ENC_EN); ++ ++ return 0; ++} ++ ++void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf) ++{ ++ mtk_ecc_wait_idle(snf, ECC_ENCIDLE); ++ ecc_write16(snf, ECC_ENCCON, 0); ++} ++ ++int mtk_snand_ecc_decoder_start(struct mtk_snand *snf) ++{ ++ int ret; ++ ++ ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE); ++ if (ret) { ++ ecc_write16(snf, ECC_DECCON, 0); ++ mtk_ecc_wait_idle(snf, ECC_DECIDLE); ++ } ++ ++ ecc_write16(snf, ECC_DECCON, DEC_EN); ++ ++ return 0; ++} ++ ++void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf) ++{ ++ mtk_ecc_wait_idle(snf, ECC_DECIDLE); ++ ecc_write16(snf, ECC_DECCON, 0); ++} ++ ++int mtk_ecc_wait_decoder_done(struct mtk_snand *snf) ++{ ++ uint16_t val, step_mask = (1 << snf->ecc_steps) - 1; ++ uint32_t reg = snf->ecc_soc->regs[ECC_DECDONE]; ++ int ret; ++ ++ ret = read16_poll_timeout(snf->ecc_base + reg, val, ++ (val & step_mask) == step_mask, 0, ++ ECC_TIMEOUT); ++ if (ret) ++ snand_log_ecc(snf->pdev, "ECC decoder is busy\n"); ++ ++ return ret; ++} ++ ++int mtk_ecc_check_decode_error(struct mtk_snand *snf, uint32_t page) ++{ ++ uint32_t i, regi, fi, errnum; ++ uint32_t errnum_shift = snf->ecc_soc->errnum_shift; ++ uint32_t errnum_mask = (1 << snf->ecc_soc->errnum_bits) - 1; ++ int ret = 0; ++ ++ for (i = 0; i < snf->ecc_steps; i++) { ++ regi = i / 4; ++ fi = i % 4; ++ ++ errnum = ecc_read32(snf, ECC_DECENUM(regi)); ++ errnum = (errnum >> (fi * errnum_shift)) & errnum_mask; ++ if (!errnum) ++ continue; ++ ++ if (errnum <= snf->ecc_strength) { ++ if (ret >= 0) ++ ret += errnum; ++ continue; ++ } ++ ++ snand_log_ecc(snf->pdev, ++ "Uncorrectable bitflips in page %u sect %u\n", ++ page, i); ++ ret = -EBADMSG; ++ } ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-ids.c +@@ -0,0 +1,511 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include "mtk-snand-def.h" ++ ++static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx); ++static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx); ++ ++#define SNAND_MEMORG_512M_2K_64 SNAND_MEMORG(2048, 64, 64, 512, 1, 1) ++#define SNAND_MEMORG_1G_2K_64 SNAND_MEMORG(2048, 64, 64, 1024, 1, 1) ++#define SNAND_MEMORG_2G_2K_64 SNAND_MEMORG(2048, 64, 64, 2048, 1, 1) ++#define SNAND_MEMORG_2G_2K_120 SNAND_MEMORG(2048, 120, 64, 2048, 1, 1) ++#define SNAND_MEMORG_4G_2K_64 SNAND_MEMORG(2048, 64, 64, 4096, 1, 1) ++#define SNAND_MEMORG_1G_2K_120 SNAND_MEMORG(2048, 120, 64, 1024, 1, 1) ++#define SNAND_MEMORG_1G_2K_128 SNAND_MEMORG(2048, 128, 64, 1024, 1, 1) ++#define SNAND_MEMORG_2G_2K_128 SNAND_MEMORG(2048, 128, 64, 2048, 1, 1) ++#define SNAND_MEMORG_4G_2K_128 SNAND_MEMORG(2048, 128, 64, 4096, 1, 1) ++#define SNAND_MEMORG_4G_4K_240 SNAND_MEMORG(4096, 240, 64, 2048, 1, 1) ++#define SNAND_MEMORG_4G_4K_256 SNAND_MEMORG(4096, 256, 64, 2048, 1, 1) ++#define SNAND_MEMORG_8G_4K_256 SNAND_MEMORG(4096, 256, 64, 4096, 1, 1) ++#define SNAND_MEMORG_2G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 2048, 2, 1) ++#define SNAND_MEMORG_2G_2K_64_2D SNAND_MEMORG(2048, 64, 64, 1024, 1, 2) ++#define SNAND_MEMORG_2G_2K_128_2P SNAND_MEMORG(2048, 128, 64, 2048, 2, 1) ++#define SNAND_MEMORG_4G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 4096, 2, 1) ++#define SNAND_MEMORG_4G_2K_128_2P_2D SNAND_MEMORG(2048, 128, 64, 2048, 2, 2) ++#define SNAND_MEMORG_8G_4K_256_2D SNAND_MEMORG(4096, 256, 64, 2048, 1, 2) ++ ++static const SNAND_IO_CAP(snand_cap_read_from_cache_quad, ++ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | ++ SPI_IO_1_4_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), ++ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), ++ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), ++ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 4)); ++ ++static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_q2d, ++ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | ++ SPI_IO_1_4_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), ++ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), ++ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), ++ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 2)); ++ ++static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_a8d, ++ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | ++ SPI_IO_1_4_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), ++ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), ++ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 8), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), ++ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 8)); ++ ++static const SNAND_IO_CAP(snand_cap_read_from_cache_x4, ++ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_1_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), ++ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8)); ++ ++static const SNAND_IO_CAP(snand_cap_read_from_cache_x4_only, ++ SPI_IO_1_1_1 | SPI_IO_1_1_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8)); ++ ++static const SNAND_IO_CAP(snand_cap_program_load_x1, ++ SPI_IO_1_1_1, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0)); ++ ++static const SNAND_IO_CAP(snand_cap_program_load_x4, ++ SPI_IO_1_1_1 | SPI_IO_1_1_4, ++ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0), ++ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_PROGRAM_LOAD_X4, 0)); ++ ++static const struct snand_flash_info snand_flash_ids[] = { ++ SNAND_INFO("W25N512GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x20), ++ SNAND_MEMORG_512M_2K_64, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("W25N01GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x21), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("W25M02GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xab, 0x21), ++ SNAND_MEMORG_2G_2K_64_2D, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4, ++ mtk_snand_winbond_select_die), ++ SNAND_INFO("W25N02KV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x22), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("GD5F1GQ4UAWxx", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x10), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F1GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd1), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F1GQ4UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd9), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F1GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf1), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F2GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd2), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F2GQ5UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x32), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_a8d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F2GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf2), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F4GQ4UBxIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd4), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F4GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf4), ++ SNAND_MEMORG_4G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F2GQ5UExxG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x52), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("GD5F4GQ4UCxIG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0xb4), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("MX35LF1GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x12), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF1G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x14), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX31LF1GE4BC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x1e), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF2GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x22), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF2G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x24), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF2GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x26), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF2G14AC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x20), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF4G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x35), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MX35LF4GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x37), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("MT29F1G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x12), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("MT29F1G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x14), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MT29F2G01AAAED", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x9f), ++ SNAND_MEMORG_2G_2K_64_2P, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("MT29F2G01ABAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x24), ++ SNAND_MEMORG_2G_2K_128_2P, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MT29F4G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x32), ++ SNAND_MEMORG_4G_2K_64_2P, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("MT29F4G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x34), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("MT29F4G01ADAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x36), ++ SNAND_MEMORG_4G_2K_128_2P_2D, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4, ++ mtk_snand_micron_select_die), ++ SNAND_INFO("MT29F8G01ADAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x46), ++ SNAND_MEMORG_8G_4K_256_2D, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4, ++ mtk_snand_micron_select_die), ++ ++ SNAND_INFO("TC58CVG0S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xc2), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("TC58CVG1S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcb), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("TC58CVG2S0HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcd), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x1), ++ SNAND_INFO("TC58CVG0S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe2), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("TC58CVG1S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xeb), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("TC58CVG2S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xed), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("TH58CVG3S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe4), ++ SNAND_MEMORG_8G_4K_256, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("F50L512M41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x20), ++ SNAND_MEMORG_512M_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("F50L1G41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("F50L1G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x01), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("F50L2G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x0a), ++ SNAND_MEMORG_2G_2K_64_2D, ++ &snand_cap_read_from_cache_quad, ++ &snand_cap_program_load_x4, ++ mtk_snand_winbond_select_die), ++ ++ SNAND_INFO("CS11G0T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x00), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G0G0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x10), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G0S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x20), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G1T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x01), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G1S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x21), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G2T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x02), ++ SNAND_MEMORG_4G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("CS11G2S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x22), ++ SNAND_MEMORG_4G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("EM73B044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x01), ++ SNAND_MEMORG_512M_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x11), ++ SNAND_MEMORG_1G_2K_120, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x09), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x18), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x19), ++ SNAND_MEMORG(2048, 64, 128, 512, 1, 1), ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1c), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1e), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044VCC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x22), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044VCF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x25), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x31), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0a), ++ SNAND_MEMORG_2G_2K_120, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x12), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x10), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x13), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x14), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x17), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCH", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1b), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1f), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x20), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCL", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2e), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x32), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x03), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0b), ++ SNAND_MEMORG_4G_4K_240, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x23), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2c), ++ SNAND_MEMORG_4G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2f), ++ SNAND_MEMORG_4G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73F044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x24), ++ SNAND_MEMORG_8G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73F044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2d), ++ SNAND_MEMORG_8G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73E044SNE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0e), ++ SNAND_MEMORG_8G_4K_256, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73C044SNG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0c), ++ SNAND_MEMORG_1G_2K_120, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("EM73D044VCN", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0f), ++ SNAND_MEMORG_2G_2K_64, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("FM35Q1GA", SNAND_ID(SNAND_ID_DYMMY, 0xe5, 0x71), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("PN26G01A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe1), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("PN26G02A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe2), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("IS37SML01G1", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("ATO25D1GA", SNAND_ID(SNAND_ID_DYMMY, 0x9b, 0x12), ++ SNAND_MEMORG_1G_2K_64, ++ &snand_cap_read_from_cache_x4_only, ++ &snand_cap_program_load_x4), ++ ++ SNAND_INFO("HYF1GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x51), ++ SNAND_MEMORG_1G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++ SNAND_INFO("HYF2GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x52), ++ SNAND_MEMORG_2G_2K_128, ++ &snand_cap_read_from_cache_quad_q2d, ++ &snand_cap_program_load_x4), ++}; ++ ++static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx) ++{ ++ uint8_t op[2]; ++ ++ if (dieidx > 1) { ++ snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx); ++ return -EINVAL; ++ } ++ ++ op[0] = SNAND_CMD_WINBOND_SELECT_DIE; ++ op[1] = (uint8_t)dieidx; ++ ++ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); ++} ++ ++static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx) ++{ ++ int ret; ++ ++ if (dieidx > 1) { ++ snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx); ++ return -EINVAL; ++ } ++ ++ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_MICRON_DIE_ADDR, ++ SNAND_MICRON_DIE_SEL_1); ++ if (ret) { ++ snand_log_chip(snf->pdev, ++ "Failed to set die selection feature\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type, ++ const uint8_t *id) ++{ ++ const struct snand_id *fid; ++ uint32_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(snand_flash_ids); i++) { ++ if (snand_flash_ids[i].id.type != type) ++ continue; ++ ++ fid = &snand_flash_ids[i].id; ++ if (memcmp(fid->id, id, fid->len)) ++ continue; ++ ++ return &snand_flash_ids[i]; ++ } ++ ++ return NULL; ++} +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-mtd.c +@@ -0,0 +1,524 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk-snand.h" ++ ++struct mtk_snand_mtd { ++ struct udevice *dev; ++ struct mtk_snand *snf; ++ struct mtk_snand_chip_info cinfo; ++ uint8_t *page_cache; ++}; ++ ++static const char snand_mtd_name_prefix[] = "spi-nand"; ++ ++static u32 snandidx; ++ ++static inline struct mtk_snand_mtd *mtd_to_msm(struct mtd_info *mtd) ++{ ++ return mtd->priv; ++} ++ ++static int mtk_snand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ u64 start_addr, end_addr; ++ int ret; ++ ++ /* Do not allow write past end of device */ ++ if ((instr->addr + instr->len) > mtd->size) { ++ pr_debug("%s: attempt to erase beyond end of device\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ start_addr = instr->addr & (~mtd->erasesize_mask); ++ end_addr = instr->addr + instr->len; ++ if (end_addr & mtd->erasesize_mask) { ++ end_addr = (end_addr + mtd->erasesize_mask) & ++ (~mtd->erasesize_mask); ++ } ++ ++ instr->state = MTD_ERASING; ++ ++ while (start_addr < end_addr) { ++ WATCHDOG_RESET(); ++ ++ if (mtk_snand_block_isbad(msm->snf, start_addr)) { ++ if (!instr->scrub) { ++ instr->fail_addr = start_addr; ++ ret = -EIO; ++ break; ++ } ++ } ++ ++ ret = mtk_snand_erase_block(msm->snf, start_addr); ++ if (ret) { ++ instr->fail_addr = start_addr; ++ break; ++ } ++ ++ start_addr += mtd->erasesize; ++ } ++ ++ if (ret) ++ instr->state = MTD_ERASE_FAILED; ++ else ++ instr->state = MTD_ERASE_DONE; ++ ++ if (ret) ++ ret = -EIO; ++ ++ return ret; ++} ++ ++static int mtk_snand_mtd_read_data(struct mtk_snand_mtd *msm, uint64_t addr, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_info *mtd = dev_get_uclass_priv(msm->dev); ++ size_t len, ooblen, maxooblen, chklen; ++ uint32_t col, ooboffs; ++ uint8_t *datcache, *oobcache; ++ bool raw = ops->mode == MTD_OPS_RAW ? true : false; ++ int ret; ++ ++ col = addr & mtd->writesize_mask; ++ addr &= ~mtd->writesize_mask; ++ maxooblen = mtd_oobavail(mtd, ops); ++ ooboffs = ops->ooboffs; ++ ooblen = ops->ooblen; ++ len = ops->len; ++ ++ datcache = len ? msm->page_cache : NULL; ++ oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL; ++ ++ ops->oobretlen = 0; ++ ops->retlen = 0; ++ ++ while (len || ooblen) { ++ WATCHDOG_RESET(); ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ ret = mtk_snand_read_page_auto_oob(msm->snf, addr, ++ datcache, oobcache, maxooblen, NULL, raw); ++ else ++ ret = mtk_snand_read_page(msm->snf, addr, datcache, ++ oobcache, raw); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (len) { ++ /* Move data */ ++ chklen = mtd->writesize - col; ++ if (chklen > len) ++ chklen = len; ++ ++ memcpy(ops->datbuf + ops->retlen, datcache + col, ++ chklen); ++ len -= chklen; ++ col = 0; /* (col + chklen) % */ ++ ops->retlen += chklen; ++ } ++ ++ if (ooblen) { ++ /* Move oob */ ++ chklen = maxooblen - ooboffs; ++ if (chklen > ooblen) ++ chklen = ooblen; ++ ++ memcpy(ops->oobbuf + ops->oobretlen, oobcache + ooboffs, ++ chklen); ++ ooblen -= chklen; ++ ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */ ++ ops->oobretlen += chklen; ++ } ++ ++ addr += mtd->writesize; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ uint32_t maxooblen; ++ ++ if (!ops->oobbuf && !ops->datbuf) { ++ if (ops->ooblen || ops->len) ++ return -EINVAL; ++ ++ return 0; ++ } ++ ++ switch (ops->mode) { ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_AUTO_OOB: ++ case MTD_OPS_RAW: ++ break; ++ default: ++ pr_debug("%s: unsupported oob mode: %u\n", __func__, ops->mode); ++ return -EINVAL; ++ } ++ ++ maxooblen = mtd_oobavail(mtd, ops); ++ ++ /* Do not allow read past end of device */ ++ if (ops->datbuf && (from + ops->len) > mtd->size) { ++ pr_debug("%s: attempt to read beyond end of device\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(ops->ooboffs >= maxooblen)) { ++ pr_debug("%s: attempt to start read outside oob\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(from >= mtd->size || ++ ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - ++ (from >> mtd->writesize_shift)) * maxooblen)) { ++ pr_debug("%s: attempt to read beyond end of device\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ return mtk_snand_mtd_read_data(msm, from, ops); ++} ++ ++static int mtk_snand_mtd_write_data(struct mtk_snand_mtd *msm, uint64_t addr, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_info *mtd = dev_get_uclass_priv(msm->dev); ++ size_t len, ooblen, maxooblen, chklen, oobwrlen; ++ uint32_t col, ooboffs; ++ uint8_t *datcache, *oobcache; ++ bool raw = ops->mode == MTD_OPS_RAW ? true : false; ++ int ret; ++ ++ col = addr & mtd->writesize_mask; ++ addr &= ~mtd->writesize_mask; ++ maxooblen = mtd_oobavail(mtd, ops); ++ ooboffs = ops->ooboffs; ++ ooblen = ops->ooblen; ++ len = ops->len; ++ ++ datcache = len ? msm->page_cache : NULL; ++ oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL; ++ ++ ops->oobretlen = 0; ++ ops->retlen = 0; ++ ++ while (len || ooblen) { ++ WATCHDOG_RESET(); ++ ++ if (len) { ++ /* Move data */ ++ chklen = mtd->writesize - col; ++ if (chklen > len) ++ chklen = len; ++ ++ memset(datcache, 0xff, col); ++ memcpy(datcache + col, ops->datbuf + ops->retlen, ++ chklen); ++ memset(datcache + col + chklen, 0xff, ++ mtd->writesize - col - chklen); ++ len -= chklen; ++ col = 0; /* (col + chklen) % */ ++ ops->retlen += chklen; ++ } ++ ++ oobwrlen = 0; ++ if (ooblen) { ++ /* Move oob */ ++ chklen = maxooblen - ooboffs; ++ if (chklen > ooblen) ++ chklen = ooblen; ++ ++ memset(oobcache, 0xff, ooboffs); ++ memcpy(oobcache + ooboffs, ++ ops->oobbuf + ops->oobretlen, chklen); ++ memset(oobcache + ooboffs + chklen, 0xff, ++ mtd->oobsize - ooboffs - chklen); ++ oobwrlen = chklen + ooboffs; ++ ooblen -= chklen; ++ ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */ ++ ops->oobretlen += chklen; ++ } ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ ret = mtk_snand_write_page_auto_oob(msm->snf, addr, ++ datcache, oobcache, oobwrlen, NULL, raw); ++ else ++ ret = mtk_snand_write_page(msm->snf, addr, datcache, ++ oobcache, raw); ++ ++ if (ret) ++ return ret; ++ ++ addr += mtd->writesize; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ uint32_t maxooblen; ++ ++ if (!ops->oobbuf && !ops->datbuf) { ++ if (ops->ooblen || ops->len) ++ return -EINVAL; ++ ++ return 0; ++ } ++ ++ switch (ops->mode) { ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_AUTO_OOB: ++ case MTD_OPS_RAW: ++ break; ++ default: ++ pr_debug("%s: unsupported oob mode: %u\n", __func__, ops->mode); ++ return -EINVAL; ++ } ++ ++ maxooblen = mtd_oobavail(mtd, ops); ++ ++ /* Do not allow write past end of device */ ++ if (ops->datbuf && (to + ops->len) > mtd->size) { ++ pr_debug("%s: attempt to write beyond end of device\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(ops->ooboffs >= maxooblen)) { ++ pr_debug("%s: attempt to start write outside oob\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(to >= mtd->size || ++ ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - ++ (to >> mtd->writesize_shift)) * maxooblen)) { ++ pr_debug("%s: attempt to write beyond end of device\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ return mtk_snand_mtd_write_data(msm, to, ops); ++} ++ ++static int mtk_snand_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t *retlen, u_char *buf) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .datbuf = buf, ++ .len = len, ++ }; ++ int ret; ++ ++ ret = mtk_snand_mtd_read_oob(mtd, from, &ops); ++ ++ if (retlen) ++ *retlen = ops.retlen; ++ ++ return ret; ++} ++ ++static int mtk_snand_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const u_char *buf) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .datbuf = (void *)buf, ++ .len = len, ++ }; ++ int ret; ++ ++ ret = mtk_snand_mtd_write_oob(mtd, to, &ops); ++ ++ if (retlen) ++ *retlen = ops.retlen; ++ ++ return ret; ++} ++ ++static int mtk_snand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ ++ return mtk_snand_block_isbad(msm->snf, offs); ++} ++ ++static int mtk_snand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ ++ return mtk_snand_block_markbad(msm->snf, offs); ++} ++ ++static int mtk_snand_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobecc) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ ++ if (section) ++ return -ERANGE; ++ ++ oobecc->offset = msm->cinfo.fdm_size * msm->cinfo.num_sectors; ++ oobecc->length = mtd->oobsize - oobecc->offset; ++ ++ return 0; ++} ++ ++static int mtk_snand_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobfree) ++{ ++ struct mtk_snand_mtd *msm = mtd_to_msm(mtd); ++ ++ if (section >= msm->cinfo.num_sectors) ++ return -ERANGE; ++ ++ oobfree->length = msm->cinfo.fdm_size - 1; ++ oobfree->offset = section * msm->cinfo.fdm_size + 1; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops mtk_snand_ooblayout = { ++ .ecc = mtk_snand_ooblayout_ecc, ++ .rfree = mtk_snand_ooblayout_free, ++}; ++ ++static int mtk_snand_mtd_probe(struct udevice *dev) ++{ ++ struct mtk_snand_mtd *msm = dev_get_priv(dev); ++ struct mtd_info *mtd = dev_get_uclass_priv(dev); ++ struct mtk_snand_platdata mtk_snand_pdata = {}; ++ size_t namelen; ++ fdt_addr_t base; ++ int ret; ++ ++ base = dev_read_addr_name(dev, "nfi"); ++ if (base == FDT_ADDR_T_NONE) ++ return -EINVAL; ++ mtk_snand_pdata.nfi_base = map_sysmem(base, 0); ++ ++ base = dev_read_addr_name(dev, "ecc"); ++ if (base == FDT_ADDR_T_NONE) ++ return -EINVAL; ++ mtk_snand_pdata.ecc_base = map_sysmem(base, 0); ++ ++ mtk_snand_pdata.soc = dev_get_driver_data(dev); ++ mtk_snand_pdata.quad_spi = dev_read_bool(dev, "quad-spi"); ++ ++ ret = mtk_snand_init(NULL, &mtk_snand_pdata, &msm->snf); ++ if (ret) ++ return ret; ++ ++ mtk_snand_get_chip_info(msm->snf, &msm->cinfo); ++ ++ msm->page_cache = malloc(msm->cinfo.pagesize + msm->cinfo.sparesize); ++ if (!msm->page_cache) { ++ printf("%s: failed to allocate memory for page cache\n", ++ __func__); ++ ret = -ENOMEM; ++ goto errout1; ++ } ++ ++ namelen = sizeof(snand_mtd_name_prefix) + 12; ++ ++ mtd->name = malloc(namelen); ++ if (!mtd->name) { ++ printf("%s: failed to allocate memory for MTD name\n", ++ __func__); ++ ret = -ENOMEM; ++ goto errout2; ++ } ++ ++ msm->dev = dev; ++ ++ snprintf(mtd->name, namelen, "%s%u", snand_mtd_name_prefix, snandidx++); ++ ++ mtd->priv = msm; ++ mtd->dev = dev; ++ mtd->type = MTD_NANDFLASH; ++ mtd->flags = MTD_CAP_NANDFLASH; ++ ++ mtd->size = msm->cinfo.chipsize; ++ mtd->erasesize = msm->cinfo.blocksize; ++ mtd->writesize = msm->cinfo.pagesize; ++ mtd->writebufsize = mtd->writesize; ++ mtd->oobsize = msm->cinfo.sparesize; ++ mtd->oobavail = msm->cinfo.num_sectors * (msm->cinfo.fdm_size - 1); ++ ++ mtd->ooblayout = &mtk_snand_ooblayout; ++ ++ mtd->ecc_strength = msm->cinfo.ecc_strength * msm->cinfo.num_sectors; ++ mtd->bitflip_threshold = (mtd->ecc_strength * 3) / 4; ++ mtd->ecc_step_size = msm->cinfo.sector_size; ++ ++ mtd->_read = mtk_snand_mtd_read; ++ mtd->_write = mtk_snand_mtd_write; ++ mtd->_erase = mtk_snand_mtd_erase; ++ mtd->_read_oob = mtk_snand_mtd_read_oob; ++ mtd->_write_oob = mtk_snand_mtd_write_oob; ++ mtd->_block_isbad = mtk_snand_mtd_block_isbad; ++ mtd->_block_markbad = mtk_snand_mtd_block_markbad; ++ ++ ret = add_mtd_device(mtd); ++ if (ret) { ++ printf("%s: failed to add SPI-NAND MTD device\n", __func__); ++ ret = -ENODEV; ++ goto errout3; ++ } ++ ++ printf("SPI-NAND: %s (%lluMB)\n", msm->cinfo.model, ++ msm->cinfo.chipsize >> 20); ++ ++ return 0; ++ ++errout3: ++ free(mtd->name); ++ ++errout2: ++ free(msm->page_cache); ++ ++errout1: ++ mtk_snand_cleanup(msm->snf); ++ ++ return ret; ++} ++ ++static const struct udevice_id mtk_snand_ids[] = { ++ { .compatible = "mediatek,mt7622-snand", .data = SNAND_SOC_MT7622 }, ++ { .compatible = "mediatek,mt7629-snand", .data = SNAND_SOC_MT7629 }, ++ { .compatible = "mediatek,mt7986-snand", .data = SNAND_SOC_MT7986 }, ++ { /* sentinel */ }, ++}; ++ ++U_BOOT_DRIVER(spinand) = { ++ .name = "mtk-snand", ++ .id = UCLASS_MTD, ++ .of_match = mtk_snand_ids, ++ .priv_auto = sizeof(struct mtk_snand_mtd), ++ .probe = mtk_snand_mtd_probe, ++}; +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-os.c +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include "mtk-snand-def.h" ++ ++int mtk_snand_log(struct mtk_snand_plat_dev *pdev, ++ enum mtk_snand_log_category cat, const char *fmt, ...) ++{ ++ const char *catname = ""; ++ va_list ap; ++ int ret; ++ ++ switch (cat) { ++ case SNAND_LOG_NFI: ++ catname = "NFI: "; ++ break; ++ case SNAND_LOG_SNFI: ++ catname = "SNFI: "; ++ break; ++ case SNAND_LOG_ECC: ++ catname = "ECC: "; ++ break; ++ default: ++ break; ++ } ++ ++ puts("SPI-NAND: "); ++ puts(catname); ++ ++ va_start(ap, fmt); ++ ret = vprintf(fmt, ap); ++ va_end(ap); ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-os.h +@@ -0,0 +1,120 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#ifndef _MTK_SNAND_OS_H_ ++#define _MTK_SNAND_OS_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef ARCH_DMA_MINALIGN ++#define ARCH_DMA_MINALIGN 64 ++#endif ++ ++struct mtk_snand_plat_dev { ++ ulong unused; ++}; ++ ++/* Polling helpers */ ++#define read16_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ ++ readw_poll_timeout((addr), (val), (cond), (timeout_us)) ++ ++#define read32_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ ++ readl_poll_timeout((addr), (val), (cond), (timeout_us)) ++ ++/* Timer helpers */ ++typedef uint64_t mtk_snand_time_t; ++ ++static inline mtk_snand_time_t timer_get_ticks(void) ++{ ++ return get_ticks(); ++} ++ ++static inline mtk_snand_time_t timer_time_to_tick(uint32_t timeout_us) ++{ ++ return usec_to_tick(timeout_us); ++} ++ ++static inline bool timer_is_timeout(mtk_snand_time_t start_tick, ++ mtk_snand_time_t timeout_tick) ++{ ++ return get_ticks() - start_tick > timeout_tick; ++} ++ ++/* Memory helpers */ ++static inline void *generic_mem_alloc(struct mtk_snand_plat_dev *pdev, ++ size_t size) ++{ ++ return calloc(1, size); ++} ++ ++static inline void generic_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr) ++{ ++ free(ptr); ++} ++ ++static inline void *dma_mem_alloc(struct mtk_snand_plat_dev *pdev, size_t size) ++{ ++ return memalign(ARCH_DMA_MINALIGN, size); ++} ++ ++static inline void dma_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr) ++{ ++ free(ptr); ++} ++ ++static inline int dma_mem_map(struct mtk_snand_plat_dev *pdev, void *vaddr, ++ uintptr_t *dma_addr, size_t size, bool to_device) ++{ ++ size_t cachelen = roundup(size, ARCH_DMA_MINALIGN); ++ uintptr_t endaddr = (uintptr_t)vaddr + cachelen; ++ ++ if (to_device) ++ flush_dcache_range((uintptr_t)vaddr, endaddr); ++ else ++ invalidate_dcache_range((uintptr_t)vaddr, endaddr); ++ ++ *dma_addr = (uintptr_t)vaddr; ++ ++ return 0; ++} ++ ++static inline void dma_mem_unmap(struct mtk_snand_plat_dev *pdev, ++ uintptr_t dma_addr, size_t size, ++ bool to_device) ++{ ++} ++ ++/* Interrupt helpers */ ++static inline void irq_completion_done(struct mtk_snand_plat_dev *pdev) ++{ ++} ++ ++static inline void irq_completion_init(struct mtk_snand_plat_dev *pdev) ++{ ++} ++ ++static inline int irq_completion_wait(struct mtk_snand_plat_dev *pdev, ++ void __iomem *reg, uint32_t bit, ++ uint32_t timeout_us) ++{ ++ uint32_t val; ++ ++ return read32_poll_timeout(reg, val, val & bit, 0, timeout_us); ++} ++ ++#endif /* _MTK_SNAND_OS_H_ */ +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand.c +@@ -0,0 +1,1776 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include "mtk-snand-def.h" ++ ++/* NFI registers */ ++#define NFI_CNFG 0x000 ++#define CNFG_OP_MODE_S 12 ++#define CNFG_OP_MODE_CUST 6 ++#define CNFG_OP_MODE_PROGRAM 3 ++#define CNFG_AUTO_FMT_EN BIT(9) ++#define CNFG_HW_ECC_EN BIT(8) ++#define CNFG_DMA_BURST_EN BIT(2) ++#define CNFG_READ_MODE BIT(1) ++#define CNFG_DMA_MODE BIT(0) ++ ++#define NFI_PAGEFMT 0x0004 ++#define NFI_SPARE_SIZE_LS_S 16 ++#define NFI_FDM_ECC_NUM_S 12 ++#define NFI_FDM_NUM_S 8 ++#define NFI_SPARE_SIZE_S 4 ++#define NFI_SEC_SEL_512 BIT(2) ++#define NFI_PAGE_SIZE_S 0 ++#define NFI_PAGE_SIZE_512_2K 0 ++#define NFI_PAGE_SIZE_2K_4K 1 ++#define NFI_PAGE_SIZE_4K_8K 2 ++#define NFI_PAGE_SIZE_8K_16K 3 ++ ++#define NFI_CON 0x008 ++#define CON_SEC_NUM_S 12 ++#define CON_BWR BIT(9) ++#define CON_BRD BIT(8) ++#define CON_NFI_RST BIT(1) ++#define CON_FIFO_FLUSH BIT(0) ++ ++#define NFI_INTR_EN 0x010 ++#define NFI_INTR_STA 0x014 ++#define NFI_IRQ_INTR_EN BIT(31) ++#define NFI_IRQ_CUS_READ BIT(8) ++#define NFI_IRQ_CUS_PG BIT(7) ++ ++#define NFI_CMD 0x020 ++ ++#define NFI_STRDATA 0x040 ++#define STR_DATA BIT(0) ++ ++#define NFI_STA 0x060 ++#define NFI_NAND_FSM GENMASK(28, 24) ++#define NFI_FSM GENMASK(19, 16) ++#define READ_EMPTY BIT(12) ++ ++#define NFI_FIFOSTA 0x064 ++#define FIFO_WR_REMAIN_S 8 ++#define FIFO_RD_REMAIN_S 0 ++ ++#define NFI_STRADDR 0x080 ++ ++#define NFI_FDM0L 0x0a0 ++#define NFI_FDM0M 0x0a4 ++#define NFI_FDML(n) (NFI_FDM0L + (n) * 8) ++#define NFI_FDMM(n) (NFI_FDM0M + (n) * 8) ++ ++#define NFI_DEBUG_CON1 0x220 ++#define WBUF_EN BIT(2) ++ ++#define NFI_MASTERSTA 0x224 ++#define MAS_ADDR GENMASK(11, 9) ++#define MAS_RD GENMASK(8, 6) ++#define MAS_WR GENMASK(5, 3) ++#define MAS_RDDLY GENMASK(2, 0) ++#define NFI_MASTERSTA_MASK_7622 (MAS_ADDR | MAS_RD | MAS_WR | MAS_RDDLY) ++#define AHB_BUS_BUSY BIT(1) ++#define BUS_BUSY BIT(0) ++#define NFI_MASTERSTA_MASK_7986 (AHB_BUS_BUSY | BUS_BUSY) ++ ++/* SNFI registers */ ++#define SNF_MAC_CTL 0x500 ++#define MAC_XIO_SEL BIT(4) ++#define SF_MAC_EN BIT(3) ++#define SF_TRIG BIT(2) ++#define WIP_READY BIT(1) ++#define WIP BIT(0) ++ ++#define SNF_MAC_OUTL 0x504 ++#define SNF_MAC_INL 0x508 ++ ++#define SNF_RD_CTL2 0x510 ++#define DATA_READ_DUMMY_S 8 ++#define DATA_READ_CMD_S 0 ++ ++#define SNF_RD_CTL3 0x514 ++ ++#define SNF_PG_CTL1 0x524 ++#define PG_LOAD_CMD_S 8 ++ ++#define SNF_PG_CTL2 0x528 ++ ++#define SNF_MISC_CTL 0x538 ++#define SW_RST BIT(28) ++#define FIFO_RD_LTC_S 25 ++#define PG_LOAD_X4_EN BIT(20) ++#define DATA_READ_MODE_S 16 ++#define DATA_READ_MODE GENMASK(18, 16) ++#define DATA_READ_MODE_X1 0 ++#define DATA_READ_MODE_X2 1 ++#define DATA_READ_MODE_X4 2 ++#define DATA_READ_MODE_DUAL 5 ++#define DATA_READ_MODE_QUAD 6 ++#define PG_LOAD_CUSTOM_EN BIT(7) ++#define DATARD_CUSTOM_EN BIT(6) ++#define CS_DESELECT_CYC_S 0 ++ ++#define SNF_MISC_CTL2 0x53c ++#define PROGRAM_LOAD_BYTE_NUM_S 16 ++#define READ_DATA_BYTE_NUM_S 11 ++ ++#define SNF_DLY_CTL3 0x548 ++#define SFCK_SAM_DLY_S 0 ++ ++#define SNF_STA_CTL1 0x550 ++#define CUS_PG_DONE BIT(28) ++#define CUS_READ_DONE BIT(27) ++#define SPI_STATE_S 0 ++#define SPI_STATE GENMASK(3, 0) ++ ++#define SNF_CFG 0x55c ++#define SPI_MODE BIT(0) ++ ++#define SNF_GPRAM 0x800 ++#define SNF_GPRAM_SIZE 0xa0 ++ ++#define SNFI_POLL_INTERVAL 1000000 ++ ++static const uint8_t mt7622_spare_sizes[] = { 16, 26, 27, 28 }; ++ ++static const uint8_t mt7986_spare_sizes[] = { ++ 16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, ++ 67, 74 ++}; ++ ++static const struct mtk_snand_soc_data mtk_snand_socs[__SNAND_SOC_MAX] = { ++ [SNAND_SOC_MT7622] = { ++ .sector_size = 512, ++ .max_sectors = 8, ++ .fdm_size = 8, ++ .fdm_ecc_size = 1, ++ .fifo_size = 32, ++ .bbm_swap = false, ++ .empty_page_check = false, ++ .mastersta_mask = NFI_MASTERSTA_MASK_7622, ++ .spare_sizes = mt7622_spare_sizes, ++ .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes) ++ }, ++ [SNAND_SOC_MT7629] = { ++ .sector_size = 512, ++ .max_sectors = 8, ++ .fdm_size = 8, ++ .fdm_ecc_size = 1, ++ .fifo_size = 32, ++ .bbm_swap = true, ++ .empty_page_check = false, ++ .mastersta_mask = NFI_MASTERSTA_MASK_7622, ++ .spare_sizes = mt7622_spare_sizes, ++ .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes) ++ }, ++ [SNAND_SOC_MT7986] = { ++ .sector_size = 1024, ++ .max_sectors = 16, ++ .fdm_size = 8, ++ .fdm_ecc_size = 1, ++ .fifo_size = 64, ++ .bbm_swap = true, ++ .empty_page_check = true, ++ .mastersta_mask = NFI_MASTERSTA_MASK_7986, ++ .spare_sizes = mt7986_spare_sizes, ++ .num_spare_size = ARRAY_SIZE(mt7986_spare_sizes) ++ }, ++}; ++ ++static inline uint32_t nfi_read32(struct mtk_snand *snf, uint32_t reg) ++{ ++ return readl(snf->nfi_base + reg); ++} ++ ++static inline void nfi_write32(struct mtk_snand *snf, uint32_t reg, ++ uint32_t val) ++{ ++ writel(val, snf->nfi_base + reg); ++} ++ ++static inline void nfi_write16(struct mtk_snand *snf, uint32_t reg, ++ uint16_t val) ++{ ++ writew(val, snf->nfi_base + reg); ++} ++ ++static inline void nfi_rmw32(struct mtk_snand *snf, uint32_t reg, uint32_t clr, ++ uint32_t set) ++{ ++ uint32_t val; ++ ++ val = readl(snf->nfi_base + reg); ++ val &= ~clr; ++ val |= set; ++ writel(val, snf->nfi_base + reg); ++} ++ ++static void nfi_write_data(struct mtk_snand *snf, uint32_t reg, ++ const uint8_t *data, uint32_t len) ++{ ++ uint32_t i, val = 0, es = sizeof(uint32_t); ++ ++ for (i = reg; i < reg + len; i++) { ++ val |= ((uint32_t)*data++) << (8 * (i % es)); ++ ++ if (i % es == es - 1 || i == reg + len - 1) { ++ nfi_write32(snf, i & ~(es - 1), val); ++ val = 0; ++ } ++ } ++} ++ ++static void nfi_read_data(struct mtk_snand *snf, uint32_t reg, uint8_t *data, ++ uint32_t len) ++{ ++ uint32_t i, val = 0, es = sizeof(uint32_t); ++ ++ for (i = reg; i < reg + len; i++) { ++ if (i == reg || i % es == 0) ++ val = nfi_read32(snf, i & ~(es - 1)); ++ ++ *data++ = (uint8_t)(val >> (8 * (i % es))); ++ } ++} ++ ++static inline void do_bm_swap(uint8_t *bm1, uint8_t *bm2) ++{ ++ uint8_t tmp = *bm1; ++ *bm1 = *bm2; ++ *bm2 = tmp; ++} ++ ++static void mtk_snand_bm_swap_raw(struct mtk_snand *snf) ++{ ++ uint32_t fdm_bbm_pos; ++ ++ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) ++ return; ++ ++ fdm_bbm_pos = (snf->ecc_steps - 1) * snf->raw_sector_size + ++ snf->nfi_soc->sector_size; ++ do_bm_swap(&snf->page_cache[fdm_bbm_pos], ++ &snf->page_cache[snf->writesize]); ++} ++ ++static void mtk_snand_bm_swap(struct mtk_snand *snf) ++{ ++ uint32_t buf_bbm_pos, fdm_bbm_pos; ++ ++ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) ++ return; ++ ++ buf_bbm_pos = snf->writesize - ++ (snf->ecc_steps - 1) * snf->spare_per_sector; ++ fdm_bbm_pos = snf->writesize + ++ (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size; ++ do_bm_swap(&snf->page_cache[fdm_bbm_pos], ++ &snf->page_cache[buf_bbm_pos]); ++} ++ ++static void mtk_snand_fdm_bm_swap_raw(struct mtk_snand *snf) ++{ ++ uint32_t fdm_bbm_pos1, fdm_bbm_pos2; ++ ++ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) ++ return; ++ ++ fdm_bbm_pos1 = snf->nfi_soc->sector_size; ++ fdm_bbm_pos2 = (snf->ecc_steps - 1) * snf->raw_sector_size + ++ snf->nfi_soc->sector_size; ++ do_bm_swap(&snf->page_cache[fdm_bbm_pos1], ++ &snf->page_cache[fdm_bbm_pos2]); ++} ++ ++static void mtk_snand_fdm_bm_swap(struct mtk_snand *snf) ++{ ++ uint32_t fdm_bbm_pos1, fdm_bbm_pos2; ++ ++ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) ++ return; ++ ++ fdm_bbm_pos1 = snf->writesize; ++ fdm_bbm_pos2 = snf->writesize + ++ (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size; ++ do_bm_swap(&snf->page_cache[fdm_bbm_pos1], ++ &snf->page_cache[fdm_bbm_pos2]); ++} ++ ++static int mtk_nfi_reset(struct mtk_snand *snf) ++{ ++ uint32_t val, fifo_mask; ++ int ret; ++ ++ nfi_write32(snf, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST); ++ ++ ret = read16_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val, ++ !(val & snf->nfi_soc->mastersta_mask), 0, ++ SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_nfi(snf->pdev, ++ "NFI master is still busy after reset\n"); ++ return ret; ++ } ++ ++ ret = read32_poll_timeout(snf->nfi_base + NFI_STA, val, ++ !(val & (NFI_FSM | NFI_NAND_FSM)), 0, ++ SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_nfi(snf->pdev, "Failed to reset NFI\n"); ++ return ret; ++ } ++ ++ fifo_mask = ((snf->nfi_soc->fifo_size - 1) << FIFO_RD_REMAIN_S) | ++ ((snf->nfi_soc->fifo_size - 1) << FIFO_WR_REMAIN_S); ++ ret = read16_poll_timeout(snf->nfi_base + NFI_FIFOSTA, val, ++ !(val & fifo_mask), 0, SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_nfi(snf->pdev, "NFI FIFOs are not empty\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snand_mac_reset(struct mtk_snand *snf) ++{ ++ int ret; ++ uint32_t val; ++ ++ nfi_rmw32(snf, SNF_MISC_CTL, 0, SW_RST); ++ ++ ret = read32_poll_timeout(snf->nfi_base + SNF_STA_CTL1, val, ++ !(val & SPI_STATE), 0, SNFI_POLL_INTERVAL); ++ if (ret) ++ snand_log_snfi(snf->pdev, "Failed to reset SNFI MAC\n"); ++ ++ nfi_write32(snf, SNF_MISC_CTL, (2 << FIFO_RD_LTC_S) | ++ (10 << CS_DESELECT_CYC_S)); ++ ++ return ret; ++} ++ ++static int mtk_snand_mac_trigger(struct mtk_snand *snf, uint32_t outlen, ++ uint32_t inlen) ++{ ++ int ret; ++ uint32_t val; ++ ++ nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN); ++ nfi_write32(snf, SNF_MAC_OUTL, outlen); ++ nfi_write32(snf, SNF_MAC_INL, inlen); ++ ++ nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN | SF_TRIG); ++ ++ ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val, ++ val & WIP_READY, 0, SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_snfi(snf->pdev, "Timed out waiting for WIP_READY\n"); ++ goto cleanup; ++ } ++ ++ ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val, ++ !(val & WIP), 0, SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_snfi(snf->pdev, ++ "Timed out waiting for WIP cleared\n"); ++ } ++ ++cleanup: ++ nfi_write32(snf, SNF_MAC_CTL, 0); ++ ++ return ret; ++} ++ ++int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen, ++ uint8_t *in, uint32_t inlen) ++{ ++ int ret; ++ ++ if (outlen + inlen > SNF_GPRAM_SIZE) ++ return -EINVAL; ++ ++ mtk_snand_mac_reset(snf); ++ ++ nfi_write_data(snf, SNF_GPRAM, out, outlen); ++ ++ ret = mtk_snand_mac_trigger(snf, outlen, inlen); ++ if (ret) ++ return ret; ++ ++ if (!inlen) ++ return 0; ++ ++ nfi_read_data(snf, SNF_GPRAM + outlen, in, inlen); ++ ++ return 0; ++} ++ ++static int mtk_snand_get_feature(struct mtk_snand *snf, uint32_t addr) ++{ ++ uint8_t op[2], val; ++ int ret; ++ ++ op[0] = SNAND_CMD_GET_FEATURE; ++ op[1] = (uint8_t)addr; ++ ++ ret = mtk_snand_mac_io(snf, op, sizeof(op), &val, 1); ++ if (ret) ++ return ret; ++ ++ return val; ++} ++ ++int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val) ++{ ++ uint8_t op[3]; ++ ++ op[0] = SNAND_CMD_SET_FEATURE; ++ op[1] = (uint8_t)addr; ++ op[2] = (uint8_t)val; ++ ++ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); ++} ++ ++static int mtk_snand_poll_status(struct mtk_snand *snf, uint32_t wait_us) ++{ ++ int val; ++ mtk_snand_time_t time_start, tmo; ++ ++ time_start = timer_get_ticks(); ++ tmo = timer_time_to_tick(wait_us); ++ ++ do { ++ val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR); ++ if (!(val & SNAND_STATUS_OIP)) ++ return val & (SNAND_STATUS_ERASE_FAIL | ++ SNAND_STATUS_PROGRAM_FAIL); ++ } while (!timer_is_timeout(time_start, tmo)); ++ ++ return -ETIMEDOUT; ++} ++ ++int mtk_snand_chip_reset(struct mtk_snand *snf) ++{ ++ uint8_t op = SNAND_CMD_RESET; ++ int ret; ++ ++ ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int mtk_snand_config_feature(struct mtk_snand *snf, uint8_t clr, ++ uint8_t set) ++{ ++ int val, newval; ++ int ret; ++ ++ val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR); ++ if (val < 0) { ++ snand_log_chip(snf->pdev, ++ "Failed to get configuration feature\n"); ++ return val; ++ } ++ ++ newval = (val & (~clr)) | set; ++ ++ if (newval == val) ++ return 0; ++ ++ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_CONFIG_ADDR, ++ (uint8_t)newval); ++ if (val < 0) { ++ snand_log_chip(snf->pdev, ++ "Failed to set configuration feature\n"); ++ return ret; ++ } ++ ++ val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR); ++ if (val < 0) { ++ snand_log_chip(snf->pdev, ++ "Failed to get configuration feature\n"); ++ return val; ++ } ++ ++ if (newval != val) ++ return -ENOTSUPP; ++ ++ return 0; ++} ++ ++static int mtk_snand_ondie_ecc_control(struct mtk_snand *snf, bool enable) ++{ ++ int ret; ++ ++ if (enable) ++ ret = mtk_snand_config_feature(snf, 0, SNAND_FEATURE_ECC_EN); ++ else ++ ret = mtk_snand_config_feature(snf, SNAND_FEATURE_ECC_EN, 0); ++ ++ if (ret) { ++ snand_log_chip(snf->pdev, "Failed to %s On-Die ECC engine\n", ++ enable ? "enable" : "disable"); ++ } ++ ++ return ret; ++} ++ ++static int mtk_snand_qspi_control(struct mtk_snand *snf, bool enable) ++{ ++ int ret; ++ ++ if (enable) { ++ ret = mtk_snand_config_feature(snf, 0, ++ SNAND_FEATURE_QUAD_ENABLE); ++ } else { ++ ret = mtk_snand_config_feature(snf, ++ SNAND_FEATURE_QUAD_ENABLE, 0); ++ } ++ ++ if (ret) { ++ snand_log_chip(snf->pdev, "Failed to %s quad spi\n", ++ enable ? "enable" : "disable"); ++ } ++ ++ return ret; ++} ++ ++static int mtk_snand_unlock(struct mtk_snand *snf) ++{ ++ int ret; ++ ++ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_PROTECT_ADDR, 0); ++ if (ret) { ++ snand_log_chip(snf->pdev, "Failed to set protection feature\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snand_write_enable(struct mtk_snand *snf) ++{ ++ uint8_t op = SNAND_CMD_WRITE_ENABLE; ++ int ret, val; ++ ++ ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0); ++ if (ret) ++ return ret; ++ ++ val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR); ++ if (val < 0) ++ return ret; ++ ++ if (val & SNAND_STATUS_WEL) ++ return 0; ++ ++ snand_log_chip(snf->pdev, "Failed to send write-enable command\n"); ++ ++ return -ENOTSUPP; ++} ++ ++static int mtk_snand_select_die(struct mtk_snand *snf, uint32_t dieidx) ++{ ++ if (!snf->select_die) ++ return 0; ++ ++ return snf->select_die(snf, dieidx); ++} ++ ++static uint64_t mtk_snand_select_die_address(struct mtk_snand *snf, ++ uint64_t addr) ++{ ++ uint32_t dieidx; ++ ++ if (!snf->select_die) ++ return addr; ++ ++ dieidx = addr >> snf->die_shift; ++ ++ mtk_snand_select_die(snf, dieidx); ++ ++ return addr & snf->die_mask; ++} ++ ++static uint32_t mtk_snand_get_plane_address(struct mtk_snand *snf, ++ uint32_t page) ++{ ++ uint32_t pages_per_block; ++ ++ pages_per_block = 1 << (snf->erasesize_shift - snf->writesize_shift); ++ ++ if (page & pages_per_block) ++ return 1 << (snf->writesize_shift + 1); ++ ++ return 0; ++} ++ ++static int mtk_snand_page_op(struct mtk_snand *snf, uint32_t page, uint8_t cmd) ++{ ++ uint8_t op[4]; ++ ++ op[0] = cmd; ++ op[1] = (page >> 16) & 0xff; ++ op[2] = (page >> 8) & 0xff; ++ op[3] = page & 0xff; ++ ++ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); ++} ++ ++static void mtk_snand_read_fdm(struct mtk_snand *snf, uint8_t *buf) ++{ ++ uint32_t vall, valm; ++ uint8_t *oobptr = buf; ++ int i, j; ++ ++ for (i = 0; i < snf->ecc_steps; i++) { ++ vall = nfi_read32(snf, NFI_FDML(i)); ++ valm = nfi_read32(snf, NFI_FDMM(i)); ++ ++ for (j = 0; j < snf->nfi_soc->fdm_size; j++) ++ oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8); ++ ++ oobptr += snf->nfi_soc->fdm_size; ++ } ++} ++ ++static int mtk_snand_read_cache(struct mtk_snand *snf, uint32_t page, bool raw) ++{ ++ uint32_t coladdr, rwbytes, mode, len; ++ uintptr_t dma_addr; ++ int ret; ++ ++ /* Column address with plane bit */ ++ coladdr = mtk_snand_get_plane_address(snf, page); ++ ++ mtk_snand_mac_reset(snf); ++ mtk_nfi_reset(snf); ++ ++ /* Command and dummy cycles */ ++ nfi_write32(snf, SNF_RD_CTL2, ++ ((uint32_t)snf->dummy_rfc << DATA_READ_DUMMY_S) | ++ (snf->opcode_rfc << DATA_READ_CMD_S)); ++ ++ /* Column address */ ++ nfi_write32(snf, SNF_RD_CTL3, coladdr); ++ ++ /* Set read mode */ ++ mode = (uint32_t)snf->mode_rfc << DATA_READ_MODE_S; ++ nfi_rmw32(snf, SNF_MISC_CTL, DATA_READ_MODE, mode | DATARD_CUSTOM_EN); ++ ++ /* Set bytes to read */ ++ rwbytes = snf->ecc_steps * snf->raw_sector_size; ++ nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) | ++ rwbytes); ++ ++ /* NFI read prepare */ ++ mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN; ++ nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_CUST << CNFG_OP_MODE_S) | ++ CNFG_DMA_BURST_EN | CNFG_READ_MODE | CNFG_DMA_MODE | mode); ++ ++ nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S)); ++ ++ /* Prepare for DMA read */ ++ len = snf->writesize + snf->oobsize; ++ ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, false); ++ if (ret) { ++ snand_log_nfi(snf->pdev, ++ "DMA map from device failed with %d\n", ret); ++ return ret; ++ } ++ ++ nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr); ++ ++ if (!raw) ++ mtk_snand_ecc_decoder_start(snf); ++ ++ /* Prepare for custom read interrupt */ ++ nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_READ); ++ irq_completion_init(snf->pdev); ++ ++ /* Trigger NFI into custom mode */ ++ nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_READ); ++ ++ /* Start DMA read */ ++ nfi_rmw32(snf, NFI_CON, 0, CON_BRD); ++ nfi_write16(snf, NFI_STRDATA, STR_DATA); ++ ++ /* Wait for operation finished */ ++ ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1, ++ CUS_READ_DONE, SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_nfi(snf->pdev, ++ "DMA timed out for reading from cache\n"); ++ goto cleanup; ++ } ++ ++ if (!raw) { ++ ret = mtk_ecc_wait_decoder_done(snf); ++ if (ret) ++ goto cleanup; ++ ++ mtk_snand_read_fdm(snf, snf->page_cache + snf->writesize); ++ ++ /* ++ * For new IPs, ecc error may occur on empty pages. ++ * Use an specific indication bit to check empty page. ++ */ ++ if (snf->nfi_soc->empty_page_check && ++ (nfi_read32(snf, NFI_STA) & READ_EMPTY)) ++ ret = 0; ++ else ++ ret = mtk_ecc_check_decode_error(snf, page); ++ ++ mtk_snand_ecc_decoder_stop(snf); ++ } ++ ++cleanup: ++ /* DMA cleanup */ ++ dma_mem_unmap(snf->pdev, dma_addr, len, false); ++ ++ /* Stop read */ ++ nfi_write32(snf, NFI_CON, 0); ++ ++ /* Clear SNF done flag */ ++ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE); ++ nfi_write32(snf, SNF_STA_CTL1, 0); ++ ++ /* Disable interrupt */ ++ nfi_read32(snf, NFI_INTR_STA); ++ nfi_write32(snf, NFI_INTR_EN, 0); ++ ++ nfi_rmw32(snf, SNF_MISC_CTL, DATARD_CUSTOM_EN, 0); ++ ++ return ret; ++} ++ ++static void mtk_snand_from_raw_page(struct mtk_snand *snf, void *buf, void *oob) ++{ ++ uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; ++ uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size; ++ uint8_t *bufptr = buf, *oobptr = oob, *raw_sector; ++ ++ for (i = 0; i < snf->ecc_steps; i++) { ++ raw_sector = snf->page_cache + i * snf->raw_sector_size; ++ ++ if (buf) { ++ memcpy(bufptr, raw_sector, snf->nfi_soc->sector_size); ++ bufptr += snf->nfi_soc->sector_size; ++ } ++ ++ raw_sector += snf->nfi_soc->sector_size; ++ ++ if (oob) { ++ memcpy(oobptr, raw_sector, snf->nfi_soc->fdm_size); ++ oobptr += snf->nfi_soc->fdm_size; ++ raw_sector += snf->nfi_soc->fdm_size; ++ ++ memcpy(eccptr, raw_sector, ecc_bytes); ++ eccptr += ecc_bytes; ++ } ++ } ++} ++ ++static int mtk_snand_do_read_page(struct mtk_snand *snf, uint64_t addr, ++ void *buf, void *oob, bool raw, bool format) ++{ ++ uint64_t die_addr; ++ uint32_t page; ++ int ret; ++ ++ die_addr = mtk_snand_select_die_address(snf, addr); ++ page = die_addr >> snf->writesize_shift; ++ ++ ret = mtk_snand_page_op(snf, page, SNAND_CMD_READ_TO_CACHE); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); ++ if (ret < 0) { ++ snand_log_chip(snf->pdev, "Read to cache command timed out\n"); ++ return ret; ++ } ++ ++ ret = mtk_snand_read_cache(snf, page, raw); ++ if (ret < 0 && ret != -EBADMSG) ++ return ret; ++ ++ if (raw) { ++ if (format) { ++ mtk_snand_bm_swap_raw(snf); ++ mtk_snand_fdm_bm_swap_raw(snf); ++ mtk_snand_from_raw_page(snf, buf, oob); ++ } else { ++ if (buf) ++ memcpy(buf, snf->page_cache, snf->writesize); ++ ++ if (oob) { ++ memset(oob, 0xff, snf->oobsize); ++ memcpy(oob, snf->page_cache + snf->writesize, ++ snf->ecc_steps * snf->spare_per_sector); ++ } ++ } ++ } else { ++ mtk_snand_bm_swap(snf); ++ mtk_snand_fdm_bm_swap(snf); ++ ++ if (buf) ++ memcpy(buf, snf->page_cache, snf->writesize); ++ ++ if (oob) { ++ memset(oob, 0xff, snf->oobsize); ++ memcpy(oob, snf->page_cache + snf->writesize, ++ snf->ecc_steps * snf->nfi_soc->fdm_size); ++ } ++ } ++ ++ return ret; ++} ++ ++int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf, ++ void *oob, bool raw) ++{ ++ if (!snf || (!buf && !oob)) ++ return -EINVAL; ++ ++ if (addr >= snf->size) ++ return -EINVAL; ++ ++ return mtk_snand_do_read_page(snf, addr, buf, oob, raw, true); ++} ++ ++static void mtk_snand_write_fdm(struct mtk_snand *snf, const uint8_t *buf) ++{ ++ uint32_t vall, valm, fdm_size = snf->nfi_soc->fdm_size; ++ const uint8_t *oobptr = buf; ++ int i, j; ++ ++ for (i = 0; i < snf->ecc_steps; i++) { ++ vall = 0; ++ valm = 0; ++ ++ for (j = 0; j < 8; j++) { ++ if (j < 4) ++ vall |= (j < fdm_size ? oobptr[j] : 0xff) ++ << (j * 8); ++ else ++ valm |= (j < fdm_size ? oobptr[j] : 0xff) ++ << ((j - 4) * 8); ++ } ++ ++ nfi_write32(snf, NFI_FDML(i), vall); ++ nfi_write32(snf, NFI_FDMM(i), valm); ++ ++ oobptr += fdm_size; ++ } ++} ++ ++static int mtk_snand_program_load(struct mtk_snand *snf, uint32_t page, ++ bool raw) ++{ ++ uint32_t coladdr, rwbytes, mode, len; ++ uintptr_t dma_addr; ++ int ret; ++ ++ /* Column address with plane bit */ ++ coladdr = mtk_snand_get_plane_address(snf, page); ++ ++ mtk_snand_mac_reset(snf); ++ mtk_nfi_reset(snf); ++ ++ /* Write FDM registers if necessary */ ++ if (!raw) ++ mtk_snand_write_fdm(snf, snf->page_cache + snf->writesize); ++ ++ /* Command */ ++ nfi_write32(snf, SNF_PG_CTL1, (snf->opcode_pl << PG_LOAD_CMD_S)); ++ ++ /* Column address */ ++ nfi_write32(snf, SNF_PG_CTL2, coladdr); ++ ++ /* Set write mode */ ++ mode = snf->mode_pl ? PG_LOAD_X4_EN : 0; ++ nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_X4_EN, mode | PG_LOAD_CUSTOM_EN); ++ ++ /* Set bytes to write */ ++ rwbytes = snf->ecc_steps * snf->raw_sector_size; ++ nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) | ++ rwbytes); ++ ++ /* NFI write prepare */ ++ mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN; ++ nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_PROGRAM << CNFG_OP_MODE_S) | ++ CNFG_DMA_BURST_EN | CNFG_DMA_MODE | mode); ++ ++ nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S)); ++ ++ /* Prepare for DMA write */ ++ len = snf->writesize + snf->oobsize; ++ ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, true); ++ if (ret) { ++ snand_log_nfi(snf->pdev, ++ "DMA map to device failed with %d\n", ret); ++ return ret; ++ } ++ ++ nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr); ++ ++ if (!raw) ++ mtk_snand_ecc_encoder_start(snf); ++ ++ /* Prepare for custom write interrupt */ ++ nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG); ++ irq_completion_init(snf->pdev); ++ ++ /* Trigger NFI into custom mode */ ++ nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE); ++ ++ /* Start DMA write */ ++ nfi_rmw32(snf, NFI_CON, 0, CON_BWR); ++ nfi_write16(snf, NFI_STRDATA, STR_DATA); ++ ++ /* Wait for operation finished */ ++ ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1, ++ CUS_PG_DONE, SNFI_POLL_INTERVAL); ++ if (ret) { ++ snand_log_nfi(snf->pdev, ++ "DMA timed out for program load\n"); ++ goto cleanup; ++ } ++ ++ if (!raw) ++ mtk_snand_ecc_encoder_stop(snf); ++ ++cleanup: ++ /* DMA cleanup */ ++ dma_mem_unmap(snf->pdev, dma_addr, len, true); ++ ++ /* Stop write */ ++ nfi_write16(snf, NFI_CON, 0); ++ ++ /* Clear SNF done flag */ ++ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_PG_DONE); ++ nfi_write32(snf, SNF_STA_CTL1, 0); ++ ++ /* Disable interrupt */ ++ nfi_read32(snf, NFI_INTR_STA); ++ nfi_write32(snf, NFI_INTR_EN, 0); ++ ++ nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_CUSTOM_EN, 0); ++ ++ return ret; ++} ++ ++static void mtk_snand_to_raw_page(struct mtk_snand *snf, ++ const void *buf, const void *oob, ++ bool empty_ecc) ++{ ++ uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; ++ const uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size; ++ const uint8_t *bufptr = buf, *oobptr = oob; ++ uint8_t *raw_sector; ++ ++ memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize); ++ for (i = 0; i < snf->ecc_steps; i++) { ++ raw_sector = snf->page_cache + i * snf->raw_sector_size; ++ ++ if (buf) { ++ memcpy(raw_sector, bufptr, snf->nfi_soc->sector_size); ++ bufptr += snf->nfi_soc->sector_size; ++ } ++ ++ raw_sector += snf->nfi_soc->sector_size; ++ ++ if (oob) { ++ memcpy(raw_sector, oobptr, snf->nfi_soc->fdm_size); ++ oobptr += snf->nfi_soc->fdm_size; ++ raw_sector += snf->nfi_soc->fdm_size; ++ ++ if (empty_ecc) ++ memset(raw_sector, 0xff, ecc_bytes); ++ else ++ memcpy(raw_sector, eccptr, ecc_bytes); ++ eccptr += ecc_bytes; ++ } ++ } ++} ++ ++static bool mtk_snand_is_empty_page(struct mtk_snand *snf, const void *buf, ++ const void *oob) ++{ ++ const uint8_t *p = buf; ++ uint32_t i, j; ++ ++ if (buf) { ++ for (i = 0; i < snf->writesize; i++) { ++ if (p[i] != 0xff) ++ return false; ++ } ++ } ++ ++ if (oob) { ++ for (j = 0; j < snf->ecc_steps; j++) { ++ p = oob + j * snf->nfi_soc->fdm_size; ++ ++ for (i = 0; i < snf->nfi_soc->fdm_ecc_size; i++) { ++ if (p[i] != 0xff) ++ return false; ++ } ++ } ++ } ++ ++ return true; ++} ++ ++static int mtk_snand_do_write_page(struct mtk_snand *snf, uint64_t addr, ++ const void *buf, const void *oob, ++ bool raw, bool format) ++{ ++ uint64_t die_addr; ++ bool empty_ecc = false; ++ uint32_t page; ++ int ret; ++ ++ die_addr = mtk_snand_select_die_address(snf, addr); ++ page = die_addr >> snf->writesize_shift; ++ ++ if (!raw && mtk_snand_is_empty_page(snf, buf, oob)) { ++ /* ++ * If the data in the page to be ecc-ed is full 0xff, ++ * change to raw write mode ++ */ ++ raw = true; ++ format = true; ++ ++ /* fill ecc parity code region with 0xff */ ++ empty_ecc = true; ++ } ++ ++ if (raw) { ++ if (format) { ++ mtk_snand_to_raw_page(snf, buf, oob, empty_ecc); ++ mtk_snand_fdm_bm_swap_raw(snf); ++ mtk_snand_bm_swap_raw(snf); ++ } else { ++ memset(snf->page_cache, 0xff, ++ snf->writesize + snf->oobsize); ++ ++ if (buf) ++ memcpy(snf->page_cache, buf, snf->writesize); ++ ++ if (oob) { ++ memcpy(snf->page_cache + snf->writesize, oob, ++ snf->ecc_steps * snf->spare_per_sector); ++ } ++ } ++ } else { ++ memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize); ++ if (buf) ++ memcpy(snf->page_cache, buf, snf->writesize); ++ ++ if (oob) { ++ memcpy(snf->page_cache + snf->writesize, oob, ++ snf->ecc_steps * snf->nfi_soc->fdm_size); ++ } ++ ++ mtk_snand_fdm_bm_swap(snf); ++ mtk_snand_bm_swap(snf); ++ } ++ ++ ret = mtk_snand_write_enable(snf); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_program_load(snf, page, raw); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_page_op(snf, page, SNAND_CMD_PROGRAM_EXECUTE); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); ++ if (ret < 0) { ++ snand_log_chip(snf->pdev, ++ "Page program command timed out on page %u\n", ++ page); ++ return ret; ++ } ++ ++ if (ret & SNAND_STATUS_PROGRAM_FAIL) { ++ snand_log_chip(snf->pdev, ++ "Page program failed on page %u\n", page); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf, ++ const void *oob, bool raw) ++{ ++ if (!snf || (!buf && !oob)) ++ return -EINVAL; ++ ++ if (addr >= snf->size) ++ return -EINVAL; ++ ++ return mtk_snand_do_write_page(snf, addr, buf, oob, raw, true); ++} ++ ++int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr) ++{ ++ uint64_t die_addr; ++ uint32_t page, block; ++ int ret; ++ ++ if (!snf) ++ return -EINVAL; ++ ++ if (addr >= snf->size) ++ return -EINVAL; ++ ++ die_addr = mtk_snand_select_die_address(snf, addr); ++ block = die_addr >> snf->erasesize_shift; ++ page = block << (snf->erasesize_shift - snf->writesize_shift); ++ ++ ret = mtk_snand_write_enable(snf); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_page_op(snf, page, SNAND_CMD_BLOCK_ERASE); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); ++ if (ret < 0) { ++ snand_log_chip(snf->pdev, ++ "Block erase command timed out on block %u\n", ++ block); ++ return ret; ++ } ++ ++ if (ret & SNAND_STATUS_ERASE_FAIL) { ++ snand_log_chip(snf->pdev, ++ "Block erase failed on block %u\n", block); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snand_block_isbad_std(struct mtk_snand *snf, uint64_t addr) ++{ ++ int ret; ++ ++ ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true, ++ false); ++ if (ret && ret != -EBADMSG) ++ return ret; ++ ++ return snf->buf_cache[0] != 0xff; ++} ++ ++static int mtk_snand_block_isbad_mtk(struct mtk_snand *snf, uint64_t addr) ++{ ++ int ret; ++ ++ ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true, ++ true); ++ if (ret && ret != -EBADMSG) ++ return ret; ++ ++ return snf->buf_cache[0] != 0xff; ++} ++ ++int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr) ++{ ++ if (!snf) ++ return -EINVAL; ++ ++ if (addr >= snf->size) ++ return -EINVAL; ++ ++ addr &= ~snf->erasesize_mask; ++ ++ if (snf->nfi_soc->bbm_swap) ++ return mtk_snand_block_isbad_std(snf, addr); ++ ++ return mtk_snand_block_isbad_mtk(snf, addr); ++} ++ ++static int mtk_snand_block_markbad_std(struct mtk_snand *snf, uint64_t addr) ++{ ++ /* Standard BBM position */ ++ memset(snf->buf_cache, 0xff, snf->oobsize); ++ snf->buf_cache[0] = 0; ++ ++ return mtk_snand_do_write_page(snf, addr, NULL, snf->buf_cache, true, ++ false); ++} ++ ++static int mtk_snand_block_markbad_mtk(struct mtk_snand *snf, uint64_t addr) ++{ ++ /* Write the whole page with zeros */ ++ memset(snf->buf_cache, 0, snf->writesize + snf->oobsize); ++ ++ return mtk_snand_do_write_page(snf, addr, snf->buf_cache, ++ snf->buf_cache + snf->writesize, true, ++ true); ++} ++ ++int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr) ++{ ++ if (!snf) ++ return -EINVAL; ++ ++ if (addr >= snf->size) ++ return -EINVAL; ++ ++ addr &= ~snf->erasesize_mask; ++ ++ if (snf->nfi_soc->bbm_swap) ++ return mtk_snand_block_markbad_std(snf, addr); ++ ++ return mtk_snand_block_markbad_mtk(snf, addr); ++} ++ ++int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw, ++ const uint8_t *oobbuf, size_t ooblen) ++{ ++ size_t len = ooblen, sect_fdm_len; ++ const uint8_t *oob = oobbuf; ++ uint32_t step = 0; ++ ++ if (!snf || !oobraw || !oob) ++ return -EINVAL; ++ ++ while (len && step < snf->ecc_steps) { ++ sect_fdm_len = snf->nfi_soc->fdm_size - 1; ++ if (sect_fdm_len > len) ++ sect_fdm_len = len; ++ ++ memcpy(oobraw + step * snf->nfi_soc->fdm_size + 1, oob, ++ sect_fdm_len); ++ ++ len -= sect_fdm_len; ++ oob += sect_fdm_len; ++ step++; ++ } ++ ++ return len; ++} ++ ++int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf, ++ size_t ooblen, const uint8_t *oobraw) ++{ ++ size_t len = ooblen, sect_fdm_len; ++ uint8_t *oob = oobbuf; ++ uint32_t step = 0; ++ ++ if (!snf || !oobraw || !oob) ++ return -EINVAL; ++ ++ while (len && step < snf->ecc_steps) { ++ sect_fdm_len = snf->nfi_soc->fdm_size - 1; ++ if (sect_fdm_len > len) ++ sect_fdm_len = len; ++ ++ memcpy(oob, oobraw + step * snf->nfi_soc->fdm_size + 1, ++ sect_fdm_len); ++ ++ len -= sect_fdm_len; ++ oob += sect_fdm_len; ++ step++; ++ } ++ ++ return len; ++} ++ ++int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr, ++ void *buf, void *oob, size_t ooblen, ++ size_t *actualooblen, bool raw) ++{ ++ int ret, oobremain; ++ ++ if (!snf) ++ return -EINVAL; ++ ++ if (!oob) ++ return mtk_snand_read_page(snf, addr, buf, NULL, raw); ++ ++ ret = mtk_snand_read_page(snf, addr, buf, snf->buf_cache, raw); ++ if (ret && ret != -EBADMSG) { ++ if (actualooblen) ++ *actualooblen = 0; ++ return ret; ++ } ++ ++ oobremain = mtk_snand_transfer_oob(snf, oob, ooblen, snf->buf_cache); ++ if (actualooblen) ++ *actualooblen = ooblen - oobremain; ++ ++ return ret; ++} ++ ++int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr, ++ const void *buf, const void *oob, ++ size_t ooblen, size_t *actualooblen, bool raw) ++{ ++ int oobremain; ++ ++ if (!snf) ++ return -EINVAL; ++ ++ if (!oob) ++ return mtk_snand_write_page(snf, addr, buf, NULL, raw); ++ ++ memset(snf->buf_cache, 0xff, snf->oobsize); ++ oobremain = mtk_snand_fill_oob(snf, snf->buf_cache, oob, ooblen); ++ if (actualooblen) ++ *actualooblen = ooblen - oobremain; ++ ++ return mtk_snand_write_page(snf, addr, buf, snf->buf_cache, raw); ++} ++ ++int mtk_snand_get_chip_info(struct mtk_snand *snf, ++ struct mtk_snand_chip_info *info) ++{ ++ if (!snf || !info) ++ return -EINVAL; ++ ++ info->model = snf->model; ++ info->chipsize = snf->size; ++ info->blocksize = snf->erasesize; ++ info->pagesize = snf->writesize; ++ info->sparesize = snf->oobsize; ++ info->spare_per_sector = snf->spare_per_sector; ++ info->fdm_size = snf->nfi_soc->fdm_size; ++ info->fdm_ecc_size = snf->nfi_soc->fdm_ecc_size; ++ info->num_sectors = snf->ecc_steps; ++ info->sector_size = snf->nfi_soc->sector_size; ++ info->ecc_strength = snf->ecc_strength; ++ info->ecc_bytes = snf->ecc_bytes; ++ ++ return 0; ++} ++ ++int mtk_snand_irq_process(struct mtk_snand *snf) ++{ ++ uint32_t sta, ien; ++ ++ if (!snf) ++ return -EINVAL; ++ ++ sta = nfi_read32(snf, NFI_INTR_STA); ++ ien = nfi_read32(snf, NFI_INTR_EN); ++ ++ if (!(sta & ien)) ++ return 0; ++ ++ nfi_write32(snf, NFI_INTR_EN, 0); ++ irq_completion_done(snf->pdev); ++ ++ return 1; ++} ++ ++static int mtk_snand_select_spare_per_sector(struct mtk_snand *snf) ++{ ++ uint32_t spare_per_step = snf->oobsize / snf->ecc_steps; ++ int i, mul = 1; ++ ++ /* ++ * If we're using the 1KB sector size, HW will automatically ++ * double the spare size. So we should only use half of the value. ++ */ ++ if (snf->nfi_soc->sector_size == 1024) ++ mul = 2; ++ ++ spare_per_step /= mul; ++ ++ for (i = snf->nfi_soc->num_spare_size - 1; i >= 0; i--) { ++ if (snf->nfi_soc->spare_sizes[i] <= spare_per_step) { ++ snf->spare_per_sector = snf->nfi_soc->spare_sizes[i]; ++ snf->spare_per_sector *= mul; ++ return i; ++ } ++ } ++ ++ snand_log_nfi(snf->pdev, ++ "Page size %u+%u is not supported\n", snf->writesize, ++ snf->oobsize); ++ ++ return -1; ++} ++ ++static int mtk_snand_pagefmt_setup(struct mtk_snand *snf) ++{ ++ uint32_t spare_size_idx, spare_size_shift, pagesize_idx; ++ uint32_t sector_size_512; ++ ++ if (snf->nfi_soc->sector_size == 512) { ++ sector_size_512 = NFI_SEC_SEL_512; ++ spare_size_shift = NFI_SPARE_SIZE_S; ++ } else { ++ sector_size_512 = 0; ++ spare_size_shift = NFI_SPARE_SIZE_LS_S; ++ } ++ ++ switch (snf->writesize) { ++ case SZ_512: ++ pagesize_idx = NFI_PAGE_SIZE_512_2K; ++ break; ++ case SZ_2K: ++ if (snf->nfi_soc->sector_size == 512) ++ pagesize_idx = NFI_PAGE_SIZE_2K_4K; ++ else ++ pagesize_idx = NFI_PAGE_SIZE_512_2K; ++ break; ++ case SZ_4K: ++ if (snf->nfi_soc->sector_size == 512) ++ pagesize_idx = NFI_PAGE_SIZE_4K_8K; ++ else ++ pagesize_idx = NFI_PAGE_SIZE_2K_4K; ++ break; ++ case SZ_8K: ++ if (snf->nfi_soc->sector_size == 512) ++ pagesize_idx = NFI_PAGE_SIZE_8K_16K; ++ else ++ pagesize_idx = NFI_PAGE_SIZE_4K_8K; ++ break; ++ case SZ_16K: ++ pagesize_idx = NFI_PAGE_SIZE_8K_16K; ++ break; ++ default: ++ snand_log_nfi(snf->pdev, "Page size %u is not supported\n", ++ snf->writesize); ++ return -ENOTSUPP; ++ } ++ ++ spare_size_idx = mtk_snand_select_spare_per_sector(snf); ++ if (unlikely(spare_size_idx < 0)) ++ return -ENOTSUPP; ++ ++ snf->raw_sector_size = snf->nfi_soc->sector_size + ++ snf->spare_per_sector; ++ ++ /* Setup page format */ ++ nfi_write32(snf, NFI_PAGEFMT, ++ (snf->nfi_soc->fdm_ecc_size << NFI_FDM_ECC_NUM_S) | ++ (snf->nfi_soc->fdm_size << NFI_FDM_NUM_S) | ++ (spare_size_idx << spare_size_shift) | ++ (pagesize_idx << NFI_PAGE_SIZE_S) | ++ sector_size_512); ++ ++ return 0; ++} ++ ++static enum snand_flash_io mtk_snand_select_opcode(struct mtk_snand *snf, ++ uint32_t snfi_caps, uint8_t *opcode, ++ uint8_t *dummy, ++ const struct snand_io_cap *op_cap) ++{ ++ uint32_t i, caps; ++ ++ caps = snfi_caps & op_cap->caps; ++ ++ i = fls(caps); ++ if (i > 0) { ++ *opcode = op_cap->opcodes[i - 1].opcode; ++ if (dummy) ++ *dummy = op_cap->opcodes[i - 1].dummy; ++ return i - 1; ++ } ++ ++ return __SNAND_IO_MAX; ++} ++ ++static int mtk_snand_select_opcode_rfc(struct mtk_snand *snf, ++ uint32_t snfi_caps, ++ const struct snand_io_cap *op_cap) ++{ ++ enum snand_flash_io idx; ++ ++ static const uint8_t rfc_modes[__SNAND_IO_MAX] = { ++ [SNAND_IO_1_1_1] = DATA_READ_MODE_X1, ++ [SNAND_IO_1_1_2] = DATA_READ_MODE_X2, ++ [SNAND_IO_1_2_2] = DATA_READ_MODE_DUAL, ++ [SNAND_IO_1_1_4] = DATA_READ_MODE_X4, ++ [SNAND_IO_1_4_4] = DATA_READ_MODE_QUAD, ++ }; ++ ++ idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_rfc, ++ &snf->dummy_rfc, op_cap); ++ if (idx >= __SNAND_IO_MAX) { ++ snand_log_snfi(snf->pdev, ++ "No capable opcode for read from cache\n"); ++ return -ENOTSUPP; ++ } ++ ++ snf->mode_rfc = rfc_modes[idx]; ++ ++ if (idx == SNAND_IO_1_1_4 || idx == SNAND_IO_1_4_4) ++ snf->quad_spi_op = true; ++ ++ return 0; ++} ++ ++static int mtk_snand_select_opcode_pl(struct mtk_snand *snf, uint32_t snfi_caps, ++ const struct snand_io_cap *op_cap) ++{ ++ enum snand_flash_io idx; ++ ++ static const uint8_t pl_modes[__SNAND_IO_MAX] = { ++ [SNAND_IO_1_1_1] = 0, ++ [SNAND_IO_1_1_4] = 1, ++ }; ++ ++ idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_pl, ++ NULL, op_cap); ++ if (idx >= __SNAND_IO_MAX) { ++ snand_log_snfi(snf->pdev, ++ "No capable opcode for program load\n"); ++ return -ENOTSUPP; ++ } ++ ++ snf->mode_pl = pl_modes[idx]; ++ ++ if (idx == SNAND_IO_1_1_4) ++ snf->quad_spi_op = true; ++ ++ return 0; ++} ++ ++static int mtk_snand_setup(struct mtk_snand *snf, ++ const struct snand_flash_info *snand_info) ++{ ++ const struct snand_mem_org *memorg = &snand_info->memorg; ++ uint32_t i, msg_size, snfi_caps; ++ int ret; ++ ++ /* Calculate flash memory organization */ ++ snf->model = snand_info->model; ++ snf->writesize = memorg->pagesize; ++ snf->oobsize = memorg->sparesize; ++ snf->erasesize = snf->writesize * memorg->pages_per_block; ++ snf->die_size = (uint64_t)snf->erasesize * memorg->blocks_per_die; ++ snf->size = snf->die_size * memorg->ndies; ++ snf->num_dies = memorg->ndies; ++ ++ snf->writesize_mask = snf->writesize - 1; ++ snf->erasesize_mask = snf->erasesize - 1; ++ snf->die_mask = snf->die_size - 1; ++ ++ snf->writesize_shift = ffs(snf->writesize) - 1; ++ snf->erasesize_shift = ffs(snf->erasesize) - 1; ++ snf->die_shift = mtk_snand_ffs64(snf->die_size) - 1; ++ ++ snf->select_die = snand_info->select_die; ++ ++ /* Determine opcodes for read from cache/program load */ ++ snfi_caps = SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2; ++ if (snf->snfi_quad_spi) ++ snfi_caps |= SPI_IO_1_1_4 | SPI_IO_1_4_4; ++ ++ ret = mtk_snand_select_opcode_rfc(snf, snfi_caps, snand_info->cap_rd); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snand_select_opcode_pl(snf, snfi_caps, snand_info->cap_pl); ++ if (ret) ++ return ret; ++ ++ /* ECC and page format */ ++ snf->ecc_steps = snf->writesize / snf->nfi_soc->sector_size; ++ if (snf->ecc_steps > snf->nfi_soc->max_sectors) { ++ snand_log_nfi(snf->pdev, "Page size %u is not supported\n", ++ snf->writesize); ++ return -ENOTSUPP; ++ } ++ ++ ret = mtk_snand_pagefmt_setup(snf); ++ if (ret) ++ return ret; ++ ++ msg_size = snf->nfi_soc->sector_size + snf->nfi_soc->fdm_ecc_size; ++ ret = mtk_ecc_setup(snf, snf->nfi_base + NFI_FDM0L, ++ snf->spare_per_sector - snf->nfi_soc->fdm_size, ++ msg_size); ++ if (ret) ++ return ret; ++ ++ nfi_write16(snf, NFI_CNFG, 0); ++ ++ /* Tuning options */ ++ nfi_write16(snf, NFI_DEBUG_CON1, WBUF_EN); ++ nfi_write32(snf, SNF_DLY_CTL3, (40 << SFCK_SAM_DLY_S)); ++ ++ /* Interrupts */ ++ nfi_read32(snf, NFI_INTR_STA); ++ nfi_write32(snf, NFI_INTR_EN, 0); ++ ++ /* Clear SNF done flag */ ++ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE | CUS_PG_DONE); ++ nfi_write32(snf, SNF_STA_CTL1, 0); ++ ++ /* Initialization on all dies */ ++ for (i = 0; i < snf->num_dies; i++) { ++ mtk_snand_select_die(snf, i); ++ ++ /* Disable On-Die ECC engine */ ++ ret = mtk_snand_ondie_ecc_control(snf, false); ++ if (ret) ++ return ret; ++ ++ /* Disable block protection */ ++ mtk_snand_unlock(snf); ++ ++ /* Enable/disable quad-spi */ ++ mtk_snand_qspi_control(snf, snf->quad_spi_op); ++ } ++ ++ mtk_snand_select_die(snf, 0); ++ ++ return 0; ++} ++ ++static int mtk_snand_id_probe(struct mtk_snand *snf, ++ const struct snand_flash_info **snand_info) ++{ ++ uint8_t id[4], op[2]; ++ int ret; ++ ++ /* Read SPI-NAND JEDEC ID, OP + dummy/addr + ID */ ++ op[0] = SNAND_CMD_READID; ++ op[1] = 0; ++ ret = mtk_snand_mac_io(snf, op, 2, id, sizeof(id)); ++ if (ret) ++ return ret; ++ ++ *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id); ++ if (*snand_info) ++ return 0; ++ ++ /* Read SPI-NAND JEDEC ID, OP + ID */ ++ op[0] = SNAND_CMD_READID; ++ ret = mtk_snand_mac_io(snf, op, 1, id, sizeof(id)); ++ if (ret) ++ return ret; ++ ++ *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id); ++ if (*snand_info) ++ return 0; ++ ++ snand_log_chip(snf->pdev, ++ "Unrecognized SPI-NAND ID: %02x %02x %02x %02x\n", ++ id[0], id[1], id[2], id[3]); ++ ++ return -EINVAL; ++} ++ ++int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata, ++ struct mtk_snand **psnf) ++{ ++ const struct snand_flash_info *snand_info; ++ struct mtk_snand tmpsnf, *snf; ++ uint32_t rawpage_size; ++ int ret; ++ ++ if (!pdata || !psnf) ++ return -EINVAL; ++ ++ if (pdata->soc >= __SNAND_SOC_MAX) { ++ snand_log_chip(dev, "Invalid SOC %u for MTK-SNAND\n", ++ pdata->soc); ++ return -EINVAL; ++ } ++ ++ /* Dummy instance only for initial reset and id probe */ ++ tmpsnf.nfi_base = pdata->nfi_base; ++ tmpsnf.ecc_base = pdata->ecc_base; ++ tmpsnf.soc = pdata->soc; ++ tmpsnf.nfi_soc = &mtk_snand_socs[pdata->soc]; ++ tmpsnf.pdev = dev; ++ ++ /* Switch to SNFI mode */ ++ writel(SPI_MODE, tmpsnf.nfi_base + SNF_CFG); ++ ++ /* Reset SNFI & NFI */ ++ mtk_snand_mac_reset(&tmpsnf); ++ mtk_nfi_reset(&tmpsnf); ++ ++ /* Reset SPI-NAND chip */ ++ ret = mtk_snand_chip_reset(&tmpsnf); ++ if (ret) { ++ snand_log_chip(dev, "Failed to reset SPI-NAND chip\n"); ++ return ret; ++ } ++ ++ /* Probe SPI-NAND flash by JEDEC ID */ ++ ret = mtk_snand_id_probe(&tmpsnf, &snand_info); ++ if (ret) ++ return ret; ++ ++ rawpage_size = snand_info->memorg.pagesize + ++ snand_info->memorg.sparesize; ++ ++ /* Allocate memory for instance and cache */ ++ snf = generic_mem_alloc(dev, sizeof(*snf) + rawpage_size); ++ if (!snf) { ++ snand_log_chip(dev, "Failed to allocate memory for instance\n"); ++ return -ENOMEM; ++ } ++ ++ snf->buf_cache = (uint8_t *)((uintptr_t)snf + sizeof(*snf)); ++ ++ /* Allocate memory for DMA buffer */ ++ snf->page_cache = dma_mem_alloc(dev, rawpage_size); ++ if (!snf->page_cache) { ++ generic_mem_free(dev, snf); ++ snand_log_chip(dev, ++ "Failed to allocate memory for DMA buffer\n"); ++ return -ENOMEM; ++ } ++ ++ /* Fill up instance */ ++ snf->pdev = dev; ++ snf->nfi_base = pdata->nfi_base; ++ snf->ecc_base = pdata->ecc_base; ++ snf->soc = pdata->soc; ++ snf->nfi_soc = &mtk_snand_socs[pdata->soc]; ++ snf->snfi_quad_spi = pdata->quad_spi; ++ ++ /* Initialize SNFI & ECC engine */ ++ ret = mtk_snand_setup(snf, snand_info); ++ if (ret) { ++ dma_mem_free(dev, snf->page_cache); ++ generic_mem_free(dev, snf); ++ return ret; ++ } ++ ++ *psnf = snf; ++ ++ return 0; ++} ++ ++int mtk_snand_cleanup(struct mtk_snand *snf) ++{ ++ if (!snf) ++ return 0; ++ ++ dma_mem_free(snf->pdev, snf->page_cache); ++ generic_mem_free(snf->pdev, snf); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand.h +@@ -0,0 +1,77 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#ifndef _MTK_SNAND_H_ ++#define _MTK_SNAND_H_ ++ ++#ifndef PRIVATE_MTK_SNAND_HEADER ++#include ++#include ++#include ++#endif ++ ++enum mtk_snand_soc { ++ SNAND_SOC_MT7622, ++ SNAND_SOC_MT7629, ++ SNAND_SOC_MT7986, ++ ++ __SNAND_SOC_MAX ++}; ++ ++struct mtk_snand_platdata { ++ void *nfi_base; ++ void *ecc_base; ++ enum mtk_snand_soc soc; ++ bool quad_spi; ++}; ++ ++struct mtk_snand_chip_info { ++ const char *model; ++ uint64_t chipsize; ++ uint32_t blocksize; ++ uint32_t pagesize; ++ uint32_t sparesize; ++ uint32_t spare_per_sector; ++ uint32_t fdm_size; ++ uint32_t fdm_ecc_size; ++ uint32_t num_sectors; ++ uint32_t sector_size; ++ uint32_t ecc_strength; ++ uint32_t ecc_bytes; ++}; ++ ++struct mtk_snand; ++struct snand_flash_info; ++ ++int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata, ++ struct mtk_snand **psnf); ++int mtk_snand_cleanup(struct mtk_snand *snf); ++ ++int mtk_snand_chip_reset(struct mtk_snand *snf); ++int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf, ++ void *oob, bool raw); ++int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf, ++ const void *oob, bool raw); ++int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr); ++int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr); ++int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr); ++int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw, ++ const uint8_t *oobbuf, size_t ooblen); ++int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf, ++ size_t ooblen, const uint8_t *oobraw); ++int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr, ++ void *buf, void *oob, size_t ooblen, ++ size_t *actualooblen, bool raw); ++int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr, ++ const void *buf, const void *oob, ++ size_t ooblen, size_t *actualooblen, ++ bool raw); ++int mtk_snand_get_chip_info(struct mtk_snand *snf, ++ struct mtk_snand_chip_info *info); ++int mtk_snand_irq_process(struct mtk_snand *snf); ++ ++#endif /* _MTK_SNAND_H_ */ diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch new file mode 100644 index 00000000..4a06acc2 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch @@ -0,0 +1,174 @@ +From b7fb0e0674db12bcf53df4b107a17c80758ee5d3 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 08:57:29 +0800 +Subject: [PATCH 05/12] mtd: mtk-snand: add support for SPL + +Add support to initialize SPI-NAND in SPL. +Add implementation for SPL NAND loader. + +Signed-off-by: Weijie Gao +--- + drivers/mtd/mtk-snand/Kconfig | 6 ++ + drivers/mtd/mtk-snand/Makefile | 4 + + drivers/mtd/mtk-snand/mtk-snand-spl.c | 132 ++++++++++++++++++++++++++ + 3 files changed, 142 insertions(+) + create mode 100644 drivers/mtd/mtk-snand/mtk-snand-spl.c + +--- a/drivers/mtd/mtk-snand/Kconfig ++++ b/drivers/mtd/mtk-snand/Kconfig +@@ -19,3 +19,9 @@ config MTK_SPI_NAND_MTD + help + This option enables access to SPI-NAND flashes through the + MTD interface of MediaTek SPI NAND Flash Controller ++ ++config SPL_MTK_SPI_NAND ++ tristate "SPL support for MediaTek SPI NAND flash controller" ++ depends on MTK_SPI_NAND ++ help ++ This option enables access to SPI-NAND flashes in the SPL stage +--- a/drivers/mtd/mtk-snand/Makefile ++++ b/drivers/mtd/mtk-snand/Makefile +@@ -8,4 +8,8 @@ + obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o + obj-$(CONFIG_MTK_SPI_NAND_MTD) += mtk-snand-mtd.o + ++ifdef CONFIG_SPL_BUILD ++obj-$(CONFIG_SPL_MTK_SPI_NAND) += mtk-snand-spl.o ++endif ++ + ccflags-y += -DPRIVATE_MTK_SNAND_HEADER +--- /dev/null ++++ b/drivers/mtd/mtk-snand/mtk-snand-spl.c +@@ -0,0 +1,132 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk-snand.h" ++ ++static struct mtk_snand *snf; ++static struct mtk_snand_chip_info cinfo; ++static u32 oobavail; ++ ++static u8 *page_cache; ++ ++int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) ++{ ++ u32 sizeremain = size, chunksize, leading; ++ uint32_t off = offs, writesize_mask = cinfo.pagesize - 1; ++ uint8_t *ptr = dst; ++ int ret; ++ ++ if (!snf) ++ return -ENODEV; ++ ++ while (sizeremain) { ++ WATCHDOG_RESET(); ++ ++ leading = off & writesize_mask; ++ chunksize = cinfo.pagesize - leading; ++ if (chunksize > sizeremain) ++ chunksize = sizeremain; ++ ++ if (chunksize == cinfo.pagesize) { ++ ret = mtk_snand_read_page(snf, off - leading, ptr, ++ NULL, false); ++ if (ret) ++ break; ++ } else { ++ ret = mtk_snand_read_page(snf, off - leading, ++ page_cache, NULL, false); ++ if (ret) ++ break; ++ ++ memcpy(ptr, page_cache + leading, chunksize); ++ } ++ ++ off += chunksize; ++ ptr += chunksize; ++ sizeremain -= chunksize; ++ } ++ ++ return ret; ++} ++ ++void nand_init(void) ++{ ++ struct mtk_snand_platdata mtk_snand_pdata = {}; ++ struct udevice *dev; ++ fdt_addr_t base; ++ int ret; ++ ++ ret = uclass_get_device_by_driver(UCLASS_MTD, DM_DRIVER_GET(mtk_snand), ++ &dev); ++ if (ret) { ++ printf("mtk-snand-spl: Device instance not found!\n"); ++ return; ++ } ++ ++ base = dev_read_addr_name(dev, "nfi"); ++ if (base == FDT_ADDR_T_NONE) { ++ printf("mtk-snand-spl: NFI base not set\n"); ++ return; ++ } ++ mtk_snand_pdata.nfi_base = map_sysmem(base, 0); ++ ++ base = dev_read_addr_name(dev, "ecc"); ++ if (base == FDT_ADDR_T_NONE) { ++ printf("mtk-snand-spl: ECC base not set\n"); ++ return; ++ } ++ mtk_snand_pdata.ecc_base = map_sysmem(base, 0); ++ ++ mtk_snand_pdata.soc = dev_get_driver_data(dev); ++ mtk_snand_pdata.quad_spi = dev_read_bool(dev, "quad-spi"); ++ ++ ret = mtk_snand_init(NULL, &mtk_snand_pdata, &snf); ++ if (ret) { ++ printf("mtk-snand-spl: failed to initialize SPI-NAND\n"); ++ return; ++ } ++ ++ mtk_snand_get_chip_info(snf, &cinfo); ++ ++ oobavail = cinfo.num_sectors * (cinfo.fdm_size - 1); ++ ++ printf("SPI-NAND: %s (%uMB)\n", cinfo.model, ++ (u32)(cinfo.chipsize >> 20)); ++ ++ page_cache = malloc(cinfo.pagesize + cinfo.sparesize); ++ if (!page_cache) { ++ mtk_snand_cleanup(snf); ++ printf("mtk-snand-spl: failed to allocate page cache\n"); ++ } ++} ++ ++void nand_deselect(void) ++{ ++ ++} ++ ++static const struct udevice_id mtk_snand_ids[] = { ++ { .compatible = "mediatek,mt7622-snand", .data = SNAND_SOC_MT7622 }, ++ { .compatible = "mediatek,mt7629-snand", .data = SNAND_SOC_MT7629 }, ++ { .compatible = "mediatek,mt7986-snand", .data = SNAND_SOC_MT7986 }, ++ { /* sentinel */ }, ++}; ++ ++U_BOOT_DRIVER(mtk_snand) = { ++ .name = "mtk-snand", ++ .id = UCLASS_MTD, ++ .of_match = mtk_snand_ids, ++ .flags = DM_FLAG_PRE_RELOC, ++}; diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch new file mode 100644 index 00000000..d4f34606 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch @@ -0,0 +1,409 @@ +From a26620ec83fa3077f0c261046e82091f7455736f Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:11:32 +0800 +Subject: [PATCH 06/12] env: add support for generic MTD device + +Add an env driver for generic MTD device. + +Signed-off-by: Weijie Gao +--- + cmd/nvedit.c | 3 +- + env/Kconfig | 37 +++++- + env/Makefile | 1 + + env/env.c | 3 + + env/mtd.c | 256 +++++++++++++++++++++++++++++++++++++++++ + include/env_internal.h | 1 + + tools/Makefile | 1 + + 7 files changed, 299 insertions(+), 3 deletions(-) + create mode 100644 env/mtd.c + +--- a/cmd/nvedit.c ++++ b/cmd/nvedit.c +@@ -48,6 +48,7 @@ DECLARE_GLOBAL_DATA_PTR; + defined(CONFIG_ENV_IS_IN_MMC) || \ + defined(CONFIG_ENV_IS_IN_FAT) || \ + defined(CONFIG_ENV_IS_IN_EXT4) || \ ++ defined(CONFIG_ENV_IS_IN_MTD) || \ + defined(CONFIG_ENV_IS_IN_NAND) || \ + defined(CONFIG_ENV_IS_IN_NVRAM) || \ + defined(CONFIG_ENV_IS_IN_ONENAND) || \ +@@ -62,7 +63,7 @@ DECLARE_GLOBAL_DATA_PTR; + + #if !defined(ENV_IS_IN_DEVICE) && \ + !defined(CONFIG_ENV_IS_NOWHERE) +-# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ ++# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|MTD|\ + NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE + #endif + +--- a/env/Kconfig ++++ b/env/Kconfig +@@ -19,7 +19,7 @@ config ENV_IS_NOWHERE + !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \ + !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \ + !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \ +- !ENV_IS_IN_UBI ++ !ENV_IS_IN_UBI && !ENV_IS_IN_MTD + help + Define this if you don't want to or can't have an environment stored + on a storage medium. In this case the environment will still exist +@@ -208,6 +208,27 @@ config ENV_IS_IN_MMC + This value is also in units of bytes, but must also be aligned to + an MMC sector boundary. + ++config ENV_IS_IN_MTD ++ bool "Environment in a MTD device" ++ depends on !CHAIN_OF_TRUST ++ depends on MTD ++ help ++ Define this if you have a MTD device which you want to use for ++ the environment. ++ ++ - CONFIG_ENV_MTD_NAME: ++ - CONFIG_ENV_OFFSET: ++ - CONFIG_ENV_SIZE: ++ ++ These three #defines specify the MTD device where the environment ++ is stored, offset and size of the environment area within the MTD ++ device. CONFIG_ENV_OFFSET must be aligned to an erase block boundary. ++ ++ - CONFIG_ENV_SIZE_REDUND: ++ ++ This #define specify the maximum size allowed for read/write/erase ++ with skipped bad blocks starting from ENV_OFFSET. ++ + config ENV_IS_IN_NAND + bool "Environment in a NAND device" + depends on !CHAIN_OF_TRUST +@@ -535,10 +556,16 @@ config ENV_ADDR_REDUND + Offset from the start of the device (or partition) of the redundant + environment location. + ++config ENV_MTD_NAME ++ string "Name of the MTD device storing the environment" ++ depends on ENV_IS_IN_MTD ++ help ++ Name of the MTD device that stores the environment ++ + config ENV_OFFSET + hex "Environment offset" + depends on ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \ +- ENV_IS_IN_SPI_FLASH ++ ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD + default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC + default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH + default 0x88000 if ARCH_SUNXI +@@ -583,6 +610,12 @@ config ENV_SECT_SIZE + help + Size of the sector containing the environment. + ++config ENV_SIZE_REDUND ++ hex "Redundant environment size" ++ depends on ENV_IS_IN_MTD ++ help ++ The maximum size allowed for read/write/erase with skipped bad blocks. ++ + config ENV_UBI_PART + string "UBI partition name" + depends on ENV_IS_IN_UBI +--- a/env/Makefile ++++ b/env/Makefile +@@ -26,6 +26,7 @@ obj-$(CONFIG_$(SPL_TPL_)ENV_IS_NOWHERE) + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MMC) += mmc.o + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FAT) += fat.o + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_EXT4) += ext4.o ++obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MTD) += mtd.o + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_NAND) += nand.o + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_SPI_FLASH) += sf.o + obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FLASH) += flash.o +--- a/env/env.c ++++ b/env/env.c +@@ -69,6 +69,9 @@ static enum env_location env_locations[] + #ifdef CONFIG_ENV_IS_IN_MMC + ENVL_MMC, + #endif ++#ifdef CONFIG_ENV_IS_IN_MTD ++ ENVL_MTD, ++#endif + #ifdef CONFIG_ENV_IS_IN_NAND + ENVL_NAND, + #endif +--- /dev/null ++++ b/env/mtd.c +@@ -0,0 +1,256 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE ++#undef CONFIG_ENV_SIZE_REDUND ++#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE ++#endif ++ ++#if defined(ENV_IS_EMBEDDED) ++env_t *env_ptr = &environment; ++#else /* ! ENV_IS_EMBEDDED */ ++env_t *env_ptr; ++#endif /* ENV_IS_EMBEDDED */ ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++static int env_mtd_init(void) ++{ ++#if defined(ENV_IS_EMBEDDED) ++ int crc1_ok = 0, crc2_ok = 0; ++ env_t *tmp_env1; ++ ++ tmp_env1 = env_ptr; ++ crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc; ++ ++ if (!crc1_ok && !crc2_ok) { ++ gd->env_addr = 0; ++ gd->env_valid = ENV_INVALID; ++ ++ return 0; ++ } else if (crc1_ok && !crc2_ok) { ++ gd->env_valid = ENV_VALID; ++ } ++ ++ if (gd->env_valid == ENV_VALID) ++ env_ptr = tmp_env1; ++ ++ gd->env_addr = (ulong)env_ptr->data; ++ ++#else /* ENV_IS_EMBEDDED */ ++ gd->env_addr = (ulong)&default_environment[0]; ++ gd->env_valid = ENV_VALID; ++#endif /* ENV_IS_EMBEDDED */ ++ ++ return 0; ++} ++ ++static struct mtd_info *env_mtd_get_dev(void) ++{ ++ struct mtd_info *mtd; ++ ++ mtd_probe_devices(); ++ ++ mtd = get_mtd_device_nm(CONFIG_ENV_MTD_NAME); ++ if (IS_ERR(mtd) || !mtd) { ++ printf("MTD device '%s' not found\n", CONFIG_ENV_MTD_NAME); ++ return NULL; ++ } ++ ++ return mtd; ++} ++ ++static inline bool mtd_addr_is_block_aligned(struct mtd_info *mtd, u64 addr) ++{ ++ return (addr & mtd->erasesize_mask) == 0; ++} ++ ++static int mtd_io_skip_bad(struct mtd_info *mtd, bool read, loff_t offset, ++ size_t length, size_t redund, u8 *buffer) ++{ ++ struct mtd_oob_ops io_op = {}; ++ size_t remaining = length; ++ loff_t off, end; ++ int ret; ++ ++ io_op.mode = MTD_OPS_PLACE_OOB; ++ io_op.len = mtd->writesize; ++ io_op.datbuf = (void *)buffer; ++ ++ /* Search for the first good block after the given offset */ ++ off = offset; ++ end = (off + redund) | (mtd->erasesize - 1); ++ while (mtd_block_isbad(mtd, off) && off < end) ++ off += mtd->erasesize; ++ ++ /* Reached end position */ ++ if (off >= end) ++ return -EIO; ++ ++ /* Loop over the pages to do the actual read/write */ ++ while (remaining) { ++ /* Skip the block if it is bad */ ++ if (mtd_addr_is_block_aligned(mtd, off) && ++ mtd_block_isbad(mtd, off)) { ++ off += mtd->erasesize; ++ continue; ++ } ++ ++ if (read) ++ ret = mtd_read_oob(mtd, off, &io_op); ++ else ++ ret = mtd_write_oob(mtd, off, &io_op); ++ ++ if (ret) { ++ printf("Failure while %s at offset 0x%llx\n", ++ read ? "reading" : "writing", off); ++ break; ++ } ++ ++ off += io_op.retlen; ++ remaining -= io_op.retlen; ++ io_op.datbuf += io_op.retlen; ++ io_op.oobbuf += io_op.oobretlen; ++ ++ /* Reached end position */ ++ if (off >= end) ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_CMD_SAVEENV ++static int mtd_erase_skip_bad(struct mtd_info *mtd, loff_t offset, ++ size_t length, size_t redund) ++{ ++ struct erase_info erase_op = {}; ++ loff_t end = (offset + redund) | (mtd->erasesize - 1); ++ int ret; ++ ++ erase_op.mtd = mtd; ++ erase_op.addr = offset; ++ erase_op.len = length; ++ ++ while (erase_op.len) { ++ ret = mtd_erase(mtd, &erase_op); ++ ++ /* Abort if its not a bad block error */ ++ if (ret != -EIO) ++ return ret; ++ ++ printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr); ++ ++ /* Skip bad block and continue behind it */ ++ erase_op.len -= erase_op.fail_addr - erase_op.addr; ++ erase_op.len -= mtd->erasesize; ++ erase_op.addr = erase_op.fail_addr + mtd->erasesize; ++ ++ /* Reached end position */ ++ if (erase_op.addr >= end) ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int env_mtd_save(void) ++{ ++ ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); ++ struct mtd_info *mtd; ++ int ret = 0; ++ ++ ret = env_export(env_new); ++ if (ret) ++ return ret; ++ ++ mtd = env_mtd_get_dev(); ++ if (!mtd) ++ return 1; ++ ++ printf("Erasing on MTD device '%s'... ", mtd->name); ++ ++ ret = mtd_erase_skip_bad(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, ++ CONFIG_ENV_SIZE_REDUND); ++ ++ puts(ret ? "FAILED\n" : "OK\n"); ++ ++ if (ret) { ++ put_mtd_device(mtd); ++ return 1; ++ } ++ ++ printf("Writing to MTD device '%s'... ", mtd->name); ++ ++ ret = mtd_io_skip_bad(mtd, false, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, ++ CONFIG_ENV_SIZE_REDUND, (u8 *)env_new); ++ ++ puts(ret ? "FAILED\n" : "OK\n"); ++ ++ put_mtd_device(mtd); ++ ++ return !!ret; ++} ++#endif /* CONFIG_CMD_SAVEENV */ ++ ++static int readenv(size_t offset, u_char *buf) ++{ ++ struct mtd_info *mtd; ++ int ret; ++ ++ mtd = env_mtd_get_dev(); ++ if (!mtd) ++ return 1; ++ ++ ret = mtd_io_skip_bad(mtd, true, offset, CONFIG_ENV_SIZE, ++ CONFIG_ENV_SIZE_REDUND, buf); ++ ++ put_mtd_device(mtd); ++ ++ return !!ret; ++} ++ ++static int env_mtd_load(void) ++{ ++#if !defined(ENV_IS_EMBEDDED) ++ ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); ++ int ret; ++ ++ ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf); ++ if (ret) { ++ env_set_default("readenv() failed", 0); ++ return -EIO; ++ } ++ ++ return env_import(buf, 1, H_EXTERNAL); ++#endif /* ! ENV_IS_EMBEDDED */ ++ ++ return 0; ++} ++ ++U_BOOT_ENV_LOCATION(mtd) = { ++ .location = ENVL_MTD, ++ ENV_NAME("MTD") ++ .load = env_mtd_load, ++#if defined(CONFIG_CMD_SAVEENV) ++ .save = env_save_ptr(env_mtd_save), ++#endif ++ .init = env_mtd_init, ++}; +--- a/include/env_internal.h ++++ b/include/env_internal.h +@@ -130,6 +130,7 @@ enum env_location { + ENVL_FAT, + ENVL_FLASH, + ENVL_MMC, ++ ENVL_MTD, + ENVL_NAND, + ENVL_NVRAM, + ENVL_ONENAND, +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -41,6 +41,7 @@ ENVCRC-$(CONFIG_ENV_IS_EMBEDDED) = y + ENVCRC-$(CONFIG_ENV_IS_IN_EEPROM) = y + ENVCRC-$(CONFIG_ENV_IS_IN_FLASH) = y + ENVCRC-$(CONFIG_ENV_IS_IN_ONENAND) = y ++ENVCRC-$(CONFIG_ENV_IS_IN_MTD) = y + ENVCRC-$(CONFIG_ENV_IS_IN_NAND) = y + ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y + ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch new file mode 100644 index 00000000..4ee3d6f3 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch @@ -0,0 +1,223 @@ +From 3757223c3354b9feeffcbe916eb18eb8873bd133 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:48:53 +0800 +Subject: [PATCH 07/12] board: mt7629: add support for booting from SPI-NAND + +Add support for mt7629 to boot from SPI-NAND. +Add a new defconfig for mt7629+spi-nand configuration. + +Signed-off-by: Weijie Gao +--- + arch/arm/dts/mt7629-rfb-u-boot.dtsi | 8 ++ + arch/arm/dts/mt7629-rfb.dts | 10 +++ + arch/arm/dts/mt7629.dtsi | 16 ++++ + board/mediatek/mt7629/Kconfig | 35 ++++++++- + configs/mt7629_nand_rfb_defconfig | 111 ++++++++++++++++++++++++++++ + include/configs/mt7629.h | 7 ++ + 6 files changed, 186 insertions(+), 1 deletion(-) + create mode 100644 configs/mt7629_nand_rfb_defconfig + +--- a/arch/arm/dts/mt7629-rfb-u-boot.dtsi ++++ b/arch/arm/dts/mt7629-rfb-u-boot.dtsi +@@ -40,3 +40,11 @@ + &snfi { + u-boot,dm-pre-reloc; + }; ++ ++&pinctrl { ++ u-boot,dm-pre-reloc; ++}; ++ ++&snand { ++ u-boot,dm-pre-reloc; ++}; +--- a/arch/arm/dts/mt7629-rfb.dts ++++ b/arch/arm/dts/mt7629-rfb.dts +@@ -47,9 +47,12 @@ + }; + + snfi_pins: snfi-pins { ++ u-boot,dm-pre-reloc; ++ + mux { + function = "flash"; + groups = "snfi"; ++ u-boot,dm-pre-reloc; + }; + }; + +@@ -102,6 +105,13 @@ + }; + }; + ++&snand { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; ++ status = "okay"; ++ quad-spi; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +--- a/arch/arm/dts/mt7629.dtsi ++++ b/arch/arm/dts/mt7629.dtsi +@@ -229,6 +229,22 @@ + #size-cells = <0>; + }; + ++ snand: snand@1100d000 { ++ compatible = "mediatek,mt7629-snand"; ++ reg = <0x1100d000 0x1000>, ++ <0x1100e000 0x1000>; ++ reg-names = "nfi", "ecc"; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, ++ <&pericfg CLK_PERI_SNFI_PD>, ++ <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfi_clk", "pad_clk", "ecc_clk"; ++ assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>, ++ <&topckgen CLK_TOP_NFI_INFRA_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>, ++ <&topckgen CLK_TOP_UNIVPLL2_D8>; ++ status = "disabled"; ++ }; ++ + snor: snor@11014000 { + compatible = "mediatek,mtk-snor"; + reg = <0x11014000 0x1000>; +--- /dev/null ++++ b/configs/mt7629_nand_rfb_defconfig +@@ -0,0 +1,111 @@ ++CONFIG_ARM=y ++CONFIG_SYS_ARCH_TIMER=y ++CONFIG_SYS_THUMB_BUILD=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_ENV_SIZE=0x20000 ++CONFIG_ENV_OFFSET=0x100000 ++CONFIG_SPL_TEXT_BASE=0x201000 ++CONFIG_TARGET_MT7629=y ++CONFIG_BOOT_FROM_SNAND_2K_64=y ++CONFIG_SPL_SERIAL_SUPPORT=y ++CONFIG_SPL_DRIVERS_MISC_SUPPORT=y ++CONFIG_SPL_STACK_R_ADDR=0x40800000 ++CONFIG_SPL_PAYLOAD="u-boot.img" ++CONFIG_BUILD_TARGET="u-boot-mtk.bin" ++CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb" ++CONFIG_SPL_IMAGE="spl/u-boot-spl-mtk.bin" ++CONFIG_FIT=y ++CONFIG_FIT_VERBOSE=y ++CONFIG_BOOTDELAY=3 ++CONFIG_DEFAULT_FDT_FILE="mt7629-rfb" ++CONFIG_SYS_CONSOLE_IS_IN_ENV=y ++CONFIG_SYS_STDIO_DEREGISTER=y ++# CONFIG_DISPLAY_BOARDINFO is not set ++CONFIG_SPL_SYS_MALLOC_SIMPLE=y ++CONFIG_SPL_STACK_R=y ++CONFIG_SPL_MTD_SUPPORT=y ++CONFIG_SPL_NAND_SUPPORT=y ++CONFIG_SPL_WATCHDOG_SUPPORT=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_PROMPT="U-Boot> " ++CONFIG_CMD_BOOTMENU=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_BIND=y ++CONFIG_CMD_DM=y ++# CONFIG_CMD_FLASH is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_USB=y ++# CONFIG_CMD_SETEXPR is not set ++# CONFIG_CMD_NFS is not set ++CONFIG_CMD_PING=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_LOG=y ++CONFIG_EFI_PARTITION=y ++# CONFIG_SPL_PARTITION_UUIDS is not set ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_OF_SPL_REMOVE_PROPS="interrupt-parent assigned-clocks assigned-clock-parents" ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MTD=y ++CONFIG_ENV_MTD_NAME="spi-nand0" ++CONFIG_ENV_SIZE_REDUND=0x40000 ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_SPL_DM_SEQ_ALIAS=y ++CONFIG_REGMAP=y ++CONFIG_SPL_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_SPL_SYSCON=y ++CONFIG_BLK=y ++CONFIG_CLK=y ++CONFIG_SPL_CLK=y ++# CONFIG_MMC is not set ++CONFIG_MTD=y ++CONFIG_DM_MTD=y ++CONFIG_MTK_SPI_NAND=y ++CONFIG_MTK_SPI_NAND_MTD=y ++CONFIG_SPL_MTK_SPI_NAND=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_SPL_PINCTRL=y ++CONFIG_SPL_PINCONF=y ++CONFIG_PINCTRL_MT7629=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_RAM=y ++CONFIG_SPL_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_SPI_MEM=y ++CONFIG_MTK_SNFI_SPI=y ++CONFIG_SYSRESET=y ++CONFIG_SPL_SYSRESET=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_USB=y ++CONFIG_DM_USB=y ++# CONFIG_SPL_DM_USB is not set ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_WDT_MTK=y ++CONFIG_FAT_WRITE=y ++CONFIG_LZMA=y ++CONFIG_SPL_LZMA=y ++# CONFIG_EFI_LOADER is not set +--- a/include/configs/mt7629.h ++++ b/include/configs/mt7629.h +@@ -25,12 +25,19 @@ + + /* Defines for SPL */ + #define CONFIG_SPL_STACK 0x106000 ++#ifdef CONFIG_MT7629_BOOT_FROM_SNAND ++#define CONFIG_SPL_MAX_SIZE SZ_128K ++#define CONFIG_SPL_MAX_FOOTPRINT SZ_128K ++#define CONFIG_SPL_PAD_TO 0x20000 ++#define CONFIG_SYS_NAND_U_BOOT_OFFS CONFIG_SPL_PAD_TO ++#else + #define CONFIG_SPL_MAX_SIZE SZ_64K + #define CONFIG_SPL_MAX_FOOTPRINT SZ_64K + #define CONFIG_SPL_PAD_TO 0x10000 + + #define CONFIG_SPI_ADDR 0x30000000 + #define CONFIG_SYS_UBOOT_BASE (CONFIG_SPI_ADDR + CONFIG_SPL_PAD_TO) ++#endif + + /* SPL -> Uboot */ + #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + SZ_2M - \ diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch new file mode 100644 index 00000000..84101d0e --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch @@ -0,0 +1,76 @@ +From 6bcd65ed47844e747ff6db066b092632f1760256 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:51:43 +0800 +Subject: [PATCH 08/12] board: mt7622: use new spi-nand driver + +Enable new spi-nand driver support for mt7622_rfb_defconfig + +Signed-off-by: Weijie Gao +--- + arch/arm/dts/mt7622-rfb.dts | 7 +++++++ + arch/arm/dts/mt7622.dtsi | 16 ++++++++++++++++ + configs/mt7622_rfb_defconfig | 5 +++++ + 3 files changed, 28 insertions(+) + +--- a/arch/arm/dts/mt7622-rfb.dts ++++ b/arch/arm/dts/mt7622-rfb.dts +@@ -188,6 +188,13 @@ + }; + }; + ++&snand { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; ++ status = "okay"; ++ quad-spi; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +--- a/arch/arm/dts/mt7622.dtsi ++++ b/arch/arm/dts/mt7622.dtsi +@@ -53,6 +53,22 @@ + #size-cells = <0>; + }; + ++ snand: snand@1100d000 { ++ compatible = "mediatek,mt7622-snand"; ++ reg = <0x1100d000 0x1000>, ++ <0x1100e000 0x1000>; ++ reg-names = "nfi", "ecc"; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, ++ <&pericfg CLK_PERI_SNFI_PD>, ++ <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfi_clk", "pad_clk", "ecc_clk"; ++ assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>, ++ <&topckgen CLK_TOP_NFI_INFRA_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>, ++ <&topckgen CLK_TOP_UNIVPLL2_D8>; ++ status = "disabled"; ++ }; ++ + snor: snor@11014000 { + compatible = "mediatek,mtk-snor"; + reg = <0x11014000 0x1000>; +--- a/configs/mt7622_rfb_defconfig ++++ b/configs/mt7622_rfb_defconfig +@@ -16,6 +16,7 @@ CONFIG_LOG=y + CONFIG_SYS_PROMPT="MT7622> " + CONFIG_CMD_BOOTMENU=y + CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y + CONFIG_CMD_PCI=y + CONFIG_CMD_SF_TEST=y + CONFIG_CMD_PING=y +@@ -28,6 +29,10 @@ CONFIG_SYSCON=y + CONFIG_CLK=y + CONFIG_MMC_HS200_SUPPORT=y + CONFIG_MMC_MTK=y ++CONFIG_MTD=y ++CONFIG_DM_MTD=y ++CONFIG_MTK_SPI_NAND=y ++CONFIG_MTK_SPI_NAND_MTD=y + CONFIG_DM_SPI_FLASH=y + CONFIG_SPI_FLASH_EON=y + CONFIG_SPI_FLASH_GIGADEVICE=y diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch new file mode 100644 index 00000000..69ea2b0f --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch @@ -0,0 +1,31 @@ +From 632f09f140610cf45da1dba25c66e9ca79a70a15 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 12:12:39 +0800 +Subject: [PATCH 09/12] configs: mt7629: remove unused options and add dm + command + +Remove unused bootm options +Add dm command + +Signed-off-by: Weijie Gao +--- + configs/mt7629_rfb_defconfig | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/configs/mt7629_rfb_defconfig ++++ b/configs/mt7629_rfb_defconfig +@@ -29,9 +29,14 @@ CONFIG_SPL_WATCHDOG=y + CONFIG_HUSH_PARSER=y + CONFIG_SYS_PROMPT="U-Boot> " + CONFIG_CMD_BOOTMENU=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_BIND=y ++CONFIG_CMD_DM=y + # CONFIG_CMD_FLASH is not set + CONFIG_CMD_GPIO=y + CONFIG_CMD_SF_TEST=y diff --git a/root/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch b/root/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch new file mode 100644 index 00000000..c66451dc --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch @@ -0,0 +1,33 @@ +From 93d7086edb0db4b05149dfea21a2a82d8f160944 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Sat, 6 Mar 2021 16:29:33 +0800 +Subject: [PATCH 10/12] configs: mt7622: enable environment for mt7622_rfb + +Enable environment vairables for mt7622_rfb + +Signed-off-by: Weijie Gao +--- + configs/mt7622_rfb_defconfig | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/configs/mt7622_rfb_defconfig ++++ b/configs/mt7622_rfb_defconfig +@@ -5,6 +5,8 @@ CONFIG_SYS_TEXT_BASE=0x41e00000 + CONFIG_SYS_MALLOC_F_LEN=0x4000 + CONFIG_NR_DRAM_BANKS=1 + CONFIG_DEFAULT_DEVICE_TREE="mt7622-rfb" ++CONFIG_ENV_SIZE=0x20000 ++CONFIG_ENV_OFFSET=0x280000 + CONFIG_DEBUG_UART_BASE=0x11002000 + CONFIG_DEBUG_UART_CLOCK=25000000 + CONFIG_DEBUG_UART=y +@@ -22,6 +24,9 @@ CONFIG_CMD_SF_TEST=y + CONFIG_CMD_PING=y + CONFIG_CMD_SMC=y + CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MTD=y ++CONFIG_ENV_MTD_NAME="spi-nand0" ++CONFIG_ENV_SIZE_REDUND=0x40000 + CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y + CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_REGMAP=y diff --git a/root/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch b/root/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch new file mode 100644 index 00000000..42d60c3f --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch @@ -0,0 +1,33 @@ +--- a/arch/arm/dts/mt7622.dtsi ++++ b/arch/arm/dts/mt7622.dtsi +@@ -37,6 +37,30 @@ + }; + }; + ++ psci { ++ compatible = "arm,psci-1.0"; ++ method = "smc"; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@0x42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ ++ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ secmon_reserved: secmon@43000000 { ++ reg = <0 0x43000000 0 0x30000>; ++ no-map; ++ }; ++ }; ++ + snfi: snfi@1100d000 { + compatible = "mediatek,mtk-snfi-spi"; + reg = <0x1100d000 0x2000>; diff --git a/root/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch b/root/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch new file mode 100644 index 00000000..3fcae5ac --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch @@ -0,0 +1,24 @@ +From 12de602dc824bcb821287500fba831225cff5392 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Mon, 13 Jul 2020 23:37:37 +0200 +Subject: [PATCH 11/12] scripts: remove dependency on swig + +Don't build the libfdt tool, as it has a dependency on swig (which +OpenWrt does not ship). + +This requires more hacks, as of-platdata generation does not work +without it. + +Signed-off-by: David Bauer +--- + scripts/dtc/Makefile | 2 -- + 1 file changed, 2 deletions(-) + +--- a/scripts/dtc/Makefile ++++ b/scripts/dtc/Makefile +@@ -18,5 +18,3 @@ HOSTCFLAGS_dtc-parser.tab.o := -I$(src) + # dependencies on generated files need to be listed explicitly + $(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h + +-# Added for U-Boot +-subdir-$(CONFIG_PYLIBFDT) += pylibfdt diff --git a/root/package/boot/uboot-mediatek/patches/110-no-kwbimage.patch b/root/package/boot/uboot-mediatek/patches/110-no-kwbimage.patch new file mode 100644 index 00000000..65d14f5b --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/110-no-kwbimage.patch @@ -0,0 +1,10 @@ +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -119,7 +119,6 @@ dumpimage-mkimage-objs := aisimage.o \ + imximage.o \ + imx8image.o \ + imx8mimage.o \ +- kwbimage.o \ + lib/md5.o \ + lpc32xximage.o \ + mxsimage.o \ diff --git a/root/package/boot/uboot-mediatek/patches/120-use-xz-instead-of-lzma.patch b/root/package/boot/uboot-mediatek/patches/120-use-xz-instead-of-lzma.patch new file mode 100644 index 00000000..c13871b7 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/120-use-xz-instead-of-lzma.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -1045,7 +1045,7 @@ quiet_cmd_pad_cat = CAT $@ + cmd_pad_cat = $(cmd_objcopy) && $(append) || { rm -f $@; false; } + + quiet_cmd_lzma = LZMA $@ +-cmd_lzma = lzma -c -z -k -9 $< > $@ ++cmd_lzma = xz --format=lzma -c -z -k -9 $< > $@ + + cfg: u-boot.cfg + diff --git a/root/package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch b/root/package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch new file mode 100644 index 00000000..5dce177c --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch @@ -0,0 +1,132 @@ +--- a/cmd/bootm.c ++++ b/cmd/bootm.c +@@ -228,6 +228,65 @@ U_BOOT_CMD( + /* iminfo - print header info for a requested image */ + /*******************************************************************/ + #if defined(CONFIG_CMD_IMI) ++#define SECTOR_SHIFT 9 ++static int image_totalsize(struct cmd_tbl *cmdtp, int flag, int argc, ++ char *const argv[], short int in_blocks) ++{ ++ ulong addr; ++ void *fit; ++ int bsize, tsize; ++ char buf[16]; ++ ++ if (argc >= 2) ++ addr = simple_strtoul(argv[1], NULL, 16); ++ else ++ addr = image_load_addr; ++ ++ fit = (void *)map_sysmem(addr, 0); ++ tsize = fit_get_totalsize(fit); ++ unmap_sysmem(fit); ++ if (tsize == 0) ++ return 1; ++ ++ bsize = (tsize >> SECTOR_SHIFT) + ((tsize & ((1 << SECTOR_SHIFT) - 1))?1:0); ++ ++ if (!in_blocks) ++ snprintf(buf, sizeof(buf), "%x", tsize); ++ else ++ snprintf(buf, sizeof(buf), "%x", bsize); ++ ++ if (argc >= 3) ++ return env_set(argv[2], buf); ++ else ++ printf("%s\n", buf); ++ ++ return 0; ++} ++ ++static int do_imsz(struct cmd_tbl *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ return image_totalsize(cmdtp, flag, argc, argv, 0); ++} ++ ++static int do_imszb(struct cmd_tbl *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ return image_totalsize(cmdtp, flag, argc, argv, 1); ++} ++ ++U_BOOT_CMD( ++ imsz, CONFIG_SYS_MAXARGS, 1, do_imsz, ++ "get image total size (in bytes)", ++ "addr [maxhdrlen] [varname]\n" ++); ++ ++U_BOOT_CMD( ++ imszb, CONFIG_SYS_MAXARGS, 1, do_imszb, ++ "get image total size (in blocks)", ++ "addr [maxhdrlen] [varname]\n" ++); ++ + static int do_iminfo(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) + { +--- a/boot/image-fit.c ++++ b/boot/image-fit.c +@@ -1993,6 +1993,51 @@ static const char *fit_get_image_type_pr + return "unknown"; + } + ++size_t fit_get_totalsize(const void *fit) ++{ ++ int ret, ndepth, noffset, images_noffset; ++ size_t data_size, hdrsize, img_total, max_size = 0; ++ const void *data; ++ ++ ret = fdt_check_header(fit); ++ if (ret) { ++ debug("Wrong FIT format: not a flattened device tree (err=%d)\n", ++ ret); ++ return 0; ++ } ++ ++ hdrsize = fdt_totalsize(fit); ++ ++ /* simple FIT with internal images */ ++ if (hdrsize > 0x1000) ++ return hdrsize; ++ ++ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); ++ if (images_noffset < 0) { ++ printf("Can't find images parent node '%s' (%s)\n", ++ FIT_IMAGES_PATH, fdt_strerror(images_noffset)); ++ return 0; ++ } ++ ++ for (ndepth = 0, ++ noffset = fdt_next_node(fit, images_noffset, &ndepth); ++ (noffset >= 0) && (ndepth > 0); ++ noffset = fdt_next_node(fit, noffset, &ndepth)) { ++ if (ndepth == 1) { ++ ret = fit_image_get_data_and_size(fit, noffset, &data, &data_size); ++ if (ret) ++ return 0; ++ ++ img_total = data_size + (data - fit); ++ ++ max_size = (max_size > img_total) ? max_size : img_total; ++ } ++ } ++ ++ return max_size; ++} ++ ++ + int fit_image_load(bootm_headers_t *images, ulong addr, + const char **fit_unamep, const char **fit_uname_configp, + int arch, int image_type, int bootstage_id, +--- a/include/image.h ++++ b/include/image.h +@@ -952,6 +952,7 @@ int fit_parse_subimage(const char *spec, + ulong *addr, const char **image_name); + + int fit_get_subimage_count(const void *fit, int images_noffset); ++size_t fit_get_totalsize(const void *fit); + void fit_print_contents(const void *fit); + void fit_image_print(const void *fit, int noffset, const char *p); + diff --git a/root/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch b/root/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch new file mode 100644 index 00000000..c43b542d --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch @@ -0,0 +1,192 @@ +From afea25576fc92d562b248b783cf03564eb4521da Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 19 Jan 2021 10:58:48 +0800 +Subject: [PATCH 12/12] cmd: bootmenu: add ability to select item by shortkey + +Add ability to use shortkey to select item for bootmenu command + +Signed-off-by: Weijie Gao +--- + cmd/bootmenu.c | 77 +++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 70 insertions(+), 7 deletions(-) + +--- a/cmd/bootmenu.c ++++ b/cmd/bootmenu.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -38,6 +39,7 @@ struct bootmenu_data { + int active; /* active menu entry */ + int count; /* total count of menu entries */ + struct bootmenu_entry *first; /* first menu entry */ ++ bool last_choiced; + }; + + enum bootmenu_key { +@@ -46,8 +48,27 @@ enum bootmenu_key { + KEY_DOWN, + KEY_SELECT, + KEY_QUIT, ++ KEY_CHOICE, + }; + ++static const char choice_chars[] = { ++ '1', '2', '3', '4', '5', '6', '7', '8', '9', ++ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', ++ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', ++ 'u', 'v', 'w', 'x', 'y', 'z' ++}; ++ ++static int find_choice(char choice) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(choice_chars); i++) ++ if (tolower(choice) == choice_chars[i]) ++ return i; ++ ++ return -1; ++} ++ + static char *bootmenu_getoption(unsigned short int n) + { + char name[MAX_ENV_SIZE]; +@@ -82,7 +103,7 @@ static void bootmenu_print_entry(void *d + } + + static void bootmenu_autoboot_loop(struct bootmenu_data *menu, +- enum bootmenu_key *key, int *esc) ++ enum bootmenu_key *key, int *esc, int *choice) + { + int i, c; + +@@ -115,6 +136,19 @@ static void bootmenu_autoboot_loop(struc + break; + default: + *key = KEY_NONE; ++ if (*esc) ++ break; ++ ++ *choice = find_choice(c); ++ if ((*choice >= 0 && ++ *choice < menu->count - 1)) { ++ *key = KEY_CHOICE; ++ } else if (c == '0') { ++ *choice = menu->count - 1; ++ *key = KEY_CHOICE; ++ } else { ++ *key = KEY_NONE; ++ } + break; + } + +@@ -136,10 +170,16 @@ static void bootmenu_autoboot_loop(struc + } + + static void bootmenu_loop(struct bootmenu_data *menu, +- enum bootmenu_key *key, int *esc) ++ enum bootmenu_key *key, int *esc, int *choice) + { + int c; + ++ if (menu->last_choiced) { ++ menu->last_choiced = false; ++ *key = KEY_SELECT; ++ return; ++ } ++ + if (*esc == 1) { + if (tstc()) { + c = getchar(); +@@ -165,6 +205,14 @@ static void bootmenu_loop(struct bootmen + if (c == '\e') { + *esc = 1; + *key = KEY_NONE; ++ } else { ++ *choice = find_choice(c); ++ if ((*choice >= 0 && *choice < menu->count - 1)) { ++ *key = KEY_CHOICE; ++ } else if (c == '0') { ++ *choice = menu->count - 1; ++ *key = KEY_CHOICE; ++ } + } + break; + case 1: +@@ -216,16 +264,17 @@ static char *bootmenu_choice_entry(void + struct bootmenu_data *menu = data; + struct bootmenu_entry *iter; + enum bootmenu_key key = KEY_NONE; ++ int choice = -1; + int esc = 0; + int i; + + while (1) { + if (menu->delay >= 0) { + /* Autoboot was not stopped */ +- bootmenu_autoboot_loop(menu, &key, &esc); ++ bootmenu_autoboot_loop(menu, &key, &esc, &choice); + } else { + /* Some key was pressed, so autoboot was stopped */ +- bootmenu_loop(menu, &key, &esc); ++ bootmenu_loop(menu, &key, &esc, &choice); + } + + switch (key) { +@@ -239,6 +288,12 @@ static char *bootmenu_choice_entry(void + ++menu->active; + /* no menu key selected, regenerate menu */ + return NULL; ++ case KEY_CHOICE: ++ menu->active = choice; ++ if (!menu->last_choiced) { ++ menu->last_choiced = true; ++ return NULL; ++ } + case KEY_SELECT: + iter = menu->first; + for (i = 0; i < menu->active; ++i) +@@ -294,6 +349,7 @@ static struct bootmenu_data *bootmenu_cr + menu->delay = delay; + menu->active = 0; + menu->first = NULL; ++ menu->last_choiced = false; + + default_str = env_get("bootmenu_default"); + if (default_str) +@@ -311,12 +367,19 @@ static struct bootmenu_data *bootmenu_cr + goto cleanup; + + len = sep-option; +- entry->title = malloc(len + 1); ++ entry->title = malloc(len + 4); + if (!entry->title) { + free(entry); + goto cleanup; + } +- memcpy(entry->title, option, len); ++ ++ if (i < ARRAY_SIZE(choice_chars)) { ++ len = sprintf(entry->title, "%c. %.*s", choice_chars[i], ++ len, option); ++ } else { ++ len = sprintf(entry->title, " %.*s", len, option); ++ } ++ + entry->title[len] = 0; + + len = strlen(sep + 1); +@@ -353,7 +416,7 @@ static struct bootmenu_data *bootmenu_cr + if (!entry) + goto cleanup; + +- entry->title = strdup("U-Boot console"); ++ entry->title = strdup("0. U-Boot console"); + if (!entry->title) { + free(entry); + goto cleanup; diff --git a/root/package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch b/root/package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch new file mode 100644 index 00000000..3f98f13c --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch @@ -0,0 +1,32 @@ +--- a/cmd/bootmenu.c ++++ b/cmd/bootmenu.c +@@ -39,6 +39,7 @@ struct bootmenu_data { + int active; /* active menu entry */ + int count; /* total count of menu entries */ + struct bootmenu_entry *first; /* first menu entry */ ++ char *mtitle; /* custom menu title */ + bool last_choiced; + }; + +@@ -471,7 +472,12 @@ static void menu_display_statusline(stru + printf(ANSI_CURSOR_POSITION, 1, 1); + puts(ANSI_CLEAR_LINE); + printf(ANSI_CURSOR_POSITION, 2, 1); +- puts(" *** U-Boot Boot Menu ***"); ++ ++ if (menu->mtitle) ++ puts(menu->mtitle); ++ else ++ puts(" *** U-Boot Boot Menu ***"); ++ + puts(ANSI_CLEAR_LINE_TO_END); + printf(ANSI_CURSOR_POSITION, 3, 1); + puts(ANSI_CLEAR_LINE); +@@ -525,6 +531,7 @@ static void bootmenu_show(int delay) + return; + } + ++ bootmenu->mtitle = env_get("bootmenu_title"); + for (iter = bootmenu->first; iter; iter = iter->next) { + if (!menu_item_add(menu, iter->key, iter)) + goto cleanup; diff --git a/root/package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch b/root/package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch new file mode 100644 index 00000000..f7f20216 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch @@ -0,0 +1,116 @@ +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -483,6 +483,12 @@ config CMD_ENV_EXISTS + Check if a variable is defined in the environment for use in + shell scripting. + ++config CMD_ENV_READMEM ++ bool "env readmem" ++ default y ++ help ++ Store memory content into environment variable. ++ + config CMD_ENV_CALLBACK + bool "env callbacks - print callbacks and their associated variables" + help +--- a/cmd/nvedit.c ++++ b/cmd/nvedit.c +@@ -408,6 +408,60 @@ int do_env_ask(struct cmd_tbl *cmdtp, in + } + #endif + ++#if defined(CONFIG_CMD_ENV_READMEM) ++int do_env_readmem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ char varstr[CONFIG_SYS_CBSIZE]; ++ const void *buf; ++ char *local_args[4]; ++ ulong addr, bytes = 6; ++ int hexdump = 0; ++ ++ /* ++ * Check the syntax: ++ * ++ * readmem [-b] name address [size] ++ */ ++ if (argc < 3) ++ return CMD_RET_USAGE; ++ ++ local_args[0] = argv[0]; ++ ++ if (!strncmp(argv[1], "-b", 3)) ++ hexdump = 1; ++ ++ local_args[1] = argv[hexdump + 1]; ++ local_args[2] = varstr; ++ local_args[3] = NULL; ++ ++ addr = simple_strtoul(argv[hexdump + 2], NULL, 16); ++ ++ if (!hexdump) ++ bytes = simple_strtoul(argv[hexdump + 3], NULL, 16); ++ ++ if (bytes < 1) ++ return 1; ++ ++ if ((hexdump * 3) * bytes >= CONFIG_SYS_CBSIZE) ++ return 1; ++ ++ buf = map_sysmem(addr, bytes); ++ if (!buf) ++ return 1; ++ ++ if (hexdump) { ++ sprintf(varstr, "%pM", buf); ++ } else { ++ memcpy(varstr, buf, bytes); ++ varstr[bytes] = '\0'; ++ } ++ unmap_sysmem(buf); ++ ++ /* Continue calling setenv code */ ++ return _do_env_set(flag, 3, local_args, H_INTERACTIVE); ++} ++#endif ++ + #if defined(CONFIG_CMD_ENV_CALLBACK) + static int print_static_binding(const char *var_name, const char *callback_name, + void *priv) +@@ -1189,6 +1243,9 @@ static struct cmd_tbl cmd_env_sub[] = { + U_BOOT_CMD_MKENT(load, 1, 0, do_env_load, "", ""), + #endif + U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""), ++#if defined(CONFIG_CMD_ENV_READMEM) ++ U_BOOT_CMD_MKENT(readmem, CONFIG_SYS_MAXARGS, 3, do_env_readmem, "", ""), ++#endif + #if defined(CONFIG_CMD_RUN) + U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), + #endif +@@ -1277,6 +1334,9 @@ static char env_help_text[] = + #if defined(CONFIG_CMD_NVEDIT_EFI) + "env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n" + #endif ++#if defined(CONFIG_CMD_ENV_READMEM) ++ "env readmem [-b] name address size - read variable from memory\n" ++#endif + #if defined(CONFIG_CMD_RUN) + "env run var [...] - run commands in an environment variable\n" + #endif +@@ -1386,6 +1446,17 @@ U_BOOT_CMD( + ); + #endif + ++#if defined(CONFIG_CMD_ENV_READMEM) ++U_BOOT_CMD_COMPLETE( ++ readmem, CONFIG_SYS_MAXARGS, 3, do_env_readmem, ++ "get environment variable from memory address", ++ "name [-b] address size\n" ++ " - store memory address to env variable\n" ++ " \"-b\": read binary ethaddr", ++ var_complete ++); ++#endif ++ + #if defined(CONFIG_CMD_RUN) + U_BOOT_CMD_COMPLETE( + run, CONFIG_SYS_MAXARGS, 1, do_run, diff --git a/root/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch b/root/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch new file mode 100644 index 00000000..587245d2 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch @@ -0,0 +1,78 @@ +--- a/cmd/pstore.c ++++ b/cmd/pstore.c +@@ -207,6 +207,58 @@ static int pstore_set(struct cmd_tbl *cm + } + + /** ++ * pstore_check() - Check for pstore records ++ * @cmdtp: Command data struct pointer ++ * @flag: Command flag ++ * @argc: Command-line argument count ++ * @argv: Array of command-line arguments ++ * ++ * Return: 0 if there are records in pstore, 1 otherwise ++ */ ++static int pstore_check(struct cmd_tbl *cmdtp, int flag, int argc, ++ char * const argv[]) ++{ ++ phys_addr_t ptr; ++ char *buffer; ++ u32 size; ++ int header_len = 0; ++ bool compressed; ++ ++ if (pstore_length == 0) { ++ printf("Please set PStore configuration\n"); ++ return CMD_RET_USAGE; ++ } ++ ++ if (buffer_size == 0) ++ pstore_init_buffer_size(); ++ ++ buffer = malloc_cache_aligned(buffer_size); ++ ++ ptr = pstore_addr; ++ phys_addr_t ptr_end = ptr + pstore_length - pstore_pmsg_size ++ - pstore_ftrace_size - pstore_console_size; ++ ++ while (ptr < ptr_end) { ++ size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, ++ pstore_record_size, buffer); ++ ptr += pstore_record_size; ++ ++ if (size == 0) ++ continue; ++ ++ header_len = pstore_read_kmsg_hdr(buffer, &compressed); ++ if (header_len == 0) ++ continue; ++ ++ free(buffer); ++ return 0; ++ } ++ ++ free(buffer); ++ return 1; ++} ++ ++/** + * pstore_print_buffer() - Print buffer + * @type: buffer type + * @buffer: buffer to print +@@ -458,6 +510,7 @@ static int pstore_save(struct cmd_tbl *c + + static struct cmd_tbl cmd_pstore_sub[] = { + U_BOOT_CMD_MKENT(set, 8, 0, pstore_set, "", ""), ++ U_BOOT_CMD_MKENT(check, 1, 0, pstore_check, "", ""), + U_BOOT_CMD_MKENT(display, 3, 0, pstore_display, "", ""), + U_BOOT_CMD_MKENT(save, 4, 0, pstore_save, "", ""), + }; +@@ -531,6 +584,8 @@ U_BOOT_CMD(pstore, 10, 0, do_pstore, + " 'pmsg-size' is the size of the user space logs record.\n" + " 'ecc-size' enables/disables ECC support and specifies ECC buffer size in\n" + " bytes (0 disables it, 1 is a special value, means 16 bytes ECC).\n" ++ "pstore check\n" ++ "- Returns true if there are records in pstore.\n" + "pstore display [record-type] [nb]\n" + "- Display existing records in pstore reserved memory. A 'record-type' can\n" + " be given to only display records of this kind. 'record-type' can be one\n" diff --git a/root/package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch b/root/package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch new file mode 100644 index 00000000..a6204c7b --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch @@ -0,0 +1,10 @@ +--- a/include/linux/types.h ++++ b/include/linux/types.h +@@ -1,6 +1,7 @@ + #ifndef _LINUX_TYPES_H + #define _LINUX_TYPES_H + ++typedef unsigned long long __u64; + #include + #include + #include diff --git a/root/package/boot/uboot-mediatek/patches/280-image-fdt-save-name-of-FIT-configuration-in-chosen-node.patch b/root/package/boot/uboot-mediatek/patches/280-image-fdt-save-name-of-FIT-configuration-in-chosen-node.patch new file mode 100644 index 00000000..76e272a2 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/280-image-fdt-save-name-of-FIT-configuration-in-chosen-node.patch @@ -0,0 +1,60 @@ +From patchwork Mon Mar 21 23:22:23 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 1607954 +Return-Path: +X-Original-To: incoming@patchwork.ozlabs.org +Delivered-To: patchwork-incoming@bilbo.ozlabs.org +Date: Mon, 21 Mar 2022 23:22:23 +0000 +From: Daniel Golle +To: u-boot@lists.denx.de +Cc: Simon Glass , Alexandru Gagniuc , + Patrick Delaunay , + Heinrich Schuchardt +Subject: [PATCH] image-fdt: save name of FIT configuration in '/chosen' node +Message-ID: +MIME-Version: 1.0 +Content-Disposition: inline +X-BeenThere: u-boot@lists.denx.de +X-Mailman-Version: 2.1.39 +Precedence: list +List-Id: U-Boot discussion +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: u-boot-bounces@lists.denx.de +Sender: "U-Boot" + +It can be useful for the OS (Linux) to know which configuration has +been chosen by U-Boot when launching a FIT image. +Store the name of the FIT configuration node used in a new string +attribute called 'bootconf' in the '/chosen' node in device tree. + +Signed-off-by: Daniel Golle +--- + boot/image-fdt.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/boot/image-fdt.c b/boot/image-fdt.c +index 692a9ad3e4..4017bc94a6 100644 +--- a/boot/image-fdt.c ++++ b/boot/image-fdt.c +@@ -601,6 +601,12 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, + goto err; + } + ++ /* Store name of configuration node as bootconf in /chosen node */ ++ if (images->fit_uname_cfg) ++ fdt_find_and_setprop(blob, "/chosen", "bootconf", ++ images->fit_uname_cfg, ++ strlen(images->fit_uname_cfg) + 1, 1); ++ + /* Update ethernet nodes */ + fdt_fixup_ethernet(blob); + #if CONFIG_IS_ENABLED(CMD_PSTORE) diff --git a/root/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch b/root/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch new file mode 100644 index 00000000..43270a7a --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch @@ -0,0 +1,51 @@ +--- a/board/mediatek/mt7622/mt7622_rfb.c ++++ b/board/mediatek/mt7622/mt7622_rfb.c +@@ -6,9 +6,16 @@ + + #include + #include ++#include ++#include + #include + #include + #include ++#include ++ ++#ifndef CONFIG_RESET_BUTTON_LABEL ++#define CONFIG_RESET_BUTTON_LABEL "reset" ++#endif + + DECLARE_GLOBAL_DATA_PTR; + +@@ -20,7 +27,19 @@ int board_init(void) + + int board_late_init(void) + { +- gd->env_valid = 1; //to load environment variable from persistent store ++ struct udevice *dev; ++ ++ if (!button_get_by_label(CONFIG_RESET_BUTTON_LABEL, &dev)) { ++ puts("reset button found\n"); ++#ifdef CONFIG_RESET_BUTTON_SETTLE_DELAY ++ mdelay(CONFIG_RESET_BUTTON_SETTLE_DELAY); ++#endif ++ if (button_get_state(dev) == BUTTON_ON) { ++ puts("button pushed, resetting environment\n"); ++ gd->env_valid = ENV_INVALID; ++ } ++ } ++ + env_relocate(); + return 0; + } +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -115,4 +115,8 @@ config MTK_BROM_HEADER_INFO + default "media=emmc" if TARGET_MT8516 || TARGET_MT8365 || TARGET_MT8183 + default "lk=1" if TARGET_MT7623 + ++config RESET_BUTTON_LABEL ++ string "Button to trigger factory reset" ++ default "reset" ++ + endif diff --git a/root/package/boot/uboot-mediatek/patches/301-mt7623-generic-reset-button-ignore-env.patch b/root/package/boot/uboot-mediatek/patches/301-mt7623-generic-reset-button-ignore-env.patch new file mode 100644 index 00000000..e144f42c --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/301-mt7623-generic-reset-button-ignore-env.patch @@ -0,0 +1,43 @@ +--- a/board/mediatek/mt7623/mt7623_rfb.c ++++ b/board/mediatek/mt7623/mt7623_rfb.c +@@ -4,8 +4,17 @@ + */ + + #include ++#include ++#include ++#include ++#include + #include + #include ++#include ++ ++#ifndef CONFIG_RESET_BUTTON_LABEL ++#define CONFIG_RESET_BUTTON_LABEL "reset" ++#endif + + DECLARE_GLOBAL_DATA_PTR; + +@@ -41,3 +50,22 @@ int mmc_get_env_dev(void) + return mmc_get_boot_dev(); + } + #endif ++ ++int board_late_init(void) ++{ ++ struct udevice *dev; ++ ++ if (!button_get_by_label(CONFIG_RESET_BUTTON_LABEL, &dev)) { ++ puts("reset button found\n"); ++#ifdef CONFIG_RESET_BUTTON_SETTLE_DELAY ++ mdelay(CONFIG_RESET_BUTTON_SETTLE_DELAY); ++#endif ++ if (button_get_state(dev) == BUTTON_ON) { ++ puts("button pushed, resetting environment\n"); ++ gd->env_valid = ENV_INVALID; ++ } ++ } ++ ++ env_relocate(); ++ return 0; ++} diff --git a/root/package/boot/uboot-mediatek/patches/350-add-support-for-Winbond-W25Q512JV.patch b/root/package/boot/uboot-mediatek/patches/350-add-support-for-Winbond-W25Q512JV.patch new file mode 100644 index 00000000..50df49d8 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/350-add-support-for-Winbond-W25Q512JV.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/spi/spi-nor-ids.c ++++ b/drivers/mtd/spi/spi-nor-ids.c +@@ -369,6 +369,8 @@ const struct flash_info spi_nor_ids[] = + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { INFO("w25q512jv", 0xef4020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ | ++ SPI_NOR_HAS_TB | SPI_NOR_HAS_LOCK) }, + { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + #endif diff --git a/root/package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch b/root/package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch new file mode 100644 index 00000000..01a550b3 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch @@ -0,0 +1,246 @@ +--- a/configs/mt7623n_bpir2_defconfig ++++ b/configs/mt7623n_bpir2_defconfig +@@ -4,53 +4,138 @@ CONFIG_ARCH_MEDIATEK=y + CONFIG_SYS_TEXT_BASE=0x81e00000 + CONFIG_SYS_MALLOC_F_LEN=0x4000 + CONFIG_NR_DRAM_BANKS=1 +-CONFIG_ENV_SIZE=0x1000 ++CONFIG_ENV_SIZE=0x10000 + CONFIG_ENV_OFFSET=0x100000 +-CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" + CONFIG_TARGET_MT7623=y ++CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" ++CONFIG_USE_DEFAULT_ENV_FILE=y + CONFIG_DISTRO_DEFAULTS=y + CONFIG_SYS_LOAD_ADDR=0x84000000 + CONFIG_FIT=y +-CONFIG_FIT_VERBOSE=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_BOARD_LATE_INIT=y + CONFIG_BOOTDELAY=3 ++CONFIG_BOOTP_SEND_HOSTNAME=y + CONFIG_DEFAULT_FDT_FILE="mt7623n-bananapi-bpi-r2.dtb" + CONFIG_SYS_CONSOLE_IS_IN_ENV=y ++CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r2_env" ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_RESET_BUTTON_LABEL="factory" ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_CMD_ENV_FLAGS=y + # CONFIG_DISPLAY_BOARDINFO is not set +-CONFIG_SYS_PROMPT="U-Boot> " ++CONFIG_SYS_PROMPT="MT7623> " + CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CACHE=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y + # CONFIG_CMD_ELF is not set + # CONFIG_CMD_XIMG is not set + CONFIG_CMD_GPIO=y +-CONFIG_CMD_GPT=y ++# CONFIG_CMD_GPT is not set ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++CONFIG_CMD_MBR=y + CONFIG_CMD_MMC=y +-CONFIG_CMD_READ=y +-# CONFIG_CMD_SETEXPR is not set ++CONFIG_CMD_MTD=y + # CONFIG_CMD_NFS is not set ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SATA=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_STRINGS=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_SCSI=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_ETH=y ++CONFIG_DM_GPIO=y ++CONFIG_DM_SCSI=y ++CONFIG_DM_MMC=y ++CONFIG_DM_MTD=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_SERIAL=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_DM_PCI=y ++CONFIG_DM_PWM=y ++CONFIG_AHCI=y ++CONFIG_AHCI_PCI=y ++CONFIG_SCSI_AHCI=y ++CONFIG_SCSI=y ++CONFIG_PWM_MTK=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y + CONFIG_ENV_OVERWRITE=y + CONFIG_ENV_IS_IN_MMC=y + CONFIG_SYS_RELOC_GD_ENV_ADDR=y + CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_NETCONSOLE=y + CONFIG_REGMAP=y + CONFIG_SYSCON=y + CONFIG_CLK=y ++CONFIG_LZMA=y ++CONFIG_MEDIATEK_ETH=y + # CONFIG_MMC_QUIRKS is not set + CONFIG_SUPPORT_EMMC_BOOT=y + CONFIG_MMC_HS400_SUPPORT=y + CONFIG_MMC_MTK=y ++CONFIG_MTK_AHCI=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_MTK_SERIAL=y ++CONFIG_MTK_TIMER=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY=y + CONFIG_PHY_FIXED=y +-CONFIG_DM_ETH=y +-CONFIG_MEDIATEK_ETH=y + CONFIG_PINCTRL=y + CONFIG_PINCONF=y + CONFIG_PINCTRL_MT7623=y + CONFIG_POWER_DOMAIN=y +-CONFIG_MTK_POWER_DOMAIN=y +-CONFIG_DM_SERIAL=y +-CONFIG_MTK_SERIAL=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y + CONFIG_SYSRESET=y + CONFIG_SYSRESET_WATCHDOG=y + CONFIG_TIMER=y +-CONFIG_MTK_TIMER=y ++CONFIG_VERSION_VARIABLE=y + CONFIG_WDT_MTK=y +-CONFIG_LZMA=y + # CONFIG_EFI_GRUB_ARM32_WORKAROUND is not set +--- /dev/null ++++ b/bananapi_bpi-r2_env +@@ -0,0 +1,70 @@ ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x88000000 ++dtaddr=0x83f00000 ++console=earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200 console=tty1 ++initrd_high=0xafffffff ++part_default=3 ++part_recovery=2 ++bootcmd=run boot_mmc ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7623-bananapi_bpi-r2-initramfs-recovery.itb ++bootfile_upg=openwrt-mediatek-mt7623-bananapi_bpi-r2-squashfs-sysupgrade.itb ++bootled_pwr=bpi-r2:pio:green ++bootled_rec=bpi-r2:pio:blue ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_first=if button factory ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_tftp_forever=led bpi-r2:pio:blue on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run mmc_write_production ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run mmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr ++boot_mmc=run boot_production ; run boot_recovery ++emmc_init=run emmc_init_bl && run emmc_init_openwrt ; env default bootcmd ; saveenv ++emmc_init_bl=run sdmmc_read_emmc_hdr && run emmc_write_hdr && run sdmmc_read_preloader && run emmc_write_preloader && run sdmmc_read_uboot && run emmc_write_uboot ++emmc_init_openwrt=run sdmmc_read_recovery && run emmc_write_recovery ; run sdmmc_read_production && run emmc_write_production ++emmc_write_hdr=mmc dev 0 0 ; mmc erase 0x0 0x2000 ; mmc write $loadaddr 0x0 0x4 ; mmc dev 0 1 ; mmc partconf 0 1 1 1 ; mmc erase 0x0 0x400 ; mmc write $loadaddr 0x0 0x4 ; mmc partconf 0 1 1 0 ++emmc_write_preloader=mmc dev 0 1 ; mmc partconf 0 1 1 1 ; mmc write $loadaddr 0x4 0x100 ; mmc partconf 0 1 1 0 ++emmc_write_uboot=mmc dev 0 0 ; part size mmc 0 1 part_size && part start mmc 0 1 part_addr && mmc write $loadaddr $part_addr 0x400 ++emmc_write_production=mmc dev 0 0 ; iminfo $loadaddr && part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol ++emmc_write_recovery=mmc dev 0 0 ; iminfo $loadaddr && part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol ++emmc_read_production=mmc dev 0 0 ; part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol ++emmc_read_recovery=mmc dev 0 0 ; part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol ++mmc_write_production=if test "$bootedfrom" = "SD" ; then run sdmmc_write_production ; else run emmc_write_production ; fi ++mmc_write_recovery=if test "$bootedfrom" = "SD" ; run sdmmc_write_recovery ; else run emmc_write_recovery ; fi ++mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$part_size && mmc write $loadaddr 0x$part_addr 0x$image_size ++mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 ++reset_factory=eraseenv && reset ++sdmmc_read_emmc_hdr=mmc dev 1 && mmc read $loadaddr 0x1ff8 0x8 ++sdmmc_read_preloader=mmc dev 1 && mmc read $loadaddr 0x4 0x100 ++sdmmc_read_uboot=mmc dev 1 ; part start mmc 1 1 part_addr && part size mmc 1 1 part_size && mmc read $loadaddr $part_addr $part_size ++sdmmc_read_production=mmc dev 1 ; part start mmc 1 $part_default part_addr && part size mmc 1 $part_default part_size && run mmc_read_vol ++sdmmc_read_recovery=mmc dev 1 ; part start mmc 1 $part_recovery part_addr && part size mmc 1 $part_recovery part_size && run mmc_read_vol ++sdmmc_write_production=iminfo $fileaddr && mmc dev 1 && part start mmc 1 $part_default part_addr && part size mmc 1 $part_default part_size && run mmc_write_vol ++sdmmc_write_recovery=iminfo $fileaddr && mmc dev 1 && part start mmc 1 $part_recovery part_addr && part size mmc 1 $part_recovery part_size && run mmc_write_vol ++_checkbootedfrom=setenv _checkbootedfrom ; if itest.l *81dffff0 == 434d4d65 ; then setenv bootedfrom eMMC ; else setenv bootedfrom SD ; fi ++_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv ++_firstboot=setenv _firstboot ; led $bootled_pwr off ;led $bootled_rec on ; run _checkbootedfrom _switch_to_menu _update_bootdev _update_bootcmd _update_bootcmd2 _init_env boot_first ++_set_bootcmd_sdmmc=setenv boot_production "led $bootled_rec off ; led $bootled_pwr on ; run sdmmc_read_production && bootm $loadaddr ; led $bootled_pwr off" ++_set_bootcmd_emmc=setenv boot_production "led $bootled_rec off ; led $bootled_pwr on ; run emmc_read_production && bootm $loadaddr ; led $bootled_pwr off" ++_update_bootcmd=setenv _update_bootcmd ; if test "$bootedfrom" = "SD" ; then run _set_bootcmd_sdmmc ; else run _set_bootcmd_emmc ; fi ; setenv _set_bootcmd_sdmmc ; setenv _set_bootcmd_emmc ++_set_bootcmd2_sdmmc=setenv boot_recovery "led $bootled_pwr off ; led $bootled_rec on ; run sdmmc_read_recovery && bootm $loadaddr ; led $bootled_rec off" ++_set_bootcmd2_emmc=setenv boot_recovery "led $bootled_pwr off ; led $bootled_rec on ; run emmc_read_recovery && bootm $loadaddr ; led $bootled_rec off" ++_update_bootcmd2=setenv _update_bootcmd2 ; if test "$bootedfrom" = "SD" ; then run _set_bootcmd2_sdmmc ; else run _set_bootcmd2_emmc ; fi ; setenv _set_bootcmd2_sdmmc ; setenv _set_bootcmd2_emmc ++_update_bootdev=setenv _update_bootdev ; if test "$bootedfrom" = "SD" ; then setenv bootargs "$console root=/dev/mmcblk1p65" ; else setenv bootargs "$console root=/dev/mmcblk0p65" ; fi ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title [$bootedfrom] $ver" ; run _set_bm2 ++_set_bm2=setenv _set_bm2 ; setenv bootmenu_2 "Boot production system from $bootedfrom.=run boot_production ; run bootmenu_confirm_return" ; run _set_bm3 ++_set_bm3=setenv _set_bm3 ; setenv bootmenu_3 "Boot recovery system from $bootedfrom.=run boot_recovery ; run bootmenu_confirm_return" ; run _set_bm4 ++_set_bm4=setenv _set_bm4 ; setenv bootmenu_4 "Load production system via TFTP then write to $bootedfrom.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return" ; run _set_bm5 ++_set_bm5=setenv _set_bm5 ; setenv bootmenu_5 "Load recovery system via TFTP then write to $bootedfrom.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return" ; run _set_bm5a ++_set_bm5a=setenv _set_bm5a ; if test "$bootedfrom" = "SD" ; then run _set_bm6 ; else setenv _set_bm6 ; setenv _menu_next 6 ; fi ; run _set_bmr ++_set_bm6=setenv _set_bm6 ; setenv bootmenu_6 "Install bootloader, recovery and production to eMMC.=run emmc_init ; run bootmenu_confirm_return" ; setenv _menu_next 7 ++_set_bmr=setenv _set_bmr ; setenv bootmenu_${_menu_next} "Reboot.=reset" ; setexpr _menu_next ${_menu_next} + 1 ; run _set_bmf ++_set_bmf=setenv _set_bmf ; setenv bootmenu_${_menu_next} "Reset all settings to factory defaults.=run reset_factory ; reset" ; setenv _menu_next +--- a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts +@@ -66,6 +66,15 @@ + default-state = "off"; + }; + }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ factory { ++ label = "factory"; ++ gpios = <&gpio 256 GPIO_ACTIVE_LOW>; ++ }; ++ }; + }; + + ð { diff --git a/root/package/boot/uboot-mediatek/patches/401-update-u7623-defconfig.patch b/root/package/boot/uboot-mediatek/patches/401-update-u7623-defconfig.patch new file mode 100644 index 00000000..ac870b86 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/401-update-u7623-defconfig.patch @@ -0,0 +1,202 @@ +--- a/configs/mt7623a_unielec_u7623_02_defconfig ++++ b/configs/mt7623a_unielec_u7623_02_defconfig +@@ -4,51 +4,135 @@ CONFIG_ARCH_MEDIATEK=y + CONFIG_SYS_TEXT_BASE=0x81e00000 + CONFIG_SYS_MALLOC_F_LEN=0x4000 + CONFIG_NR_DRAM_BANKS=1 +-CONFIG_ENV_SIZE=0x1000 ++CONFIG_ENV_SIZE=0x10000 + CONFIG_ENV_OFFSET=0x100000 + CONFIG_DEFAULT_DEVICE_TREE="mt7623a-unielec-u7623-02-emmc" ++CONFIG_USE_DEFAULT_ENV_FILE=y + CONFIG_TARGET_MT7623=y + CONFIG_DISTRO_DEFAULTS=y + CONFIG_SYS_LOAD_ADDR=0x84000000 + CONFIG_FIT=y +-CONFIG_FIT_VERBOSE=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_BOARD_LATE_INIT=y + CONFIG_BOOTDELAY=3 ++CONFIG_BOOTP_SEND_HOSTNAME=y + CONFIG_DEFAULT_FDT_FILE="mt7623a-unielec-u7623-02-emmc.dtb" + CONFIG_SYS_CONSOLE_IS_IN_ENV=y ++CONFIG_DEFAULT_ENV_FILE="unielec_u7623-02_env" ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_RESET_BUTTON_LABEL="factory" ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_CMD_ENV_FLAGS=y + # CONFIG_DISPLAY_BOARDINFO is not set +-CONFIG_SYS_PROMPT="U-Boot> " ++CONFIG_SYS_PROMPT="MT7623> " + CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BOOTZ=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CACHE=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y + # CONFIG_CMD_ELF is not set + # CONFIG_CMD_XIMG is not set + CONFIG_CMD_GPIO=y +-CONFIG_CMD_GPT=y ++# CONFIG_CMD_GPT is not set ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++CONFIG_CMD_MBR=y + CONFIG_CMD_MMC=y +-CONFIG_CMD_READ=y +-# CONFIG_CMD_SETEXPR is not set + # CONFIG_CMD_NFS is not set +-CONFIG_ENV_IS_IN_MMC=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SATA=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_STRINGS=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_SCSI=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_ETH=y ++CONFIG_DM_GPIO=y ++CONFIG_DM_SCSI=y ++CONFIG_DM_MMC=y ++CONFIG_DM_MTD=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_SERIAL=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_DM_PCI=y ++CONFIG_DM_PWM=y ++CONFIG_AHCI=y ++CONFIG_AHCI_PCI=y ++CONFIG_SCSI_AHCI=y ++CONFIG_SCSI=y ++CONFIG_PWM_MTK=y ++CONFIG_HUSH_PARSER=y + CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_SYS_MMC_ENV_DEV=0 ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MMC=y + CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_NETCONSOLE=y + CONFIG_REGMAP=y + CONFIG_SYSCON=y + CONFIG_CLK=y ++CONFIG_LZMA=y ++CONFIG_MEDIATEK_ETH=y + # CONFIG_MMC_QUIRKS is not set + CONFIG_SUPPORT_EMMC_BOOT=y + CONFIG_MMC_HS400_SUPPORT=y + CONFIG_MMC_MTK=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_MTK_SERIAL=y ++CONFIG_MTK_TIMER=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY=y + CONFIG_PHY_FIXED=y +-CONFIG_DM_ETH=y +-CONFIG_MEDIATEK_ETH=y + CONFIG_PINCTRL=y + CONFIG_PINCONF=y + CONFIG_PINCTRL_MT7623=y + CONFIG_POWER_DOMAIN=y +-CONFIG_MTK_POWER_DOMAIN=y +-CONFIG_DM_SERIAL=y +-CONFIG_MTK_SERIAL=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y + CONFIG_SYSRESET=y + CONFIG_SYSRESET_WATCHDOG=y + CONFIG_TIMER=y +-CONFIG_MTK_TIMER=y ++CONFIG_VERSION_VARIABLE=y + CONFIG_WDT_MTK=y +-CONFIG_LZMA=y +--- /dev/null ++++ b/unielec_u7623-02_env +@@ -0,0 +1,47 @@ ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x88000000 ++dtaddr=0x83f00000 ++console=earlycon=uart8250,mmio32,0x11004000 console=ttyS0,115200 ++initrd_high=0xafffffff ++part_default=3 ++part_recovery=2 ++bootcmd=run boot_mmc ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7623-unielec_u7623-02-initramfs-recovery.itb ++bootfile_upg=openwrt-mediatek-mt7623-unielec_u7623-02-squashfs-sysupgrade.itb ++bootled_rec=u7623-01:green:led3 ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Reboot.=reset ++bootmenu_7=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_first=if button factory ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_production=run emmc_read_production && bootm $loadaddr ++boot_recovery=run emmc_read_recovery && bootm $loadaddr ++boot_tftp_forever=led bpi-r64:pio:blue on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run emmc_write_production ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run emmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr ++boot_mmc=run boot_production ; run boot_recovery ++emmc_write_production=mmc dev 0 0 ; iminfo $loadaddr && part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol ++emmc_write_recovery=mmc dev 0 0 ; iminfo $loadaddr && part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol ++emmc_read_production=mmc dev 0 0 ; part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol ++emmc_read_recovery=mmc dev 0 0 ; part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol ++mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$part_size && mmc write $loadaddr 0x$part_addr 0x$image_size ++mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 ++reset_factory=eraseenv && reset ++_init_env=setenv _init_env ; saveenv ; saveenv ++_firstboot=setenv _firstboot ; run _switch_to_menu _update_bootdev _init_env boot_first ++_update_bootdev=setenv _update_bootdev ; setenv bootargs "$console root=/dev/mmcblk0p65" ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/root/package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch b/root/package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch new file mode 100644 index 00000000..781a6857 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch @@ -0,0 +1,71 @@ +--- a/arch/arm/dts/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm/dts/mt7622-bananapi-bpi-r64.dts +@@ -20,6 +20,7 @@ + + aliases { + spi0 = &snfi; ++ ethernet0 = ð + }; + + memory@40000000 { +@@ -27,6 +28,42 @@ + reg = <0x40000000 0x40000000>; + }; + ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ reset { ++ label = "reset"; ++ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; ++ }; ++ ++ wps { ++ label = "wps"; ++ gpios = <&gpio 102 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++/* ++ * red { ++ * label = "bpi-r64:pio:red"; ++ * gpios = <&gpio 88 GPIO_ACTIVE_HIGH>; ++ * default-state = "off"; ++ * }; ++ */ ++ green { ++ label = "bpi-r64:pio:green"; ++ gpios = <&gpio 89 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ blue { ++ label = "bpi-r64:pio:blue"; ++ gpios = <&gpio 85 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; +@@ -199,7 +236,7 @@ + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; +- cap-sd-highspeed; ++ cap-mmc-highspeed; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + non-removable; +@@ -210,7 +247,7 @@ + pinctrl-0 = <&mmc1_pins_default>; + status = "okay"; + bus-width = <4>; +- max-frequency = <50000000>; ++ max-frequency = <12000000>; + cap-sd-highspeed; + r_smpl = <1>; + vmmc-supply = <®_3p3v>; diff --git a/root/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64-snand.patch b/root/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64-snand.patch new file mode 100644 index 00000000..1dc2a848 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64-snand.patch @@ -0,0 +1,33 @@ +--- a/arch/arm/dts/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm/dts/mt7622-bananapi-bpi-r64.dts +@@ -19,7 +19,7 @@ + }; + + aliases { +- spi0 = &snfi; ++ spi0 = &snand; + ethernet0 = ð + }; + +@@ -205,17 +205,11 @@ + }; + }; + +-&snfi { +- pinctrl-names = "default", "snfi"; +- pinctrl-0 = <&snor_pins>; +- pinctrl-1 = <&snfi_pins>; ++&snand { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; + status = "okay"; +- +- spi-flash@0{ +- compatible = "jedec,spi-nor"; +- reg = <0>; +- u-boot,dm-pre-reloc; +- }; ++ quad-spi; + }; + + &uart0 { diff --git a/root/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch b/root/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch new file mode 100644 index 00000000..5ce3a7cd --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch @@ -0,0 +1,658 @@ +--- /dev/null ++++ b/configs/mt7622_bananapi_bpi-r64-sdmmc_defconfig +@@ -0,0 +1,159 @@ ++CONFIG_ARM=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_BOOTP_SEND_HOSTNAME=y ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64" ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_DEBUG_UART=y ++CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r64-sdmmc_env" ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_SMBIOS_PRODUCT_NAME="" ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_BOOTDELAY=30 ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_GPIO_HOG=y ++CONFIG_CMD_ENV_FLAGS=y ++CONFIG_FIT=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_DEFAULT_FDT_FILE="mediatek/mt7622-bananapi-bpi-r64.dtb" ++CONFIG_SYS_PROMPT="MT7622> " ++CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CACHE=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++# CONFIG_CMD_MBR is not set ++CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_UBI=y ++CONFIG_CMD_UBI_RENAME=y ++CONFIG_CMD_UBIFS=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_STRINGS=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_MMC=y ++CONFIG_DM_MTD=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_DM_PWM=y ++CONFIG_PWM_MTK=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_REDUNDAND_ENVIRONMENT=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_SYS_MMC_ENV_DEV=1 ++CONFIG_ENV_OFFSET=0x400000 ++CONFIG_ENV_OFFSET_REDUND=0x480000 ++CONFIG_ENV_SIZE=0x80000 ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_VERSION_VARIABLE=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_NETCONSOLE=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_DM_GPIO=y ++CONFIG_DM_SCSI=y ++CONFIG_AHCI=y ++CONFIG_AHCI_PCI=y ++CONFIG_SCSI_AHCI=y ++CONFIG_SCSI=y ++CONFIG_CMD_SCSI=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PHY_FIXED=y ++CONFIG_MTK_AHCI=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_MTD=y ++CONFIG_MTD_UBI_FASTMAP=y ++CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:512k(bl2),2048k(fip),-(ubi)" ++CONFIG_DM_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_PRE_CONSOLE_BUFFER=y ++CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_MMC=y ++CONFIG_MMC_DEFAULT_DEV=1 ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_MMC_SUPPORTS_TUNING=y ++CONFIG_SUPPORT_EMMC_BOOT=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SPI_NAND=y ++CONFIG_MTK_SPI_NAND_MTD=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_WDT_MTK=y ++CONFIG_LZO=y ++CONFIG_ZSTD=y ++CONFIG_HEXDUMP=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y ++CONFIG_USB=y ++CONFIG_USB_HOST=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y +--- /dev/null ++++ b/bananapi_bpi-r64-sdmmc_env +@@ -0,0 +1,82 @@ ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x48000000 ++bootargs=root=/dev/mmcblk1p65 ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi ++bootconf=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_sata=config-mt7622-bananapi-bpi-r64-sata ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb ++bootfile_emmcbl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-preloader.bin ++bootfile_emmcbl3=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-bl31-uboot.fip ++bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb ++bootled_pwr=bpi-r64:pio:green ++bootled_rec=bpi-r64:pio:blue ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) [SD card] ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from SD card.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from SD card.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to SD card.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to SD card.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Install bootloader, recovery and production to eMMC.=run emmc_init ; run bootmenu_confirm_return ++bootmenu_7=Install bootloader, recovery and production to NAND.=run ubi_init ; run bootmenu_confirm_return ++bootmenu_8=Reboot.=reset ++bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_production=led $bootled_pwr on ; run sdmmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off ++boot_recovery=led $bootled_rec on ; run sdmmc_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off ++boot_sdmmc=run boot_production ; run boot_recovery ++boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run sdmmc_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run sdmmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr ++boot_ubi=ubi part ubi && setenv bootargs && run boot_ubi_production ; run boot_ubi_recovery ++boot_ubi_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr ; led $bootled_pwr off ++boot_ubi_recovery=led $bootled_rec on ; run ubi_read_recovery ; bootm $loadaddr#$bootconf ; ubi remove recovery ; led $bootled_rec off ++check_ubi=ubi part ubi || run ubi_format ++emmc_init=run emmc_init_bl && run emmc_init_openwrt ; env default bootcmd ; saveenv ; saveenv ++emmc_init_bl=run sdmmc_read_emmc_bl2 && run emmc_write_bl2 && run sdmmc_read_emmc_hdr && run emmc_write_hdr && run sdmmc_read_emmc_fip && run emmc_write_fip ++emmc_init_openwrt=run sdmmc_read_recovery && iminfo $loadaddr && run emmc_write_recovery ; run sdmmc_read_production && iminfo $loadaddr && run emmc_write_production ++emmc_write_bl2=mmc dev 0 1 && mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $loadaddr 0x0 0x100 ; mmc partconf 0 1 1 0 ++emmc_write_fip=mmc dev 0 0 && mmc erase 0x1000 0x1000 && mmc write $loadaddr 0x1000 0x1000 && mmc erase 0x2000 0x800 ++emmc_write_hdr=mmc dev 0 0 && mmc erase 0x0 0x40 && mmc write $loadaddr 0x0 0x40 ++emmc_write_production=mmc dev 0 && part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol ++emmc_write_recovery=mmc dev 0 && part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol ++mmc_write_vol=imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$part_size && mmc write $loadaddr 0x$part_addr 0x$image_size ++mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size && setexpr filesize $image_size * 0x200 ++part_default=production ++part_recovery=recovery ++reset_factory=eraseenv && reset ++sdmmc_read_emmc_hdr=mmc dev 1 && part start mmc 1 install part_addr && mmc read $loadaddr $part_addr 0x40 ++sdmmc_read_emmc_bl2=mmc dev 1 && part start mmc 1 install part_addr && setexpr offset $part_addr + 0x400 && mmc read $loadaddr $offset 0x400 ++sdmmc_read_emmc_fip=mmc dev 1 && part start mmc 1 install part_addr && setexpr offset $part_addr + 0x1000 && mmc read $loadaddr $offset 0x1000 ++sdmmc_read_production=mmc dev 1 && part start mmc 1 $part_default part_addr && part size mmc 1 $part_default part_size && run mmc_read_vol ++sdmmc_read_recovery=mmc dev 1 && part start mmc 1 $part_recovery part_addr && part size mmc 1 $part_recovery part_size && run mmc_read_vol ++sdmmc_read_snand_bl2=mmc dev 1 && part start mmc 1 install part_addr && setexpr offset $part_addr + 0x2000 && mmc read $loadaddr $offset 0x400 ++sdmmc_read_snand_fip=mmc dev 1 && part start mmc 1 install part_addr && setexpr offset $part_addr + 0x2400 && mmc read $loadaddr $offset 0x1000 ++sdmmc_write_production=mmc dev 1 && part start mmc 1 $part_default part_addr && part size mmc 1 $part_default part_size && run mmc_write_vol ++sdmmc_write_recovery=mmc dev 1 && part start mmc 1 $part_recovery part_addr && part size mmc 1 $part_recovery part_size && run mmc_write_vol ++snand_write_fip=mtd erase fip && mtd write fip $loadaddr ++snand_write_bl2=mtd erase bl2 && mtd write bl2 $loadaddr ++ubi_create_env=ubi create ubootenv 0x100000 dynamic 0 ; ubi create ubootenv2 0x100000 dynamic 1 ; ubi create fit 0x100000 dynamic 2 ; ubi create recovery 0x100000 dynamic 3 ++ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset ++ubi_init=run ubi_init_bl && ubi detach && mtd erase ubi && ubi part ubi && run ubi_create_env && run ubi_init_openwrt ++ubi_init_openwrt=run sdmmc_read_recovery && iminfo $loadaddr && run ubi_write_recovery ; run sdmmc_read_production && iminfo $loadaddr && run ubi_write_production ++ubi_init_bl=run sdmmc_read_snand_bl2 && run snand_write_bl2 && run sdmmc_read_snand_fip && run snand_write_fip ++ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi ++ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs ++ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery ++ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data ++ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize ++ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize ++_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv ++_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" +--- /dev/null ++++ b/configs/mt7622_bananapi_bpi-r64-emmc_defconfig +@@ -0,0 +1,146 @@ ++CONFIG_ARM=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_BOOTP_SEND_HOSTNAME=y ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64" ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_DEBUG_UART=y ++CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r64-emmc_env" ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_SMBIOS_PRODUCT_NAME="" ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_BOOTDELAY=30 ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_GPIO_HOG=y ++CONFIG_CMD_ENV_FLAGS=y ++CONFIG_FIT=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_DEFAULT_FDT_FILE="mt7622-bananapi-bpi-r64" ++CONFIG_SYS_PROMPT="MT7622> " ++CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CACHE=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++# CONFIG_CMD_MBR is not set ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_STRINGS=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_MMC=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_DM_PWM=y ++CONFIG_PWM_MTK=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_REDUNDAND_ENVIRONMENT=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_SYS_MMC_ENV_DEV=0 ++CONFIG_ENV_OFFSET=0x400000 ++CONFIG_ENV_OFFSET_REDUND=0x480000 ++CONFIG_ENV_SIZE=0x80000 ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_VERSION_VARIABLE=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_NETCONSOLE=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_DM_GPIO=y ++CONFIG_DM_SCSI=y ++CONFIG_AHCI=y ++CONFIG_AHCI_PCI=y ++CONFIG_SCSI_AHCI=y ++CONFIG_SCSI=y ++CONFIG_CMD_SCSI=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PHY_FIXED=y ++CONFIG_MTK_AHCI=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_DM_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_PRE_CONSOLE_BUFFER=y ++CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_MMC=y ++CONFIG_MMC_DEFAULT_DEV=0 ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_MMC_SUPPORTS_TUNING=y ++CONFIG_SUPPORT_EMMC_BOOT=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_WDT_MTK=y ++CONFIG_LZO=y ++CONFIG_ZSTD=y ++CONFIG_HEXDUMP=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y ++CONFIG_USB=y ++CONFIG_USB_HOST=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y +--- /dev/null ++++ b/bananapi_bpi-r64-emmc_env +@@ -0,0 +1,56 @@ ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x48000000 ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi ++bootargs=root=/dev/mmcblk0p65 ++bootconf=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_sata=config-mt7622-bananapi-bpi-r64-sata ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb ++bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb ++bootfile_bl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-preloader.bin ++bootfile_fip=openwrt-mediatek-mt7622-bananapi_bpi-r64-emmc-bl31-uboot.fip ++bootled_pwr=bpi-r64:pio:green ++bootled_rec=bpi-r64:pio:blue ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) [eMMC] ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return ++bootmenu_7=Load BL2 preloader via TFTP then write to eMMC.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return ++bootmenu_8=Reboot.=reset ++bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_production=led $bootled_pwr on ; run emmc_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off ++boot_recovery=led $bootled_rec on ; run emmc_read_recovery && bootm $loadaddr#$bootconf ; led $bootled_rec off ++boot_emmc=run boot_production ; run boot_recovery ++boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run emmc_write_production ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run emmc_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2 ++boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr ++emmc_write_production=mmc dev 0 && part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_write_vol ++emmc_write_recovery=mmc dev 0 && part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_write_vol ++emmc_write_bl2=mmc dev 0 1 && mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $loadaddr 0x0 0x100 ; mmc partconf 0 1 1 0 ++emmc_write_fip=mmc dev 0 0 && mmc erase 0x1000 0x1000 && mmc write $loadaddr 0x1000 0x1000 && mmc erase 0x2000 0x800 ++emmc_read_production=mmc dev 0 && part start mmc 0 $part_default part_addr && part size mmc 0 $part_default part_size && run mmc_read_vol ++emmc_read_recovery=mmc dev 0 && part start mmc 0 $part_recovery part_addr && part size mmc 0 $part_recovery part_size && run mmc_read_vol ++mmc_write_vol=imszb $fileaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$part_size && mmc write $fileaddr 0x$part_addr 0x$image_size ++mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size ++part_default=production ++part_recovery=recovery ++reset_factory=eraseenv && reset ++_init_env=setenv _init_env ; setenv _create_env ; saveenv ; saveenv ++_firstboot=setenv _firstboot ; run _switch_to_menu ; run _init_env ; run boot_first ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" +--- /dev/null ++++ b/configs/mt7622_bananapi_bpi-r64-snand_defconfig +@@ -0,0 +1,140 @@ ++CONFIG_ARM=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_BOOTP_SEND_HOSTNAME=y ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64" ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_DEBUG_UART=y ++CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r64-snand_env" ++CONFIG_DISTRO_DEFAULTS=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_SMBIOS_PRODUCT_NAME="" ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_BOOTDELAY=30 ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_CMD_ENV_FLAGS=y ++CONFIG_FIT=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_DEFAULT_FDT_FILE="mediatek/mt7622-bananapi-bpi-r64.dtb" ++CONFIG_SYS_PROMPT="MT7622> " ++CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_EFIDEBUG=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++# CONFIG_CMD_MBR is not set ++CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_UBI=y ++CONFIG_CMD_UBI_RENAME=y ++CONFIG_CMD_UBIFS=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_MMC=y ++CONFIG_DM_MTD=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_REDUNDAND_ENVIRONMENT=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_ENV_IS_IN_UBI=y ++CONFIG_ENV_UBI_PART="ubi" ++CONFIG_ENV_UBI_VOLUME="ubootenv" ++CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_VERSION_VARIABLE=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_NETCONSOLE=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_PHY_FIXED=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_MTD=y ++CONFIG_MTD_UBI_FASTMAP=y ++CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:512k(bl2),2048k(fip),-(ubi)" ++CONFIG_DM_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_PRE_CONSOLE_BUFFER=y ++CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_MMC=y ++CONFIG_MMC_DEFAULT_DEV=1 ++CONFIG_MMC_MTK=y ++CONFIG_SUPPORT_EMMC_BOOT=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SPI_NAND=y ++CONFIG_MTK_SPI_NAND_MTD=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_WDT_MTK=y ++CONFIG_LZO=y ++CONFIG_ZSTD=y ++CONFIG_HEXDUMP=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y ++CONFIG_USB=y ++CONFIG_USB_HOST=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y +--- /dev/null ++++ b/bananapi_bpi-r64-snand_env +@@ -0,0 +1,57 @@ ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x48000000 ++bootargs=root=/dev/ubiblock0_2p1 ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi ++bootconf=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 ++bootconf_sata=config-mt7622-bananapi-bpi-r64-sata ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb ++bootfile_fip=openwrt-mediatek-mt7622-bananapi_bpi-r64-snand-bl31-uboot.fip ++bootfile_bl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-snand-preloader.bin ++bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb ++bootled_pwr=bpi-r64:pio:green ++bootled_rec=bpi-r64:pio:blue ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) [SPI-NAND] ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from NAND.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from NAND.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to NAND.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to NAND.=run boot_tftp_write_fip ; run bootmenu_confirm_return ++bootmenu_7=Load BL2 preloader via TFTP then write to NAND.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return ++bootmenu_8=Reboot.=reset ++bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off ++boot_recovery=led $bootled_rec on ; run ubi_read_recovery ; bootm $loadaddr#$bootconf ; ubi remove recovery ; led $bootled_rec off ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf ++boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && iminfo $loadaddr && ubi part ubi && run ubi_write_production ubi_prepare_rootfs ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && iminfo $loadaddr && ubi part ubi && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run boot_write_bl2 ++boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip ++boot_ubi=ubi part ubi && run boot_production ; run boot_recovery ++boot_write_bl2=mtd erase bl2 && mtd write spi-nand0 $loadaddr 0x0 0x20000 && mtd write spi-nand0 $loadaddr 0x20000 0x20000 && mtd write spi-nand0 $loadaddr 0x40000 0x20000 && mtd write spi-nand0 $loadaddr 0x60000 0x20000 ++boot_write_fip=mtd erase fip && mtd write fip $loadaddr ++check_ubi=ubi part ubi || run ubi_format ++reset_factory=ubi part ubi ; ubi write 0x0 ubootenv 0x0 ; ubi write 0x0 ubootenv2 0x0 ; ubi remove rootfs_data ++ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset ++ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi ++ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs ++ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery ++ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data ++ubi_write_production=ubi check fit && env exists replacevol && ubi remove fit ; if ubi check fit ; then else run ubi_remove_rootfs ; ubi create fit $filesize dynamic 2 && ubi write $loadaddr fit $filesize ; fi ++ubi_write_recovery=ubi check recovery && env exists replacevol && ubi remove recovery ; if ubi check recovery ; then else run ubi_remove_rootfs ; ubi create recovery $filesize dynamic 3 && ubi write $loadaddr recovery $filesize ; fi ++_create_env=ubi create ubootenv 0x100000 dynamic 0 ; ubi create ubootenv2 0x100000 dynamic 1 ; ubi create fit 0x100000 dynamic 2 ; ubi create recovery 0x100000 dynamic 3 ++_init_env=setenv _init_env ; if ubi check ubootenv && ubi check ubootenv2 ; then else run _create_env ; fi ; setenv _create_env ; saveenv || run ubi_format ; saveenv || run ubi_format ++_firstboot=setenv _firstboot ; run _switch_to_menu ; run check_ubi ; run _init_env ; run boot_first ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/root/package/boot/uboot-mediatek/patches/405-dts-mt7623n-bpi-r2-fix-leds.patch b/root/package/boot/uboot-mediatek/patches/405-dts-mt7623n-bpi-r2-fix-leds.patch new file mode 100644 index 00000000..87481929 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/405-dts-mt7623n-bpi-r2-fix-leds.patch @@ -0,0 +1,25 @@ +--- a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts +@@ -50,19 +50,19 @@ + + blue { + label = "bpi-r2:pio:blue"; +- gpios = <&gpio 241 GPIO_ACTIVE_HIGH>; ++ gpios = <&gpio 240 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + green { + label = "bpi-r2:pio:green"; +- gpios = <&gpio 240 GPIO_ACTIVE_HIGH>; ++ gpios = <&gpio 241 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + red { + label = "bpi-r2:pio:red"; +- gpios = <&gpio 239 GPIO_ACTIVE_HIGH>; ++ gpios = <&gpio 239 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; diff --git a/root/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch b/root/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch new file mode 100644 index 00000000..fde679f3 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch @@ -0,0 +1,407 @@ +--- /dev/null ++++ b/configs/mt7622_linksys_e8450_defconfig +@@ -0,0 +1,136 @@ ++CONFIG_ARM=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_BOOTP_SEND_HOSTNAME=y ++CONFIG_DEFAULT_ENV_FILE="linksys_e8450_env" ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-linksys-e8450-ubi" ++CONFIG_DEBUG_UART=y ++CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:512k(bl2),1280k(fip),1024k(factory),256k(reserved),-(ubi)" ++CONFIG_SMBIOS_PRODUCT_NAME="" ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_BOOTDELAY=30 ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_GPIO_HOG=y ++CONFIG_CMD_ENV_FLAGS=y ++CONFIG_FIT=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LED=y ++CONFIG_LED_BLINK=y ++CONFIG_LED_GPIO=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_DEFAULT_FDT_FILE="mt7622-linksys-e8450" ++CONFIG_SYS_PROMPT="MT7622> " ++CONFIG_CMD_BOOTMENU=y ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_FS_UUID=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LICENSE=y ++CONFIG_CMD_LINK_LOCAL=y ++# CONFIG_CMD_MBR is not set ++CONFIG_CMD_MTD=y ++CONFIG_CMD_MTDPART=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++CONFIG_CMD_UBI=y ++CONFIG_CMD_UBI_RENAME=y ++CONFIG_CMD_UBIFS=y ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SNTP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_UUID=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_REGULATOR_GPIO=y ++CONFIG_DM_USB=y ++CONFIG_HUSH_PARSER=y ++CONFIG_SYS_REDUNDAND_ENVIRONMENT=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_ENV_IS_IN_UBI=y ++CONFIG_ENV_UBI_PART="ubi" ++CONFIG_ENV_UBI_VOLUME="ubootenv" ++CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_VERSION_VARIABLE=y ++CONFIG_PARTITION_UUIDS=y ++CONFIG_NETCONSOLE=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_DM_MTD=y ++CONFIG_DM_GPIO=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PHY_FIXED=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_MTD=y ++CONFIG_MTD_UBI_FASTMAP=y ++CONFIG_DM_PCI=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_PRE_CONSOLE_BUFFER=y ++CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SPI_NAND=y ++CONFIG_MTK_SPI_NAND_MTD=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_WDT_MTK=y ++CONFIG_LZO=y ++CONFIG_ZSTD=y ++CONFIG_HEXDUMP=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y ++CONFIG_USB=y ++CONFIG_USB_HOST=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y +--- /dev/null ++++ b/arch/arm/dts/mt7622-linksys-e8450-ubi.dts +@@ -0,0 +1,195 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2019 MediaTek Inc. ++ * Author: Sam Shih ++ */ ++ ++/dts-v1/; ++#include "mt7622.dtsi" ++#include "mt7622-u-boot.dtsi" ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ model = "mt7622-linksys-e8450-ubi"; ++ compatible = "mediatek,mt7622", "linksys,e8450-ubi"; ++ chosen { ++ stdout-path = &uart0; ++ tick-timer = &timer0; ++ }; ++ ++ aliases { ++ spi0 = &snand; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ factory { ++ label = "reset"; ++ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; ++ }; ++ ++ wps { ++ label = "wps"; ++ gpios = <&gpio 102 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led_power: power_blue { ++ label = "power:blue"; ++ gpios = <&gpio 95 GPIO_ACTIVE_LOW>; ++ default-state = "on"; ++ }; ++ ++ power_orange { ++ label = "power:orange"; ++ gpios = <&gpio 96 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ inet_blue { ++ label = "inet:blue"; ++ gpios = <&gpio 97 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ inet_orange { ++ label = "inet:orange"; ++ gpios = <&gpio 98 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0x40000000 0x20000000>; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; ++ status = "okay"; ++ ++ pcie@0,0 { ++ status = "okay"; ++ }; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pinctrl { ++ pcie0_pins: pcie0-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie0_pad_perst", ++ "pcie0_1_waken", ++ "pcie0_1_clkreq"; ++ }; ++ }; ++ ++ pcie1_pins: pcie1-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie1_pad_perst", ++ "pcie1_0_waken", ++ "pcie1_0_clkreq"; ++ }; ++ }; ++ ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ ++ uart0_pins: uart0 { ++ mux { ++ function = "uart"; ++ groups = "uart0_0_tx_rx" ; ++ }; ++ }; ++ ++ watchdog_pins: watchdog-default { ++ mux { ++ function = "watchdog"; ++ groups = "watchdog"; ++ }; ++ }; ++}; ++ ++&snand { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; ++ status = "okay"; ++ quad-spi; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; ++ status = "okay"; ++}; ++ ++&watchdog { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&watchdog_pins>; ++ status = "okay"; ++}; ++ ++ð { ++ status = "okay"; ++ mediatek,gmac-id = <0>; ++ phy-mode = "sgmii"; ++ mediatek,switch = "mt7531"; ++ reset-gpios = <&gpio 54 GPIO_ACTIVE_HIGH>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++}; ++ ++&ssusb { ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ status = "okay"; ++}; ++ ++&u3phy { ++ status = "okay"; ++}; +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -1133,6 +1133,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt7622-rfb.dtb \ + mt7623a-unielec-u7623-02-emmc.dtb \ + mt7622-bananapi-bpi-r64.dtb \ ++ mt7622-linksys-e8450-ubi.dtb \ + mt7623n-bananapi-bpi-r2.dtb \ + mt7629-rfb.dtb \ + mt8183-pumpkin.dtb \ +--- /dev/null ++++ b/linksys_e8450_env +@@ -0,0 +1,57 @@ ++ethaddr_factory=mtd read spi-nand0 0x40080000 0x220000 0x20000 && env readmem -b ethaddr 0x4009fff4 0x6 ; setenv ethaddr_factory ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x48000000 ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi ++bootconf=config-1 ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7622-linksys_e8450-ubi-initramfs-recovery.itb ++bootfile_bl2=openwrt-mediatek-mt7622-linksys_e8450-ubi-preloader.bin ++bootfile_fip=openwrt-mediatek-mt7622-linksys_e8450-ubi-bl31-uboot.fip ++bootfile_upg=openwrt-mediatek-mt7622-linksys_e8450-ubi-squashfs-sysupgrade.itb ++bootled_pwr=power:blue ++bootled_rec=inet:orange on ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from flash.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to flash.=run boot_tftp_write_fip ; run bootmenu_confirm_return ++bootmenu_7=Load BL2 preloader via TFTP then write to flash.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return ++bootmenu_8=Reboot.=reset ++bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_first=if button reset ; then led $bootled_rec on ; run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off ++boot_recovery=led $bootled_rec on ; run ubi_read_recovery ; bootm $loadaddr#$bootconf ; ubi remove recovery ; led $bootled_rec off ++boot_serial_write_bl2=loadx $loadaddr 115200 && run boot_write_bl2 ++boot_serial_write_fip=loadx $loadaddr 115200 && run boot_write_fip ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf ++boot_tftp_forever=led $bootled_rec on ; while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && iminfo $loadaddr && ubi part ubi && run ubi_write_production ubi_prepare_rootfs ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && iminfo $loadaddr && ubi part ubi && run ubi_write_recovery ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi ++boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run boot_write_bl2 ++boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip ++boot_ubi=ubi part ubi && run boot_production ; run boot_recovery ++boot_write_bl2=mtd erase bl2 && mtd write spi-nand0 $loadaddr 0x0 0x20000 && mtd write spi-nand0 $loadaddr 0x20000 0x20000 && mtd write spi-nand0 $loadaddr 0x40000 0x20000 && mtd write spi-nand0 $loadaddr 0x60000 0x20000 ++boot_write_fip=mtd erase fip && mtd write fip $loadaddr ++check_ubi=ubi part ubi || run ubi_format ++reset_factory=ubi part ubi ; ubi write 0x0 ubootenv 0x0 ; ubi write 0x0 ubootenv2 0x0 ; ubi remove rootfs_data ++ubi_format=ubi detach ; mtd erase ubi && ubi part ubi ; reset ++ubi_prepare_rootfs=if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi ++ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs ++ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery ++ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data ++ubi_write_production=ubi check fit && env exists replacevol && ubi remove fit ; if ubi check fit ; then else run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize ; fi ++ubi_write_recovery=ubi check recovery && env exists replacevol && ubi remove recovery ; if ubi check recovery ; then else run ubi_remove_rootfs ; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize ; fi ++_create_env=ubi create ubootenv 0x100000 dynamic ; ubi create ubootenv2 0x100000 dynamic ++_init_env=setenv _init_env ; if ubi check ubootenv && ubi check ubootenv2 ; then else run _create_env ; fi ; setenv _create_env ; saveenv || run ubi_format ; saveenv || run ubi_format ++_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run check_ubi ; run _init_env ; run boot_first ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" diff --git a/root/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch b/root/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch new file mode 100644 index 00000000..09a72742 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch @@ -0,0 +1,454 @@ +--- /dev/null ++++ b/configs/mt7622_ubnt_unifi-6-lr_defconfig +@@ -0,0 +1,141 @@ ++CONFIG_ARM=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_SYS_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_MTDPARTS_DEFAULT="mtdparts=nor0:128k(bl2),640k(fip),64k(u-boot-env),256k(factory),64k(eeprom),15232k(recovery),-(firmware)" ++CONFIG_ENV_IS_IN_MTD=y ++CONFIG_ENV_MTD_NAME="nor0" ++CONFIG_ENV_SIZE_REDUND=0x4000 ++CONFIG_ENV_SIZE=0x4000 ++CONFIG_ENV_OFFSET=0xc0000 ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_RESET_BUTTON_SETTLE_DELAY=400 ++CONFIG_BOOTP_SEND_HOSTNAME=y ++CONFIG_DEFAULT_ENV_FILE="ubnt_unifi-6-lr_env" ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-ubnt-unifi-6-lr" ++CONFIG_DEBUG_UART=y ++CONFIG_SMBIOS_PRODUCT_NAME="" ++CONFIG_AUTOBOOT_KEYED=y ++CONFIG_BOOTDELAY=30 ++CONFIG_AUTOBOOT_MENU_SHOW=y ++CONFIG_CFB_CONSOLE_ANSI=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_GPIO_HOG=y ++CONFIG_CMD_ENV_FLAGS=y ++CONFIG_FIT=y ++CONFIG_FIT_ENABLE_SHA256_SUPPORT=y ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_DEFAULT_FDT_FILE="mt7622-ubnt-unifi-6-lr" ++CONFIG_SYS_PROMPT="MT7622> " ++# CONFIG_LEGACY_IMAGE_FORMAT is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_EFI is not set ++# CONFIG_EFI_LOADER is not set ++CONFIG_CMD_BOOTMENU=y ++# CONFIG_CMD_BOOTEFI is not set ++CONFIG_CMD_BOOTP=y ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CDP=y ++CONFIG_CMD_DHCP=y ++CONFIG_CMD_DNS=y ++CONFIG_CMD_ECHO=y ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_BOOTEFI_BOOTMGR is not set ++CONFIG_CMD_ENV_READMEM=y ++CONFIG_CMD_ERASEENV=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_HASH=y ++CONFIG_CMD_ITEST=y ++CONFIG_CMD_LED=y ++CONFIG_CMD_LINK_LOCAL=y ++# CONFIG_CMD_MBR is not set ++CONFIG_CMD_MTD=y ++CONFIG_CMD_MTDPART=y ++# CONFIG_CMD_PCI is not set ++CONFIG_CMD_SF_TEST=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PXE=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_TFTPBOOT=y ++CONFIG_CMD_TFTPSRV=y ++# CONFIG_CMD_UNLZ4 is not set ++CONFIG_CMD_ASKENV=y ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 ++CONFIG_CMD_RARP=y ++CONFIG_CMD_SETEXPR=y ++CONFIG_CMD_SLEEP=y ++CONFIG_CMD_SOURCE=y ++CONFIG_CMD_UUID=y ++CONFIG_DISPLAY_CPUINFO=y ++CONFIG_DM_ETH=y ++CONFIG_DM_ETH_PHY=y ++CONFIG_DM_GPIO=y ++CONFIG_DM_MDIO=y ++CONFIG_DM_MTD=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_REGULATOR_GPIO=y ++# CONFIG_DM_MMC is not set ++CONFIG_DM_SERIAL=y ++CONFIG_DM_SPI=y ++CONFIG_DM_SPI_FLASH=y ++CONFIG_HUSH_PARSER=y ++# CONFIG_PARTITION_UUIDS is not set ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++# CONFIG_LED is not set ++# CONFIG_LZ4 is not set ++CONFIG_VERSION_VARIABLE=y ++CONFIG_NETCONSOLE=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_PHY=y ++CONFIG_PHY_FIXED=y ++CONFIG_PHYLIB_10G=y ++CONFIG_PHY_AQUANTIA=y ++CONFIG_PHY_ADDR_ENABLE=y ++CONFIG_PHY_ADDR=8 ++CONFIG_MEDIATEK_ETH=y ++CONFIG_MTD=y ++# CONFIG_MMC is not set ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_PRE_CONSOLE_BUFFER=y ++CONFIG_PRE_CON_BUF_ADDR=0x4007EF00 ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_RAM=y ++CONFIG_MTK_SERIAL=y ++CONFIG_SPI=y ++CONFIG_MTK_SNFI_SPI=y ++CONFIG_MTK_SNOR=y ++CONFIG_SYSRESET_WATCHDOG=y ++CONFIG_WDT_MTK=y ++CONFIG_HEXDUMP=y ++CONFIG_RANDOM_UUID=y ++CONFIG_REGEX=y ++CONFIG_SPI_FLASH=y ++CONFIG_SPI_FLASH_BAR=y ++CONFIG_SPI_FLASH_MTD=y ++CONFIG_SPI_FLASH_UNLOCK_ALL=y ++CONFIG_SPI_FLASH_EON=y ++CONFIG_SPI_FLASH_GIGADEVICE=y ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_SPI_FLASH_SPANSION=y ++CONFIG_SPI_FLASH_STMICRO=y ++CONFIG_SPI_FLASH_SST=y ++CONFIG_SPI_FLASH_WINBOND=y ++CONFIG_SPI_FLASH_XMC=y +--- /dev/null ++++ b/arch/arm/dts/mt7622-ubnt-unifi-6-lr.dts +@@ -0,0 +1,202 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2019 MediaTek Inc. ++ * Author: Sam Shih ++ */ ++ ++/dts-v1/; ++#include "mt7622.dtsi" ++#include "mt7622-u-boot.dtsi" ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ model = "mt7622-ubnt-unifi-6-lr"; ++ compatible = "mediatek,mt7622", "ubnt,unifi-6-lr"; ++ ++ chosen { ++ stdout-path = &uart0; ++ tick-timer = &timer0; ++ }; ++ ++ aliases { ++ spi0 = &snor; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ u-boot,dm-pre-reloc; ++ ++ reset { ++ label = "reset"; ++ gpios = <&gpio 62 GPIO_ACTIVE_LOW>; ++ u-boot,dm-pre-reloc; ++ }; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0x40000000 0x20000000>; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; ++ status = "okay"; ++ ++ pcie@0,0 { ++ status = "okay"; ++ }; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pinctrl { ++ eth_pins: eth-pins { ++ mux { ++ function = "eth"; ++ groups = "mdc_mdio", "rgmii_via_gmac2"; ++ }; ++ }; ++ ++ pcie0_pins: pcie0-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie0_pad_perst", ++ "pcie0_1_waken", ++ "pcie0_1_clkreq"; ++ }; ++ }; ++ ++ pcie1_pins: pcie1-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie1_pad_perst", ++ "pcie1_0_waken", ++ "pcie1_0_clkreq"; ++ }; ++ }; ++ ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ ++ snor_pins: snor-pins { ++ mux { ++ function = "flash"; ++ groups = "spi_nor"; ++ }; ++ }; ++ ++ uart0_pins: uart0 { ++ mux { ++ function = "uart"; ++ groups = "uart0_0_tx_rx" ; ++ }; ++ }; ++ ++ watchdog_pins: watchdog-default { ++ mux { ++ function = "watchdog"; ++ groups = "watchdog"; ++ }; ++ }; ++}; ++ ++&snfi { ++ pinctrl-names = "default", "snfi"; ++ pinctrl-0 = <&snor_pins>; ++ pinctrl-1 = <&snfi_pins>; ++ status = "okay"; ++ ++ spi-flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ u-boot,dm-pre-reloc; ++ }; ++}; ++ ++&snor { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snor_pins>; ++ status = "okay"; ++ ++ spi-flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <4>; ++ u-boot,dm-pre-reloc; ++ }; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; ++ status = "okay"; ++}; ++ ++&watchdog { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&watchdog_pins>; ++ status = "okay"; ++}; ++ ++ð { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <ð_pins>; ++ ++ mediatek,gmac-id = <0>; ++ phy-mode = "sgmii"; ++ phy-handle = <&gphy>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ ++ mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gphy: ethernet-phy@8 { ++ /* Marvell AQRate AQR112W - no driver */ ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reg = <0x8>; ++ }; ++ }; ++}; +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -1134,6 +1134,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt7623a-unielec-u7623-02-emmc.dtb \ + mt7622-bananapi-bpi-r64.dtb \ + mt7622-linksys-e8450-ubi.dtb \ ++ mt7622-ubnt-unifi-6-lr.dtb \ + mt7623n-bananapi-bpi-r2.dtb \ + mt7629-rfb.dtb \ + mt8183-pumpkin.dtb \ +--- /dev/null ++++ b/ubnt_unifi-6-lr_env +@@ -0,0 +1,50 @@ ++ethaddr_factory=mtd read nor0 $loadaddr 0x110000 0x10000 && env readmem -b ethaddr $loadaddr 0x6 ; setenv ethaddr_factory ++ipaddr=192.168.1.1 ++serverip=192.168.1.254 ++loadaddr=0x48000000 ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi ++bootdelay=0 ++bootfile=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-initramfs-recovery.itb ++bootfile_bl2=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-preloader.bin ++bootfile_fip=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-bl31-uboot.fip ++bootfile_upg=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-squashfs-sysupgrade.itb ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 ++bootmenu_default=0 ++bootmenu_delay=0 ++bootmenu_title= ( ( ( OpenWrt ) ) ) ++bootmenu_0=Initialize environment.=run _firstboot ++bootmenu_0d=Run default boot command.=run boot_default ++bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return ++bootmenu_2=Boot production system from flash.=run boot_production ; run bootmenu_confirm_return ++bootmenu_3=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return ++bootmenu_4=Load production system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_production ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to flash.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_recovery ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return ++bootmenu_6=Load BL31+U-Boot FIP via TFTP then write to flash.=run boot_tftp_write_fip ; run bootmenu_confirm_return ++bootmenu_7=Load BL2 preloader via TFTP then write to flash.=run boot_tftp_write_preloader ; run bootmenu_confirm_return ++bootmenu_8=Reboot.=reset ++bootmenu_9=Reset all settings to factory defaults.=run reset_factory ; reset ++boot_first=if button reset ; then run boot_tftp_recovery ; setenv flag_recover 1 ; run boot_default ; fi ; bootmenu ++boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_forever ++boot_production=run nor_read_production && bootm $loadaddr ++boot_recovery=run nor_read_recovery ; bootm $loadaddr ++boot_serial_write_fip=loadx $loadaddr 115200 && run boot_write_fip ++boot_serial_write_preloader=loadx $loadaddr 115200 && run boot_write_preloader ++boot_tftp_forever=while true ; do run boot_tftp_recovery ; sleep 1 ; done ++boot_tftp_production=tftpboot $loadaddr $bootfile_upg && env exists replacevol && iminfo $loadaddr && run nor_write_production ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp_recovery=tftpboot $loadaddr $bootfile && env exists replacevol && iminfo $loadaddr && run nor_write_recovery ; if env exists noboot ; then else bootm $loadaddr ; fi ++boot_tftp=tftpboot $loadaddr $bootfile && bootm $loadaddr ++boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run boot_write_fip ++boot_tftp_write_preloader=tftpboot $loadaddr $bootfile_bl2 && run boot_write_preloader ++boot_nor=run boot_production ; run boot_recovery ++boot_write_fip=mtd erase nor0 0x20000 0x80000 && mtd write nor0 $loadaddr 0x20000 0x80000 ++boot_write_preloader=mtd erase nor0 0x0 0x20000 && mtd write nor0 $loadaddr 0x0 0x20000 ++reset_factory=mtd erase nor0 0xc0000 0x10000 && reset ++nor_read_production=mtd read nor0 $loadaddr 0x1000000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x1000000 $image_size ++nor_read_recovery=mtd read nor0 $loadaddr 0x120000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x120000 $image_size ++nor_pad_size=imsz $loadaddr image_size ; setexpr image_eb $image_size / 0x1000 ; setexpr tmp1 image_size % 0x1000 ; test 0x$tmp1 -gt 0 && setexpr image_eb $image_eb + 1 ; setexpr image_eb $image_eb * 0x1000 ++nor_write_production=run nor_pad_size ; test 0x$image_eb -le 0x3000000 && mtd erase nor0 0x1000000 0x$image_eb && mtd write nor0 $loadaddr 0x1000000 $filesize ++nor_write_recovery=run nor_pad_size ; test 0x$image_eb -le 0xee0000 && mtd erase nor0 0x120000 0x$image_eb && mtd write nor0 $loadaddr 0x120000 $filesize ++_init_env=setenv _init_env ; saveenv ++_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first ++_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title ++_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" +--- a/common/board_r.c ++++ b/common/board_r.c +@@ -78,6 +78,7 @@ + #ifdef CONFIG_EFI_SETUP_EARLY + #include + #endif ++#include + + DECLARE_GLOBAL_DATA_PTR; + +@@ -417,6 +418,21 @@ static int initr_onenand(void) + } + #endif + ++#if defined(CONFIG_SPI_FLASH) ++/* probe SPI FLASH */ ++static int initr_spiflash(void) ++{ ++ 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); ++ return 0; ++} ++#endif ++ + #ifdef CONFIG_MMC + static int initr_mmc(void) + { +@@ -705,6 +721,9 @@ static init_fnc_t init_sequence_r[] = { + #ifdef CONFIG_CMD_ONENAND + initr_onenand, + #endif ++#ifdef CONFIG_SPI_FLASH ++ initr_spiflash, ++#endif + #ifdef CONFIG_MMC + initr_mmc, + #endif diff --git a/root/package/boot/uboot-mediatek/patches/500-board-mt7623-fix-mmc-detect.patch b/root/package/boot/uboot-mediatek/patches/500-board-mt7623-fix-mmc-detect.patch new file mode 100644 index 00000000..2f0ed85e --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/500-board-mt7623-fix-mmc-detect.patch @@ -0,0 +1,21 @@ +--- a/board/mediatek/mt7623/mt7623_rfb.c ++++ b/board/mediatek/mt7623/mt7623_rfb.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -31,8 +32,9 @@ int mmc_get_boot_dev(void) + { + int g_mmc_devid = -1; + char *uflag = (char *)0x81DFFFF0; ++ struct blk_desc *desc; + +- if (!find_mmc_device(1)) ++ if (blk_get_device_by_str("mmc", "1", &desc) < 0) + return 0; + + if (strncmp(uflag,"eMMC",4)==0) { diff --git a/root/target/linux/mediatek/image/mt7622.mk b/root/target/linux/mediatek/image/mt7622.mk index 39bc7bc2..4d325e64 100644 --- a/root/target/linux/mediatek/image/mt7622.mk +++ b/root/target/linux/mediatek/image/mt7622.mk @@ -12,6 +12,23 @@ define Image/Prepare echo -ne '\xde\xad\xc0\xde' > $(KDIR)/ubi_mark endef +define Build/append-image + cp "$(BIN_DIR)/$(IMG_PREFIX)-$(DEVICE_NAME)-$(1)" "$@.stripmeta" + fwtool -s /dev/null -t "$@.stripmeta" || : + fwtool -i /dev/null -t "$@.stripmeta" || : + dd if="$@.stripmeta" >> "$@" + rm "$@.stripmeta" +endef + +define Build/append-image-stage + cp "$(BIN_DIR)/$(IMG_PREFIX)-$(DEVICE_NAME)-$(1)" "$@.stripmeta" + fwtool -s /dev/null -t "$@.stripmeta" || : + fwtool -i /dev/null -t "$@.stripmeta" || : + dd if="$@.stripmeta" of="$(STAGING_DIR_IMAGE)/$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))-$(DEVICE_NAME)-$(1)" + dd if="$@.stripmeta" >> "$@" + rm "$@.stripmeta" +endef + define Build/buffalo-kernel-trx $(eval magic=$(word 1,$(1))) $(eval dummy=$(word 2,$(1))) @@ -55,6 +72,8 @@ define Build/mt7622-gpt ) cat $@.tmp >> $@ rm $@.tmp +# 208 +# 976 endef define Build/trx-nand diff --git a/root/target/linux/ramips/patches-5.15/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch b/root/target/linux/ramips/patches-5.15/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch deleted file mode 100644 index a37426ed..00000000 --- a/root/target/linux/ramips/patches-5.15/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch +++ /dev/null @@ -1,1403 +0,0 @@ -From e84e2430ee0e483842b4ff013ae8a6e7e2fa2734 Mon Sep 17 00:00:00 2001 -From: Weijie Gao -Date: Wed, 1 Apr 2020 02:07:58 +0800 -Subject: [PATCH 1/2] mtd: rawnand: add driver support for MT7621 nand - flash controller - -This patch adds NAND flash controller driver for MediaTek MT7621 SoC. - -The NAND flash controller is similar with controllers described in -mtk_nand.c, except that the controller from MT7621 doesn't support DMA -transmission, and some registers' offset and fields are different. - -Signed-off-by: Weijie Gao ---- - drivers/mtd/nand/raw/Kconfig | 8 + - drivers/mtd/nand/raw/Makefile | 1 + - drivers/mtd/nand/raw/mt7621_nand.c | 1348 ++++++++++++++++++++++++++++++++++++ - 3 files changed, 1357 insertions(+) - create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c - ---- a/drivers/mtd/nand/raw/Kconfig -+++ b/drivers/mtd/nand/raw/Kconfig -@@ -387,6 +387,14 @@ config MTD_NAND_QCOM - Enables support for NAND flash chips on SoCs containing the EBI2 NAND - controller. This controller is found on IPQ806x SoC. - -+config MTD_NAND_MT7621 -+ tristate "MT7621 NAND controller" -+ depends on SOC_MT7621 || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ Enables support for NAND controller on MT7621 SoC. -+ This driver uses PIO mode for data transmission instead of DMA mode. -+ - config MTD_NAND_MTK - tristate "MTK NAND controller" - depends on ARCH_MEDIATEK || COMPILE_TEST ---- a/drivers/mtd/nand/raw/Makefile -+++ b/drivers/mtd/nand/raw/Makefile -@@ -51,6 +51,7 @@ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_n - obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o - obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ - obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o -+obj-$(CONFIG_MTD_NAND_MT7621) += mt7621_nand.o - obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o - obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o - obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o ---- /dev/null -+++ b/drivers/mtd/nand/raw/mt7621_nand.c -@@ -0,0 +1,1353 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek MT7621 NAND Flash Controller driver -+ * -+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. -+ * -+ * Author: Weijie Gao -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* NFI core registers */ -+#define NFI_CNFG 0x000 -+#define CNFG_OP_MODE_S 12 -+#define CNFG_OP_MODE_M 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_S 12 -+#define PAGEFMT_FDM_ECC_M GENMASK(15, 12) -+#define PAGEFMT_FDM_S 8 -+#define PAGEFMT_FDM_M GENMASK(11, 8) -+#define PAGEFMT_SPARE_S 4 -+#define PAGEFMT_SPARE_M GENMASK(5, 4) -+#define PAGEFMT_PAGE_S 0 -+#define PAGEFMT_PAGE_M GENMASK(1, 0) -+ -+#define NFI_CON 0x008 -+#define CON_NFI_SEC_S 12 -+#define CON_NFI_SEC_M 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_S 28 -+#define ACCCON_POECS_MAX 0x0f -+#define ACCCON_POECS_DEF 3 -+#define ACCCON_PRECS_S 22 -+#define ACCCON_PRECS_MAX 0x3f -+#define ACCCON_PRECS_DEF 3 -+#define ACCCON_C2R_S 16 -+#define ACCCON_C2R_MAX 0x3f -+#define ACCCON_C2R_DEF 7 -+#define ACCCON_W2R_S 12 -+#define ACCCON_W2R_MAX 0x0f -+#define ACCCON_W2R_DEF 7 -+#define ACCCON_WH_S 8 -+#define ACCCON_WH_MAX 0x0f -+#define ACCCON_WH_DEF 15 -+#define ACCCON_WST_S 4 -+#define ACCCON_WST_MAX 0x0f -+#define ACCCON_WST_DEF 15 -+#define ACCCON_WST_MIN 3 -+#define ACCCON_RLT_S 0 -+#define ACCCON_RLT_MAX 0x0f -+#define ACCCON_RLT_DEF 15 -+#define ACCCON_RLT_MIN 3 -+ -+#define NFI_CMD 0x020 -+ -+#define NFI_ADDRNOB 0x030 -+#define ADDR_ROW_NOB_S 4 -+#define ADDR_ROW_NOB_M GENMASK(6, 4) -+#define ADDR_COL_NOB_S 0 -+#define ADDR_COL_NOB_M 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_S 4 -+#define CB2R_TIME_M 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_S 16 -+#define STA_NFI_FSM_M 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_S 12 -+#define SEC_CNTR_M GENMASK(15, 12) -+#define SEC_ADDR_S 0 -+#define SEC_ADDR_M GENMASK(9, 0) -+ -+#define NFI_CSEL 0x090 -+#define CSEL_S 0 -+#define CSEL_M 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_S 16 -+#define ENC_CNFG_MSG_M GENMASK(28, 16) -+#define ENC_MODE_S 4 -+#define ENC_MODE_M GENMASK(5, 4) -+#define ENC_MODE_NFI 1 -+#define ENC_TNUM_S 0 -+#define ENC_TNUM_M 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_S 16 -+#define DEC_CS_M GENMASK(28, 16) -+#define DEC_CON_S 12 -+#define DEC_CON_M GENMASK(13, 12) -+#define DEC_CON_EL 2 -+#define DEC_MODE_S 4 -+#define DEC_MODE_M GENMASK(5, 4) -+#define DEC_MODE_NFI 1 -+#define DEC_TNUM_S 0 -+#define DEC_TNUM_M 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_EVEN_S 0 -+#define DEC_EL_M 0x1fff -+#define DEC_EL_BYTE_POS_S 3 -+#define DEC_EL_BIT_POS_M GENMASK(3, 0) -+ -+#define ECC_FDMADDR 0x13c -+ -+/* ENCIDLE and DECIDLE */ -+#define ECC_IDLE BIT(0) -+ -+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \ -+ ((tpoecs) << ACCCON_POECS_S | (tprecs) << ACCCON_PRECS_S | \ -+ (tc2r) << ACCCON_C2R_S | (tw2r) << ACCCON_W2R_S | \ -+ (twh) << ACCCON_WH_S | (twst) << ACCCON_WST_S | (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 -+ -+#define MT7621_NFC_NAME "mt7621-nand" -+ -+struct mt7621_nfc { -+ struct nand_controller controller; -+ struct nand_chip nand; -+ struct clk *nfi_clk; -+ struct device *dev; -+ -+ void __iomem *nfi_regs; -+ void __iomem *ecc_regs; -+ -+ u32 spare_per_sector; -+}; -+ -+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) -+{ -+ struct device *dev = nfc->dev; -+ u32 val; -+ int ret; -+ -+ ret = readw_poll_timeout_atomic(nfc->ecc_regs + reg, val, -+ val & ECC_IDLE, 10, -+ ECC_ENGINE_TIMEOUT); -+ if (ret) { -+ dev_warn(dev, "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) -+{ -+ struct device *dev = nfc->dev; -+ u32 val; -+ int ret; -+ -+ ret = readw_poll_timeout_atomic(nfc->ecc_regs + ECC_DECDONE, val, -+ val & (1 << sect), 10, -+ ECC_ENGINE_TIMEOUT); -+ -+ if (ret) { -+ dev_warn(dev, "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) -+{ -+ struct device *dev = nfc->dev; -+ u16 val; -+ int ret; -+ -+ ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_ADDRCNTR, val, -+ ((val & SEC_CNTR_M) >> SEC_CNTR_S) >= nand->ecc.steps, 10, -+ NFI_CORE_TIMEOUT); -+ -+ if (ret) { -+ dev_warn(dev, "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), 50, -+ NFI_RESET_TIMEOUT); -+ if (ret) { -+ dev_warn(nfc->dev, "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_M | 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) -+{ -+ struct device *dev = nfc->dev; -+ u32 val; -+ int ret; -+ -+ nfi_write32(nfc, NFI_CMD, command); -+ -+ ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val, -+ !(val & STA_CMD), 10, -+ NFI_CORE_TIMEOUT); -+ if (ret) { -+ dev_warn(dev, "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) -+{ -+ struct device *dev = nfc->dev; -+ 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_atomic(nfc->nfi_regs + NFI_STA, val, -+ !(val & STA_ADDR), 10, -+ NFI_CORE_TIMEOUT); -+ if (ret) { -+ dev_warn(dev, "NFI core timed out entering address mode\n"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int mt7621_nfc_send_address(struct mt7621_nfc *nfc, const u8 *addr, -+ unsigned int naddrs) -+{ -+ int ret; -+ -+ while (naddrs) { -+ ret = mt7621_nfc_send_address_byte(nfc, *addr); -+ if (ret) -+ return ret; -+ -+ addr++; -+ naddrs--; -+ } -+ -+ return 0; -+} -+ -+static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc) -+{ -+ struct device *dev = nfc->dev; -+ int ret; -+ u16 val; -+ -+ ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_PIO_DIRDY, val, -+ val & PIO_DIRDY, 10, -+ NFI_CORE_TIMEOUT); -+ if (ret < 0) -+ dev_err(dev, "NFI core PIO mode not ready\n"); -+} -+ -+static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br) -+{ -+ u32 reg; -+ -+ /* after each byte read, the NFI_STA reg is reset by the hardware */ -+ reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S; -+ if (reg != 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_M | 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; -+ -+ reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S; -+ if (reg != 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_M | 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 int mt7621_nfc_dev_ready(struct mt7621_nfc *nfc, -+ unsigned int timeout_ms) -+{ -+ u32 val; -+ -+ return readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val, -+ !(val & STA_BUSY), 10, -+ timeout_ms * 1000); -+} -+ -+static int mt7621_nfc_exec_instr(struct nand_chip *nand, -+ const struct nand_op_instr *instr) -+{ -+ struct mt7621_nfc *nfc = nand_get_controller_data(nand); -+ -+ switch (instr->type) { -+ case NAND_OP_CMD_INSTR: -+ mt7621_nfc_hw_reset(nfc); -+ nfi_write16(nfc, NFI_CNFG, CNFG_OP_CUSTOM << CNFG_OP_MODE_S); -+ return mt7621_nfc_send_command(nfc, instr->ctx.cmd.opcode); -+ case NAND_OP_ADDR_INSTR: -+ return mt7621_nfc_send_address(nfc, instr->ctx.addr.addrs, -+ instr->ctx.addr.naddrs); -+ case NAND_OP_DATA_IN_INSTR: -+ mt7621_nfc_read_data(nfc, instr->ctx.data.buf.in, -+ instr->ctx.data.len); -+ return 0; -+ case NAND_OP_DATA_OUT_INSTR: -+ mt7621_nfc_write_data(nfc, instr->ctx.data.buf.out, -+ instr->ctx.data.len); -+ return 0; -+ case NAND_OP_WAITRDY_INSTR: -+ return mt7621_nfc_dev_ready(nfc, -+ instr->ctx.waitrdy.timeout_ms); -+ default: -+ WARN_ONCE(1, "unsupported NAND instruction type: %d\n", -+ instr->type); -+ -+ return -EINVAL; -+ } -+} -+ -+static int mt7621_nfc_exec_op(struct nand_chip *nand, -+ const struct nand_operation *op, bool check_only) -+{ -+ struct mt7621_nfc *nfc = nand_get_controller_data(nand); -+ int i, ret; -+ -+ if (check_only) -+ return 0; -+ -+ /* Only CS0 available */ -+ nfi_write16(nfc, NFI_CSEL, 0); -+ -+ for (i = 0; i < op->ninstrs; i++) { -+ ret = mt7621_nfc_exec_instr(nand, &op->instrs[i]); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int mt7621_nfc_setup_interface(struct nand_chip *nand, int csline, -+ const struct nand_interface_config *conf) -+{ -+ struct mt7621_nfc *nfc = nand_get_controller_data(nand); -+ const struct nand_sdr_timings *timings; -+ u32 acccon, temp, rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt; -+ -+ if (!nfc->nfi_clk) -+ return -ENOTSUPP; -+ -+ timings = nand_get_sdr_timings(conf); -+ if (IS_ERR(timings)) -+ return -ENOTSUPP; -+ -+ rate = clk_get_rate(nfc->nfi_clk); -+ -+ /* turn clock rate into KHZ */ -+ rate /= 1000; -+ -+ tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000; -+ tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000); -+ tpoecs = min_t(u32, tpoecs, ACCCON_POECS_MAX); -+ -+ tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000; -+ tprecs = DIV_ROUND_UP(tprecs * rate, 1000000); -+ tprecs = min_t(u32, tprecs, ACCCON_PRECS_MAX); -+ -+ /* sdr interface has no tCR which means CE# low to RE# low */ -+ tc2r = 0; -+ -+ tw2r = timings->tWHR_min / 1000; -+ tw2r = DIV_ROUND_UP(tw2r * rate, 1000000); -+ tw2r = DIV_ROUND_UP(tw2r - 1, 2); -+ tw2r = min_t(u32, tw2r, ACCCON_W2R_MAX); -+ -+ twh = max(timings->tREH_min, timings->tWH_min) / 1000; -+ twh = DIV_ROUND_UP(twh * rate, 1000000) - 1; -+ twh = min_t(u32, twh, ACCCON_WH_MAX); -+ -+ /* Calculate real WE#/RE# hold time in nanosecond */ -+ temp = (twh + 1) * 1000000 / rate; -+ /* nanosecond to picosecond */ -+ temp *= 1000; -+ -+ /* -+ * WE# low level time should be expaned to meet WE# pulse time -+ * and WE# cycle time at the same time. -+ */ -+ if (temp < timings->tWC_min) -+ twst = timings->tWC_min - temp; -+ else -+ twst = 0; -+ twst = max(timings->tWP_min, twst) / 1000; -+ twst = DIV_ROUND_UP(twst * rate, 1000000) - 1; -+ twst = min_t(u32, twst, ACCCON_WST_MAX); -+ -+ /* -+ * RE# low level time should be expaned to meet RE# pulse time -+ * and RE# cycle time at the same time. -+ */ -+ if (temp < timings->tRC_min) -+ trlt = timings->tRC_min - temp; -+ else -+ trlt = 0; -+ trlt = max(trlt, timings->tRP_min) / 1000; -+ trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1; -+ trlt = min_t(u32, trlt, ACCCON_RLT_MAX); -+ -+ if (csline == NAND_DATA_IFACE_CHECK_ONLY) { -+ if (twst < ACCCON_WST_MIN || trlt < ACCCON_RLT_MIN) -+ return -ENOTSUPP; -+ } -+ -+ acccon = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt); -+ -+ dev_info(nfc->dev, "Using programmed access timing: %08x\n", acccon); -+ -+ nfi_write32(nfc, NFI_ACCCON, acccon); -+ -+ return 0; -+} -+ -+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)) { -+ dev_err(nfc->dev, "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); -+ -+ dev_info(nfc->dev, "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))) { -+ dev_err(nfc->dev, "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 spare_per_sector, encode_block_size, decode_block_size; -+ u32 ecc_enccfg, ecc_deccfg; -+ int ecc_cap; -+ -+ /* Only hardware ECC mode is supported */ -+ if (nand->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) { -+ dev_err(nfc->dev, "Only hardware ECC mode is supported\n"); -+ return -EINVAL; -+ } -+ -+ nand->ecc.size = ECC_SECTOR_SIZE; -+ nand->ecc.steps = mtd->writesize / nand->ecc.size; -+ -+ spare_per_sector = mtd->oobsize / nand->ecc.steps; -+ -+ ecc_cap = mt7621_nfc_calc_ecc_strength(nfc, -+ spare_per_sector - NFI_FDM_SIZE); -+ if (ecc_cap < 0) -+ return ecc_cap; -+ -+ /* Sector + FDM */ -+ encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8; -+ ecc_enccfg = ecc_cap | (ENC_MODE_NFI << ENC_MODE_S) | -+ (encode_block_size << ENC_CNFG_MSG_S); -+ -+ /* 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 | (DEC_MODE_NFI << DEC_MODE_S) | -+ (decode_block_size << DEC_CS_S) | -+ (DEC_CON_EL << DEC_CON_S) | 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))) { -+ dev_err(nfc->dev, "Page size (%u) is not supported\n", -+ mtd->writesize); -+ return -EINVAL; -+ } -+ -+ pagefmt = i | (spare_size << PAGEFMT_SPARE_S) | -+ (NFI_FDM_SIZE << PAGEFMT_FDM_S) | -+ (NFI_FDM_SIZE << PAGEFMT_FDM_ECC_S); -+ -+ 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) { -+ dev_err(nfc->dev, "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 const struct nand_controller_ops mt7621_nfc_controller_ops = { -+ .attach_chip = mt7621_nfc_attach_chip, -+ .exec_op = mt7621_nfc_exec_op, -+ .setup_interface = mt7621_nfc_setup_interface, -+}; -+ -+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 = { -+ .free = mt7621_nfc_ooblayout_free, -+ .ecc = mt7621_nfc_ooblayout_ecc, -+}; -+ -+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 - 4) * 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 nand_chip *nand, uint8_t *buf, -+ int oob_required, int page) -+{ -+ struct mt7621_nfc *nfc = nand_get_controller_data(nand); -+ struct mtd_info *mtd = nand_to_mtd(nand); -+ int bitflips = 0; -+ int rc, i; -+ -+ nand_read_page_op(nand, page, 0, NULL, 0); -+ -+ nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | -+ CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); -+ -+ mt7621_ecc_decoder_op(nfc, true); -+ -+ nfi_write16(nfc, NFI_CON, -+ CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S)); -+ -+ 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) { -+ bitflips = -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) { -+ dev_warn(nfc->dev, -+ "Uncorrectable ECC error at page %d.%d\n", -+ page, i); -+ bitflips = -EBADMSG; -+ mtd->ecc_stats.failed++; -+ } else if (bitflips >= 0) { -+ bitflips += rc; -+ mtd->ecc_stats.corrected += rc; -+ } -+ } -+ -+ mt7621_ecc_decoder_op(nfc, false); -+ -+ nfi_write16(nfc, NFI_CON, 0); -+ -+ return bitflips; -+} -+ -+static int mt7621_nfc_read_page_raw(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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | -+ CNFG_READ_MODE); -+ -+ nfi_write16(nfc, NFI_CON, -+ CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S)); -+ -+ 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 nand_chip *nand, int page) -+{ -+ return mt7621_nfc_read_page_hwecc(nand, NULL, 1, page); -+} -+ -+static int mt7621_nfc_read_oob_raw(struct nand_chip *nand, int page) -+{ -+ return mt7621_nfc_read_page_raw(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); -+ uint32_t i, j; -+ u8 *oobptr; -+ -+ 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 nand_chip *nand, -+ const uint8_t *buf, int oob_required, -+ int page) -+{ -+ struct mt7621_nfc *nfc = nand_get_controller_data(nand); -+ struct mtd_info *mtd = nand_to_mtd(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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | -+ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); -+ -+ mt7621_ecc_encoder_op(nfc, true); -+ -+ mt7621_nfc_write_fdm(nfc); -+ -+ nfi_write16(nfc, NFI_CON, -+ CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S)); -+ -+ 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 nand_chip *nand, -+ const uint8_t *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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S)); -+ -+ nfi_write16(nfc, NFI_CON, -+ CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S)); -+ -+ 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 nand_chip *nand, int page) -+{ -+ return mt7621_nfc_write_page_hwecc(nand, NULL, 1, page); -+} -+ -+static int mt7621_nfc_write_oob_raw(struct nand_chip *nand, int page) -+{ -+ return mt7621_nfc_write_page_raw(nand, NULL, 1, page); -+} -+ -+static int mt7621_nfc_init_chip(struct mt7621_nfc *nfc) -+{ -+ struct nand_chip *nand = &nfc->nand; -+ struct mtd_info *mtd; -+ int ret; -+ -+ nand->controller = &nfc->controller; -+ nand_set_controller_data(nand, (void *)nfc); -+ nand_set_flash_node(nand, nfc->dev->of_node); -+ -+ nand->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE; -+ if (!nfc->nfi_clk) -+ nand->options |= NAND_KEEP_TIMINGS; -+ -+ nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; -+ 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; -+ -+ mtd = nand_to_mtd(nand); -+ mtd->owner = THIS_MODULE; -+ mtd->dev.parent = nfc->dev; -+ mtd->name = MT7621_NFC_NAME; -+ mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops); -+ -+ mt7621_nfc_hw_init(nfc); -+ -+ ret = nand_scan(nand, 1); -+ if (ret) -+ return ret; -+ -+ ret = mtd_device_register(mtd, NULL, 0); -+ if (ret) { -+ dev_err(nfc->dev, "Failed to register MTD: %d\n", ret); -+ nand_cleanup(nand); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int mt7621_nfc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mt7621_nfc *nfc; -+ struct resource *res; -+ int ret; -+ -+ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); -+ if (!nfc) -+ return -ENOMEM; -+ -+ nand_controller_init(&nfc->controller); -+ nfc->controller.ops = &mt7621_nfc_controller_ops; -+ nfc->dev = dev; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi"); -+ nfc->nfi_regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(nfc->nfi_regs)) { -+ ret = PTR_ERR(nfc->nfi_regs); -+ return ret; -+ } -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc"); -+ nfc->ecc_regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(nfc->ecc_regs)) { -+ ret = PTR_ERR(nfc->ecc_regs); -+ return ret; -+ } -+ -+ nfc->nfi_clk = devm_clk_get(dev, "nfi_clk"); -+ if (IS_ERR(nfc->nfi_clk)) { -+ dev_warn(dev, "nfi clk not provided\n"); -+ nfc->nfi_clk = NULL; -+ } else { -+ ret = clk_prepare_enable(nfc->nfi_clk); -+ if (ret) { -+ dev_err(dev, "Failed to enable nfi core clock\n"); -+ return ret; -+ } -+ } -+ -+ platform_set_drvdata(pdev, nfc); -+ -+ ret = mt7621_nfc_init_chip(nfc); -+ if (ret) { -+ dev_err(dev, "Failed to initialize nand chip\n"); -+ goto clk_disable; -+ } -+ -+ return 0; -+ -+clk_disable: -+ clk_disable_unprepare(nfc->nfi_clk); -+ -+ return ret; -+} -+ -+static int mt7621_nfc_remove(struct platform_device *pdev) -+{ -+ struct mt7621_nfc *nfc = platform_get_drvdata(pdev); -+ struct nand_chip *nand = &nfc->nand; -+ struct mtd_info *mtd = nand_to_mtd(nand); -+ -+ mtd_device_unregister(mtd); -+ nand_cleanup(nand); -+ clk_disable_unprepare(nfc->nfi_clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id mt7621_nfc_id_table[] = { -+ { .compatible = "mediatek,mt7621-nfc" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, match); -+ -+static struct platform_driver mt7621_nfc_driver = { -+ .probe = mt7621_nfc_probe, -+ .remove = mt7621_nfc_remove, -+ .driver = { -+ .name = MT7621_NFC_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = mt7621_nfc_id_table, -+ }, -+}; -+module_platform_driver(mt7621_nfc_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Weijie Gao "); -+MODULE_DESCRIPTION("MediaTek MT7621 NAND Flash Controller driver");