From ce19e8fa438f7013881b71956f39cf299e6fce46 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 11 Mar 2021 16:00:20 +0000 Subject: [PATCH 01/32] tools: mkimage: add patches for 64-bit MediaTek BootROM Add patches for mkimage to allow using it instead of the binary-only 'bromimage' tool to generate bl2 for MT7622. Signed-off-by: Daniel Golle --- ...01-make-brom-sign-key-optional-again.patch | 17 -- ...add-support-for-booting-ARM64-images.patch | 134 +++++++++++ ...n-option-to-set-device-header-offset.patch | 226 ++++++++++++++++++ 3 files changed, 360 insertions(+), 17 deletions(-) delete mode 100644 package/boot/arm-trusted-firmware-mediatek/patches/001-make-brom-sign-key-optional-again.patch create mode 100644 tools/mkimage/patches/080-mtk_image-add-support-for-booting-ARM64-images.patch create mode 100644 tools/mkimage/patches/081-mtk_image-add-an-option-to-set-device-header-offset.patch diff --git a/package/boot/arm-trusted-firmware-mediatek/patches/001-make-brom-sign-key-optional-again.patch b/package/boot/arm-trusted-firmware-mediatek/patches/001-make-brom-sign-key-optional-again.patch deleted file mode 100644 index 60b221ad5f..0000000000 --- a/package/boot/arm-trusted-firmware-mediatek/patches/001-make-brom-sign-key-optional-again.patch +++ /dev/null @@ -1,17 +0,0 @@ -Index: arm-trusted-firmware-mediatek-2021-02-25-1220acb0/plat/mediatek/mt7622/platform.mk -=================================================================== ---- arm-trusted-firmware-mediatek-2021-02-25-1220acb0.orig/plat/mediatek/mt7622/platform.mk -+++ arm-trusted-firmware-mediatek-2021-02-25-1220acb0/plat/mediatek/mt7622/platform.mk -@@ -99,9 +99,9 @@ BL2_SOURCES += drivers/mmc/mmc.c \ - BROM_HEADER_TYPE := sdmmc - CPPFLAGS += -DMSDC_INDEX=1 - DEVICE_HEADER_OFFSET ?= 0x80000 --ifeq ($(BROM_SIGN_KEY),) --$(error BootROM signing key is required for SD booting. Please specify BROM_SIGN_KEY) --endif -+#ifeq ($(BROM_SIGN_KEY),) -+#$(error BootROM signing key is required for SD booting. Please specify BROM_SIGN_KEY) -+#endif - endif - ifeq ($(BOOT_DEVICE),snand) - include ${MTK_PLAT}/common/drivers/snfi/mtk-snand.mk diff --git a/tools/mkimage/patches/080-mtk_image-add-support-for-booting-ARM64-images.patch b/tools/mkimage/patches/080-mtk_image-add-support-for-booting-ARM64-images.patch new file mode 100644 index 0000000000..dfe8128fb5 --- /dev/null +++ b/tools/mkimage/patches/080-mtk_image-add-support-for-booting-ARM64-images.patch @@ -0,0 +1,134 @@ +From 44165e4c676d266f73fda2e6ba82b4bf3262daf2 Mon Sep 17 00:00:00 2001 +From: Fabien Parent +Date: Fri, 16 Oct 2020 19:52:37 +0200 +Subject: [PATCH] tools: mtk_image: add support for booting ARM64 images + +mkimage is only able to package aarch32 binaries. Add support for +AArch64 images. + +One can create a ARM64 image using the following command line: +mkimage -T mtk_image -a 0x201000 -e 0x201000 -n "media=emmc;arm64=1" +-d bl2.bin bl2.img + +Signed-off-by: Fabien Parent +--- + tools/mtk_image.c | 28 ++++++++++++++++++++++++---- + tools/mtk_image.h | 6 +++++- + 2 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/tools/mtk_image.c b/tools/mtk_image.c +index 2ca519483d..bde1e5da4b 100644 +--- a/tools/mtk_image.c ++++ b/tools/mtk_image.c +@@ -246,6 +246,7 @@ static const struct brom_img_type { + /* Image type selected by user */ + static enum brlyt_img_type hdr_media; + static int use_lk_hdr; ++static bool is_arm64_image; + + /* LK image name */ + static char lk_name[32] = "U-Boot"; +@@ -276,6 +277,7 @@ static int mtk_brom_parse_imagename(const char *imagename) + static const char *media = ""; + static const char *nandinfo = ""; + static const char *lk = ""; ++ static const char *arm64_param = ""; + + key = buf; + while (key) { +@@ -323,6 +325,9 @@ static int mtk_brom_parse_imagename(const char *imagename) + + if (!strcmp(key, "lkname")) + snprintf(lk_name, sizeof(lk_name), "%s", val); ++ ++ if (!strcmp(key, "arm64")) ++ arm64_param = val; + } + + if (next) +@@ -354,6 +359,9 @@ static int mtk_brom_parse_imagename(const char *imagename) + } + } + ++ if (arm64_param && arm64_param[0] == '1') ++ is_arm64_image = true; ++ + free(buf); + + if (hdr_media == BRLYT_TYPE_INVALID) { +@@ -458,6 +466,9 @@ static int mtk_image_verify_gen_header(const uint8_t *ptr, int print) + le32_to_cpu(gfh->file_info.load_addr) + + le32_to_cpu(gfh->file_info.jump_offset)); + ++ if (print) ++ printf("Architecture: %s\n", is_arm64_image ? "ARM64" : "ARM"); ++ + return 0; + } + +@@ -523,6 +534,9 @@ static int mtk_image_verify_nand_header(const uint8_t *ptr, int print) + le32_to_cpu(gfh->file_info.load_addr) + + le32_to_cpu(gfh->file_info.jump_offset)); + ++ if (print) ++ printf("Architecture: %s\n", is_arm64_image ? "ARM64" : "ARM"); ++ + return 0; + } + +@@ -581,6 +595,8 @@ static void put_ghf_common_header(struct gfh_common_header *gfh, int size, + static void put_ghf_header(struct gfh_header *gfh, int file_size, + int dev_hdr_size, int load_addr, int flash_type) + { ++ uint32_t cfg_bits; ++ + memset(gfh, 0, sizeof(struct gfh_header)); + + /* GFH_FILE_INFO header */ +@@ -608,11 +624,15 @@ static void put_ghf_header(struct gfh_header *gfh, int file_size, + /* GFH_BROM_CFG header */ + put_ghf_common_header(&gfh->brom_cfg.gfh, sizeof(gfh->brom_cfg), + GFH_TYPE_BROM_CFG, 3); +- gfh->brom_cfg.cfg_bits = cpu_to_le32( +- GFH_BROM_CFG_USBDL_AUTO_DETECT_DIS | +- GFH_BROM_CFG_USBDL_BY_KCOL0_TIMEOUT_EN | +- GFH_BROM_CFG_USBDL_BY_FLAG_TIMEOUT_EN); ++ cfg_bits = GFH_BROM_CFG_USBDL_AUTO_DETECT_DIS | ++ GFH_BROM_CFG_USBDL_BY_KCOL0_TIMEOUT_EN | ++ GFH_BROM_CFG_USBDL_BY_FLAG_TIMEOUT_EN; + gfh->brom_cfg.usbdl_by_kcol0_timeout_ms = cpu_to_le32(5000); ++ if (is_arm64_image) { ++ gfh->brom_cfg.jump_bl_arm64 = GFH_BROM_CFG_JUMP_BL_ARM64; ++ cfg_bits |= GFH_BROM_CFG_JUMP_BL_ARM64_EN; ++ } ++ gfh->brom_cfg.cfg_bits = cpu_to_le32(cfg_bits); + + /* GFH_BL_SEC_KEY header */ + put_ghf_common_header(&gfh->bl_sec_key.gfh, sizeof(gfh->bl_sec_key), +diff --git a/tools/mtk_image.h b/tools/mtk_image.h +index 4e78b3d0ff..7dda71ce88 100644 +--- a/tools/mtk_image.h ++++ b/tools/mtk_image.h +@@ -136,7 +136,9 @@ struct gfh_brom_cfg { + struct gfh_common_header gfh; + uint32_t cfg_bits; + uint32_t usbdl_by_auto_detect_timeout_ms; +- uint8_t unused[0x48]; ++ uint8_t unused[0x45]; ++ uint8_t jump_bl_arm64; ++ uint8_t unused2[2]; + uint32_t usbdl_by_kcol0_timeout_ms; + uint32_t usbdl_by_flag_timeout_ms; + uint32_t pad; +@@ -146,6 +148,8 @@ struct gfh_brom_cfg { + #define GFH_BROM_CFG_USBDL_AUTO_DETECT_DIS 0x10 + #define GFH_BROM_CFG_USBDL_BY_KCOL0_TIMEOUT_EN 0x80 + #define GFH_BROM_CFG_USBDL_BY_FLAG_TIMEOUT_EN 0x100 ++#define GFH_BROM_CFG_JUMP_BL_ARM64_EN 0x1000 ++#define GFH_BROM_CFG_JUMP_BL_ARM64 0x64 + + struct gfh_bl_sec_key { + struct gfh_common_header gfh; +-- +2.30.1 + diff --git a/tools/mkimage/patches/081-mtk_image-add-an-option-to-set-device-header-offset.patch b/tools/mkimage/patches/081-mtk_image-add-an-option-to-set-device-header-offset.patch new file mode 100644 index 0000000000..45f8f7c1c1 --- /dev/null +++ b/tools/mkimage/patches/081-mtk_image-add-an-option-to-set-device-header-offset.patch @@ -0,0 +1,226 @@ +From patchwork Tue Mar 9 07:52:31 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Weijie Gao +X-Patchwork-Id: 1449568 +Return-Path: +X-Original-To: incoming@patchwork.ozlabs.org +Delivered-To: patchwork-incoming@bilbo.ozlabs.org +Authentication-Results: ozlabs.org; + spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de + (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; + envelope-from=u-boot-bounces@lists.denx.de; receiver=) +Authentication-Results: ozlabs.org; + dkim=pass (1024-bit key; + unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 + header.s=dk header.b=i1dK9gFR; + dkim-atps=neutral +Received: from phobos.denx.de (phobos.denx.de + [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest + SHA256) + (No client certificate requested) + by ozlabs.org (Postfix) with ESMTPS id 4DvnX84rrHz9sW1 + for ; Tue, 9 Mar 2021 18:53:44 +1100 (AEDT) +Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) + by phobos.denx.de (Postfix) with ESMTP id DF60F8219C; + Tue, 9 Mar 2021 08:53:29 +0100 (CET) +Authentication-Results: phobos.denx.de; + dmarc=pass (p=none dis=none) header.from=mediatek.com +Authentication-Results: phobos.denx.de; + spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de +Authentication-Results: phobos.denx.de; + dkim=pass (1024-bit key; + unprotected) header.d=mediatek.com header.i=@mediatek.com + header.b="i1dK9gFR"; + dkim-atps=neutral +Received: by phobos.denx.de (Postfix, from userid 109) + id 5456882625; Tue, 9 Mar 2021 08:53:28 +0100 (CET) +X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de +X-Spam-Level: +X-Spam-Status: No, score=0.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, + DKIM_VALID,DKIM_VALID_AU,MIME_BASE64_TEXT,RDNS_NONE,SPF_HELO_NONE, + UNPARSEABLE_RELAY autolearn=no autolearn_force=no version=3.4.2 +Received: from mailgw02.mediatek.com (unknown [1.203.163.81]) + by phobos.denx.de (Postfix) with ESMTP id 7526E80EF2 + for ; Tue, 9 Mar 2021 08:53:19 +0100 (CET) +Authentication-Results: phobos.denx.de; + dmarc=pass (p=none dis=none) header.from=mediatek.com +Authentication-Results: phobos.denx.de; + spf=pass smtp.mailfrom=weijie.gao@mediatek.com +X-UUID: 3b5ccbd89ab948daa31ec738ee94e7ed-20210309 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=mediatek.com; + s=dk; + h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID:Date:Subject:CC:To:From; + bh=mijplkmurYfYet7eQPGQD6GyyMtN6xMXZKHVAlpy0hM=; + b=i1dK9gFRfmkqD5vAud81Q3CdZlOQm3XK0H/NwbxYyncwalZqRZA1YBKTQhmPW0avcbwOQpGVlRmu1VAfALWgK80acX7bPIjWjtaJtK4/99vc+wIthmm1E5QMewyBAFkzGfx7A8ryh4HdcsG/esbnI0Mk2nletBHwRFAEVs3uUfU=; +X-UUID: 3b5ccbd89ab948daa31ec738ee94e7ed-20210309 +Received: from mtkcas32.mediatek.inc [(172.27.4.253)] by mailgw02.mediatek.com + (envelope-from ) + (mailgw01.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) + with ESMTP id 23424931; Tue, 09 Mar 2021 15:53:06 +0800 +Received: from MTKCAS32.mediatek.inc (172.27.4.184) by MTKMBS31N1.mediatek.inc + (172.27.4.69) with Microsoft SMTP Server (TLS) id 15.0.1497.2; + Tue, 9 Mar 2021 15:52:58 +0800 +Received: from mcddlt001.mediatek.inc (10.19.240.15) by MTKCAS32.mediatek.inc + (172.27.4.170) with Microsoft SMTP Server id 15.0.1497.2 via Frontend + Transport; Tue, 9 Mar 2021 15:52:58 +0800 +From: Weijie Gao +To: +CC: GSS_MTK_Uboot_upstream , Weijie Gao + +Subject: [PATCH] tools: mtk_image: add an option to set device header offset +Date: Tue, 9 Mar 2021 15:52:31 +0800 +Message-ID: <1615276351-30641-1-git-send-email-weijie.gao@mediatek.com> +X-Mailer: git-send-email 1.9.1 +MIME-Version: 1.0 +X-TM-SNTS-SMTP: + B09EA906E69093D91FA73A3F764A0B89D3838DA91A4FA20DA0483EBE19962CA02000:8 +X-MTK: N +X-BeenThere: u-boot@lists.denx.de +X-Mailman-Version: 2.1.34 +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" +X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de +X-Virus-Status: Clean + +This patch adds an option which allows setting the device header offset. +This is useful if this tool is used to generate ATF BL2 image of mt7622 for +SD cards. + +Signed-off-by: Weijie Gao +--- + tools/mtk_image.c | 50 ++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 47 insertions(+), 3 deletions(-) + +diff --git a/tools/mtk_image.c b/tools/mtk_image.c +index bde1e5da4b..418c5fd54b 100644 +--- a/tools/mtk_image.c ++++ b/tools/mtk_image.c +@@ -243,8 +243,13 @@ static const struct brom_img_type { + } + }; + ++/* Indicates whether we're generating or verifying */ ++static bool img_gen; ++static uint32_t img_size; ++ + /* Image type selected by user */ + static enum brlyt_img_type hdr_media; ++static uint32_t hdr_offset; + static int use_lk_hdr; + static bool is_arm64_image; + +@@ -275,6 +280,7 @@ static int mtk_brom_parse_imagename(const char *imagename) + + /* User passed arguments from image name */ + static const char *media = ""; ++ static const char *hdr_offs = ""; + static const char *nandinfo = ""; + static const char *lk = ""; + static const char *arm64_param = ""; +@@ -317,6 +323,9 @@ static int mtk_brom_parse_imagename(const char *imagename) + if (!strcmp(key, "media")) + media = val; + ++ if (!strcmp(key, "hdroffset")) ++ hdr_offs = val; ++ + if (!strcmp(key, "nandinfo")) + nandinfo = val; + +@@ -359,6 +368,10 @@ static int mtk_brom_parse_imagename(const char *imagename) + } + } + ++ /* parse device header offset */ ++ if (hdr_offs && hdr_offs[0]) ++ hdr_offset = strtoul(hdr_offs, NULL, 0); ++ + if (arm64_param && arm64_param[0] == '1') + is_arm64_image = true; + +@@ -422,6 +435,7 @@ static int mtk_image_vrec_header(struct image_tool_params *params, + static int mtk_image_verify_gen_header(const uint8_t *ptr, int print) + { + union gen_boot_header *gbh = (union gen_boot_header *)ptr; ++ uint32_t gfh_offset, total_size, devh_size; + struct brom_layout_header *bh; + struct gfh_header *gfh; + const char *bootmedia; +@@ -453,7 +467,32 @@ static int mtk_image_verify_gen_header(const uint8_t *ptr, int print) + le32_to_cpu(bh->type) != BRLYT_TYPE_SDMMC)) + return -1; + +- gfh = (struct gfh_header *)(ptr + le32_to_cpu(bh->header_size)); ++ devh_size = sizeof(struct gen_device_header); ++ ++ if (img_gen) { ++ gfh_offset = devh_size; ++ } else { ++ gfh_offset = le32_to_cpu(bh->header_size); ++ ++ if (gfh_offset + sizeof(struct gfh_header) > img_size) { ++ /* ++ * This may happen if the hdr_offset used to generate ++ * this image is not zero. ++ * Since device header size is not fixed, we can't ++ * cover all possible cases. ++ * Assuming the image is valid only if the real ++ * device header size equals to devh_size. ++ */ ++ total_size = le32_to_cpu(bh->total_size); ++ ++ if (total_size - gfh_offset > img_size - devh_size) ++ return -1; ++ ++ gfh_offset = devh_size; ++ } ++ } ++ ++ gfh = (struct gfh_header *)(ptr + gfh_offset); + + if (strcmp(gfh->file_info.name, GFH_FILE_INFO_NAME)) + return -1; +@@ -549,6 +588,8 @@ static int mtk_image_verify_header(unsigned char *ptr, int image_size, + if (le32_to_cpu(lk->magic) == LK_PART_MAGIC) + return 0; + ++ img_size = image_size; ++ + if (!strcmp((char *)ptr, NAND_BOOT_NAME)) + return mtk_image_verify_nand_header(ptr, 0); + else +@@ -682,8 +723,8 @@ static void mtk_image_set_gen_header(void *ptr, off_t filesize, + + /* BRLYT header */ + put_brom_layout_header(&hdr->brlyt, hdr_media); +- hdr->brlyt.header_size = cpu_to_le32(sizeof(struct gen_device_header)); +- hdr->brlyt.total_size = cpu_to_le32(filesize); ++ hdr->brlyt.header_size = cpu_to_le32(hdr_offset + sizeof(*hdr)); ++ hdr->brlyt.total_size = cpu_to_le32(hdr_offset + filesize); + hdr->brlyt.header_size_2 = hdr->brlyt.header_size; + hdr->brlyt.total_size_2 = hdr->brlyt.total_size; + +@@ -747,6 +788,9 @@ static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd, + return; + } + ++ img_gen = true; ++ img_size = sbuf->st_size; ++ + if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND) + mtk_image_set_nand_header(ptr, sbuf->st_size, params->addr); + else From e2cffbb80528b1c13bbaba6e53835de378ef3923 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 11 Mar 2021 16:01:32 +0000 Subject: [PATCH 02/32] arm-trusted-firmware-mediatek: update to 2021-03-10 Most prominently this adds changes which allow replacing the binary- only 'bromimage' tool by U-Boot's 'mkimage' (see previous commit). This fixes build on non-Linux and/or non-x86 platforms. Signed-off-by: Daniel Golle --- package/boot/arm-trusted-firmware-mediatek/Makefile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/package/boot/arm-trusted-firmware-mediatek/Makefile b/package/boot/arm-trusted-firmware-mediatek/Makefile index 9ec69db09d..b2afdbed06 100644 --- a/package/boot/arm-trusted-firmware-mediatek/Makefile +++ b/package/boot/arm-trusted-firmware-mediatek/Makefile @@ -13,9 +13,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=https://github.com/mtk-openwrt/arm-trusted-firmware.git -PKG_SOURCE_DATE:=2021-02-25 -PKG_SOURCE_VERSION:=1220acb044a9db9a201aba3be0bb4ce0c9ed3702 -PKG_MIRROR_HASH:=f2ca44b9b8acfbd3a6be30aba316c765f73bad6231a821f524c9f21a845e50a3 +PKG_SOURCE_DATE:=2021-03-10 +PKG_SOURCE_VERSION:=8b635f61091f2e5bce88269468c53fc30bb4cd64 +PKG_MIRROR_HASH:=ffe233a19b51504f605a90a88c7a1bb74303e4a7173a59b24a4dfa572ce99139 PKG_MAINTAINER:=Daniel Golle @@ -85,7 +85,11 @@ TFA_TARGETS:= \ mt7622-sdmmc-1ddr \ mt7622-sdmmc-2ddr -TFA_MAKE_FLAGS += BOOT_DEVICE=$(BOOT_DEVICE) $(if $(DDR3_FLYBY),DDR3_FLYBY=1) all +TFA_MAKE_FLAGS += \ + BOOT_DEVICE=$(BOOT_DEVICE) \ + USE_MKIMAGE=1 MKIMAGE=$(STAGING_DIR_HOST)/bin/mkimage \ + $(if $(DDR3_FLYBY),DDR3_FLYBY=1) \ + all define Build/Configure $(call Build/Configure/Default) From 9dfc2b3ca4dff28259576e21bc3ade910ff52a05 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 20 Feb 2021 13:04:38 +0000 Subject: [PATCH 03/32] uboot-mediatek: update to 2021.04-rc3 with MediaTek's patches MediaTek published their current U-Boot patchset on github: https://github.com/mtk-openwrt/u-boot/commits/mtksoc Import the platform patches from there (`00-mtk-*.patch`), arrange, them nicely, drop no longer needed local patches and rebase on top of U-Boot 2021.04-rc3. Tested and works well on Linksys E8450 (snand-1ddr) as well as Bananapi BPi-R64 (sdmmc-2ddr, emmc-2ddr). Signed-off-by: Daniel Golle --- package/boot/uboot-mediatek/Makefile | 4 +- ...-clk-Add-debugging-for-return-values.patch | 69 + ...igs-RPi2-Disable-EFI-Grub-workaround.patch | 21 + ...-fix-wrong-assignment-in-mtk_get_pin.patch | 25 + ...-add-get_pin_muxing-ops-for-mediatek.patch | 43 + ...-do-not-probe-gpio-driver-if-not-ena.patch | 58 + ...7629-add-jtag-function-and-pin-group.patch | 50 + ...se-ARMv8-Generic-Timer-instead-of-mt.patch | 25 + ...s-mt7629-enable-JTAG-pins-by-default.patch | 50 + ...atek-add-more-network-configurations.patch | 44 + ...d-increase-the-minimum-bus-frequency.patch | 38 + ...rial-mtk-rewrite-the-setbrg-function.patch | 141 + ...ble-compression-of-u-boot-to-reduce-.patch | 94 + ...nable-debug-uart-for-mt7622_rfb_defc.patch | 26 + ...support-for-MediaTek-SPI-NAND-flash-.patch | 3698 +++++++ ...15-mtd-mtk-snand-add-support-for-SPL.patch | 174 + ...v-add-support-for-generic-MTD-device.patch | 409 + ...dd-support-for-booting-from-SPI-NAND.patch | 266 + ...board-mt7622-use-new-spi-nand-driver.patch | 76 + ...emove-unused-options-and-add-dm-comm.patch | 31 + ...22-enable-environment-for-mt7622_rfb.patch | 33 + ...-ignore-max-frequency-from-device-tr.patch | 31 + .../002-nand-add-spi-nand-driver.patch | 8540 ----------------- ...boot-add-dts-and-config-for-spi-nand.patch | 57 - ...le-mtd-and-mtk_spi_nand-in-defconfig.patch | 22 - .../006-cmd-button-return-button-status.patch | 38 - .../patches/010-no-binman.patch | 23 - .../100-increase-CONFIG_SYS_BOOTM_LEN.patch | 11 - ...00-scripts-remove-dependency-on-swig.patch | 24 + ...patch => 200-cmd-add-imsz-and-imszb.patch} | 8 +- ...d-ability-to-select-item-by-shortkey.patch | 192 + ...ch => 211-cmd-bootmenu-custom-title.patch} | 8 +- ...eadmem.patch => 220-cmd-env-readmem.patch} | 10 +- ...622-generic-reset-button-ignore-env.patch} | 6 +- ...patch => 400-update-bpir2-defconfig.patch} | 3 +- ...patch => 401-update-u7623-defconfig.patch} | 0 ...update-bananapi-bpi-r64-device-tree.patch} | 42 +- ...403-add-bananapi_bpi-r64_defconfigs.patch} | 69 +- ...8450.patch => 410-add-linksys-e8450.patch} | 99 +- 39 files changed, 5711 insertions(+), 8847 deletions(-) create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-02-configs-RPi2-Disable-EFI-Grub-workaround.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-03-pinctrl-mediatek-fix-wrong-assignment-in-mtk_get_pin.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-04-pinctrl-mediatek-add-get_pin_muxing-ops-for-mediatek.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-05-pinctrl-mediatek-do-not-probe-gpio-driver-if-not-ena.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-06-pinctrl-mt7629-add-jtag-function-and-pin-group.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-07-configs-mt7622-use-ARMv8-Generic-Timer-instead-of-mt.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-08-dts-mt7629-enable-JTAG-pins-by-default.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-11-serial-serial-mtk-rewrite-the-setbrg-function.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-12-board-mt7629-enable-compression-of-u-boot-to-reduce-.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-13-configs-mt7622-enable-debug-uart-for-mt7622_rfb_defc.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch create mode 100644 package/boot/uboot-mediatek/patches/000-mtk-21-mmc-mtk-sd-don-t-ignore-max-frequency-from-device-tr.patch delete mode 100644 package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch delete mode 100644 package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch delete mode 100644 package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch delete mode 100644 package/boot/uboot-mediatek/patches/006-cmd-button-return-button-status.patch delete mode 100644 package/boot/uboot-mediatek/patches/010-no-binman.patch delete mode 100644 package/boot/uboot-mediatek/patches/100-increase-CONFIG_SYS_BOOTM_LEN.patch create mode 100644 package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch rename package/boot/uboot-mediatek/patches/{016-fit-totalsize.patch => 200-cmd-add-imsz-and-imszb.patch} (94%) create mode 100644 package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch rename package/boot/uboot-mediatek/patches/{008-bootmenu-custom-title.patch => 211-cmd-bootmenu-custom-title.patch} (80%) rename package/boot/uboot-mediatek/patches/{007-env-readmem.patch => 220-cmd-env-readmem.patch} (91%) rename package/boot/uboot-mediatek/patches/{009-mt7622-generic-reset-button-ignore-env.patch => 300-mt7622-generic-reset-button-ignore-env.patch} (88%) rename package/boot/uboot-mediatek/patches/{005-update-bpir2-defconfig.patch => 400-update-bpir2-defconfig.patch} (84%) rename package/boot/uboot-mediatek/patches/{010-update-u7623-defconfig.patch => 401-update-u7623-defconfig.patch} (100%) rename package/boot/uboot-mediatek/patches/{015-update-bananapi-bpi-r64-device-tree.patch => 402-update-bananapi-bpi-r64-device-tree.patch} (64%) rename package/boot/uboot-mediatek/patches/{017-add-bananapi_bpi-r64_defconfigs.patch => 403-add-bananapi_bpi-r64_defconfigs.patch} (86%) rename package/boot/uboot-mediatek/patches/{020-add-linksys-e8450.patch => 410-add-linksys-e8450.patch} (76%) diff --git a/package/boot/uboot-mediatek/Makefile b/package/boot/uboot-mediatek/Makefile index 6904b39938..efdc25a195 100644 --- a/package/boot/uboot-mediatek/Makefile +++ b/package/boot/uboot-mediatek/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk -PKG_VERSION:=2020.10 -PKG_HASH:=0d481bbdc05c0ee74908ec2f56a6daa53166cc6a78a0e4fac2ac5d025770a622 +PKG_VERSION:=2021.04-rc3 +PKG_HASH:=7c418e07f6065c8761eb2df890bb524d7109864325d8850ddb0c93eb345734f9 PKG_BUILD_DEPENDS:=arm-trusted-firmware-tools/host include $(INCLUDE_DIR)/u-boot.mk diff --git a/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch b/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch new file mode 100644 index 0000000000..c398ae4ab7 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-01-Revert-clk-Add-debugging-for-return-values.patch @@ -0,0 +1,69 @@ +From 5efb7855a9d33ac897d6e2a7117e4e3d35d433a5 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 11 Mar 2021 10:28:53 +0000 +Subject: [PATCH 01/21] 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 +@@ -84,7 +84,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; +@@ -97,15 +97,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, +@@ -124,7 +123,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; + } + + +@@ -472,7 +471,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)) +@@ -482,11 +480,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/package/boot/uboot-mediatek/patches/000-mtk-02-configs-RPi2-Disable-EFI-Grub-workaround.patch b/package/boot/uboot-mediatek/patches/000-mtk-02-configs-RPi2-Disable-EFI-Grub-workaround.patch new file mode 100644 index 0000000000..7b54489832 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-02-configs-RPi2-Disable-EFI-Grub-workaround.patch @@ -0,0 +1,21 @@ +From 04815ef5a49a9996acacfcb5e18924569f5e1bf5 Mon Sep 17 00:00:00 2001 +From: Matthias Brugger +Date: Tue, 16 Feb 2021 20:54:08 +0100 +Subject: [PATCH 02/21] configs: RPi2: Disable EFI Grub workaround + +The EFI Grub workaround isn't needed with Grub version 2.04 or higher. +This version was published over a year ago, so disable the workaround +to reduce boot time. + +Signed-off-by: Matthias Brugger +--- + configs/rpi_2_defconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/configs/rpi_2_defconfig ++++ b/configs/rpi_2_defconfig +@@ -42,3 +42,4 @@ CONFIG_SYS_WHITE_ON_BLACK=y + CONFIG_CONSOLE_SCROLL_LINES=10 + CONFIG_PHYS_TO_BUS=y + CONFIG_OF_LIBFDT_OVERLAY=y ++# CONFIG_EFI_GRUB_ARM32_WORKAROUND is not set diff --git a/package/boot/uboot-mediatek/patches/000-mtk-03-pinctrl-mediatek-fix-wrong-assignment-in-mtk_get_pin.patch b/package/boot/uboot-mediatek/patches/000-mtk-03-pinctrl-mediatek-fix-wrong-assignment-in-mtk_get_pin.patch new file mode 100644 index 0000000000..3aa6b6105f --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-03-pinctrl-mediatek-fix-wrong-assignment-in-mtk_get_pin.patch @@ -0,0 +1,25 @@ +From 6f18e581a7e98db3675b4c111701263647b20781 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Thu, 17 Dec 2020 19:29:56 +0800 +Subject: [PATCH 03/21] pinctrl: mediatek: fix wrong assignment in + mtk_get_pin_name + +This is a bug fix for mtk pinctrl common part. Appearently pins should be +used instead of grps in mtk_get_pin_name(). + +Signed-off-by: Sam Shih +--- + drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +@@ -219,7 +219,7 @@ static const char *mtk_get_pin_name(stru + { + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + +- if (!priv->soc->grps[selector].name) ++ if (!priv->soc->pins[selector].name) + return mtk_pinctrl_dummy_name; + + return priv->soc->pins[selector].name; diff --git a/package/boot/uboot-mediatek/patches/000-mtk-04-pinctrl-mediatek-add-get_pin_muxing-ops-for-mediatek.patch b/package/boot/uboot-mediatek/patches/000-mtk-04-pinctrl-mediatek-add-get_pin_muxing-ops-for-mediatek.patch new file mode 100644 index 0000000000..89b51f7e81 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-04-pinctrl-mediatek-add-get_pin_muxing-ops-for-mediatek.patch @@ -0,0 +1,43 @@ +From ca73da39ff0c9f599f75d7ccac0196030aa946b9 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Thu, 17 Dec 2020 19:32:48 +0800 +Subject: [PATCH 04/21] pinctrl: mediatek: add get_pin_muxing ops for mediatek + pinctrl + +This patch add get_pin_muxing support for mediatek pinctrl drivers + +Signed-off-by: Sam Shih +--- + drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +@@ -232,6 +232,19 @@ static int mtk_get_pins_count(struct ude + return priv->soc->npins; + } + ++static int mtk_get_pin_muxing(struct udevice *dev, ++ unsigned int selector, ++ char *buf, int size) ++{ ++ int val, err; ++ err = mtk_hw_get_value(dev, selector, PINCTRL_PIN_REG_MODE, &val); ++ if (err) ++ return err; ++ ++ snprintf(buf, size, "Aux Func.%d", val); ++ return 0; ++} ++ + static const char *mtk_get_group_name(struct udevice *dev, + unsigned int selector) + { +@@ -512,6 +525,7 @@ static int mtk_pinconf_group_set(struct + const struct pinctrl_ops mtk_pinctrl_ops = { + .get_pins_count = mtk_get_pins_count, + .get_pin_name = mtk_get_pin_name, ++ .get_pin_muxing = mtk_get_pin_muxing, + .get_groups_count = mtk_get_groups_count, + .get_group_name = mtk_get_group_name, + .get_functions_count = mtk_get_functions_count, diff --git a/package/boot/uboot-mediatek/patches/000-mtk-05-pinctrl-mediatek-do-not-probe-gpio-driver-if-not-ena.patch b/package/boot/uboot-mediatek/patches/000-mtk-05-pinctrl-mediatek-do-not-probe-gpio-driver-if-not-ena.patch new file mode 100644 index 0000000000..7a98e88843 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-05-pinctrl-mediatek-do-not-probe-gpio-driver-if-not-ena.patch @@ -0,0 +1,58 @@ +From d3fbbef13853a695cdea75a980a3d6bd150a68c1 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Mon, 11 Jan 2021 10:17:15 +0800 +Subject: [PATCH 05/21] pinctrl: mediatek: do not probe gpio driver if not + enabled + +The mtk pinctrl driver is a combination driver with support for both +pinctrl and gpio. When this driver is used in SPL, gpio support may not be +enabled, and this will result in a compilation error. + +To fix this, macros are added to make sure gpio related code will only be +compiled when gpio support is enabled. + +Signed-off-by: Weijie Gao +--- + drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +@@ -540,6 +540,8 @@ const struct pinctrl_ops mtk_pinctrl_ops + .set_state = pinctrl_generic_set_state, + }; + ++#if CONFIG_IS_ENABLED(DM_GPIO) || \ ++ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT)) + static int mtk_gpio_get(struct udevice *dev, unsigned int off) + { + int val, err; +@@ -647,12 +649,13 @@ static int mtk_gpiochip_register(struct + + return 0; + } ++#endif + + int mtk_pinctrl_common_probe(struct udevice *dev, + struct mtk_pinctrl_soc *soc) + { + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); +- int ret; ++ int ret = 0; + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) +@@ -660,9 +663,10 @@ int mtk_pinctrl_common_probe(struct udev + + priv->soc = soc; + ++#if CONFIG_IS_ENABLED(DM_GPIO) || \ ++ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT)) + ret = mtk_gpiochip_register(dev); +- if (ret) +- return ret; ++#endif + +- return 0; ++ return ret; + } diff --git a/package/boot/uboot-mediatek/patches/000-mtk-06-pinctrl-mt7629-add-jtag-function-and-pin-group.patch b/package/boot/uboot-mediatek/patches/000-mtk-06-pinctrl-mt7629-add-jtag-function-and-pin-group.patch new file mode 100644 index 0000000000..f4cc1eb69d --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-06-pinctrl-mt7629-add-jtag-function-and-pin-group.patch @@ -0,0 +1,50 @@ +From 1c6d07abf7fc79bf3950dc9ac56e3b566c334d3d Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 13 Jan 2021 16:29:23 +0800 +Subject: [PATCH 06/21] pinctrl: mt7629: add jtag function and pin group + +The EPHY LEDs of mt7629 can be used as JTAG. This patch adds the jtag pin +group to the pinctrl driver. + +Signed-off-by: Weijie Gao +--- + drivers/pinctrl/mediatek/pinctrl-mt7629.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/pinctrl/mediatek/pinctrl-mt7629.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c +@@ -201,6 +201,10 @@ static int mt7629_wf2g_led_funcs[] = { 1 + static int mt7629_wf5g_led_pins[] = { 18, }; + static int mt7629_wf5g_led_funcs[] = { 1, }; + ++/* LED for EPHY used as JTAG */ ++static int mt7629_ephy_leds_jtag_pins[] = { 12, 13, 14, 15, 16, }; ++static int mt7629_ephy_leds_jtag_funcs[] = { 7, 7, 7, 7, 7, }; ++ + /* Watchdog */ + static int mt7629_watchdog_pins[] = { 11, }; + static int mt7629_watchdog_funcs[] = { 1, }; +@@ -297,6 +301,7 @@ static const struct mtk_group_desc mt762 + PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2), + PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3), + PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4), ++ PINCTRL_PIN_GROUP("ephy_leds_jtag", mt7629_ephy_leds_jtag), + PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led), + PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led), + PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog), +@@ -364,6 +369,7 @@ static const char *const mt7629_uart_gro + static const char *const mt7629_wdt_groups[] = { "watchdog", }; + static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", }; + static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" }; ++static const char *const mt7629_jtag_groups[] = { "ephy_leds_jtag" }; + + static const struct mtk_function_desc mt7629_functions[] = { + {"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)}, +@@ -376,6 +382,7 @@ static const struct mtk_function_desc mt + {"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)}, + {"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)}, + {"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)}, ++ {"jtag", mt7629_jtag_groups, ARRAY_SIZE(mt7629_jtag_groups)}, + }; + + static struct mtk_pinctrl_soc mt7629_data = { diff --git a/package/boot/uboot-mediatek/patches/000-mtk-07-configs-mt7622-use-ARMv8-Generic-Timer-instead-of-mt.patch b/package/boot/uboot-mediatek/patches/000-mtk-07-configs-mt7622-use-ARMv8-Generic-Timer-instead-of-mt.patch new file mode 100644 index 0000000000..060c9aadbf --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-07-configs-mt7622-use-ARMv8-Generic-Timer-instead-of-mt.patch @@ -0,0 +1,25 @@ +From c47a5b927787a463eff8f67339d91e60fe0381c4 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:02:50 +0800 +Subject: [PATCH 07/21] configs: mt7622: use ARMv8 Generic Timer instead of + mtk_timer + +It's better to use the generic timer which is correctly initialized by +the ATF. The generic timer has higher resolution than the mtk_timer. + +Signed-off-by: Weijie Gao +--- + configs/mt7622_rfb_defconfig | 2 -- + 1 file changed, 2 deletions(-) + +--- a/configs/mt7622_rfb_defconfig ++++ b/configs/mt7622_rfb_defconfig +@@ -51,8 +51,6 @@ CONFIG_SPI=y + CONFIG_DM_SPI=y + CONFIG_MTK_SNOR=y + CONFIG_SYSRESET_WATCHDOG=y +-CONFIG_TIMER=y +-CONFIG_MTK_TIMER=y + CONFIG_WDT_MTK=y + CONFIG_LZO=y + CONFIG_HEXDUMP=y diff --git a/package/boot/uboot-mediatek/patches/000-mtk-08-dts-mt7629-enable-JTAG-pins-by-default.patch b/package/boot/uboot-mediatek/patches/000-mtk-08-dts-mt7629-enable-JTAG-pins-by-default.patch new file mode 100644 index 0000000000..f9f783ef37 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-08-dts-mt7629-enable-JTAG-pins-by-default.patch @@ -0,0 +1,50 @@ +From 4bee3f9e285007ccf77ca9916fff3d93fc4d8a80 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:43:27 +0800 +Subject: [PATCH 08/21] dts: mt7629: enable JTAG pins by default + +The EPHY LEDs belongs to the built-in FE switch of MT7629, which is barely +used. These LED pins on reference boards are used as JTAG socket. So it's +a good idea to change the default state to JTAG, and this will make it +convenience for debugging. + +Signed-off-by: Weijie Gao +--- + arch/arm/dts/mt7629-rfb.dts | 10 ++++++++++ + arch/arm/dts/mt7629.dtsi | 6 ++++++ + 2 files changed, 16 insertions(+) + +--- a/arch/arm/dts/mt7629-rfb.dts ++++ b/arch/arm/dts/mt7629-rfb.dts +@@ -36,6 +36,16 @@ + }; + + &pinctrl { ++ state_default: pinmux_conf { ++ u-boot,dm-pre-reloc; ++ ++ mux { ++ function = "jtag"; ++ groups = "ephy_leds_jtag"; ++ u-boot,dm-pre-reloc; ++ }; ++ }; ++ + snfi_pins: snfi-pins { + mux { + function = "flash"; +--- a/arch/arm/dts/mt7629.dtsi ++++ b/arch/arm/dts/mt7629.dtsi +@@ -152,6 +152,12 @@ + compatible = "mediatek,mt7629-pinctrl"; + reg = <0x10217000 0x8000>; + ++ pinctrl-names = "default"; ++ pinctrl-0 = <&state_default>; ++ ++ state_default: pinmux_conf { ++ }; ++ + gpio: gpio-controller { + gpio-controller; + #gpio-cells = <2>; diff --git a/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch b/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch new file mode 100644 index 0000000000..56a40ca0e1 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-09-board-mediatek-add-more-network-configurations.patch @@ -0,0 +1,44 @@ +From f3f320af7078a8c5647d870a31c1d3695dacd7cf Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:47:45 +0800 +Subject: [PATCH 09/21] 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 +@@ -36,6 +36,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 +@@ -54,6 +54,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 +@@ -52,5 +52,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/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch b/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch new file mode 100644 index 0000000000..658cbc1232 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-10-mmc-mtk-sd-increase-the-minimum-bus-frequency.patch @@ -0,0 +1,38 @@ +From ed880b7572e1135e3bd8382d4670a375f7d9c91b Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 15:56:17 +0800 +Subject: [PATCH 10/21] 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 | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/mmc/mtk-sd.c ++++ b/drivers/mmc/mtk-sd.c +@@ -232,6 +232,8 @@ + + #define SCLK_CYCLES_SHIFT 20 + ++#define MIN_BUS_CLK 260000 ++ + #define CMD_INTS_MASK \ + (MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO) + +@@ -1639,6 +1641,9 @@ static int msdc_drv_probe(struct udevice + else + cfg->f_min = host->src_clk_freq / (4 * 4095); + ++ if (cfg->f_min < MIN_BUS_CLK) ++ cfg->f_min = MIN_BUS_CLK; ++ + cfg->f_max = host->src_clk_freq; + + cfg->b_max = 1024; diff --git a/package/boot/uboot-mediatek/patches/000-mtk-11-serial-serial-mtk-rewrite-the-setbrg-function.patch b/package/boot/uboot-mediatek/patches/000-mtk-11-serial-serial-mtk-rewrite-the-setbrg-function.patch new file mode 100644 index 0000000000..2ce7733314 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-11-serial-serial-mtk-rewrite-the-setbrg-function.patch @@ -0,0 +1,141 @@ +From d8bde59186dafdea5bbe8d29d3a6ae7cac98e9d0 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Mon, 25 Jan 2021 11:19:08 +0800 +Subject: [PATCH 11/21] serial: serial-mtk: rewrite the setbrg function + +Currently the setbrg logic of serial-mtk is messy, and should be rewritten. +Also an option is added to make it possible to use highspeed=3 mode for all +bauds. + +The new logic is: +1. If baud clock > 12MHz + a) If baud <= 115200, highspeed=0 mode will be used (ns16550 compatible) + b) If baud <= 576000, highspeed=2 mode will be used + c) any baud > 576000, highspeed=3 mode will be used +2. If baud clock <= 12MHz + Always uses highspeed=3 mode + a) If baud <= 115200, calculates the divisor using DIV_ROUND_CLOSEST + b) any baud > 115200, the same as 1. c) + +Signed-off-by: Weijie Gao +--- + drivers/serial/serial_mtk.c | 74 +++++++++++++++++-------------------- + 1 file changed, 33 insertions(+), 41 deletions(-) + +--- a/drivers/serial/serial_mtk.c ++++ b/drivers/serial/serial_mtk.c +@@ -73,74 +73,64 @@ struct mtk_serial_regs { + struct mtk_serial_priv { + struct mtk_serial_regs __iomem *regs; + u32 clock; ++ bool force_highspeed; + }; + + static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud) + { +- bool support_clk12m_baud115200; +- u32 quot, samplecount, realbaud; ++ u32 quot, realbaud, samplecount = 1; + +- if ((baud <= 115200) && (priv->clock == 12000000)) +- support_clk12m_baud115200 = true; +- else +- support_clk12m_baud115200 = false; ++ /* Special case for low baud clock */ ++ if ((baud <= 115200) && (priv->clock == 12000000)) { ++ writel(3, &priv->regs->highspeed); ++ ++ quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud); ++ if (quot == 0) ++ quot = 1; ++ ++ samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud); ++ ++ realbaud = priv->clock / samplecount / quot; ++ if ((realbaud > BAUD_ALLOW_MAX(baud)) || ++ (realbaud < BAUD_ALLOW_MIX(baud))) { ++ pr_info("baud %d can't be handled\n", baud); ++ } ++ ++ goto set_baud; ++ } ++ ++ if (priv->force_highspeed) ++ goto use_hs3; + + if (baud <= 115200) { + writel(0, &priv->regs->highspeed); + quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud); +- +- if (support_clk12m_baud115200) { +- writel(3, &priv->regs->highspeed); +- quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud); +- if (quot == 0) +- quot = 1; +- +- samplecount = DIV_ROUND_CLOSEST(priv->clock, +- quot * baud); +- if (samplecount != 0) { +- realbaud = priv->clock / samplecount / quot; +- if ((realbaud > BAUD_ALLOW_MAX(baud)) || +- (realbaud < BAUD_ALLOW_MIX(baud))) { +- pr_info("baud %d can't be handled\n", +- baud); +- } +- } else { +- pr_info("samplecount is 0\n"); +- } +- } + } else if (baud <= 576000) { + writel(2, &priv->regs->highspeed); + + /* Set to next lower baudrate supported */ + if ((baud == 500000) || (baud == 576000)) + baud = 460800; ++ + quot = DIV_ROUND_UP(priv->clock, 4 * baud); + } else { ++use_hs3: + writel(3, &priv->regs->highspeed); ++ + quot = DIV_ROUND_UP(priv->clock, 256 * baud); ++ samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud); + } + ++set_baud: + /* set divisor */ + writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr); + writel(quot & 0xff, &priv->regs->dll); + writel((quot >> 8) & 0xff, &priv->regs->dlm); + writel(UART_LCR_WLS_8, &priv->regs->lcr); + +- if (baud > 460800) { +- u32 tmp; +- +- tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud); +- writel(tmp - 1, &priv->regs->sample_count); +- writel((tmp - 2) >> 1, &priv->regs->sample_point); +- } else { +- writel(0, &priv->regs->sample_count); +- writel(0xff, &priv->regs->sample_point); +- } +- +- if (support_clk12m_baud115200) { +- writel(samplecount - 1, &priv->regs->sample_count); +- writel((samplecount - 2) >> 1, &priv->regs->sample_point); +- } ++ /* set highspeed mode sample count & point */ ++ writel(samplecount - 1, &priv->regs->sample_count); ++ writel((samplecount - 2) >> 1, &priv->regs->sample_point); + } + + static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch) +@@ -248,6 +238,8 @@ static int mtk_serial_of_to_plat(struct + return -EINVAL; + } + ++ priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed"); ++ + return 0; + } + diff --git a/package/boot/uboot-mediatek/patches/000-mtk-12-board-mt7629-enable-compression-of-u-boot-to-reduce-.patch b/package/boot/uboot-mediatek/patches/000-mtk-12-board-mt7629-enable-compression-of-u-boot-to-reduce-.patch new file mode 100644 index 0000000000..3b5545db15 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-12-board-mt7629-enable-compression-of-u-boot-to-reduce-.patch @@ -0,0 +1,94 @@ +From a80ef99cb308904b82662deb66c5ed7a6ff59928 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 11:13:36 +0800 +Subject: [PATCH 12/21] board: mt7629: enable compression of u-boot to reduce + the size of final image + +This patch makes use of the decompression mechanism implemented for mt7628 +previously to reduce the total image size. Binman will be also removed. + +Signed-off-by: Weijie Gao +--- + Makefile | 3 +++ + arch/arm/dts/mt7629-rfb-u-boot.dtsi | 18 ------------------ + arch/arm/mach-mediatek/Kconfig | 1 - + configs/mt7629_rfb_defconfig | 6 ++++++ + 4 files changed, 9 insertions(+), 19 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -1728,6 +1728,9 @@ u-boot-elf.lds: arch/u-boot-elf.lds prep + + ifeq ($(CONFIG_SPL),y) + spl/u-boot-spl-mtk.bin: spl/u-boot-spl ++ ++u-boot-mtk.bin: u-boot-with-spl.bin ++ $(call if_changed,copy) + else + MKIMAGEFLAGS_u-boot-mtk.bin = -T mtk_image \ + -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \ +--- a/arch/arm/dts/mt7629-rfb-u-boot.dtsi ++++ b/arch/arm/dts/mt7629-rfb-u-boot.dtsi +@@ -5,24 +5,6 @@ + * Author: Weijie Gao + */ + +-#include +-/ { +- binman { +- filename = "u-boot-mtk.bin"; +- pad-byte = <0xff>; +- +-#ifdef CONFIG_SPL +- blob { +- filename = "spl/u-boot-spl-mtk.bin"; +- size = ; +- }; +- +- u-boot-img { +- }; +-#endif +- }; +-}; +- + &infracfg { + u-boot,dm-pre-reloc; + }; +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -36,7 +36,6 @@ config TARGET_MT7629 + bool "MediaTek MT7629 SoC" + select CPU_V7A + select SPL +- select BINMAN + help + The MediaTek MT7629 is a ARM-based SoC with a dual-core Cortex-A7 + including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet, +--- a/configs/mt7629_rfb_defconfig ++++ b/configs/mt7629_rfb_defconfig +@@ -10,7 +10,11 @@ CONFIG_SPL_TEXT_BASE=0x201000 + CONFIG_TARGET_MT7629=y + CONFIG_SPL_SERIAL_SUPPORT=y + CONFIG_SPL_DRIVERS_MISC_SUPPORT=y ++CONFIG_SPL_STACK_R_ADDR=0x40800000 ++CONFIG_SPL_PAYLOAD="u-boot-lzma.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 +@@ -18,6 +22,7 @@ CONFIG_DEFAULT_FDT_FILE="mt7629-rfb" + CONFIG_SYS_CONSOLE_IS_IN_ENV=y + # CONFIG_DISPLAY_BOARDINFO is not set + CONFIG_SPL_SYS_MALLOC_SIMPLE=y ++CONFIG_SPL_STACK_R=y + CONFIG_SPL_NOR_SUPPORT=y + CONFIG_SPL_WATCHDOG_SUPPORT=y + CONFIG_HUSH_PARSER=y +@@ -87,4 +92,5 @@ CONFIG_USB_STORAGE=y + CONFIG_USB_KEYBOARD=y + CONFIG_WDT_MTK=y + CONFIG_LZMA=y ++CONFIG_SPL_LZMA=y + # CONFIG_EFI_LOADER is not set diff --git a/package/boot/uboot-mediatek/patches/000-mtk-13-configs-mt7622-enable-debug-uart-for-mt7622_rfb_defc.patch b/package/boot/uboot-mediatek/patches/000-mtk-13-configs-mt7622-enable-debug-uart-for-mt7622_rfb_defc.patch new file mode 100644 index 0000000000..6b832148b9 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-13-configs-mt7622-enable-debug-uart-for-mt7622_rfb_defc.patch @@ -0,0 +1,26 @@ +From acd49b1549ff52286aace5e841420aa750325f8b Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:53:14 +0800 +Subject: [PATCH 13/21] configs: mt7622: enable debug uart for + mt7622_rfb_defconfig + +Enable debug uart for mt7622_rfb_defconfig + +Signed-off-by: Weijie Gao +--- + configs/mt7622_rfb_defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/configs/mt7622_rfb_defconfig ++++ b/configs/mt7622_rfb_defconfig +@@ -4,7 +4,10 @@ CONFIG_ARCH_MEDIATEK=y + CONFIG_SYS_TEXT_BASE=0x41e00000 + CONFIG_SYS_MALLOC_F_LEN=0x4000 + CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 + CONFIG_DEFAULT_DEVICE_TREE="mt7622-rfb" ++CONFIG_DEBUG_UART=y + CONFIG_FIT=y + CONFIG_DEFAULT_FDT_FILE="mt7622-rfb" + CONFIG_LOGLEVEL=7 diff --git a/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch b/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch new file mode 100644 index 0000000000..a01d9e2b17 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-14-drivers-mtd-add-support-for-MediaTek-SPI-NAND-flash-.patch @@ -0,0 +1,3698 @@ +From f22a055a9f589f1ec614045eba3cb0c5fd887feb Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 2 Mar 2021 16:58:01 +0800 +Subject: [PATCH 14/21] 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 +@@ -108,6 +108,8 @@ config HBMC_AM654 + This is the driver for HyperBus controller on TI's AM65x and + other SoCs + ++source "drivers/mtd/mtk-snand/Kconfig" ++ + source "drivers/mtd/nand/Kconfig" + + source "drivers/mtd/spi/Kconfig" +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -40,3 +40,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,526 @@ ++// 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) ++ mtd_erase_callback(instr); ++ else ++ 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/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch b/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch new file mode 100644 index 0000000000..0ec20eb91c --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-15-mtd-mtk-snand-add-support-for-SPL.patch @@ -0,0 +1,174 @@ +From 0c857d4c9cd9dc8e8ebba18cf9e9b10513ccb35d Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 08:57:29 +0800 +Subject: [PATCH 15/21] 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/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch b/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch new file mode 100644 index 0000000000..932c4b736a --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-16-env-add-support-for-generic-MTD-device.patch @@ -0,0 +1,409 @@ +From eaa9bc597e0bf8bcd1486ea49c8c7c070a37a8aa Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:11:32 +0800 +Subject: [PATCH 16/21] 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 +@@ -50,6 +50,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) || \ +@@ -64,7 +65,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 +@@ -207,6 +207,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 +@@ -513,10 +534,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 +@@ -560,6 +587,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 +@@ -131,6 +131,7 @@ enum env_location { + ENVL_FAT, + ENVL_FLASH, + ENVL_MMC, ++ ENVL_MTD, + ENVL_NAND, + ENVL_NVRAM, + ENVL_ONENAND, +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -22,6 +22,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/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch b/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch new file mode 100644 index 0000000000..aa38b2745e --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-17-board-mt7629-add-support-for-booting-from-SPI-NAND.patch @@ -0,0 +1,266 @@ +From 47b386259625061b376f538055a4f3fbd0ab7fef Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:48:53 +0800 +Subject: [PATCH 17/21] 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>; +--- a/board/mediatek/mt7629/Kconfig ++++ b/board/mediatek/mt7629/Kconfig +@@ -12,6 +12,39 @@ config MTK_SPL_PAD_SIZE + + config MTK_BROM_HEADER_INFO + string +- default "media=nor" ++ default "media=nor" if BOOT_FROM_SNOR ++ default "media=snand;nandinfo=2k+64" if BOOT_FROM_SNAND_2K_64 ++ default "media=snand;nandinfo=2k+128" if BOOT_FROM_SNAND_2K_128 ++ default "media=snand;nandinfo=4k+128" if BOOT_FROM_SNAND_4K_128 ++ default "media=snand;nandinfo=4k+256" if BOOT_FROM_SNAND_4K_256 ++ ++choice ++ prompt "Boot device" ++ default BOOT_FROM_SNOR ++ ++config BOOT_FROM_SNOR ++ bool "SPI-NOR" ++ ++config BOOT_FROM_SNAND_2K_64 ++ bool "SPI-NAND (2K+64)" ++ select MT7629_BOOT_FROM_SNAND ++ ++config BOOT_FROM_SNAND_2K_128 ++ bool "SPI-NAND (2K+128)" ++ select MT7629_BOOT_FROM_SNAND ++ ++config BOOT_FROM_SNAND_4K_128 ++ bool "SPI-NAND (4K+128)" ++ select MT7629_BOOT_FROM_SNAND ++ ++config BOOT_FROM_SNAND_4K_256 ++ bool "SPI-NAND (4K+256)" ++ select MT7629_BOOT_FROM_SNAND ++ ++endchoice ++ ++config MT7629_BOOT_FROM_SNAND ++ bool ++ default n + + endif +--- /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 +@@ -30,12 +30,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/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch b/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch new file mode 100644 index 0000000000..2202911950 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-18-board-mt7622-use-new-spi-nand-driver.patch @@ -0,0 +1,76 @@ +From ec0d1899b035700a657721761ff6370b940450ab Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 10:51:43 +0800 +Subject: [PATCH 18/21] 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 +@@ -15,6 +15,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_CLK=y + CONFIG_DM_MMC=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/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch b/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch new file mode 100644 index 0000000000..fadb274bfd --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-19-configs-mt7629-remove-unused-options-and-add-dm-comm.patch @@ -0,0 +1,31 @@ +From 2f7aaf3c2c127bd53d5e8bfe39e808fdd6eb99be Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Wed, 3 Mar 2021 12:12:39 +0800 +Subject: [PATCH 19/21] 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 +@@ -28,9 +28,14 @@ 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_SF_TEST=y diff --git a/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch b/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch new file mode 100644 index 0000000000..228c3351ca --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-20-configs-mt7622-enable-environment-for-mt7622_rfb.patch @@ -0,0 +1,33 @@ +From e5a71a0eebadfb3d75d8619a8b317eec58b2bca2 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Sat, 6 Mar 2021 16:29:33 +0800 +Subject: [PATCH 20/21] 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 +@@ -4,6 +4,8 @@ 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=0x280000 + CONFIG_DEBUG_UART_BASE=0x11002000 + CONFIG_DEBUG_UART_CLOCK=25000000 + CONFIG_DEFAULT_DEVICE_TREE="mt7622-rfb" +@@ -21,6 +23,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/package/boot/uboot-mediatek/patches/000-mtk-21-mmc-mtk-sd-don-t-ignore-max-frequency-from-device-tr.patch b/package/boot/uboot-mediatek/patches/000-mtk-21-mmc-mtk-sd-don-t-ignore-max-frequency-from-device-tr.patch new file mode 100644 index 0000000000..37810f9d74 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/000-mtk-21-mmc-mtk-sd-don-t-ignore-max-frequency-from-device-tr.patch @@ -0,0 +1,31 @@ +From 4bdab0ea008113dda4e001ab8d6863945000c1b2 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 11 Mar 2021 14:58:26 +0000 +Subject: [PATCH 21/21] mmc: mtk-sd: don't ignore max-frequency from device + tree + +commit e58e68d9 ("mmc: mtk-sd: assign plat->cfg.f_max with a correct value") +wrongly assumed that plat->cfg.f_max is always unset at the time +mscd_drv_probe() is run. This is not true in case max-frequency being +defined in device tree, as it is then already set by mmc_of_parser() +in msdc_of_to_plat(). +Only set plat->cfg.f_max to the default maximum value in case it is +not already set to a sane value. + +Signed-off-by: Daniel Golle +--- + drivers/mmc/mtk-sd.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mmc/mtk-sd.c ++++ b/drivers/mmc/mtk-sd.c +@@ -1644,7 +1644,8 @@ static int msdc_drv_probe(struct udevice + if (cfg->f_min < MIN_BUS_CLK) + cfg->f_min = MIN_BUS_CLK; + +- cfg->f_max = host->src_clk_freq; ++ if (cfg->f_max < cfg->f_min || cfg->f_max > host->src_clk_freq) ++ cfg->f_max = host->src_clk_freq; + + cfg->b_max = 1024; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch b/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch deleted file mode 100644 index 5d3e94ac86..0000000000 --- a/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch +++ /dev/null @@ -1,8540 +0,0 @@ -From de8b6cf615be20b25d0f3c817866de2c0d46a704 Mon Sep 17 00:00:00 2001 -From: Sam Shih -Date: Mon, 20 Apr 2020 17:10:05 +0800 -Subject: [PATCH 1/3] nand: add spi nand driver - -Add spi nand driver support for mt7622 based on nfi controller - -Signed-off-by: Xiangsheng Hou ---- - drivers/mtd/Kconfig | 7 + - drivers/mtd/Makefile | 4 + - drivers/mtd/nand/raw/nand.c | 2 + - drivers/mtd/nandx/NOTICE | 52 + - drivers/mtd/nandx/Nandx.config | 17 + - drivers/mtd/nandx/Nandx.mk | 91 ++ - drivers/mtd/nandx/README | 31 + - drivers/mtd/nandx/core/Nandx.mk | 38 + - drivers/mtd/nandx/core/core_io.c | 735 +++++++++ - drivers/mtd/nandx/core/core_io.h | 39 + - drivers/mtd/nandx/core/nand/device_spi.c | 200 +++ - drivers/mtd/nandx/core/nand/device_spi.h | 132 ++ - drivers/mtd/nandx/core/nand/nand_spi.c | 526 +++++++ - drivers/mtd/nandx/core/nand/nand_spi.h | 35 + - drivers/mtd/nandx/core/nand_base.c | 304 ++++ - drivers/mtd/nandx/core/nand_base.h | 71 + - drivers/mtd/nandx/core/nand_chip.c | 272 ++++ - drivers/mtd/nandx/core/nand_chip.h | 103 ++ - drivers/mtd/nandx/core/nand_device.c | 285 ++++ - drivers/mtd/nandx/core/nand_device.h | 608 ++++++++ - drivers/mtd/nandx/core/nfi.h | 51 + - drivers/mtd/nandx/core/nfi/nfi_base.c | 1357 +++++++++++++++++ - drivers/mtd/nandx/core/nfi/nfi_base.h | 95 ++ - drivers/mtd/nandx/core/nfi/nfi_regs.h | 114 ++ - drivers/mtd/nandx/core/nfi/nfi_spi.c | 689 +++++++++ - drivers/mtd/nandx/core/nfi/nfi_spi.h | 44 + - drivers/mtd/nandx/core/nfi/nfi_spi_regs.h | 64 + - drivers/mtd/nandx/core/nfi/nfiecc.c | 510 +++++++ - drivers/mtd/nandx/core/nfi/nfiecc.h | 90 ++ - drivers/mtd/nandx/core/nfi/nfiecc_regs.h | 51 + - drivers/mtd/nandx/driver/Nandx.mk | 18 + - drivers/mtd/nandx/driver/bbt/bbt.c | 408 +++++ - drivers/mtd/nandx/driver/uboot/driver.c | 574 +++++++ - drivers/mtd/nandx/include/Nandx.mk | 16 + - drivers/mtd/nandx/include/internal/bbt.h | 62 + - .../mtd/nandx/include/internal/nandx_core.h | 250 +++ - .../mtd/nandx/include/internal/nandx_errno.h | 40 + - .../mtd/nandx/include/internal/nandx_util.h | 221 +++ - drivers/mtd/nandx/include/uboot/nandx_os.h | 78 + - include/configs/mt7622.h | 25 + - 40 files changed, 8309 insertions(+) - create mode 100644 drivers/mtd/nandx/NOTICE - create mode 100644 drivers/mtd/nandx/Nandx.config - create mode 100644 drivers/mtd/nandx/Nandx.mk - create mode 100644 drivers/mtd/nandx/README - create mode 100644 drivers/mtd/nandx/core/Nandx.mk - create mode 100644 drivers/mtd/nandx/core/core_io.c - create mode 100644 drivers/mtd/nandx/core/core_io.h - create mode 100644 drivers/mtd/nandx/core/nand/device_spi.c - create mode 100644 drivers/mtd/nandx/core/nand/device_spi.h - create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.c - create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.h - create mode 100644 drivers/mtd/nandx/core/nand_base.c - create mode 100644 drivers/mtd/nandx/core/nand_base.h - create mode 100644 drivers/mtd/nandx/core/nand_chip.c - create mode 100644 drivers/mtd/nandx/core/nand_chip.h - create mode 100644 drivers/mtd/nandx/core/nand_device.c - create mode 100644 drivers/mtd/nandx/core/nand_device.h - create mode 100644 drivers/mtd/nandx/core/nfi.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.c - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_regs.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.c - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi_regs.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.c - create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.h - create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc_regs.h - create mode 100644 drivers/mtd/nandx/driver/Nandx.mk - create mode 100644 drivers/mtd/nandx/driver/bbt/bbt.c - create mode 100644 drivers/mtd/nandx/driver/uboot/driver.c - create mode 100644 drivers/mtd/nandx/include/Nandx.mk - create mode 100644 drivers/mtd/nandx/include/internal/bbt.h - create mode 100644 drivers/mtd/nandx/include/internal/nandx_core.h - create mode 100644 drivers/mtd/nandx/include/internal/nandx_errno.h - create mode 100644 drivers/mtd/nandx/include/internal/nandx_util.h - create mode 100644 drivers/mtd/nandx/include/uboot/nandx_os.h - ---- a/drivers/mtd/Kconfig -+++ b/drivers/mtd/Kconfig -@@ -108,6 +108,13 @@ config HBMC_AM654 - This is the driver for HyperBus controller on TI's AM65x and - other SoCs - -+config MTK_SPI_NAND -+ tristate "Mediatek SPI Nand" -+ depends on DM_MTD -+ help -+ This option will support SPI Nand device via Mediatek -+ NFI controller. -+ - source "drivers/mtd/nand/Kconfig" - - source "drivers/mtd/spi/Kconfig" ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -41,3 +41,7 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPOR - obj-$(CONFIG_SPL_UBI) += ubispl/ - - endif -+ -+ifeq ($(CONFIG_MTK_SPI_NAND), y) -+include $(srctree)/drivers/mtd/nandx/Nandx.mk -+endif ---- a/drivers/mtd/nand/raw/nand.c -+++ b/drivers/mtd/nand/raw/nand.c -@@ -91,8 +91,10 @@ static void nand_init_chip(int i) - if (board_nand_init(nand)) - return; - -+#ifndef CONFIG_MTK_SPI_NAND - if (nand_scan(mtd, maxchips)) - return; -+#endif - - nand_register(i, mtd); - } ---- /dev/null -+++ b/drivers/mtd/nandx/NOTICE -@@ -0,0 +1,52 @@ -+ -+/* -+ * Nandx - Mediatek Common Nand Driver -+ * Copyright (C) 2017 MediaTek Inc. -+ * -+ * Nandx is dual licensed: you can use it either under the terms of -+ * the GPL, or the BSD license, at your option. -+ * -+ * a) This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details. -+ * -+ * Alternatively, -+ * -+ * b) Redistribution and use in source and binary forms, with or -+ * without modification, are permitted provided that the following -+ * conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer. -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#################################################################################################### -\ No newline at end of file ---- /dev/null -+++ b/drivers/mtd/nandx/Nandx.config -@@ -0,0 +1,17 @@ -+NANDX_SIMULATOR_SUPPORT := n -+NANDX_CTP_SUPPORT := n -+NANDX_DA_SUPPORT := n -+NANDX_PRELOADER_SUPPORT := n -+NANDX_LK_SUPPORT := n -+NANDX_KERNEL_SUPPORT := n -+NANDX_BROM_SUPPORT := n -+NANDX_UBOOT_SUPPORT := y -+NANDX_BBT_SUPPORT := y -+ -+NANDX_NAND_SPI := y -+NANDX_NAND_SLC := n -+NANDX_NAND_MLC := n -+NANDX_NAND_TLC := n -+NANDX_NFI_BASE := y -+NANDX_NFI_ECC := y -+NANDX_NFI_SPI := y ---- /dev/null -+++ b/drivers/mtd/nandx/Nandx.mk -@@ -0,0 +1,91 @@ -+# -+# Copyright (C) 2017 MediaTek Inc. -+# Licensed under either -+# BSD Licence, (see NOTICE for more details) -+# GNU General Public License, version 2.0, (see NOTICE for more details) -+# -+ -+nandx_dir := $(shell dirname $(lastword $(MAKEFILE_LIST))) -+include $(nandx_dir)/Nandx.config -+ -+ifeq ($(NANDX_SIMULATOR_SUPPORT), y) -+sim-obj := -+sim-inc := -+nandx-obj := sim-obj -+nandx-prefix := . -+nandx-postfix := %.o -+sim-inc += -I$(nandx-prefix)/include/internal -+sim-inc += -I$(nandx-prefix)/include/simulator -+endif -+ -+ifeq ($(NANDX_CTP_SUPPORT), y) -+nandx-obj := C_SRC_FILES -+nandx-prefix := $(nandx_dir) -+nandx-postfix := %.c -+INC_DIRS += $(nandx_dir)/include/internal -+INC_DIRS += $(nandx_dir)/include/ctp -+endif -+ -+ifeq ($(NANDX_DA_SUPPORT), y) -+nandx-obj := obj-y -+nandx-prefix := $(nandx_dir) -+nandx-postfix := %.o -+INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/internal -+INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/da -+endif -+ -+ifeq ($(NANDX_PRELOADER_SUPPORT), y) -+nandx-obj := MOD_SRC -+nandx-prefix := $(nandx_dir) -+nandx-postfix := %.c -+C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/internal -+C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/preloader -+endif -+ -+ifeq ($(NANDX_LK_SUPPORT), y) -+nandx-obj := MODULE_SRCS -+nandx-prefix := $(nandx_dir) -+nandx-postfix := %.c -+GLOBAL_INCLUDES += $(nandx_dir)/include/internal -+GLOBAL_INCLUDES += $(nandx_dir)/include/lk -+endif -+ -+ifeq ($(NANDX_KERNEL_SUPPORT), y) -+nandx-obj := obj-y -+nandx-prefix := nandx -+nandx-postfix := %.o -+ccflags-y += -I$(nandx_dir)/include/internal -+ccflags-y += -I$(nandx_dir)/include/kernel -+endif -+ -+ifeq ($(NANDX_UBOOT_SUPPORT), y) -+nandx-obj := obj-y -+nandx-prefix := nandx -+nandx-postfix := %.o -+ccflags-y += -I$(nandx_dir)/include/internal -+ccflags-y += -I$(nandx_dir)/include/uboot -+endif -+ -+nandx-y := -+include $(nandx_dir)/core/Nandx.mk -+nandx-target := $(nandx-prefix)/core/$(nandx-postfix) -+$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y)) -+ -+ -+nandx-y := -+include $(nandx_dir)/driver/Nandx.mk -+nandx-target := $(nandx-prefix)/driver/$(nandx-postfix) -+$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y)) -+ -+ifeq ($(NANDX_SIMULATOR_SUPPORT), y) -+cc := gcc -+CFLAGS += $(sim-inc) -+ -+.PHONY:nandx -+nandx: $(sim-obj) -+ $(cc) $(sim-obj) -o nandx -+ -+.PHONY:clean -+clean: -+ rm -rf $(sim-obj) nandx -+endif ---- /dev/null -+++ b/drivers/mtd/nandx/README -@@ -0,0 +1,31 @@ -+ -+ NAND2.0 -+ =============================== -+ -+ NAND2.0 is a common nand driver which designed for accessing -+different type of NANDs(SLC, SPI-NAND, MLC, TLC) on various OS. This -+driver can work on mostly SoCs of Mediatek. -+ -+ Although there already has a common nand driver, it doesn't cover -+SPI-NAND, and not match our IC-Verification's reqirement. We need -+a driver that can be exten or cut easily. -+ -+ This driver is base on NANDX & SLC. We try to refactor structures, -+and make them inheritable. We also refactor some operations' flow -+principally for adding SPI-NAND support. -+ -+ This driver's architecture is like: -+ -+ Driver @LK/Uboot/DA... |IC verify/other purposes -+ ---------------------------------------------------------------- -+ partition | BBM | -+ -------------------------------------- | extend_core -+ nandx_core/core_io | -+ ---------------------------------------------------------------- -+ nand_chip/nand_base | -+ -------------------------------------- | extend_nfi -+ nand_device | nfi/nfi_base | -+ -+ Any block of above graph can be extended at your will, if you -+want add new feature into this code, please make sure that your code -+would follow the framework, and we will be appreciated about it. ---- /dev/null -+++ b/drivers/mtd/nandx/core/Nandx.mk -@@ -0,0 +1,38 @@ -+# -+# Copyright (C) 2017 MediaTek Inc. -+# Licensed under either -+# BSD Licence, (see NOTICE for more details) -+# GNU General Public License, version 2.0, (see NOTICE for more details) -+# -+ -+nandx-y += nand_device.c -+nandx-y += nand_base.c -+nandx-y += nand_chip.c -+nandx-y += core_io.c -+ -+nandx-header-y += nand_device.h -+nandx-header-y += nand_base.h -+nandx-header-y += nand_chip.h -+nandx-header-y += core_io.h -+nandx-header-y += nfi.h -+ -+nandx-$(NANDX_NAND_SPI) += nand/device_spi.c -+nandx-$(NANDX_NAND_SPI) += nand/nand_spi.c -+nandx-$(NANDX_NAND_SLC) += nand/device_slc.c -+nandx-$(NANDX_NAND_SLC) += nand/nand_slc.c -+ -+nandx-header-$(NANDX_NAND_SPI) += nand/device_spi.h -+nandx-header-$(NANDX_NAND_SPI) += nand/nand_spi.h -+nandx-header-$(NANDX_NAND_SLC) += nand/device_slc.h -+nandx-header-$(NANDX_NAND_SLC) += nand/nand_slc.h -+ -+nandx-$(NANDX_NFI_BASE) += nfi/nfi_base.c -+nandx-$(NANDX_NFI_ECC) += nfi/nfiecc.c -+nandx-$(NANDX_NFI_SPI) += nfi/nfi_spi.c -+ -+nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_base.h -+nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_regs.h -+nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc.h -+nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc_regs.h -+nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi.h -+nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi_regs.h ---- /dev/null -+++ b/drivers/mtd/nandx/core/core_io.c -@@ -0,0 +1,735 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+/*NOTE: switch cache/multi*/ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "nand_chip.h" -+#include "core_io.h" -+ -+static struct nandx_desc *g_nandx; -+ -+static inline bool is_sector_align(u64 val) -+{ -+ return reminder(val, g_nandx->chip->sector_size) ? false : true; -+} -+ -+static inline bool is_page_align(u64 val) -+{ -+ return reminder(val, g_nandx->chip->page_size) ? false : true; -+} -+ -+static inline bool is_block_align(u64 val) -+{ -+ return reminder(val, g_nandx->chip->block_size) ? false : true; -+} -+ -+static inline u32 page_sectors(void) -+{ -+ return div_down(g_nandx->chip->page_size, g_nandx->chip->sector_size); -+} -+ -+static inline u32 sector_oob(void) -+{ -+ return div_down(g_nandx->chip->oob_size, page_sectors()); -+} -+ -+static inline u32 sector_padded_size(void) -+{ -+ return g_nandx->chip->sector_size + g_nandx->chip->sector_spare_size; -+} -+ -+static inline u32 page_padded_size(void) -+{ -+ return page_sectors() * sector_padded_size(); -+} -+ -+static inline u32 offset_to_padded_col(u64 offset) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ u32 col, sectors; -+ -+ col = reminder(offset, nandx->chip->page_size); -+ sectors = div_down(col, nandx->chip->sector_size); -+ -+ return col + sectors * nandx->chip->sector_spare_size; -+} -+ -+static inline u32 offset_to_row(u64 offset) -+{ -+ return div_down(offset, g_nandx->chip->page_size); -+} -+ -+static inline u32 offset_to_col(u64 offset) -+{ -+ return reminder(offset, g_nandx->chip->page_size); -+} -+ -+static inline u32 oob_upper_size(void) -+{ -+ return g_nandx->ecc_en ? g_nandx->chip->oob_size : -+ g_nandx->chip->sector_spare_size * page_sectors(); -+} -+ -+static inline bool is_upper_oob_align(u64 val) -+{ -+ return reminder(val, oob_upper_size()) ? false : true; -+} -+ -+#define prepare_op(_op, _row, _col, _len, _data, _oob) \ -+ do { \ -+ (_op).row = (_row); \ -+ (_op).col = (_col); \ -+ (_op).len = (_len); \ -+ (_op).data = (_data); \ -+ (_op).oob = (_oob); \ -+ } while (0) -+ -+static int operation_multi(enum nandx_op_mode mode, u8 *data, u8 *oob, -+ u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ u32 row = offset_to_row(offset); -+ u32 col = offset_to_padded_col(offset); -+ -+ if (nandx->mode == NANDX_IDLE) { -+ nandx->mode = mode; -+ nandx->ops_current = 0; -+ } else if (nandx->mode != mode) { -+ pr_info("forbid mixed operations.\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ prepare_op(nandx->ops[nandx->ops_current], row, col, len, data, oob); -+ nandx->ops_current++; -+ -+ if (nandx->ops_current == nandx->ops_multi_len) -+ return nandx_sync(); -+ -+ return nandx->ops_multi_len - nandx->ops_current; -+} -+ -+static int operation_sequent(enum nandx_op_mode mode, u8 *data, u8 *oob, -+ u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ struct nand_chip *chip = nandx->chip; -+ u32 row = offset_to_row(offset); -+ func_chip_ops chip_ops; -+ u8 *ref_data = data, *ref_oob = oob; -+ int align, ops, row_step; -+ int i, rem; -+ -+ align = data ? chip->page_size : oob_upper_size(); -+ ops = data ? div_down(len, align) : div_down(len, oob_upper_size()); -+ row_step = 1; -+ -+ switch (mode) { -+ case NANDX_ERASE: -+ chip_ops = chip->erase_block; -+ align = chip->block_size; -+ ops = div_down(len, align); -+ row_step = chip->block_pages; -+ break; -+ -+ case NANDX_READ: -+ chip_ops = chip->read_page; -+ break; -+ -+ case NANDX_WRITE: -+ chip_ops = chip->write_page; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ if (!data) { -+ ref_data = nandx->head_buf; -+ memset(ref_data, 0xff, chip->page_size); -+ } -+ -+ if (!oob) { -+ ref_oob = nandx->head_buf + chip->page_size; -+ memset(ref_oob, 0xff, oob_upper_size()); -+ } -+ -+ for (i = 0; i < ops; i++) { -+ prepare_op(nandx->ops[nandx->ops_current], -+ row + i * row_step, 0, align, ref_data, ref_oob); -+ nandx->ops_current++; -+ /* if data or oob is null, nandx->head_buf or -+ * nandx->head_buf + chip->page_size should not been used -+ * so, here it is safe to use the buf. -+ */ -+ ref_data = data ? ref_data + chip->page_size : nandx->head_buf; -+ ref_oob = oob ? ref_oob + oob_upper_size() : -+ nandx->head_buf + chip->page_size; -+ } -+ -+ if (nandx->mode == NANDX_WRITE) { -+ rem = reminder(nandx->ops_current, nandx->min_write_pages); -+ if (rem) -+ return nandx->min_write_pages - rem; -+ } -+ -+ nandx->ops_current = 0; -+ return chip_ops(chip, nandx->ops, ops); -+} -+ -+static int read_pages(u8 *data, u8 *oob, u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ struct nand_chip *chip = nandx->chip; -+ struct nandx_split64 split = {0}; -+ u8 *ref_data = data, *ref_oob; -+ u32 row, col; -+ int ret = 0, i, ops; -+ u32 head_offset = 0; -+ u64 val; -+ -+ if (!data) -+ return operation_sequent(NANDX_READ, NULL, oob, offset, len); -+ -+ ref_oob = oob ? oob : nandx->head_buf + chip->page_size; -+ -+ nandx_split(&split, offset, len, val, chip->page_size); -+ -+ if (split.head_len) { -+ row = offset_to_row(split.head); -+ col = offset_to_col(split.head); -+ prepare_op(nandx->ops[nandx->ops_current], row, 0, -+ chip->page_size, -+ nandx->head_buf, ref_oob); -+ nandx->ops_current++; -+ -+ head_offset = col; -+ -+ ref_data += split.head_len; -+ ref_oob = oob ? ref_oob + oob_upper_size() : -+ nandx->head_buf + chip->page_size; -+ } -+ -+ if (split.body_len) { -+ ops = div_down(split.body_len, chip->page_size); -+ row = offset_to_row(split.body); -+ for (i = 0; i < ops; i++) { -+ prepare_op(nandx->ops[nandx->ops_current], -+ row + i, 0, chip->page_size, -+ ref_data, ref_oob); -+ nandx->ops_current++; -+ ref_data += chip->page_size; -+ ref_oob = oob ? ref_oob + oob_upper_size() : -+ nandx->head_buf + chip->page_size; -+ } -+ } -+ -+ if (split.tail_len) { -+ row = offset_to_row(split.tail); -+ prepare_op(nandx->ops[nandx->ops_current], row, 0, -+ chip->page_size, nandx->tail_buf, ref_oob); -+ nandx->ops_current++; -+ } -+ -+ ret = chip->read_page(chip, nandx->ops, nandx->ops_current); -+ -+ if (split.head_len) -+ memcpy(data, nandx->head_buf + head_offset, split.head_len); -+ if (split.tail_len) -+ memcpy(ref_data, nandx->tail_buf, split.tail_len); -+ -+ nandx->ops_current = 0; -+ return ret; -+} -+ -+int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ -+ if (!len || len > nandx->info.total_size) -+ return -EINVAL; -+ if (div_up(len, nandx->chip->page_size) > nandx->ops_len) -+ return -EINVAL; -+ if (!data && !oob) -+ return -EINVAL; -+ /** -+ * as design, oob not support partial read -+ * and, the length of oob buf should be oob size aligned -+ */ -+ if (!data && !is_upper_oob_align(len)) -+ return -EINVAL; -+ -+ if (g_nandx->multi_en) { -+ /* as design, there only 2 buf for partial read, -+ * if partial read allowed for multi read, -+ * there are not enough buf -+ */ -+ if (!is_sector_align(offset)) -+ return -EINVAL; -+ if (data && !is_sector_align(len)) -+ return -EINVAL; -+ return operation_multi(NANDX_READ, data, oob, offset, len); -+ } -+ -+ nandx->ops_current = 0; -+ nandx->mode = NANDX_IDLE; -+ return read_pages(data, oob, offset, len); -+} -+ -+static int write_pages(u8 *data, u8 *oob, u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ struct nand_chip *chip = nandx->chip; -+ struct nandx_split64 split = {0}; -+ int ret, rem, i, ops; -+ u32 row, col; -+ u8 *ref_oob = oob; -+ u64 val; -+ -+ nandx->mode = NANDX_WRITE; -+ -+ if (!data) -+ return operation_sequent(NANDX_WRITE, NULL, oob, offset, len); -+ -+ if (!oob) { -+ ref_oob = nandx->head_buf + chip->page_size; -+ memset(ref_oob, 0xff, oob_upper_size()); -+ } -+ -+ nandx_split(&split, offset, len, val, chip->page_size); -+ -+ /*NOTE: slc can support sector write, here copy too many data.*/ -+ if (split.head_len) { -+ row = offset_to_row(split.head); -+ col = offset_to_col(split.head); -+ memset(nandx->head_buf, 0xff, page_padded_size()); -+ memcpy(nandx->head_buf + col, data, split.head_len); -+ prepare_op(nandx->ops[nandx->ops_current], row, 0, -+ chip->page_size, nandx->head_buf, ref_oob); -+ nandx->ops_current++; -+ -+ data += split.head_len; -+ ref_oob = oob ? ref_oob + oob_upper_size() : -+ nandx->head_buf + chip->page_size; -+ } -+ -+ if (split.body_len) { -+ row = offset_to_row(split.body); -+ ops = div_down(split.body_len, chip->page_size); -+ for (i = 0; i < ops; i++) { -+ prepare_op(nandx->ops[nandx->ops_current], -+ row + i, 0, chip->page_size, data, ref_oob); -+ nandx->ops_current++; -+ data += chip->page_size; -+ ref_oob = oob ? ref_oob + oob_upper_size() : -+ nandx->head_buf + chip->page_size; -+ } -+ } -+ -+ if (split.tail_len) { -+ row = offset_to_row(split.tail); -+ memset(nandx->tail_buf, 0xff, page_padded_size()); -+ memcpy(nandx->tail_buf, data, split.tail_len); -+ prepare_op(nandx->ops[nandx->ops_current], row, 0, -+ chip->page_size, nandx->tail_buf, ref_oob); -+ nandx->ops_current++; -+ } -+ -+ rem = reminder(nandx->ops_current, nandx->min_write_pages); -+ if (rem) -+ return nandx->min_write_pages - rem; -+ -+ ret = chip->write_page(chip, nandx->ops, nandx->ops_current); -+ -+ nandx->ops_current = 0; -+ nandx->mode = NANDX_IDLE; -+ return ret; -+} -+ -+int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ -+ if (!len || len > nandx->info.total_size) -+ return -EINVAL; -+ if (div_up(len, nandx->chip->page_size) > nandx->ops_len) -+ return -EINVAL; -+ if (!data && !oob) -+ return -EINVAL; -+ if (!data && !is_upper_oob_align(len)) -+ return -EINVAL; -+ -+ if (nandx->multi_en) { -+ if (!is_page_align(offset)) -+ return -EINVAL; -+ if (data && !is_page_align(len)) -+ return -EINVAL; -+ -+ return operation_multi(NANDX_WRITE, data, oob, offset, len); -+ } -+ -+ return write_pages(data, oob, offset, len); -+} -+ -+int nandx_erase(u64 offset, size_t len) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ -+ if (!len || len > nandx->info.total_size) -+ return -EINVAL; -+ if (div_down(len, nandx->chip->block_size) > nandx->ops_len) -+ return -EINVAL; -+ if (!is_block_align(offset) || !is_block_align(len)) -+ return -EINVAL; -+ -+ if (g_nandx->multi_en) -+ return operation_multi(NANDX_ERASE, NULL, NULL, offset, len); -+ -+ nandx->ops_current = 0; -+ nandx->mode = NANDX_IDLE; -+ return operation_sequent(NANDX_ERASE, NULL, NULL, offset, len); -+} -+ -+int nandx_sync(void) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ struct nand_chip *chip = nandx->chip; -+ func_chip_ops chip_ops; -+ int ret, i, rem; -+ -+ if (!nandx->ops_current) -+ return 0; -+ -+ rem = reminder(nandx->ops_current, nandx->ops_multi_len); -+ if (nandx->multi_en && rem) { -+ ret = -EIO; -+ goto error; -+ } -+ -+ switch (nandx->mode) { -+ case NANDX_IDLE: -+ return 0; -+ case NANDX_ERASE: -+ chip_ops = chip->erase_block; -+ break; -+ case NANDX_READ: -+ chip_ops = chip->read_page; -+ break; -+ case NANDX_WRITE: -+ chip_ops = chip->write_page; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ rem = reminder(nandx->ops_current, nandx->min_write_pages); -+ if (!nandx->multi_en && nandx->mode == NANDX_WRITE && rem) { -+ /* in one process of program, only allow 2 pages to do partial -+ * write, here we supposed 1st buf would be used, and 2nd -+ * buf should be not used. -+ */ -+ memset(nandx->tail_buf, 0xff, -+ chip->page_size + oob_upper_size()); -+ for (i = 0; i < rem; i++) { -+ prepare_op(nandx->ops[nandx->ops_current], -+ nandx->ops[nandx->ops_current - 1].row + 1, -+ 0, chip->page_size, nandx->tail_buf, -+ nandx->tail_buf + chip->page_size); -+ nandx->ops_current++; -+ } -+ } -+ -+ ret = chip_ops(nandx->chip, nandx->ops, nandx->ops_current); -+ -+error: -+ nandx->mode = NANDX_IDLE; -+ nandx->ops_current = 0; -+ -+ return ret; -+} -+ -+int nandx_ioctl(int cmd, void *arg) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ struct nand_chip *chip = nandx->chip; -+ int ret = 0; -+ -+ switch (cmd) { -+ case CORE_CTRL_NAND_INFO: -+ *(struct nandx_info *)arg = nandx->info; -+ break; -+ -+ case CHIP_CTRL_OPS_MULTI: -+ ret = chip->chip_ctrl(chip, cmd, arg); -+ if (!ret) -+ nandx->multi_en = *(bool *)arg; -+ break; -+ -+ case NFI_CTRL_ECC: -+ ret = chip->chip_ctrl(chip, cmd, arg); -+ if (!ret) -+ nandx->ecc_en = *(bool *)arg; -+ break; -+ -+ default: -+ ret = chip->chip_ctrl(chip, cmd, arg); -+ break; -+ } -+ -+ return ret; -+} -+ -+bool nandx_is_bad_block(u64 offset) -+{ -+ struct nandx_desc *nandx = g_nandx; -+ -+ prepare_op(nandx->ops[0], offset_to_row(offset), 0, -+ nandx->chip->page_size, nandx->head_buf, -+ nandx->head_buf + nandx->chip->page_size); -+ -+ return nandx->chip->is_bad_block(nandx->chip, nandx->ops, 1); -+} -+ -+int nandx_suspend(void) -+{ -+ return g_nandx->chip->suspend(g_nandx->chip); -+} -+ -+int nandx_resume(void) -+{ -+ return g_nandx->chip->resume(g_nandx->chip); -+} -+ -+int nandx_init(struct nfi_resource *res) -+{ -+ struct nand_chip *chip; -+ struct nandx_desc *nandx; -+ int ret = 0; -+ -+ if (!res) -+ return -EINVAL; -+ -+ chip = nand_chip_init(res); -+ if (!chip) { -+ pr_info("nand chip init fail.\n"); -+ return -EFAULT; -+ } -+ -+ nandx = (struct nandx_desc *)mem_alloc(1, sizeof(struct nandx_desc)); -+ if (!nandx) -+ return -ENOMEM; -+ -+ g_nandx = nandx; -+ -+ nandx->chip = chip; -+ nandx->min_write_pages = chip->min_program_pages; -+ nandx->ops_multi_len = nandx->min_write_pages * chip->plane_num; -+ nandx->ops_len = chip->block_pages * chip->plane_num; -+ nandx->ops = mem_alloc(1, sizeof(struct nand_ops) * nandx->ops_len); -+ if (!nandx->ops) { -+ ret = -ENOMEM; -+ goto ops_error; -+ } -+ -+#if NANDX_BULK_IO_USE_DRAM -+ nandx->head_buf = NANDX_CORE_BUF_ADDR; -+#else -+ nandx->head_buf = mem_alloc(2, page_padded_size()); -+#endif -+ if (!nandx->head_buf) { -+ ret = -ENOMEM; -+ goto buf_error; -+ } -+ nandx->tail_buf = nandx->head_buf + page_padded_size(); -+ memset(nandx->head_buf, 0xff, 2 * page_padded_size()); -+ nandx->multi_en = false; -+ nandx->ecc_en = false; -+ nandx->ops_current = 0; -+ nandx->mode = NANDX_IDLE; -+ -+ nandx->info.max_io_count = nandx->ops_len; -+ nandx->info.min_write_pages = nandx->min_write_pages; -+ nandx->info.plane_num = chip->plane_num; -+ nandx->info.oob_size = chip->oob_size; -+ nandx->info.page_parity_size = chip->sector_spare_size * page_sectors(); -+ nandx->info.page_size = chip->page_size; -+ nandx->info.block_size = chip->block_size; -+ nandx->info.total_size = chip->block_size * chip->block_num; -+ nandx->info.fdm_ecc_size = chip->fdm_ecc_size; -+ nandx->info.fdm_reg_size = chip->fdm_reg_size; -+ nandx->info.ecc_strength = chip->ecc_strength; -+ nandx->info.sector_size = chip->sector_size; -+ -+ return 0; -+ -+buf_error: -+#if !NANDX_BULK_IO_USE_DRAM -+ mem_free(nandx->head_buf); -+#endif -+ops_error: -+ mem_free(nandx); -+ -+ return ret; -+} -+ -+void nandx_exit(void) -+{ -+ nand_chip_exit(g_nandx->chip); -+#if !NANDX_BULK_IO_USE_DRAM -+ mem_free(g_nandx->head_buf); -+#endif -+ mem_free(g_nandx->ops); -+ mem_free(g_nandx); -+} -+ -+#ifdef NANDX_UNIT_TEST -+static void dump_buf(u8 *buf, u32 len) -+{ -+ u32 i; -+ -+ pr_info("dump buf@0x%X start", (u32)buf); -+ for (i = 0; i < len; i++) { -+ if (!reminder(i, 16)) -+ pr_info("\n0x"); -+ pr_info("%x ", buf[i]); -+ } -+ pr_info("\ndump buf done.\n"); -+} -+ -+int nandx_unit_test(u64 offset, size_t len) -+{ -+ u8 *src_buf, *dst_buf; -+ u32 i, j; -+ int ret; -+ -+ if (!len || len > g_nandx->chip->block_size) -+ return -EINVAL; -+ -+#if NANDX_BULK_IO_USE_DRAM -+ src_buf = NANDX_UT_SRC_ADDR; -+ dst_buf = NANDX_UT_DST_ADDR; -+ -+#else -+ src_buf = mem_alloc(1, g_nandx->chip->page_size); -+ if (!src_buf) -+ return -ENOMEM; -+ dst_buf = mem_alloc(1, g_nandx->chip->page_size); -+ if (!dst_buf) { -+ mem_free(src_buf); -+ return -ENOMEM; -+ } -+#endif -+ -+ pr_info("%s: src_buf address 0x%x, dst_buf address 0x%x\n", -+ __func__, (int)((unsigned long)src_buf), -+ (int)((unsigned long)dst_buf)); -+ -+ memset(dst_buf, 0, g_nandx->chip->page_size); -+ pr_info("read page 0 data...!\n"); -+ ret = nandx_read(dst_buf, NULL, 0, g_nandx->chip->page_size); -+ if (ret < 0) { -+ pr_info("read fail with ret %d\n", ret); -+ } else { -+ pr_info("read page success!\n"); -+ } -+ -+ for (i = 0; i < g_nandx->chip->page_size; i++) { -+ src_buf[i] = 0x5a; -+ } -+ -+ ret = nandx_erase(offset, g_nandx->chip->block_size); -+ if (ret < 0) { -+ pr_info("erase fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ for (j = 0; j < g_nandx->chip->block_pages; j++) { -+ memset(dst_buf, 0, g_nandx->chip->page_size); -+ pr_info("check data after erase...!\n"); -+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size); -+ if (ret < 0) { -+ pr_info("read fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ for (i = 0; i < g_nandx->chip->page_size; i++) { -+ if (dst_buf[i] != 0xff) { -+ pr_info("read after erase, check fail @%d\n", i); -+ pr_info("all data should be 0xff\n"); -+ ret = -ENANDERASE; -+ dump_buf(dst_buf, 128); -+ //goto error; -+ break; -+ } -+ } -+ -+ pr_info("write data...!\n"); -+ ret = nandx_write(src_buf, NULL, offset, g_nandx->chip->page_size); -+ if (ret < 0) { -+ pr_info("write fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ memset(dst_buf, 0, g_nandx->chip->page_size); -+ pr_info("read data...!\n"); -+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size); -+ if (ret < 0) { -+ pr_info("read fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ for (i = 0; i < g_nandx->chip->page_size; i++) { -+ if (dst_buf[i] != src_buf[i]) { -+ pr_info("read after write, check fail @%d\n", i); -+ pr_info("dst_buf should be same as src_buf\n"); -+ ret = -EIO; -+ dump_buf(src_buf + i, 128); -+ dump_buf(dst_buf + i, 128); -+ break; -+ } -+ } -+ -+ pr_err("%s %d %s@%d\n", __func__, __LINE__, ret?"Failed":"OK", j); -+ if (ret) -+ break; -+ -+ offset += g_nandx->chip->page_size; -+ } -+ -+ ret = nandx_erase(offset, g_nandx->chip->block_size); -+ if (ret < 0) { -+ pr_info("erase fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ memset(dst_buf, 0, g_nandx->chip->page_size); -+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size); -+ if (ret < 0) { -+ pr_info("read fail with ret %d\n", ret); -+ goto error; -+ } -+ -+ for (i = 0; i < g_nandx->chip->page_size; i++) { -+ if (dst_buf[i] != 0xff) { -+ pr_info("read after erase, check fail\n"); -+ pr_info("all data should be 0xff\n"); -+ ret = -ENANDERASE; -+ dump_buf(dst_buf, 128); -+ goto error; -+ } -+ } -+ -+ return 0; -+ -+error: -+#if !NANDX_BULK_IO_USE_DRAM -+ mem_free(src_buf); -+ mem_free(dst_buf); -+#endif -+ return ret; -+} -+#endif ---- /dev/null -+++ b/drivers/mtd/nandx/core/core_io.h -@@ -0,0 +1,39 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __CORE_IO_H__ -+#define __CORE_IO_H__ -+ -+typedef int (*func_chip_ops)(struct nand_chip *, struct nand_ops *, -+ int); -+ -+enum nandx_op_mode { -+ NANDX_IDLE, -+ NANDX_WRITE, -+ NANDX_READ, -+ NANDX_ERASE -+}; -+ -+struct nandx_desc { -+ struct nand_chip *chip; -+ struct nandx_info info; -+ enum nandx_op_mode mode; -+ -+ bool multi_en; -+ bool ecc_en; -+ -+ struct nand_ops *ops; -+ int ops_len; -+ int ops_multi_len; -+ int ops_current; -+ int min_write_pages; -+ -+ u8 *head_buf; -+ u8 *tail_buf; -+}; -+ -+#endif /* __CORE_IO_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand/device_spi.c -@@ -0,0 +1,200 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "../nand_device.h" -+#include "device_spi.h" -+ -+/* spi nand basic commands */ -+static struct nand_cmds spi_cmds = { -+ .reset = 0xff, -+ .read_id = 0x9f, -+ .read_status = 0x0f, -+ .read_param_page = 0x03, -+ .set_feature = 0x1f, -+ .get_feature = 0x0f, -+ .read_1st = 0x13, -+ .read_2nd = -1, -+ .random_out_1st = 0x03, -+ .random_out_2nd = -1, -+ .program_1st = 0x02, -+ .program_2nd = 0x10, -+ .erase_1st = 0xd8, -+ .erase_2nd = -1, -+ .read_cache = 0x30, -+ .read_cache_last = 0x3f, -+ .program_cache = 0x02 -+}; -+ -+/* spi nand extend commands */ -+static struct spi_extend_cmds spi_extend_cmds = { -+ .die_select = 0xc2, -+ .write_enable = 0x06 -+}; -+ -+/* means the start bit of addressing type */ -+static struct nand_addressing spi_addressing = { -+ .row_bit_start = 0, -+ .block_bit_start = 0, -+ .plane_bit_start = 12, -+ .lun_bit_start = 0, -+}; -+ -+/* spi nand endurance */ -+static struct nand_endurance spi_endurance = { -+ .pe_cycle = 100000, -+ .ecc_req = 1, -+ .max_bitflips = 1 -+}; -+ -+/* array_busy, write_protect, erase_fail, program_fail */ -+static struct nand_status spi_status[] = { -+ {.array_busy = BIT(0), -+ .write_protect = BIT(1), -+ .erase_fail = BIT(2), -+ .program_fail = BIT(3)} -+}; -+ -+/* measure time by the us */ -+static struct nand_array_timing spi_array_timing = { -+ .tRST = 500, -+ .tWHR = 1, -+ .tR = 25, -+ .tRCBSY = 25, -+ .tFEAT = 1, -+ .tPROG = 600, -+ .tPCBSY = 600, -+ .tBERS = 10000, -+ .tDBSY = 1 -+}; -+ -+/* spi nand device table */ -+static struct device_spi spi_nand[] = { -+ { -+ NAND_DEVICE("W25N01GV", -+ NAND_PACK_ID(0xef, 0xaa, 0x21, 0, 0, 0, 0, 0), -+ 3, 0, 3, 3, -+ 1, 1, 1, 1024, KB(128), KB(2), 64, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 0), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { -+ NAND_DEVICE("MX35LF1G", -+ NAND_PACK_ID(0xc2, 0x12, 0x21, 0, 0, 0, 0, 0), -+ 2, 0, 3, 3, -+ 1, 1, 1, 1024, KB(128), KB(2), 64, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 1), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { -+ NAND_DEVICE("MT29F4G01ABAFDWB", -+ NAND_PACK_ID(0x2c, 0x34, 0, 0, 0, 0, 0, 0), -+ 2, 0, 3, 3, -+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 1), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { -+ NAND_DEVICE("GD5F4GQ4UB", -+ NAND_PACK_ID(0xc8, 0xd4, 0, 0, 0, 0, 0, 0), -+ 2, 0, 3, 3, -+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 1), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { -+ NAND_DEVICE("TC58CVG2S0HRAIJ", -+ NAND_PACK_ID(0x98, 0xED, 0x51, 0, 0, 0, 0, 0), -+ 3, 0, 3, 3, -+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 1), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { -+ NAND_DEVICE("NO-DEVICE", -+ NAND_PACK_ID(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 0), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ } -+}; -+ -+u8 spi_replace_rx_cmds(u8 mode) -+{ -+ u8 rx_replace_cmds[] = {0x03, 0x3b, 0x6b, 0xbb, 0xeb}; -+ -+ return rx_replace_cmds[mode]; -+} -+ -+u8 spi_replace_tx_cmds(u8 mode) -+{ -+ u8 tx_replace_cmds[] = {0x02, 0x32}; -+ -+ return tx_replace_cmds[mode]; -+} -+ -+u8 spi_replace_rx_col_cycle(u8 mode) -+{ -+ u8 rx_replace_col_cycle[] = {3, 3, 3, 3, 4}; -+ -+ return rx_replace_col_cycle[mode]; -+} -+ -+u8 spi_replace_tx_col_cycle(u8 mode) -+{ -+ u8 tx_replace_col_cycle[] = {2, 2}; -+ -+ return tx_replace_col_cycle[mode]; -+} -+ -+struct nand_device *nand_get_device(int index) -+{ -+ return &spi_nand[index].dev; -+} -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand/device_spi.h -@@ -0,0 +1,132 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __DEVICE_SPI_H__ -+#define __DEVICE_SPI_H__ -+ -+/* -+ * extend commands -+ * @die_select: select nand device die command -+ * @write_enable: enable write command before write data to spi nand -+ * spi nand device will auto to be disable after write done -+ */ -+struct spi_extend_cmds { -+ short die_select; -+ short write_enable; -+}; -+ -+/* -+ * protection feature register -+ * @addr: register address -+ * @wp_en_bit: write protection enable bit -+ * @bp_start_bit: block protection mask start bit -+ * @bp_end_bit: block protection mask end bit -+ */ -+struct feature_protect { -+ u8 addr; -+ u8 wp_en_bit; -+ u8 bp_start_bit; -+ u8 bp_end_bit; -+}; -+ -+/* -+ * configuration feature register -+ * @addr: register address -+ * @ecc_en_bit: in-die ecc enable bit -+ * @otp_en_bit: enter otp access mode bit -+ * @need_qe: quad io enable bit -+ */ -+struct feature_config { -+ u8 addr; -+ u8 ecc_en_bit; -+ u8 otp_en_bit; -+ u8 need_qe; -+}; -+ -+/* -+ * status feature register -+ * @addr: register address -+ * @ecc_start_bit: ecc status mask start bit for error bits number -+ * @ecc_end_bit: ecc status mask end bit for error bits number -+ * note that: -+ * operations status (ex. array busy status) could see on struct nand_status -+ */ -+struct feature_status { -+ u8 addr; -+ u8 ecc_start_bit; -+ u8 ecc_end_bit; -+}; -+ -+/* -+ * character feature register -+ * @addr: register address -+ * @die_sel_bit: die select bit -+ * @drive_start_bit: drive strength mask start bit -+ * @drive_end_bit: drive strength mask end bit -+ */ -+struct feature_character { -+ u8 addr; -+ u8 die_sel_bit; -+ u8 drive_start_bit; -+ u8 drive_end_bit; -+}; -+ -+/* -+ * spi features -+ * @protect: protection feature register -+ * @config: configuration feature register -+ * @status: status feature register -+ * @character: character feature register -+ */ -+struct spi_features { -+ struct feature_protect protect; -+ struct feature_config config; -+ struct feature_status status; -+ struct feature_character character; -+}; -+ -+/* -+ * device_spi -+ * configurations of spi nand device table -+ * @dev: base information of nand device -+ * @feature: feature information for spi nand -+ * @extend_cmds: extended the nand base commands -+ * @tx_mode_mask: tx mode mask for chip read -+ * @rx_mode_mask: rx mode mask for chip write -+ */ -+struct device_spi { -+ struct nand_device dev; -+ struct spi_features feature; -+ struct spi_extend_cmds *extend_cmds; -+ -+ u8 tx_mode_mask; -+ u8 rx_mode_mask; -+}; -+ -+#define NAND_SPI_PROTECT(addr, wp_en_bit, bp_start_bit, bp_end_bit) \ -+ {addr, wp_en_bit, bp_start_bit, bp_end_bit} -+ -+#define NAND_SPI_CONFIG(addr, ecc_en_bit, otp_en_bit, need_qe) \ -+ {addr, ecc_en_bit, otp_en_bit, need_qe} -+ -+#define NAND_SPI_STATUS(addr, ecc_start_bit, ecc_end_bit) \ -+ {addr, ecc_start_bit, ecc_end_bit} -+ -+#define NAND_SPI_CHARACTER(addr, die_sel_bit, drive_start_bit, drive_end_bit) \ -+ {addr, die_sel_bit, drive_start_bit, drive_end_bit} -+ -+static inline struct device_spi *device_to_spi(struct nand_device *dev) -+{ -+ return container_of(dev, struct device_spi, dev); -+} -+ -+u8 spi_replace_rx_cmds(u8 mode); -+u8 spi_replace_tx_cmds(u8 mode); -+u8 spi_replace_rx_col_cycle(u8 mode); -+u8 spi_replace_tx_col_cycle(u8 mode); -+ -+#endif /* __DEVICE_SPI_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand/nand_spi.c -@@ -0,0 +1,526 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "../nand_chip.h" -+#include "../nand_device.h" -+#include "../nfi.h" -+#include "../nand_base.h" -+#include "device_spi.h" -+#include "nand_spi.h" -+ -+#define READY_TIMEOUT 500000 /* us */ -+ -+static int nand_spi_read_status(struct nand_base *nand) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ u8 status; -+ -+ nand->get_feature(nand, dev->feature.status.addr, &status, 1); -+ -+ return status; -+} -+ -+static int nand_spi_wait_ready(struct nand_base *nand, u32 timeout) -+{ -+ u64 now, end; -+ int status; -+ -+ end = get_current_time_us() + timeout; -+ -+ do { -+ status = nand_spi_read_status(nand); -+ status &= nand->dev->status->array_busy; -+ now = get_current_time_us(); -+ -+ if (now > end) -+ break; -+ } while (status); -+ -+ return status ? -EBUSY : 0; -+} -+ -+static int nand_spi_set_op_mode(struct nand_base *nand, u8 mode) -+{ -+ struct nand_spi *spi_nand = base_to_spi(nand); -+ struct nfi *nfi = nand->nfi; -+ int ret = 0; -+ -+ if (spi_nand->op_mode != mode) { -+ ret = nfi->nfi_ctrl(nfi, SNFI_CTRL_OP_MODE, (void *)&mode); -+ spi_nand->op_mode = mode; -+ } -+ -+ return ret; -+} -+ -+static int nand_spi_set_config(struct nand_base *nand, u8 addr, u8 mask, -+ bool en) -+{ -+ u8 configs = 0; -+ -+ nand->get_feature(nand, addr, &configs, 1); -+ -+ if (en) -+ configs |= mask; -+ else -+ configs &= ~mask; -+ -+ nand->set_feature(nand, addr, &configs, 1); -+ -+ configs = 0; -+ nand->get_feature(nand, addr, &configs, 1); -+ -+ return (configs & mask) == en ? 0 : -EFAULT; -+} -+ -+static int nand_spi_die_select(struct nand_base *nand, int *row) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nfi *nfi = nand->nfi; -+ int lun_blocks, block_pages, lun, blocks; -+ int page = *row, ret = 0; -+ u8 param = 0, die_sel; -+ -+ if (nand->dev->lun_num < 2) -+ return 0; -+ -+ block_pages = nand_block_pages(nand->dev); -+ lun_blocks = nand_lun_blocks(nand->dev); -+ blocks = div_down(page, block_pages); -+ lun = div_down(blocks, lun_blocks); -+ -+ if (dev->extend_cmds->die_select == -1) { -+ die_sel = (u8)(lun << dev->feature.character.die_sel_bit); -+ nand->get_feature(nand, dev->feature.character.addr, ¶m, 1); -+ param |= die_sel; -+ nand->set_feature(nand, dev->feature.character.addr, ¶m, 1); -+ param = 0; -+ nand->get_feature(nand, dev->feature.character.addr, ¶m, 1); -+ ret = (param & die_sel) ? 0 : -EFAULT; -+ } else { -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->extend_cmds->die_select); -+ nfi->send_addr(nfi, lun, 0, 1, 0); -+ nfi->trigger(nfi); -+ } -+ -+ *row = page - (lun_blocks * block_pages) * lun; -+ -+ return ret; -+} -+ -+static int nand_spi_select_device(struct nand_base *nand, int cs) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ return parent->select_device(nand, cs); -+} -+ -+static int nand_spi_reset(struct nand_base *nand) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ parent->reset(nand); -+ -+ return nand_spi_wait_ready(nand, READY_TIMEOUT); -+} -+ -+static int nand_spi_read_id(struct nand_base *nand, u8 *id, int count) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ return parent->read_id(nand, id, count); -+} -+ -+static int nand_spi_read_param_page(struct nand_base *nand, u8 *data, -+ int count) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nfi *nfi = nand->nfi; -+ int sectors, value; -+ u8 param = 0; -+ -+ sectors = div_round_up(count, nfi->sector_size); -+ -+ nand->get_feature(nand, dev->feature.config.addr, ¶m, 1); -+ param |= BIT(dev->feature.config.otp_en_bit); -+ nand->set_feature(nand, dev->feature.config.addr, ¶m, 1); -+ -+ param = 0; -+ nand->get_feature(nand, dev->feature.config.addr, ¶m, 1); -+ if (param & BIT(dev->feature.config.otp_en_bit)) { -+ value = 0; -+ nfi->nfi_ctrl(nfi, NFI_CTRL_ECC, &value); -+ nand->dev->col_cycle = spi_replace_rx_col_cycle(spi->rx_mode); -+ nand->read_page(nand, 0x01); -+ nand->read_data(nand, 0x01, 0, sectors, data, NULL); -+ } -+ -+ param &= ~BIT(dev->feature.config.otp_en_bit); -+ nand->set_feature(nand, dev->feature.config.addr, ¶m, 1); -+ -+ return 0; -+} -+ -+static int nand_spi_set_feature(struct nand_base *nand, u8 addr, -+ u8 *param, -+ int count) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand->write_enable(nand); -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ return parent->set_feature(nand, addr, param, count); -+} -+ -+static int nand_spi_get_feature(struct nand_base *nand, u8 addr, -+ u8 *param, -+ int count) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ return parent->get_feature(nand, addr, param, count); -+} -+ -+static int nand_spi_addressing(struct nand_base *nand, int *row, -+ int *col) -+{ -+ struct nand_device *dev = nand->dev; -+ int plane, block, block_pages; -+ int ret; -+ -+ ret = nand_spi_die_select(nand, row); -+ if (ret) -+ return ret; -+ -+ block_pages = nand_block_pages(dev); -+ block = div_down(*row, block_pages); -+ -+ plane = block % dev->plane_num; -+ *col |= (plane << dev->addressing->plane_bit_start); -+ -+ return 0; -+} -+ -+static int nand_spi_read_page(struct nand_base *nand, int row) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ if (spi->op_mode == SNFI_AUTO_MODE) -+ nand_spi_set_op_mode(nand, SNFI_AUTO_MODE); -+ else -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ parent->read_page(nand, row); -+ -+ return nand_spi_wait_ready(nand, READY_TIMEOUT); -+} -+ -+static int nand_spi_read_data(struct nand_base *nand, int row, int col, -+ int sectors, u8 *data, u8 *oob) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ int ret; -+ -+ if ((spi->rx_mode == SNFI_RX_114 || spi->rx_mode == SNFI_RX_144) && -+ dev->feature.config.need_qe) -+ nand_spi_set_config(nand, dev->feature.config.addr, -+ BIT(0), true); -+ -+ nand->dev->col_cycle = spi_replace_rx_col_cycle(spi->rx_mode); -+ -+ nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE); -+ -+ ret = parent->read_data(nand, row, col, sectors, data, oob); -+ if (ret) -+ return -ENANDREAD; -+ -+ if (spi->ondie_ecc) { -+ ret = nand_spi_read_status(nand); -+ ret &= GENMASK(dev->feature.status.ecc_end_bit, -+ dev->feature.status.ecc_start_bit); -+ ret >>= dev->feature.status.ecc_start_bit; -+ if (ret > nand->dev->endurance->ecc_req) -+ return -ENANDREAD; -+ else if (ret > nand->dev->endurance->max_bitflips) -+ return -ENANDFLIPS; -+ } -+ -+ return 0; -+} -+ -+static int nand_spi_write_enable(struct nand_base *nand) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nfi *nfi = nand->nfi; -+ int status; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->extend_cmds->write_enable); -+ -+ nfi->trigger(nfi); -+ -+ status = nand_spi_read_status(nand); -+ status &= nand->dev->status->write_protect; -+ -+ return !status; -+} -+ -+static int nand_spi_program_data(struct nand_base *nand, int row, -+ int col, -+ u8 *data, u8 *oob) -+{ -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nand_spi *spi = base_to_spi(nand); -+ -+ if (spi->tx_mode == SNFI_TX_114 && dev->feature.config.need_qe) -+ nand_spi_set_config(nand, dev->feature.config.addr, -+ BIT(0), true); -+ -+ nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE); -+ -+ nand->dev->col_cycle = spi_replace_tx_col_cycle(spi->tx_mode); -+ -+ return spi->parent->program_data(nand, row, col, data, oob); -+} -+ -+static int nand_spi_program_page(struct nand_base *nand, int row) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_device *dev = nand->dev; -+ struct nfi *nfi = nand->nfi; -+ -+ if (spi->op_mode == SNFI_AUTO_MODE) -+ nand_spi_set_op_mode(nand, SNFI_AUTO_MODE); -+ else -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->program_2nd); -+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle); -+ nfi->trigger(nfi); -+ -+ return nand_spi_wait_ready(nand, READY_TIMEOUT); -+} -+ -+static int nand_spi_erase_block(struct nand_base *nand, int row) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nand_base *parent = spi->parent; -+ -+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE); -+ -+ parent->erase_block(nand, row); -+ -+ return nand_spi_wait_ready(nand, READY_TIMEOUT); -+} -+ -+static int nand_chip_spi_ctrl(struct nand_chip *chip, int cmd, -+ void *args) -+{ -+ struct nand_base *nand = chip->nand; -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nand_spi *spi = base_to_spi(nand); -+ struct nfi *nfi = nand->nfi; -+ int ret = 0, value = *(int *)args; -+ -+ switch (cmd) { -+ case CHIP_CTRL_ONDIE_ECC: -+ spi->ondie_ecc = (bool)value; -+ ret = nand_spi_set_config(nand, dev->feature.config.addr, -+ BIT(dev->feature.config.ecc_en_bit), -+ spi->ondie_ecc); -+ break; -+ -+ case SNFI_CTRL_TX_MODE: -+ if (value < 0 || value > SNFI_TX_114) -+ return -EOPNOTSUPP; -+ -+ if (dev->tx_mode_mask & BIT(value)) { -+ spi->tx_mode = value; -+ nand->dev->cmds->random_out_1st = spi_replace_tx_cmds( -+ spi->tx_mode); -+ ret = nfi->nfi_ctrl(nfi, cmd, args); -+ } -+ -+ break; -+ -+ case SNFI_CTRL_RX_MODE: -+ if (value < 0 || value > SNFI_RX_144) -+ return -EOPNOTSUPP; -+ -+ if (dev->rx_mode_mask & BIT(value)) { -+ spi->rx_mode = value; -+ nand->dev->cmds->program_1st = spi_replace_rx_cmds( -+ spi->rx_mode); -+ ret = nfi->nfi_ctrl(nfi, cmd, args); -+ } -+ -+ break; -+ -+ case CHIP_CTRL_OPS_CACHE: -+ case CHIP_CTRL_OPS_MULTI: -+ case CHIP_CTRL_PSLC_MODE: -+ case CHIP_CTRL_DDR_MODE: -+ case CHIP_CTRL_DRIVE_STRENGTH: -+ case CHIP_CTRL_TIMING_MODE: -+ ret = -EOPNOTSUPP; -+ break; -+ -+ default: -+ ret = nfi->nfi_ctrl(nfi, cmd, args); -+ break; -+ } -+ -+ return ret; -+} -+ -+int nand_chip_spi_resume(struct nand_chip *chip) -+{ -+ struct nand_base *nand = chip->nand; -+ struct nand_spi *spi = base_to_spi(nand); -+ struct device_spi *dev = device_to_spi(nand->dev); -+ struct nfi *nfi = nand->nfi; -+ struct nfi_format format; -+ u8 mask; -+ -+ nand->reset(nand); -+ -+ mask = GENMASK(dev->feature.protect.bp_end_bit, -+ dev->feature.protect.bp_start_bit); -+ nand_spi_set_config(nand, dev->feature.config.addr, mask, false); -+ mask = BIT(dev->feature.config.ecc_en_bit); -+ nand_spi_set_config(nand, dev->feature.config.addr, mask, -+ spi->ondie_ecc); -+ -+ format.page_size = nand->dev->page_size; -+ format.spare_size = nand->dev->spare_size; -+ format.ecc_req = nand->dev->endurance->ecc_req; -+ -+ return nfi->set_format(nfi, &format); -+} -+ -+static int nand_spi_set_format(struct nand_base *nand) -+{ -+ struct nfi_format format = { -+ nand->dev->page_size, -+ nand->dev->spare_size, -+ nand->dev->endurance->ecc_req -+ }; -+ -+ return nand->nfi->set_format(nand->nfi, &format); -+} -+ -+struct nand_base *nand_device_init(struct nand_chip *chip) -+{ -+ struct nand_base *nand; -+ struct nand_spi *spi; -+ struct device_spi *dev; -+ int ret; -+ u8 mask; -+ -+ spi = mem_alloc(1, sizeof(struct nand_spi)); -+ if (!spi) { -+ pr_info("alloc nand_spi fail\n"); -+ return NULL; -+ } -+ -+ spi->ondie_ecc = false; -+ spi->op_mode = SNFI_CUSTOM_MODE; -+ spi->rx_mode = SNFI_RX_114; -+ spi->tx_mode = SNFI_TX_114; -+ -+ spi->parent = chip->nand; -+ nand = &spi->base; -+ nand->dev = spi->parent->dev; -+ nand->nfi = spi->parent->nfi; -+ -+ nand->select_device = nand_spi_select_device; -+ nand->reset = nand_spi_reset; -+ nand->read_id = nand_spi_read_id; -+ nand->read_param_page = nand_spi_read_param_page; -+ nand->set_feature = nand_spi_set_feature; -+ nand->get_feature = nand_spi_get_feature; -+ nand->read_status = nand_spi_read_status; -+ nand->addressing = nand_spi_addressing; -+ nand->read_page = nand_spi_read_page; -+ nand->read_data = nand_spi_read_data; -+ nand->write_enable = nand_spi_write_enable; -+ nand->program_data = nand_spi_program_data; -+ nand->program_page = nand_spi_program_page; -+ nand->erase_block = nand_spi_erase_block; -+ -+ chip->chip_ctrl = nand_chip_spi_ctrl; -+ chip->nand_type = NAND_SPI; -+ chip->resume = nand_chip_spi_resume; -+ -+ ret = nand_detect_device(nand); -+ if (ret) -+ goto err; -+ -+ nand->select_device(nand, 0); -+ -+ ret = nand_spi_set_format(nand); -+ if (ret) -+ goto err; -+ -+ dev = (struct device_spi *)nand->dev; -+ -+ nand->dev->cmds->random_out_1st = -+ spi_replace_rx_cmds(spi->rx_mode); -+ nand->dev->cmds->program_1st = -+ spi_replace_tx_cmds(spi->tx_mode); -+ -+ mask = GENMASK(dev->feature.protect.bp_end_bit, -+ dev->feature.protect.bp_start_bit); -+ ret = nand_spi_set_config(nand, dev->feature.protect.addr, mask, false); -+ if (ret) -+ goto err; -+ -+ mask = BIT(dev->feature.config.ecc_en_bit); -+ ret = nand_spi_set_config(nand, dev->feature.config.addr, mask, -+ spi->ondie_ecc); -+ if (ret) -+ goto err; -+ -+ return nand; -+ -+err: -+ mem_free(spi); -+ return NULL; -+} -+ -+void nand_exit(struct nand_base *nand) -+{ -+ struct nand_spi *spi = base_to_spi(nand); -+ -+ nand_base_exit(spi->parent); -+ mem_free(spi); -+} ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand/nand_spi.h -@@ -0,0 +1,35 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NAND_SPI_H__ -+#define __NAND_SPI_H__ -+ -+/* -+ * spi nand handler -+ * @base: spi nand base functions -+ * @parent: common parent nand base functions -+ * @tx_mode: spi bus width of transfer to device -+ * @rx_mode: spi bus width of transfer from device -+ * @op_mode: spi nand controller (NFI) operation mode -+ * @ondie_ecc: spi nand on-die ecc flag -+ */ -+ -+struct nand_spi { -+ struct nand_base base; -+ struct nand_base *parent; -+ u8 tx_mode; -+ u8 rx_mode; -+ u8 op_mode; -+ bool ondie_ecc; -+}; -+ -+static inline struct nand_spi *base_to_spi(struct nand_base *base) -+{ -+ return container_of(base, struct nand_spi, base); -+} -+ -+#endif /* __NAND_SPI_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_base.c -@@ -0,0 +1,304 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "nand_chip.h" -+#include "nand_device.h" -+#include "nfi.h" -+#include "nand_base.h" -+ -+static int nand_base_select_device(struct nand_base *nand, int cs) -+{ -+ struct nfi *nfi = nand->nfi; -+ -+ nfi->reset(nfi); -+ -+ return nfi->select_chip(nfi, cs); -+} -+ -+static int nand_base_reset(struct nand_base *nand) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->reset); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRST); -+} -+ -+static int nand_base_read_id(struct nand_base *nand, u8 *id, int count) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_id); -+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR); -+ nfi->send_addr(nfi, 0, 0, 1, 0); -+ -+ return nfi->read_bytes(nfi, id, count); -+} -+ -+static int nand_base_read_param_page(struct nand_base *nand, u8 *data, -+ int count) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_param_page); -+ nfi->send_addr(nfi, 0, 0, 1, 0); -+ -+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR); -+ -+ return nfi->read_bytes(nfi, data, count); -+} -+ -+static int nand_base_set_feature(struct nand_base *nand, u8 addr, -+ u8 *param, -+ int count) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->set_feature); -+ nfi->send_addr(nfi, addr, 0, 1, 0); -+ -+ nfi->write_bytes(nfi, param, count); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tFEAT); -+} -+ -+static int nand_base_get_feature(struct nand_base *nand, u8 addr, -+ u8 *param, -+ int count) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->get_feature); -+ nfi->send_addr(nfi, addr, 0, 1, 0); -+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tFEAT); -+ -+ return nfi->read_bytes(nfi, param, count); -+} -+ -+static int nand_base_read_status(struct nand_base *nand) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ u8 status = 0; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_status); -+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR); -+ nfi->read_bytes(nfi, &status, 1); -+ -+ return status; -+} -+ -+static int nand_base_addressing(struct nand_base *nand, int *row, -+ int *col) -+{ -+ struct nand_device *dev = nand->dev; -+ int lun, plane, block, page, cs = 0; -+ int block_pages, target_blocks, wl = 0; -+ int icol = *col; -+ -+ if (dev->target_num > 1) { -+ block_pages = nand_block_pages(dev); -+ target_blocks = nand_target_blocks(dev); -+ cs = div_down(*row, block_pages * target_blocks); -+ *row -= cs * block_pages * target_blocks; -+ } -+ -+ nand->select_device(nand, cs); -+ -+ block_pages = nand_block_pages(dev); -+ block = div_down(*row, block_pages); -+ page = *row - block * block_pages; -+ plane = reminder(block, dev->plane_num); -+ lun = div_down(block, nand_lun_blocks(dev)); -+ -+ wl |= (page << dev->addressing->row_bit_start); -+ wl |= (block << dev->addressing->block_bit_start); -+ wl |= (plane << dev->addressing->plane_bit_start); -+ wl |= (lun << dev->addressing->lun_bit_start); -+ -+ *row = wl; -+ *col = icol; -+ -+ return 0; -+} -+ -+static int nand_base_read_page(struct nand_base *nand, int row) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_1st); -+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle); -+ nfi->send_cmd(nfi, dev->cmds->read_2nd); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR); -+} -+ -+static int nand_base_read_data(struct nand_base *nand, int row, int col, -+ int sectors, u8 *data, u8 *oob) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->random_out_1st); -+ nfi->send_addr(nfi, col, row, dev->col_cycle, dev->row_cycle); -+ nfi->send_cmd(nfi, dev->cmds->random_out_2nd); -+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRCBSY); -+ -+ return nfi->read_sectors(nfi, data, oob, sectors); -+} -+ -+static int nand_base_write_enable(struct nand_base *nand) -+{ -+ struct nand_device *dev = nand->dev; -+ int status; -+ -+ status = nand_base_read_status(nand); -+ if (status & dev->status->write_protect) -+ return 0; -+ -+ return -ENANDWP; -+} -+ -+static int nand_base_program_data(struct nand_base *nand, int row, -+ int col, -+ u8 *data, u8 *oob) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->program_1st); -+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle); -+ -+ return nfi->write_page(nfi, data, oob); -+} -+ -+static int nand_base_program_page(struct nand_base *nand, int row) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->program_2nd); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tPROG); -+} -+ -+static int nand_base_erase_block(struct nand_base *nand, int row) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->erase_1st); -+ nfi->send_addr(nfi, 0, row, 0, dev->row_cycle); -+ nfi->send_cmd(nfi, dev->cmds->erase_2nd); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tBERS); -+} -+ -+static int nand_base_read_cache(struct nand_base *nand, int row) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_1st); -+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle); -+ nfi->send_cmd(nfi, dev->cmds->read_cache); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tRCBSY); -+} -+ -+static int nand_base_read_last(struct nand_base *nand) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->read_cache_last); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tRCBSY); -+} -+ -+static int nand_base_program_cache(struct nand_base *nand) -+{ -+ struct nfi *nfi = nand->nfi; -+ struct nand_device *dev = nand->dev; -+ -+ nfi->reset(nfi); -+ nfi->send_cmd(nfi, dev->cmds->program_cache); -+ nfi->trigger(nfi); -+ -+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, -+ dev->array_timing->tPCBSY); -+} -+ -+struct nand_base *nand_base_init(struct nand_device *dev, -+ struct nfi *nfi) -+{ -+ struct nand_base *nand; -+ -+ nand = mem_alloc(1, sizeof(struct nand_base)); -+ if (!nand) -+ return NULL; -+ -+ nand->dev = dev; -+ nand->nfi = nfi; -+ nand->select_device = nand_base_select_device; -+ nand->reset = nand_base_reset; -+ nand->read_id = nand_base_read_id; -+ nand->read_param_page = nand_base_read_param_page; -+ nand->set_feature = nand_base_set_feature; -+ nand->get_feature = nand_base_get_feature; -+ nand->read_status = nand_base_read_status; -+ nand->addressing = nand_base_addressing; -+ nand->read_page = nand_base_read_page; -+ nand->read_data = nand_base_read_data; -+ nand->read_cache = nand_base_read_cache; -+ nand->read_last = nand_base_read_last; -+ nand->write_enable = nand_base_write_enable; -+ nand->program_data = nand_base_program_data; -+ nand->program_page = nand_base_program_page; -+ nand->program_cache = nand_base_program_cache; -+ nand->erase_block = nand_base_erase_block; -+ -+ return nand; -+} -+ -+void nand_base_exit(struct nand_base *base) -+{ -+ nfi_exit(base->nfi); -+ mem_free(base); -+} ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_base.h -@@ -0,0 +1,71 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NAND_BASE_H__ -+#define __NAND_BASE_H__ -+ -+/* -+ * nand base functions -+ * @dev: nand device infomations -+ * @nfi: nand host controller -+ * @select_device: select one nand device of multi nand on chip -+ * @reset: reset current nand device -+ * @read_id: read current nand id -+ * @read_param_page: read current nand parameters page -+ * @set_feature: configurate the nand device feature -+ * @get_feature: get the nand device feature -+ * @read_status: read nand device status -+ * @addressing: addressing the address to nand device physical address -+ * @read_page: read page data to device cache register -+ * @read_data: read data from device cache register by bus protocol -+ * @read_cache: nand cache read operation for data output -+ * @read_last: nand cache read operation for last page output -+ * @write_enable: enable program/erase for nand, especially spi nand -+ * @program_data: program data to nand device cache register -+ * @program_page: program page data from nand device cache register to array -+ * @program_cache: nand cache program operation for data input -+ * @erase_block: erase nand block operation -+ */ -+struct nand_base { -+ struct nand_device *dev; -+ struct nfi *nfi; -+ int (*select_device)(struct nand_base *nand, int cs); -+ int (*reset)(struct nand_base *nand); -+ int (*read_id)(struct nand_base *nand, u8 *id, int count); -+ int (*read_param_page)(struct nand_base *nand, u8 *data, int count); -+ int (*set_feature)(struct nand_base *nand, u8 addr, u8 *param, -+ int count); -+ int (*get_feature)(struct nand_base *nand, u8 addr, u8 *param, -+ int count); -+ int (*read_status)(struct nand_base *nand); -+ int (*addressing)(struct nand_base *nand, int *row, int *col); -+ -+ int (*read_page)(struct nand_base *nand, int row); -+ int (*read_data)(struct nand_base *nand, int row, int col, int sectors, -+ u8 *data, u8 *oob); -+ int (*read_cache)(struct nand_base *nand, int row); -+ int (*read_last)(struct nand_base *nand); -+ -+ int (*write_enable)(struct nand_base *nand); -+ int (*program_data)(struct nand_base *nand, int row, int col, u8 *data, -+ u8 *oob); -+ int (*program_page)(struct nand_base *nand, int row); -+ int (*program_cache)(struct nand_base *nand); -+ -+ int (*erase_block)(struct nand_base *nand, int row); -+}; -+ -+struct nand_base *nand_base_init(struct nand_device *device, -+ struct nfi *nfi); -+void nand_base_exit(struct nand_base *base); -+ -+struct nand_base *nand_device_init(struct nand_chip *nand); -+void nand_exit(struct nand_base *nand); -+ -+int nand_detect_device(struct nand_base *nand); -+ -+#endif /* __NAND_BASE_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_chip.c -@@ -0,0 +1,272 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "nand_chip.h" -+#include "nand_device.h" -+#include "nfi.h" -+#include "nand_base.h" -+ -+static int nand_chip_read_page(struct nand_chip *chip, -+ struct nand_ops *ops, -+ int count) -+{ -+ struct nand_base *nand = chip->nand; -+ struct nand_device *dev = nand->dev; -+ int i, ret = 0; -+ int row, col, sectors; -+ u8 *data, *oob; -+ -+ for (i = 0; i < count; i++) { -+ row = ops[i].row; -+ col = ops[i].col; -+ -+ nand->addressing(nand, &row, &col); -+ ops[i].status = nand->read_page(nand, row); -+ if (ops[i].status < 0) { -+ ret = ops[i].status; -+ continue; -+ } -+ -+ data = ops[i].data; -+ oob = ops[i].oob; -+ sectors = ops[i].len / chip->sector_size; -+ ops[i].status = nand->read_data(nand, row, col, -+ sectors, data, oob); -+ if (ops[i].status > 0) -+ ops[i].status = ops[i].status >= -+ dev->endurance->max_bitflips ? -+ -ENANDFLIPS : 0; -+ -+ ret = min_t(int, ret, ops[i].status); -+ } -+ -+ return ret; -+} -+ -+static int nand_chip_write_page(struct nand_chip *chip, -+ struct nand_ops *ops, -+ int count) -+{ -+ struct nand_base *nand = chip->nand; -+ struct nand_device *dev = nand->dev; -+ int i, ret = 0; -+ int row, col; -+ u8 *data, *oob; -+ -+ for (i = 0; i < count; i++) { -+ row = ops[i].row; -+ col = ops[i].col; -+ -+ nand->addressing(nand, &row, &col); -+ -+ ops[i].status = nand->write_enable(nand); -+ if (ops[i].status) { -+ pr_debug("Write Protect at %x!\n", row); -+ ops[i].status = -ENANDWP; -+ return -ENANDWP; -+ } -+ -+ data = ops[i].data; -+ oob = ops[i].oob; -+ ops[i].status = nand->program_data(nand, row, col, data, oob); -+ if (ops[i].status < 0) { -+ ret = ops[i].status; -+ continue; -+ } -+ -+ ops[i].status = nand->program_page(nand, row); -+ if (ops[i].status < 0) { -+ ret = ops[i].status; -+ continue; -+ } -+ -+ ops[i].status = nand->read_status(nand); -+ if (ops[i].status & dev->status->program_fail) -+ ops[i].status = -ENANDWRITE; -+ -+ ret = min_t(int, ret, ops[i].status); -+ } -+ -+ return ret; -+} -+ -+static int nand_chip_erase_block(struct nand_chip *chip, -+ struct nand_ops *ops, -+ int count) -+{ -+ struct nand_base *nand = chip->nand; -+ struct nand_device *dev = nand->dev; -+ int i, ret = 0; -+ int row, col; -+ -+ for (i = 0; i < count; i++) { -+ row = ops[i].row; -+ col = ops[i].col; -+ -+ nand->addressing(nand, &row, &col); -+ -+ ops[i].status = nand->write_enable(nand); -+ if (ops[i].status) { -+ pr_debug("Write Protect at %x!\n", row); -+ ops[i].status = -ENANDWP; -+ return -ENANDWP; -+ } -+ -+ ops[i].status = nand->erase_block(nand, row); -+ if (ops[i].status < 0) { -+ ret = ops[i].status; -+ continue; -+ } -+ -+ ops[i].status = nand->read_status(nand); -+ if (ops[i].status & dev->status->erase_fail) -+ ops[i].status = -ENANDERASE; -+ -+ ret = min_t(int, ret, ops[i].status); -+ } -+ -+ return ret; -+} -+ -+/* read first bad mark on spare */ -+static int nand_chip_is_bad_block(struct nand_chip *chip, -+ struct nand_ops *ops, -+ int count) -+{ -+ int i, ret, value; -+ int status = 0; -+ u8 *data, *tmp_buf; -+ -+ tmp_buf = mem_alloc(1, chip->page_size); -+ if (!tmp_buf) -+ return -ENOMEM; -+ -+ memset(tmp_buf, 0x00, chip->page_size); -+ -+ /* Disable ECC */ -+ value = 0; -+ ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value); -+ if (ret) -+ goto out; -+ -+ ret = chip->read_page(chip, ops, count); -+ if (ret) -+ goto out; -+ -+ for (i = 0; i < count; i++) { -+ data = ops[i].data; -+ -+ /* temp solution for mt7622, because of no bad mark swap */ -+ if (!memcmp(data, tmp_buf, chip->page_size)) { -+ ops[i].status = -ENANDBAD; -+ status = -ENANDBAD; -+ -+ } else { -+ ops[i].status = 0; -+ } -+ } -+ -+ /* Enable ECC */ -+ value = 1; -+ ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value); -+ if (ret) -+ goto out; -+ -+ mem_free(tmp_buf); -+ return status; -+ -+out: -+ mem_free(tmp_buf); -+ return ret; -+} -+ -+static int nand_chip_ctrl(struct nand_chip *chip, int cmd, void *args) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static int nand_chip_suspend(struct nand_chip *chip) -+{ -+ return 0; -+} -+ -+static int nand_chip_resume(struct nand_chip *chip) -+{ -+ return 0; -+} -+ -+struct nand_chip *nand_chip_init(struct nfi_resource *res) -+{ -+ struct nand_chip *chip; -+ struct nand_base *nand; -+ struct nfi *nfi; -+ -+ chip = mem_alloc(1, sizeof(struct nand_chip)); -+ if (!chip) { -+ pr_info("nand chip alloc fail!\n"); -+ return NULL; -+ } -+ -+ nfi = nfi_init(res); -+ if (!nfi) { -+ pr_info("nfi init fail!\n"); -+ goto nfi_err; -+ } -+ -+ nand = nand_base_init(NULL, nfi); -+ if (!nand) { -+ pr_info("nand base init fail!\n"); -+ goto base_err; -+ } -+ -+ chip->nand = (void *)nand; -+ chip->read_page = nand_chip_read_page; -+ chip->write_page = nand_chip_write_page; -+ chip->erase_block = nand_chip_erase_block; -+ chip->is_bad_block = nand_chip_is_bad_block; -+ chip->chip_ctrl = nand_chip_ctrl; -+ chip->suspend = nand_chip_suspend; -+ chip->resume = nand_chip_resume; -+ -+ nand = nand_device_init(chip); -+ if (!nand) -+ goto nand_err; -+ -+ chip->nand = (void *)nand; -+ chip->plane_num = nand->dev->plane_num; -+ chip->block_num = nand_total_blocks(nand->dev); -+ chip->block_size = nand->dev->block_size; -+ chip->block_pages = nand_block_pages(nand->dev); -+ chip->page_size = nand->dev->page_size; -+ chip->oob_size = nfi->fdm_size * div_down(chip->page_size, -+ nfi->sector_size); -+ chip->sector_size = nfi->sector_size; -+ chip->sector_spare_size = nfi->sector_spare_size; -+ chip->min_program_pages = nand->dev->min_program_pages; -+ chip->ecc_strength = nfi->ecc_strength; -+ chip->ecc_parity_size = nfi->ecc_parity_size; -+ chip->fdm_ecc_size = nfi->fdm_ecc_size; -+ chip->fdm_reg_size = nfi->fdm_size; -+ -+ return chip; -+ -+nand_err: -+ mem_free(nand); -+base_err: -+ nfi_exit(nfi); -+nfi_err: -+ mem_free(chip); -+ return NULL; -+} -+ -+void nand_chip_exit(struct nand_chip *chip) -+{ -+ nand_exit(chip->nand); -+ mem_free(chip); -+} ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_chip.h -@@ -0,0 +1,103 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NAND_CHIP_H__ -+#define __NAND_CHIP_H__ -+ -+enum nand_type { -+ NAND_SPI, -+ NAND_SLC, -+ NAND_MLC, -+ NAND_TLC -+}; -+ -+/* -+ * nand chip operation unit -+ * one nand_ops indicates one row operation -+ * @row: nand chip row address, like as nand row -+ * @col: nand chip column address, like as nand column -+ * @len: operate data length, min is sector_size, -+ * max is page_size and sector_size aligned -+ * @status: one operation result status -+ * @data: data buffer for operation -+ * @oob: oob buffer for operation, like as nand spare area -+ */ -+struct nand_ops { -+ int row; -+ int col; -+ int len; -+ int status; -+ void *data; -+ void *oob; -+}; -+ -+/* -+ * nand chip descriptions -+ * nand chip includes nand controller and the several same nand devices -+ * @nand_type: the nand type on this chip, -+ * the chip maybe have several nand device and the type must be same -+ * @plane_num: the whole plane number on the chip -+ * @block_num: the whole block number on the chip -+ * @block_size: nand device block size -+ * @block_pages: nand device block has page number -+ * @page_size: nand device page size -+ * @oob_size: chip out of band size, like as nand spare szie, -+ * but restricts this: -+ * the size is provied by nand controller(NFI), -+ * because NFI would use some nand spare size -+ * @min_program_pages: chip needs min pages per program operations -+ * one page as one nand_ops -+ * @sector_size: chip min read size -+ * @sector_spare_size: spare size for sector, is spare_size/page_sectors -+ * @ecc_strength: ecc stregth per sector_size, it would be for calculated ecc -+ * @ecc_parity_size: ecc parity size for one sector_size data -+ * @nand: pointer to inherited struct nand_base -+ * @read_page: read %count pages on chip -+ * @write_page: write %count pages on chip -+ * @erase_block: erase %count blocks on chip, one block is one nand_ops -+ * it is better to set nand_ops.row to block start row -+ * @is_bad_block: judge the %count blocks on chip if they are bad -+ * by vendor specification -+ * @chip_ctrl: control the chip features by nandx_ctrl_cmd -+ * @suspend: suspend nand chip -+ * @resume: resume nand chip -+ */ -+struct nand_chip { -+ int nand_type; -+ int plane_num; -+ int block_num; -+ int block_size; -+ int block_pages; -+ int page_size; -+ int oob_size; -+ -+ int min_program_pages; -+ int sector_size; -+ int sector_spare_size; -+ int ecc_strength; -+ int ecc_parity_size; -+ u32 fdm_ecc_size; -+ u32 fdm_reg_size; -+ -+ void *nand; -+ -+ int (*read_page)(struct nand_chip *chip, struct nand_ops *ops, -+ int count); -+ int (*write_page)(struct nand_chip *chip, struct nand_ops *ops, -+ int count); -+ int (*erase_block)(struct nand_chip *chip, struct nand_ops *ops, -+ int count); -+ int (*is_bad_block)(struct nand_chip *chip, struct nand_ops *ops, -+ int count); -+ int (*chip_ctrl)(struct nand_chip *chip, int cmd, void *args); -+ int (*suspend)(struct nand_chip *chip); -+ int (*resume)(struct nand_chip *chip); -+}; -+ -+struct nand_chip *nand_chip_init(struct nfi_resource *res); -+void nand_chip_exit(struct nand_chip *chip); -+#endif /* __NAND_CHIP_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_device.c -@@ -0,0 +1,285 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "nand_chip.h" -+#include "nand_device.h" -+#include "nand_base.h" -+ -+#define MAX_CHIP_DEVICE 4 -+#define PARAM_PAGE_LEN 2048 -+#define ONFI_CRC_BASE 0x4f4e -+ -+static u16 nand_onfi_crc16(u16 crc, u8 const *p, size_t len) -+{ -+ int i; -+ -+ while (len--) { -+ crc ^= *p++ << 8; -+ -+ for (i = 0; i < 8; i++) -+ crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); -+ } -+ -+ return crc; -+} -+ -+static inline void decode_addr_cycle(u8 addr_cycle, u8 *row_cycle, -+ u8 *col_cycle) -+{ -+ *row_cycle = addr_cycle & 0xf; -+ *col_cycle = (addr_cycle >> 4) & 0xf; -+} -+ -+static int detect_onfi(struct nand_device *dev, -+ struct nand_onfi_params *onfi) -+{ -+ struct nand_endurance *endurance = dev->endurance; -+ u16 size, i, crc16; -+ u8 *id; -+ -+ size = sizeof(struct nand_onfi_params) - sizeof(u16); -+ -+ for (i = 0; i < 3; i++) { -+ crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&onfi[i], size); -+ -+ if (onfi[i].signature[0] == 'O' && -+ onfi[i].signature[1] == 'N' && -+ onfi[i].signature[2] == 'F' && -+ onfi[i].signature[3] == 'I' && -+ onfi[i].crc16 == crc16) -+ break; -+ -+ /* in some spi nand, onfi signature maybe "NAND" */ -+ if (onfi[i].signature[0] == 'N' && -+ onfi[i].signature[1] == 'A' && -+ onfi[i].signature[2] == 'N' && -+ onfi[i].signature[3] == 'D' && -+ onfi[i].crc16 == crc16) -+ break; -+ } -+ -+ if (i == 3) -+ return -ENODEV; -+ -+ memcpy(dev->name, onfi[i].model, 20); -+ id = onfi[i].manufacturer; -+ dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6], -+ id[7]); -+ dev->id_len = MAX_ID_NUM; -+ dev->io_width = (onfi[i].features & 1) ? NAND_IO16 : NAND_IO8; -+ decode_addr_cycle(onfi[i].addr_cycle, &dev->row_cycle, -+ &dev->col_cycle); -+ dev->target_num = 1; -+ dev->lun_num = onfi[i].lun_num; -+ dev->plane_num = BIT(onfi[i].plane_address_bits); -+ dev->block_num = onfi[i].lun_blocks / dev->plane_num; -+ dev->block_size = onfi[i].block_pages * onfi[i].page_size; -+ dev->page_size = onfi[i].page_size; -+ dev->spare_size = onfi[i].spare_size; -+ -+ endurance->ecc_req = onfi[i].ecc_req; -+ endurance->pe_cycle = onfi[i].valid_block_endurance; -+ endurance->max_bitflips = endurance->ecc_req >> 1; -+ -+ return 0; -+} -+ -+static int detect_jedec(struct nand_device *dev, -+ struct nand_jedec_params *jedec) -+{ -+ struct nand_endurance *endurance = dev->endurance; -+ u16 size, i, crc16; -+ u8 *id; -+ -+ size = sizeof(struct nand_jedec_params) - sizeof(u16); -+ -+ for (i = 0; i < 3; i++) { -+ crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&jedec[i], size); -+ -+ if (jedec[i].signature[0] == 'J' && -+ jedec[i].signature[1] == 'E' && -+ jedec[i].signature[2] == 'S' && -+ jedec[i].signature[3] == 'D' && -+ jedec[i].crc16 == crc16) -+ break; -+ } -+ -+ if (i == 3) -+ return -ENODEV; -+ -+ memcpy(dev->name, jedec[i].model, 20); -+ id = jedec[i].manufacturer; -+ dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6], -+ id[7]); -+ dev->id_len = MAX_ID_NUM; -+ dev->io_width = (jedec[i].features & 1) ? NAND_IO16 : NAND_IO8; -+ decode_addr_cycle(jedec[i].addr_cycle, &dev->row_cycle, -+ &dev->col_cycle); -+ dev->target_num = 1; -+ dev->lun_num = jedec[i].lun_num; -+ dev->plane_num = BIT(jedec[i].plane_address_bits); -+ dev->block_num = jedec[i].lun_blocks / dev->plane_num; -+ dev->block_size = jedec[i].block_pages * jedec[i].page_size; -+ dev->page_size = jedec[i].page_size; -+ dev->spare_size = jedec[i].spare_size; -+ -+ endurance->ecc_req = jedec[i].endurance_block0[0]; -+ endurance->pe_cycle = jedec[i].valid_block_endurance; -+ endurance->max_bitflips = endurance->ecc_req >> 1; -+ -+ return 0; -+} -+ -+static struct nand_device *detect_parameters_page(struct nand_base -+ *nand) -+{ -+ struct nand_device *dev = nand->dev; -+ void *params; -+ int ret; -+ -+ params = mem_alloc(1, PARAM_PAGE_LEN); -+ if (!params) -+ return NULL; -+ -+ memset(params, 0, PARAM_PAGE_LEN); -+ ret = nand->read_param_page(nand, params, PARAM_PAGE_LEN); -+ if (ret < 0) { -+ pr_info("read parameters page fail!\n"); -+ goto error; -+ } -+ -+ ret = detect_onfi(dev, params); -+ if (ret) { -+ pr_info("detect onfi device fail! try to detect jedec\n"); -+ ret = detect_jedec(dev, params); -+ if (ret) { -+ pr_info("detect jedec device fail!\n"); -+ goto error; -+ } -+ } -+ -+ mem_free(params); -+ return dev; -+ -+error: -+ mem_free(params); -+ return NULL; -+} -+ -+static int read_device_id(struct nand_base *nand, int cs, u8 *id) -+{ -+ int i; -+ -+ nand->select_device(nand, cs); -+ nand->reset(nand); -+ nand->read_id(nand, id, MAX_ID_NUM); -+ pr_info("device %d ID: ", cs); -+ -+ for (i = 0; i < MAX_ID_NUM; i++) -+ pr_info("%x ", id[i]); -+ -+ pr_info("\n"); -+ -+ return 0; -+} -+ -+static int detect_more_device(struct nand_base *nand, u8 *id) -+{ -+ u8 id_ext[MAX_ID_NUM]; -+ int i, j, target_num = 0; -+ -+ for (i = 1; i < MAX_CHIP_DEVICE; i++) { -+ memset(id_ext, 0xff, MAX_ID_NUM); -+ read_device_id(nand, i, id_ext); -+ -+ for (j = 0; j < MAX_ID_NUM; j++) { -+ if (id_ext[j] != id[j]) -+ goto out; -+ } -+ -+ target_num += 1; -+ } -+ -+out: -+ return target_num; -+} -+ -+static struct nand_device *scan_device_table(const u8 *id, int id_len) -+{ -+ struct nand_device *dev; -+ int i = 0, j; -+ u8 ids[MAX_ID_NUM] = {0}; -+ -+ while (1) { -+ dev = nand_get_device(i); -+ -+ if (!strcmp(dev->name, "NO-DEVICE")) -+ break; -+ -+ if (id_len < dev->id_len) { -+ i += 1; -+ continue; -+ } -+ -+ NAND_UNPACK_ID(dev->id, ids, MAX_ID_NUM); -+ for (j = 0; j < dev->id_len; j++) { -+ if (ids[j] != id[j]) -+ break; -+ } -+ -+ if (j == dev->id_len) -+ break; -+ -+ i += 1; -+ } -+ -+ return dev; -+} -+ -+int nand_detect_device(struct nand_base *nand) -+{ -+ struct nand_device *dev; -+ u8 id[MAX_ID_NUM] = { 0 }; -+ int target_num = 0; -+ -+ /* Get nand device default setting for reset/read_id */ -+ nand->dev = scan_device_table(NULL, -1); -+ -+ read_device_id(nand, 0, id); -+ dev = scan_device_table(id, MAX_ID_NUM); -+ -+ if (!strcmp(dev->name, "NO-DEVICE")) { -+ pr_info("device scan fail\n"); -+ return -ENODEV; -+ } -+ -+ /* TobeFix: has null pointer issue in this funciton */ -+ if (!strcmp(dev->name, "NO-DEVICE")) { -+ pr_info("device scan fail, detect parameters page\n"); -+ dev = detect_parameters_page(nand); -+ if (!dev) { -+ pr_info("detect parameters fail\n"); -+ return -ENODEV; -+ } -+ } -+ -+ if (dev->target_num > 1) -+ target_num = detect_more_device(nand, id); -+ -+ target_num += 1; -+ pr_debug("chip has target device num: %d\n", target_num); -+ -+ if (dev->target_num != target_num) -+ dev->target_num = target_num; -+ -+ nand->dev = dev; -+ -+ return 0; -+} -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nand_device.h -@@ -0,0 +1,608 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NAND_DEVICE_H__ -+#define __NAND_DEVICE_H__ -+ -+/* onfi 3.2 */ -+struct nand_onfi_params { -+ /* Revision information and features block. 0 */ -+ /* -+ * Byte 0: 4Fh, -+ * Byte 1: 4Eh, -+ * Byte 2: 46h, -+ * Byte 3: 49h, -+ */ -+ u8 signature[4]; -+ /* -+ * 9-15 Reserved (0) -+ * 8 1 = supports ONFI version 3.2 -+ * 7 1 = supports ONFI version 3.1 -+ * 6 1 = supports ONFI version 3.0 -+ * 5 1 = supports ONFI version 2.3 -+ * 4 1 = supports ONFI version 2.2 -+ * 3 1 = supports ONFI version 2.1 -+ * 2 1 = supports ONFI version 2.0 -+ * 1 1 = supports ONFI version 1.0 -+ * 0 Reserved (0) -+ */ -+ u16 revision; -+ /* -+ * 13-15 Reserved (0) -+ * 12 1 = supports external Vpp -+ * 11 1 = supports Volume addressing -+ * 10 1 = supports NV-DDR2 -+ * 9 1 = supports EZ NAND -+ * 8 1 = supports program page register clear enhancement -+ * 7 1 = supports extended parameter page -+ * 6 1 = supports multi-plane read operations -+ * 5 1 = supports NV-DDR -+ * 4 1 = supports odd to even page Copyback -+ * 3 1 = supports multi-plane program and erase operations -+ * 2 1 = supports non-sequential page programming -+ * 1 1 = supports multiple LUN operations -+ * 0 1 = supports 16-bit data bus width -+ */ -+ u16 features; -+ /* -+ * 13-15 Reserved (0) -+ * 12 1 = supports LUN Get and LUN Set Features -+ * 11 1 = supports ODT Configure -+ * 10 1 = supports Volume Select -+ * 9 1 = supports Reset LUN -+ * 8 1 = supports Small Data Move -+ * 7 1 = supports Change Row Address -+ * 6 1 = supports Change Read Column Enhanced -+ * 5 1 = supports Read Unique ID -+ * 4 1 = supports Copyback -+ * 3 1 = supports Read Status Enhanced -+ * 2 1 = supports Get Features and Set Features -+ * 1 1 = supports Read Cache commands -+ * 0 1 = supports Page Cache Program command -+ */ -+ u16 opt_cmds; -+ /* -+ * 4-7 Reserved (0) -+ * 3 1 = supports Multi-plane Block Erase -+ * 2 1 = supports Multi-plane Copyback Program -+ * 1 1 = supports Multi-plane Page Program -+ * 0 1 = supports Random Data Out -+ */ -+ u8 advance_cmds; -+ u8 reserved0[1]; -+ u16 extend_param_len; -+ u8 param_page_num; -+ u8 reserved1[17]; -+ -+ /* Manufacturer information block. 32 */ -+ u8 manufacturer[12]; -+ u8 model[20]; -+ u8 jedec_id; -+ u16 data_code; -+ u8 reserved2[13]; -+ -+ /* Memory organization block. 80 */ -+ u32 page_size; -+ u16 spare_size; -+ u32 partial_page_size; /* obsolete */ -+ u16 partial_spare_size; /* obsolete */ -+ u32 block_pages; -+ u32 lun_blocks; -+ u8 lun_num; -+ /* -+ * 4-7 Column address cycles -+ * 0-3 Row address cycles -+ */ -+ u8 addr_cycle; -+ u8 cell_bits; -+ u16 lun_max_bad_blocks; -+ u16 block_endurance; -+ u8 target_begin_valid_blocks; -+ u16 valid_block_endurance; -+ u8 page_program_num; -+ u8 partial_program_attr; /* obsolete */ -+ u8 ecc_req; -+ /* -+ * 4-7 Reserved (0) -+ * 0-3 Number of plane address bits -+ */ -+ u8 plane_address_bits; -+ /* -+ * 6-7 Reserved (0) -+ * 5 1 = lower bit XNOR block address restriction -+ * 4 1 = read cache supported -+ * 3 Address restrictions for cache operations -+ * 2 1 = program cache supported -+ * 1 1 = no block address restrictions -+ * 0 Overlapped / concurrent multi-plane support -+ */ -+ u8 multi_plane_attr; -+ u8 ez_nand_support; -+ u8 reserved3[12]; -+ -+ /* Electrical parameters block. 128 */ -+ u8 io_pin_max_capacitance; -+ /* -+ * 6-15 Reserved (0) -+ * 5 1 = supports timing mode 5 -+ * 4 1 = supports timing mode 4 -+ * 3 1 = supports timing mode 3 -+ * 2 1 = supports timing mode 2 -+ * 1 1 = supports timing mode 1 -+ * 0 1 = supports timing mode 0, shall be 1 -+ */ -+ u16 sdr_timing_mode; -+ u16 sdr_program_cache_timing_mode; /* obsolete */ -+ u16 tPROG; -+ u16 tBERS; -+ u16 tR; -+ u16 tCCS; -+ /* -+ * 7 Reserved (0) -+ * 6 1 = supports NV-DDR2 timing mode 8 -+ * 5 1 = supports NV-DDR timing mode 5 -+ * 4 1 = supports NV-DDR timing mode 4 -+ * 3 1 = supports NV-DDR timing mode 3 -+ * 2 1 = supports NV-DDR timing mode 2 -+ * 1 1 = supports NV-DDR timing mode 1 -+ * 0 1 = supports NV-DDR timing mode 0 -+ */ -+ u8 nvddr_timing_mode; -+ /* -+ * 7 1 = supports timing mode 7 -+ * 6 1 = supports timing mode 6 -+ * 5 1 = supports timing mode 5 -+ * 4 1 = supports timing mode 4 -+ * 3 1 = supports timing mode 3 -+ * 2 1 = supports timing mode 2 -+ * 1 1 = supports timing mode 1 -+ * 0 1 = supports timing mode 0 -+ */ -+ u8 nvddr2_timing_mode; -+ /* -+ * 4-7 Reserved (0) -+ * 3 1 = device requires Vpp enablement sequence -+ * 2 1 = device supports CLK stopped for data input -+ * 1 1 = typical capacitance -+ * 0 tCAD value to use -+ */ -+ u8 nvddr_fetures; -+ u16 clk_pin_capacitance; -+ u16 io_pin_capacitance; -+ u16 input_pin_capacitance; -+ u8 input_pin_max_capacitance; -+ /* -+ * 3-7 Reserved (0) -+ * 2 1 = supports 18 Ohm drive strength -+ * 1 1 = supports 25 Ohm drive strength -+ * 0 1 = supports driver strength settings -+ */ -+ u8 drive_strength; -+ u16 tR_multi_plane; -+ u16 tADL; -+ u16 tR_ez_nand; -+ /* -+ * 6-7 Reserved (0) -+ * 5 1 = external VREFQ required for >= 200 MT/s -+ * 4 1 = supports differential signaling for DQS -+ * 3 1 = supports differential signaling for RE_n -+ * 2 1 = supports ODT value of 30 Ohms -+ * 1 1 = supports matrix termination ODT -+ * 0 1 = supports self-termination ODT -+ */ -+ u8 nvddr2_features; -+ u8 nvddr2_warmup_cycles; -+ u8 reserved4[4]; -+ -+ /* vendor block. 164 */ -+ u16 vendor_revision; -+ u8 vendor_spec[88]; -+ -+ /* CRC for Parameter Page. 254 */ -+ u16 crc16; -+} __packed; -+ -+/* JESD230-B */ -+struct nand_jedec_params { -+ /* Revision information and features block. 0 */ -+ /* -+ * Byte 0:4Ah -+ * Byte 1:45h -+ * Byte 2:53h -+ * Byte 3:44h -+ */ -+ u8 signature[4]; -+ /* -+ * 3-15: Reserved (0) -+ * 2: 1 = supports parameter page revision 1.0 and standard revision 1.0 -+ * 1: 1 = supports vendor specific parameter page -+ * 0: Reserved (0) -+ */ -+ u16 revision; -+ /* -+ * 9-15 Reserved (0) -+ * 8: 1 = supports program page register clear enhancement -+ * 7: 1 = supports external Vpp -+ * 6: 1 = supports Toggle Mode DDR -+ * 5: 1 = supports Synchronous DDR -+ * 4: 1 = supports multi-plane read operations -+ * 3: 1 = supports multi-plane program and erase operations -+ * 2: 1 = supports non-sequential page programming -+ * 1: 1 = supports multiple LUN operations -+ * 0: 1 = supports 16-bit data bus width -+ */ -+ u16 features; -+ /* -+ * 11-23: Reserved (0) -+ * 10: 1 = supports Synchronous Reset -+ * 9: 1 = supports Reset LUN (Primary) -+ * 8: 1 = supports Small Data Move -+ * 7: 1 = supports Multi-plane Copyback Program (Primary) -+ * 6: 1 = supports Random Data Out (Primary) -+ * 5: 1 = supports Read Unique ID -+ * 4: 1 = supports Copyback -+ * 3: 1 = supports Read Status Enhanced (Primary) -+ * 2: 1 = supports Get Features and Set Features -+ * 1: 1 = supports Read Cache commands -+ * 0: 1 = supports Page Cache Program command -+ */ -+ u8 opt_cmds[3]; -+ /* -+ * 8-15: Reserved (0) -+ * 7: 1 = supports secondary Read Status Enhanced -+ * 6: 1 = supports secondary Multi-plane Block Erase -+ * 5: 1 = supports secondary Multi-plane Copyback Program -+ * 4: 1 = supports secondary Multi-plane Program -+ * 3: 1 = supports secondary Random Data Out -+ * 2: 1 = supports secondary Multi-plane Copyback Read -+ * 1: 1 = supports secondary Multi-plane Read Cache Random -+ * 0: 1 = supports secondary Multi-plane Read -+ */ -+ u16 secondary_cmds; -+ u8 param_page_num; -+ u8 reserved0[18]; -+ -+ /* Manufacturer information block. 32*/ -+ u8 manufacturer[12]; -+ u8 model[20]; -+ u8 jedec_id[6]; -+ u8 reserved1[10]; -+ -+ /* Memory organization block. 80 */ -+ u32 page_size; -+ u16 spare_size; -+ u8 reserved2[6]; -+ u32 block_pages; -+ u32 lun_blocks; -+ u8 lun_num; -+ /* -+ * 4-7 Column address cycles -+ * 0-3 Row address cycles -+ */ -+ u8 addr_cycle; -+ u8 cell_bits; -+ u8 page_program_num; -+ /* -+ * 4-7 Reserved (0) -+ * 0-3 Number of plane address bits -+ */ -+ u8 plane_address_bits; -+ /* -+ * 3-7: Reserved (0) -+ * 2: 1= read cache supported -+ * 1: 1 = program cache supported -+ * 0: 1= No multi-plane block address restrictions -+ */ -+ u8 multi_plane_attr; -+ u8 reserved3[38]; -+ -+ /* Electrical parameters block. 144 */ -+ /* -+ * 6-15: Reserved (0) -+ * 5: 1 = supports 20 ns speed grade (50 MHz) -+ * 4: 1 = supports 25 ns speed grade (40 MHz) -+ * 3: 1 = supports 30 ns speed grade (~33 MHz) -+ * 2: 1 = supports 35 ns speed grade (~28 MHz) -+ * 1: 1 = supports 50 ns speed grade (20 MHz) -+ * 0: 1 = supports 100 ns speed grade (10 MHz) -+ */ -+ u16 sdr_speed; -+ /* -+ * 8-15: Reserved (0) -+ * 7: 1 = supports 5 ns speed grade (200 MHz) -+ * 6: 1 = supports 6 ns speed grade (~166 MHz) -+ * 5: 1 = supports 7.5 ns speed grade (~133 MHz) -+ * 4: 1 = supports 10 ns speed grade (100 MHz) -+ * 3: 1 = supports 12 ns speed grade (~83 MHz) -+ * 2: 1 = supports 15 ns speed grade (~66 MHz) -+ * 1: 1 = supports 25 ns speed grade (40 MHz) -+ * 0: 1 = supports 30 ns speed grade (~33 MHz) -+ */ -+ u16 toggle_ddr_speed; -+ /* -+ * 6-15: Reserved (0) -+ * 5: 1 = supports 10 ns speed grade (100 MHz) -+ * 4: 1 = supports 12 ns speed grade (~83 MHz) -+ * 3: 1 = supports 15 ns speed grade (~66 MHz) -+ * 2: 1 = supports 20 ns speed grade (50 MHz) -+ * 1: 1 = supports 30 ns speed grade (~33 MHz) -+ * 0: 1 = supports 50 ns speed grade (20 MHz) -+ */ -+ u16 sync_ddr_speed; -+ u8 sdr_features; -+ u8 toggle_ddr_features; -+ /* -+ * 2-7: Reserved (0) -+ * 1: Device supports CK stopped for data input -+ * 0: tCAD value to use -+ */ -+ u8 sync_ddr_features; -+ u16 tPROG; -+ u16 tBERS; -+ u16 tR; -+ u16 tR_multi_plane; -+ u16 tCCS; -+ u16 io_pin_capacitance; -+ u16 input_pin_capacitance; -+ u16 ck_pin_capacitance; -+ /* -+ * 3-7: Reserved (0) -+ * 2: 1 = supports 18 ohm drive strength -+ * 1: 1 = supports 25 ohm drive strength -+ * 0: 1 = supports 35ohm/50ohm drive strength -+ */ -+ u8 drive_strength; -+ u16 tADL; -+ u8 reserved4[36]; -+ -+ /* ECC and endurance block. 208 */ -+ u8 target_begin_valid_blocks; -+ u16 valid_block_endurance; -+ /* -+ * Byte 0: Number of bits ECC correctability -+ * Byte 1: Codeword size -+ * Byte 2-3: Bad blocks maximum per LUN -+ * Byte 4-5: Block endurance -+ * Byte 6-7: Reserved (0) -+ */ -+ u8 endurance_block0[8]; -+ u8 endurance_block1[8]; -+ u8 endurance_block2[8]; -+ u8 endurance_block3[8]; -+ u8 reserved5[29]; -+ -+ /* Reserved. 272 */ -+ u8 reserved6[148]; -+ -+ /* Vendor specific block. 420 */ -+ u16 vendor_revision; -+ u8 vendor_spec[88]; -+ -+ /* CRC for Parameter Page. 510 */ -+ u16 crc16; -+} __packed; -+ -+/* parallel nand io width */ -+enum nand_io_width { -+ NAND_IO8, -+ NAND_IO16 -+}; -+ -+/* all supported nand timming type */ -+enum nand_timing_type { -+ NAND_TIMING_SDR, -+ NAND_TIMING_SYNC_DDR, -+ NAND_TIMING_TOGGLE_DDR, -+ NAND_TIMING_NVDDR2 -+}; -+ -+/* nand basic commands */ -+struct nand_cmds { -+ short reset; -+ short read_id; -+ short read_status; -+ short read_param_page; -+ short set_feature; -+ short get_feature; -+ short read_1st; -+ short read_2nd; -+ short random_out_1st; -+ short random_out_2nd; -+ short program_1st; -+ short program_2nd; -+ short erase_1st; -+ short erase_2nd; -+ short read_cache; -+ short read_cache_last; -+ short program_cache; -+}; -+ -+/* -+ * addressing for nand physical address -+ * @row_bit_start: row address start bit -+ * @block_bit_start: block address start bit -+ * @plane_bit_start: plane address start bit -+ * @lun_bit_start: lun address start bit -+ */ -+struct nand_addressing { -+ u8 row_bit_start; -+ u8 block_bit_start; -+ u8 plane_bit_start; -+ u8 lun_bit_start; -+}; -+ -+/* -+ * nand operations status -+ * @array_busy: indicates device array operation busy -+ * @write_protect: indicates the device cannot be wrote or erased -+ * @erase_fail: indicates erase operation fail -+ * @program_fail: indicates program operation fail -+ */ -+struct nand_status { -+ u8 array_busy; -+ u8 write_protect; -+ u8 erase_fail; -+ u8 program_fail; -+}; -+ -+/* -+ * nand endurance information -+ * @pe_cycle: max program/erase cycle for nand stored data stability -+ * @ecc_req: ecc strength required for the nand, measured per 1KB -+ * @max_bitflips: bitflips is ecc corrected bits, -+ * max_bitflips is the threshold for nand stored data stability -+ * if corrected bits is over max_bitflips, stored data must be moved -+ * to another good block -+ */ -+struct nand_endurance { -+ int pe_cycle; -+ int ecc_req; -+ int max_bitflips; -+}; -+ -+/* wait for nand busy type */ -+enum nand_wait_type { -+ NAND_WAIT_IRQ, -+ NAND_WAIT_POLLING, -+ NAND_WAIT_TWHR2, -+}; -+ -+/* each nand array operations time */ -+struct nand_array_timing { -+ u16 tRST; -+ u16 tWHR; -+ u16 tR; -+ u16 tRCBSY; -+ u16 tFEAT; -+ u16 tPROG; -+ u16 tPCBSY; -+ u16 tBERS; -+ u16 tDBSY; -+}; -+ -+/* nand sdr interface timing required */ -+struct nand_sdr_timing { -+ u16 tREA; -+ u16 tREH; -+ u16 tCR; -+ u16 tRP; -+ u16 tWP; -+ u16 tWH; -+ u16 tWHR; -+ u16 tCLS; -+ u16 tALS; -+ u16 tCLH; -+ u16 tALH; -+ u16 tWC; -+ u16 tRC; -+}; -+ -+/* nand onfi ddr (nvddr) interface timing required */ -+struct nand_onfi_timing { -+ u16 tCAD; -+ u16 tWPRE; -+ u16 tWPST; -+ u16 tWRCK; -+ u16 tDQSCK; -+ u16 tWHR; -+}; -+ -+/* nand toggle ddr (toggle 1.0) interface timing required */ -+struct nand_toggle_timing { -+ u16 tCS; -+ u16 tCH; -+ u16 tCAS; -+ u16 tCAH; -+ u16 tCALS; -+ u16 tCALH; -+ u16 tWP; -+ u16 tWPRE; -+ u16 tWPST; -+ u16 tWPSTH; -+ u16 tCR; -+ u16 tRPRE; -+ u16 tRPST; -+ u16 tRPSTH; -+ u16 tCDQSS; -+ u16 tWHR; -+}; -+ -+/* nand basic device information */ -+struct nand_device { -+ u8 *name; -+ u64 id; -+ u8 id_len; -+ u8 io_width; -+ u8 row_cycle; -+ u8 col_cycle; -+ u8 target_num; -+ u8 lun_num; -+ u8 plane_num; -+ int block_num; -+ int block_size; -+ int page_size; -+ int spare_size; -+ int min_program_pages; -+ struct nand_cmds *cmds; -+ struct nand_addressing *addressing; -+ struct nand_status *status; -+ struct nand_endurance *endurance; -+ struct nand_array_timing *array_timing; -+}; -+ -+#define NAND_DEVICE(_name, _id, _id_len, _io_width, _row_cycle, \ -+ _col_cycle, _target_num, _lun_num, _plane_num, \ -+ _block_num, _block_size, _page_size, _spare_size, \ -+ _min_program_pages, _cmds, _addressing, _status, \ -+ _endurance, _array_timing) \ -+{ \ -+ _name, _id, _id_len, _io_width, _row_cycle, \ -+ _col_cycle, _target_num, _lun_num, _plane_num, \ -+ _block_num, _block_size, _page_size, _spare_size, \ -+ _min_program_pages, _cmds, _addressing, _status, \ -+ _endurance, _array_timing \ -+} -+ -+#define MAX_ID_NUM sizeof(u64) -+ -+#define NAND_PACK_ID(id0, id1, id2, id3, id4, id5, id6, id7) \ -+ ( \ -+ id0 | id1 << 8 | id2 << 16 | id3 << 24 | \ -+ (u64)id4 << 32 | (u64)id5 << 40 | \ -+ (u64)id6 << 48 | (u64)id7 << 56 \ -+ ) -+ -+#define NAND_UNPACK_ID(id, ids, len) \ -+ do { \ -+ int _i; \ -+ for (_i = 0; _i < len; _i++) \ -+ ids[_i] = id >> (_i << 3) & 0xff; \ -+ } while (0) -+ -+static inline int nand_block_pages(struct nand_device *device) -+{ -+ return div_down(device->block_size, device->page_size); -+} -+ -+static inline int nand_lun_blocks(struct nand_device *device) -+{ -+ return device->plane_num * device->block_num; -+} -+ -+static inline int nand_target_blocks(struct nand_device *device) -+{ -+ return device->lun_num * device->plane_num * device->block_num; -+} -+ -+static inline int nand_total_blocks(struct nand_device *device) -+{ -+ return device->target_num * device->lun_num * device->plane_num * -+ device->block_num; -+} -+ -+struct nand_device *nand_get_device(int index); -+#endif /* __NAND_DEVICE_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi.h -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFI_H__ -+#define __NFI_H__ -+ -+struct nfi_format { -+ int page_size; -+ int spare_size; -+ int ecc_req; -+}; -+ -+struct nfi { -+ int sector_size; -+ int sector_spare_size; -+ int fdm_size; /*for sector*/ -+ int fdm_ecc_size; -+ int ecc_strength; -+ int ecc_parity_size; /*for sector*/ -+ -+ int (*select_chip)(struct nfi *nfi, int cs); -+ int (*set_format)(struct nfi *nfi, struct nfi_format *format); -+ int (*set_timing)(struct nfi *nfi, void *timing, int type); -+ int (*nfi_ctrl)(struct nfi *nfi, int cmd, void *args); -+ -+ int (*reset)(struct nfi *nfi); -+ int (*send_cmd)(struct nfi *nfi, short cmd); -+ int (*send_addr)(struct nfi *nfi, int col, int row, -+ int col_cycle, int row_cycle); -+ int (*trigger)(struct nfi *nfi); -+ -+ int (*write_page)(struct nfi *nfi, u8 *data, u8 *fdm); -+ int (*write_bytes)(struct nfi *nfi, u8 *data, int count); -+ int (*read_sectors)(struct nfi *nfi, u8 *data, u8 *fdm, -+ int sectors); -+ int (*read_bytes)(struct nfi *nfi, u8 *data, int count); -+ -+ int (*wait_ready)(struct nfi *nfi, int type, u32 timeout); -+ -+ int (*enable_randomizer)(struct nfi *nfi, u32 row, bool encode); -+ int (*disable_randomizer)(struct nfi *nfi); -+}; -+ -+struct nfi *nfi_init(struct nfi_resource *res); -+void nfi_exit(struct nfi *nfi); -+ -+#endif /* __NFI_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_base.c -@@ -0,0 +1,1357 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+/** -+ * nfi_base.c - the base logic for nfi to access nand flash -+ * -+ * slc/mlc/tlc could use same code to access nand -+ * of cause, there still some work need to do -+ * even for spi nand, there should be a chance to integrate code together -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "../nfi.h" -+#include "../nand_device.h" -+#include "nfi_regs.h" -+#include "nfiecc.h" -+#include "nfi_base.h" -+ -+static const int spare_size_mt7622[] = { -+ 16, 26, 27, 28 -+}; -+ -+#define RAND_SEED_SHIFT(op) \ -+ ((op) == RAND_ENCODE ? ENCODE_SEED_SHIFT : DECODE_SEED_SHIFT) -+#define RAND_EN(op) \ -+ ((op) == RAND_ENCODE ? RAN_ENCODE_EN : RAN_DECODE_EN) -+ -+#define SS_SEED_NUM 128 -+static u16 ss_randomizer_seed[SS_SEED_NUM] = { -+ 0x576A, 0x05E8, 0x629D, 0x45A3, 0x649C, 0x4BF0, 0x2342, 0x272E, -+ 0x7358, 0x4FF3, 0x73EC, 0x5F70, 0x7A60, 0x1AD8, 0x3472, 0x3612, -+ 0x224F, 0x0454, 0x030E, 0x70A5, 0x7809, 0x2521, 0x484F, 0x5A2D, -+ 0x492A, 0x043D, 0x7F61, 0x3969, 0x517A, 0x3B42, 0x769D, 0x0647, -+ 0x7E2A, 0x1383, 0x49D9, 0x07B8, 0x2578, 0x4EEC, 0x4423, 0x352F, -+ 0x5B22, 0x72B9, 0x367B, 0x24B6, 0x7E8E, 0x2318, 0x6BD0, 0x5519, -+ 0x1783, 0x18A7, 0x7B6E, 0x7602, 0x4B7F, 0x3648, 0x2C53, 0x6B99, -+ 0x0C23, 0x67CF, 0x7E0E, 0x4D8C, 0x5079, 0x209D, 0x244A, 0x747B, -+ 0x350B, 0x0E4D, 0x7004, 0x6AC3, 0x7F3E, 0x21F5, 0x7A15, 0x2379, -+ 0x1517, 0x1ABA, 0x4E77, 0x15A1, 0x04FA, 0x2D61, 0x253A, 0x1302, -+ 0x1F63, 0x5AB3, 0x049A, 0x5AE8, 0x1CD7, 0x4A00, 0x30C8, 0x3247, -+ 0x729C, 0x5034, 0x2B0E, 0x57F2, 0x00E4, 0x575B, 0x6192, 0x38F8, -+ 0x2F6A, 0x0C14, 0x45FC, 0x41DF, 0x38DA, 0x7AE1, 0x7322, 0x62DF, -+ 0x5E39, 0x0E64, 0x6D85, 0x5951, 0x5937, 0x6281, 0x33A1, 0x6A32, -+ 0x3A5A, 0x2BAC, 0x743A, 0x5E74, 0x3B2E, 0x7EC7, 0x4FD2, 0x5D28, -+ 0x751F, 0x3EF8, 0x39B1, 0x4E49, 0x746B, 0x6EF6, 0x44BE, 0x6DB7 -+}; -+ -+#if 0 -+static void dump_register(void *regs) -+{ -+ int i; -+ -+ pr_info("registers:\n"); -+ for (i = 0; i < 0x600; i += 0x10) { -+ pr_info(" address 0x%X : %X %X %X %X\n", -+ (u32)((unsigned long)regs + i), -+ (u32)readl(regs + i), -+ (u32)readl(regs + i + 0x4), -+ (u32)readl(regs + i + 0x8), -+ (u32)readl(regs + i + 0xC)); -+ } -+} -+#endif -+ -+static int nfi_enable_randomizer(struct nfi *nfi, u32 row, bool encode) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ enum randomizer_op op = RAND_ENCODE; -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ if (!encode) -+ op = RAND_DECODE; -+ -+ /* randomizer type and reseed type setup */ -+ val = readl(regs + NFI_CNFG); -+ val |= CNFG_RAND_SEL | CNFG_RESEED_SEC_EN; -+ writel(val, regs + NFI_CNFG); -+ -+ /* randomizer seed and type setup */ -+ val = ss_randomizer_seed[row % SS_SEED_NUM] & RAN_SEED_MASK; -+ val <<= RAND_SEED_SHIFT(op); -+ val |= RAND_EN(op); -+ writel(val, regs + NFI_RANDOM_CNFG); -+ -+ return 0; -+} -+ -+static int nfi_disable_randomizer(struct nfi *nfi) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ -+ writel(0, nb->res.nfi_regs + NFI_RANDOM_CNFG); -+ -+ return 0; -+} -+ -+static int nfi_irq_handler(int irq, void *data) -+{ -+ struct nfi_base *nb = (struct nfi_base *) data; -+ void *regs = nb->res.nfi_regs; -+ u16 status, en; -+ -+ status = readw(regs + NFI_INTR_STA); -+ en = readw(regs + NFI_INTR_EN); -+ -+ if (!(status & en)) -+ return NAND_IRQ_NONE; -+ -+ writew(~status & en, regs + NFI_INTR_EN); -+ -+ nandx_event_complete(nb->done); -+ -+ return NAND_IRQ_HANDLED; -+} -+ -+static int nfi_select_chip(struct nfi *nfi, int cs) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ -+ writel(cs, nb->res.nfi_regs + NFI_CSEL); -+ -+ return 0; -+} -+ -+static inline void set_op_mode(void *regs, u32 mode) -+{ -+ u32 val = readl(regs + NFI_CNFG); -+ -+ val &= ~CNFG_OP_MODE_MASK; -+ val |= mode; -+ -+ writel(val, regs + NFI_CNFG); -+} -+ -+static int nfi_reset(struct nfi *nfi) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ int ret, val; -+ -+ /* The NFI reset to reset all registers and force the NFI -+ * master be early terminated -+ */ -+ writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON); -+ -+ /* check state of NFI internal FSM and NAND interface FSM */ -+ ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA, val, -+ !(val & MASTER_BUS_BUSY), -+ 10, NFI_TIMEOUT); -+ if (ret) -+ pr_info("nfi reset timeout...\n"); -+ -+ writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON); -+ writew(STAR_DE, regs + NFI_STRDATA); -+ -+ return ret; -+} -+ -+static void bad_mark_swap(struct nfi *nfi, u8 *buf, u8 *fdm) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ u32 start_sector = div_down(nb->col, nfi->sector_size); -+ u32 data_mark_pos; -+ u8 temp; -+ -+ /* raw access, no need to do swap. */ -+ if (!nb->ecc_en) -+ return; -+ -+ if (!buf || !fdm) -+ return; -+ -+ if (nb->bad_mark_ctrl.sector < start_sector || -+ nb->bad_mark_ctrl.sector > start_sector + nb->rw_sectors) -+ return; -+ -+ data_mark_pos = nb->bad_mark_ctrl.position + -+ (nb->bad_mark_ctrl.sector - start_sector) * -+ nfi->sector_size; -+ -+ temp = *fdm; -+ *fdm = *(buf + data_mark_pos); -+ *(buf + data_mark_pos) = temp; -+} -+ -+static u8 *fdm_shift(struct nfi *nfi, u8 *fdm, int sector) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ u8 *pos; -+ -+ if (!fdm) -+ return NULL; -+ -+ /* map the sector's FDM data to free oob: -+ * the beginning of the oob area stores the FDM data of bad mark sectors -+ */ -+ if (sector < nb->bad_mark_ctrl.sector) -+ pos = fdm + (sector + 1) * nfi->fdm_size; -+ else if (sector == nb->bad_mark_ctrl.sector) -+ pos = fdm; -+ else -+ pos = fdm + sector * nfi->fdm_size; -+ -+ return pos; -+ -+} -+ -+static void set_bad_mark_ctrl(struct nfi_base *nb) -+{ -+ int temp, page_size = nb->format.page_size; -+ -+ nb->bad_mark_ctrl.bad_mark_swap = bad_mark_swap; -+ nb->bad_mark_ctrl.fdm_shift = fdm_shift; -+ -+ temp = nb->nfi.sector_size + nb->nfi.sector_spare_size; -+ nb->bad_mark_ctrl.sector = div_down(page_size, temp); -+ nb->bad_mark_ctrl.position = reminder(page_size, temp); -+} -+ -+/* NOTE: check if page_size valid future */ -+static int setup_format(struct nfi_base *nb, int spare_idx) -+{ -+ struct nfi *nfi = &nb->nfi; -+ u32 page_size = nb->format.page_size; -+ u32 val; -+ -+ switch (page_size) { -+ case 512: -+ val = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512; -+ break; -+ -+ case KB(2): -+ if (nfi->sector_size == 512) -+ val = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512; -+ else -+ val = PAGEFMT_512_2K; -+ -+ break; -+ -+ case KB(4): -+ if (nfi->sector_size == 512) -+ val = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512; -+ else -+ val = PAGEFMT_2K_4K; -+ -+ break; -+ -+ case KB(8): -+ if (nfi->sector_size == 512) -+ val = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512; -+ else -+ val = PAGEFMT_4K_8K; -+ -+ break; -+ -+ case KB(16): -+ val = PAGEFMT_8K_16K; -+ break; -+ -+ default: -+ pr_info("invalid page len: %d\n", page_size); -+ return -EINVAL; -+ } -+ -+ val |= spare_idx << PAGEFMT_SPARE_SHIFT; -+ val |= nfi->fdm_size << PAGEFMT_FDM_SHIFT; -+ val |= nfi->fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT; -+ writel(val, nb->res.nfi_regs + NFI_PAGEFMT); -+ -+ if (nb->custom_sector_en) { -+ val = nfi->sector_spare_size + nfi->sector_size; -+ val |= SECCUS_SIZE_EN; -+ writel(val, nb->res.nfi_regs + NFI_SECCUS_SIZE); -+ } -+ -+ return 0; -+} -+ -+static int adjust_spare(struct nfi_base *nb, int *spare) -+{ -+ int multi = nb->nfi.sector_size == 512 ? 1 : 2; -+ int i, count = nb->caps->spare_size_num; -+ -+ if (*spare >= nb->caps->spare_size[count - 1] * multi) { -+ *spare = nb->caps->spare_size[count - 1] * multi; -+ return count - 1; -+ } -+ -+ if (*spare < nb->caps->spare_size[0] * multi) -+ return -EINVAL; -+ -+ for (i = 1; i < count; i++) { -+ if (*spare < nb->caps->spare_size[i] * multi) { -+ *spare = nb->caps->spare_size[i - 1] * multi; -+ return i - 1; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int nfi_set_format(struct nfi *nfi, struct nfi_format *format) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfiecc *ecc = nb->ecc; -+ int ecc_strength = format->ecc_req; -+ int min_fdm, min_ecc, max_ecc; -+ u32 temp, page_sectors; -+ int spare_idx = 0; -+ -+ if (!nb->buf) { -+#if NANDX_BULK_IO_USE_DRAM -+ nb->buf = NANDX_NFI_BUF_ADDR; -+#else -+ nb->buf = mem_alloc(1, format->page_size + format->spare_size); -+#endif -+ if (!nb->buf) -+ return -ENOMEM; -+ } -+ -+ nb->format = *format; -+ -+ /* ToBeFixed: for spi nand, now sector size is 512, -+ * it should be same with slc. -+ */ -+ nfi->sector_size = 512; -+ /* format->ecc_req is the requirement per 1KB */ -+ ecc_strength >>= 1; -+ -+ page_sectors = div_down(format->page_size, nfi->sector_size); -+ nfi->sector_spare_size = div_down(format->spare_size, page_sectors); -+ -+ if (!nb->custom_sector_en) { -+ spare_idx = adjust_spare(nb, &nfi->sector_spare_size); -+ if (spare_idx < 0) -+ return -EINVAL; -+ } -+ -+ /* calculate ecc strength and fdm size */ -+ temp = (nfi->sector_spare_size - nb->caps->max_fdm_size) * 8; -+ min_ecc = div_down(temp, nb->caps->ecc_parity_bits); -+ min_ecc = ecc->adjust_strength(ecc, min_ecc); -+ if (min_ecc < 0) -+ return -EINVAL; -+ -+ temp = div_up(nb->res.min_oob_req, page_sectors); -+ temp = (nfi->sector_spare_size - temp) * 8; -+ max_ecc = div_down(temp, nb->caps->ecc_parity_bits); -+ max_ecc = ecc->adjust_strength(ecc, max_ecc); -+ if (max_ecc < 0) -+ return -EINVAL; -+ -+ temp = div_up(temp * nb->caps->ecc_parity_bits, 8); -+ temp = nfi->sector_spare_size - temp; -+ min_fdm = min_t(u32, temp, (u32)nb->caps->max_fdm_size); -+ -+ if (ecc_strength > max_ecc) { -+ pr_info("required ecc strength %d, max supported %d\n", -+ ecc_strength, max_ecc); -+ nfi->ecc_strength = max_ecc; -+ nfi->fdm_size = min_fdm; -+ } else if (format->ecc_req < min_ecc) { -+ nfi->ecc_strength = min_ecc; -+ nfi->fdm_size = nb->caps->max_fdm_size; -+ } else { -+ ecc_strength = ecc->adjust_strength(ecc, ecc_strength); -+ if (ecc_strength < 0) -+ return -EINVAL; -+ -+ nfi->ecc_strength = ecc_strength; -+ temp = div_up(ecc_strength * nb->caps->ecc_parity_bits, 8); -+ nfi->fdm_size = nfi->sector_spare_size - temp; -+ } -+ -+ nb->page_sectors = div_down(format->page_size, nfi->sector_size); -+ -+ /* some IC has fixed fdm_ecc_size, if not assigend, set to fdm_size */ -+ nfi->fdm_ecc_size = nb->caps->fdm_ecc_size ? : nfi->fdm_size; -+ -+ nfi->ecc_parity_size = div_up(nfi->ecc_strength * -+ nb->caps->ecc_parity_bits, -+ 8); -+ set_bad_mark_ctrl(nb); -+ -+ pr_debug("sector_size: %d\n", nfi->sector_size); -+ pr_debug("sector_spare_size: %d\n", nfi->sector_spare_size); -+ pr_debug("fdm_size: %d\n", nfi->fdm_size); -+ pr_debug("fdm_ecc_size: %d\n", nfi->fdm_ecc_size); -+ pr_debug("ecc_strength: %d\n", nfi->ecc_strength); -+ pr_debug("ecc_parity_size: %d\n", nfi->ecc_parity_size); -+ -+ return setup_format(nb, spare_idx); -+} -+ -+static int nfi_ctrl(struct nfi *nfi, int cmd, void *args) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ int ret = 0; -+ -+ switch (cmd) { -+ case NFI_CTRL_DMA: -+ nb->dma_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_AUTOFORMAT: -+ nb->auto_format = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_NFI_IRQ: -+ nb->nfi_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_PAGE_IRQ: -+ nb->page_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_BAD_MARK_SWAP: -+ nb->bad_mark_swap_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC: -+ nb->ecc_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_MODE: -+ nb->ecc_mode = *(enum nfiecc_mode *)args; -+ break; -+ -+ case NFI_CTRL_ECC_CLOCK: -+ /* NOTE: it seems that there's nothing need to do -+ * if new IC need, just add tht logic -+ */ -+ nb->ecc_clk_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_IRQ: -+ nb->ecc_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_DECODE_MODE: -+ nb->ecc_deccon = *(enum nfiecc_deccon *)args; -+ break; -+ -+ default: -+ pr_info("invalid arguments.\n"); -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ pr_debug("%s: set cmd(%d) to %d\n", __func__, cmd, *(int *)args); -+ return ret; -+} -+ -+static int nfi_send_cmd(struct nfi *nfi, short cmd) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ u32 val; -+ -+ pr_debug("%s: cmd 0x%x\n", __func__, cmd); -+ -+ if (cmd < 0) -+ return -EINVAL; -+ -+ set_op_mode(regs, nb->op_mode); -+ -+ writel(cmd, regs + NFI_CMD); -+ -+ ret = readl_poll_timeout_atomic(regs + NFI_STA, -+ val, !(val & STA_CMD), -+ 5, NFI_TIMEOUT); -+ if (ret) -+ pr_info("send cmd 0x%x timeout\n", cmd); -+ -+ return ret; -+} -+ -+static int nfi_send_addr(struct nfi *nfi, int col, int row, -+ int col_cycle, int row_cycle) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ u32 val; -+ -+ pr_debug("%s: col 0x%x, row 0x%x, col_cycle 0x%x, row_cycle 0x%x\n", -+ __func__, col, row, col_cycle, row_cycle); -+ -+ nb->col = col; -+ nb->row = row; -+ -+ writel(col, regs + NFI_COLADDR); -+ writel(row, regs + NFI_ROWADDR); -+ writel(col_cycle | (row_cycle << ROW_SHIFT), regs + NFI_ADDRNOB); -+ -+ ret = readl_poll_timeout_atomic(regs + NFI_STA, -+ val, !(val & STA_ADDR), -+ 5, NFI_TIMEOUT); -+ if (ret) -+ pr_info("send address timeout\n"); -+ -+ return ret; -+} -+ -+static int nfi_trigger(struct nfi *nfi) -+{ -+ /* Nothing need to do. */ -+ return 0; -+} -+ -+static inline int wait_io_ready(void *regs) -+{ -+ u32 val; -+ int ret; -+ -+ ret = readl_poll_timeout_atomic(regs + NFI_PIO_DIRDY, -+ val, val & PIO_DI_RDY, -+ 2, NFI_TIMEOUT); -+ if (ret) -+ pr_info("wait io ready timeout\n"); -+ -+ return ret; -+} -+ -+static int wait_ready_irq(struct nfi_base *nb, u32 timeout) -+{ -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ u32 val; -+ -+ writel(0xf1, regs + NFI_CNRNB); -+ nandx_event_init(nb->done); -+ -+ writel(INTR_BUSY_RETURN_EN, (void *)(regs + NFI_INTR_EN)); -+ -+ /** -+ * check if nand already bean ready, -+ * avoid issue that casued by missing irq-event. -+ */ -+ val = readl(regs + NFI_STA); -+ if (val & STA_BUSY2READY) { -+ readl(regs + NFI_INTR_STA); -+ writel(0, (void *)(regs + NFI_INTR_EN)); -+ return 0; -+ } -+ -+ ret = nandx_event_wait_complete(nb->done, timeout); -+ -+ writew(0, regs + NFI_CNRNB); -+ return ret; -+} -+ -+static void wait_ready_twhr2(struct nfi_base *nb, u32 timeout) -+{ -+ /* NOTE: this for tlc */ -+} -+ -+static int wait_ready_poll(struct nfi_base *nb, u32 timeout) -+{ -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ u32 val; -+ -+ writel(0x21, regs + NFI_CNRNB); -+ ret = readl_poll_timeout_atomic(regs + NFI_STA, val, -+ val & STA_BUSY2READY, -+ 2, timeout); -+ writew(0, regs + NFI_CNRNB); -+ -+ return ret; -+} -+ -+static int nfi_wait_ready(struct nfi *nfi, int type, u32 timeout) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ int ret; -+ -+ switch (type) { -+ case NAND_WAIT_IRQ: -+ if (nb->nfi_irq_en) -+ ret = wait_ready_irq(nb, timeout); -+ else -+ ret = -EINVAL; -+ -+ break; -+ -+ case NAND_WAIT_POLLING: -+ ret = wait_ready_poll(nb, timeout); -+ break; -+ -+ case NAND_WAIT_TWHR2: -+ wait_ready_twhr2(nb, timeout); -+ ret = 0; -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (ret) -+ pr_info("%s: type 0x%x, timeout 0x%x\n", -+ __func__, type, timeout); -+ -+ return ret; -+} -+ -+static int enable_ecc_decode(struct nfi_base *nb, int sectors) -+{ -+ struct nfi *nfi = &nb->nfi; -+ struct nfiecc *ecc = nb->ecc; -+ -+ ecc->config.op = ECC_DECODE; -+ ecc->config.mode = nb->ecc_mode; -+ ecc->config.deccon = nb->ecc_deccon; -+ ecc->config.sectors = sectors; -+ ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size; -+ ecc->config.strength = nfi->ecc_strength; -+ -+ return ecc->enable(ecc); -+} -+ -+static int enable_ecc_encode(struct nfi_base *nb) -+{ -+ struct nfiecc *ecc = nb->ecc; -+ struct nfi *nfi = &nb->nfi; -+ -+ ecc->config.op = ECC_ENCODE; -+ ecc->config.mode = nb->ecc_mode; -+ ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size; -+ ecc->config.strength = nfi->ecc_strength; -+ -+ return ecc->enable(ecc); -+} -+ -+static void read_fdm(struct nfi_base *nb, u8 *fdm, int start_sector, -+ int sectors) -+{ -+ void *regs = nb->res.nfi_regs; -+ int j, i = start_sector; -+ u32 vall, valm; -+ u8 *buf = fdm; -+ -+ for (; i < start_sector + sectors; i++) { -+ if (nb->bad_mark_swap_en) -+ buf = nb->bad_mark_ctrl.fdm_shift(&nb->nfi, fdm, i); -+ -+ vall = readl(regs + NFI_FDML(i)); -+ valm = readl(regs + NFI_FDMM(i)); -+ -+ for (j = 0; j < nb->nfi.fdm_size; j++) -+ *buf++ = (j >= 4 ? valm : vall) >> ((j & 3) << 3); -+ } -+} -+ -+static void write_fdm(struct nfi_base *nb, u8 *fdm) -+{ -+ struct nfi *nfi = &nb->nfi; -+ void *regs = nb->res.nfi_regs; -+ u32 vall, valm; -+ int i, j; -+ u8 *buf = fdm; -+ -+ for (i = 0; i < nb->page_sectors; i++) { -+ if (nb->bad_mark_swap_en) -+ buf = nb->bad_mark_ctrl.fdm_shift(nfi, fdm, i); -+ -+ vall = 0; -+ for (j = 0; j < 4; j++) -+ vall |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8); -+ writel(vall, regs + NFI_FDML(i)); -+ -+ valm = 0; -+ for (j = 0; j < 4; j++) -+ valm |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8); -+ writel(valm, regs + NFI_FDMM(i)); -+ } -+} -+ -+/* NOTE: pio not use auto format */ -+static int pio_rx_data(struct nfi_base *nb, u8 *data, u8 *fdm, -+ int sectors) -+{ -+ struct nfiecc_status ecc_status; -+ struct nfi *nfi = &nb->nfi; -+ void *regs = nb->res.nfi_regs; -+ u32 val, bitflips = 0; -+ int len, ret, i; -+ u8 *buf; -+ -+ val = readl(regs + NFI_CNFG) | CNFG_BYTE_RW; -+ writel(val, regs + NFI_CNFG); -+ -+ len = nfi->sector_size + nfi->sector_spare_size; -+ len *= sectors; -+ -+ for (i = 0; i < len; i++) { -+ ret = wait_io_ready(regs); -+ if (ret) -+ return ret; -+ -+ nb->buf[i] = readb(regs + NFI_DATAR); -+ } -+ -+ /* TODO: do error handle for autoformat setting of pio */ -+ if (nb->ecc_en) { -+ for (i = 0; i < sectors; i++) { -+ buf = nb->buf + i * (nfi->sector_size + -+ nfi->sector_spare_size); -+ ret = nb->ecc->correct_data(nb->ecc, &ecc_status, -+ buf, i); -+ if (data) -+ memcpy(data + i * nfi->sector_size, -+ buf, nfi->sector_size); -+ if (fdm) -+ memcpy(fdm + i * nfi->fdm_size, -+ buf + nfi->sector_size, nfi->fdm_size); -+ if (ret) { -+ ret = nb->ecc->decode_status(nb->ecc, i, 1); -+ if (ret < 0) -+ return ret; -+ -+ bitflips = max_t(int, (int)bitflips, ret); -+ } -+ } -+ -+ return bitflips; -+ } -+ -+ /* raw read, only data not null, and its length should be $len */ -+ if (data) -+ memcpy(data, nb->buf, len); -+ -+ return 0; -+} -+ -+static int pio_tx_data(struct nfi_base *nb, u8 *data, u8 *fdm, -+ int sectors) -+{ -+ struct nfi *nfi = &nb->nfi; -+ void *regs = nb->res.nfi_regs; -+ u32 i, val; -+ int len, ret; -+ -+ val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW; -+ writew(val, regs + NFI_CNFG); -+ -+ len = nb->ecc_en ? nfi->sector_size : -+ nfi->sector_size + nfi->sector_spare_size; -+ len *= sectors; -+ -+ /* data shouldn't null, -+ * and if ecc enable ,fdm been written in prepare process -+ */ -+ for (i = 0; i < len; i++) { -+ ret = wait_io_ready(regs); -+ if (ret) -+ return ret; -+ writeb(data[i], regs + NFI_DATAW); -+ } -+ -+ return 0; -+} -+ -+static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm, -+ int sectors) -+{ -+ u32 empty = readl(nb->res.nfi_regs + NFI_STA) & STA_EMP_PAGE; -+ -+ if (empty) { -+ pr_info("empty page!\n"); -+ return true; -+ } -+ -+ return false; -+} -+ -+static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data, -+ u8 *fdm, bool read) -+{ -+ void *regs = nb->res.nfi_regs; -+ u32 len = nb->nfi.sector_size * sectors; -+ bool irq_en = nb->dma_en && nb->nfi_irq_en; -+ void *dma_addr; -+ u32 val; -+ int ret; -+ -+ nb->rw_sectors = sectors; -+ -+ if (irq_en) { -+ nandx_event_init(nb->done); -+ writel(INTR_AHB_DONE_EN, regs + NFI_INTR_EN); -+ } -+ -+ val = readw(regs + NFI_CNFG); -+ if (read) -+ val |= CNFG_READ_EN; -+ else -+ val &= ~CNFG_READ_EN; -+ -+ /* as design, now, auto format enabled when ecc enabled */ -+ if (nb->ecc_en) { -+ val |= CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN; -+ -+ if (read) -+ ret = enable_ecc_decode(nb, sectors); -+ else -+ ret = enable_ecc_encode(nb); -+ -+ if (ret) { -+ pr_info("%s: ecc enable %s fail!\n", __func__, -+ read ? "decode" : "encode"); -+ return ret; -+ } -+ } else { -+ val &= ~(CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN); -+ } -+ -+ if (!read && nb->bad_mark_swap_en) -+ nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm); -+ -+ if (!nb->ecc_en && read) -+ len += sectors * nb->nfi.sector_spare_size; -+ -+ if (nb->dma_en) { -+ val |= CNFG_DMA_BURST_EN | CNFG_AHB; -+ -+ if (read) { -+ dma_addr = (void *)(unsigned long)nandx_dma_map( -+ nb->res.dev, nb->buf, -+ (u64)len, NDMA_FROM_DEV); -+ } else { -+ memcpy(nb->buf, data, len); -+ dma_addr = (void *)(unsigned long)nandx_dma_map( -+ nb->res.dev, nb->buf, -+ (u64)len, NDMA_TO_DEV); -+ } -+ -+ writel((unsigned long)dma_addr, (void *)regs + NFI_STRADDR); -+ -+ nb->access_len = len; -+ nb->dma_addr = dma_addr; -+ } -+ -+ if (nb->ecc_en && !read && fdm) -+ write_fdm(nb, fdm); -+ -+ writew(val, regs + NFI_CNFG); -+ /* setup R/W sector number */ -+ writel(sectors << CON_SEC_SHIFT, regs + NFI_CON); -+ -+ return 0; -+} -+ -+static void rw_trigger(struct nfi_base *nb, bool read) -+{ -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ val = read ? CON_BRD : CON_BWR; -+ val |= readl(regs + NFI_CON); -+ writel(val, regs + NFI_CON); -+ -+ writel(STAR_EN, regs + NFI_STRDATA); -+} -+ -+static int rw_wait_done(struct nfi_base *nb, int sectors, bool read) -+{ -+ void *regs = nb->res.nfi_regs; -+ bool irq_en = nb->dma_en && nb->nfi_irq_en; -+ int ret; -+ u32 val; -+ -+ if (irq_en) { -+ ret = nandx_event_wait_complete(nb->done, NFI_TIMEOUT); -+ if (!ret) { -+ writew(0, regs + NFI_INTR_EN); -+ return ret; -+ } -+ } -+ -+ if (read) { -+ ret = readl_poll_timeout_atomic(regs + NFI_BYTELEN, val, -+ ADDRCNTR_SEC(val) >= -+ (u32)sectors, -+ 2, NFI_TIMEOUT); -+ /* HW issue: if not wait ahb done, need polling bus busy */ -+ if (!ret && !irq_en) -+ ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA, -+ val, -+ !(val & -+ MASTER_BUS_BUSY), -+ 2, NFI_TIMEOUT); -+ } else { -+ ret = readl_poll_timeout_atomic(regs + NFI_ADDRCNTR, val, -+ ADDRCNTR_SEC(val) >= -+ (u32)sectors, -+ 2, NFI_TIMEOUT); -+ } -+ -+ if (ret) { -+ pr_info("do page %s timeout\n", read ? "read" : "write"); -+ return ret; -+ } -+ -+ if (read && nb->ecc_en) { -+ ret = nb->ecc->wait_done(nb->ecc); -+ if (ret) -+ return ret; -+ -+ return nb->ecc->decode_status(nb->ecc, 0, sectors); -+ } -+ -+ return 0; -+} -+ -+static int rw_data(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors, -+ bool read) -+{ -+ if (read && nb->dma_en && nb->ecc_en && fdm) -+ read_fdm(nb, fdm, 0, sectors); -+ -+ if (!nb->dma_en) { -+ if (read) -+ return pio_rx_data(nb, data, fdm, sectors); -+ -+ return pio_tx_data(nb, data, fdm, sectors); -+ } -+ -+ return 0; -+} -+ -+static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm, -+ bool read) -+{ -+ int data_len = 0; -+ bool is_empty; -+ -+ if (nb->dma_en) { -+ if (read) { -+ nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr, -+ (u64)nb->access_len, NDMA_FROM_DEV); -+ -+ if (data) { -+ data_len = nb->rw_sectors * nb->nfi.sector_size; -+ memcpy(data, nb->buf, data_len); -+ } -+ -+ if (fdm) -+ memcpy(fdm, nb->buf + data_len, -+ nb->access_len - data_len); -+ -+ if (nb->read_status == -ENANDREAD) { -+ is_empty = nb->is_page_empty(nb, data, fdm, -+ nb->rw_sectors); -+ if (is_empty) -+ nb->read_status = 0; -+ } -+ } else { -+ nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr, -+ (u64)nb->access_len, NDMA_TO_DEV); -+ } -+ } -+ -+ /* whether it's reading or writing, we all check if nee swap -+ * for write, we need to restore data -+ */ -+ if (nb->bad_mark_swap_en) -+ nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm); -+ -+ if (nb->ecc_en) -+ nb->ecc->disable(nb->ecc); -+ -+ writel(0, nb->res.nfi_regs + NFI_CNFG); -+ writel(0, nb->res.nfi_regs + NFI_CON); -+} -+ -+static int nfi_read_sectors(struct nfi *nfi, u8 *data, u8 *fdm, -+ int sectors) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ int bitflips = 0, ret; -+ -+ pr_debug("%s: read page#%d\n", __func__, nb->row); -+ pr_debug("%s: data address 0x%x, fdm address 0x%x, sectors 0x%x\n", -+ __func__, (u32)((unsigned long)data), -+ (u32)((unsigned long)fdm), sectors); -+ -+ nb->read_status = 0; -+ -+ ret = nb->rw_prepare(nb, sectors, data, fdm, true); -+ if (ret) -+ return ret; -+ -+ nb->rw_trigger(nb, true); -+ -+ if (nb->dma_en) { -+ ret = nb->rw_wait_done(nb, sectors, true); -+ if (ret > 0) -+ bitflips = ret; -+ else if (ret == -ENANDREAD) -+ nb->read_status = -ENANDREAD; -+ else if (ret < 0) -+ goto complete; -+ -+ } -+ -+ ret = nb->rw_data(nb, data, fdm, sectors, true); -+ if (ret > 0) -+ ret = max_t(int, ret, bitflips); -+ -+complete: -+ nb->rw_complete(nb, data, fdm, true); -+ -+ if (nb->read_status == -ENANDREAD) -+ return -ENANDREAD; -+ -+ return ret; -+} -+ -+int nfi_write_page(struct nfi *nfi, u8 *data, u8 *fdm) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ u32 sectors = div_down(nb->format.page_size, nfi->sector_size); -+ int ret; -+ -+ pr_debug("%s: data address 0x%x, fdm address 0x%x\n", -+ __func__, (int)((unsigned long)data), -+ (int)((unsigned long)fdm)); -+ -+ ret = nb->rw_prepare(nb, sectors, data, fdm, false); -+ if (ret) -+ return ret; -+ -+ nb->rw_trigger(nb, false); -+ -+ ret = nb->rw_data(nb, data, fdm, sectors, false); -+ if (ret) -+ return ret; -+ -+ ret = nb->rw_wait_done(nb, sectors, false); -+ -+ nb->rw_complete(nb, data, fdm, false); -+ -+ return ret; -+} -+ -+static int nfi_rw_bytes(struct nfi *nfi, u8 *data, int count, bool read) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ int i, ret; -+ u32 val; -+ -+ for (i = 0; i < count; i++) { -+ val = readl(regs + NFI_STA) & NFI_FSM_MASK; -+ if (val != NFI_FSM_CUSTDATA) { -+ val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW; -+ if (read) -+ val |= CNFG_READ_EN; -+ writew(val, regs + NFI_CNFG); -+ -+ val = div_up(count, nfi->sector_size); -+ val = (val << CON_SEC_SHIFT) | CON_BRD | CON_BWR; -+ writel(val, regs + NFI_CON); -+ -+ writew(STAR_EN, regs + NFI_STRDATA); -+ } -+ -+ ret = wait_io_ready(regs); -+ if (ret) -+ return ret; -+ -+ if (read) -+ data[i] = readb(regs + NFI_DATAR); -+ else -+ writeb(data[i], regs + NFI_DATAW); -+ } -+ -+ writel(0, nb->res.nfi_regs + NFI_CNFG); -+ -+ return 0; -+} -+ -+static int nfi_read_bytes(struct nfi *nfi, u8 *data, int count) -+{ -+ return nfi_rw_bytes(nfi, data, count, true); -+} -+ -+static int nfi_write_bytes(struct nfi *nfi, u8 *data, int count) -+{ -+ return nfi_rw_bytes(nfi, data, count, false); -+} -+ -+/* As register map says, only when flash macro is idle, -+ * sw reset or nand interface change can be issued -+ */ -+static inline int wait_flash_macro_idle(void *regs) -+{ -+ u32 val; -+ -+ return readl_poll_timeout_atomic(regs + NFI_STA, val, -+ val & FLASH_MACRO_IDLE, 2, -+ NFI_TIMEOUT); -+} -+ -+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \ -+ ((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \ -+ (tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt)) -+ -+static int nfi_set_sdr_timing(struct nfi *nfi, void *timing, u8 type) -+{ -+ struct nand_sdr_timing *sdr = (struct nand_sdr_timing *) timing; -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ u32 tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt, tstrobe; -+ u32 rate, val; -+ int ret; -+ -+ ret = wait_flash_macro_idle(regs); -+ if (ret) -+ return ret; -+ -+ /* turn clock rate into KHZ */ -+ rate = nb->res.clock_1x / 1000; -+ -+ tpoecs = max_t(u16, sdr->tALH, sdr->tCLH); -+ tpoecs = div_up(tpoecs * rate, 1000000); -+ tpoecs &= 0xf; -+ -+ tprecs = max_t(u16, sdr->tCLS, sdr->tALS); -+ tprecs = div_up(tprecs * rate, 1000000); -+ tprecs &= 0x3f; -+ -+ /* tc2r is in unit of 2T */ -+ tc2r = div_up(sdr->tCR * rate, 1000000); -+ tc2r = div_down(tc2r, 2); -+ tc2r &= 0x3f; -+ -+ tw2r = div_up(sdr->tWHR * rate, 1000000); -+ tw2r = div_down(tw2r, 2); -+ tw2r &= 0xf; -+ -+ twh = max_t(u16, sdr->tREH, sdr->tWH); -+ twh = div_up(twh * rate, 1000000) - 1; -+ twh &= 0xf; -+ -+ twst = div_up(sdr->tWP * rate, 1000000) - 1; -+ twst &= 0xf; -+ -+ trlt = div_up(sdr->tRP * rate, 1000000) - 1; -+ trlt &= 0xf; -+ -+ /* If tREA is bigger than tRP, setup strobe sel here */ -+ if ((trlt + 1) * 1000000 / rate < sdr->tREA) { -+ tstrobe = sdr->tREA - (trlt + 1) * 1000000 / rate; -+ tstrobe = div_up(tstrobe * rate, 1000000); -+ val = readl(regs + NFI_DEBUG_CON1); -+ val &= ~STROBE_MASK; -+ val |= tstrobe << STROBE_SHIFT; -+ writel(val, regs + NFI_DEBUG_CON1); -+ } -+ -+ /* -+ * ACCON: access timing control register -+ * ------------------------------------- -+ * 31:28: tpoecs, minimum required time for CS post pulling down after -+ * accessing the device -+ * 27:22: tprecs, minimum required time for CS pre pulling down before -+ * accessing the device -+ * 21:16: tc2r, minimum required time from NCEB low to NREB low -+ * 15:12: tw2r, minimum required time from NWEB high to NREB low. -+ * 11:08: twh, write enable hold time -+ * 07:04: twst, write wait states -+ * 03:00: trlt, read wait states -+ */ -+ val = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt); -+ pr_info("acctiming: 0x%x\n", val); -+ writel(val, regs + NFI_ACCCON); -+ -+ /* set NAND type */ -+ writel(NAND_TYPE_ASYNC, regs + NFI_NAND_TYPE_CNFG); -+ -+ return ret; -+} -+ -+static int nfi_set_timing(struct nfi *nfi, void *timing, int type) -+{ -+ switch (type) { -+ case NAND_TIMING_SDR: -+ return nfi_set_sdr_timing(nfi, timing, type); -+ -+ /* NOTE: for mlc/tlc */ -+ case NAND_TIMING_SYNC_DDR: -+ case NAND_TIMING_TOGGLE_DDR: -+ case NAND_TIMING_NVDDR2: -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void set_nfi_funcs(struct nfi *nfi) -+{ -+ nfi->select_chip = nfi_select_chip; -+ nfi->set_format = nfi_set_format; -+ nfi->nfi_ctrl = nfi_ctrl; -+ nfi->set_timing = nfi_set_timing; -+ -+ nfi->reset = nfi_reset; -+ nfi->send_cmd = nfi_send_cmd; -+ nfi->send_addr = nfi_send_addr; -+ nfi->trigger = nfi_trigger; -+ -+ nfi->write_page = nfi_write_page; -+ nfi->write_bytes = nfi_write_bytes; -+ nfi->read_sectors = nfi_read_sectors; -+ nfi->read_bytes = nfi_read_bytes; -+ -+ nfi->wait_ready = nfi_wait_ready; -+ -+ nfi->enable_randomizer = nfi_enable_randomizer; -+ nfi->disable_randomizer = nfi_disable_randomizer; -+} -+ -+static struct nfi_caps nfi_caps_mt7622 = { -+ .max_fdm_size = 8, -+ .fdm_ecc_size = 1, -+ .ecc_parity_bits = 13, -+ .spare_size = spare_size_mt7622, -+ .spare_size_num = 4, -+}; -+ -+static struct nfi_caps *nfi_get_match_data(enum mtk_ic_version ic) -+{ -+ /* NOTE: add other IC's data */ -+ return &nfi_caps_mt7622; -+} -+ -+static void set_nfi_base_params(struct nfi_base *nb) -+{ -+ nb->ecc_en = false; -+ nb->dma_en = false; -+ nb->nfi_irq_en = false; -+ nb->ecc_irq_en = false; -+ nb->page_irq_en = false; -+ nb->ecc_clk_en = false; -+ nb->randomize_en = false; -+ nb->custom_sector_en = false; -+ nb->bad_mark_swap_en = false; -+ -+ nb->op_mode = CNFG_CUSTOM_MODE; -+ nb->ecc_deccon = ECC_DEC_CORRECT; -+ nb->ecc_mode = ECC_NFI_MODE; -+ -+ nb->done = nandx_event_create(); -+ nb->caps = nfi_get_match_data(nb->res.ic_ver); -+ -+ nb->set_op_mode = set_op_mode; -+ nb->is_page_empty = is_page_empty; -+ -+ nb->rw_prepare = rw_prepare; -+ nb->rw_trigger = rw_trigger; -+ nb->rw_wait_done = rw_wait_done; -+ nb->rw_data = rw_data; -+ nb->rw_complete = rw_complete; -+} -+ -+struct nfi *__weak nfi_extend_init(struct nfi_base *nb) -+{ -+ return &nb->nfi; -+} -+ -+void __weak nfi_extend_exit(struct nfi_base *nb) -+{ -+ mem_free(nb); -+} -+ -+struct nfi *nfi_init(struct nfi_resource *res) -+{ -+ struct nfiecc_resource ecc_res; -+ struct nfi_base *nb; -+ struct nfiecc *ecc; -+ struct nfi *nfi; -+ int ret; -+ -+ nb = mem_alloc(1, sizeof(struct nfi_base)); -+ if (!nb) { -+ pr_info("nfi alloc memory fail @%s.\n", __func__); -+ return NULL; -+ } -+ -+ nb->res = *res; -+ -+ ret = nandx_irq_register(res->dev, res->nfi_irq_id, nfi_irq_handler, -+ "mtk_nand", nb); -+ if (ret) { -+ pr_info("nfi irq register failed!\n"); -+ goto error; -+ } -+ -+ /* fill ecc paras and init ecc */ -+ ecc_res.ic_ver = nb->res.ic_ver; -+ ecc_res.dev = nb->res.dev; -+ ecc_res.irq_id = nb->res.ecc_irq_id; -+ ecc_res.regs = nb->res.ecc_regs; -+ ecc = nfiecc_init(&ecc_res); -+ if (!ecc) { -+ pr_info("nfiecc init fail.\n"); -+ return NULL; -+ } -+ -+ nb->ecc = ecc; -+ -+ set_nfi_base_params(nb); -+ set_nfi_funcs(&nb->nfi); -+ -+ /* Assign a temp sector size for reading ID & para page. -+ * We may assign new value later. -+ */ -+ nb->nfi.sector_size = 512; -+ -+ /* give a default timing, and as discuss -+ * this is the only thing what we need do for nfi init -+ * if need do more, then we can add a function -+ */ -+ writel(0x30C77FFF, nb->res.nfi_regs + NFI_ACCCON); -+ -+ nfi = nfi_extend_init(nb); -+ if (nfi) -+ return nfi; -+ -+error: -+ mem_free(nb); -+ return NULL; -+} -+ -+void nfi_exit(struct nfi *nfi) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ -+ nandx_event_destroy(nb->done); -+ nfiecc_exit(nb->ecc); -+#if !NANDX_BULK_IO_USE_DRAM -+ mem_free(nb->buf); -+#endif -+ nfi_extend_exit(nb); -+} -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_base.h -@@ -0,0 +1,95 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFI_BASE_H__ -+#define __NFI_BASE_H__ -+ -+#define NFI_TIMEOUT 1000000 -+ -+enum randomizer_op { -+ RAND_ENCODE, -+ RAND_DECODE -+}; -+ -+struct bad_mark_ctrl { -+ void (*bad_mark_swap)(struct nfi *nfi, u8 *buf, u8 *fdm); -+ u8 *(*fdm_shift)(struct nfi *nfi, u8 *fdm, int sector); -+ u32 sector; -+ u32 position; -+}; -+ -+struct nfi_caps { -+ u8 max_fdm_size; -+ u8 fdm_ecc_size; -+ u8 ecc_parity_bits; -+ const int *spare_size; -+ u32 spare_size_num; -+}; -+ -+struct nfi_base { -+ struct nfi nfi; -+ struct nfi_resource res; -+ struct nfiecc *ecc; -+ struct nfi_format format; -+ struct nfi_caps *caps; -+ struct bad_mark_ctrl bad_mark_ctrl; -+ -+ /* page_size + spare_size */ -+ u8 *buf; -+ -+ /* used for spi nand */ -+ u8 cmd_mode; -+ u32 op_mode; -+ -+ int page_sectors; -+ -+ void *done; -+ -+ /* for read/write */ -+ int col; -+ int row; -+ int access_len; -+ int rw_sectors; -+ void *dma_addr; -+ int read_status; -+ -+ bool dma_en; -+ bool nfi_irq_en; -+ bool page_irq_en; -+ bool auto_format; -+ bool ecc_en; -+ bool ecc_irq_en; -+ bool ecc_clk_en; -+ bool randomize_en; -+ bool custom_sector_en; -+ bool bad_mark_swap_en; -+ -+ enum nfiecc_deccon ecc_deccon; -+ enum nfiecc_mode ecc_mode; -+ -+ void (*set_op_mode)(void *regs, u32 mode); -+ bool (*is_page_empty)(struct nfi_base *nb, u8 *data, u8 *fdm, -+ int sectors); -+ -+ int (*rw_prepare)(struct nfi_base *nb, int sectors, u8 *data, u8 *fdm, -+ bool read); -+ void (*rw_trigger)(struct nfi_base *nb, bool read); -+ int (*rw_wait_done)(struct nfi_base *nb, int sectors, bool read); -+ int (*rw_data)(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors, -+ bool read); -+ void (*rw_complete)(struct nfi_base *nb, u8 *data, u8 *fdm, bool read); -+}; -+ -+static inline struct nfi_base *nfi_to_base(struct nfi *nfi) -+{ -+ return container_of(nfi, struct nfi_base, nfi); -+} -+ -+struct nfi *nfi_extend_init(struct nfi_base *nb); -+void nfi_extend_exit(struct nfi_base *nb); -+ -+#endif /* __NFI_BASE_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_regs.h -@@ -0,0 +1,114 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFI_REGS_H__ -+#define __NFI_REGS_H__ -+ -+#define NFI_CNFG 0x000 -+#define CNFG_AHB BIT(0) -+#define CNFG_READ_EN BIT(1) -+#define CNFG_DMA_BURST_EN BIT(2) -+#define CNFG_RESEED_SEC_EN BIT(4) -+#define CNFG_RAND_SEL BIT(5) -+#define CNFG_BYTE_RW BIT(6) -+#define CNFG_HW_ECC_EN BIT(8) -+#define CNFG_AUTO_FMT_EN BIT(9) -+#define CNFG_RAND_MASK GENMASK(5, 4) -+#define CNFG_OP_MODE_MASK GENMASK(14, 12) -+#define CNFG_IDLE_MOD 0 -+#define CNFG_READ_MODE (1 << 12) -+#define CNFG_SINGLE_READ_MODE (2 << 12) -+#define CNFG_PROGRAM_MODE (3 << 12) -+#define CNFG_ERASE_MODE (4 << 12) -+#define CNFG_RESET_MODE (5 << 12) -+#define CNFG_CUSTOM_MODE (6 << 12) -+#define NFI_PAGEFMT 0x004 -+#define PAGEFMT_SPARE_SHIFT 4 -+#define PAGEFMT_FDM_ECC_SHIFT 12 -+#define PAGEFMT_FDM_SHIFT 8 -+#define PAGEFMT_SEC_SEL_512 BIT(2) -+#define PAGEFMT_512_2K 0 -+#define PAGEFMT_2K_4K 1 -+#define PAGEFMT_4K_8K 2 -+#define PAGEFMT_8K_16K 3 -+#define NFI_CON 0x008 -+#define CON_FIFO_FLUSH BIT(0) -+#define CON_NFI_RST BIT(1) -+#define CON_BRD BIT(8) -+#define CON_BWR BIT(9) -+#define CON_SEC_SHIFT 12 -+#define NFI_ACCCON 0x00c -+#define NFI_INTR_EN 0x010 -+#define INTR_BUSY_RETURN_EN BIT(4) -+#define INTR_AHB_DONE_EN BIT(6) -+#define NFI_INTR_STA 0x014 -+#define NFI_CMD 0x020 -+#define NFI_ADDRNOB 0x030 -+#define ROW_SHIFT 4 -+#define NFI_COLADDR 0x034 -+#define NFI_ROWADDR 0x038 -+#define NFI_STRDATA 0x040 -+#define STAR_EN 1 -+#define STAR_DE 0 -+#define NFI_CNRNB 0x044 -+#define NFI_DATAW 0x050 -+#define NFI_DATAR 0x054 -+#define NFI_PIO_DIRDY 0x058 -+#define PIO_DI_RDY 1 -+#define NFI_STA 0x060 -+#define STA_CMD BIT(0) -+#define STA_ADDR BIT(1) -+#define FLASH_MACRO_IDLE BIT(5) -+#define STA_BUSY BIT(8) -+#define STA_BUSY2READY BIT(9) -+#define STA_EMP_PAGE BIT(12) -+#define NFI_FSM_CUSTDATA (0xe << 16) -+#define NFI_FSM_MASK GENMASK(19, 16) -+#define NAND_FSM_MASK GENMASK(29, 23) -+#define NFI_ADDRCNTR 0x070 -+#define CNTR_VALID_MASK GENMASK(16, 0) -+#define CNTR_MASK GENMASK(15, 12) -+#define ADDRCNTR_SEC_SHIFT 12 -+#define ADDRCNTR_SEC(val) \ -+ (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT) -+#define NFI_STRADDR 0x080 -+#define NFI_BYTELEN 0x084 -+#define NFI_CSEL 0x090 -+#define NFI_FDML(x) (0x0a0 + (x) * 8) -+#define NFI_FDMM(x) (0x0a4 + (x) * 8) -+#define NFI_DEBUG_CON1 0x220 -+#define STROBE_MASK GENMASK(4, 3) -+#define STROBE_SHIFT 3 -+#define ECC_CLK_EN BIT(11) -+#define AUTOC_SRAM_MODE BIT(12) -+#define BYPASS_MASTER_EN BIT(15) -+#define NFI_MASTER_STA 0x224 -+#define MASTER_BUS_BUSY 0x3 -+#define NFI_SECCUS_SIZE 0x22c -+#define SECCUS_SIZE_EN BIT(17) -+#define NFI_RANDOM_CNFG 0x238 -+#define RAN_ENCODE_EN BIT(0) -+#define ENCODE_SEED_SHIFT 1 -+#define RAN_DECODE_EN BIT(16) -+#define DECODE_SEED_SHIFT 17 -+#define RAN_SEED_MASK 0x7fff -+#define NFI_EMPTY_THRESH 0x23c -+#define NFI_NAND_TYPE_CNFG 0x240 -+#define NAND_TYPE_ASYNC 0 -+#define NAND_TYPE_TOGGLE 1 -+#define NAND_TYPE_SYNC 2 -+#define NFI_ACCCON1 0x244 -+#define NFI_DELAY_CTRL 0x248 -+#define NFI_TLC_RD_WHR2 0x300 -+#define TLC_RD_WHR2_EN BIT(12) -+#define TLC_RD_WHR2_MASK GENMASK(11, 0) -+#define SNF_SNF_CNFG 0x55c -+#define SPI_MODE_EN 1 -+#define SPI_MODE_DIS 0 -+ -+#endif /* __NFI_REGS_H__ */ -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_spi.c -@@ -0,0 +1,689 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "../nfi.h" -+#include "nfiecc.h" -+#include "nfi_regs.h" -+#include "nfi_base.h" -+#include "nfi_spi_regs.h" -+#include "nfi_spi.h" -+ -+#define NFI_CMD_DUMMY_RD 0x00 -+#define NFI_CMD_DUMMY_WR 0x80 -+ -+static struct nfi_spi_delay spi_delay[SPI_NAND_MAX_DELAY] = { -+ /* -+ * tCLK_SAM_DLY, tCLK_OUT_DLY, tCS_DLY, tWR_EN_DLY, -+ * tIO_IN_DLY[4], tIO_OUT_DLY[4], tREAD_LATCH_LATENCY -+ */ -+ {0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0}, -+ {21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0}, -+ {63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0}, -+ {0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1}, -+ {21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1}, -+ {63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1} -+}; -+ -+static inline struct nfi_spi *base_to_snfi(struct nfi_base *nb) -+{ -+ return container_of(nb, struct nfi_spi, base); -+} -+ -+static void snfi_mac_enable(struct nfi_base *nb) -+{ -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ val = readl(regs + SNF_MAC_CTL); -+ val &= ~MAC_XIO_SEL; -+ val |= SF_MAC_EN; -+ -+ writel(val, regs + SNF_MAC_CTL); -+} -+ -+static void snfi_mac_disable(struct nfi_base *nb) -+{ -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ val = readl(regs + SNF_MAC_CTL); -+ val &= ~(SF_TRIG | SF_MAC_EN); -+ writel(val, regs + SNF_MAC_CTL); -+} -+ -+static int snfi_mac_trigger(struct nfi_base *nb) -+{ -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ u32 val; -+ -+ val = readl(regs + SNF_MAC_CTL); -+ val |= SF_TRIG; -+ writel(val, regs + SNF_MAC_CTL); -+ -+ ret = readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val, -+ val & WIP_READY, 10, -+ NFI_TIMEOUT); -+ if (ret) { -+ pr_info("polling wip ready for read timeout\n"); -+ return ret; -+ } -+ -+ return readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val, -+ !(val & WIP), 10, -+ NFI_TIMEOUT); -+} -+ -+static int snfi_mac_op(struct nfi_base *nb) -+{ -+ int ret; -+ -+ snfi_mac_enable(nb); -+ ret = snfi_mac_trigger(nb); -+ snfi_mac_disable(nb); -+ -+ return ret; -+} -+ -+static void snfi_write_mac(struct nfi_spi *nfi_spi, u8 *data, int count) -+{ -+ struct nandx_split32 split = {0}; -+ u32 reg_offset = round_down(nfi_spi->tx_count, 4); -+ void *regs = nfi_spi->base.res.nfi_regs; -+ u32 data_offset = 0, i, val; -+ u8 *p_val = (u8 *)(&val); -+ -+ nandx_split(&split, nfi_spi->tx_count, count, val, 4); -+ -+ if (split.head_len) { -+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset); -+ -+ for (i = 0; i < split.head_len; i++) -+ p_val[split.head + i] = data[i]; -+ -+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset); -+ } -+ -+ if (split.body_len) { -+ reg_offset = split.body; -+ data_offset = split.head_len; -+ -+ for (i = 0; i < split.body_len; i++) { -+ p_val[i & 3] = data[data_offset + i]; -+ -+ if ((i & 3) == 3) { -+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset); -+ reg_offset += 4; -+ } -+ } -+ } -+ -+ if (split.tail_len) { -+ reg_offset = split.tail; -+ data_offset += split.body_len; -+ -+ for (i = 0; i < split.tail_len; i++) { -+ p_val[i] = data[data_offset + i]; -+ -+ if (i == split.tail_len - 1) -+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset); -+ } -+ } -+} -+ -+static void snfi_read_mac(struct nfi_spi *nfi_spi, u8 *data, int count) -+{ -+ void *regs = nfi_spi->base.res.nfi_regs; -+ u32 reg_offset = round_down(nfi_spi->tx_count, 4); -+ struct nandx_split32 split = {0}; -+ u32 data_offset = 0, i, val; -+ u8 *p_val = (u8 *)&val; -+ -+ nandx_split(&split, nfi_spi->tx_count, count, val, 4); -+ -+ if (split.head_len) { -+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset); -+ -+ for (i = 0; i < split.head_len; i++) -+ data[data_offset + i] = p_val[split.head + i]; -+ } -+ -+ if (split.body_len) { -+ reg_offset = split.body; -+ data_offset = split.head_len; -+ -+ for (i = 0; i < split.body_len; i++) { -+ if ((i & 3) == 0) { -+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset); -+ reg_offset += 4; -+ } -+ -+ data[data_offset + i] = p_val[i % 4]; -+ } -+ } -+ -+ if (split.tail_len) { -+ reg_offset = split.tail; -+ data_offset += split.body_len; -+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset); -+ -+ for (i = 0; i < split.tail_len; i++) -+ data[data_offset + i] = p_val[i]; -+ } -+} -+ -+static int snfi_send_command(struct nfi *nfi, short cmd) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ -+ if (cmd == -1) -+ return 0; -+ -+ if (nfi_spi->snfi_mode == SNFI_MAC_MODE) { -+ snfi_write_mac(nfi_spi, (u8 *)&cmd, 1); -+ nfi_spi->tx_count++; -+ return 0; -+ } -+ -+ nfi_spi->cmd[nfi_spi->cur_cmd_idx++] = cmd; -+ return 0; -+} -+ -+static int snfi_send_address(struct nfi *nfi, int col, int row, -+ int col_cycle, -+ int row_cycle) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ u32 addr, cycle, temp; -+ -+ nb->col = col; -+ nb->row = row; -+ -+ if (nfi_spi->snfi_mode == SNFI_MAC_MODE) { -+ addr = row; -+ cycle = row_cycle; -+ -+ if (!row_cycle) { -+ addr = col; -+ cycle = col_cycle; -+ } -+ -+ temp = nandx_cpu_to_be32(addr) >> ((4 - cycle) << 3); -+ snfi_write_mac(nfi_spi, (u8 *)&temp, cycle); -+ nfi_spi->tx_count += cycle; -+ } else { -+ nfi_spi->row_addr[nfi_spi->cur_addr_idx++] = row; -+ nfi_spi->col_addr[nfi_spi->cur_addr_idx++] = col; -+ } -+ -+ return 0; -+} -+ -+static int snfi_trigger(struct nfi *nfi) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ -+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL); -+ writel(0, regs + SNF_MAC_INL); -+ -+ nfi_spi->tx_count = 0; -+ nfi_spi->cur_cmd_idx = 0; -+ nfi_spi->cur_addr_idx = 0; -+ -+ return snfi_mac_op(nb); -+} -+ -+static int snfi_select_chip(struct nfi *nfi, int cs) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ val = readl(regs + SNF_MISC_CTL); -+ -+ if (cs == 0) { -+ val &= ~SF2CS_SEL; -+ val &= ~SF2CS_EN; -+ } else if (cs == 1) { -+ val |= SF2CS_SEL; -+ val |= SF2CS_EN; -+ } else { -+ return -EIO; -+ } -+ -+ writel(val, regs + SNF_MISC_CTL); -+ -+ return 0; -+} -+ -+static int snfi_set_delay(struct nfi_base *nb, u8 delay_mode) -+{ -+ void *regs = nb->res.nfi_regs; -+ struct nfi_spi_delay *delay; -+ u32 val; -+ -+ if (delay_mode < 0 || delay_mode > SPI_NAND_MAX_DELAY) -+ return -EINVAL; -+ -+ delay = &spi_delay[delay_mode]; -+ -+ val = delay->tIO_OUT_DLY[0] | delay->tIO_OUT_DLY[1] << 8 | -+ delay->tIO_OUT_DLY[2] << 16 | -+ delay->tIO_OUT_DLY[3] << 24; -+ writel(val, regs + SNF_DLY_CTL1); -+ -+ val = delay->tIO_IN_DLY[0] | (delay->tIO_IN_DLY[1] << 8) | -+ delay->tIO_IN_DLY[2] << 16 | -+ delay->tIO_IN_DLY[3] << 24; -+ writel(val, regs + SNF_DLY_CTL2); -+ -+ val = delay->tCLK_SAM_DLY | delay->tCLK_OUT_DLY << 8 | -+ delay->tCS_DLY << 16 | -+ delay->tWR_EN_DLY << 24; -+ writel(val, regs + SNF_DLY_CTL3); -+ -+ writel(delay->tCS_DLY, regs + SNF_DLY_CTL4); -+ -+ val = readl(regs + SNF_MISC_CTL); -+ val |= (delay->tREAD_LATCH_LATENCY) << -+ LATCH_LAT_SHIFT; -+ writel(val, regs + SNF_MISC_CTL); -+ -+ return 0; -+} -+ -+static int snfi_set_timing(struct nfi *nfi, void *timing, int type) -+{ -+ /* Nothing need to do. */ -+ return 0; -+} -+ -+static int snfi_wait_ready(struct nfi *nfi, int type, u32 timeout) -+{ -+ /* Nothing need to do. */ -+ return 0; -+} -+ -+static int snfi_ctrl(struct nfi *nfi, int cmd, void *args) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ int ret = 0; -+ -+ if (!args) -+ return -EINVAL; -+ -+ switch (cmd) { -+ case NFI_CTRL_DMA: -+ nb->dma_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_NFI_IRQ: -+ nb->nfi_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_IRQ: -+ nb->ecc_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_PAGE_IRQ: -+ nb->page_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC: -+ nb->ecc_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_BAD_MARK_SWAP: -+ nb->bad_mark_swap_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_CLOCK: -+ nb->ecc_clk_en = *(bool *)args; -+ break; -+ -+ case SNFI_CTRL_OP_MODE: -+ nfi_spi->snfi_mode = *(u8 *)args; -+ break; -+ -+ case SNFI_CTRL_RX_MODE: -+ nfi_spi->read_cache_mode = *(u8 *)args; -+ break; -+ -+ case SNFI_CTRL_TX_MODE: -+ nfi_spi->write_cache_mode = *(u8 *)args; -+ break; -+ -+ case SNFI_CTRL_DELAY_MODE: -+ ret = snfi_set_delay(nb, *(u8 *)args); -+ break; -+ -+ default: -+ pr_info("operation not support.\n"); -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int snfi_read_bytes(struct nfi *nfi, u8 *data, int count) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ int ret; -+ -+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL); -+ writel(count, regs + SNF_MAC_INL); -+ -+ ret = snfi_mac_op(nb); -+ if (ret) -+ return ret; -+ -+ snfi_read_mac(nfi_spi, data, count); -+ -+ nfi_spi->tx_count = 0; -+ -+ return 0; -+} -+ -+static int snfi_write_bytes(struct nfi *nfi, u8 *data, int count) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ -+ snfi_write_mac(nfi_spi, data, count); -+ nfi_spi->tx_count += count; -+ -+ writel(0, regs + SNF_MAC_INL); -+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL); -+ -+ nfi_spi->tx_count = 0; -+ -+ return snfi_mac_op(nb); -+} -+ -+static int snfi_reset(struct nfi *nfi) -+{ -+ struct nfi_base *nb = nfi_to_base(nfi); -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ int ret; -+ -+ ret = nfi_spi->parent->nfi.reset(nfi); -+ if (ret) -+ return ret; -+ -+ val = readl(regs + SNF_MISC_CTL); -+ val |= SW_RST; -+ writel(val, regs + SNF_MISC_CTL); -+ -+ ret = readx_poll_timeout_atomic(readw, regs + SNF_STA_CTL1, val, -+ !(val & SPI_STATE), 50, -+ NFI_TIMEOUT); -+ if (ret) { -+ pr_info("spi state active in reset [0x%x] = 0x%x\n", -+ SNF_STA_CTL1, val); -+ return ret; -+ } -+ -+ val = readl(regs + SNF_MISC_CTL); -+ val &= ~SW_RST; -+ writel(val, regs + SNF_MISC_CTL); -+ -+ return 0; -+} -+ -+static int snfi_config_for_write(struct nfi_base *nb, int count) -+{ -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ nb->set_op_mode(regs, CNFG_CUSTOM_MODE); -+ -+ val = readl(regs + SNF_MISC_CTL); -+ -+ if (nfi_spi->write_cache_mode == SNFI_TX_114) -+ val |= PG_LOAD_X4_EN; -+ -+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) -+ val |= PG_LOAD_CUSTOM_EN; -+ -+ writel(val, regs + SNF_MISC_CTL); -+ -+ val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size); -+ writel(val << PG_LOAD_SHIFT, regs + SNF_MISC_CTL2); -+ -+ val = readl(regs + SNF_PG_CTL1); -+ -+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) -+ val |= nfi_spi->cmd[0] << PG_LOAD_CMD_SHIFT; -+ else { -+ val |= nfi_spi->cmd[0] | nfi_spi->cmd[1] << PG_LOAD_CMD_SHIFT | -+ nfi_spi->cmd[2] << PG_EXE_CMD_SHIFT; -+ -+ writel(nfi_spi->row_addr[1], regs + SNF_PG_CTL3); -+ writel(nfi_spi->cmd[3] << GF_CMD_SHIFT | nfi_spi->col_addr[2] << -+ GF_ADDR_SHIFT, regs + SNF_GF_CTL1); -+ } -+ -+ writel(val, regs + SNF_PG_CTL1); -+ writel(nfi_spi->col_addr[1], regs + SNF_PG_CTL2); -+ -+ writel(NFI_CMD_DUMMY_WR, regs + NFI_CMD); -+ -+ return 0; -+} -+ -+static int snfi_config_for_read(struct nfi_base *nb, int count) -+{ -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ int ret = 0; -+ -+ nb->set_op_mode(regs, CNFG_CUSTOM_MODE); -+ -+ val = readl(regs + SNF_MISC_CTL); -+ val &= ~DARA_READ_MODE_MASK; -+ -+ switch (nfi_spi->read_cache_mode) { -+ -+ case SNFI_RX_111: -+ break; -+ -+ case SNFI_RX_112: -+ val |= X2_DATA_MODE << READ_MODE_SHIFT; -+ break; -+ -+ case SNFI_RX_114: -+ val |= X4_DATA_MODE << READ_MODE_SHIFT; -+ break; -+ -+ case SNFI_RX_122: -+ val |= DUAL_IO_MODE << READ_MODE_SHIFT; -+ break; -+ -+ case SNFI_RX_144: -+ val |= QUAD_IO_MODE << READ_MODE_SHIFT; -+ break; -+ -+ default: -+ pr_info("Not support this read operarion: %d!\n", -+ nfi_spi->read_cache_mode); -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) -+ val |= DATARD_CUSTOM_EN; -+ -+ writel(val, regs + SNF_MISC_CTL); -+ -+ val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size); -+ writel(val, regs + SNF_MISC_CTL2); -+ -+ val = readl(regs + SNF_RD_CTL2); -+ -+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) { -+ val |= nfi_spi->cmd[0]; -+ writel(nfi_spi->col_addr[1], regs + SNF_RD_CTL3); -+ } else { -+ val |= nfi_spi->cmd[2]; -+ writel(nfi_spi->cmd[0] << PAGE_READ_CMD_SHIFT | -+ nfi_spi->row_addr[0], regs + SNF_RD_CTL1); -+ writel(nfi_spi->cmd[1] << GF_CMD_SHIFT | -+ nfi_spi->col_addr[1] << GF_ADDR_SHIFT, -+ regs + SNF_GF_CTL1); -+ writel(nfi_spi->col_addr[2], regs + SNF_RD_CTL3); -+ } -+ -+ writel(val, regs + SNF_RD_CTL2); -+ -+ writel(NFI_CMD_DUMMY_RD, regs + NFI_CMD); -+ -+ return ret; -+} -+ -+static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm, -+ int sectors) -+{ -+ u32 *data32 = (u32 *)data; -+ u32 *fdm32 = (u32 *)fdm; -+ u32 i, count = 0; -+ -+ for (i = 0; i < nb->format.page_size >> 2; i++) { -+ if (data32[i] != 0xffff) { -+ count += zero_popcount(data32[i]); -+ if (count > 10) { -+ pr_info("%s %d %d count:%d\n", -+ __func__, __LINE__, i, count); -+ return false; -+ } -+ } -+ } -+ -+ if (fdm) { -+ for (i = 0; i < (nb->nfi.fdm_size * sectors >> 2); i++) -+ if (fdm32[i] != 0xffff) { -+ count += zero_popcount(fdm32[i]); -+ if (count > 10) { -+ pr_info("%s %d %d count:%d\n", -+ __func__, __LINE__, i, count); -+ return false; -+ } -+ } -+ } -+ -+ return true; -+} -+ -+static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data, -+ u8 *fdm, -+ bool read) -+{ -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ int ret; -+ -+ ret = nfi_spi->parent->rw_prepare(nb, sectors, data, fdm, read); -+ if (ret) -+ return ret; -+ -+ if (read) -+ ret = snfi_config_for_read(nb, sectors); -+ else -+ ret = snfi_config_for_write(nb, sectors); -+ -+ return ret; -+} -+ -+static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm, -+ bool read) -+{ -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ void *regs = nb->res.nfi_regs; -+ u32 val; -+ -+ nfi_spi->parent->rw_complete(nb, data, fdm, read); -+ -+ val = readl(regs + SNF_MISC_CTL); -+ -+ if (read) -+ val &= ~DATARD_CUSTOM_EN; -+ else -+ val &= ~PG_LOAD_CUSTOM_EN; -+ -+ writel(val, regs + SNF_MISC_CTL); -+ -+ nfi_spi->tx_count = 0; -+ nfi_spi->cur_cmd_idx = 0; -+ nfi_spi->cur_addr_idx = 0; -+} -+ -+static void set_nfi_base_funcs(struct nfi_base *nb) -+{ -+ nb->nfi.reset = snfi_reset; -+ nb->nfi.set_timing = snfi_set_timing; -+ nb->nfi.wait_ready = snfi_wait_ready; -+ -+ nb->nfi.send_cmd = snfi_send_command; -+ nb->nfi.send_addr = snfi_send_address; -+ nb->nfi.trigger = snfi_trigger; -+ nb->nfi.nfi_ctrl = snfi_ctrl; -+ nb->nfi.select_chip = snfi_select_chip; -+ -+ nb->nfi.read_bytes = snfi_read_bytes; -+ nb->nfi.write_bytes = snfi_write_bytes; -+ -+ nb->rw_prepare = rw_prepare; -+ nb->rw_complete = rw_complete; -+ nb->is_page_empty = is_page_empty; -+ -+} -+ -+struct nfi *nfi_extend_init(struct nfi_base *nb) -+{ -+ struct nfi_spi *nfi_spi; -+ -+ nfi_spi = mem_alloc(1, sizeof(struct nfi_spi)); -+ if (!nfi_spi) { -+ pr_info("snfi alloc memory fail @%s.\n", __func__); -+ return NULL; -+ } -+ -+ memcpy(&nfi_spi->base, nb, sizeof(struct nfi_base)); -+ nfi_spi->parent = nb; -+ -+ nfi_spi->read_cache_mode = SNFI_RX_114; -+ nfi_spi->write_cache_mode = SNFI_TX_114; -+ -+ set_nfi_base_funcs(&nfi_spi->base); -+ -+ /* Change nfi to spi mode */ -+ writel(SPI_MODE, nb->res.nfi_regs + SNF_SNF_CNFG); -+ -+ return &(nfi_spi->base.nfi); -+} -+ -+void nfi_extend_exit(struct nfi_base *nb) -+{ -+ struct nfi_spi *nfi_spi = base_to_snfi(nb); -+ -+ mem_free(nfi_spi->parent); -+ mem_free(nfi_spi); -+} -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_spi.h -@@ -0,0 +1,44 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFI_SPI_H__ -+#define __NFI_SPI_H__ -+ -+#define SPI_NAND_MAX_DELAY 6 -+#define SPI_NAND_MAX_OP 4 -+ -+/*TODO - add comments */ -+struct nfi_spi_delay { -+ u8 tCLK_SAM_DLY; -+ u8 tCLK_OUT_DLY; -+ u8 tCS_DLY; -+ u8 tWR_EN_DLY; -+ u8 tIO_IN_DLY[4]; -+ u8 tIO_OUT_DLY[4]; -+ u8 tREAD_LATCH_LATENCY; -+}; -+ -+/* SPI Nand structure */ -+struct nfi_spi { -+ struct nfi_base base; -+ struct nfi_base *parent; -+ -+ u8 snfi_mode; -+ u8 tx_count; -+ -+ u8 cmd[SPI_NAND_MAX_OP]; -+ u8 cur_cmd_idx; -+ -+ u32 row_addr[SPI_NAND_MAX_OP]; -+ u32 col_addr[SPI_NAND_MAX_OP]; -+ u8 cur_addr_idx; -+ -+ u8 read_cache_mode; -+ u8 write_cache_mode; -+}; -+ -+#endif /* __NFI_SPI_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h -@@ -0,0 +1,64 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFI_SPI_REGS_H__ -+#define __NFI_SPI_REGS_H__ -+ -+#define SNF_MAC_CTL 0x500 -+#define WIP BIT(0) -+#define WIP_READY BIT(1) -+#define SF_TRIG BIT(2) -+#define SF_MAC_EN BIT(3) -+#define MAC_XIO_SEL BIT(4) -+#define SNF_MAC_OUTL 0x504 -+#define SNF_MAC_INL 0x508 -+#define SNF_RD_CTL1 0x50c -+#define PAGE_READ_CMD_SHIFT 24 -+#define SNF_RD_CTL2 0x510 -+#define SNF_RD_CTL3 0x514 -+#define SNF_GF_CTL1 0x518 -+#define GF_ADDR_SHIFT 16 -+#define GF_CMD_SHIFT 24 -+#define SNF_GF_CTL3 0x520 -+#define SNF_PG_CTL1 0x524 -+#define PG_EXE_CMD_SHIFT 16 -+#define PG_LOAD_CMD_SHIFT 8 -+#define SNF_PG_CTL2 0x528 -+#define SNF_PG_CTL3 0x52c -+#define SNF_ER_CTL 0x530 -+#define SNF_ER_CTL2 0x534 -+#define SNF_MISC_CTL 0x538 -+#define SW_RST BIT(28) -+#define PG_LOAD_X4_EN BIT(20) -+#define X2_DATA_MODE 1 -+#define X4_DATA_MODE 2 -+#define DUAL_IO_MODE 5 -+#define QUAD_IO_MODE 6 -+#define READ_MODE_SHIFT 16 -+#define LATCH_LAT_SHIFT 8 -+#define LATCH_LAT_MASK GENMASK(9, 8) -+#define DARA_READ_MODE_MASK GENMASK(18, 16) -+#define SF2CS_SEL BIT(13) -+#define SF2CS_EN BIT(12) -+#define PG_LOAD_CUSTOM_EN BIT(7) -+#define DATARD_CUSTOM_EN BIT(6) -+#define SNF_MISC_CTL2 0x53c -+#define PG_LOAD_SHIFT 16 -+#define SNF_DLY_CTL1 0x540 -+#define SNF_DLY_CTL2 0x544 -+#define SNF_DLY_CTL3 0x548 -+#define SNF_DLY_CTL4 0x54c -+#define SNF_STA_CTL1 0x550 -+#define SPI_STATE GENMASK(3, 0) -+#define SNF_STA_CTL2 0x554 -+#define SNF_STA_CTL3 0x558 -+#define SNF_SNF_CNFG 0x55c -+#define SPI_MODE BIT(0) -+#define SNF_DEBUG_SEL 0x560 -+#define SPI_GPRAM_ADDR 0x800 -+ -+#endif /* __NFI_SPI_REGS_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfiecc.c -@@ -0,0 +1,510 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "nfiecc_regs.h" -+#include "nfiecc.h" -+ -+#define NFIECC_IDLE_REG(op) \ -+ ((op) == ECC_ENCODE ? NFIECC_ENCIDLE : NFIECC_DECIDLE) -+#define IDLE_MASK 1 -+#define NFIECC_CTL_REG(op) \ -+ ((op) == ECC_ENCODE ? NFIECC_ENCCON : NFIECC_DECCON) -+#define NFIECC_IRQ_REG(op) \ -+ ((op) == ECC_ENCODE ? NFIECC_ENCIRQEN : NFIECC_DECIRQEN) -+#define NFIECC_ADDR(op) \ -+ ((op) == ECC_ENCODE ? NFIECC_ENCDIADDR : NFIECC_DECDIADDR) -+ -+#define ECC_TIMEOUT 500000 -+ -+/* ecc strength that each IP supports */ -+static const int ecc_strength_mt7622[] = { -+ 4, 6, 8, 10, 12, 14, 16 -+}; -+ -+static int nfiecc_irq_handler(void *data) -+{ -+ struct nfiecc *ecc = data; -+ void *regs = ecc->res.regs; -+ u32 status; -+ -+ status = readl(regs + NFIECC_DECIRQSTA) & DEC_IRQSTA_GEN; -+ if (status) { -+ status = readl(regs + NFIECC_DECDONE); -+ if (!(status & ecc->config.sectors)) -+ return NAND_IRQ_NONE; -+ -+ /* -+ * Clear decode IRQ status once again to ensure that -+ * there will be no extra IRQ. -+ */ -+ readl(regs + NFIECC_DECIRQSTA); -+ ecc->config.sectors = 0; -+ nandx_event_complete(ecc->done); -+ } else { -+ status = readl(regs + NFIECC_ENCIRQSTA) & ENC_IRQSTA_GEN; -+ if (!status) -+ return NAND_IRQ_NONE; -+ -+ nandx_event_complete(ecc->done); -+ } -+ -+ return NAND_IRQ_HANDLED; -+} -+ -+static inline int nfiecc_wait_idle(struct nfiecc *ecc) -+{ -+ int op = ecc->config.op; -+ int ret, val; -+ -+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_IDLE_REG(op), -+ val, val & IDLE_MASK, -+ 10, ECC_TIMEOUT); -+ if (ret) -+ pr_info("%s not idle\n", -+ op == ECC_ENCODE ? "encoder" : "decoder"); -+ -+ return ret; -+} -+ -+static int nfiecc_wait_encode_done(struct nfiecc *ecc) -+{ -+ int ret, val; -+ -+ if (ecc->ecc_irq_en) { -+ /* poll one time to avoid missing irq event */ -+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA, -+ val, val & ENC_FSM_IDLE, 1, 1); -+ if (!ret) -+ return 0; -+ -+ /* irq done, if not, we can go on to poll status for a while */ -+ ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT); -+ if (ret) -+ return 0; -+ } -+ -+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA, -+ val, val & ENC_FSM_IDLE, -+ 10, ECC_TIMEOUT); -+ if (ret) -+ pr_info("encode timeout\n"); -+ -+ return ret; -+ -+} -+ -+static int nfiecc_wait_decode_done(struct nfiecc *ecc) -+{ -+ u32 secbit = BIT(ecc->config.sectors - 1); -+ void *regs = ecc->res.regs; -+ int ret, val; -+ -+ if (ecc->ecc_irq_en) { -+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE, -+ val, val & secbit, 1, 1); -+ if (!ret) -+ return 0; -+ -+ ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT); -+ if (ret) -+ return 0; -+ } -+ -+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE, -+ val, val & secbit, -+ 10, ECC_TIMEOUT); -+ if (ret) { -+ pr_info("decode timeout\n"); -+ return ret; -+ } -+ -+ /* decode done does not stands for ecc all work done. -+ * we need check syn, bma, chien, autoc all idle. -+ * just check it when ECC_DECCNFG[13:12] is 3, -+ * which means auto correct. -+ */ -+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECFSM, -+ val, (val & FSM_MASK) == FSM_IDLE, -+ 10, ECC_TIMEOUT); -+ if (ret) -+ pr_info("decode fsm(0x%x) is not idle\n", -+ readl(regs + NFIECC_DECFSM)); -+ -+ return ret; -+} -+ -+static int nfiecc_wait_done(struct nfiecc *ecc) -+{ -+ if (ecc->config.op == ECC_ENCODE) -+ return nfiecc_wait_encode_done(ecc); -+ -+ return nfiecc_wait_decode_done(ecc); -+} -+ -+static void nfiecc_encode_config(struct nfiecc *ecc, u32 ecc_idx) -+{ -+ struct nfiecc_config *config = &ecc->config; -+ u32 val; -+ -+ val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift); -+ -+ if (config->mode == ECC_DMA_MODE) -+ val |= ENC_BURST_EN; -+ -+ val |= (config->len << 3) << ENCCNFG_MS_SHIFT; -+ writel(val, ecc->res.regs + NFIECC_ENCCNFG); -+} -+ -+static void nfiecc_decode_config(struct nfiecc *ecc, u32 ecc_idx) -+{ -+ struct nfiecc_config *config = &ecc->config; -+ u32 dec_sz = (config->len << 3) + -+ config->strength * ecc->caps->parity_bits; -+ u32 val; -+ -+ val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift); -+ -+ if (config->mode == ECC_DMA_MODE) -+ val |= DEC_BURST_EN; -+ -+ val |= (dec_sz << DECCNFG_MS_SHIFT) | -+ (config->deccon << DEC_CON_SHIFT); -+ val |= DEC_EMPTY_EN; -+ writel(val, ecc->res.regs + NFIECC_DECCNFG); -+} -+ -+static void nfiecc_config(struct nfiecc *ecc) -+{ -+ u32 idx; -+ -+ for (idx = 0; idx < ecc->caps->ecc_strength_num; idx++) { -+ if (ecc->config.strength == ecc->caps->ecc_strength[idx]) -+ break; -+ } -+ -+ if (ecc->config.op == ECC_ENCODE) -+ nfiecc_encode_config(ecc, idx); -+ else -+ nfiecc_decode_config(ecc, idx); -+} -+ -+static int nfiecc_enable(struct nfiecc *ecc) -+{ -+ enum nfiecc_operation op = ecc->config.op; -+ void *regs = ecc->res.regs; -+ -+ nfiecc_config(ecc); -+ -+ writel(ECC_OP_EN, regs + NFIECC_CTL_REG(op)); -+ -+ if (ecc->ecc_irq_en) { -+ writel(ECC_IRQEN, regs + NFIECC_IRQ_REG(op)); -+ -+ if (ecc->page_irq_en) -+ writel(ECC_IRQEN | ECC_PG_IRQ_SEL, -+ regs + NFIECC_IRQ_REG(op)); -+ -+ nandx_event_init(ecc->done); -+ } -+ -+ return 0; -+} -+ -+static int nfiecc_disable(struct nfiecc *ecc) -+{ -+ enum nfiecc_operation op = ecc->config.op; -+ void *regs = ecc->res.regs; -+ -+ nfiecc_wait_idle(ecc); -+ -+ writel(0, regs + NFIECC_IRQ_REG(op)); -+ writel(~ECC_OP_EN, regs + NFIECC_CTL_REG(op)); -+ -+ return 0; -+} -+ -+static int nfiecc_correct_data(struct nfiecc *ecc, -+ struct nfiecc_status *status, -+ u8 *data, u32 sector) -+{ -+ u32 err, offset, i; -+ u32 loc, byteloc, bitloc; -+ -+ status->corrected = 0; -+ status->failed = 0; -+ -+ offset = (sector >> 2); -+ err = readl(ecc->res.regs + NFIECC_DECENUM(offset)); -+ err >>= (sector % 4) * 8; -+ err &= ecc->caps->err_mask; -+ -+ if (err == ecc->caps->err_mask) { -+ status->failed++; -+ return -ENANDREAD; -+ } -+ -+ status->corrected += err; -+ status->bitflips = max_t(u32, status->bitflips, err); -+ -+ for (i = 0; i < err; i++) { -+ loc = readl(ecc->res.regs + NFIECC_DECEL(i >> 1)); -+ loc >>= ((i & 0x1) << 4); -+ byteloc = loc >> 3; -+ bitloc = loc & 0x7; -+ data[byteloc] ^= (1 << bitloc); -+ } -+ -+ return 0; -+} -+ -+static int nfiecc_fill_data(struct nfiecc *ecc, u8 *data) -+{ -+ struct nfiecc_config *config = &ecc->config; -+ void *regs = ecc->res.regs; -+ int size, ret, i; -+ u32 val; -+ -+ if (config->mode == ECC_DMA_MODE) { -+ if ((unsigned long)config->dma_addr & 0x3) -+ pr_info("encode address is not 4B aligned: 0x%x\n", -+ (u32)(unsigned long)config->dma_addr); -+ -+ writel((unsigned long)config->dma_addr, -+ regs + NFIECC_ADDR(config->op)); -+ } else if (config->mode == ECC_PIO_MODE) { -+ if (config->op == ECC_ENCODE) { -+ size = (config->len + 3) >> 2; -+ } else { -+ size = config->strength * ecc->caps->parity_bits; -+ size = (size + 7) >> 3; -+ size += config->len; -+ size >>= 2; -+ } -+ -+ for (i = 0; i < size; i++) { -+ ret = readl_poll_timeout_atomic(regs + NFIECC_PIO_DIRDY, -+ val, val & PIO_DI_RDY, -+ 10, ECC_TIMEOUT); -+ if (ret) -+ return ret; -+ -+ writel(*((u32 *)data + i), regs + NFIECC_PIO_DI); -+ } -+ } -+ -+ return 0; -+} -+ -+static int nfiecc_encode(struct nfiecc *ecc, u8 *data) -+{ -+ struct nfiecc_config *config = &ecc->config; -+ u32 len, i, val = 0; -+ u8 *p; -+ int ret; -+ -+ /* Under NFI mode, nothing need to do */ -+ if (config->mode == ECC_NFI_MODE) -+ return 0; -+ -+ ret = nfiecc_fill_data(ecc, data); -+ if (ret) -+ return ret; -+ -+ ret = nfiecc_wait_encode_done(ecc); -+ if (ret) -+ return ret; -+ -+ ret = nfiecc_wait_idle(ecc); -+ if (ret) -+ return ret; -+ -+ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */ -+ len = (config->strength * ecc->caps->parity_bits + 7) >> 3; -+ p = data + config->len; -+ -+ /* Write the parity bytes generated by the ECC back to the OOB region */ -+ for (i = 0; i < len; i++) { -+ if ((i % 4) == 0) -+ val = readl(ecc->res.regs + NFIECC_ENCPAR(i / 4)); -+ -+ p[i] = (val >> ((i % 4) * 8)) & 0xff; -+ } -+ -+ return 0; -+} -+ -+static int nfiecc_decode(struct nfiecc *ecc, u8 *data) -+{ -+ int ret; -+ -+ /* Under NFI mode, nothing need to do */ -+ if (ecc->config.mode == ECC_NFI_MODE) -+ return 0; -+ -+ ret = nfiecc_fill_data(ecc, data); -+ if (ret) -+ return ret; -+ -+ return nfiecc_wait_decode_done(ecc); -+} -+ -+static int nfiecc_decode_status(struct nfiecc *ecc, u32 start_sector, -+ u32 sectors) -+{ -+ void *regs = ecc->res.regs; -+ u32 i, val = 0, err; -+ u32 bitflips = 0; -+ -+ for (i = start_sector; i < start_sector + sectors; i++) { -+ if ((i % 4) == 0) -+ val = readl(regs + NFIECC_DECENUM(i / 4)); -+ -+ err = val >> ((i % 4) * 5); -+ err &= ecc->caps->err_mask; -+ -+ if (err == ecc->caps->err_mask) -+ pr_err("sector %d is uncorrect\n", i); -+ -+ bitflips = max_t(u32, bitflips, err); -+ } -+ -+ if (bitflips == ecc->caps->err_mask) -+ return -ENANDREAD; -+ -+ if (bitflips) -+ pr_info("bitflips %d is corrected\n", bitflips); -+ -+ return bitflips; -+} -+ -+static int nfiecc_adjust_strength(struct nfiecc *ecc, int strength) -+{ -+ struct nfiecc_caps *caps = ecc->caps; -+ int i, count = caps->ecc_strength_num; -+ -+ if (strength >= caps->ecc_strength[count - 1]) -+ return caps->ecc_strength[count - 1]; -+ -+ if (strength < caps->ecc_strength[0]) -+ return -EINVAL; -+ -+ for (i = 1; i < count; i++) { -+ if (strength < caps->ecc_strength[i]) -+ return caps->ecc_strength[i - 1]; -+ } -+ -+ return -EINVAL; -+} -+ -+static int nfiecc_ctrl(struct nfiecc *ecc, int cmd, void *args) -+{ -+ int ret = 0; -+ -+ switch (cmd) { -+ case NFI_CTRL_ECC_IRQ: -+ ecc->ecc_irq_en = *(bool *)args; -+ break; -+ -+ case NFI_CTRL_ECC_PAGE_IRQ: -+ ecc->page_irq_en = *(bool *)args; -+ break; -+ -+ default: -+ pr_info("invalid arguments.\n"); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int nfiecc_hw_init(struct nfiecc *ecc) -+{ -+ int ret; -+ -+ ret = nfiecc_wait_idle(ecc); -+ if (ret) -+ return ret; -+ -+ writel(~ECC_OP_EN, ecc->res.regs + NFIECC_ENCCON); -+ -+ ret = nfiecc_wait_idle(ecc); -+ if (ret) -+ return ret; -+ -+ writel(~ECC_OP_EN, ecc->res.regs + NFIECC_DECCON); -+ -+ return 0; -+} -+ -+static struct nfiecc_caps nfiecc_caps_mt7622 = { -+ .err_mask = 0x1f, -+ .ecc_mode_shift = 4, -+ .parity_bits = 13, -+ .ecc_strength = ecc_strength_mt7622, -+ .ecc_strength_num = 7, -+}; -+ -+static struct nfiecc_caps *nfiecc_get_match_data(enum mtk_ic_version ic) -+{ -+ /* NOTE: add other IC's data */ -+ return &nfiecc_caps_mt7622; -+} -+ -+struct nfiecc *nfiecc_init(struct nfiecc_resource *res) -+{ -+ struct nfiecc *ecc; -+ int ret; -+ -+ ecc = mem_alloc(1, sizeof(struct nfiecc)); -+ if (!ecc) -+ return NULL; -+ -+ ecc->res = *res; -+ -+ ret = nandx_irq_register(res->dev, res->irq_id, nfiecc_irq_handler, -+ "mtk-ecc", ecc); -+ if (ret) { -+ pr_info("ecc irq register failed!\n"); -+ goto error; -+ } -+ -+ ecc->ecc_irq_en = false; -+ ecc->page_irq_en = false; -+ ecc->done = nandx_event_create(); -+ ecc->caps = nfiecc_get_match_data(res->ic_ver); -+ -+ ecc->adjust_strength = nfiecc_adjust_strength; -+ ecc->enable = nfiecc_enable; -+ ecc->disable = nfiecc_disable; -+ ecc->decode = nfiecc_decode; -+ ecc->encode = nfiecc_encode; -+ ecc->wait_done = nfiecc_wait_done; -+ ecc->decode_status = nfiecc_decode_status; -+ ecc->correct_data = nfiecc_correct_data; -+ ecc->nfiecc_ctrl = nfiecc_ctrl; -+ -+ ret = nfiecc_hw_init(ecc); -+ if (ret) -+ return NULL; -+ -+ return ecc; -+ -+error: -+ mem_free(ecc); -+ -+ return NULL; -+} -+ -+void nfiecc_exit(struct nfiecc *ecc) -+{ -+ nandx_event_destroy(ecc->done); -+ mem_free(ecc); -+} -+ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfiecc.h -@@ -0,0 +1,90 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFIECC_H__ -+#define __NFIECC_H__ -+ -+enum nfiecc_mode { -+ ECC_DMA_MODE, -+ ECC_NFI_MODE, -+ ECC_PIO_MODE -+}; -+ -+enum nfiecc_operation { -+ ECC_ENCODE, -+ ECC_DECODE -+}; -+ -+enum nfiecc_deccon { -+ ECC_DEC_FER = 1, -+ ECC_DEC_LOCATE = 2, -+ ECC_DEC_CORRECT = 3 -+}; -+ -+struct nfiecc_resource { -+ int ic_ver; -+ void *dev; -+ void *regs; -+ int irq_id; -+ -+}; -+ -+struct nfiecc_status { -+ u32 corrected; -+ u32 failed; -+ u32 bitflips; -+}; -+ -+struct nfiecc_caps { -+ u32 err_mask; -+ u32 ecc_mode_shift; -+ u32 parity_bits; -+ const int *ecc_strength; -+ u32 ecc_strength_num; -+}; -+ -+struct nfiecc_config { -+ enum nfiecc_operation op; -+ enum nfiecc_mode mode; -+ enum nfiecc_deccon deccon; -+ -+ void *dma_addr; /* DMA use only */ -+ u32 strength; -+ u32 sectors; -+ u32 len; -+}; -+ -+struct nfiecc { -+ struct nfiecc_resource res; -+ struct nfiecc_config config; -+ struct nfiecc_caps *caps; -+ -+ bool ecc_irq_en; -+ bool page_irq_en; -+ -+ void *done; -+ -+ int (*adjust_strength)(struct nfiecc *ecc, int strength); -+ int (*enable)(struct nfiecc *ecc); -+ int (*disable)(struct nfiecc *ecc); -+ -+ int (*decode)(struct nfiecc *ecc, u8 *data); -+ int (*encode)(struct nfiecc *ecc, u8 *data); -+ -+ int (*decode_status)(struct nfiecc *ecc, u32 start_sector, u32 sectors); -+ int (*correct_data)(struct nfiecc *ecc, -+ struct nfiecc_status *status, -+ u8 *data, u32 sector); -+ int (*wait_done)(struct nfiecc *ecc); -+ -+ int (*nfiecc_ctrl)(struct nfiecc *ecc, int cmd, void *args); -+}; -+ -+struct nfiecc *nfiecc_init(struct nfiecc_resource *res); -+void nfiecc_exit(struct nfiecc *ecc); -+ -+#endif /* __NFIECC_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/core/nfi/nfiecc_regs.h -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NFIECC_REGS_H__ -+#define __NFIECC_REGS_H__ -+ -+#define NFIECC_ENCCON 0x000 -+/* NFIECC_DECCON has same bit define */ -+#define ECC_OP_EN BIT(0) -+#define NFIECC_ENCCNFG 0x004 -+#define ENCCNFG_MS_SHIFT 16 -+#define ENC_BURST_EN BIT(8) -+#define NFIECC_ENCDIADDR 0x008 -+#define NFIECC_ENCIDLE 0x00c -+#define NFIECC_ENCSTA 0x02c -+#define ENC_FSM_IDLE 1 -+#define NFIECC_ENCIRQEN 0x030 -+/* NFIECC_DECIRQEN has same bit define */ -+#define ECC_IRQEN BIT(0) -+#define ECC_PG_IRQ_SEL BIT(1) -+#define NFIECC_ENCIRQSTA 0x034 -+#define ENC_IRQSTA_GEN BIT(0) -+#define NFIECC_PIO_DIRDY 0x080 -+#define PIO_DI_RDY BIT(0) -+#define NFIECC_PIO_DI 0x084 -+#define NFIECC_DECCON 0x100 -+#define NFIECC_DECCNFG 0x104 -+#define DEC_BURST_EN BIT(8) -+#define DEC_EMPTY_EN BIT(31) -+#define DEC_CON_SHIFT 12 -+#define DECCNFG_MS_SHIFT 16 -+#define NFIECC_DECDIADDR 0x108 -+#define NFIECC_DECIDLE 0x10c -+#define NFIECC_DECENUM(x) (0x114 + (x) * 4) -+#define NFIECC_DECDONE 0x11c -+#define NFIECC_DECIRQEN 0x140 -+#define NFIECC_DECIRQSTA 0x144 -+#define DEC_IRQSTA_GEN BIT(0) -+#define NFIECC_DECFSM 0x14c -+#define FSM_MASK 0x7f0f0f0f -+#define FSM_IDLE 0x01010101 -+#define NFIECC_BYPASS 0x20c -+#define NFIECC_BYPASS_EN BIT(0) -+#define NFIECC_ENCPAR(x) (0x010 + (x) * 4) -+#define NFIECC_DECEL(x) (0x120 + (x) * 4) -+ -+#endif /* __NFIECC_REGS_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/driver/Nandx.mk -@@ -0,0 +1,18 @@ -+# -+# Copyright (C) 2017 MediaTek Inc. -+# Licensed under either -+# BSD Licence, (see NOTICE for more details) -+# GNU General Public License, version 2.0, (see NOTICE for more details) -+# -+ -+nandx-$(NANDX_SIMULATOR_SUPPORT) += simulator/driver.c -+ -+nandx-$(NANDX_CTP_SUPPORT) += ctp/ts_nand.c -+nandx-$(NANDX_CTP_SUPPORT) += ctp/nand_test.c -+nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nand_test.h -+ -+nandx-$(NANDX_BBT_SUPPORT) += bbt/bbt.c -+nandx-$(NANDX_BROM_SUPPORT) += brom/driver.c -+nandx-$(NANDX_KERNEL_SUPPORT) += kernel/driver.c -+nandx-$(NANDX_LK_SUPPORT) += lk/driver.c -+nandx-$(NANDX_UBOOT_SUPPORT) += uboot/driver.c ---- /dev/null -+++ b/drivers/mtd/nandx/driver/bbt/bbt.c -@@ -0,0 +1,408 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include "nandx_util.h" -+#include "nandx_core.h" -+#include "bbt.h" -+ -+/* Not support: multi-chip */ -+static u8 main_bbt_pattern[] = {'B', 'b', 't', '0' }; -+static u8 mirror_bbt_pattern[] = {'1', 't', 'b', 'B' }; -+ -+static struct bbt_manager g_bbt_manager = { -+ { {{main_bbt_pattern, 4}, 0, BBT_INVALID_ADDR}, -+ {{mirror_bbt_pattern, 4}, 0, BBT_INVALID_ADDR} -+ }, -+ NAND_BBT_SCAN_MAXBLOCKS, NULL -+}; -+ -+static inline void set_bbt_mark(u8 *bbt, int block, u8 mark) -+{ -+ int index, offset; -+ -+ index = GET_ENTRY(block); -+ offset = GET_POSITION(block); -+ -+ bbt[index] &= ~(BBT_ENTRY_MASK << offset); -+ bbt[index] |= (mark & BBT_ENTRY_MASK) << offset; -+ pr_info("%s %d block:%d, bbt[%d]:0x%x, offset:%d, mark:%d\n", -+ __func__, __LINE__, block, index, bbt[index], offset, mark); -+} -+ -+static inline u8 get_bbt_mark(u8 *bbt, int block) -+{ -+ int offset = GET_POSITION(block); -+ int index = GET_ENTRY(block); -+ u8 value = bbt[index]; -+ -+ return (value >> offset) & BBT_ENTRY_MASK; -+} -+ -+static void mark_nand_bad(struct nandx_info *nand, int block) -+{ -+ u8 *buf; -+ -+ buf = mem_alloc(1, nand->page_size + nand->oob_size); -+ if (!buf) { -+ pr_info("%s, %d, memory alloc fail, pagesize:%d, oobsize:%d\n", -+ __func__, __LINE__, nand->page_size, nand->oob_size); -+ return; -+ } -+ memset(buf, 0, nand->page_size + nand->oob_size); -+ nandx_erase(block * nand->block_size, nand->block_size); -+ nandx_write(buf, buf + nand->page_size, block * nand->block_size, -+ nand->page_size); -+ mem_free(buf); -+} -+ -+static inline bool is_bbt_data(u8 *buf, struct bbt_pattern *pattern) -+{ -+ int i; -+ -+ for (i = 0; i < pattern->len; i++) { -+ if (buf[i] != pattern->data[i]) -+ return false; -+ } -+ -+ return true; -+} -+ -+static u64 get_bbt_address(struct nandx_info *nand, u8 *bbt, -+ u64 mirror_addr, -+ int max_blocks) -+{ -+ u64 addr, end_addr; -+ u8 mark; -+ -+ addr = nand->total_size; -+ end_addr = nand->total_size - nand->block_size * max_blocks; -+ -+ while (addr > end_addr) { -+ addr -= nand->block_size; -+ mark = get_bbt_mark(bbt, div_down(addr, nand->block_size)); -+ -+ if (mark == BBT_BLOCK_WORN || mark == BBT_BLOCK_FACTORY_BAD) -+ continue; -+ if (addr != mirror_addr) -+ return addr; -+ } -+ -+ return BBT_INVALID_ADDR; -+} -+ -+static int read_bbt(struct bbt_desc *desc, u8 *bbt, u32 len) -+{ -+ int ret; -+ -+ ret = nandx_read(bbt, NULL, desc->bbt_addr + desc->pattern.len + 1, -+ len); -+ if (ret < 0) -+ pr_info("nand_bbt: error reading BBT page, ret:-%x\n", ret); -+ -+ return ret; -+} -+ -+static void create_bbt(struct nandx_info *nand, u8 *bbt) -+{ -+ u32 offset = 0, block = 0; -+ -+ do { -+ if (nandx_is_bad_block(offset)) { -+ pr_info("Create bbt at bad block:%d\n", block); -+ set_bbt_mark(bbt, block, BBT_BLOCK_FACTORY_BAD); -+ } -+ block++; -+ offset += nand->block_size; -+ } while (offset < nand->total_size); -+} -+ -+static int search_bbt(struct nandx_info *nand, struct bbt_desc *desc, -+ int max_blocks) -+{ -+ u64 addr, end_addr; -+ u8 *buf; -+ int ret; -+ -+ buf = mem_alloc(1, nand->page_size); -+ if (!buf) { -+ pr_info("%s, %d, mem alloc fail!!! len:%d\n", -+ __func__, __LINE__, nand->page_size); -+ return -ENOMEM; -+ } -+ -+ addr = nand->total_size; -+ end_addr = nand->total_size - max_blocks * nand->block_size; -+ while (addr > end_addr) { -+ addr -= nand->block_size; -+ -+ nandx_read(buf, NULL, addr, nand->page_size); -+ -+ if (is_bbt_data(buf, &desc->pattern)) { -+ desc->bbt_addr = addr; -+ desc->version = buf[desc->pattern.len]; -+ pr_info("BBT is found at addr 0x%llx, version %d\n", -+ desc->bbt_addr, desc->version); -+ ret = 0; -+ break; -+ } -+ ret = -EFAULT; -+ } -+ -+ mem_free(buf); -+ return ret; -+} -+ -+static int save_bbt(struct nandx_info *nand, struct bbt_desc *desc, -+ u8 *bbt) -+{ -+ u32 page_size_mask, total_block; -+ int write_len; -+ u8 *buf; -+ int ret; -+ -+ ret = nandx_erase(desc->bbt_addr, nand->block_size); -+ if (ret) { -+ pr_info("erase addr 0x%llx fail !!!, ret %d\n", -+ desc->bbt_addr, ret); -+ return ret; -+ } -+ -+ total_block = div_down(nand->total_size, nand->block_size); -+ write_len = GET_BBT_LENGTH(total_block) + desc->pattern.len + 1; -+ page_size_mask = nand->page_size - 1; -+ write_len = (write_len + page_size_mask) & (~page_size_mask); -+ -+ buf = (u8 *)mem_alloc(1, write_len); -+ if (!buf) { -+ pr_info("%s, %d, mem alloc fail!!! len:%d\n", -+ __func__, __LINE__, write_len); -+ return -ENOMEM; -+ } -+ memset(buf, 0xFF, write_len); -+ -+ memcpy(buf, desc->pattern.data, desc->pattern.len); -+ buf[desc->pattern.len] = desc->version; -+ -+ memcpy(buf + desc->pattern.len + 1, bbt, GET_BBT_LENGTH(total_block)); -+ -+ ret = nandx_write(buf, NULL, desc->bbt_addr, write_len); -+ -+ if (ret) -+ pr_info("nandx_write fail(%d), offset:0x%llx, len(%d)\n", -+ ret, desc->bbt_addr, write_len); -+ mem_free(buf); -+ -+ return ret; -+} -+ -+static int write_bbt(struct nandx_info *nand, struct bbt_desc *main, -+ struct bbt_desc *mirror, u8 *bbt, int max_blocks) -+{ -+ int block; -+ int ret; -+ -+ do { -+ if (main->bbt_addr == BBT_INVALID_ADDR) { -+ main->bbt_addr = get_bbt_address(nand, bbt, -+ mirror->bbt_addr, max_blocks); -+ if (main->bbt_addr == BBT_INVALID_ADDR) -+ return -ENOSPC; -+ } -+ -+ ret = save_bbt(nand, main, bbt); -+ if (!ret) -+ break; -+ -+ block = div_down(main->bbt_addr, nand->block_size); -+ set_bbt_mark(bbt, block, BBT_BLOCK_WORN); -+ main->version++; -+ mark_nand_bad(nand, block); -+ main->bbt_addr = BBT_INVALID_ADDR; -+ } while (1); -+ -+ return 0; -+} -+ -+static void mark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks) -+{ -+ int total_block; -+ int block; -+ u8 mark; -+ -+ total_block = div_down(nand->total_size, nand->block_size); -+ block = total_block - bbt_blocks; -+ -+ while (bbt_blocks) { -+ mark = get_bbt_mark(bbt, block); -+ if (mark == BBT_BLOCK_GOOD) -+ set_bbt_mark(bbt, block, BBT_BLOCK_RESERVED); -+ block++; -+ bbt_blocks--; -+ } -+} -+ -+static void unmark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks) -+{ -+ int total_block; -+ int block; -+ u8 mark; -+ -+ total_block = div_down(nand->total_size, nand->block_size); -+ block = total_block - bbt_blocks; -+ -+ while (bbt_blocks) { -+ mark = get_bbt_mark(bbt, block); -+ if (mark == BBT_BLOCK_RESERVED) -+ set_bbt_mark(bbt, block, BBT_BLOCK_GOOD); -+ block++; -+ bbt_blocks--; -+ } -+} -+ -+static int update_bbt(struct nandx_info *nand, struct bbt_desc *desc, -+ u8 *bbt, -+ int max_blocks) -+{ -+ int ret = 0, i; -+ -+ /* The reserved info is not stored in NAND*/ -+ unmark_bbt_region(nand, bbt, max_blocks); -+ -+ desc[0].version++; -+ for (i = 0; i < 2; i++) { -+ if (i > 0) -+ desc[i].version = desc[i - 1].version; -+ -+ ret = write_bbt(nand, &desc[i], &desc[1 - i], bbt, max_blocks); -+ if (ret) -+ break; -+ } -+ mark_bbt_region(nand, bbt, max_blocks); -+ -+ return ret; -+} -+ -+int scan_bbt(struct nandx_info *nand) -+{ -+ struct bbt_manager *manager = &g_bbt_manager; -+ struct bbt_desc *pdesc; -+ int total_block, len, i; -+ int valid_desc = 0; -+ int ret = 0; -+ u8 *bbt; -+ -+ total_block = div_down(nand->total_size, nand->block_size); -+ len = GET_BBT_LENGTH(total_block); -+ -+ if (!manager->bbt) { -+ manager->bbt = (u8 *)mem_alloc(1, len); -+ if (!manager->bbt) { -+ pr_info("%s, %d, mem alloc fail!!! len:%d\n", -+ __func__, __LINE__, len); -+ return -ENOMEM; -+ } -+ } -+ bbt = manager->bbt; -+ memset(bbt, 0xFF, len); -+ -+ /* scan bbt */ -+ for (i = 0; i < 2; i++) { -+ pdesc = &manager->desc[i]; -+ pdesc->bbt_addr = BBT_INVALID_ADDR; -+ pdesc->version = 0; -+ ret = search_bbt(nand, pdesc, manager->max_blocks); -+ if (!ret && (pdesc->bbt_addr != BBT_INVALID_ADDR)) -+ valid_desc += 1 << i; -+ } -+ -+ pdesc = &manager->desc[0]; -+ if ((valid_desc == 0x3) && (pdesc[0].version != pdesc[1].version)) -+ valid_desc = (pdesc[0].version > pdesc[1].version) ? 1 : 2; -+ -+ /* read bbt */ -+ for (i = 0; i < 2; i++) { -+ if (!(valid_desc & (1 << i))) -+ continue; -+ ret = read_bbt(&pdesc[i], bbt, len); -+ if (ret) { -+ pdesc->bbt_addr = BBT_INVALID_ADDR; -+ pdesc->version = 0; -+ valid_desc &= ~(1 << i); -+ } -+ /* If two BBT version is same, only need to read the first bbt*/ -+ if ((valid_desc == 0x3) && -+ (pdesc[0].version == pdesc[1].version)) -+ break; -+ } -+ -+ if (!valid_desc) { -+ create_bbt(nand, bbt); -+ pdesc[0].version = 1; -+ pdesc[1].version = 1; -+ } -+ -+ pdesc[0].version = max_t(u8, pdesc[0].version, pdesc[1].version); -+ pdesc[1].version = pdesc[0].version; -+ -+ for (i = 0; i < 2; i++) { -+ if (valid_desc & (1 << i)) -+ continue; -+ -+ ret = write_bbt(nand, &pdesc[i], &pdesc[1 - i], bbt, -+ manager->max_blocks); -+ if (ret) { -+ pr_info("write bbt(%d) fail, ret:%d\n", i, ret); -+ manager->bbt = NULL; -+ return ret; -+ } -+ } -+ -+ /* Prevent the bbt regions from erasing / writing */ -+ mark_bbt_region(nand, manager->bbt, manager->max_blocks); -+ -+ for (i = 0; i < total_block; i++) { -+ if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_WORN) -+ pr_info("Checked WORN bad blk: %d\n", i); -+ else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_FACTORY_BAD) -+ pr_info("Checked Factory bad blk: %d\n", i); -+ else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_RESERVED) -+ pr_info("Checked Reserved blk: %d\n", i); -+ else if (get_bbt_mark(manager->bbt, i) != BBT_BLOCK_GOOD) -+ pr_info("Checked unknown blk: %d\n", i); -+ } -+ -+ return 0; -+} -+ -+int bbt_mark_bad(struct nandx_info *nand, off_t offset) -+{ -+ struct bbt_manager *manager = &g_bbt_manager; -+ int block = div_down(offset, nand->block_size); -+ int ret = 0; -+ -+ mark_nand_bad(nand, block); -+ -+#if 0 -+ set_bbt_mark(manager->bbt, block, BBT_BLOCK_WORN); -+ -+ /* Update flash-based bad block table */ -+ ret = update_bbt(nand, manager->desc, manager->bbt, -+ manager->max_blocks); -+#endif -+ pr_info("block %d, update result %d.\n", block, ret); -+ -+ return ret; -+} -+ -+int bbt_is_bad(struct nandx_info *nand, off_t offset) -+{ -+ int block; -+ -+ block = div_down(offset, nand->block_size); -+ -+ return get_bbt_mark(g_bbt_manager.bbt, block) != BBT_BLOCK_GOOD; -+} ---- /dev/null -+++ b/drivers/mtd/nandx/driver/uboot/driver.c -@@ -0,0 +1,574 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "nandx_core.h" -+#include "nandx_util.h" -+#include "bbt.h" -+ -+typedef int (*func_nandx_operation)(u8 *, u8 *, u64, size_t); -+ -+struct nandx_clk { -+ struct clk *nfi_clk; -+ struct clk *ecc_clk; -+ struct clk *snfi_clk; -+ struct clk *snfi_clk_sel; -+ struct clk *snfi_parent_50m; -+}; -+ -+struct nandx_nfc { -+ struct nandx_info info; -+ struct nandx_clk clk; -+ struct nfi_resource *res; -+ -+ struct nand_chip *nand; -+ spinlock_t lock; -+}; -+ -+/* Default flash layout for MTK nand controller -+ * 64Bytes oob format. -+ */ -+static struct nand_ecclayout eccoob = { -+ .eccbytes = 42, -+ .eccpos = { -+ 17, 18, 19, 20, 21, 22, 23, 24, 25, -+ 26, 27, 28, 29, 30, 31, 32, 33, 34, -+ 35, 36, 37, 38, 39, 40, 41 -+ }, -+ .oobavail = 16, -+ .oobfree = { -+ { -+ .offset = 0, -+ .length = 16, -+ }, -+ } -+}; -+ -+static struct nandx_nfc *mtd_to_nfc(struct mtd_info *mtd) -+{ -+ struct nand_chip *nand = mtd_to_nand(mtd); -+ -+ return (struct nandx_nfc *)nand_get_controller_data(nand); -+} -+ -+static int nandx_enable_clk(struct nandx_clk *clk) -+{ -+ int ret; -+ -+ ret = clk_enable(clk->nfi_clk); -+ if (ret) { -+ pr_info("failed to enable nfi clk\n"); -+ return ret; -+ } -+ -+ ret = clk_enable(clk->ecc_clk); -+ if (ret) { -+ pr_info("failed to enable ecc clk\n"); -+ goto disable_nfi_clk; -+ } -+ -+ ret = clk_enable(clk->snfi_clk); -+ if (ret) { -+ pr_info("failed to enable snfi clk\n"); -+ goto disable_ecc_clk; -+ } -+ -+ ret = clk_enable(clk->snfi_clk_sel); -+ if (ret) { -+ pr_info("failed to enable snfi clk sel\n"); -+ goto disable_snfi_clk; -+ } -+ -+ ret = clk_set_parent(clk->snfi_clk_sel, clk->snfi_parent_50m); -+ if (ret) { -+ pr_info("failed to set snfi parent 50MHz\n"); -+ goto disable_snfi_clk; -+ } -+ -+ return 0; -+ -+disable_snfi_clk: -+ clk_disable(clk->snfi_clk); -+disable_ecc_clk: -+ clk_disable(clk->ecc_clk); -+disable_nfi_clk: -+ clk_disable(clk->nfi_clk); -+ -+ return ret; -+} -+ -+static void nandx_disable_clk(struct nandx_clk *clk) -+{ -+ clk_disable(clk->ecc_clk); -+ clk_disable(clk->nfi_clk); -+ clk_disable(clk->snfi_clk); -+} -+ -+static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oob_region) -+{ -+ struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd); -+ u32 eccsteps; -+ -+ eccsteps = div_down(mtd->writesize, mtd->ecc_step_size); -+ -+ if (section >= eccsteps) -+ return -EINVAL; -+ -+ oob_region->length = nfc->info.fdm_reg_size - nfc->info.fdm_ecc_size; -+ oob_region->offset = section * nfc->info.fdm_reg_size -+ + nfc->info.fdm_ecc_size; -+ -+ return 0; -+} -+ -+static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oob_region) -+{ -+ struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd); -+ u32 eccsteps; -+ -+ if (section) -+ return -EINVAL; -+ -+ eccsteps = div_down(mtd->writesize, mtd->ecc_step_size); -+ oob_region->offset = nfc->info.fdm_reg_size * eccsteps; -+ oob_region->length = mtd->oobsize - oob_region->offset; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = { -+ .rfree = mtk_nfc_ooblayout_free, -+ .ecc = mtk_nfc_ooblayout_ecc, -+}; -+ -+struct nfc_compatible { -+ enum mtk_ic_version ic_ver; -+ -+ u32 clock_1x; -+ u32 *clock_2x; -+ int clock_2x_num; -+ -+ int min_oob_req; -+}; -+ -+static const struct nfc_compatible nfc_compats_mt7622 = { -+ .ic_ver = NANDX_MT7622, -+ .clock_1x = 26000000, -+ .clock_2x = NULL, -+ .clock_2x_num = 8, -+ .min_oob_req = 1, -+}; -+ -+static const struct udevice_id ic_of_match[] = { -+ {.compatible = "mediatek,mt7622-nfc", .data = &nfc_compats_mt7622}, -+ {} -+}; -+ -+static int nand_operation(struct mtd_info *mtd, loff_t addr, size_t len, -+ size_t *retlen, uint8_t *data, uint8_t *oob, bool read) -+{ -+ struct nandx_split64 split = {0}; -+ func_nandx_operation operation; -+ u64 block_oobs, val, align; -+ uint8_t *databuf, *oobbuf; -+ struct nandx_nfc *nfc; -+ bool readoob; -+ int ret = 0; -+ -+ nfc = (struct nandx_nfc *)nand_get_controller_data; -+ spin_lock(&nfc->lock); -+ -+ databuf = data; -+ oobbuf = oob; -+ -+ readoob = data ? false : true; -+ block_oobs = div_up(mtd->erasesize, mtd->writesize) * mtd->oobavail; -+ align = readoob ? block_oobs : mtd->erasesize; -+ -+ operation = read ? nandx_read : nandx_write; -+ -+ nandx_split(&split, addr, len, val, align); -+ -+ if (split.head_len) { -+ ret = operation((u8 *) databuf, oobbuf, addr, split.head_len); -+ -+ if (databuf) -+ databuf += split.head_len; -+ -+ if (oobbuf) -+ oobbuf += split.head_len; -+ -+ addr += split.head_len; -+ *retlen += split.head_len; -+ } -+ -+ if (split.body_len) { -+ while (div_up(split.body_len, align)) { -+ ret = operation((u8 *) databuf, oobbuf, addr, align); -+ -+ if (databuf) { -+ databuf += mtd->erasesize; -+ split.body_len -= mtd->erasesize; -+ *retlen += mtd->erasesize; -+ } -+ -+ if (oobbuf) { -+ oobbuf += block_oobs; -+ split.body_len -= block_oobs; -+ *retlen += block_oobs; -+ } -+ -+ addr += mtd->erasesize; -+ } -+ -+ } -+ -+ if (split.tail_len) { -+ ret = operation((u8 *) databuf, oobbuf, addr, split.tail_len); -+ *retlen += split.tail_len; -+ } -+ -+ spin_unlock(&nfc->lock); -+ -+ return ret; -+} -+ -+static int mtk_nand_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ return nand_operation(mtd, from, len, retlen, buf, NULL, true); -+} -+ -+static int mtk_nand_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ return nand_operation(mtd, to, len, retlen, (uint8_t *)buf, -+ NULL, false); -+} -+ -+int mtk_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) -+{ -+ size_t retlen; -+ -+ return nand_operation(mtd, from, ops->ooblen, &retlen, NULL, -+ ops->oobbuf, true); -+} -+ -+int mtk_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) -+{ -+ size_t retlen; -+ -+ return nand_operation(mtd, to, ops->ooblen, &retlen, NULL, -+ ops->oobbuf, false); -+} -+ -+static int mtk_nand_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct nandx_nfc *nfc; -+ u64 erase_len, erase_addr; -+ u32 block_size; -+ int ret = 0; -+ -+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd); -+ block_size = nfc->info.block_size; -+ erase_len = instr->len; -+ erase_addr = instr->addr; -+ spin_lock(&nfc->lock); -+ instr->state = MTD_ERASING; -+ -+ while (erase_len) { -+ if (mtk_nand_is_bad(mtd, erase_addr)) { -+ pr_info("block(0x%llx) is bad, not erase\n", -+ erase_addr); -+ instr->state = MTD_ERASE_FAILED; -+ goto erase_exit; -+ } else { -+ ret = nandx_erase(erase_addr, block_size); -+ if (ret < 0) { -+ instr->state = MTD_ERASE_FAILED; -+ goto erase_exit; -+ pr_info("erase fail at blk %llu, ret:%d\n", -+ erase_addr, ret); -+ } -+ } -+ erase_addr += block_size; -+ erase_len -= block_size; -+ } -+ -+ instr->state = MTD_ERASE_DONE; -+ -+erase_exit: -+ ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; -+ -+ spin_unlock(&nfc->lock); -+ /* Do mtd call back function */ -+ if (!ret) -+ mtd_erase_callback(instr); -+ -+ return ret; -+} -+ -+int mtk_nand_is_bad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nandx_nfc *nfc; -+ int ret; -+ -+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd); -+ spin_lock(&nfc->lock); -+ -+ /*ret = bbt_is_bad(&nfc->info, ofs);*/ -+ ret = nandx_is_bad_block(ofs); -+ spin_unlock(&nfc->lock); -+ -+ if (ret) { -+ pr_info("nand block 0x%x is bad, ret %d!\n", ofs, ret); -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+int mtk_nand_mark_bad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nandx_nfc *nfc; -+ int ret; -+ -+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd); -+ spin_lock(&nfc->lock); -+ pr_info("%s, %d\n", __func__, __LINE__); -+ ret = bbt_mark_bad(&nfc->info, ofs); -+ -+ spin_unlock(&nfc->lock); -+ -+ return ret; -+} -+ -+void mtk_nand_sync(struct mtd_info *mtd) -+{ -+ nandx_sync(); -+} -+ -+static struct mtd_info *mtd_info_create(struct udevice *pdev, -+ struct nandx_nfc *nfc, struct nand_chip *nand) -+{ -+ struct mtd_info *mtd = nand_to_mtd(nand); -+ int ret; -+ -+ nand_set_controller_data(nand, nfc); -+ -+ nand->flash_node = dev_of_offset(pdev); -+ nand->ecc.layout = &eccoob; -+ -+ ret = nandx_ioctl(CORE_CTRL_NAND_INFO, &nfc->info); -+ if (ret) { -+ pr_info("fail to get nand info (%d)!\n", ret); -+ mem_free(mtd); -+ return NULL; -+ } -+ -+ mtd->owner = THIS_MODULE; -+ -+ mtd->name = "MTK-SNand"; -+ mtd->writesize = nfc->info.page_size; -+ mtd->erasesize = nfc->info.block_size; -+ mtd->oobsize = nfc->info.oob_size; -+ mtd->size = nfc->info.total_size; -+ mtd->type = MTD_NANDFLASH; -+ mtd->flags = MTD_CAP_NANDFLASH; -+ mtd->_erase = mtk_nand_erase; -+ mtd->_read = mtk_nand_read; -+ mtd->_write = mtk_nand_write; -+ mtd->_read_oob = mtk_nand_read_oob; -+ mtd->_write_oob = mtk_nand_write_oob; -+ mtd->_sync = mtk_nand_sync; -+ mtd->_lock = NULL; -+ mtd->_unlock = NULL; -+ mtd->_block_isbad = mtk_nand_is_bad; -+ mtd->_block_markbad = mtk_nand_mark_bad; -+ mtd->writebufsize = mtd->writesize; -+ -+ mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops); -+ -+ mtd->ecc_strength = nfc->info.ecc_strength; -+ mtd->ecc_step_size = nfc->info.sector_size; -+ -+ if (!mtd->bitflip_threshold) -+ mtd->bitflip_threshold = mtd->ecc_strength; -+ -+ return mtd; -+} -+ -+int board_nand_init(struct nand_chip *nand) -+{ -+ struct udevice *dev; -+ struct mtd_info *mtd; -+ struct nandx_nfc *nfc; -+ int arg = 1; -+ int ret; -+ -+ ret = uclass_get_device_by_driver(UCLASS_MTD, -+ DM_GET_DRIVER(mtk_snand_drv), -+ &dev); -+ if (ret) { -+ pr_err("Failed to get mtk_nand_drv. (error %d)\n", ret); -+ return ret; -+ } -+ -+ nfc = dev_get_priv(dev); -+ -+ ret = nandx_enable_clk(&nfc->clk); -+ if (ret) { -+ pr_err("failed to enable nfi clk (error %d)\n", ret); -+ return ret; -+ } -+ -+ ret = nandx_init(nfc->res); -+ if (ret) { -+ pr_err("nandx init error (%d)!\n", ret); -+ goto disable_clk; -+ } -+ -+ arg = 1; -+ nandx_ioctl(NFI_CTRL_DMA, &arg); -+ nandx_ioctl(NFI_CTRL_ECC, &arg); -+ -+#ifdef NANDX_UNIT_TEST -+ nandx_unit_test(0x780000, 0x800); -+#endif -+ -+ mtd = mtd_info_create(dev, nfc, nand); -+ if (!mtd) { -+ ret = -ENOMEM; -+ goto disable_clk; -+ } -+ -+ spin_lock_init(&nfc->lock); -+#if 0 -+ ret = scan_bbt(&nfc->info); -+ if (ret) { -+ pr_info("bbt init error (%d)!\n", ret); -+ goto disable_clk; -+ } -+#endif -+ return ret; -+ -+disable_clk: -+ nandx_disable_clk(&nfc->clk); -+ -+ return ret; -+} -+ -+static int mtk_snand_ofdata_to_platdata(struct udevice *dev) -+{ -+ struct nandx_nfc *nfc = dev_get_priv(dev); -+ struct nfc_compatible *compat; -+ struct nfi_resource *res; -+ -+ int ret = 0; -+ -+ res = mem_alloc(1, sizeof(struct nfi_resource)); -+ if (!res) -+ return -ENOMEM; -+ -+ nfc->res = res; -+ -+ res->nfi_regs = (void *)dev_read_addr_index(dev, 0); -+ res->ecc_regs = (void *)dev_read_addr_index(dev, 1); -+ pr_debug("mtk snand nfi_regs:0x%x ecc_regs:0x%x\n", -+ res->nfi_regs, res->ecc_regs); -+ -+ compat = (struct nfc_compatible *)dev_get_driver_data(dev); -+ -+ res->ic_ver = (enum mtk_ic_version)(compat->ic_ver); -+ res->clock_1x = compat->clock_1x; -+ res->clock_2x = compat->clock_2x; -+ res->clock_2x_num = compat->clock_2x_num; -+ -+ memset(&nfc->clk, 0, sizeof(struct nandx_clk)); -+ nfc->clk.nfi_clk = -+ kmalloc(sizeof(*nfc->clk.nfi_clk), GFP_KERNEL); -+ nfc->clk.ecc_clk = -+ kmalloc(sizeof(*nfc->clk.ecc_clk), GFP_KERNEL); -+ nfc->clk.snfi_clk= -+ kmalloc(sizeof(*nfc->clk.snfi_clk), GFP_KERNEL); -+ nfc->clk.snfi_clk_sel = -+ kmalloc(sizeof(*nfc->clk.snfi_clk_sel), GFP_KERNEL); -+ nfc->clk.snfi_parent_50m = -+ kmalloc(sizeof(*nfc->clk.snfi_parent_50m), GFP_KERNEL); -+ -+ if (!nfc->clk.nfi_clk || !nfc->clk.ecc_clk || !nfc->clk.snfi_clk || -+ !nfc->clk.snfi_clk_sel || !nfc->clk.snfi_parent_50m) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ ret = clk_get_by_name(dev, "nfi_clk", nfc->clk.nfi_clk); -+ if (IS_ERR(nfc->clk.nfi_clk)) { -+ ret = PTR_ERR(nfc->clk.nfi_clk); -+ goto err; -+ } -+ -+ ret = clk_get_by_name(dev, "ecc_clk", nfc->clk.ecc_clk); -+ if (IS_ERR(nfc->clk.ecc_clk)) { -+ ret = PTR_ERR(nfc->clk.ecc_clk); -+ goto err; -+ } -+ -+ ret = clk_get_by_name(dev, "snfi_clk", nfc->clk.snfi_clk); -+ if (IS_ERR(nfc->clk.snfi_clk)) { -+ ret = PTR_ERR(nfc->clk.snfi_clk); -+ goto err; -+ } -+ -+ ret = clk_get_by_name(dev, "spinfi_sel", nfc->clk.snfi_clk_sel); -+ if (IS_ERR(nfc->clk.snfi_clk_sel)) { -+ ret = PTR_ERR(nfc->clk.snfi_clk_sel); -+ goto err; -+ } -+ -+ ret = clk_get_by_name(dev, "spinfi_parent_50m", nfc->clk.snfi_parent_50m); -+ if (IS_ERR(nfc->clk.snfi_parent_50m)) -+ pr_info("spinfi parent 50MHz is not configed\n"); -+ -+ return 0; -+err: -+ if (nfc->clk.nfi_clk) -+ kfree(nfc->clk.nfi_clk); -+ if (nfc->clk.snfi_clk) -+ kfree(nfc->clk.snfi_clk); -+ if (nfc->clk.ecc_clk) -+ kfree(nfc->clk.ecc_clk); -+ if (nfc->clk.snfi_clk_sel) -+ kfree(nfc->clk.snfi_clk_sel); -+ if (nfc->clk.snfi_parent_50m) -+ kfree(nfc->clk.snfi_parent_50m); -+ -+ return ret; -+} -+ -+U_BOOT_DRIVER(mtk_snand_drv) = { -+ .name = "mtk_snand", -+ .id = UCLASS_MTD, -+ .of_match = ic_of_match, -+ .ofdata_to_platdata = mtk_snand_ofdata_to_platdata, -+ .priv_auto_alloc_size = sizeof(struct nandx_nfc), -+}; -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver"); -+MODULE_AUTHOR("MediaTek"); ---- /dev/null -+++ b/drivers/mtd/nandx/include/Nandx.mk -@@ -0,0 +1,16 @@ -+# -+# Copyright (C) 2017 MediaTek Inc. -+# Licensed under either -+# BSD Licence, (see NOTICE for more details) -+# GNU General Public License, version 2.0, (see NOTICE for more details) -+# -+ -+nandx-header-y += internal/nandx_core.h -+nandx-header-y += internal/nandx_errno.h -+nandx-header-y += internal/nandx_util.h -+nandx-header-$(NANDX_BBT_SUPPORT) += internal/bbt.h -+nandx-header-$(NANDX_SIMULATOR_SUPPORT) += simulator/nandx_os.h -+nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nandx_os.h -+nandx-header-$(NANDX_LK_SUPPORT) += lk/nandx_os.h -+nandx-header-$(NANDX_KERNEL_SUPPORT) += kernel/nandx_os.h -+nandx-header-$(NANDX_UBOOT_SUPPORT) += uboot/nandx_os.h ---- /dev/null -+++ b/drivers/mtd/nandx/include/internal/bbt.h -@@ -0,0 +1,62 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __BBT_H__ -+#define __BBT_H__ -+ -+#define BBT_BLOCK_GOOD 0x03 -+#define BBT_BLOCK_WORN 0x02 -+#define BBT_BLOCK_RESERVED 0x01 -+#define BBT_BLOCK_FACTORY_BAD 0x00 -+ -+#define BBT_INVALID_ADDR 0 -+/* The maximum number of blocks to scan for a bbt */ -+#define NAND_BBT_SCAN_MAXBLOCKS 4 -+#define NAND_BBT_USE_FLASH 0x00020000 -+#define NAND_BBT_NO_OOB 0x00040000 -+ -+/* Search good / bad pattern on the first and the second page */ -+#define NAND_BBT_SCAN2NDPAGE 0x00008000 -+/* Search good / bad pattern on the last page of the eraseblock */ -+#define NAND_BBT_SCANLASTPAGE 0x00010000 -+ -+#define NAND_DRAM_BUF_DATABUF_ADDR (NAND_BUF_ADDR) -+ -+struct bbt_pattern { -+ u8 *data; -+ int len; -+}; -+ -+struct bbt_desc { -+ struct bbt_pattern pattern; -+ u8 version; -+ u64 bbt_addr;/*0: invalid value; otherwise, valid value*/ -+}; -+ -+struct bbt_manager { -+ /* main bbt descriptor and mirror descriptor */ -+ struct bbt_desc desc[2];/* 0: main bbt; 1: mirror bbt */ -+ int max_blocks; -+ u8 *bbt; -+}; -+ -+#define BBT_ENTRY_MASK 0x03 -+#define BBT_ENTRY_SHIFT 2 -+ -+#define GET_BBT_LENGTH(blocks) (blocks >> 2) -+#define GET_ENTRY(block) ((block) >> BBT_ENTRY_SHIFT) -+#define GET_POSITION(block) (((block) & BBT_ENTRY_MASK) * 2) -+#define GET_MARK_VALUE(block, mark) \ -+ (((mark) & BBT_ENTRY_MASK) << GET_POSITION(block)) -+ -+int scan_bbt(struct nandx_info *nand); -+ -+int bbt_mark_bad(struct nandx_info *nand, off_t offset); -+ -+int bbt_is_bad(struct nandx_info *nand, off_t offset); -+ -+#endif /*__BBT_H__*/ ---- /dev/null -+++ b/drivers/mtd/nandx/include/internal/nandx_core.h -@@ -0,0 +1,250 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NANDX_CORE_H__ -+#define __NANDX_CORE_H__ -+ -+/** -+ * mtk_ic_version - indicates specifical IC, IP need this to load some info -+ */ -+enum mtk_ic_version { -+ NANDX_MT7622, -+}; -+ -+/** -+ * nandx_ioctl_cmd - operations supported by nandx -+ * -+ * @NFI_CTRL_DMA dma enable or not -+ * @NFI_CTRL_NFI_MODE customer/read/program/erase... -+ * @NFI_CTRL_ECC ecc enable or not -+ * @NFI_CTRL_ECC_MODE nfi/dma/pio -+ * @CHIP_CTRL_DRIVE_STRENGTH enum chip_ctrl_drive_strength -+ */ -+enum nandx_ctrl_cmd { -+ CORE_CTRL_NAND_INFO, -+ -+ NFI_CTRL_DMA, -+ NFI_CTRL_NFI_MODE, -+ NFI_CTRL_AUTOFORMAT, -+ NFI_CTRL_NFI_IRQ, -+ NFI_CTRL_PAGE_IRQ, -+ NFI_CTRL_RANDOMIZE, -+ NFI_CTRL_BAD_MARK_SWAP, -+ -+ NFI_CTRL_ECC, -+ NFI_CTRL_ECC_MODE, -+ NFI_CTRL_ECC_CLOCK, -+ NFI_CTRL_ECC_IRQ, -+ NFI_CTRL_ECC_PAGE_IRQ, -+ NFI_CTRL_ECC_DECODE_MODE, -+ -+ SNFI_CTRL_OP_MODE, -+ SNFI_CTRL_RX_MODE, -+ SNFI_CTRL_TX_MODE, -+ SNFI_CTRL_DELAY_MODE, -+ -+ CHIP_CTRL_OPS_CACHE, -+ CHIP_CTRL_OPS_MULTI, -+ CHIP_CTRL_PSLC_MODE, -+ CHIP_CTRL_DRIVE_STRENGTH, -+ CHIP_CTRL_DDR_MODE, -+ CHIP_CTRL_ONDIE_ECC, -+ CHIP_CTRL_TIMING_MODE -+}; -+ -+enum snfi_ctrl_op_mode { -+ SNFI_CUSTOM_MODE, -+ SNFI_AUTO_MODE, -+ SNFI_MAC_MODE -+}; -+ -+enum snfi_ctrl_rx_mode { -+ SNFI_RX_111, -+ SNFI_RX_112, -+ SNFI_RX_114, -+ SNFI_RX_122, -+ SNFI_RX_144 -+}; -+ -+enum snfi_ctrl_tx_mode { -+ SNFI_TX_111, -+ SNFI_TX_114, -+}; -+ -+enum chip_ctrl_drive_strength { -+ CHIP_DRIVE_NORMAL, -+ CHIP_DRIVE_HIGH, -+ CHIP_DRIVE_MIDDLE, -+ CHIP_DRIVE_LOW -+}; -+ -+enum chip_ctrl_timing_mode { -+ CHIP_TIMING_MODE0, -+ CHIP_TIMING_MODE1, -+ CHIP_TIMING_MODE2, -+ CHIP_TIMING_MODE3, -+ CHIP_TIMING_MODE4, -+ CHIP_TIMING_MODE5, -+}; -+ -+/** -+ * nandx_info - basic information -+ */ -+struct nandx_info { -+ u32 max_io_count; -+ u32 min_write_pages; -+ u32 plane_num; -+ u32 oob_size; -+ u32 page_parity_size; -+ u32 page_size; -+ u32 block_size; -+ u64 total_size; -+ u32 fdm_reg_size; -+ u32 fdm_ecc_size; -+ u32 ecc_strength; -+ u32 sector_size; -+}; -+ -+/** -+ * nfi_resource - the resource needed by nfi & ecc to do initialization -+ */ -+struct nfi_resource { -+ int ic_ver; -+ void *dev; -+ -+ void *ecc_regs; -+ int ecc_irq_id; -+ -+ void *nfi_regs; -+ int nfi_irq_id; -+ -+ u32 clock_1x; -+ u32 *clock_2x; -+ int clock_2x_num; -+ -+ int min_oob_req; -+}; -+ -+/** -+ * nandx_init - init all related modules below -+ * -+ * @res: basic resource of the project -+ * -+ * return 0 if init success, otherwise return negative error code -+ */ -+int nandx_init(struct nfi_resource *res); -+ -+/** -+ * nandx_exit - release resource those that obtained in init flow -+ */ -+void nandx_exit(void); -+ -+/** -+ * nandx_read - read data from nand this function can read data and related -+ * oob from specifical address -+ * if do multi_ops, set one operation per time, and call nandx_sync at last -+ * in multi mode, not support page partial read -+ * oob not support partial read -+ * -+ * @data: buf to receive data from nand -+ * @oob: buf to receive oob data from nand which related to data page -+ * length of @oob should oob size aligned, oob not support partial read -+ * @offset: offset address on the whole flash -+ * @len: the length of @data that need to read -+ * -+ * if read success return 0, otherwise return negative error code -+ */ -+int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len); -+ -+/** -+ * nandx_write - write data to nand -+ * this function can write data and related oob to specifical address -+ * if do multi_ops, set one operation per time, and call nandx_sync at last -+ * -+ * @data: source data to be written to nand, -+ * for multi operation, the length of @data should be page size aliged -+ * @oob: source oob which related to data page to be written to nand, -+ * length of @oob should oob size aligned -+ * @offset: offset address on the whole flash, the value should be start address -+ * of a page -+ * @len: the length of @data that need to write, -+ * for multi operation, the len should be page size aliged -+ * -+ * if write success return 0, otherwise return negative error code -+ * if return value > 0, it indicates that how many pages still need to write, -+ * and data has not been written to nand -+ * please call nandx_sync after pages alligned $nandx_info.min_write_pages -+ */ -+int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len); -+ -+/** -+ * nandx_erase - erase an area of nand -+ * if do multi_ops, set one operation per time, and call nandx_sync at last -+ * -+ * @offset: offset address on the flash -+ * @len: erase length which should be block size aligned -+ * -+ * if erase success return 0, otherwise return negative error code -+ */ -+int nandx_erase(u64 offset, size_t len); -+ -+/** -+ * nandx_sync - sync all operations to nand -+ * when do multi_ops, this function will be called at last operation -+ * when write data, if number of pages not alligned -+ * by $nandx_info.min_write_pages, this interface could be called to do -+ * force write, 0xff will be padded to blanked pages. -+ */ -+int nandx_sync(void); -+ -+/** -+ * nandx_is_bad_block - check if the block is bad -+ * only check the flag that marked by the flash vendor -+ * -+ * @offset: offset address on the whole flash -+ * -+ * return true if the block is bad, otherwise return false -+ */ -+bool nandx_is_bad_block(u64 offset); -+ -+/** -+ * nandx_ioctl - set/get property of nand chip -+ * -+ * @cmd: parameter that defined in enum nandx_ioctl_cmd -+ * @arg: operate parameter -+ * -+ * return 0 if operate success, otherwise return negative error code -+ */ -+int nandx_ioctl(int cmd, void *arg); -+ -+/** -+ * nandx_suspend - suspend nand, and store some data -+ * -+ * return 0 if suspend success, otherwise return negative error code -+ */ -+int nandx_suspend(void); -+ -+/** -+ * nandx_resume - resume nand, and replay some data -+ * -+ * return 0 if resume success, otherwise return negative error code -+ */ -+int nandx_resume(void); -+ -+#ifdef NANDX_UNIT_TEST -+/** -+ * nandx_unit_test - unit test -+ * -+ * @offset: offset address on the whole flash -+ * @len: should be not larger than a block size, we only test a block per time -+ * -+ * return 0 if test success, otherwise return negative error code -+ */ -+int nandx_unit_test(u64 offset, size_t len); -+#endif -+ -+#endif /* __NANDX_CORE_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/include/internal/nandx_errno.h -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NANDX_ERRNO_H__ -+#define __NANDX_ERRNO_H__ -+ -+#ifndef EIO -+#define EIO 5 /* I/O error */ -+#define ENOMEM 12 /* Out of memory */ -+#define EFAULT 14 /* Bad address */ -+#define EBUSY 16 /* Device or resource busy */ -+#define ENODEV 19 /* No such device */ -+#define EINVAL 22 /* Invalid argument */ -+#define ENOSPC 28 /* No space left on device */ -+/* Operation not supported on transport endpoint */ -+#define EOPNOTSUPP 95 -+#define ETIMEDOUT 110 /* Connection timed out */ -+#endif -+ -+#define ENANDFLIPS 1024 /* Too many bitflips, uncorrected */ -+#define ENANDREAD 1025 /* Read fail, can't correct */ -+#define ENANDWRITE 1026 /* Write fail */ -+#define ENANDERASE 1027 /* Erase fail */ -+#define ENANDBAD 1028 /* Bad block */ -+#define ENANDWP 1029 -+ -+#define IS_NAND_ERR(err) ((err) >= -ENANDBAD && (err) <= -ENANDFLIPS) -+ -+#ifndef MAX_ERRNO -+#define MAX_ERRNO 4096 -+#define ERR_PTR(errno) ((void *)((long)errno)) -+#define PTR_ERR(ptr) ((long)(ptr)) -+#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)-MAX_ERRNO) -+#endif -+ -+#endif /* __NANDX_ERRNO_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/include/internal/nandx_util.h -@@ -0,0 +1,221 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NANDX_UTIL_H__ -+#define __NANDX_UTIL_H__ -+ -+typedef unsigned char u8; -+typedef unsigned short u16; -+typedef unsigned int u32; -+typedef unsigned long long u64; -+ -+enum nand_irq_return { -+ NAND_IRQ_NONE, -+ NAND_IRQ_HANDLED, -+}; -+ -+enum nand_dma_operation { -+ NDMA_FROM_DEV, -+ NDMA_TO_DEV, -+}; -+ -+ -+/* -+ * Compatible function -+ * used for preloader/lk/kernel environment -+ */ -+#include "nandx_os.h" -+#include "nandx_errno.h" -+ -+#ifndef BIT -+#define BIT(a) (1 << (a)) -+#endif -+ -+#ifndef min_t -+#define min_t(type, x, y) ({ \ -+ type __min1 = (x); \ -+ type __min2 = (y); \ -+ __min1 < __min2 ? __min1 : __min2; }) -+ -+#define max_t(type, x, y) ({ \ -+ type __max1 = (x); \ -+ type __max2 = (y); \ -+ __max1 > __max2 ? __max1 : __max2; }) -+#endif -+ -+#ifndef GENMASK -+#define GENMASK(h, l) \ -+ (((~0UL) << (l)) & (~0UL >> ((sizeof(unsigned long) * 8) - 1 - (h)))) -+#endif -+ -+#ifndef __weak -+#define __weak __attribute__((__weak__)) -+#endif -+ -+#ifndef __packed -+#define __packed __attribute__((__packed__)) -+#endif -+ -+#ifndef KB -+#define KB(x) ((x) << 10) -+#define MB(x) (KB(x) << 10) -+#define GB(x) (MB(x) << 10) -+#endif -+ -+#ifndef offsetof -+#define offsetof(type, member) ((size_t)&((type *)0)->member) -+#endif -+ -+#ifndef NULL -+#define NULL (void *)0 -+#endif -+static inline u32 nandx_popcount(u32 x) -+{ -+ x = (x & 0x55555555) + ((x >> 1) & 0x55555555); -+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333); -+ x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); -+ x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); -+ x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF); -+ -+ return x; -+} -+ -+#ifndef zero_popcount -+#define zero_popcount(x) (32 - nandx_popcount(x)) -+#endif -+ -+#ifndef do_div -+#define do_div(n, base) \ -+ ({ \ -+ u32 __base = (base); \ -+ u32 __rem; \ -+ __rem = ((u64)(n)) % __base; \ -+ (n) = ((u64)(n)) / __base; \ -+ __rem; \ -+ }) -+#endif -+ -+#define div_up(x, y) \ -+ ({ \ -+ u64 __temp = ((x) + (y) - 1); \ -+ do_div(__temp, (y)); \ -+ __temp; \ -+ }) -+ -+#define div_down(x, y) \ -+ ({ \ -+ u64 __temp = (x); \ -+ do_div(__temp, (y)); \ -+ __temp; \ -+ }) -+ -+#define div_round_up(x, y) (div_up(x, y) * (y)) -+#define div_round_down(x, y) (div_down(x, y) * (y)) -+ -+#define reminder(x, y) \ -+ ({ \ -+ u64 __temp = (x); \ -+ do_div(__temp, (y)); \ -+ }) -+ -+#ifndef round_up -+#define round_up(x, y) ((((x) - 1) | ((y) - 1)) + 1) -+#define round_down(x, y) ((x) & ~((y) - 1)) -+#endif -+ -+#ifndef readx_poll_timeout_atomic -+#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \ -+ ({ \ -+ u64 end = get_current_time_us() + timeout_us; \ -+ for (;;) { \ -+ u64 now = get_current_time_us(); \ -+ (val) = op(addr); \ -+ if (cond) \ -+ break; \ -+ if (now > end) { \ -+ (val) = op(addr); \ -+ break; \ -+ } \ -+ } \ -+ (cond) ? 0 : -ETIMEDOUT; \ -+ }) -+ -+#define readl_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \ -+ readx_poll_timeout_atomic(readl, addr, val, cond, delay_us, timeout_us) -+#define readw_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \ -+ readx_poll_timeout_atomic(readw, addr, val, cond, delay_us, timeout_us) -+#define readb_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \ -+ readx_poll_timeout_atomic(readb, addr, val, cond, delay_us, timeout_us) -+#endif -+ -+struct nandx_split64 { -+ u64 head; -+ size_t head_len; -+ u64 body; -+ size_t body_len; -+ u64 tail; -+ size_t tail_len; -+}; -+ -+struct nandx_split32 { -+ u32 head; -+ u32 head_len; -+ u32 body; -+ u32 body_len; -+ u32 tail; -+ u32 tail_len; -+}; -+ -+#define nandx_split(split, offset, len, val, align) \ -+ do { \ -+ (split)->head = (offset); \ -+ (val) = div_round_down((offset), (align)); \ -+ (val) = (align) - ((offset) - (val)); \ -+ if ((val) == (align)) \ -+ (split)->head_len = 0; \ -+ else if ((val) > (len)) \ -+ (split)->head_len = len; \ -+ else \ -+ (split)->head_len = val; \ -+ (split)->body = (offset) + (split)->head_len; \ -+ (split)->body_len = div_round_down((len) - \ -+ (split)->head_len,\ -+ (align)); \ -+ (split)->tail = (split)->body + (split)->body_len; \ -+ (split)->tail_len = (len) - (split)->head_len - \ -+ (split)->body_len; \ -+ } while (0) -+ -+#ifndef container_of -+#define container_of(ptr, type, member) \ -+ ({const __typeof__(((type *)0)->member) * __mptr = (ptr); \ -+ (type *)((char *)__mptr - offsetof(type, member)); }) -+#endif -+ -+static inline u32 nandx_cpu_to_be32(u32 val) -+{ -+ u32 temp = 1; -+ u8 *p_temp = (u8 *)&temp; -+ -+ if (*p_temp) -+ return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | -+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff); -+ -+ return val; -+} -+ -+static inline void nandx_set_bits32(unsigned long addr, u32 mask, -+ u32 val) -+{ -+ u32 temp = readl((void *)addr); -+ -+ temp &= ~(mask); -+ temp |= val; -+ writel(temp, (void *)addr); -+} -+ -+#endif /* __NANDX_UTIL_H__ */ ---- /dev/null -+++ b/drivers/mtd/nandx/include/uboot/nandx_os.h -@@ -0,0 +1,78 @@ -+/* -+ * Copyright (C) 2017 MediaTek Inc. -+ * Licensed under either -+ * BSD Licence, (see NOTICE for more details) -+ * GNU General Public License, version 2.0, (see NOTICE for more details) -+ */ -+ -+#ifndef __NANDX_OS_H__ -+#define __NANDX_OS_H__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define NANDX_BULK_IO_USE_DRAM 0 -+ -+#define nandx_event_create() NULL -+#define nandx_event_destroy(event) -+#define nandx_event_complete(event) -+#define nandx_event_init(event) -+#define nandx_event_wait_complete(event, timeout) true -+ -+#define nandx_irq_register(dev, irq, irq_handler, name, data) NULL -+ -+static inline void *mem_alloc(u32 count, u32 size) -+{ -+ return kmalloc(count * size, GFP_KERNEL | __GFP_ZERO); -+} -+ -+static inline void mem_free(void *mem) -+{ -+ kfree(mem); -+} -+ -+static inline u64 get_current_time_us(void) -+{ -+ return timer_get_us(); -+} -+ -+static inline u32 nandx_dma_map(void *dev, void *buf, u64 len, -+ enum nand_dma_operation op) -+{ -+ unsigned long addr = (unsigned long)buf; -+ u64 size; -+ -+ size = ALIGN(len, ARCH_DMA_MINALIGN); -+ -+ if (op == NDMA_FROM_DEV) -+ invalidate_dcache_range(addr, addr + size); -+ else -+ flush_dcache_range(addr, addr + size); -+ -+ return addr; -+} -+ -+static inline void nandx_dma_unmap(void *dev, void *buf, void *addr, -+ u64 len, enum nand_dma_operation op) -+{ -+ u64 size; -+ -+ size = ALIGN(len, ARCH_DMA_MINALIGN); -+ -+ if (op != NDMA_FROM_DEV) -+ invalidate_dcache_range((unsigned long)addr, addr + size); -+ else -+ flush_dcache_range((unsigned long)addr, addr + size); -+ -+ return addr; -+} -+ -+#endif /* __NANDX_OS_H__ */ ---- a/include/configs/mt7622.h -+++ b/include/configs/mt7622.h -@@ -11,6 +11,31 @@ - - #include - -+/* SPI Nand */ -+#if defined(CONFIG_MTD_RAW_NAND) -+#define CONFIG_SYS_MAX_NAND_DEVICE 1 -+#define CONFIG_SYS_NAND_BASE 0x1100d000 -+ -+#define ENV_BOOT_READ_IMAGE \ -+ "boot_rd_img=" \ -+ "nand read 0x4007ff28 0x380000 0x1400000" \ -+ ";iminfo 0x4007ff28 \0" -+ -+#define ENV_BOOT_WRITE_IMAGE \ -+ "boot_wr_img=" \ -+ "nand write 0x4007ff28 0x380000 0x1400000" \ -+ ";iminfo 0x4007ff28 \0" -+ -+#define ENV_BOOT_CMD \ -+ "mtk_boot=run boot_rd_img;bootm;\0" -+ -+#define CONFIG_EXTRA_ENV_SETTINGS \ -+ ENV_BOOT_READ_IMAGE \ -+ ENV_BOOT_CMD \ -+ "bootcmd=run mtk_boot;\0" -+ -+#endif -+ - #define CONFIG_SYS_MAXARGS 8 - #define CONFIG_SYS_BOOTM_LEN SZ_64M - #define CONFIG_SYS_CBSIZE SZ_1K diff --git a/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch b/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch deleted file mode 100644 index 7167a498ad..0000000000 --- a/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch +++ /dev/null @@ -1,57 +0,0 @@ -From b1b3c3d2ce62872c8dec4a7d645af6b3c565e094 Mon Sep 17 00:00:00 2001 -From: Sam Shih -Date: Mon, 20 Apr 2020 17:11:32 +0800 -Subject: [PATCH 2/3] mt7622 uboot: add dts and config for spi nand - -This patch add dts and config for mt7622 spi nand - -Signed-off-by: Xiangsheng Hou ---- - arch/arm/dts/mt7622-rfb.dts | 6 ++++++ - arch/arm/dts/mt7622.dtsi | 20 ++++++++++++++++++++ - 2 files changed, 26 insertions(+) - ---- a/arch/arm/dts/mt7622-rfb.dts -+++ b/arch/arm/dts/mt7622-rfb.dts -@@ -174,6 +174,12 @@ - }; - }; - -+&nandc { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&snfi_pins>; -+ status = "okay"; -+}; -+ - &uart0 { - pinctrl-names = "default"; - pinctrl-0 = <&uart0_pins>; ---- a/arch/arm/dts/mt7622.dtsi -+++ b/arch/arm/dts/mt7622.dtsi -@@ -53,6 +53,26 @@ - #size-cells = <0>; - }; - -+ nandc: nfi@1100d000 { -+ compatible = "mediatek,mt7622-nfc"; -+ reg = <0x1100d000 0x1000>, -+ <0x1100e000 0x1000>; -+ interrupts = , -+ ; -+ clocks = <&pericfg CLK_PERI_NFI_PD>, -+ <&pericfg CLK_PERI_NFIECC_PD>, -+ <&pericfg CLK_PERI_SNFI_PD>, -+ <&topckgen CLK_TOP_NFI_INFRA_SEL>, -+ <&topckgen CLK_TOP_UNIVPLL2_D8>; -+ clock-names = "nfi_clk", -+ "ecc_clk", -+ "snfi_clk", -+ "spinfi_sel", -+ "spinfi_parent_50m"; -+ nand-ecc-mode = "hw"; -+ status = "disabled"; -+ }; -+ - timer { - compatible = "arm,armv8-timer"; - interrupt-parent = <&gic>; diff --git a/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch b/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch deleted file mode 100644 index 6999e5e235..0000000000 --- a/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch +++ /dev/null @@ -1,22 +0,0 @@ -From e5745143a2984cf44fbfc0b3aedb49e57873f109 Mon Sep 17 00:00:00 2001 -From: Sam Shih -Date: Mon, 20 Apr 2020 17:17:04 +0800 -Subject: [PATCH 3/3] configs: enable mtd and mtk_spi_nand in defconfig - -This patch enable mtk and mtk_spi_nand in mt7622_rfb defconfig - -Signed-off-by: Sam Shih ---- - configs/mt7622_rfb_defconfig | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/configs/mt7622_rfb_defconfig -+++ b/configs/mt7622_rfb_defconfig -@@ -13,6 +13,7 @@ CONFIG_DEFAULT_FDT_FILE="mt7622-rfb" - CONFIG_SYS_PROMPT="MT7622> " - CONFIG_CMD_BOOTMENU=y - CONFIG_CMD_MMC=y -+CONFIG_CMD_NAND=y - CONFIG_CMD_PCI=y - CONFIG_CMD_SF_TEST=y - CONFIG_CMD_PING=y diff --git a/package/boot/uboot-mediatek/patches/006-cmd-button-return-button-status.patch b/package/boot/uboot-mediatek/patches/006-cmd-button-return-button-status.patch deleted file mode 100644 index a413688f1c..0000000000 --- a/package/boot/uboot-mediatek/patches/006-cmd-button-return-button-status.patch +++ /dev/null @@ -1,38 +0,0 @@ -From a6bfd71a96201127836d59736abcb54dc2d5e1a5 Mon Sep 17 00:00:00 2001 -From: Heinrich Schuchardt -Date: Mon, 14 Sep 2020 12:50:56 +0200 -Subject: [PATCH] cmd/button: return button status - -To make the button command useful in a shell script it should return the -status of the button: - -* 0 (true) - pressed, on -* 1 (false) - not pressed, off - -The button command takes only one argument. Correct maxargs. - -Adjust the Python unit test. - -Signed-off-by: Heinrich Schuchardt -Reviewed-by: Philippe Reynes ---- - cmd/button.c | 4 ++-- - test/py/tests/test_button.py | 34 ++++++++++++++++++++++++++-------- - 2 files changed, 28 insertions(+), 10 deletions(-) - ---- a/cmd/button.c -+++ b/cmd/button.c -@@ -75,11 +75,11 @@ int do_button(struct cmd_tbl *cmdtp, int - - ret = show_button_state(dev); - -- return 0; -+ return !ret; - } - - U_BOOT_CMD( -- button, 4, 1, do_button, -+ button, 2, 1, do_button, - "manage buttons", - " \tGet button state\n" - "button list\t\tShow a list of buttons" diff --git a/package/boot/uboot-mediatek/patches/010-no-binman.patch b/package/boot/uboot-mediatek/patches/010-no-binman.patch deleted file mode 100644 index 7071a6c410..0000000000 --- a/package/boot/uboot-mediatek/patches/010-no-binman.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/Makefile -+++ b/Makefile -@@ -1716,6 +1716,10 @@ u-boot-elf.lds: arch/u-boot-elf.lds prep - - ifeq ($(CONFIG_SPL),y) - spl/u-boot-spl-mtk.bin: spl/u-boot-spl -+OBJCOPYFLAGS_u-boot-mtk.bin = -I binary -O binary \ -+ --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff -+u-boot-mtk.bin: u-boot.img spl/u-boot-spl-mtk.bin FORCE -+ $(call if_changed,pad_cat) - else - MKIMAGEFLAGS_u-boot-mtk.bin = -T mtk_image \ - -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \ ---- a/arch/arm/mach-mediatek/Kconfig -+++ b/arch/arm/mach-mediatek/Kconfig -@@ -36,7 +36,6 @@ config TARGET_MT7629 - bool "MediaTek MT7629 SoC" - select CPU_V7A - select SPL -- select BINMAN - help - The MediaTek MT7629 is a ARM-based SoC with a dual-core Cortex-A7 - including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet, diff --git a/package/boot/uboot-mediatek/patches/100-increase-CONFIG_SYS_BOOTM_LEN.patch b/package/boot/uboot-mediatek/patches/100-increase-CONFIG_SYS_BOOTM_LEN.patch deleted file mode 100644 index 811e8489dd..0000000000 --- a/package/boot/uboot-mediatek/patches/100-increase-CONFIG_SYS_BOOTM_LEN.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/include/configs/mt7622.h -+++ b/include/configs/mt7622.h -@@ -37,7 +37,7 @@ - #endif - - #define CONFIG_SYS_MAXARGS 8 --#define CONFIG_SYS_BOOTM_LEN SZ_64M -+#define CONFIG_SYS_BOOTM_LEN SZ_128M - #define CONFIG_SYS_CBSIZE SZ_1K - #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ - sizeof(CONFIG_SYS_PROMPT) + 16) diff --git a/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch b/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch new file mode 100644 index 0000000000..0505589385 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/100-scripts-remove-dependency-on-swig.patch @@ -0,0 +1,24 @@ +From b137ca16b54c67d76714ea5a0138741959b0dc29 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Mon, 13 Jul 2020 23:37:37 +0200 +Subject: [PATCH] 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/package/boot/uboot-mediatek/patches/016-fit-totalsize.patch b/package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch similarity index 94% rename from package/boot/uboot-mediatek/patches/016-fit-totalsize.patch rename to package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch index 72fb4ac516..a96345e6fe 100644 --- a/package/boot/uboot-mediatek/patches/016-fit-totalsize.patch +++ b/package/boot/uboot-mediatek/patches/200-cmd-add-imsz-and-imszb.patch @@ -1,6 +1,6 @@ --- a/cmd/bootm.c +++ b/cmd/bootm.c -@@ -227,6 +227,65 @@ U_BOOT_CMD( +@@ -228,6 +228,65 @@ U_BOOT_CMD( /* iminfo - print header info for a requested image */ /*******************************************************************/ #if defined(CONFIG_CMD_IMI) @@ -10,7 +10,7 @@ +{ + ulong addr; + void *fit; -+ int bsize, tsize, maxhdrsize; ++ int bsize, tsize; + char buf[16]; + + if (argc >= 2) @@ -68,7 +68,7 @@ { --- a/common/image-fit.c +++ b/common/image-fit.c -@@ -1878,6 +1878,51 @@ static const char *fit_get_image_type_pr +@@ -1970,6 +1970,51 @@ static const char *fit_get_image_type_pr return "unknown"; } @@ -122,7 +122,7 @@ int arch, int image_type, int bootstage_id, --- a/include/image.h +++ b/include/image.h -@@ -1027,6 +1027,7 @@ int fit_parse_subimage(const char *spec, +@@ -1041,6 +1041,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); diff --git a/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch b/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch new file mode 100644 index 0000000000..82d97f756c --- /dev/null +++ b/package/boot/uboot-mediatek/patches/210-cmd-bootmenu-add-ability-to-select-item-by-shortkey.patch @@ -0,0 +1,192 @@ +From 26d4e2e58bf0007db74b47c783785c3305ea1fa0 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 19 Jan 2021 10:58:48 +0800 +Subject: [PATCH 17/23] 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/package/boot/uboot-mediatek/patches/008-bootmenu-custom-title.patch b/package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch similarity index 80% rename from package/boot/uboot-mediatek/patches/008-bootmenu-custom-title.patch rename to package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch index 32f26ece8e..3f98f13c6e 100644 --- a/package/boot/uboot-mediatek/patches/008-bootmenu-custom-title.patch +++ b/package/boot/uboot-mediatek/patches/211-cmd-bootmenu-custom-title.patch @@ -1,14 +1,14 @@ --- a/cmd/bootmenu.c +++ b/cmd/bootmenu.c -@@ -38,6 +38,7 @@ struct bootmenu_data { +@@ -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; }; - enum bootmenu_key { -@@ -380,7 +381,12 @@ static void menu_display_statusline(stru +@@ -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); @@ -22,7 +22,7 @@ puts(ANSI_CLEAR_LINE_TO_END); printf(ANSI_CURSOR_POSITION, 3, 1); puts(ANSI_CLEAR_LINE); -@@ -434,6 +440,7 @@ static void bootmenu_show(int delay) +@@ -525,6 +531,7 @@ static void bootmenu_show(int delay) return; } diff --git a/package/boot/uboot-mediatek/patches/007-env-readmem.patch b/package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch similarity index 91% rename from package/boot/uboot-mediatek/patches/007-env-readmem.patch rename to package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch index a8c88a2757..705b749e71 100644 --- a/package/boot/uboot-mediatek/patches/007-env-readmem.patch +++ b/package/boot/uboot-mediatek/patches/220-cmd-env-readmem.patch @@ -1,6 +1,6 @@ --- a/cmd/Kconfig +++ b/cmd/Kconfig -@@ -571,6 +571,12 @@ config CMD_ENV_EXISTS +@@ -465,6 +465,12 @@ config CMD_ENV_EXISTS Check if a variable is defined in the environment for use in shell scripting. @@ -15,7 +15,7 @@ help --- a/cmd/nvedit.c +++ b/cmd/nvedit.c -@@ -469,6 +469,60 @@ int do_env_ask(struct cmd_tbl *cmdtp, in +@@ -473,6 +473,60 @@ int do_env_ask(struct cmd_tbl *cmdtp, in } #endif @@ -76,7 +76,7 @@ #if defined(CONFIG_CMD_ENV_CALLBACK) static int print_static_binding(const char *var_name, const char *callback_name, void *priv) -@@ -1373,6 +1427,9 @@ static struct cmd_tbl cmd_env_sub[] = { +@@ -1377,6 +1431,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, "", ""), @@ -86,7 +86,7 @@ #if defined(CONFIG_CMD_RUN) U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), #endif -@@ -1461,6 +1518,9 @@ static char env_help_text[] = +@@ -1465,6 +1522,9 @@ static char env_help_text[] = #if defined(CONFIG_CMD_NVEDIT_EFI) "env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n" #endif @@ -96,7 +96,7 @@ #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif -@@ -1570,6 +1630,17 @@ U_BOOT_CMD( +@@ -1574,6 +1634,17 @@ U_BOOT_CMD( ); #endif diff --git a/package/boot/uboot-mediatek/patches/009-mt7622-generic-reset-button-ignore-env.patch b/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch similarity index 88% rename from package/boot/uboot-mediatek/patches/009-mt7622-generic-reset-button-ignore-env.patch rename to package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch index 037bbb89ea..aeb4c49b9e 100644 --- a/package/boot/uboot-mediatek/patches/009-mt7622-generic-reset-button-ignore-env.patch +++ b/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch @@ -1,13 +1,15 @@ --- a/board/mediatek/mt7622/mt7622_rfb.c +++ b/board/mediatek/mt7622/mt7622_rfb.c -@@ -6,9 +6,15 @@ +@@ -6,10 +6,17 @@ #include #include +#include +#include ++ #include #include + #include +#ifndef CONFIG_RESET_BUTTON_LABEL +#define CONFIG_RESET_BUTTON_LABEL "reset" @@ -16,7 +18,7 @@ DECLARE_GLOBAL_DATA_PTR; int board_init(void) -@@ -19,7 +25,15 @@ int board_init(void) +@@ -20,7 +27,15 @@ int board_init(void) int board_late_init(void) { diff --git a/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch b/package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch similarity index 84% rename from package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch rename to package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch index b750dda6e8..ec0fed84b8 100644 --- a/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch +++ b/package/boot/uboot-mediatek/patches/400-update-bpir2-defconfig.patch @@ -1,6 +1,6 @@ --- a/configs/mt7623n_bpir2_defconfig +++ b/configs/mt7623n_bpir2_defconfig -@@ -51,5 +51,15 @@ CONFIG_SYSRESET=y +@@ -51,6 +51,16 @@ CONFIG_SYSRESET=y CONFIG_SYSRESET_WATCHDOG=y CONFIG_TIMER=y CONFIG_MTK_TIMER=y @@ -16,3 +16,4 @@ +CONFIG_CMD_SETEXPR=y CONFIG_WDT_MTK=y CONFIG_LZMA=y + # CONFIG_EFI_GRUB_ARM32_WORKAROUND is not set diff --git a/package/boot/uboot-mediatek/patches/010-update-u7623-defconfig.patch b/package/boot/uboot-mediatek/patches/401-update-u7623-defconfig.patch similarity index 100% rename from package/boot/uboot-mediatek/patches/010-update-u7623-defconfig.patch rename to package/boot/uboot-mediatek/patches/401-update-u7623-defconfig.patch diff --git a/package/boot/uboot-mediatek/patches/015-update-bananapi-bpi-r64-device-tree.patch b/package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch similarity index 64% rename from package/boot/uboot-mediatek/patches/015-update-bananapi-bpi-r64-device-tree.patch rename to package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch index dd4b94e2e1..781a685721 100644 --- a/package/boot/uboot-mediatek/patches/015-update-bananapi-bpi-r64-device-tree.patch +++ b/package/boot/uboot-mediatek/patches/402-update-bananapi-bpi-r64-device-tree.patch @@ -8,7 +8,7 @@ }; memory@40000000 { -@@ -27,6 +29,42 @@ +@@ -27,6 +28,42 @@ reg = <0x40000000 0x40000000>; }; @@ -51,30 +51,7 @@ reg_1p8v: regulator-1p8v { compatible = "regulator-fixed"; regulator-name = "fixed-1.8V"; -@@ -139,11 +177,12 @@ - - }; - -- mmc1_pins_default: mmc1default { -+ sd0_pins_default: sd0-pins-default { - mux { - function = "sd"; -- groups = "sd_0"; -+ groups = "sd_0"; - }; -+ - /* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN", - * "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1, - * DAT2, DAT3, CMD, CLK for SD respectively. -@@ -164,7 +203,6 @@ - pins = "TXD3"; - bias-pull-up; - }; -- - }; - }; - -@@ -199,7 +237,7 @@ +@@ -199,7 +236,7 @@ status = "okay"; bus-width = <8>; max-frequency = <50000000>; @@ -83,21 +60,12 @@ vmmc-supply = <®_3p3v>; vqmmc-supply = <®_3p3v>; non-removable; -@@ -207,14 +245,15 @@ - - &mmc1 { - pinctrl-names = "default"; -- pinctrl-0 = <&mmc1_pins_default>; -+ pinctrl-0 = <&sd0_pins_default>; +@@ -210,7 +247,7 @@ + pinctrl-0 = <&mmc1_pins_default>; status = "okay"; bus-width = <4>; - max-frequency = <50000000>; -+ max-frequency = <20000000>; ++ max-frequency = <12000000>; cap-sd-highspeed; r_smpl = <1>; vmmc-supply = <®_3p3v>; - vqmmc-supply = <®_3p3v>; -+ cd-gpios = <&gpio 81 GPIO_ACTIVE_LOW>; - }; - - &watchdog { diff --git a/package/boot/uboot-mediatek/patches/017-add-bananapi_bpi-r64_defconfigs.patch b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch similarity index 86% rename from package/boot/uboot-mediatek/patches/017-add-bananapi_bpi-r64_defconfigs.patch rename to package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch index 3624c0102a..2fb2d3aa8f 100644 --- a/package/boot/uboot-mediatek/patches/017-add-bananapi_bpi-r64_defconfigs.patch +++ b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/configs/mt7622_bananapi_bpi-r64-sdmmc_defconfig -@@ -0,0 +1,123 @@ +@@ -0,0 +1,124 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -10,7 +10,10 @@ +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_DEBUG_UART=y +CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r64-sdmmc_env" +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_SMBIOS_PRODUCT_NAME="" @@ -50,7 +53,7 @@ +CONFIG_CMD_LED=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_LINK_LOCAL=y -+CONFIG_CMD_MBR=y ++# CONFIG_CMD_MBR is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_PCI=y +CONFIG_CMD_SF_TEST=y @@ -61,7 +64,7 @@ +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+CONFIG_CMD_PSTORE=y ++# CONFIG_CMD_PSTORE is not set +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -111,8 +114,6 @@ +CONFIG_MMC_MTK=y +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_TIMER=y -+CONFIG_MTK_TIMER=y +CONFIG_WDT_MTK=y +CONFIG_LZO=y +CONFIG_ZSTD=y @@ -131,26 +132,26 @@ +serverip=192.168.1.254 +loadaddr=0x4007ff28 +bootcmd=run boot_sdmmc -+bootargs=earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512 root=/dev/mmcblk1p6 ++bootargs=root=/dev/mmcblk1p6 +bootdelay=0 +bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb +bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb +bootfile_emmcbl3=openwrt-mediatek-mt7622-bananapi_bpi-r64-boot-emmc.img +bootfile_emmcbl2=openwrt-mediatek-mt7622-bananapi_bpi-r64-bl2-emmc.bin -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu ++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=0. Initialize environment.=run _firstboot -+bootmenu_0d=0. Run default boot command.=run boot_default -+bootmenu_1=1. Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=2. Boot production system from SD card.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=3. Boot recovery system from SD card.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=4. Load production system via TFTP then write to SD card.=setenv noboot 1 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_5=5. Load recovery system via TFTP then write to SD card.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_6=6. Install bootloader and recovery to eMMC.=run emmc_init ; run bootmenu_confirm_return -+bootmenu_7=7. Reboot.=reset -+bootmenu_8=8. Reset all settings to factory defaults.=run reset_factory ; reset ++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 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to SD card.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; run bootmenu_confirm_return ++bootmenu_6=Install bootloader and recovery to eMMC.=run emmc_init ; run bootmenu_confirm_return ++bootmenu_7=Reboot.=reset ++bootmenu_8=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 ; run boot_tftp_forever +boot_first=if button reset ; then run boot_tftp_forever ; fi ; setenv flag_recover 1 ; bootmenu +boot_production=led bpi-r64:pio:green on ; run sdmmc_read_production && bootm $loadaddr @@ -183,7 +184,7 @@ +_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,123 @@ +@@ -0,0 +1,125 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -193,7 +194,10 @@ +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_DEBUG_UART=y +CONFIG_DEFAULT_ENV_FILE="bananapi_bpi-r64-emmc_env" +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_SMBIOS_PRODUCT_NAME="" @@ -233,7 +237,7 @@ +CONFIG_CMD_LED=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_LINK_LOCAL=y -+CONFIG_CMD_MBR=y ++# CONFIG_CMD_MBR is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_PCI=y +CONFIG_CMD_SF_TEST=y @@ -244,7 +248,7 @@ +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+CONFIG_CMD_PSTORE=y ++# CONFIG_CMD_PSTORE is not set +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -292,10 +296,9 @@ +CONFIG_MMC=y +CONFIG_MMC_DEFAULT_DEV=0 +CONFIG_MMC_MTK=y ++CONFIG_MMC_SUPPORTS_TUNING=y +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_TIMER=y -+CONFIG_MTK_TIMER=y +CONFIG_WDT_MTK=y +CONFIG_LZO=y +CONFIG_ZSTD=y @@ -314,23 +317,23 @@ +serverip=192.168.1.254 +loadaddr=0x4007ff28 +bootcmd=run boot_emmc -+bootargs=earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512 root=/dev/mmcblk0p5 ++bootargs=root=/dev/mmcblk0p5 +bootdelay=0 +bootfile=openwrt-mediatek-mt7622-bananapi_bpi-r64-initramfs-recovery.itb +bootfile_upg=openwrt-mediatek-mt7622-bananapi_bpi-r64-squashfs-sysupgrade.itb -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 +bootmenu_default=0 +bootmenu_delay=0 +bootmenu_title= ( ( ( OpenWrt ) ) ) [eMMC] -+bootmenu_0=0. Initialize environment.=run _firstboot -+bootmenu_0d=0. Run default boot command.=run boot_default -+bootmenu_1=1. Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_2=2. Boot production system from eMMC.=run boot_production ; run bootmenu_confirm_return -+bootmenu_3=3. Boot recovery system from eMMC.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_4=4. Load production system via TFTP then write to eMMC.=setenv noboot 1 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_5=5. Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_6=6. Reboot.=reset -+bootmenu_7=7. Reset all settings to factory defaults.=run reset_factory ; reset ++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 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to eMMC.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; 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 ; run boot_tftp_forever +boot_first=if button reset ; then run boot_tftp_forever ; fi ; setenv flag_recover 1 ; bootmenu +boot_production=led bpi-r64:pio:green on ; run emmc_read_production && bootm $loadaddr diff --git a/package/boot/uboot-mediatek/patches/020-add-linksys-e8450.patch b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch similarity index 76% rename from package/boot/uboot-mediatek/patches/020-add-linksys-e8450.patch rename to package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch index 711c1e6983..e78641e8fe 100644 --- a/package/boot/uboot-mediatek/patches/020-add-linksys-e8450.patch +++ b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/configs/mt7622_linksys_e8450_defconfig -@@ -0,0 +1,130 @@ +@@ -0,0 +1,128 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -11,7 +11,10 @@ +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_SMBIOS_PRODUCT_NAME="" +CONFIG_AUTOBOOT_KEYED=y +CONFIG_BOOTDELAY=30 @@ -49,10 +52,9 @@ +CONFIG_CMD_LED=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_LINK_LOCAL=y -+CONFIG_CMD_MBR=y ++# CONFIG_CMD_MBR is not set +CONFIG_CMD_MTD=y +CONFIG_CMD_MTDPART=y -+CONFIG_CMD_NAND=y +CONFIG_CMD_PCI=y +CONFIG_CMD_SF_TEST=y +CONFIG_CMD_PING=y @@ -65,7 +67,7 @@ +CONFIG_CMD_UBIFS=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+CONFIG_CMD_PSTORE=y ++# CONFIG_CMD_PSTORE is not set +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -98,7 +100,6 @@ +CONFIG_MEDIATEK_ETH=y +CONFIG_PCI=y +CONFIG_MTD=y -+CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_UBI_FASTMAP=y +CONFIG_DM_PCI=y +CONFIG_PCIE_MEDIATEK=y @@ -114,12 +115,9 @@ +CONFIG_MTK_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y -+CONFIG_MTK_SNFI_SPI=y +CONFIG_MTK_SPI_NAND=y -+CONFIG_NAND_SUPPORT=y ++CONFIG_MTK_SPI_NAND_MTD=y +CONFIG_SYSRESET_WATCHDOG=y -+CONFIG_TIMER=y -+CONFIG_MTK_TIMER=y +CONFIG_WDT_MTK=y +CONFIG_LZO=y +CONFIG_ZSTD=y @@ -133,7 +131,7 @@ +CONFIG_USB_STORAGE=y --- /dev/null +++ b/arch/arm/dts/mt7622-linksys-e8450-ubi.dts -@@ -0,0 +1,206 @@ +@@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. @@ -155,7 +153,7 @@ + }; + + aliases { -+ spi0 = &snfi; ++ spi0 = &snand; + }; + + gpio-keys { @@ -288,22 +286,11 @@ + }; +}; + -+&snfi { ++&snand { + pinctrl-names = "default"; + pinctrl-0 = <&snfi_pins>; + status = "okay"; -+ -+ mediatek,bmt-v2; -+ -+ spi-flash@0{ -+ compatible = "jedec,spi-nor"; -+ reg = <0>; -+ u-boot,dm-pre-reloc; -+ }; -+}; -+ -+&nandc { -+ status = "okay"; ++ quad-spi; +}; + +&uart0 { @@ -342,7 +329,7 @@ +}; --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile -@@ -963,6 +963,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ +@@ -996,6 +996,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt7622-rfb.dtb \ mt7623a-unielec-u7623-02-emmc.dtb \ mt7622-bananapi-bpi-r64.dtb \ @@ -350,35 +337,11 @@ mt7623n-bananapi-bpi-r2.dtb \ mt7629-rfb.dtb \ mt8512-bm1-emmc.dtb \ ---- a/drivers/mtd/nandx/core/nand/device_spi.c -+++ b/drivers/mtd/nandx/core/nand/device_spi.c -@@ -150,6 +150,21 @@ static struct device_spi spi_nand[] = { - &spi_extend_cmds, 0xff, 0xff - }, - { -+ NAND_DEVICE("FM35X1GA", -+ NAND_PACK_ID(0xe5, 0x71, 0, 0, 0, 0, 0, 0), -+ 2, 0, 3, 3, -+ 1, 1, 1, 1024, KB(128), KB(2), 64, 1, -+ &spi_cmds, &spi_addressing, &spi_status[0], -+ &spi_endurance, &spi_array_timing), -+ { -+ NAND_SPI_PROTECT(0xa0, 1, 2, 6), -+ NAND_SPI_CONFIG(0xb0, 4, 6, 1), -+ NAND_SPI_STATUS(0xc0, 4, 5), -+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff) -+ }, -+ &spi_extend_cmds, 0xff, 0xff -+ }, -+ { - NAND_DEVICE("NO-DEVICE", - NAND_PACK_ID(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, --- /dev/null +++ b/linksys_e8450_env @@ -0,0 +1,57 @@ -+mtdparts=nand0:512k(bl2),1280k(fip),1024k(factory),256k(reserved),-(ubi) -+ethaddr_factory=nand read 0x40080000 0x220000 0x20000 && env readmem -b ethaddr 0x4009fff4 0x6 ; setenv ethaddr_factory ++mtdparts=spi-nand0:512k(bl2),1280k(fip),1024k(factory),256k(reserved),-(ubi) ++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=0x4007ff28 @@ -388,21 +351,21 @@ +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 -+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu ++bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60 +bootmenu_default=0 +bootmenu_delay=0 +bootmenu_title= ( ( ( OpenWrt ) ) ) -+bootmenu_0=0. Initialize environment.=run _firstboot -+bootmenu_0d=0. Run default boot command.=run boot_default -+bootmenu_1=1. Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return -+bootmenu_3=2. Boot production system from flash.=run boot_production ; run bootmenu_confirm_return -+bootmenu_2=3. Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return -+bootmenu_5=4. Load production system via TFTP then write to flash.=setenv noboot 1 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_4=5. Load recovery system via TFTP then write to flash.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; run bootmenu_confirm_return -+bootmenu_6=6. Load BL31+U-Boot FIP via TFTP then write to flash.=run boot_tftp_write_fip ; run bootmenu_confirm_return -+bootmenu_7=7. Load BL2 preloader via TFTP then write to flash.=run boot_tftp_write_preloader ; run bootmenu_confirm_return -+bootmenu_8=8. Reboot.=reset -+bootmenu_9=9. Reset all settings to factory defaults.=run reset_factory ; reset ++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 ; run boot_tftp_production ; setenv noboot ; run bootmenu_confirm_return ++bootmenu_5=Load recovery system via TFTP then write to flash.=setenv noboot 1 ; run boot_tftp_recovery ; setenv noboot ; 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_forever ; fi ; setenv flag_recover 1 ; bootmenu +boot_default=if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; run boot_tftp_forever +boot_production=led power:blue on ; run ubi_read_production && bootm $loadaddr @@ -417,18 +380,18 @@ +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_ubi=ubi part ubi && run boot_production_or_recovery -+boot_write_fip=nand erase 0x80000 0x140000 && nand write $loadaddr 0x80000 0x140000 -+boot_write_preloader=nand erase 0x0 0x80000 && nand write $loadaddr 0x0 0x20000 && nand write $loadaddr 0x20000 0x20000 && nand write $loadaddr 0x40000 0x20000 && nand write $loadaddr 0x60000 0x20000 ++boot_write_fip=mtd erase spi-nand0 0x80000 0x140000 && mtd write spi-nand0 $loadaddr 0x80000 0x140000 ++boot_write_preloader=mtd erase spi-nand0 0x0 0x80000 && 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 +check_recovery=run ubi_read_recovery ; if iminfo $loadaddr ; then bootm $loadaddr ; else ubi remove recovery ; fi +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 ; nand erase 0x300000 0x7D00000 && ubi part ubi ; reset ++ubi_format=ubi detach ; mtd erase spi-nand0 0x300000 0x7D00000 && 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=run ubi_remove_rootfs ; ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize -+ubi_write_recovery=run ubi_remove_rootfs ; ubi check recovery && ubi remove recovery; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize ++ubi_write_production=ubi check fit && ubi remove fit ; run ubi_remove_rootfs ; ubi create fit $filesize dynamic && ubi write $loadaddr fit $filesize ++ubi_write_recovery=ubi check recovery && ubi remove recovery ; run ubi_remove_rootfs ; ubi create recovery $filesize dynamic && ubi write $loadaddr recovery $filesize +_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 ; led power:orange on ; run _switch_to_menu ; run ethaddr_factory ; run check_ubi ; run _init_env ; run boot_first From ba220ad2fd915aaed2e9c850a84078c5c5977d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 11 Mar 2021 13:35:38 +0100 Subject: [PATCH 04/32] realtek: drop ethtool log noise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demote a number of debugging printk's to pr_debug to avoid log nosie. Several of these functions are called as a result of userspace activity. This can cause a lot of log noise when userspace does periodic polling. Most of this could probably be removed completely, but let's keep it for now since these drivers are still in development. Signed-off-by: Bjørn Mork Tested-by: Stijn Tintel --- .../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 2 +- .../drivers/net/ethernet/rtl838x_eth.c | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c index e0832c42b8..af6d92cbc2 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c @@ -310,7 +310,7 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, link = priv->r->get_port_reg_le(priv->r->mac_link_sts); if (link & BIT_ULL(port)) state->link = 1; - pr_info("%s: link state: %llx\n", __func__, link & BIT_ULL(port)); + pr_debug("%s: link state: %llx\n", __func__, link & BIT_ULL(port)); state->duplex = 0; if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port)) diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c index 7931daff07..2f678b7384 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c @@ -855,7 +855,7 @@ static int rtl838x_eth_open(struct net_device *ndev) struct ring_b *ring = priv->membase; int i, err; - pr_info("%s called: RX rings %d(length %d), TX rings %d(length %d)\n", + pr_debug("%s called: RX rings %d(length %d), TX rings %d(length %d)\n", __func__, priv->rxrings, priv->rxringlen, TXRINGS, TXRINGLEN); spin_lock_irqsave(&priv->lock, flags); @@ -1342,7 +1342,7 @@ static void rtl838x_validate(struct phylink_config *config, { __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); if (!phy_interface_mode_is_rgmii(state->interface) && state->interface != PHY_INTERFACE_MODE_1000BASEX && @@ -1404,7 +1404,7 @@ static void rtl838x_mac_an_restart(struct phylink_config *config) if (priv->family_id != RTL8380_FAMILY_ID) return; - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); /* Restart by disabling and re-enabling link */ sw_w32(0x6192D, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); mdelay(20); @@ -1419,7 +1419,7 @@ static int rtl838x_mac_pcs_get_state(struct phylink_config *config, struct rtl838x_eth_priv *priv = netdev_priv(dev); int port = priv->cpu_port; - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); state->link = priv->r->get_mac_link_sts(port) ? 1 : 0; state->duplex = priv->r->get_mac_link_dup_sts(port) ? 1 : 0; @@ -1456,7 +1456,7 @@ static void rtl838x_mac_link_down(struct phylink_config *config, struct net_device *dev = container_of(config->dev, struct net_device, dev); struct rtl838x_eth_priv *priv = netdev_priv(dev); - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); /* Stop TX/RX to port */ sw_w32_mask(0x03, 0, priv->r->mac_port_ctrl(priv->cpu_port)); } @@ -1468,7 +1468,7 @@ static void rtl838x_mac_link_up(struct phylink_config *config, unsigned int mode struct net_device *dev = container_of(config->dev, struct net_device, dev); struct rtl838x_eth_priv *priv = netdev_priv(dev); - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); /* Restart TX/RX to port */ sw_w32_mask(0, 0x03, priv->r->mac_port_ctrl(priv->cpu_port)); } @@ -1479,7 +1479,7 @@ static void rtl838x_set_mac_hw(struct net_device *dev, u8 *mac) unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - pr_info("In %s\n", __func__); + pr_debug("In %s\n", __func__); sw_w32((mac[0] << 8) | mac[1], priv->r->mac); sw_w32((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], priv->r->mac + 4); @@ -1547,7 +1547,7 @@ static int rtl838x_get_link_ksettings(struct net_device *ndev, { struct rtl838x_eth_priv *priv = netdev_priv(ndev); - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); return phylink_ethtool_ksettings_get(priv->phylink, cmd); } @@ -1556,7 +1556,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev, { struct rtl838x_eth_priv *priv = netdev_priv(ndev); - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); return phylink_ethtool_ksettings_set(priv->phylink, cmd); } @@ -1678,7 +1678,7 @@ static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id, static int rtl838x_mdio_reset(struct mii_bus *bus) { - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); /* Disable MAC polling the PHY so that we can start configuration */ sw_w32(0x00000000, RTL838X_SMI_POLL_CTRL); @@ -1693,7 +1693,7 @@ static int rtl839x_mdio_reset(struct mii_bus *bus) { return 0; - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); /* BUG: The following does not work, but should! */ /* Disable MAC polling the PHY so that we can start configuration */ sw_w32(0x00000000, RTL839X_SMI_PORT_POLLING_CTRL); @@ -1710,7 +1710,7 @@ static int rtl931x_mdio_reset(struct mii_bus *bus) sw_w32(0x00000000, RTL931X_SMI_PORT_POLLING_CTRL); sw_w32(0x00000000, RTL931X_SMI_PORT_POLLING_CTRL + 4); - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); return 0; } @@ -1767,7 +1767,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) struct device_node *mii_np; int ret; - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); mii_np = of_get_child_by_name(priv->pdev->dev.of_node, "mdio-bus"); if (!mii_np) { @@ -1827,7 +1827,7 @@ err_put_node: static int rtl838x_mdio_remove(struct rtl838x_eth_priv *priv) { - pr_info("%s called\n", __func__); + pr_debug("%s called\n", __func__); if (!priv->mii_bus) return 0; From 0183ee2eb9905b83acc76453b88618bb8c199e0c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 11 Mar 2021 21:52:07 +0000 Subject: [PATCH 05/32] uboot-mediatek: update configs for MT7622 devies * make sure USB 2.0 works (useful for UEFI-booting eg. memtest86) * include more useful U-Boot config options on BPi-R64. Signed-off-by: Daniel Golle --- .../403-add-bananapi_bpi-r64_defconfigs.patch | 45 +++++++++++++++++-- .../patches/410-add-linksys-e8450.patch | 7 ++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch index 2fb2d3aa8f..5a7101a7fe 100644 --- a/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch +++ b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch @@ -1,9 +1,10 @@ --- /dev/null +++ b/configs/mt7622_bananapi_bpi-r64-sdmmc_defconfig -@@ -0,0 +1,124 @@ +@@ -0,0 +1,144 @@ +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_USE_DEFAULT_ENV_FILE=y @@ -13,6 +14,7 @@ +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 @@ -23,6 +25,7 @@ +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 @@ -36,6 +39,7 @@ +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 @@ -59,6 +63,7 @@ +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 @@ -70,6 +75,7 @@ +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 @@ -78,6 +84,8 @@ +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 @@ -93,7 +101,17 @@ +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 is not set +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y +CONFIG_PCI=y @@ -111,7 +129,9 @@ +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_SYSRESET_WATCHDOG=y +CONFIG_WDT_MTK=y @@ -184,10 +204,11 @@ +_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,125 @@ +@@ -0,0 +1,144 @@ +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_USE_DEFAULT_ENV_FILE=y @@ -197,8 +218,9 @@ +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_DEFAULT_ENV_FILE="bananapi_bpi-r64-sdmmc_env" +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_SMBIOS_PRODUCT_NAME="" +CONFIG_AUTOBOOT_KEYED=y @@ -207,6 +229,7 @@ +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 @@ -220,6 +243,7 @@ +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 @@ -243,6 +267,7 @@ +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 @@ -254,6 +279,7 @@ +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 @@ -262,6 +288,8 @@ +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 @@ -277,7 +305,17 @@ +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 is not set +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y +CONFIG_PCI=y @@ -295,6 +333,7 @@ +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 diff --git a/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch index e78641e8fe..9fe83725b3 100644 --- a/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch +++ b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch @@ -1,9 +1,10 @@ --- /dev/null +++ b/configs/mt7622_linksys_e8450_defconfig -@@ -0,0 +1,128 @@ +@@ -0,0 +1,133 @@ +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_USE_DEFAULT_ENV_FILE=y @@ -22,6 +23,7 @@ +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 @@ -95,6 +97,9 @@ +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 From 36b404a2260361ebd6abc7bf4a9f382c373f15ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Fri, 12 Mar 2021 14:29:51 +0100 Subject: [PATCH 06/32] bmips: switch to upstream bcm2835-rng reset patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch has been accepted upstream. Signed-off-by: Álvaro Fernández Rojas --- ...gs-rng-bcm2835-add-clock-constraints.patch | 38 ++++++++++++++ ...s-rng-bcm2835-document-reset-support.patch | 51 +++++++++++++++++++ ...054-hwrng-bcm2835-add-reset-support.patch} | 14 +++-- 3 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch create mode 100644 target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch rename target/linux/bmips/patches-5.10/{207-hwrng-bcm2835-add-reset-support.patch => 054-hwrng-bcm2835-add-reset-support.patch} (84%) diff --git a/target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch b/target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch new file mode 100644 index 0000000000..246293e384 --- /dev/null +++ b/target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch @@ -0,0 +1,38 @@ +From 0618e07ea3e0981d7765b43d3f7db39e739842eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Fri, 5 Mar 2021 08:01:30 +0100 +Subject: [PATCH 1/3] dt-bindings: rng: bcm2835: add clock constraints +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +brcm,bcm6368-rng controllers require enabling the IPSEC clock in order to get +a functional RNG. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Rob Herring +Acked-by: Florian Fainelli +Signed-off-by: Herbert Xu +--- + .../devicetree/bindings/rng/brcm,bcm2835.yaml | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml ++++ b/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml +@@ -35,6 +35,16 @@ required: + - compatible + - reg + ++if: ++ properties: ++ compatible: ++ enum: ++ - brcm,bcm6368-rng ++then: ++ required: ++ - clocks ++ - clock-names ++ + additionalProperties: false + + examples: diff --git a/target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch b/target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch new file mode 100644 index 0000000000..ce14a1037c --- /dev/null +++ b/target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch @@ -0,0 +1,51 @@ +From 381345820db55bf8e7289de047c24c00a2e3690d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Fri, 5 Mar 2021 08:01:31 +0100 +Subject: [PATCH 2/3] dt-bindings: rng: bcm2835: document reset support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +brcm,bcm6368-rng controllers require resetting the IPSEC clock in order to get +a functional RNG. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Rob Herring +Acked-by: Florian Fainelli +Signed-off-by: Herbert Xu +--- + .../devicetree/bindings/rng/brcm,bcm2835.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml ++++ b/Documentation/devicetree/bindings/rng/brcm,bcm2835.yaml +@@ -28,6 +28,12 @@ properties: + clock-names: + const: ipsec + ++ resets: ++ maxItems: 1 ++ ++ reset-names: ++ const: ipsec ++ + interrupts: + maxItems: 1 + +@@ -44,6 +50,8 @@ then: + required: + - clocks + - clock-names ++ - resets ++ - reset-names + + additionalProperties: false + +@@ -68,4 +76,7 @@ examples: + + clocks = <&periph_clk 18>; + clock-names = "ipsec"; ++ ++ resets = <&periph_rst 4>; ++ reset-names = "ipsec"; + }; diff --git a/target/linux/bmips/patches-5.10/207-hwrng-bcm2835-add-reset-support.patch b/target/linux/bmips/patches-5.10/054-hwrng-bcm2835-add-reset-support.patch similarity index 84% rename from target/linux/bmips/patches-5.10/207-hwrng-bcm2835-add-reset-support.patch rename to target/linux/bmips/patches-5.10/054-hwrng-bcm2835-add-reset-support.patch index 1da0e952a8..24b74817be 100644 --- a/target/linux/bmips/patches-5.10/207-hwrng-bcm2835-add-reset-support.patch +++ b/target/linux/bmips/patches-5.10/054-hwrng-bcm2835-add-reset-support.patch @@ -1,12 +1,14 @@ -From 846cd2c9eee7a99de29c743911cc047fdd56db02 Mon Sep 17 00:00:00 2001 +From e5f9f41d5e62004c913bfd4ddf06abe032f5ce1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= -Date: Mon, 22 Feb 2021 20:41:04 +0100 -Subject: [PATCH] hwrng: bcm2835: add reset support +Date: Fri, 5 Mar 2021 08:01:32 +0100 +Subject: [PATCH 3/3] hwrng: bcm2835 - add reset support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -BCM6368 devices need to reset the in order to generate true random numbers. +BCM6368 devices need to reset the IPSEC controller in order to generate true +random numbers. + This is what BCM6368 produces without a reset: root@OpenWrt:/# cat /dev/hwrng | rngtest -c 1000 rngtest 6.10 @@ -25,9 +27,11 @@ rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=37.253; avg=320.827; max=635.783)Mibits/s rngtest: FIPS tests speed: (min=12.141; avg=15.034; max=16.428)Mibits/s rngtest: Program run time: 1336176 microseconds -cat: write error: Broken pipe Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Philipp Zabel +Acked-by: Florian Fainelli +Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm2835-rng.c | 10 ++++++++++ 1 file changed, 10 insertions(+) From 1c48eee5b2bcfaf9815cc9a6f6664392d17164cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 18:07:57 +0100 Subject: [PATCH 07/32] kernel: backport Broadcom NVRAM driver cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactoring of bcm47xx_nvram driver. It's used by bcm47xx and bcm53xx. Signed-off-by: Rafał Miłecki --- ..._nvram-rename-finding-function-and-i.patch | 85 +++++++++++++++++ ..._nvram-add-helper-checking-for-NVRAM.patch | 95 +++++++++++++++++++ ...7xx_nvram-extract-code-copying-NVRAM.patch | 86 +++++++++++++++++ ..._nvram-look-for-NVRAM-with-for-inste.patch | 42 ++++++++ ..._nvram-inline-code-checking-NVRAM-si.patch | 75 +++++++++++++++ ..._nvram-rename-finding-function-and-i.patch | 80 ++++++++++++++++ ..._nvram-add-helper-checking-for-NVRAM.patch | 90 ++++++++++++++++++ ...7xx_nvram-extract-code-copying-NVRAM.patch | 80 ++++++++++++++++ ..._nvram-look-for-NVRAM-with-for-inste.patch | 37 ++++++++ ..._nvram-inline-code-checking-NVRAM-si.patch | 70 ++++++++++++++ 10 files changed, 740 insertions(+) create mode 100644 target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch create mode 100644 target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch create mode 100644 target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch create mode 100644 target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch create mode 100644 target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch create mode 100644 target/linux/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch create mode 100644 target/linux/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch create mode 100644 target/linux/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch create mode 100644 target/linux/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch create mode 100644 target/linux/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch diff --git a/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch b/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch new file mode 100644 index 0000000000..711ec28f52 --- /dev/null +++ b/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch @@ -0,0 +1,85 @@ +From fb009cbdd0693bd633f11e99526617b3d392cfad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:16 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: rename finding function and its + variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Use "bcm47xx_" function name prefix for consistency +2. It takes flash start as argument so s/iobase/flash_start/ +3. "off" was used for finding flash end so just call it "flash_size" + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 24 ++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c +index 835ece9c00f1..b04007adc79f 100644 +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem *end) + return 0; + } + +-/* Probe for NVRAM header */ +-static int nvram_find_and_copy(void __iomem *iobase, u32 lim) ++/** ++ * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it ++ */ ++static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { + struct nvram_header __iomem *header; +- u32 off; ++ size_t flash_size; + u32 size; + + if (nvram_len) { +@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __iomem *iobase, u32 lim) + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- off = FLASH_MIN; +- while (off <= lim) { ++ flash_size = FLASH_MIN; ++ while (flash_size <= res_size) { + /* Windowed flash access */ +- size = find_nvram_size(iobase + off); ++ size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(iobase + off - size); ++ header = (struct nvram_header *)(flash_start + flash_size - size); + goto found; + } +- off <<= 1; ++ flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(iobase + 4096); ++ header = (struct nvram_header *)(flash_start + 4096); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; + } + +- header = (struct nvram_header *)(iobase + 1024); ++ header = (struct nvram_header *)(flash_start + 1024); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; +@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base, u32 lim) + if (!iobase) + return -ENOMEM; + +- err = nvram_find_and_copy(iobase, lim); ++ err = bcm47xx_nvram_find_and_copy(iobase, lim); + + iounmap(iobase); + +-- +2.26.2 + diff --git a/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch b/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch new file mode 100644 index 0000000000..beef1cf675 --- /dev/null +++ b/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch @@ -0,0 +1,95 @@ +From 0a24b51a3264a3f942a75025ea5ff6133c8989b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:17 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: add helper checking for NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This avoids duplicating code doing casting and checking for NVRAM magic. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 30 ++++++++++++++--------- + 1 file changed, 18 insertions(+), 12 deletions(-) + +diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c +index b04007adc79f..99f3ec180be6 100644 +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -34,14 +34,20 @@ static char nvram_buf[NVRAM_SPACE]; + static size_t nvram_len; + static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000}; + ++/** ++ * bcm47xx_nvram_is_valid - check for a valid NVRAM at specified memory ++ */ ++static bool bcm47xx_nvram_is_valid(void __iomem *nvram) ++{ ++ return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; ++} ++ + static u32 find_nvram_size(void __iomem *end) + { +- struct nvram_header __iomem *header; + int i; + + for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- header = (struct nvram_header *)(end - nvram_sizes[i]); +- if (header->magic == NVRAM_MAGIC) ++ if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) + return nvram_sizes[i]; + } + +@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + { + struct nvram_header __iomem *header; + size_t flash_size; ++ size_t offset; + u32 size; + + if (nvram_len) { +@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(flash_start + flash_size - size); ++ offset = flash_size - size; + goto found; + } + flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(flash_start + 4096); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ ++ offset = 4096; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + +- header = (struct nvram_header *)(flash_start + 1024); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ offset = 1024; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + + pr_err("no nvram found\n"); + return -ENXIO; + + found: ++ header = (struct nvram_header *)(flash_start + offset); + __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); + nvram_len = ((struct nvram_header *)(nvram_buf))->len; ++ size = res_size - offset; + if (nvram_len > size) { + pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); + nvram_len = size; +-- +2.26.2 + diff --git a/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch b/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch new file mode 100644 index 0000000000..67ec157f5e --- /dev/null +++ b/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch @@ -0,0 +1,86 @@ +From 298923cf999cecd2ef06df126f85a3d68da8c4d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:18 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: extract code copying NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This simplifies function finding NVRAM. It doesn't directly deal with +NVRAM structure anymore and is a bit smaller. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 43 +++++++++++++---------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c +index 99f3ec180be6..09f51b95849e 100644 +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -54,12 +54,35 @@ static u32 find_nvram_size(void __iomem *end) + return 0; + } + ++/** ++ * bcm47xx_nvram_copy - copy NVRAM to internal buffer ++ */ ++static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size) ++{ ++ struct nvram_header __iomem *header = nvram_start; ++ size_t copy_size; ++ ++ copy_size = header->len; ++ if (copy_size > res_size) { ++ pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); ++ copy_size = res_size; ++ } ++ if (copy_size >= NVRAM_SPACE) { ++ pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", ++ copy_size, NVRAM_SPACE - 1); ++ copy_size = NVRAM_SPACE - 1; ++ } ++ ++ __ioread32_copy(nvram_buf, nvram_start, DIV_ROUND_UP(copy_size, 4)); ++ nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ nvram_len = copy_size; ++} ++ + /** + * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it + */ + static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { +- struct nvram_header __iomem *header; + size_t flash_size; + size_t offset; + u32 size; +@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + return -ENXIO; + + found: +- header = (struct nvram_header *)(flash_start + offset); +- __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); +- nvram_len = ((struct nvram_header *)(nvram_buf))->len; +- size = res_size - offset; +- if (nvram_len > size) { +- pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); +- nvram_len = size; +- } +- if (nvram_len >= NVRAM_SPACE) { +- pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", +- nvram_len, NVRAM_SPACE - 1); +- nvram_len = NVRAM_SPACE - 1; +- } +- /* proceed reading data after header */ +- __ioread32_copy(nvram_buf + sizeof(*header), header + 1, +- DIV_ROUND_UP(nvram_len, 4)); +- nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ bcm47xx_nvram_copy(flash_start + offset, res_size - offset); + + return 0; + } +-- +2.26.2 + diff --git a/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch b/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch new file mode 100644 index 0000000000..0dadc601a9 --- /dev/null +++ b/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch @@ -0,0 +1,42 @@ +From 98b68324f67236e8c9152976535dc1f27fb67ba8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:19 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: look for NVRAM with for instead of + while +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This loop requires variable initialization, stop condition and post +iteration increment. It's pretty much a for loop definition. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c +index 09f51b95849e..1d2271b1e07a 100644 +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- flash_size = FLASH_MIN; +- while (flash_size <= res_size) { ++ for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { + offset = flash_size - size; + goto found; + } +- flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +-- +2.26.2 + diff --git a/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch b/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch new file mode 100644 index 0000000000..065543184f --- /dev/null +++ b/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch @@ -0,0 +1,75 @@ +From f52da4ccfec9192e17f5c16260dfdd6d3ea76f65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:20 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: inline code checking NVRAM size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Separated function was not improving code quality much (or at all). +Moreover it expected possible flash end address as argument and it was +returning NVRAM size. + +The new code always operates on offsets which means less logic and less +calculations. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 25 +++++++---------------- + 1 file changed, 7 insertions(+), 18 deletions(-) + +diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c +index 1d2271b1e07a..bd235833b687 100644 +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void __iomem *nvram) + return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; + } + +-static u32 find_nvram_size(void __iomem *end) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) +- return nvram_sizes[i]; +- } +- +- return 0; +-} +- + /** + * bcm47xx_nvram_copy - copy NVRAM to internal buffer + */ +@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + { + size_t flash_size; + size_t offset; +- u32 size; ++ int i; + + if (nvram_len) { + pr_warn("nvram already initialized\n"); +@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ ++ ++ /* Try every possible flash size and check for NVRAM at its end */ + for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { +- /* Windowed flash access */ +- size = find_nvram_size(flash_start + flash_size); +- if (size) { +- offset = flash_size - size; +- goto found; ++ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { ++ offset = flash_size - nvram_sizes[i]; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) ++ goto found; + } + } + +-- +2.26.2 + diff --git a/target/linux/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch b/target/linux/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch new file mode 100644 index 0000000000..19938704b7 --- /dev/null +++ b/target/linux/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch @@ -0,0 +1,80 @@ +From fb009cbdd0693bd633f11e99526617b3d392cfad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:16 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: rename finding function and its + variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Use "bcm47xx_" function name prefix for consistency +2. It takes flash start as argument so s/iobase/flash_start/ +3. "off" was used for finding flash end so just call it "flash_size" + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 24 ++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem + return 0; + } + +-/* Probe for NVRAM header */ +-static int nvram_find_and_copy(void __iomem *iobase, u32 lim) ++/** ++ * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it ++ */ ++static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { + struct nvram_header __iomem *header; +- u32 off; ++ size_t flash_size; + u32 size; + + if (nvram_len) { +@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __io + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- off = FLASH_MIN; +- while (off <= lim) { ++ flash_size = FLASH_MIN; ++ while (flash_size <= res_size) { + /* Windowed flash access */ +- size = find_nvram_size(iobase + off); ++ size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(iobase + off - size); ++ header = (struct nvram_header *)(flash_start + flash_size - size); + goto found; + } +- off <<= 1; ++ flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(iobase + 4096); ++ header = (struct nvram_header *)(flash_start + 4096); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; + } + +- header = (struct nvram_header *)(iobase + 1024); ++ header = (struct nvram_header *)(flash_start + 1024); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; +@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base + if (!iobase) + return -ENOMEM; + +- err = nvram_find_and_copy(iobase, lim); ++ err = bcm47xx_nvram_find_and_copy(iobase, lim); + + iounmap(iobase); + diff --git a/target/linux/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch b/target/linux/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch new file mode 100644 index 0000000000..6ab072883d --- /dev/null +++ b/target/linux/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch @@ -0,0 +1,90 @@ +From 0a24b51a3264a3f942a75025ea5ff6133c8989b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:17 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: add helper checking for NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This avoids duplicating code doing casting and checking for NVRAM magic. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 30 ++++++++++++++--------- + 1 file changed, 18 insertions(+), 12 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -34,14 +34,20 @@ static char nvram_buf[NVRAM_SPACE]; + static size_t nvram_len; + static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000}; + ++/** ++ * bcm47xx_nvram_is_valid - check for a valid NVRAM at specified memory ++ */ ++static bool bcm47xx_nvram_is_valid(void __iomem *nvram) ++{ ++ return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; ++} ++ + static u32 find_nvram_size(void __iomem *end) + { +- struct nvram_header __iomem *header; + int i; + + for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- header = (struct nvram_header *)(end - nvram_sizes[i]); +- if (header->magic == NVRAM_MAGIC) ++ if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) + return nvram_sizes[i]; + } + +@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(v + { + struct nvram_header __iomem *header; + size_t flash_size; ++ size_t offset; + u32 size; + + if (nvram_len) { +@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(v + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(flash_start + flash_size - size); ++ offset = flash_size - size; + goto found; + } + flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(flash_start + 4096); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ ++ offset = 4096; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + +- header = (struct nvram_header *)(flash_start + 1024); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ offset = 1024; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + + pr_err("no nvram found\n"); + return -ENXIO; + + found: ++ header = (struct nvram_header *)(flash_start + offset); + __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); + nvram_len = ((struct nvram_header *)(nvram_buf))->len; ++ size = res_size - offset; + if (nvram_len > size) { + pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); + nvram_len = size; diff --git a/target/linux/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch b/target/linux/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch new file mode 100644 index 0000000000..a1351f1197 --- /dev/null +++ b/target/linux/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch @@ -0,0 +1,80 @@ +From 298923cf999cecd2ef06df126f85a3d68da8c4d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:18 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: extract code copying NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This simplifies function finding NVRAM. It doesn't directly deal with +NVRAM structure anymore and is a bit smaller. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 43 +++++++++++++---------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -55,11 +55,34 @@ static u32 find_nvram_size(void __iomem + } + + /** ++ * bcm47xx_nvram_copy - copy NVRAM to internal buffer ++ */ ++static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size) ++{ ++ struct nvram_header __iomem *header = nvram_start; ++ size_t copy_size; ++ ++ copy_size = header->len; ++ if (copy_size > res_size) { ++ pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); ++ copy_size = res_size; ++ } ++ if (copy_size >= NVRAM_SPACE) { ++ pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", ++ copy_size, NVRAM_SPACE - 1); ++ copy_size = NVRAM_SPACE - 1; ++ } ++ ++ __ioread32_copy(nvram_buf, nvram_start, DIV_ROUND_UP(copy_size, 4)); ++ nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ nvram_len = copy_size; ++} ++ ++/** + * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it + */ + static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { +- struct nvram_header __iomem *header; + size_t flash_size; + size_t offset; + u32 size; +@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(v + return -ENXIO; + + found: +- header = (struct nvram_header *)(flash_start + offset); +- __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); +- nvram_len = ((struct nvram_header *)(nvram_buf))->len; +- size = res_size - offset; +- if (nvram_len > size) { +- pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); +- nvram_len = size; +- } +- if (nvram_len >= NVRAM_SPACE) { +- pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", +- nvram_len, NVRAM_SPACE - 1); +- nvram_len = NVRAM_SPACE - 1; +- } +- /* proceed reading data after header */ +- __ioread32_copy(nvram_buf + sizeof(*header), header + 1, +- DIV_ROUND_UP(nvram_len, 4)); +- nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ bcm47xx_nvram_copy(flash_start + offset, res_size - offset); + + return 0; + } diff --git a/target/linux/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch b/target/linux/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch new file mode 100644 index 0000000000..059a13220b --- /dev/null +++ b/target/linux/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch @@ -0,0 +1,37 @@ +From 98b68324f67236e8c9152976535dc1f27fb67ba8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:19 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: look for NVRAM with for instead of + while +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This loop requires variable initialization, stop condition and post +iteration increment. It's pretty much a for loop definition. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(v + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- flash_size = FLASH_MIN; +- while (flash_size <= res_size) { ++ for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { + offset = flash_size - size; + goto found; + } +- flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ diff --git a/target/linux/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch b/target/linux/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch new file mode 100644 index 0000000000..21d250049e --- /dev/null +++ b/target/linux/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch @@ -0,0 +1,70 @@ +From f52da4ccfec9192e17f5c16260dfdd6d3ea76f65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:20 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: inline code checking NVRAM size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Separated function was not improving code quality much (or at all). +Moreover it expected possible flash end address as argument and it was +returning NVRAM size. + +The new code always operates on offsets which means less logic and less +calculations. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 25 +++++++---------------- + 1 file changed, 7 insertions(+), 18 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void + return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; + } + +-static u32 find_nvram_size(void __iomem *end) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) +- return nvram_sizes[i]; +- } +- +- return 0; +-} +- + /** + * bcm47xx_nvram_copy - copy NVRAM to internal buffer + */ +@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(v + { + size_t flash_size; + size_t offset; +- u32 size; ++ int i; + + if (nvram_len) { + pr_warn("nvram already initialized\n"); +@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(v + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ ++ ++ /* Try every possible flash size and check for NVRAM at its end */ + for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { +- /* Windowed flash access */ +- size = find_nvram_size(flash_start + flash_size); +- if (size) { +- offset = flash_size - size; +- goto found; ++ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { ++ offset = flash_size - nvram_sizes[i]; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) ++ goto found; + } + } + From baf04eed028a838518c65be48cbaabe0892343aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 18:10:09 +0100 Subject: [PATCH 08/32] bcm53xx: initialize NVRAM from NVMEM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NVRAM access may be needed early in boot process. Reading it using mtd happens quite late in the init process. Add NVRAM initialization to the NVMEM driver which comes up early and depends on IO mapping only. This is required by Linksys devices which use NVRAM content for proper partitioning (detecting current firmware partition). Signed-off-by: Rafał Miłecki --- ...xx_nvram-support-init-from-IO-memory.patch | 61 +++++++++++++++++++ ...-provide-NVMEM-content-to-the-NVRAM-.patch | 31 ++++++++++ 2 files changed, 92 insertions(+) create mode 100644 target/linux/bcm53xx/patches-5.4/800-0001-firmware-bcm47xx_nvram-support-init-from-IO-memory.patch create mode 100644 target/linux/bcm53xx/patches-5.4/800-0002-nvmem-brcm_nvram-provide-NVMEM-content-to-the-NVRAM-.patch diff --git a/target/linux/bcm53xx/patches-5.4/800-0001-firmware-bcm47xx_nvram-support-init-from-IO-memory.patch b/target/linux/bcm53xx/patches-5.4/800-0001-firmware-bcm47xx_nvram-support-init-from-IO-memory.patch new file mode 100644 index 0000000000..86792d6ebf --- /dev/null +++ b/target/linux/bcm53xx/patches-5.4/800-0001-firmware-bcm47xx_nvram-support-init-from-IO-memory.patch @@ -0,0 +1,61 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Mar 2021 08:24:44 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: support init from IO memory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 17 +++++++++++++++++ + include/linux/bcm47xx_nvram.h | 6 ++++++ + 2 files changed, 23 insertions(+) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -110,6 +110,23 @@ found: + return 0; + } + ++int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size) ++{ ++ if (nvram_len) { ++ pr_warn("nvram already initialized\n"); ++ return -EEXIST; ++ } ++ ++ if (!bcm47xx_nvram_is_valid(nvram_start)) { ++ pr_err("No valid NVRAM found\n"); ++ return -ENOENT; ++ } ++ ++ bcm47xx_nvram_copy(nvram_start, res_size); ++ ++ return 0; ++} ++ + /* + * On bcm47xx we need access to the NVRAM very early, so we can't use mtd + * subsystem to access flash. We can't even use platform device / driver to +--- a/include/linux/bcm47xx_nvram.h ++++ b/include/linux/bcm47xx_nvram.h +@@ -11,6 +11,7 @@ + #include + + #ifdef CONFIG_BCM47XX_NVRAM ++int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size); + int bcm47xx_nvram_init_from_mem(u32 base, u32 lim); + int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len); + int bcm47xx_nvram_gpio_pin(const char *name); +@@ -20,6 +21,11 @@ static inline void bcm47xx_nvram_release + vfree(nvram); + }; + #else ++static inline int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, ++ size_t res_size) ++{ ++ return -ENOTSUPP; ++} + static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim) + { + return -ENOTSUPP; diff --git a/target/linux/bcm53xx/patches-5.4/800-0002-nvmem-brcm_nvram-provide-NVMEM-content-to-the-NVRAM-.patch b/target/linux/bcm53xx/patches-5.4/800-0002-nvmem-brcm_nvram-provide-NVMEM-content-to-the-NVRAM-.patch new file mode 100644 index 0000000000..cf5952ad5f --- /dev/null +++ b/target/linux/bcm53xx/patches-5.4/800-0002-nvmem-brcm_nvram-provide-NVMEM-content-to-the-NVRAM-.patch @@ -0,0 +1,31 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Mar 2021 08:26:14 +0100 +Subject: [PATCH] nvmem: brcm_nvram: provide NVMEM content to the NVRAM driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + drivers/nvmem/brcm_nvram.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -3,6 +3,7 @@ + * Copyright (C) 2021 Rafał Miłecki + */ + ++#include + #include + #include + #include +@@ -46,6 +47,8 @@ static int brcm_nvram_probe(struct platf + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + ++ bcm47xx_nvram_init_from_iomem(priv->base, resource_size(res)); ++ + config.dev = dev; + config.priv = priv; + config.size = resource_size(res); From b2b75e1939313ee64e6ff3f3374477a81fdb3746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 17:36:58 +0100 Subject: [PATCH 09/32] kernel: add two more missed 5.10 backports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those were added to 5.4 but missed while introducing 5.10 kernel. Signed-off-by: Rafał Miłecki --- ...move-partition-binding-to-its-own-fi.patch | 115 ++++++++++++++++++ ...d-add-binding-for-BCM4908-partitions.patch | 92 ++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 target/linux/generic/backport-5.10/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch create mode 100644 target/linux/generic/backport-5.10/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch diff --git a/target/linux/generic/backport-5.10/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch b/target/linux/generic/backport-5.10/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch new file mode 100644 index 0000000000..f3b1179ecd --- /dev/null +++ b/target/linux/generic/backport-5.10/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch @@ -0,0 +1,115 @@ +From 6418522022c706fd867b00b2571edba48b8fa8c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Feb 2021 23:04:25 +0100 +Subject: [PATCH] dt-bindings: mtd: move partition binding to its own file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Single partition binding is quite common and may be: +1. Used by multiple parsers +2. Extended for more specific cases + +Move it to separated file to avoid code duplication. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Rob Herring +Signed-off-by: Richard Weinberger +--- + .../mtd/partitions/fixed-partitions.yaml | 33 +------------ + .../bindings/mtd/partitions/partition.yaml | 47 +++++++++++++++++++ + 2 files changed, 48 insertions(+), 32 deletions(-) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/partition.yaml + +--- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml ++++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml +@@ -27,38 +27,7 @@ properties: + + patternProperties: + "@[0-9a-f]+$": +- description: node describing a single flash partition +- type: object +- +- properties: +- reg: +- description: partition's offset and size within the flash +- maxItems: 1 +- +- label: +- description: The label / name for this partition. If omitted, the label +- is taken from the node name (excluding the unit address). +- +- read-only: +- description: This parameter, if present, is a hint that this partition +- should only be mounted read-only. This is usually used for flash +- partitions containing early-boot firmware images or data which should +- not be clobbered. +- type: boolean +- +- lock: +- description: Do not unlock the partition at initialization time (not +- supported on all devices) +- type: boolean +- +- slc-mode: +- description: This parameter, if present, allows one to emulate SLC mode +- on a partition attached to an MLC NAND thus making this partition +- immune to paired-pages corruptions +- type: boolean +- +- required: +- - reg ++ $ref: "partition.yaml#" + + required: + - "#address-cells" +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml +@@ -0,0 +1,47 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/partition.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Partition ++ ++description: | ++ This binding describes a single flash partition. Each partition must have its ++ relative offset and size specified. Depending on partition function extra ++ properties can be used. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ reg: ++ description: partition's offset and size within the flash ++ maxItems: 1 ++ ++ label: ++ description: The label / name for this partition. If omitted, the label ++ is taken from the node name (excluding the unit address). ++ ++ read-only: ++ description: This parameter, if present, is a hint that this partition ++ should only be mounted read-only. This is usually used for flash ++ partitions containing early-boot firmware images or data which should ++ not be clobbered. ++ type: boolean ++ ++ lock: ++ description: Do not unlock the partition at initialization time (not ++ supported on all devices) ++ type: boolean ++ ++ slc-mode: ++ description: This parameter, if present, allows one to emulate SLC mode ++ on a partition attached to an MLC NAND thus making this partition ++ immune to paired-pages corruptions ++ type: boolean ++ ++required: ++ - reg ++ ++additionalProperties: true diff --git a/target/linux/generic/backport-5.10/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch b/target/linux/generic/backport-5.10/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch new file mode 100644 index 0000000000..8576c7d78d --- /dev/null +++ b/target/linux/generic/backport-5.10/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch @@ -0,0 +1,92 @@ +From 6e9dff6fe3fbc452f16566e4a7e293b0decefdba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Feb 2021 23:04:26 +0100 +Subject: [PATCH] dt-bindings: mtd: add binding for BCM4908 partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM4908 uses fixed partitions layout but function of some partitions may +vary. Some devices use multiple firmware partitions and those partitions +should be marked to let system discover their purpose. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Richard Weinberger +--- + .../partitions/brcm,bcm4908-partitions.yaml | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml +@@ -0,0 +1,70 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/brcm,bcm4908-partitions.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom BCM4908 partitioning ++ ++description: | ++ Broadcom BCM4908 CFE bootloader supports two firmware partitions. One is used ++ for regular booting, the other is treated as fallback. ++ ++ This binding allows defining all fixed partitions and marking those containing ++ firmware. System can use that information e.g. for booting or flashing ++ purposes. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ compatible: ++ const: brcm,bcm4908-partitions ++ ++ "#address-cells": ++ enum: [ 1, 2 ] ++ ++ "#size-cells": ++ enum: [ 1, 2 ] ++ ++patternProperties: ++ "^partition@[0-9a-f]+$": ++ $ref: "partition.yaml#" ++ properties: ++ compatible: ++ const: brcm,bcm4908-firmware ++ unevaluatedProperties: false ++ ++required: ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ partitions { ++ compatible = "brcm,bcm4908-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "cferom"; ++ reg = <0x0 0x100000>; ++ }; ++ ++ partition@100000 { ++ compatible = "brcm,bcm4908-firmware"; ++ reg = <0x100000 0xf00000>; ++ }; ++ ++ partition@1000000 { ++ compatible = "brcm,bcm4908-firmware"; ++ reg = <0x1000000 0xf00000>; ++ }; ++ ++ partition@1f00000 { ++ label = "calibration"; ++ reg = <0x1f00000 0x100000>; ++ }; ++ }; From deceb039931cd8eb011a0eb65731f335662070d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 17:37:59 +0100 Subject: [PATCH 10/32] kernel: move mtd ofpart accepted patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move upstream patch to the backport directory. Signed-off-by: Rafał Miłecki --- ....13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch} | 0 ....13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename target/linux/generic/{pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch => backport-5.10/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch} (100%) rename target/linux/generic/{pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch => backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch} (100%) diff --git a/target/linux/generic/pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/target/linux/generic/backport-5.10/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch similarity index 100% rename from target/linux/generic/pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch rename to target/linux/generic/backport-5.10/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch diff --git a/target/linux/generic/pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/target/linux/generic/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch similarity index 100% rename from target/linux/generic/pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch rename to target/linux/generic/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch From e90e75b12c818c49704755b9e530491aee2d554c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 18:30:01 +0100 Subject: [PATCH 11/32] kernel: add pending mtd patches adding NVMEM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's meant to provide upstream support for mtd & NVMEM. It's required e.g. for reading MAC address from mtd partition content. It seems to be in a final shape so it's worth testing. Signed-off-by: Rafał Miłecki --- ...rt-limit-parsing-of-deprecated-DT-sy.patch | 69 +++++++++++ ...rt-limit-parsing-of-deprecated-DT-sy.patch | 69 +++++++++++ ...em-cells-compatible-to-parse-mtd-as-.patch | 38 ++++++ ...vmem-nvmem-drop-nodename-restriction.patch | 25 ++++ ...Document-use-of-nvmem-cells-compatib.patch | 117 ++++++++++++++++++ .../480-mtd-set-rootfs-to-be-root-dev.patch | 2 +- ...-mtd-core-add-get_mtd_device_by_node.patch | 2 +- ...em-cells-compatible-to-parse-mtd-as-.patch | 38 ++++++ ...vmem-nvmem-drop-nodename-restriction.patch | 25 ++++ ...Document-use-of-nvmem-cells-compatib.patch | 117 ++++++++++++++++++ .../480-mtd-set-rootfs-to-be-root-dev.patch | 2 +- ...-mtd-core-add-get_mtd_device_by_node.patch | 2 +- .../202-linksys-find-active-root.patch | 4 +- .../202-linksys-find-active-root.patch | 4 +- .../patches-5.4/0101-find_active_root.patch | 8 +- .../patches-5.10/400-find_active_root.patch | 4 +- .../patches-5.4/400-find_active_root.patch | 4 +- ...or-support-mtd-name-from-device-tree.patch | 2 +- 18 files changed, 515 insertions(+), 17 deletions(-) create mode 100644 target/linux/generic/backport-5.10/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch create mode 100644 target/linux/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch create mode 100644 target/linux/generic/pending-5.10/401-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch create mode 100644 target/linux/generic/pending-5.10/401-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch create mode 100644 target/linux/generic/pending-5.10/401-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch create mode 100644 target/linux/generic/pending-5.4/405-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch create mode 100644 target/linux/generic/pending-5.4/405-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch create mode 100644 target/linux/generic/pending-5.4/405-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch diff --git a/target/linux/generic/backport-5.10/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch b/target/linux/generic/backport-5.10/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch new file mode 100644 index 0000000000..55a91d7680 --- /dev/null +++ b/target/linux/generic/backport-5.10/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch @@ -0,0 +1,69 @@ +From 2d751203aacf86a1b301a188d8551c7da91043ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 2 Mar 2021 20:00:12 +0100 +Subject: [PATCH] mtd: parsers: ofpart: limit parsing of deprecated DT syntax +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For backward compatibility ofpart still supports the old syntax like: +spi-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + }; +}; +(without "partitions" subnode). + +There is no reason however to support nested partitions without a clear +"compatible" string like: +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; +(we never officially supported or documented that). + +Make sure ofpart doesn't attempt to parse above. + +Cc: Ansuel Smith +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210302190012.1255-1-zajec5@gmail.com +--- + drivers/mtd/parsers/ofpart_core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -53,7 +53,7 @@ static int parse_fixed_partitions(struct + return 0; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node) { ++ if (!ofpart_node && !master->parent) { + /* + * We might get here even when ofpart isn't used at all (e.g., + * when using another parser), so don't be louder than +@@ -64,6 +64,8 @@ static int parse_fixed_partitions(struct + ofpart_node = mtd_node; + dedicated = false; + } ++ if (!ofpart_node) ++ return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/target/linux/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch b/target/linux/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch new file mode 100644 index 0000000000..35058adba7 --- /dev/null +++ b/target/linux/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch @@ -0,0 +1,69 @@ +From 2d751203aacf86a1b301a188d8551c7da91043ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 2 Mar 2021 20:00:12 +0100 +Subject: [PATCH] mtd: parsers: ofpart: limit parsing of deprecated DT syntax +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For backward compatibility ofpart still supports the old syntax like: +spi-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + }; +}; +(without "partitions" subnode). + +There is no reason however to support nested partitions without a clear +"compatible" string like: +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; +(we never officially supported or documented that). + +Make sure ofpart doesn't attempt to parse above. + +Cc: Ansuel Smith +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210302190012.1255-1-zajec5@gmail.com +--- + drivers/mtd/parsers/ofpart_core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -53,7 +53,7 @@ static int parse_fixed_partitions(struct + return 0; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node) { ++ if (!ofpart_node && !mtd_is_partition(master)) { + /* + * We might get here even when ofpart isn't used at all (e.g., + * when using another parser), so don't be louder than +@@ -64,6 +64,8 @@ static int parse_fixed_partitions(struct + ofpart_node = mtd_node; + dedicated = false; + } ++ if (!ofpart_node) ++ return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/target/linux/generic/pending-5.10/401-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch b/target/linux/generic/pending-5.10/401-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch new file mode 100644 index 0000000000..28335cb71f --- /dev/null +++ b/target/linux/generic/pending-5.10/401-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch @@ -0,0 +1,38 @@ +From a5d83d6e2bc747b13f347962d4b335d70b23559b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:19 +0100 +Subject: [PATCH] mtd: core: add nvmem-cells compatible to parse mtd as nvmem + cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Partitions that contains the nvmem-cells compatible will register +their direct subonodes as nvmem cells and the node will be treated as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Tested-by: Rafał Miłecki +--- + drivers/mtd/mtdcore.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv + + static int mtd_nvmem_add(struct mtd_info *mtd) + { ++ struct device_node *node = mtd_get_of_node(mtd); + struct nvmem_config config = {}; + + config.id = -1; +@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info + config.stride = 1; + config.read_only = true; + config.root_only = true; +- config.no_of_node = true; ++ config.no_of_node = !of_device_is_compatible(node, "nvmem-cells"); + config.priv = mtd; + + mtd->nvmem = nvmem_register(&config); diff --git a/target/linux/generic/pending-5.10/401-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch b/target/linux/generic/pending-5.10/401-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch new file mode 100644 index 0000000000..14ea3f6b8c --- /dev/null +++ b/target/linux/generic/pending-5.10/401-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch @@ -0,0 +1,25 @@ +From 42645976c3289b03a12f1bd2bc131fd98fc27170 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:20 +0100 +Subject: [PATCH] devicetree: nvmem: nvmem: drop $nodename restriction + +Drop $nodename restriction as now mtd partition can also be used as +nvmem provider. + +Signed-off-by: Ansuel Smith +--- + Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 --- + 1 file changed, 3 deletions(-) + +--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml ++++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml +@@ -20,9 +20,6 @@ description: | + storage device. + + properties: +- $nodename: +- pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$" +- + "#address-cells": + const: 1 + diff --git a/target/linux/generic/pending-5.10/401-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch b/target/linux/generic/pending-5.10/401-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch new file mode 100644 index 0000000000..0eb4c637cf --- /dev/null +++ b/target/linux/generic/pending-5.10/401-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch @@ -0,0 +1,117 @@ +From 377aa0135dc8489312edd3184d143ce3a89ff7ee Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:21 +0100 +Subject: [PATCH] dt-bindings: mtd: Document use of nvmem-cells compatible + +Document nvmem-cells compatible used to treat mtd partitions as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +--- + .../bindings/mtd/partitions/nvmem-cells.yaml | 99 +++++++++++++++++++ + 1 file changed, 99 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml +@@ -0,0 +1,99 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Nvmem cells ++ ++description: | ++ Any partition containing the compatible "nvmem-cells" will register as a ++ nvmem provider. ++ Each direct subnodes represents a nvmem cell following the nvmem binding. ++ Nvmem binding to declare nvmem-cells can be found in: ++ Documentation/devicetree/bindings/nvmem/nvmem.yaml ++ ++maintainers: ++ - Ansuel Smith ++ ++allOf: ++ - $ref: /schemas/nvmem/nvmem.yaml# ++ ++properties: ++ compatible: ++ const: nvmem-cells ++ ++required: ++ - compatible ++ ++additionalProperties: true ++ ++examples: ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* ... */ ++ ++ }; ++ art: art@1200000 { ++ compatible = "nvmem-cells"; ++ reg = <0x1200000 0x0140000>; ++ label = "art"; ++ read-only; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ macaddr_gmac1: macaddr_gmac1@0 { ++ reg = <0x0 0x6>; ++ }; ++ ++ macaddr_gmac2: macaddr_gmac2@6 { ++ reg = <0x6 0x6>; ++ }; ++ ++ pre_cal_24g: pre_cal_24g@1000 { ++ reg = <0x1000 0x2f20>; ++ }; ++ ++ pre_cal_5g: pre_cal_5g@5000{ ++ reg = <0x5000 0x2f20>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bootloader"; ++ reg = <0x000000 0x100000>; ++ read-only; ++ }; ++ ++ firmware@100000 { ++ compatible = "brcm,trx"; ++ label = "firmware"; ++ reg = <0x100000 0xe00000>; ++ }; ++ ++ calibration@f00000 { ++ compatible = "nvmem-cells"; ++ label = "calibration"; ++ reg = <0xf00000 0x100000>; ++ ranges = <0 0xf00000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ wifi0@0 { ++ reg = <0x000000 0x080000>; ++ }; ++ ++ wifi1@80000 { ++ reg = <0x080000 0x080000>; ++ }; ++ }; ++ }; diff --git a/target/linux/generic/pending-5.10/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/pending-5.10/480-mtd-set-rootfs-to-be-root-dev.patch index 11cdc179d2..e01b991942 100644 --- a/target/linux/generic/pending-5.10/480-mtd-set-rootfs-to-be-root-dev.patch +++ b/target/linux/generic/pending-5.10/480-mtd-set-rootfs-to-be-root-dev.patch @@ -20,7 +20,7 @@ Signed-off-by: Gabor Juhos #include #include -@@ -692,6 +693,15 @@ int add_mtd_device(struct mtd_info *mtd) +@@ -693,6 +694,15 @@ int add_mtd_device(struct mtd_info *mtd) of this try_ nonsense, and no bitching about it either. :) */ __module_get(THIS_MODULE); diff --git a/target/linux/generic/pending-5.10/495-mtd-core-add-get_mtd_device_by_node.patch b/target/linux/generic/pending-5.10/495-mtd-core-add-get_mtd_device_by_node.patch index 98c5c2ef19..7a7ad6b263 100644 --- a/target/linux/generic/pending-5.10/495-mtd-core-add-get_mtd_device_by_node.patch +++ b/target/linux/generic/pending-5.10/495-mtd-core-add-get_mtd_device_by_node.patch @@ -17,7 +17,7 @@ Reviewed-by: Miquel Raynal --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -1052,6 +1052,44 @@ out_unlock: +@@ -1053,6 +1053,44 @@ out_unlock: } EXPORT_SYMBOL_GPL(get_mtd_device_nm); diff --git a/target/linux/generic/pending-5.4/405-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch b/target/linux/generic/pending-5.4/405-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch new file mode 100644 index 0000000000..25801e4686 --- /dev/null +++ b/target/linux/generic/pending-5.4/405-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch @@ -0,0 +1,38 @@ +From a5d83d6e2bc747b13f347962d4b335d70b23559b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:19 +0100 +Subject: [PATCH] mtd: core: add nvmem-cells compatible to parse mtd as nvmem + cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Partitions that contains the nvmem-cells compatible will register +their direct subonodes as nvmem cells and the node will be treated as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Tested-by: Rafał Miłecki +--- + drivers/mtd/mtdcore.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -559,6 +559,7 @@ static int mtd_nvmem_reg_read(void *priv + + static int mtd_nvmem_add(struct mtd_info *mtd) + { ++ struct device_node *node = mtd_get_of_node(mtd); + struct nvmem_config config = {}; + + config.id = -1; +@@ -571,7 +572,7 @@ static int mtd_nvmem_add(struct mtd_info + config.stride = 1; + config.read_only = true; + config.root_only = true; +- config.no_of_node = true; ++ config.no_of_node = !of_device_is_compatible(node, "nvmem-cells"); + config.priv = mtd; + + mtd->nvmem = nvmem_register(&config); diff --git a/target/linux/generic/pending-5.4/405-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch b/target/linux/generic/pending-5.4/405-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch new file mode 100644 index 0000000000..14ea3f6b8c --- /dev/null +++ b/target/linux/generic/pending-5.4/405-0002-devicetree-nvmem-nvmem-drop-nodename-restriction.patch @@ -0,0 +1,25 @@ +From 42645976c3289b03a12f1bd2bc131fd98fc27170 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:20 +0100 +Subject: [PATCH] devicetree: nvmem: nvmem: drop $nodename restriction + +Drop $nodename restriction as now mtd partition can also be used as +nvmem provider. + +Signed-off-by: Ansuel Smith +--- + Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 --- + 1 file changed, 3 deletions(-) + +--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml ++++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml +@@ -20,9 +20,6 @@ description: | + storage device. + + properties: +- $nodename: +- pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$" +- + "#address-cells": + const: 1 + diff --git a/target/linux/generic/pending-5.4/405-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch b/target/linux/generic/pending-5.4/405-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch new file mode 100644 index 0000000000..0eb4c637cf --- /dev/null +++ b/target/linux/generic/pending-5.4/405-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch @@ -0,0 +1,117 @@ +From 377aa0135dc8489312edd3184d143ce3a89ff7ee Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:21 +0100 +Subject: [PATCH] dt-bindings: mtd: Document use of nvmem-cells compatible + +Document nvmem-cells compatible used to treat mtd partitions as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +--- + .../bindings/mtd/partitions/nvmem-cells.yaml | 99 +++++++++++++++++++ + 1 file changed, 99 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml +@@ -0,0 +1,99 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Nvmem cells ++ ++description: | ++ Any partition containing the compatible "nvmem-cells" will register as a ++ nvmem provider. ++ Each direct subnodes represents a nvmem cell following the nvmem binding. ++ Nvmem binding to declare nvmem-cells can be found in: ++ Documentation/devicetree/bindings/nvmem/nvmem.yaml ++ ++maintainers: ++ - Ansuel Smith ++ ++allOf: ++ - $ref: /schemas/nvmem/nvmem.yaml# ++ ++properties: ++ compatible: ++ const: nvmem-cells ++ ++required: ++ - compatible ++ ++additionalProperties: true ++ ++examples: ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* ... */ ++ ++ }; ++ art: art@1200000 { ++ compatible = "nvmem-cells"; ++ reg = <0x1200000 0x0140000>; ++ label = "art"; ++ read-only; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ macaddr_gmac1: macaddr_gmac1@0 { ++ reg = <0x0 0x6>; ++ }; ++ ++ macaddr_gmac2: macaddr_gmac2@6 { ++ reg = <0x6 0x6>; ++ }; ++ ++ pre_cal_24g: pre_cal_24g@1000 { ++ reg = <0x1000 0x2f20>; ++ }; ++ ++ pre_cal_5g: pre_cal_5g@5000{ ++ reg = <0x5000 0x2f20>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bootloader"; ++ reg = <0x000000 0x100000>; ++ read-only; ++ }; ++ ++ firmware@100000 { ++ compatible = "brcm,trx"; ++ label = "firmware"; ++ reg = <0x100000 0xe00000>; ++ }; ++ ++ calibration@f00000 { ++ compatible = "nvmem-cells"; ++ label = "calibration"; ++ reg = <0xf00000 0x100000>; ++ ranges = <0 0xf00000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ wifi0@0 { ++ reg = <0x000000 0x080000>; ++ }; ++ ++ wifi1@80000 { ++ reg = <0x080000 0x080000>; ++ }; ++ }; ++ }; diff --git a/target/linux/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch index 3907ac2368..95863d6edb 100644 --- a/target/linux/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch +++ b/target/linux/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch @@ -20,7 +20,7 @@ Signed-off-by: Gabor Juhos #include #include -@@ -698,6 +699,15 @@ int add_mtd_device(struct mtd_info *mtd) +@@ -699,6 +700,15 @@ int add_mtd_device(struct mtd_info *mtd) of this try_ nonsense, and no bitching about it either. :) */ __module_get(THIS_MODULE); diff --git a/target/linux/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch b/target/linux/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch index 3a118e38fe..b6e36410e7 100644 --- a/target/linux/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch +++ b/target/linux/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch @@ -17,7 +17,7 @@ Reviewed-by: Miquel Raynal --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -1049,6 +1049,44 @@ out_unlock: +@@ -1050,6 +1050,44 @@ out_unlock: } EXPORT_SYMBOL_GPL(get_mtd_device_nm); diff --git a/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch b/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch index 2d1f769e96..214a0cd649 100644 --- a/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch +++ b/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz const char *partname; struct device_node *pp; int nr_parts, i, ret = 0; -@@ -124,9 +127,15 @@ static int parse_fixed_partitions(struct +@@ -126,9 +129,15 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -242,6 +251,18 @@ static int __init ofpart_parser_init(voi +@@ -244,6 +253,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch b/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch index cc35583b98..3077e718c3 100644 --- a/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch +++ b/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz const char *partname; struct device_node *pp; int nr_parts, i, ret = 0; -@@ -124,9 +127,15 @@ static int parse_fixed_partitions(struct +@@ -126,9 +129,15 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -239,6 +248,18 @@ static int __init ofpart_parser_init(voi +@@ -241,6 +250,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/lantiq/patches-5.4/0101-find_active_root.patch b/target/linux/lantiq/patches-5.4/0101-find_active_root.patch index d541cc247c..201cdd3f87 100644 --- a/target/linux/lantiq/patches-5.4/0101-find_active_root.patch +++ b/target/linux/lantiq/patches-5.4/0101-find_active_root.patch @@ -48,7 +48,7 @@ /* Pull of_node from the master device node */ mtd_node = mtd_get_of_node(master); -@@ -86,7 +120,9 @@ static int parse_fixed_partitions(struct +@@ -88,7 +122,9 @@ static int parse_fixed_partitions(struct return 0; parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); @@ -59,7 +59,7 @@ return -ENOMEM; i = 0; -@@ -135,6 +171,11 @@ static int parse_fixed_partitions(struct +@@ -137,6 +173,11 @@ static int parse_fixed_partitions(struct if (of_get_property(pp, "lock", &len)) parts[i].mask_flags |= MTD_POWERUP_LOCK; @@ -71,7 +71,7 @@ i++; } -@@ -144,6 +185,11 @@ static int parse_fixed_partitions(struct +@@ -146,6 +187,11 @@ static int parse_fixed_partitions(struct if (quirks && quirks->post_parse) quirks->post_parse(master, parts, nr_parts); @@ -83,7 +83,7 @@ *pparts = parts; return nr_parts; -@@ -154,6 +200,7 @@ ofpart_fail: +@@ -156,6 +202,7 @@ ofpart_fail: ofpart_none: of_node_put(pp); kfree(parts); diff --git a/target/linux/mvebu/patches-5.10/400-find_active_root.patch b/target/linux/mvebu/patches-5.10/400-find_active_root.patch index 9df99d69ae..6146c8e038 100644 --- a/target/linux/mvebu/patches-5.10/400-find_active_root.patch +++ b/target/linux/mvebu/patches-5.10/400-find_active_root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz struct device_node *pp; int nr_parts, i, ret = 0; bool dedicated = true; -@@ -124,9 +127,13 @@ static int parse_fixed_partitions(struct +@@ -126,9 +129,13 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -242,6 +249,18 @@ static int __init ofpart_parser_init(voi +@@ -244,6 +251,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/mvebu/patches-5.4/400-find_active_root.patch b/target/linux/mvebu/patches-5.4/400-find_active_root.patch index 8475bec925..6ac777a1d2 100644 --- a/target/linux/mvebu/patches-5.4/400-find_active_root.patch +++ b/target/linux/mvebu/patches-5.4/400-find_active_root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz struct device_node *pp; int nr_parts, i, ret = 0; bool dedicated = true; -@@ -124,9 +127,13 @@ static int parse_fixed_partitions(struct +@@ -126,9 +129,13 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -239,6 +246,18 @@ static int __init ofpart_parser_init(voi +@@ -241,6 +248,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/pistachio/patches-5.4/401-mtd-nor-support-mtd-name-from-device-tree.patch b/target/linux/pistachio/patches-5.4/401-mtd-nor-support-mtd-name-from-device-tree.patch index 2d0b1cc634..69a8303d2b 100644 --- a/target/linux/pistachio/patches-5.4/401-mtd-nor-support-mtd-name-from-device-tree.patch +++ b/target/linux/pistachio/patches-5.4/401-mtd-nor-support-mtd-name-from-device-tree.patch @@ -34,7 +34,7 @@ Signed-off-by: Abhimanyu Vishwakarma mtd->type = MTD_NORFLASH; --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -778,6 +778,17 @@ out_error: +@@ -779,6 +779,17 @@ out_error: */ static void mtd_set_dev_defaults(struct mtd_info *mtd) { From 0d5bf53197481d291f9a541eefa03b11a34033f9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 8 Mar 2021 17:20:20 +0100 Subject: [PATCH 12/32] kernel: update 5.10 flow offload patches Includes PPPoE support and VLAN related fixes Signed-off-by: Felix Fietkau --- ...netfilter-add-xt_FLOWOFFLOAD-target.patch} | 64 +++-- ...arding-path-from-virtual-netdevice-a.patch | 8 +- ...lve-forwarding-path-for-vlan-devices.patch | 6 +- ...ble-use-dev_fill_forward_path-to-obt.patch | 10 +- ...ble-use-dev_fill_forward_path-to-obt.patch | 26 +- ...netfilter-flowtable-add-vlan-support.patch | 165 ++++++----- ...ve-VLAN-tag-actions-in-forwarding-pa.patch | 4 +- ...w_offload-add-bridge-vlan-filtering.patch} | 10 +- ...forwarding-path-for-bridge-pppoe-dev.patch | 100 +++++++ ...forwarding-path-for-dsa-slave-ports.patch} | 10 +- ...etfilter-flowtable-add-pppoe-support.patch | 263 ++++++++++++++++++ ...er-nft_flow_offload-add-dsa-support.patch} | 14 +- ...le-add-offload-support-for-xmit-pat.patch} | 6 +- ...ow_offload-use-direct-xmit-if-hardwa.patch | 51 ---- ...a-slave-add-support-for-TC_SETUP_FT.patch} | 0 ...ow_offload-fix-bridge-vlan-tag-handl.patch | 22 -- ...owtable-rework-ingress-vlan-matching.patch | 143 ---------- ...ow_offload-use-direct-xmit-if-hardwa.patch | 108 +++++++ ...ble-handle-bridge-vlan-filter-offloa.patch | 106 ------- ...w_table-fix-untagging-with-hardware-.patch | 122 ++++++++ ...w_offload-add-FLOW_ACTION_PPPOE_PUSH.patch | 26 ++ ...ble-support-for-FLOW_ACTION_PPPOE_PU.patch | 31 +++ ...T-skip-GRO-for-foreign-MAC-addresses.patch | 2 +- ...dd-support-for-threaded-NAPI-polling.patch | 2 +- ..._eth_soc-add-flow-offloading-support.patch | 19 +- 25 files changed, 845 insertions(+), 473 deletions(-) rename target/linux/generic/hack-5.10/{650-netfilter-add-xt_OFFLOAD-target.patch => 650-netfilter-add-xt_FLOWOFFLOAD-target.patch} (93%) rename target/linux/generic/pending-5.10/{640-14-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch => 640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch} (74%) create mode 100644 target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch rename target/linux/generic/pending-5.10/{640-10-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch => 640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch} (87%) create mode 100644 target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch rename target/linux/generic/pending-5.10/{640-12-netfilter-nft_flow_offload-add-dsa-support.patch => 640-14-netfilter-nft_flow_offload-add-dsa-support.patch} (64%) rename target/linux/generic/pending-5.10/{640-11-netfilter-flowtable-add-offload-support-for-xmit-pat.patch => 640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch} (98%) delete mode 100644 target/linux/generic/pending-5.10/640-15-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch rename target/linux/generic/pending-5.10/{640-13-dsa-slave-add-support-for-TC_SETUP_FT.patch => 640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch} (100%) delete mode 100644 target/linux/generic/pending-5.10/640-16-netfilter-nft_flow_offload-fix-bridge-vlan-tag-handl.patch delete mode 100644 target/linux/generic/pending-5.10/640-17-netfilter-flowtable-rework-ingress-vlan-matching.patch create mode 100644 target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch delete mode 100644 target/linux/generic/pending-5.10/640-18-netfilter-flowtable-handle-bridge-vlan-filter-offloa.patch create mode 100644 target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch create mode 100644 target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch create mode 100644 target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch diff --git a/target/linux/generic/hack-5.10/650-netfilter-add-xt_OFFLOAD-target.patch b/target/linux/generic/hack-5.10/650-netfilter-add-xt_FLOWOFFLOAD-target.patch similarity index 93% rename from target/linux/generic/hack-5.10/650-netfilter-add-xt_OFFLOAD-target.patch rename to target/linux/generic/hack-5.10/650-netfilter-add-xt_FLOWOFFLOAD-target.patch index eb540acc85..97aa7a673b 100644 --- a/target/linux/generic/hack-5.10/650-netfilter-add-xt_OFFLOAD-target.patch +++ b/target/linux/generic/hack-5.10/650-netfilter-add-xt_FLOWOFFLOAD-target.patch @@ -1,6 +1,6 @@ From: Felix Fietkau Date: Tue, 20 Feb 2018 15:56:02 +0100 -Subject: [PATCH] netfilter: add xt_OFFLOAD target +Subject: [PATCH] netfilter: add xt_FLOWOFFLOAD target Signed-off-by: Felix Fietkau --- @@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o --- /dev/null +++ b/net/netfilter/xt_FLOWOFFLOAD.c -@@ -0,0 +1,660 @@ +@@ -0,0 +1,658 @@ +/* + * Copyright (C) 2018-2021 Felix Fietkau + * @@ -265,20 +265,14 @@ Signed-off-by: Felix Fietkau +xt_flowoffload_check_hook(struct flow_offload *flow, void *data) +{ + struct xt_flowoffload_table *table = data; -+ struct flow_offload_tuple *tuple = &flow->tuplehash[0].tuple; ++ struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple; ++ struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple; + struct xt_flowoffload_hook *hook; + + spin_lock_bh(&hooks_lock); + hlist_for_each_entry(hook, &table->hooks, list) { -+ int ifindex; -+ -+ if (tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) -+ ifindex = tuple->out.ifidx; -+ else -+ ifindex = tuple->dst_cache->dev->ifindex; -+ -+ if (hook->ops.dev->ifindex != tuple->iifidx && -+ hook->ops.dev->ifindex != ifindex) ++ if (hook->ops.dev->ifindex != tuple0->iifidx && ++ hook->ops.dev->ifindex != tuple1->iifidx) + continue; + + hook->used = true; @@ -357,6 +351,7 @@ Signed-off-by: Felix Fietkau + int i; + + route->tuple[!dir].in.ifindex = dev->ifindex; ++ route->tuple[dir].out.ifindex = dev->ifindex; + + if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_XFRM) + return; @@ -386,52 +381,54 @@ Signed-off-by: Felix Fietkau + prev_type = DEV_PATH_ETHERNET; + for (i = 0; i <= stack.num_paths; i++) { + const struct net_device_path *path = &stack.path[i]; -+ int n_vlans = route->tuple[!dir].in.num_vlans; ++ int n_encaps = route->tuple[!dir].in.num_encaps; + + dev = (struct net_device *)path->dev; + if (flow_is_valid_ether_device(dev)) { -+ if (route->tuple[dir].xmit_type != FLOW_OFFLOAD_XMIT_DIRECT) ++ if (route->tuple[dir].xmit_type != FLOW_OFFLOAD_XMIT_DIRECT) { + memcpy(route->tuple[dir].out.h_source, + dev->dev_addr, ETH_ALEN); ++ route->tuple[dir].out.ifindex = dev->ifindex; ++ } + route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; -+ route->tuple[dir].out.ifindex = dev->ifindex; + } + + switch (path->type) { ++ case DEV_PATH_PPPOE: + case DEV_PATH_VLAN: -+ if (n_vlans >= NF_FLOW_TABLE_VLAN_MAX || ++ if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX || + i == stack.num_paths) { + last = true; + break; + } + -+ route->tuple[!dir].in.num_vlans++; -+ route->tuple[!dir].in.vid[n_vlans] = path->vlan.id; -+ route->tuple[!dir].in.vproto[n_vlans] = path->vlan.proto; ++ route->tuple[!dir].in.num_encaps++; ++ route->tuple[!dir].in.encap[n_encaps].id = path->encap.id; ++ route->tuple[!dir].in.encap[n_encaps].proto = path->encap.proto; ++ if (path->type == DEV_PATH_PPPOE) ++ memcpy(route->tuple[dir].out.h_dest, ++ path->encap.h_dest, ETH_ALEN); + break; + case DEV_PATH_BRIDGE: + switch (path->bridge.vlan_mode) { + case DEV_PATH_BR_VLAN_TAG: -+ if (n_vlans >= NF_FLOW_TABLE_VLAN_MAX || ++ if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX || + i == stack.num_paths) { + last = true; + break; + } + -+ route->tuple[!dir].in.num_vlans++; -+ route->tuple[!dir].in.vid[n_vlans] = ++ route->tuple[!dir].in.num_encaps++; ++ route->tuple[!dir].in.encap[n_encaps].id = + path->bridge.vlan_id; -+ route->tuple[!dir].in.vproto[n_vlans] = ++ route->tuple[!dir].in.encap[n_encaps].proto = + path->bridge.vlan_proto; + break; -+ case DEV_PATH_BR_VLAN_UNTAG_HW: -+ route->tuple[!dir].in.pvid.id = -+ route->tuple[!dir].in.vid[n_vlans - 1]; -+ route->tuple[!dir].in.pvid.proto = -+ route->tuple[!dir].in.vproto[n_vlans - 1]; -+ fallthrough; + case DEV_PATH_BR_VLAN_UNTAG: -+ route->tuple[!dir].in.num_vlans--; ++ route->tuple[!dir].in.num_encaps--; ++ break; ++ case DEV_PATH_BR_VLAN_UNTAG_HW: ++ route->tuple[!dir].in.ingress_vlans |= BIT(n_encaps - 1); + break; + case DEV_PATH_BR_VLAN_KEEP: + break; @@ -447,6 +444,7 @@ Signed-off-by: Felix Fietkau + } + + *out_dev = dev; ++ route->tuple[dir].out.hw_ifindex = dev->ifindex; + route->tuple[!dir].in.ifindex = dev->ifindex; +} + @@ -769,7 +767,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -355,8 +354,7 @@ flow_offload_lookup(struct nf_flowtable +@@ -356,8 +355,7 @@ flow_offload_lookup(struct nf_flowtable } EXPORT_SYMBOL_GPL(flow_offload_lookup); @@ -779,7 +777,7 @@ Signed-off-by: Felix Fietkau void (*iter)(struct flow_offload *flow, void *data), void *data) { -@@ -388,6 +386,7 @@ nf_flow_table_iterate(struct nf_flowtabl +@@ -389,6 +387,7 @@ nf_flow_table_iterate(struct nf_flowtabl return err; } @@ -809,7 +807,7 @@ Signed-off-by: Felix Fietkau +#endif /* _XT_FLOWOFFLOAD_H */ --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h -@@ -265,6 +265,10 @@ void nf_flow_table_free(struct nf_flowta +@@ -266,6 +266,10 @@ void nf_flow_table_free(struct nf_flowta void flow_offload_teardown(struct flow_offload *flow); diff --git a/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch b/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch index 953446baab..603dddfc36 100644 --- a/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch +++ b/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch @@ -1,5 +1,5 @@ From: Pablo Neira Ayuso -Date: Sun, 10 Jan 2021 15:53:58 +0100 +Date: Thu, 4 Mar 2021 23:18:11 +0100 Subject: [PATCH] net: resolve forwarding path from virtual netdevice and HW destination address @@ -91,7 +91,7 @@ Signed-off-by: Pablo Neira Ayuso * If a device is paired with a peer device, return the peer instance. * The caller must be under RCU read context. + * int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path); -+ * Get the forwarding path to reach the real device from the HW destination address ++ * Get the forwarding path to reach the real device from the HW destination address */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -99,8 +99,8 @@ Signed-off-by: Pablo Neira Ayuso int (*ndo_tunnel_ctl)(struct net_device *dev, struct ip_tunnel_parm *p, int cmd); struct net_device * (*ndo_get_peer_dev)(struct net_device *dev); -+ int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, -+ struct net_device_path *path); ++ int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, ++ struct net_device_path *path); }; /** diff --git a/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch b/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch index ddc0de0d3b..26fb64509c 100644 --- a/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch +++ b/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch @@ -42,7 +42,7 @@ Signed-off-by: Pablo Neira Ayuso + struct { + u16 id; + __be16 proto; -+ } vlan; ++ } encap; + }; }; @@ -59,8 +59,8 @@ Signed-off-by: Pablo Neira Ayuso + struct vlan_dev_priv *vlan = vlan_dev_priv(ctx->dev); + + path->type = DEV_PATH_VLAN; -+ path->vlan.id = vlan->vlan_id; -+ path->vlan.proto = vlan->vlan_proto; ++ path->encap.id = vlan->vlan_id; ++ path->encap.proto = vlan->vlan_proto; + path->dev = ctx->dev; + ctx->dev = vlan->real_dev; + diff --git a/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch b/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch index 34724a5696..1f61cff09d 100644 --- a/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch +++ b/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch @@ -89,7 +89,7 @@ Signed-off-by: Pablo Neira Ayuso +} + +struct nft_forward_info { -+ const struct net_device *dev; ++ const struct net_device *indev; +}; + +static void nft_dev_path_info(const struct net_device_path_stack *stack, @@ -102,12 +102,12 @@ Signed-off-by: Pablo Neira Ayuso + path = &stack->path[i]; + switch (path->type) { + case DEV_PATH_ETHERNET: -+ info->dev = path->dev; ++ info->indev = path->dev; + break; + case DEV_PATH_VLAN: + case DEV_PATH_BRIDGE: + default: -+ info->dev = NULL; ++ info->indev = NULL; + break; + } + } @@ -142,10 +142,10 @@ Signed-off-by: Pablo Neira Ayuso + if (nft_dev_fill_forward_path(route, dst, ct, dir, &stack) >= 0) + nft_dev_path_info(&stack, &info); + -+ if (!info.dev || !nft_flowtable_find_dev(info.dev, ft)) ++ if (!info.indev || !nft_flowtable_find_dev(info.indev, ft)) + return; + -+ route->tuple[!dir].in.ifindex = info.dev->ifindex; ++ route->tuple[!dir].in.ifindex = info.indev->ifindex; +} + static int nft_flow_route(const struct nft_pktinfo *pkt, diff --git a/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch b/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch index d4bf68a690..ada14e6c7a 100644 --- a/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch +++ b/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch @@ -1,5 +1,5 @@ From: Pablo Neira Ayuso -Date: Fri, 20 Nov 2020 13:49:19 +0100 +Date: Thu, 4 Mar 2021 03:26:35 +0100 Subject: [PATCH] netfilter: flowtable: use dev_fill_forward_path() to obtain egress device @@ -271,10 +271,11 @@ Signed-off-by: Pablo Neira Ayuso struct neighbour *n; u8 nud_state; -@@ -66,22 +65,35 @@ static int nft_dev_fill_forward_path(con +@@ -66,27 +65,43 @@ static int nft_dev_fill_forward_path(con struct nft_forward_info { - const struct net_device *dev; + const struct net_device *indev; ++ const struct net_device *outdev; + u8 h_source[ETH_ALEN]; + u8 h_dest[ETH_ALEN]; + enum flow_offload_xmit_type xmit_type; @@ -294,7 +295,7 @@ Signed-off-by: Pablo Neira Ayuso path = &stack->path[i]; switch (path->type) { case DEV_PATH_ETHERNET: - info->dev = path->dev; + info->indev = path->dev; + if (is_zero_ether_addr(info->h_source)) + memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); break; @@ -307,9 +308,16 @@ Signed-off-by: Pablo Neira Ayuso + break; + case DEV_PATH_VLAN: default: - info->dev = NULL; + info->indev = NULL; break; -@@ -114,14 +126,22 @@ static void nft_dev_forward_path(struct + } + } ++ if (!info->outdev) ++ info->outdev = info->indev; + } + + static bool nft_flowtable_find_dev(const struct net_device *dev, +@@ -114,14 +129,22 @@ static void nft_dev_forward_path(struct const struct dst_entry *dst = route->tuple[dir].dst; struct net_device_path_stack stack; struct nft_forward_info info = {}; @@ -320,15 +328,15 @@ Signed-off-by: Pablo Neira Ayuso + if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) + nft_dev_path_info(&stack, &info, ha); - if (!info.dev || !nft_flowtable_find_dev(info.dev, ft)) + if (!info.indev || !nft_flowtable_find_dev(info.indev, ft)) return; - route->tuple[!dir].in.ifindex = info.dev->ifindex; + route->tuple[!dir].in.ifindex = info.indev->ifindex; + + if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { + memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); + memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN); -+ route->tuple[dir].out.ifindex = info.dev->ifindex; ++ route->tuple[dir].out.ifindex = info.outdev->ifindex; + route->tuple[dir].xmit_type = info.xmit_type; + } } diff --git a/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch b/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch index 77aeaccbce..fea1b59dc3 100644 --- a/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch +++ b/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch @@ -16,7 +16,7 @@ Signed-off-by: Pablo Neira Ayuso FLOW_OFFLOAD_XMIT_DIRECT, }; -+#define NF_FLOW_TABLE_VLAN_MAX 2 ++#define NF_FLOW_TABLE_ENCAP_MAX 2 + struct flow_offload_tuple { union { @@ -28,7 +28,7 @@ Signed-off-by: Pablo Neira Ayuso + struct { + u16 id; + __be16 proto; -+ } in_vlan[NF_FLOW_TABLE_VLAN_MAX]; ++ } encap[NF_FLOW_TABLE_ENCAP_MAX]; /* All members above are keys for lookups, see flow_offload_hash(). */ struct { } __hash; @@ -38,17 +38,19 @@ Signed-off-by: Pablo Neira Ayuso - + u8 dir:4, + xmit_type:2, -+ in_vlan_num:2; ++ encap_num:2; u16 mtu; union { struct dst_entry *dst_cache; -@@ -174,6 +180,9 @@ struct nf_flow_route { +@@ -174,6 +180,11 @@ struct nf_flow_route { struct dst_entry *dst; struct { u32 ifindex; -+ u16 vid[NF_FLOW_TABLE_VLAN_MAX]; -+ __be16 vproto[NF_FLOW_TABLE_VLAN_MAX]; -+ u8 num_vlans; ++ struct { ++ u16 id; ++ __be16 proto; ++ } encap[NF_FLOW_TABLE_ENCAP_MAX]; ++ u8 num_encaps; } in; struct { u32 ifindex; @@ -66,33 +68,36 @@ Signed-off-by: Pablo Neira Ayuso } flow_tuple->iifidx = route->tuple[dir].in.ifindex; -+ for (i = route->tuple[dir].in.num_vlans - 1; i >= 0; i--) { -+ flow_tuple->in_vlan[j].id = route->tuple[dir].in.vid[i]; -+ flow_tuple->in_vlan[j].proto = route->tuple[dir].in.vproto[i]; ++ for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) { ++ flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id; ++ flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto; + j++; + } -+ flow_tuple->in_vlan_num = route->tuple[dir].in.num_vlans; ++ flow_tuple->encap_num = route->tuple[dir].in.num_encaps; switch (route->tuple[dir].xmit_type) { case FLOW_OFFLOAD_XMIT_DIRECT: --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c -@@ -159,17 +159,35 @@ static bool ip_has_options(unsigned int +@@ -159,17 +159,38 @@ static bool ip_has_options(unsigned int return thoff != sizeof(struct iphdr); } -+static void nf_flow_tuple_vlan(struct sk_buff *skb, -+ struct flow_offload_tuple *tuple) ++static void nf_flow_tuple_encap(struct sk_buff *skb, ++ struct flow_offload_tuple *tuple) +{ ++ int i = 0; ++ + if (skb_vlan_tag_present(skb)) { -+ tuple->in_vlan[0].id = skb_vlan_tag_get(skb); -+ tuple->in_vlan[0].proto = skb->vlan_proto; ++ tuple->encap[i].id = skb_vlan_tag_get(skb); ++ tuple->encap[i].proto = skb->vlan_proto; ++ i++; + } + if (skb->protocol == htons(ETH_P_8021Q)) { + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); + -+ tuple->in_vlan[1].id = ntohs(veth->h_vlan_TCI); -+ tuple->in_vlan[1].proto = skb->protocol; ++ tuple->encap[i].id = ntohs(veth->h_vlan_TCI); ++ tuple->encap[i].proto = skb->protocol; + } +} + @@ -116,7 +121,7 @@ Signed-off-by: Pablo Neira Ayuso thoff = iph->ihl * 4; if (ip_is_fragment(iph) || -@@ -191,11 +209,11 @@ static int nf_flow_tuple_ip(struct sk_bu +@@ -191,11 +212,11 @@ static int nf_flow_tuple_ip(struct sk_bu return -1; thoff = iph->ihl * 4; @@ -131,19 +136,19 @@ Signed-off-by: Pablo Neira Ayuso tuple->src_v4.s_addr = iph->saddr; tuple->dst_v4.s_addr = iph->daddr; -@@ -204,6 +222,7 @@ static int nf_flow_tuple_ip(struct sk_bu +@@ -204,6 +225,7 @@ static int nf_flow_tuple_ip(struct sk_bu tuple->l3proto = AF_INET; tuple->l4proto = iph->protocol; tuple->iifidx = dev->ifindex; -+ nf_flow_tuple_vlan(skb, tuple); ++ nf_flow_tuple_encap(skb, tuple); return 0; } -@@ -248,6 +267,37 @@ static unsigned int nf_flow_xmit_xfrm(st +@@ -248,6 +270,40 @@ static unsigned int nf_flow_xmit_xfrm(st return NF_STOLEN; } -+static bool nf_flow_skb_vlan_protocol(const struct sk_buff *skb, __be16 proto) ++static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto) +{ + if (skb->protocol == htons(ETH_P_8021Q)) { + struct vlan_ethhdr *veth; @@ -156,29 +161,37 @@ Signed-off-by: Pablo Neira Ayuso + return false; +} + -+static void nf_flow_vlan_pop(struct sk_buff *skb, -+ struct flow_offload_tuple_rhash *tuplehash) ++static void nf_flow_encap_pop(struct sk_buff *skb, ++ struct flow_offload_tuple_rhash *tuplehash) +{ + struct vlan_hdr *vlan_hdr; + int i; + -+ for (i = 0; i < tuplehash->tuple.in_vlan_num; i++) { ++ for (i = 0; i < tuplehash->tuple.encap_num; i++) { + if (skb_vlan_tag_present(skb)) { + __vlan_hwaccel_clear_tag(skb); + continue; + } -+ vlan_hdr = (struct vlan_hdr *)skb->data; -+ __skb_pull(skb, VLAN_HLEN); -+ vlan_set_encap_proto(skb, vlan_hdr); -+ skb_reset_network_header(skb); ++ if (skb->protocol == htons(ETH_P_8021Q)) { ++ vlan_hdr = (struct vlan_hdr *)skb->data; ++ __skb_pull(skb, VLAN_HLEN); ++ vlan_set_encap_proto(skb, vlan_hdr); ++ skb_reset_network_header(skb); ++ break; ++ } + } +} + static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb, const struct flow_offload_tuple_rhash *tuplehash, unsigned short type) -@@ -280,9 +330,11 @@ nf_flow_offload_ip_hook(void *priv, stru - unsigned int thoff; +@@ -276,13 +332,15 @@ nf_flow_offload_ip_hook(void *priv, stru + enum flow_offload_tuple_dir dir; + struct flow_offload *flow; + struct net_device *outdev; ++ unsigned int thoff, mtu; + struct rtable *rt; +- unsigned int thoff; struct iphdr *iph; __be32 nexthop; + u32 offset = 0; @@ -186,12 +199,17 @@ Signed-off-by: Pablo Neira Ayuso - if (skb->protocol != htons(ETH_P_IP)) + if (skb->protocol != htons(ETH_P_IP) && -+ !nf_flow_skb_vlan_protocol(skb, htons(ETH_P_IP))) ++ !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP))) return NF_ACCEPT; if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0) -@@ -298,11 +350,15 @@ nf_flow_offload_ip_hook(void *priv, stru - if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu))) +@@ -295,14 +353,19 @@ nf_flow_offload_ip_hook(void *priv, stru + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + +- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu))) ++ mtu = flow->tuplehash[dir].tuple.mtu + offset; ++ if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) return NF_ACCEPT; - if (skb_try_make_writable(skb, sizeof(*iph))) @@ -209,17 +227,17 @@ Signed-off-by: Pablo Neira Ayuso return NF_ACCEPT; flow_offload_refresh(flow_table, flow); -@@ -312,6 +368,9 @@ nf_flow_offload_ip_hook(void *priv, stru +@@ -312,6 +375,9 @@ nf_flow_offload_ip_hook(void *priv, stru return NF_ACCEPT; } -+ nf_flow_vlan_pop(skb, tuplehash); ++ nf_flow_encap_pop(skb, tuplehash); + thoff -= offset; + if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0) return NF_DROP; -@@ -479,14 +538,17 @@ static int nf_flow_nat_ipv6(const struct +@@ -479,14 +545,17 @@ static int nf_flow_nat_ipv6(const struct static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, struct flow_offload_tuple *tuple) { @@ -240,7 +258,7 @@ Signed-off-by: Pablo Neira Ayuso switch (ip6h->nexthdr) { case IPPROTO_TCP: -@@ -503,11 +565,11 @@ static int nf_flow_tuple_ipv6(struct sk_ +@@ -503,11 +572,11 @@ static int nf_flow_tuple_ipv6(struct sk_ return -1; thoff = sizeof(*ip6h); @@ -255,29 +273,35 @@ Signed-off-by: Pablo Neira Ayuso tuple->src_v6 = ip6h->saddr; tuple->dst_v6 = ip6h->daddr; -@@ -516,6 +578,7 @@ static int nf_flow_tuple_ipv6(struct sk_ +@@ -516,6 +585,7 @@ static int nf_flow_tuple_ipv6(struct sk_ tuple->l3proto = AF_INET6; tuple->l4proto = ip6h->nexthdr; tuple->iifidx = dev->ifindex; -+ nf_flow_tuple_vlan(skb, tuple); ++ nf_flow_tuple_encap(skb, tuple); return 0; } -@@ -533,9 +596,11 @@ nf_flow_offload_ipv6_hook(void *priv, st +@@ -533,9 +603,12 @@ nf_flow_offload_ipv6_hook(void *priv, st struct net_device *outdev; struct ipv6hdr *ip6h; struct rt6_info *rt; ++ unsigned int mtu; + u32 offset = 0; int ret; - if (skb->protocol != htons(ETH_P_IPV6)) + if (skb->protocol != htons(ETH_P_IPV6) && -+ !nf_flow_skb_vlan_protocol(skb, htons(ETH_P_IPV6))) ++ !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6))) return NF_ACCEPT; if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0) -@@ -551,8 +616,11 @@ nf_flow_offload_ipv6_hook(void *priv, st - if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu))) +@@ -548,11 +621,15 @@ nf_flow_offload_ipv6_hook(void *priv, st + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + +- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu))) ++ mtu = flow->tuplehash[dir].tuple.mtu + offset; ++ if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) return NF_ACCEPT; - if (nf_flow_state_check(flow, ipv6_hdr(skb)->nexthdr, skb, @@ -290,33 +314,35 @@ Signed-off-by: Pablo Neira Ayuso return NF_ACCEPT; flow_offload_refresh(flow_table, flow); -@@ -562,6 +630,8 @@ nf_flow_offload_ipv6_hook(void *priv, st +@@ -562,6 +639,8 @@ nf_flow_offload_ipv6_hook(void *priv, st return NF_ACCEPT; } -+ nf_flow_vlan_pop(skb, tuplehash); ++ nf_flow_encap_pop(skb, tuplehash); + if (skb_try_make_writable(skb, sizeof(*ip6h))) return NF_DROP; --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c -@@ -65,6 +65,9 @@ static int nft_dev_fill_forward_path(con - +@@ -66,6 +66,11 @@ static int nft_dev_fill_forward_path(con struct nft_forward_info { - const struct net_device *dev; -+ __u16 vid[NF_FLOW_TABLE_VLAN_MAX]; -+ __be16 vproto[NF_FLOW_TABLE_VLAN_MAX]; -+ u8 num_vlans; + const struct net_device *indev; + const struct net_device *outdev; ++ struct id { ++ __u16 id; ++ __be16 proto; ++ } encap[NF_FLOW_TABLE_ENCAP_MAX]; ++ u8 num_encaps; u8 h_source[ETH_ALEN]; u8 h_dest[ETH_ALEN]; enum flow_offload_xmit_type xmit_type; -@@ -83,9 +86,22 @@ static void nft_dev_path_info(const stru +@@ -84,9 +89,23 @@ static void nft_dev_path_info(const stru path = &stack->path[i]; switch (path->type) { case DEV_PATH_ETHERNET: + case DEV_PATH_VLAN: - info->dev = path->dev; + info->indev = path->dev; if (is_zero_ether_addr(info->h_source)) memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); + @@ -324,25 +350,26 @@ Signed-off-by: Pablo Neira Ayuso + break; + + /* DEV_PATH_VLAN */ -+ if (info->num_vlans >= NF_FLOW_TABLE_VLAN_MAX) { -+ info->dev = NULL; ++ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { ++ info->indev = NULL; + break; + } -+ info->vid[info->num_vlans] = path->vlan.id; -+ info->vproto[info->num_vlans] = path->vlan.proto; -+ info->num_vlans++; ++ info->outdev = path->dev; ++ info->encap[info->num_encaps].id = path->encap.id; ++ info->encap[info->num_encaps].proto = path->encap.proto; ++ info->num_encaps++; break; case DEV_PATH_BRIDGE: if (is_zero_ether_addr(info->h_source)) -@@ -93,7 +109,6 @@ static void nft_dev_path_info(const stru +@@ -94,7 +113,6 @@ static void nft_dev_path_info(const stru info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; break; - case DEV_PATH_VLAN: default: - info->dev = NULL; + info->indev = NULL; break; -@@ -127,6 +142,7 @@ static void nft_dev_forward_path(struct +@@ -130,6 +148,7 @@ static void nft_dev_forward_path(struct struct net_device_path_stack stack; struct nft_forward_info info = {}; unsigned char ha[ETH_ALEN]; @@ -350,15 +377,15 @@ Signed-off-by: Pablo Neira Ayuso if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) nft_dev_path_info(&stack, &info, ha); -@@ -135,6 +151,11 @@ static void nft_dev_forward_path(struct +@@ -138,6 +157,11 @@ static void nft_dev_forward_path(struct return; - route->tuple[!dir].in.ifindex = info.dev->ifindex; -+ for (i = 0; i < info.num_vlans; i++) { -+ route->tuple[!dir].in.vid[i] = info.vid[i]; -+ route->tuple[!dir].in.vproto[i] = info.vproto[i]; + route->tuple[!dir].in.ifindex = info.indev->ifindex; ++ for (i = 0; i < info.num_encaps; i++) { ++ route->tuple[!dir].in.encap[i].id = info.encap[i].id; ++ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto; + } -+ route->tuple[!dir].in.num_vlans = info.num_vlans; ++ route->tuple[!dir].in.num_encaps = info.num_encaps; if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); diff --git a/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch b/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch index fb5f736648..9bd1f6b4c6 100644 --- a/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch +++ b/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch @@ -18,7 +18,7 @@ Signed-off-by: Pablo Neira Ayuso @@ -847,10 +847,20 @@ struct net_device_path { u16 id; __be16 proto; - } vlan; + } encap; + struct { + enum { + DEV_PATH_BR_VLAN_KEEP, @@ -52,7 +52,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -777,6 +777,12 @@ static int vlan_dev_fill_forward_path(st - path->vlan.proto = vlan->vlan_proto; + path->encap.proto = vlan->vlan_proto; path->dev = ctx->dev; ctx->dev = vlan->real_dev; + if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan)) diff --git a/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch b/target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch similarity index 74% rename from target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch rename to target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch index 2e833117db..86fd6bf77b 100644 --- a/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch +++ b/target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch @@ -10,18 +10,18 @@ Signed-off-by: Pablo Neira Ayuso --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c -@@ -112,6 +112,18 @@ static void nft_dev_path_info(const stru +@@ -111,6 +111,18 @@ static void nft_dev_path_info(const stru if (is_zero_ether_addr(info->h_source)) memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); + switch (path->bridge.vlan_mode) { + case DEV_PATH_BR_VLAN_TAG: -+ info->vid[info->num_vlans] = path->vlan.id; -+ info->vproto[info->num_vlans] = path->vlan.proto; -+ info->num_vlans++; ++ info->encap[info->num_encaps].id = path->bridge.vlan_id; ++ info->encap[info->num_encaps].proto = path->bridge.vlan_proto; ++ info->num_encaps++; + break; + case DEV_PATH_BR_VLAN_UNTAG: -+ info->num_vlans--; ++ info->num_encaps--; + break; + case DEV_PATH_BR_VLAN_KEEP: + break; diff --git a/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch b/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch new file mode 100644 index 0000000000..34d918206f --- /dev/null +++ b/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch @@ -0,0 +1,100 @@ +From: Pablo Neira Ayuso +Date: Tue, 2 Mar 2021 21:45:16 +0100 +Subject: [PATCH] net: ppp: resolve forwarding path for bridge pppoe + devices + +Pass on the PPPoE session ID and the real device. +--- + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1450,12 +1450,34 @@ static void ppp_dev_priv_destructor(stru + ppp_destroy_interface(ppp); + } + ++static int ppp_fill_forward_path(struct net_device_path_ctx *ctx, ++ struct net_device_path *path) ++{ ++ struct ppp *ppp = netdev_priv(path->dev); ++ struct ppp_channel *chan; ++ struct channel *pch; ++ ++ if (ppp->flags & SC_MULTILINK) ++ return -EOPNOTSUPP; ++ ++ if (list_empty(&ppp->channels)) ++ return -ENODEV; ++ ++ pch = list_first_entry(&ppp->channels, struct channel, clist); ++ chan = pch->chan; ++ if (!chan->ops->fill_forward_path) ++ return -EOPNOTSUPP; ++ ++ return chan->ops->fill_forward_path(ctx, path, chan); ++} ++ + static const struct net_device_ops ppp_netdev_ops = { + .ndo_init = ppp_dev_init, + .ndo_uninit = ppp_dev_uninit, + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, + .ndo_get_stats64 = ppp_get_stats64, ++ .ndo_fill_forward_path = ppp_fill_forward_path, + }; + + static struct device_type ppp_type = { +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -972,8 +972,30 @@ static int pppoe_xmit(struct ppp_channel + return __pppoe_xmit(sk, skb); + } + ++static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx, ++ struct net_device_path *path, ++ const struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct pppox_sock *po = pppox_sk(sk); ++ struct net_device *dev = po->pppoe_dev; ++ ++ if (sock_flag(sk, SOCK_DEAD) || ++ !(sk->sk_state & PPPOX_CONNECTED) || !dev) ++ return -1; ++ ++ path->type = DEV_PATH_PPPOE; ++ path->encap.proto = htons(ETH_P_PPP_SES); ++ path->encap.id = be16_to_cpu(po->num); ++ path->dev = ctx->dev; ++ ctx->dev = dev; ++ ++ return 0; ++} ++ + static const struct ppp_channel_ops pppoe_chan_ops = { + .start_xmit = pppoe_xmit, ++ .fill_forward_path = pppoe_fill_forward_path, + }; + + static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -837,6 +837,7 @@ enum net_device_path_type { + DEV_PATH_ETHERNET = 0, + DEV_PATH_VLAN, + DEV_PATH_BRIDGE, ++ DEV_PATH_PPPOE, + }; + + struct net_device_path { +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -28,6 +28,9 @@ struct ppp_channel_ops { + int (*start_xmit)(struct ppp_channel *, struct sk_buff *); + /* Handle an ioctl call that has come in via /dev/ppp. */ + int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); ++ int (*fill_forward_path)(struct net_device_path_ctx *, ++ struct net_device_path *, ++ const struct ppp_channel *); + }; + + struct ppp_channel { diff --git a/target/linux/generic/pending-5.10/640-10-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch b/target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch similarity index 87% rename from target/linux/generic/pending-5.10/640-10-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch rename to target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch index 64a2b14af5..3e7a9eaef9 100644 --- a/target/linux/generic/pending-5.10/640-10-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch +++ b/target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch @@ -1,23 +1,21 @@ From: Felix Fietkau -Date: Mon, 7 Dec 2020 20:31:48 +0100 +Date: Thu, 4 Mar 2021 23:19:06 +0100 Subject: [PATCH] net: dsa: resolve forwarding path for dsa slave ports Add .ndo_fill_forward_path for dsa slave port devices - -Signed-off-by: Felix Fietkau --- --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -837,6 +837,7 @@ enum net_device_path_type { - DEV_PATH_ETHERNET = 0, +@@ -838,6 +838,7 @@ enum net_device_path_type { DEV_PATH_VLAN, DEV_PATH_BRIDGE, + DEV_PATH_PPPOE, + DEV_PATH_DSA, }; struct net_device_path { -@@ -856,6 +857,10 @@ struct net_device_path { +@@ -857,6 +858,10 @@ struct net_device_path { u16 vlan_id; __be16 vlan_proto; } bridge; diff --git a/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch b/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch new file mode 100644 index 0000000000..6a14514565 --- /dev/null +++ b/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch @@ -0,0 +1,263 @@ +From: Pablo Neira Ayuso +Date: Mon, 1 Mar 2021 23:52:49 +0100 +Subject: [PATCH] netfilter: flowtable: add pppoe support + +--- + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1453,7 +1453,7 @@ static void ppp_dev_priv_destructor(stru + static int ppp_fill_forward_path(struct net_device_path_ctx *ctx, + struct net_device_path *path) + { +- struct ppp *ppp = netdev_priv(path->dev); ++ struct ppp *ppp = netdev_priv(ctx->dev); + struct ppp_channel *chan; + struct channel *pch; + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -987,6 +987,7 @@ static int pppoe_fill_forward_path(struc + path->type = DEV_PATH_PPPOE; + path->encap.proto = htons(ETH_P_PPP_SES); + path->encap.id = be16_to_cpu(po->num); ++ memcpy(path->encap.h_dest, po->pppoe_pa.remote, ETH_ALEN); + path->dev = ctx->dev; + ctx->dev = dev; + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -848,6 +848,7 @@ struct net_device_path { + struct { + u16 id; + __be16 proto; ++ u8 h_dest[ETH_ALEN]; + } encap; + struct { + enum { +--- a/net/netfilter/nf_flow_table_ip.c ++++ b/net/netfilter/nf_flow_table_ip.c +@@ -7,6 +7,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -162,6 +165,8 @@ static bool ip_has_options(unsigned int + static void nf_flow_tuple_encap(struct sk_buff *skb, + struct flow_offload_tuple *tuple) + { ++ struct vlan_ethhdr *veth; ++ struct pppoe_hdr *phdr; + int i = 0; + + if (skb_vlan_tag_present(skb)) { +@@ -169,23 +174,35 @@ static void nf_flow_tuple_encap(struct s + tuple->encap[i].proto = skb->vlan_proto; + i++; + } +- if (skb->protocol == htons(ETH_P_8021Q)) { +- struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); +- ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): ++ veth = (struct vlan_ethhdr *)skb_mac_header(skb); + tuple->encap[i].id = ntohs(veth->h_vlan_TCI); + tuple->encap[i].proto = skb->protocol; ++ break; ++ case htons(ETH_P_PPP_SES): ++ phdr = (struct pppoe_hdr *)skb_mac_header(skb); ++ tuple->encap[i].id = ntohs(phdr->sid); ++ tuple->encap[i].proto = skb->protocol; ++ break; + } + } + + static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, +- struct flow_offload_tuple *tuple) ++ struct flow_offload_tuple *tuple, u32 *nhoff) + { + unsigned int thoff, hdrsize, offset = 0; + struct flow_ports *ports; + struct iphdr *iph; + +- if (skb->protocol == htons(ETH_P_8021Q)) ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): + offset += VLAN_HLEN; ++ break; ++ case htons(ETH_P_PPP_SES): ++ offset += PPPOE_SES_HLEN; ++ break; ++ } + + if (!pskb_may_pull(skb, sizeof(*iph) + offset)) + return -1; +@@ -226,6 +243,7 @@ static int nf_flow_tuple_ip(struct sk_bu + tuple->l4proto = iph->protocol; + tuple->iifidx = dev->ifindex; + nf_flow_tuple_encap(skb, tuple); ++ *nhoff = offset; + + return 0; + } +@@ -270,14 +288,36 @@ static unsigned int nf_flow_xmit_xfrm(st + return NF_STOLEN; + } + ++static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) ++{ ++ __be16 proto; ++ ++ proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + ++ sizeof(struct pppoe_hdr))); ++ switch (proto) { ++ case htons(PPP_IP): ++ return htons(ETH_P_IP); ++ case htons(PPP_IPV6): ++ return htons(ETH_P_IPV6); ++ } ++ ++ return 0; ++} ++ + static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto) + { +- if (skb->protocol == htons(ETH_P_8021Q)) { +- struct vlan_ethhdr *veth; ++ struct vlan_ethhdr *veth; + ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): + veth = (struct vlan_ethhdr *)skb_mac_header(skb); + if (veth->h_vlan_encapsulated_proto == proto) + return true; ++ break; ++ case htons(ETH_P_PPP_SES): ++ if (nf_flow_pppoe_proto(skb) == proto) ++ return true; ++ break; + } + + return false; +@@ -294,12 +334,18 @@ static void nf_flow_encap_pop(struct sk_ + __vlan_hwaccel_clear_tag(skb); + continue; + } +- if (skb->protocol == htons(ETH_P_8021Q)) { ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): + vlan_hdr = (struct vlan_hdr *)skb->data; + __skb_pull(skb, VLAN_HLEN); + vlan_set_encap_proto(skb, vlan_hdr); + skb_reset_network_header(skb); + break; ++ case htons(ETH_P_PPP_SES): ++ skb->protocol = nf_flow_pppoe_proto(skb); ++ skb_pull(skb, PPPOE_SES_HLEN); ++ skb_reset_network_header(skb); ++ break; + } + } + } +@@ -343,7 +389,7 @@ nf_flow_offload_ip_hook(void *priv, stru + !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP))) + return NF_ACCEPT; + +- if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0) ++ if (nf_flow_tuple_ip(skb, state->in, &tuple, &offset) < 0) + return NF_ACCEPT; + + tuplehash = flow_offload_lookup(flow_table, &tuple); +@@ -357,9 +403,6 @@ nf_flow_offload_ip_hook(void *priv, stru + if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) + return NF_ACCEPT; + +- if (skb->protocol == htons(ETH_P_8021Q)) +- offset += VLAN_HLEN; +- + if (skb_try_make_writable(skb, sizeof(*iph) + offset)) + return NF_DROP; + +@@ -543,14 +586,20 @@ static int nf_flow_nat_ipv6(const struct + } + + static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, +- struct flow_offload_tuple *tuple) ++ struct flow_offload_tuple *tuple, u32 *nhoff) + { + unsigned int thoff, hdrsize, offset = 0; + struct flow_ports *ports; + struct ipv6hdr *ip6h; + +- if (skb->protocol == htons(ETH_P_8021Q)) ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): + offset += VLAN_HLEN; ++ break; ++ case htons(ETH_P_PPP_SES): ++ offset += PPPOE_SES_HLEN; ++ break; ++ } + + if (!pskb_may_pull(skb, sizeof(*ip6h) + offset)) + return -1; +@@ -586,6 +635,7 @@ static int nf_flow_tuple_ipv6(struct sk_ + tuple->l4proto = ip6h->nexthdr; + tuple->iifidx = dev->ifindex; + nf_flow_tuple_encap(skb, tuple); ++ *nhoff = offset; + + return 0; + } +@@ -611,7 +661,7 @@ nf_flow_offload_ipv6_hook(void *priv, st + !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6))) + return NF_ACCEPT; + +- if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0) ++ if (nf_flow_tuple_ipv6(skb, state->in, &tuple, &offset) < 0) + return NF_ACCEPT; + + tuplehash = flow_offload_lookup(flow_table, &tuple); +@@ -625,9 +675,6 @@ nf_flow_offload_ipv6_hook(void *priv, st + if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) + return NF_ACCEPT; + +- if (skb->protocol == htons(ETH_P_8021Q)) +- offset += VLAN_HLEN; +- + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); + if (nf_flow_state_check(flow, ip6h->nexthdr, skb, sizeof(*ip6h))) + return NF_ACCEPT; +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -90,6 +90,7 @@ static void nft_dev_path_info(const stru + switch (path->type) { + case DEV_PATH_ETHERNET: + case DEV_PATH_VLAN: ++ case DEV_PATH_PPPOE: + info->indev = path->dev; + if (is_zero_ether_addr(info->h_source)) + memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); +@@ -97,7 +98,7 @@ static void nft_dev_path_info(const stru + if (path->type == DEV_PATH_ETHERNET) + break; + +- /* DEV_PATH_VLAN */ ++ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */ + if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { + info->indev = NULL; + break; +@@ -106,6 +107,8 @@ static void nft_dev_path_info(const stru + info->encap[info->num_encaps].id = path->encap.id; + info->encap[info->num_encaps].proto = path->encap.proto; + info->num_encaps++; ++ if (path->type == DEV_PATH_PPPOE) ++ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN); + break; + case DEV_PATH_BRIDGE: + if (is_zero_ether_addr(info->h_source)) diff --git a/target/linux/generic/pending-5.10/640-12-netfilter-nft_flow_offload-add-dsa-support.patch b/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch similarity index 64% rename from target/linux/generic/pending-5.10/640-12-netfilter-nft_flow_offload-add-dsa-support.patch rename to target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch index 3689a476b3..7ff5dad1f7 100644 --- a/target/linux/generic/pending-5.10/640-12-netfilter-nft_flow_offload-add-dsa-support.patch +++ b/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch @@ -1,5 +1,5 @@ From: Pablo Neira Ayuso -Date: Mon, 18 Jan 2021 22:27:45 +0100 +Date: Thu, 4 Mar 2021 19:22:55 +0100 Subject: [PATCH] netfilter: nft_flow_offload: add dsa support Replace the master ethernet device by the dsa slave port. @@ -9,15 +9,15 @@ Signed-off-by: Pablo Neira Ayuso --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c -@@ -86,6 +86,7 @@ static void nft_dev_path_info(const stru +@@ -89,6 +89,7 @@ static void nft_dev_path_info(const stru path = &stack->path[i]; switch (path->type) { case DEV_PATH_ETHERNET: + case DEV_PATH_DSA: case DEV_PATH_VLAN: - info->dev = path->dev; - if (is_zero_ether_addr(info->h_source)) -@@ -93,6 +94,10 @@ static void nft_dev_path_info(const stru + case DEV_PATH_PPPOE: + info->indev = path->dev; +@@ -97,6 +98,10 @@ static void nft_dev_path_info(const stru if (path->type == DEV_PATH_ETHERNET) break; @@ -26,5 +26,5 @@ Signed-off-by: Pablo Neira Ayuso + break; + } - /* DEV_PATH_VLAN */ - if (info->num_vlans >= NF_FLOW_TABLE_VLAN_MAX) { + /* DEV_PATH_VLAN and DEV_PATH_PPPOE */ + if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { diff --git a/target/linux/generic/pending-5.10/640-11-netfilter-flowtable-add-offload-support-for-xmit-pat.patch b/target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch similarity index 98% rename from target/linux/generic/pending-5.10/640-11-netfilter-flowtable-add-offload-support-for-xmit-pat.patch rename to target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch index 508dc90e14..696ea03332 100644 --- a/target/linux/generic/pending-5.10/640-11-netfilter-flowtable-add-offload-support-for-xmit-pat.patch +++ b/target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch @@ -229,12 +229,12 @@ tag to the driver. + other_tuple = &flow->tuplehash[!dir].tuple; + -+ for (i = 0; i < other_tuple->in_vlan_num; i++) { ++ for (i = 0; i < other_tuple->encap_num; i++) { + struct flow_action_entry *entry = flow_action_entry_next(flow_rule); + + entry->id = FLOW_ACTION_VLAN_PUSH; -+ entry->vlan.vid = other_tuple->in_vlan[i].id; -+ entry->vlan.proto = other_tuple->in_vlan[i].proto; ++ entry->vlan.vid = other_tuple->encap[i].id; ++ entry->vlan.proto = other_tuple->encap[i].proto; + } + + return 0; diff --git a/target/linux/generic/pending-5.10/640-15-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch b/target/linux/generic/pending-5.10/640-15-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch deleted file mode 100644 index 1c65a5e218..0000000000 --- a/target/linux/generic/pending-5.10/640-15-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch +++ /dev/null @@ -1,51 +0,0 @@ -From: Pablo Neira Ayuso -Date: Tue, 2 Feb 2021 17:10:07 +0100 -Subject: [PATCH] netfilter: nft_flow_offload: use direct xmit if - hardware offload is enabled - -If there is a forward path to reach an ethernet device and hardware -offload is enabled, then use the direct xmit path. ---- - ---- a/net/netfilter/nft_flow_offload.c -+++ b/net/netfilter/nft_flow_offload.c -@@ -73,9 +73,18 @@ struct nft_forward_info { - enum flow_offload_xmit_type xmit_type; - }; - -+static bool nft_is_valid_ether_device(const struct net_device *dev) -+{ -+ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || -+ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) -+ return false; -+ -+ return true; -+} -+ - static void nft_dev_path_info(const struct net_device_path_stack *stack, - struct nft_forward_info *info, -- unsigned char *ha) -+ unsigned char *ha, struct nf_flowtable *flowtable) - { - const struct net_device_path *path; - int i; -@@ -131,6 +140,10 @@ static void nft_dev_path_info(const stru - break; - } - } -+ -+ if (nf_flowtable_hw_offload(flowtable) && -+ nft_is_valid_ether_device(info->dev)) -+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; - } - - static bool nft_flowtable_find_dev(const struct net_device *dev, -@@ -162,7 +175,7 @@ static void nft_dev_forward_path(struct - int i; - - if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) -- nft_dev_path_info(&stack, &info, ha); -+ nft_dev_path_info(&stack, &info, ha, &ft->data); - - if (!info.dev || !nft_flowtable_find_dev(info.dev, ft)) - return; diff --git a/target/linux/generic/pending-5.10/640-13-dsa-slave-add-support-for-TC_SETUP_FT.patch b/target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch similarity index 100% rename from target/linux/generic/pending-5.10/640-13-dsa-slave-add-support-for-TC_SETUP_FT.patch rename to target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch diff --git a/target/linux/generic/pending-5.10/640-16-netfilter-nft_flow_offload-fix-bridge-vlan-tag-handl.patch b/target/linux/generic/pending-5.10/640-16-netfilter-nft_flow_offload-fix-bridge-vlan-tag-handl.patch deleted file mode 100644 index 5877e91e78..0000000000 --- a/target/linux/generic/pending-5.10/640-16-netfilter-nft_flow_offload-fix-bridge-vlan-tag-handl.patch +++ /dev/null @@ -1,22 +0,0 @@ -From: Felix Fietkau -Date: Wed, 10 Feb 2021 10:23:38 +0100 -Subject: [PATCH] netfilter: nft_flow_offload: fix bridge vlan tag handling - -the brigde type uses the path->bridge.vlan_* fields - -Signed-off-by: Felix Fietkau ---- - ---- a/net/netfilter/nft_flow_offload.c -+++ b/net/netfilter/nft_flow_offload.c -@@ -123,8 +123,8 @@ static void nft_dev_path_info(const stru - - switch (path->bridge.vlan_mode) { - case DEV_PATH_BR_VLAN_TAG: -- info->vid[info->num_vlans] = path->vlan.id; -- info->vproto[info->num_vlans] = path->vlan.proto; -+ info->vid[info->num_vlans] = path->bridge.vlan_id; -+ info->vproto[info->num_vlans] = path->bridge.vlan_proto; - info->num_vlans++; - break; - case DEV_PATH_BR_VLAN_UNTAG: diff --git a/target/linux/generic/pending-5.10/640-17-netfilter-flowtable-rework-ingress-vlan-matching.patch b/target/linux/generic/pending-5.10/640-17-netfilter-flowtable-rework-ingress-vlan-matching.patch deleted file mode 100644 index 67ec263f51..0000000000 --- a/target/linux/generic/pending-5.10/640-17-netfilter-flowtable-rework-ingress-vlan-matching.patch +++ /dev/null @@ -1,143 +0,0 @@ -From: Felix Fietkau -Date: Wed, 10 Feb 2021 19:39:23 +0100 -Subject: [PATCH] netfilter: flowtable: rework ingress vlan matching - -When dealing with bridges with VLAN filtering and DSA/switchdev offload, -the hardware could offload adding a VLAN tag configured in the bridge. -Since there doesn't seem to be an easy way to detect that, this patch -reworks the code to optionally match the last VLAN tag that would otherwise -be inserted by the bridge. -This matters when bypassing the bridge and attaching an ingress hook on -a DSA port below it. - -Signed-off-by: Felix Fietkau ---- - ---- a/include/net/netfilter/nf_flow_table.h -+++ b/include/net/netfilter/nf_flow_table.h -@@ -115,14 +115,15 @@ struct flow_offload_tuple { - - u8 l3proto; - u8 l4proto; -- struct { -- u16 id; -- __be16 proto; -- } in_vlan[NF_FLOW_TABLE_VLAN_MAX]; - - /* All members above are keys for lookups, see flow_offload_hash(). */ - struct { } __hash; - -+ struct { -+ u16 id; -+ __be16 proto; -+ } in_vlan[NF_FLOW_TABLE_VLAN_MAX], in_pvid; -+ - u8 dir:4, - xmit_type:2, - in_vlan_num:2; ---- a/net/netfilter/nf_flow_table_ip.c -+++ b/net/netfilter/nf_flow_table_ip.c -@@ -281,12 +281,13 @@ static bool nf_flow_skb_vlan_protocol(co - } - - static void nf_flow_vlan_pop(struct sk_buff *skb, -- struct flow_offload_tuple_rhash *tuplehash) -+ struct flow_offload_tuple_rhash *tuplehash, -+ bool strip_pvid) - { - struct vlan_hdr *vlan_hdr; - int i; - -- for (i = 0; i < tuplehash->tuple.in_vlan_num; i++) { -+ for (i = 0; i < tuplehash->tuple.in_vlan_num + strip_pvid; i++) { - if (skb_vlan_tag_present(skb)) { - __vlan_hwaccel_clear_tag(skb); - continue; -@@ -316,6 +317,31 @@ static unsigned int nf_flow_queue_xmit(s - return NF_STOLEN; - } - -+static bool -+nf_flow_offload_check_vlan(struct flow_offload_tuple *tuple, -+ struct flow_offload_tuple *flow_tuple, -+ bool *strip_pvid) -+{ -+ int i, cur = 0; -+ -+ if (flow_tuple->in_pvid.proto && -+ !memcmp(&tuple->in_vlan[0], &flow_tuple->in_pvid, -+ sizeof(tuple->in_vlan[0]))) -+ cur++; -+ -+ *strip_pvid = cur; -+ -+ for (i = 0; i < flow_tuple->in_vlan_num; i++, cur++) { -+ if (!memcmp(&tuple->in_vlan[cur], &flow_tuple->in_vlan[i], -+ sizeof(tuple->in_vlan[0]))) -+ continue; -+ -+ return false; -+ } -+ -+ return true; -+} -+ - unsigned int - nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, - const struct nf_hook_state *state) -@@ -329,6 +355,7 @@ nf_flow_offload_ip_hook(void *priv, stru - struct rtable *rt; - unsigned int thoff; - struct iphdr *iph; -+ bool strip_pvid; - __be32 nexthop; - u32 offset = 0; - int ret; -@@ -344,6 +371,10 @@ nf_flow_offload_ip_hook(void *priv, stru - if (tuplehash == NULL) - return NF_ACCEPT; - -+ if (!nf_flow_offload_check_vlan(&tuple, &tuplehash->tuple, -+ &strip_pvid)) -+ return NF_ACCEPT; -+ - dir = tuplehash->tuple.dir; - flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); - -@@ -368,7 +399,7 @@ nf_flow_offload_ip_hook(void *priv, stru - return NF_ACCEPT; - } - -- nf_flow_vlan_pop(skb, tuplehash); -+ nf_flow_vlan_pop(skb, tuplehash, strip_pvid); - thoff -= offset; - - if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0) -@@ -596,6 +627,7 @@ nf_flow_offload_ipv6_hook(void *priv, st - struct net_device *outdev; - struct ipv6hdr *ip6h; - struct rt6_info *rt; -+ bool strip_pvid; - u32 offset = 0; - int ret; - -@@ -610,6 +642,10 @@ nf_flow_offload_ipv6_hook(void *priv, st - if (tuplehash == NULL) - return NF_ACCEPT; - -+ if (!nf_flow_offload_check_vlan(&tuple, &tuplehash->tuple, -+ &strip_pvid)) -+ return NF_ACCEPT; -+ - dir = tuplehash->tuple.dir; - flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); - -@@ -630,7 +666,7 @@ nf_flow_offload_ipv6_hook(void *priv, st - return NF_ACCEPT; - } - -- nf_flow_vlan_pop(skb, tuplehash); -+ nf_flow_vlan_pop(skb, tuplehash, strip_pvid); - - if (skb_try_make_writable(skb, sizeof(*ip6h))) - return NF_DROP; diff --git a/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch b/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch new file mode 100644 index 0000000000..26d172bcf7 --- /dev/null +++ b/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch @@ -0,0 +1,108 @@ +From: Pablo Neira Ayuso +Date: Thu, 4 Mar 2021 19:24:11 +0100 +Subject: [PATCH] netfilter: nft_flow_offload: use direct xmit if + hardware offload is enabled + +If there is a forward path to reach an ethernet device and hardware +offload is enabled, then use the direct xmit path. +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -131,6 +131,7 @@ struct flow_offload_tuple { + struct dst_entry *dst_cache; + struct { + u32 ifidx; ++ u32 hw_ifidx; + u8 h_source[ETH_ALEN]; + u8 h_dest[ETH_ALEN]; + } out; +@@ -188,6 +189,7 @@ struct nf_flow_route { + } in; + struct { + u32 ifindex; ++ u32 hw_ifindex; + u8 h_source[ETH_ALEN]; + u8 h_dest[ETH_ALEN]; + } out; +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -106,6 +106,7 @@ static int flow_offload_fill_route(struc + memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source, + ETH_ALEN); + flow_tuple->out.ifidx = route->tuple[dir].out.ifindex; ++ flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex; + break; + case FLOW_OFFLOAD_XMIT_XFRM: + case FLOW_OFFLOAD_XMIT_NEIGH: +--- a/net/netfilter/nf_flow_table_offload.c ++++ b/net/netfilter/nf_flow_table_offload.c +@@ -506,7 +506,7 @@ static void flow_offload_redirect(struct + switch (this_tuple->xmit_type) { + case FLOW_OFFLOAD_XMIT_DIRECT: + this_tuple = &flow->tuplehash[dir].tuple; +- ifindex = this_tuple->out.ifidx; ++ ifindex = this_tuple->out.hw_ifidx; + break; + case FLOW_OFFLOAD_XMIT_NEIGH: + other_tuple = &flow->tuplehash[!dir].tuple; +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -66,6 +66,7 @@ static int nft_dev_fill_forward_path(con + struct nft_forward_info { + const struct net_device *indev; + const struct net_device *outdev; ++ const struct net_device *hw_outdev; + struct id { + __u16 id; + __be16 proto; +@@ -76,9 +77,18 @@ struct nft_forward_info { + enum flow_offload_xmit_type xmit_type; + }; + ++static bool nft_is_valid_ether_device(const struct net_device *dev) ++{ ++ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || ++ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) ++ return false; ++ ++ return true; ++} ++ + static void nft_dev_path_info(const struct net_device_path_stack *stack, + struct nft_forward_info *info, +- unsigned char *ha) ++ unsigned char *ha, struct nf_flowtable *flowtable) + { + const struct net_device_path *path; + int i; +@@ -140,6 +150,12 @@ static void nft_dev_path_info(const stru + } + if (!info->outdev) + info->outdev = info->indev; ++ ++ info->hw_outdev = info->indev; ++ ++ if (nf_flowtable_hw_offload(flowtable) && ++ nft_is_valid_ether_device(info->indev)) ++ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; + } + + static bool nft_flowtable_find_dev(const struct net_device *dev, +@@ -171,7 +187,7 @@ static void nft_dev_forward_path(struct + int i; + + if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) +- nft_dev_path_info(&stack, &info, ha); ++ nft_dev_path_info(&stack, &info, ha, &ft->data); + + if (!info.indev || !nft_flowtable_find_dev(info.indev, ft)) + return; +@@ -187,6 +203,7 @@ static void nft_dev_forward_path(struct + memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); + memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN); + route->tuple[dir].out.ifindex = info.outdev->ifindex; ++ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex; + route->tuple[dir].xmit_type = info.xmit_type; + } + } diff --git a/target/linux/generic/pending-5.10/640-18-netfilter-flowtable-handle-bridge-vlan-filter-offloa.patch b/target/linux/generic/pending-5.10/640-18-netfilter-flowtable-handle-bridge-vlan-filter-offloa.patch deleted file mode 100644 index ba480f3520..0000000000 --- a/target/linux/generic/pending-5.10/640-18-netfilter-flowtable-handle-bridge-vlan-filter-offloa.patch +++ /dev/null @@ -1,106 +0,0 @@ -From: Felix Fietkau -Date: Wed, 10 Feb 2021 19:44:33 +0100 -Subject: [PATCH] netfilter: flowtable: handle bridge vlan filter offload - tags from DSA/switchdev - -When a switchdev/DSA port is an untagged member of a bridge vlan, ingress -packets could potentially be tagged with the id of the VLAN. -When the VLAN port group has been uploaded to switchdev, report the bridge -tag mode as DEV_PATH_BR_VLAN_UNTAG_HW instead of DEV_PATH_BR_VLAN_UNTAG -and handle it in netfilter flow offloading by storing the tag in the tuple -in_pvid field. -This allows the ingress hook to detect the optional tag and remove it for -software offload. This tag processing is for ingress only, egress needs to be -fully untagged - -Signed-off-by: Felix Fietkau ---- - ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -853,6 +853,7 @@ struct net_device_path { - DEV_PATH_BR_VLAN_KEEP, - DEV_PATH_BR_VLAN_TAG, - DEV_PATH_BR_VLAN_UNTAG, -+ DEV_PATH_BR_VLAN_UNTAG_HW, - } vlan_mode; - u16 vlan_id; - __be16 vlan_proto; ---- a/include/net/netfilter/nf_flow_table.h -+++ b/include/net/netfilter/nf_flow_table.h -@@ -183,6 +183,10 @@ struct nf_flow_route { - u32 ifindex; - u16 vid[NF_FLOW_TABLE_VLAN_MAX]; - __be16 vproto[NF_FLOW_TABLE_VLAN_MAX]; -+ struct { -+ u16 id; -+ __be16 proto; -+ } pvid; - u8 num_vlans; - } in; - struct { ---- a/net/bridge/br_device.c -+++ b/net/bridge/br_device.c -@@ -435,6 +435,7 @@ static int br_fill_forward_path(struct n - ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto; - ctx->num_vlans++; - break; -+ case DEV_PATH_BR_VLAN_UNTAG_HW: - case DEV_PATH_BR_VLAN_UNTAG: - ctx->num_vlans--; - break; ---- a/net/bridge/br_vlan.c -+++ b/net/bridge/br_vlan.c -@@ -1374,6 +1374,8 @@ int br_vlan_fill_forward_path_mode(struc - - if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG) - path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP; -+ else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV) -+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW; - else - path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG; - ---- a/net/netfilter/nf_flow_table_core.c -+++ b/net/netfilter/nf_flow_table_core.c -@@ -98,6 +98,8 @@ static int flow_offload_fill_route(struc - j++; - } - flow_tuple->in_vlan_num = route->tuple[dir].in.num_vlans; -+ flow_tuple->in_pvid.id = route->tuple[dir].in.pvid.id; -+ flow_tuple->in_pvid.proto = route->tuple[dir].in.pvid.proto; - - switch (route->tuple[dir].xmit_type) { - case FLOW_OFFLOAD_XMIT_DIRECT: ---- a/net/netfilter/nft_flow_offload.c -+++ b/net/netfilter/nft_flow_offload.c -@@ -67,6 +67,10 @@ struct nft_forward_info { - const struct net_device *dev; - __u16 vid[NF_FLOW_TABLE_VLAN_MAX]; - __be16 vproto[NF_FLOW_TABLE_VLAN_MAX]; -+ struct { -+ __u16 id; -+ __be16 proto; -+ } pvid; - u8 num_vlans; - u8 h_source[ETH_ALEN]; - u8 h_dest[ETH_ALEN]; -@@ -127,6 +131,10 @@ static void nft_dev_path_info(const stru - info->vproto[info->num_vlans] = path->bridge.vlan_proto; - info->num_vlans++; - break; -+ case DEV_PATH_BR_VLAN_UNTAG_HW: -+ info->pvid.id = info->vid[info->num_vlans - 1]; -+ info->pvid.proto = info->vproto[info->num_vlans - 1]; -+ fallthrough; - case DEV_PATH_BR_VLAN_UNTAG: - info->num_vlans--; - break; -@@ -185,6 +193,8 @@ static void nft_dev_forward_path(struct - route->tuple[!dir].in.vid[i] = info.vid[i]; - route->tuple[!dir].in.vproto[i] = info.vproto[i]; - } -+ route->tuple[!dir].in.pvid.id = info.pvid.id; -+ route->tuple[!dir].in.pvid.proto = info.pvid.proto; - route->tuple[!dir].in.num_vlans = info.num_vlans; - - if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { diff --git a/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch b/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch new file mode 100644 index 0000000000..33600a862e --- /dev/null +++ b/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch @@ -0,0 +1,122 @@ +From: Felix Fietkau +Date: Mon, 8 Mar 2021 12:06:44 +0100 +Subject: [PATCH] netfilter: nf_flow_table: fix untagging with + hardware-offloaded bridge vlan_filtering + +When switchdev offloading is enabled, treat an untagged VLAN as tagged for +ingress only + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -855,6 +855,7 @@ struct net_device_path { + DEV_PATH_BR_VLAN_KEEP, + DEV_PATH_BR_VLAN_TAG, + DEV_PATH_BR_VLAN_UNTAG, ++ DEV_PATH_BR_VLAN_UNTAG_HW, + } vlan_mode; + u16 vlan_id; + __be16 vlan_proto; +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -123,9 +123,10 @@ struct flow_offload_tuple { + /* All members above are keys for lookups, see flow_offload_hash(). */ + struct { } __hash; + +- u8 dir:4, ++ u8 dir:2, + xmit_type:2, +- encap_num:2; ++ encap_num:2, ++ in_vlan_ingress:2; + u16 mtu; + union { + struct dst_entry *dst_cache; +@@ -185,7 +186,8 @@ struct nf_flow_route { + u16 id; + __be16 proto; + } encap[NF_FLOW_TABLE_ENCAP_MAX]; +- u8 num_encaps; ++ u8 num_encaps:2, ++ ingress_vlans:2; + } in; + struct { + u32 ifindex; +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -435,6 +435,7 @@ static int br_fill_forward_path(struct n + ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto; + ctx->num_vlans++; + break; ++ case DEV_PATH_BR_VLAN_UNTAG_HW: + case DEV_PATH_BR_VLAN_UNTAG: + ctx->num_vlans--; + break; +--- a/net/bridge/br_vlan.c ++++ b/net/bridge/br_vlan.c +@@ -1374,6 +1374,8 @@ int br_vlan_fill_forward_path_mode(struc + + if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG) + path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP; ++ else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV) ++ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW; + else + path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG; + +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -95,6 +95,8 @@ static int flow_offload_fill_route(struc + for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) { + flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id; + flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto; ++ if (route->tuple[dir].in.ingress_vlans & BIT(i)) ++ flow_tuple->in_vlan_ingress |= BIT(j); + j++; + } + flow_tuple->encap_num = route->tuple[dir].in.num_encaps; +--- a/net/netfilter/nf_flow_table_offload.c ++++ b/net/netfilter/nf_flow_table_offload.c +@@ -592,8 +592,12 @@ nf_flow_rule_route_common(struct net *ne + other_tuple = &flow->tuplehash[!dir].tuple; + + for (i = 0; i < other_tuple->encap_num; i++) { +- struct flow_action_entry *entry = flow_action_entry_next(flow_rule); ++ struct flow_action_entry *entry; + ++ if (other_tuple->in_vlan_ingress & BIT(i)) ++ continue; ++ ++ entry = flow_action_entry_next(flow_rule); + entry->id = FLOW_ACTION_VLAN_PUSH; + entry->vlan.vid = other_tuple->encap[i].id; + entry->vlan.proto = other_tuple->encap[i].proto; +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -72,6 +72,7 @@ struct nft_forward_info { + __be16 proto; + } encap[NF_FLOW_TABLE_ENCAP_MAX]; + u8 num_encaps; ++ u8 ingress_vlans; + u8 h_source[ETH_ALEN]; + u8 h_dest[ETH_ALEN]; + enum flow_offload_xmit_type xmit_type; +@@ -130,6 +131,9 @@ static void nft_dev_path_info(const stru + memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); + + switch (path->bridge.vlan_mode) { ++ case DEV_PATH_BR_VLAN_UNTAG_HW: ++ info->ingress_vlans |= BIT(info->num_encaps - 1); ++ break; + case DEV_PATH_BR_VLAN_TAG: + info->encap[info->num_encaps].id = path->bridge.vlan_id; + info->encap[info->num_encaps].proto = path->bridge.vlan_proto; +@@ -198,6 +202,7 @@ static void nft_dev_forward_path(struct + route->tuple[!dir].in.encap[i].proto = info.encap[i].proto; + } + route->tuple[!dir].in.num_encaps = info.num_encaps; ++ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans; + + if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { + memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); diff --git a/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch b/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch new file mode 100644 index 0000000000..3eaad27cdf --- /dev/null +++ b/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch @@ -0,0 +1,26 @@ +From: Pablo Neira Ayuso +Date: Tue, 2 Mar 2021 00:51:31 +0100 +Subject: [PATCH] net: flow_offload: add FLOW_ACTION_PPPOE_PUSH + +--- + +--- a/include/net/flow_offload.h ++++ b/include/net/flow_offload.h +@@ -147,6 +147,7 @@ enum flow_action_id { + FLOW_ACTION_MPLS_POP, + FLOW_ACTION_MPLS_MANGLE, + FLOW_ACTION_GATE, ++ FLOW_ACTION_PPPOE_PUSH, + NUM_FLOW_ACTIONS, + }; + +@@ -271,6 +272,9 @@ struct flow_action_entry { + u32 num_entries; + struct action_gate_entry *entries; + } gate; ++ struct { /* FLOW_ACTION_PPPOE_PUSH */ ++ u16 sid; ++ } pppoe; + }; + struct flow_action_cookie *cookie; /* user defined action cookie */ + }; diff --git a/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch b/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch new file mode 100644 index 0000000000..fcafff1fff --- /dev/null +++ b/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch @@ -0,0 +1,31 @@ +From: Pablo Neira Ayuso +Date: Tue, 2 Mar 2021 01:01:50 +0100 +Subject: [PATCH] netfilter: flowtable: support for + FLOW_ACTION_PPPOE_PUSH + +--- + +--- a/net/netfilter/nf_flow_table_offload.c ++++ b/net/netfilter/nf_flow_table_offload.c +@@ -598,9 +598,18 @@ nf_flow_rule_route_common(struct net *ne + continue; + + entry = flow_action_entry_next(flow_rule); +- entry->id = FLOW_ACTION_VLAN_PUSH; +- entry->vlan.vid = other_tuple->encap[i].id; +- entry->vlan.proto = other_tuple->encap[i].proto; ++ ++ switch (other_tuple->encap[i].proto) { ++ case htons(ETH_P_PPP_SES): ++ entry->id = FLOW_ACTION_PPPOE_PUSH; ++ entry->pppoe.sid = other_tuple->encap[i].id; ++ break; ++ case htons(ETH_P_8021Q): ++ entry->id = FLOW_ACTION_VLAN_PUSH; ++ entry->vlan.vid = other_tuple->encap[i].id; ++ entry->vlan.proto = other_tuple->encap[i].proto; ++ break; ++ } + } + + return 0; diff --git a/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index 6d0c84c494..0422221468 100644 --- a/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2031,6 +2031,8 @@ struct net_device { +@@ -2033,6 +2033,8 @@ struct net_device { struct netdev_hw_addr_list mc; struct netdev_hw_addr_list dev_addrs; diff --git a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch index b2c2d00ec0..24b78b94d7 100644 --- a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch +++ b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch @@ -50,7 +50,7 @@ Signed-off-by: Felix Fietkau }; enum gro_result { -@@ -2411,6 +2414,26 @@ void netif_napi_add(struct net_device *d +@@ -2413,6 +2416,26 @@ void netif_napi_add(struct net_device *d int (*poll)(struct napi_struct *, int), int weight); /** diff --git a/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch b/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch index fa9cbcafc8..2f1ae6cde6 100644 --- a/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch +++ b/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch @@ -80,7 +80,7 @@ Signed-off-by: Pablo Neira Ayuso #endif /* MTK_ETH_H */ --- /dev/null +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -0,0 +1,478 @@ +@@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Felix Fietkau @@ -113,6 +113,10 @@ Signed-off-by: Pablo Neira Ayuso + __be16 proto; + u8 num; + } vlan; ++ struct { ++ u16 sid; ++ u8 num; ++ } pppoe; +}; + +struct mtk_flow_entry { @@ -311,13 +315,20 @@ Signed-off-by: Pablo Neira Ayuso + break; + case FLOW_ACTION_VLAN_PUSH: + if (data.vlan.num == 1 || -+ data.vlan.proto != ETH_P_8021Q) ++ act->vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + + data.vlan.id = act->vlan.vid; + data.vlan.proto = act->vlan.proto; + data.vlan.num++; + break; ++ case FLOW_ACTION_PPPOE_PUSH: ++ if (data.pppoe.num == 1) ++ return -EOPNOTSUPP; ++ ++ data.pppoe.sid = act->pppoe.sid; ++ data.pppoe.num++; ++ break; + default: + return -EOPNOTSUPP; + } @@ -392,11 +403,13 @@ Signed-off-by: Pablo Neira Ayuso + } + + if (data.vlan.num == 1) { -+ if (data.vlan.proto != ETH_P_8021Q) ++ if (data.vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + + mtk_foe_entry_set_vlan(&foe, data.vlan.id); + } ++ if (data.pppoe.num == 1) ++ mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); + + err = mtk_flow_set_output_device(eth, &foe, odev); + if (err) From 3d1ea0d77f9d313c85ee82ef90082083f9e0176e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 12 Mar 2021 14:45:19 +0100 Subject: [PATCH 13/32] kernel: add compatibility with upstream threaded NAPI patch Enable threading if dev->threaded is set. This will be used to bring mt76 back in sync with upstream Signed-off-by: Felix Fietkau --- ...dd-support-for-threaded-NAPI-polling.patch | 28 +++++++++++++++---- ...dd-support-for-threaded-NAPI-polling.patch | 25 +++++++++++++---- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch index 24b78b94d7..626bac99f6 100644 --- a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch +++ b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch @@ -50,7 +50,15 @@ Signed-off-by: Felix Fietkau }; enum gro_result { -@@ -2413,6 +2416,26 @@ void netif_napi_add(struct net_device *d +@@ -2211,6 +2214,7 @@ struct net_device { + struct lock_class_key *qdisc_running_key; + bool proto_down; + unsigned wol_enabled:1; ++ unsigned threaded:1; + + struct list_head net_notifier_list; + +@@ -2413,6 +2417,26 @@ void netif_napi_add(struct net_device *d int (*poll)(struct napi_struct *, int), int weight); /** @@ -111,7 +119,7 @@ Signed-off-by: Felix Fietkau ____napi_schedule(this_cpu_ptr(&softnet_data), n); } EXPORT_SYMBOL(__napi_schedule_irqoff); -@@ -6715,6 +6726,86 @@ static void init_gro_hash(struct napi_st +@@ -6715,12 +6726,94 @@ static void init_gro_hash(struct napi_st napi->gro_bitmask = 0; } @@ -198,7 +206,15 @@ Signed-off-by: Felix Fietkau void netif_napi_add(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight) { -@@ -6738,6 +6829,7 @@ void netif_napi_add(struct net_device *d + if (WARN_ON(test_and_set_bit(NAPI_STATE_LISTED, &napi->state))) + return; + ++ if (dev->threaded) ++ set_bit(NAPI_STATE_THREADED, &napi->state); + INIT_LIST_HEAD(&napi->poll_list); + INIT_HLIST_NODE(&napi->napi_hash_node); + hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); +@@ -6738,6 +6831,7 @@ void netif_napi_add(struct net_device *d #ifdef CONFIG_NETPOLL napi->poll_owner = -1; #endif @@ -206,7 +222,7 @@ Signed-off-by: Felix Fietkau set_bit(NAPI_STATE_SCHED, &napi->state); set_bit(NAPI_STATE_NPSVC, &napi->state); list_add_rcu(&napi->dev_list, &dev->napi_list); -@@ -6780,6 +6872,7 @@ void __netif_napi_del(struct napi_struct +@@ -6780,6 +6874,7 @@ void __netif_napi_del(struct napi_struct if (!test_and_clear_bit(NAPI_STATE_LISTED, &napi->state)) return; @@ -214,7 +230,7 @@ Signed-off-by: Felix Fietkau napi_hash_del(napi); list_del_rcu(&napi->dev_list); napi_free_frags(napi); -@@ -6791,53 +6884,19 @@ EXPORT_SYMBOL(__netif_napi_del); +@@ -6791,53 +6886,19 @@ EXPORT_SYMBOL(__netif_napi_del); static int napi_poll(struct napi_struct *n, struct list_head *repoll) { @@ -272,7 +288,7 @@ Signed-off-by: Felix Fietkau /* Some drivers may have called napi_schedule * prior to exhausting their budget. */ -@@ -11291,6 +11350,10 @@ static int __init net_dev_init(void) +@@ -11291,6 +11352,10 @@ static int __init net_dev_init(void) sd->backlog.weight = weight_p; } diff --git a/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch b/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch index 6d24007b6a..a90bb2c285 100644 --- a/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch +++ b/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch @@ -50,7 +50,15 @@ Signed-off-by: Felix Fietkau }; enum gro_result { -@@ -2249,6 +2252,26 @@ void netif_napi_add(struct net_device *d +@@ -2092,6 +2095,7 @@ struct net_device { + struct lock_class_key addr_list_lock_key; + bool proto_down; + unsigned wol_enabled:1; ++ unsigned threaded:1; + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + +@@ -2249,6 +2253,26 @@ void netif_napi_add(struct net_device *d int (*poll)(struct napi_struct *, int), int weight); /** @@ -111,7 +119,7 @@ Signed-off-by: Felix Fietkau ____napi_schedule(this_cpu_ptr(&softnet_data), n); } EXPORT_SYMBOL(__napi_schedule_irqoff); -@@ -6219,6 +6230,84 @@ static void init_gro_hash(struct napi_st +@@ -6219,9 +6230,89 @@ static void init_gro_hash(struct napi_st napi->gro_bitmask = 0; } @@ -196,7 +204,12 @@ Signed-off-by: Felix Fietkau void netif_napi_add(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight) { -@@ -6238,6 +6327,7 @@ void netif_napi_add(struct net_device *d ++ if (dev->threaded) ++ set_bit(NAPI_STATE_THREADED, &napi->state); + INIT_LIST_HEAD(&napi->poll_list); + hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + napi->timer.function = napi_watchdog; +@@ -6238,6 +6329,7 @@ void netif_napi_add(struct net_device *d #ifdef CONFIG_NETPOLL napi->poll_owner = -1; #endif @@ -204,7 +217,7 @@ Signed-off-by: Felix Fietkau set_bit(NAPI_STATE_SCHED, &napi->state); set_bit(NAPI_STATE_NPSVC, &napi->state); list_add_rcu(&napi->dev_list, &dev->napi_list); -@@ -6278,6 +6368,7 @@ static void flush_gro_hash(struct napi_s +@@ -6278,6 +6370,7 @@ static void flush_gro_hash(struct napi_s void netif_napi_del(struct napi_struct *napi) { might_sleep(); @@ -212,7 +225,7 @@ Signed-off-by: Felix Fietkau if (napi_hash_del(napi)) synchronize_net(); list_del_init(&napi->dev_list); -@@ -6290,50 +6381,18 @@ EXPORT_SYMBOL(netif_napi_del); +@@ -6290,50 +6383,18 @@ EXPORT_SYMBOL(netif_napi_del); static int napi_poll(struct napi_struct *n, struct list_head *repoll) { @@ -267,7 +280,7 @@ Signed-off-by: Felix Fietkau /* Some drivers may have called napi_schedule * prior to exhausting their budget. -@@ -10271,6 +10330,10 @@ static int __init net_dev_init(void) +@@ -10271,6 +10332,10 @@ static int __init net_dev_init(void) sd->backlog.weight = weight_p; } From 9530b9bb78845910de711d425f1e4b1c7d539b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Mar 2021 21:08:24 +0100 Subject: [PATCH 14/32] bcm47xx: make WGT634U NVRAM patch apply again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 1c48eee5b2bc ("kernel: backport Broadcom NVRAM driver cleanups") Signed-off-by: Rafał Miłecki --- .../patches-5.4/820-wgt634u-nvram-fix.patch | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/target/linux/bcm47xx/patches-5.4/820-wgt634u-nvram-fix.patch b/target/linux/bcm47xx/patches-5.4/820-wgt634u-nvram-fix.patch index 6d58c1b042..5f4af85df2 100644 --- a/target/linux/bcm47xx/patches-5.4/820-wgt634u-nvram-fix.patch +++ b/target/linux/bcm47xx/patches-5.4/820-wgt634u-nvram-fix.patch @@ -250,28 +250,18 @@ out the configuration than the in kernel cfe config reader. +static int cfe_env; +extern char *cfe_env_get(char *nv_buf, const char *name); - static u32 find_nvram_size(void __iomem *end) - { -@@ -52,7 +54,9 @@ static u32 find_nvram_size(void __iomem - static int nvram_find_and_copy(void __iomem *iobase, u32 lim) - { - struct nvram_header __iomem *header; -+ int i; - u32 off; -+ u32 *src, *dst; - u32 size; - - if (nvram_len) { -@@ -60,6 +64,26 @@ static int nvram_find_and_copy(void __io + /** + * bcm47xx_nvram_is_valid - check for a valid NVRAM at specified memory +@@ -80,6 +82,26 @@ static int bcm47xx_nvram_find_and_copy(v return -EEXIST; } + cfe_env = 0; + + /* XXX: hack for supporting the CFE environment stuff on WGT634U */ -+ if (lim >= 8 * 1024 * 1024) { -+ src = (u32 *)(iobase + 8 * 1024 * 1024 - 0x2000); -+ dst = (u32 *)nvram_buf; ++ if (res_size >= 8 * 1024 * 1024) { ++ u32 *src = (u32 *)(flash_start + 8 * 1024 * 1024 - 0x2000); ++ u32 *dst = (u32 *)nvram_buf; + + if ((*src & 0xff00ff) == 0x000001) { + printk("early_nvram_init: WGT634U NVRAM found.\n"); @@ -287,9 +277,9 @@ out the configuration than the in kernel cfe config reader. + } + /* TODO: when nvram is on nand flash check for bad blocks first. */ - off = FLASH_MIN; - while (off <= lim) { -@@ -170,6 +194,13 @@ int bcm47xx_nvram_getenv(const char *nam + + /* Try every possible flash size and check for NVRAM at its end */ +@@ -172,6 +194,13 @@ int bcm47xx_nvram_getenv(const char *nam if (!name) return -EINVAL; From 997ff740dc44045390680eaa30b6566d40bca322 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 13 Mar 2021 13:38:25 +0000 Subject: [PATCH 15/32] uboot-mediatek: fix build on Mac OS X Copy patch added to uboot-sunxi by commit 3cc57ba462 ("uboot-sunxi: add missing type __u64") also to uboot-mediatek. Signed-off-by: Daniel Golle --- .../patches/260-add-missing-type-u64.patch | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch diff --git a/package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch b/package/boot/uboot-mediatek/patches/260-add-missing-type-u64.patch new file mode 100644 index 0000000000..a6204c7b69 --- /dev/null +++ b/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 From 1a7ef2c3cf12262ebd1d445a525b9778657d824f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 13 Mar 2021 14:59:33 +0000 Subject: [PATCH 16/32] mediatek: image: don't use 'M' unit as dd may not support that dd on Mac OS X apparently fails when using 'M' unit for bs. dd: bs: illegal numeric value Use 'k' unit instead for 'pad-to' to fix that. Reported-by: Georgi Valkov Signed-off-by: Daniel Golle --- target/linux/mediatek/image/mt7622.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/linux/mediatek/image/mt7622.mk b/target/linux/mediatek/image/mt7622.mk index 0de1c375b2..9f54021524 100644 --- a/target/linux/mediatek/image/mt7622.mk +++ b/target/linux/mediatek/image/mt7622.mk @@ -48,8 +48,8 @@ define Device/bananapi_bpi-r64 IMAGES := sysupgrade.itb KERNEL_INITRAMFS_SUFFIX := -recovery.itb ARTIFACT/sdcard.img := mt7622-gpt sdmmc | pad-to 128k | mt7622-gpt emmc | pad-to 256k |\ - bl2 emmc-2ddr | pad-to 512k | bl2 sdmmc-2ddr | pad-to 1M | bl31-uboot bananapi_bpi-r64-emmc | pad-to 2M |\ - bl31-uboot bananapi_bpi-r64-sdmmc | pad-to 6M + bl2 emmc-2ddr | pad-to 512k | bl2 sdmmc-2ddr | pad-to 1024k | bl31-uboot bananapi_bpi-r64-emmc | pad-to 2048k |\ + bl31-uboot bananapi_bpi-r64-sdmmc | pad-to 6144k KERNEL := kernel-bin | gzip KERNEL_INITRAMFS := kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb with-initrd | pad-to 128k IMAGE/sysupgrade.itb := append-kernel | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb external-static-with-rootfs | append-metadata From e7fa97b326e596f64c4b9965c6f6c3773944c2c6 Mon Sep 17 00:00:00 2001 From: John Audia Date: Sun, 7 Mar 2021 07:26:24 -0500 Subject: [PATCH 17/32] kernel: bump 5.4 to 5.4.105 Ran update_kernel.sh in a fresh clone without any existing toolchains. Removed upstreamed generic-backports: 830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch 831-v5.9-usbip-tools-fix-build-error-for-multiple-definition.patch 755-v5.8-net-dsa-add-GRO-support-via-gro_cells.patch Build system: x86_64 Build-tested: ipq806x/R7800 Run-tested: ipq806x/R7800 No dmesg regressions, everything functional Signed-off-by: John Audia Tested-by: Curtis Deptuck [x86/64] [squash patches] Signed-off-by: Adrian Schmutzler --- include/kernel-version.mk | 4 +- ...ce-quirks-for-Freeway-Airmouse-T3-an.patch | 4 +- ...add-V4L2_CTRL_TYPE_AREA-control-type.patch | 4 +- ...finitions-for-HEVC-stateless-decodin.patch | 2 +- ...uapi-hevc-Add-scaling-matrix-control.patch | 2 +- ...ls-Add-helper-to-register-properties.patch | 2 +- ...-vdso-fix-jalr-t9-crash-in-vdso-code.patch | 2 +- ...an-option-for-drivers-to-always-rece.patch | 2 +- ...et-dsa-add-GRO-support-via-gro_cells.patch | 143 ------------------ ...usb-qmi_wwan-support-ZTE-P685M-modem.patch | 60 -------- ...-build-error-for-multiple-definition.patch | 33 ---- .../hack-5.4/904-debloat_dma_buf.patch | 2 +- .../306-mips_mem_functions_performance.patch | 2 +- ...dd-support-for-threaded-NAPI-polling.patch | 2 +- ...r-Gateworks-PLX-PEX860x-switch-with-.patch | 2 +- ...0031-uvc-add-iPassion-iP2970-support.patch | 2 +- .../200-pcengines-apu2-reboot.patch | 2 +- 17 files changed, 17 insertions(+), 253 deletions(-) delete mode 100644 target/linux/generic/backport-5.4/755-v5.8-net-dsa-add-GRO-support-via-gro_cells.patch delete mode 100644 target/linux/generic/backport-5.4/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch delete mode 100644 target/linux/generic/backport-5.4/831-v5.9-usbip-tools-fix-build-error-for-multiple-definition.patch diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 33fe6b2d0e..7e326d60b6 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,10 +6,10 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .102 +LINUX_VERSION-5.4 = .105 LINUX_VERSION-5.10 = .20 -LINUX_KERNEL_HASH-5.4.102 = fd697ce1c3f6024d4ae77d4eb5a1552199407b60cb8e90bc621e23cbce639aed +LINUX_KERNEL_HASH-5.4.105 = 244e4cd16184285df55ec5a9501daba011aa8b85c5527ee05eab4592e70fb8b6 LINUX_KERNEL_HASH-5.10.20 = 9be37146feba42be05137cf900a7d9012990b5a1d5e59bc0c8da1f86952930a3 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) diff --git a/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch b/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch index ee886e31a5..71d2f7da05 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch @@ -33,7 +33,7 @@ Signed-off-by: Jonathan Bell #define USB_VENDOR_ID_BELKIN 0x050d #define USB_DEVICE_ID_FLIP_KVM 0x3201 -@@ -1254,6 +1257,9 @@ +@@ -1257,6 +1260,9 @@ #define USB_VENDOR_ID_XAT 0x2505 #define USB_DEVICE_ID_XAT_CSR 0x0220 @@ -53,7 +53,7 @@ Signed-off-by: Jonathan Bell { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL }, -@@ -189,6 +190,7 @@ static const struct hid_device_id hid_qu +@@ -190,6 +191,7 @@ static const struct hid_device_id hid_qu { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT }, diff --git a/target/linux/bcm27xx/patches-5.4/950-0482-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch b/target/linux/bcm27xx/patches-5.4/950-0482-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch index d82c3196b8..4d7440b999 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0482-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0482-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch @@ -39,7 +39,7 @@ Signed-off-by: Mauro Carvalho Chehab default: return -EINVAL; } -@@ -2422,6 +2428,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s +@@ -2423,6 +2429,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); break; @@ -49,7 +49,7 @@ Signed-off-by: Mauro Carvalho Chehab default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); -@@ -4086,6 +4095,18 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l +@@ -4087,6 +4096,18 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); diff --git a/target/linux/bcm27xx/patches-5.4/950-0492-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch b/target/linux/bcm27xx/patches-5.4/950-0492-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch index 0fe0f8cea4..e08d2481ed 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0492-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0492-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch @@ -820,7 +820,7 @@ Signed-off-by: Mauro Carvalho Chehab default: return -EINVAL; } -@@ -2433,6 +2531,15 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s +@@ -2434,6 +2532,15 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0495-media-uapi-hevc-Add-scaling-matrix-control.patch b/target/linux/bcm27xx/patches-5.4/950-0495-media-uapi-hevc-Add-scaling-matrix-control.patch index c2cf27a40e..c63a0a8bbc 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0495-media-uapi-hevc-Add-scaling-matrix-control.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0495-media-uapi-hevc-Add-scaling-matrix-control.patch @@ -106,7 +106,7 @@ Signed-off-by: Jernej Skrabec case V4L2_CTRL_TYPE_AREA: area = p; if (!area->width || !area->height) -@@ -2540,6 +2547,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s +@@ -2541,6 +2548,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0908-media-v4l2-ctrls-Add-helper-to-register-properties.patch b/target/linux/bcm27xx/patches-5.4/950-0908-media-v4l2-ctrls-Add-helper-to-register-properties.patch index a76de95bf3..cf637cea04 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0908-media-v4l2-ctrls-Add-helper-to-register-properties.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0908-media-v4l2-ctrls-Add-helper-to-register-properties.patch @@ -29,7 +29,7 @@ Signed-off-by: Laurent Pinchart #define dprintk(vdev, fmt, arg...) do { \ if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \ -@@ -4577,3 +4578,42 @@ __poll_t v4l2_ctrl_poll(struct file *fil +@@ -4578,3 +4579,42 @@ __poll_t v4l2_ctrl_poll(struct file *fil return 0; } EXPORT_SYMBOL(v4l2_ctrl_poll); diff --git a/target/linux/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch b/target/linux/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch index 25c87a3263..51eef4b26b 100644 --- a/target/linux/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch +++ b/target/linux/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch @@ -44,7 +44,7 @@ Cc: richard.purdie@linuxfoundation.org --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile -@@ -29,6 +29,7 @@ endif +@@ -26,6 +26,7 @@ ccflags-vdso := \ cflags-vdso := $(ccflags-vdso) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ diff --git a/target/linux/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch b/target/linux/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch index 97ac6e2acd..921821a899 100644 --- a/target/linux/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch +++ b/target/linux/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch @@ -50,7 +50,7 @@ Signed-off-by: David S. Miller */ --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h -@@ -136,6 +136,7 @@ int dsa_port_bridge_join(struct dsa_port +@@ -139,6 +139,7 @@ int dsa_port_bridge_join(struct dsa_port void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, struct switchdev_trans *trans); diff --git a/target/linux/generic/backport-5.4/755-v5.8-net-dsa-add-GRO-support-via-gro_cells.patch b/target/linux/generic/backport-5.4/755-v5.8-net-dsa-add-GRO-support-via-gro_cells.patch deleted file mode 100644 index 6d50a40d61..0000000000 --- a/target/linux/generic/backport-5.4/755-v5.8-net-dsa-add-GRO-support-via-gro_cells.patch +++ /dev/null @@ -1,143 +0,0 @@ -From: Alexander Lobakin -Date: Tue, 21 Apr 2020 16:41:08 +0300 -Subject: [PATCH] net: dsa: add GRO support via gro_cells - -gro_cells lib is used by different encapsulating netdevices, such as -geneve, macsec, vxlan etc. to speed up decapsulated traffic processing. -CPU tag is a sort of "encapsulation", and we can use the same mechs to -greatly improve overall DSA performance. -skbs are passed to the GRO layer after removing CPU tags, so we don't -need any new packet offload types as it was firstly proposed by me in -the first GRO-over-DSA variant [1]. - -The size of struct gro_cells is sizeof(void *), so hot struct -dsa_slave_priv becomes only 4/8 bytes bigger, and all critical fields -remain in one 32-byte cacheline. -The other positive side effect is that drivers for network devices -that can be shipped as CPU ports of DSA-driven switches can now use -napi_gro_frags() to pass skbs to kernel. Packets built that way are -completely non-linear and are likely being dropped without GRO. - -This was tested on to-be-mainlined-soon Ethernet driver that uses -napi_gro_frags(), and the overall performance was on par with the -variant from [1], sometimes even better due to minimal overhead. -net.core.gro_normal_batch tuning may help to push it to the limit -on particular setups and platforms. - -iperf3 IPoE VLAN NAT TCP forwarding (port1.218 -> port0) setup -on 1.2 GHz MIPS board: - -5.7-rc2 baseline: - -[ID] Interval Transfer Bitrate Retr -[ 5] 0.00-120.01 sec 9.00 GBytes 644 Mbits/sec 413 sender -[ 5] 0.00-120.00 sec 8.99 GBytes 644 Mbits/sec receiver - -Iface RX packets TX packets -eth0 7097731 7097702 -port0 426050 6671829 -port1 6671681 425862 -port1.218 6671677 425851 - -With this patch: - -[ID] Interval Transfer Bitrate Retr -[ 5] 0.00-120.01 sec 12.2 GBytes 870 Mbits/sec 122 sender -[ 5] 0.00-120.00 sec 12.2 GBytes 870 Mbits/sec receiver - -Iface RX packets TX packets -eth0 9474792 9474777 -port0 455200 353288 -port1 9019592 455035 -port1.218 353144 455024 - -v2: - - Add some performance examples in the commit message; - - No functional changes. - -[1] https://lore.kernel.org/netdev/20191230143028.27313-1-alobakin@dlink.ru/ - -Signed-off-by: Alexander Lobakin -Signed-off-by: David S. Miller ---- - ---- a/net/dsa/Kconfig -+++ b/net/dsa/Kconfig -@@ -9,6 +9,7 @@ menuconfig NET_DSA - tristate "Distributed Switch Architecture" - depends on HAVE_NET_DSA - depends on BRIDGE || BRIDGE=n -+ select GRO_CELLS - select NET_SWITCHDEV - select PHYLINK - select NET_DEVLINK ---- a/net/dsa/dsa.c -+++ b/net/dsa/dsa.c -@@ -238,7 +238,7 @@ static int dsa_switch_rcv(struct sk_buff - if (dsa_skb_defer_rx_timestamp(p, skb)) - return 0; - -- netif_receive_skb(skb); -+ gro_cells_receive(&p->gcells, skb); - - return 0; - } ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - enum { - DSA_NOTIFIER_AGEING_TIME, -@@ -68,6 +69,8 @@ struct dsa_slave_priv { - - struct pcpu_sw_netstats *stats64; - -+ struct gro_cells gcells; -+ - /* DSA port data, such as switch, port index, etc. */ - struct dsa_port *dp; - ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -1431,6 +1431,11 @@ int dsa_slave_create(struct dsa_port *po - free_netdev(slave_dev); - return -ENOMEM; - } -+ -+ ret = gro_cells_init(&p->gcells, slave_dev); -+ if (ret) -+ goto out_free; -+ - p->dp = port; - INIT_LIST_HEAD(&p->mall_tc_list); - INIT_WORK(&port->xmit_work, dsa_port_xmit_work); -@@ -1443,7 +1448,7 @@ int dsa_slave_create(struct dsa_port *po - ret = dsa_slave_phy_setup(slave_dev); - if (ret) { - netdev_err(master, "error %d setting up slave phy\n", ret); -- goto out_free; -+ goto out_gcells; - } - - dsa_slave_notify(slave_dev, DSA_PORT_REGISTER); -@@ -1462,6 +1467,8 @@ out_phy: - phylink_disconnect_phy(p->dp->pl); - rtnl_unlock(); - phylink_destroy(p->dp->pl); -+out_gcells: -+ gro_cells_destroy(&p->gcells); - out_free: - free_percpu(p->stats64); - free_netdev(slave_dev); -@@ -1482,6 +1489,7 @@ void dsa_slave_destroy(struct net_device - dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER); - unregister_netdev(slave_dev); - phylink_destroy(dp->pl); -+ gro_cells_destroy(&p->gcells); - free_percpu(p->stats64); - free_netdev(slave_dev); - } diff --git a/target/linux/generic/backport-5.4/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch b/target/linux/generic/backport-5.4/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch deleted file mode 100644 index 35da12af92..0000000000 --- a/target/linux/generic/backport-5.4/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 88eee9b7b42e69fb622ddb3ff6f37e8e4347f5b2 Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Tue, 23 Feb 2021 19:34:56 +0100 -Subject: net: usb: qmi_wwan: support ZTE P685M modem -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Now that interface 3 in "option" driver is no longer mapped, add device -ID matching it to qmi_wwan. - -The modem is used inside ZTE MF283+ router and carriers identify it as -such. -Interface mapping is: -0: QCDM, 1: AT (PCUI), 2: AT (Modem), 3: QMI, 4: ADB - -T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 -D: Ver= 2.01 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 -P: Vendor=19d2 ProdID=1275 Rev=f0.00 -S: Manufacturer=ZTE,Incorporated -S: Product=ZTE Technologies MSM -S: SerialNumber=P685M510ZTED0000CP&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&0 -C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA -I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option -E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option -E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option -E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan -E: Ad=87(I) Atr=03(Int.) MxPS= 8 Ivl=32ms -E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) -E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms - -Acked-by: Bjørn Mork -Signed-off-by: Lech Perczak -Link: https://lore.kernel.org/r/20210223183456.6377-1-lech.perczak@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/usb/qmi_wwan.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/usb/qmi_wwan.c -+++ b/drivers/net/usb/qmi_wwan.c -@@ -1280,6 +1280,7 @@ static const struct usb_device_id produc - {QMI_FIXED_INTF(0x19d2, 0x1255, 4)}, - {QMI_FIXED_INTF(0x19d2, 0x1256, 4)}, - {QMI_FIXED_INTF(0x19d2, 0x1270, 5)}, /* ZTE MF667 */ -+ {QMI_FIXED_INTF(0x19d2, 0x1275, 3)}, /* ZTE P685M */ - {QMI_FIXED_INTF(0x19d2, 0x1401, 2)}, - {QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */ - {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, diff --git a/target/linux/generic/backport-5.4/831-v5.9-usbip-tools-fix-build-error-for-multiple-definition.patch b/target/linux/generic/backport-5.4/831-v5.9-usbip-tools-fix-build-error-for-multiple-definition.patch deleted file mode 100644 index 03f27fb528..0000000000 --- a/target/linux/generic/backport-5.4/831-v5.9-usbip-tools-fix-build-error-for-multiple-definition.patch +++ /dev/null @@ -1,33 +0,0 @@ -From d5efc2e6b98fe661dbd8dd0d5d5bfb961728e57a Mon Sep 17 00:00:00 2001 -From: Antonio Borneo -Date: Thu, 18 Jun 2020 02:08:44 +0200 -Subject: usbip: tools: fix build error for multiple definition - -With GCC 10, building usbip triggers error for multiple definition -of 'udev_context', in: -- libsrc/vhci_driver.c:18 and -- libsrc/usbip_host_common.c:27. - -Declare as extern the definition in libsrc/usbip_host_common.c. - -Signed-off-by: Antonio Borneo -Acked-by: Shuah Khan -Link: https://lore.kernel.org/r/20200618000844.1048309-1-borneo.antonio@gmail.com -Signed-off-by: Greg Kroah-Hartman ---- - tools/usb/usbip/libsrc/usbip_host_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -(limited to 'tools/usb/usbip') - ---- a/tools/usb/usbip/libsrc/usbip_host_common.c -+++ b/tools/usb/usbip/libsrc/usbip_host_common.c -@@ -23,7 +23,7 @@ - #include "list.h" - #include "sysfs_utils.h" - --struct udev *udev_context; -+extern struct udev *udev_context; - - static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) - { diff --git a/target/linux/generic/hack-5.4/904-debloat_dma_buf.patch b/target/linux/generic/hack-5.4/904-debloat_dma_buf.patch index 7c67478fc0..92c230c511 100644 --- a/target/linux/generic/hack-5.4/904-debloat_dma_buf.patch +++ b/target/linux/generic/hack-5.4/904-debloat_dma_buf.patch @@ -54,7 +54,7 @@ Signed-off-by: Felix Fietkau +MODULE_LICENSE("GPL"); --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -2756,6 +2756,7 @@ int wake_up_state(struct task_struct *p, +@@ -2754,6 +2754,7 @@ int wake_up_state(struct task_struct *p, { return try_to_wake_up(p, state, 0); } diff --git a/target/linux/generic/pending-5.4/306-mips_mem_functions_performance.patch b/target/linux/generic/pending-5.4/306-mips_mem_functions_performance.patch index 4e6b7b5cd3..611aa0314f 100644 --- a/target/linux/generic/pending-5.4/306-mips_mem_functions_performance.patch +++ b/target/linux/generic/pending-5.4/306-mips_mem_functions_performance.patch @@ -25,7 +25,7 @@ Signed-off-by: Felix Fietkau -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ --- a/arch/mips/include/asm/string.h +++ b/arch/mips/include/asm/string.h -@@ -140,4 +140,42 @@ extern void *memcpy(void *__to, __const_ +@@ -19,4 +19,42 @@ extern void *memcpy(void *__to, __const_ #define __HAVE_ARCH_MEMMOVE extern void *memmove(void *__dest, __const__ void *__src, size_t __n); diff --git a/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch b/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch index a90bb2c285..6392b9d756 100644 --- a/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch +++ b/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch @@ -280,7 +280,7 @@ Signed-off-by: Felix Fietkau /* Some drivers may have called napi_schedule * prior to exhausting their budget. -@@ -10271,6 +10332,10 @@ static int __init net_dev_init(void) +@@ -10313,6 +10374,10 @@ static int __init net_dev_init(void) sd->backlog.weight = weight_p; } diff --git a/target/linux/octeontx/patches-5.4/0004-PCI-add-quirk-for-Gateworks-PLX-PEX860x-switch-with-.patch b/target/linux/octeontx/patches-5.4/0004-PCI-add-quirk-for-Gateworks-PLX-PEX860x-switch-with-.patch index 833604ae55..e33a28e953 100644 --- a/target/linux/octeontx/patches-5.4/0004-PCI-add-quirk-for-Gateworks-PLX-PEX860x-switch-with-.patch +++ b/target/linux/octeontx/patches-5.4/0004-PCI-add-quirk-for-Gateworks-PLX-PEX860x-switch-with-.patch @@ -22,7 +22,7 @@ Signed-off-by: Tim Harvey #include #include #include -@@ -5622,3 +5623,34 @@ static void apex_pci_fixup_class(struct +@@ -5625,3 +5626,34 @@ static void apex_pci_fixup_class(struct } DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a, PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class); diff --git a/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch index 084b655483..dbeee8a78b 100644 --- a/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch +++ b/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch @@ -13,7 +13,7 @@ Signed-off-by: John Crispin --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c -@@ -2908,6 +2908,18 @@ static const struct usb_device_id uvc_id +@@ -2911,6 +2911,18 @@ static const struct usb_device_id uvc_id .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, diff --git a/target/linux/x86/patches-5.4/200-pcengines-apu2-reboot.patch b/target/linux/x86/patches-5.4/200-pcengines-apu2-reboot.patch index bc57806c74..742b6d6ad5 100644 --- a/target/linux/x86/patches-5.4/200-pcengines-apu2-reboot.patch +++ b/target/linux/x86/patches-5.4/200-pcengines-apu2-reboot.patch @@ -1,6 +1,6 @@ --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c -@@ -477,6 +477,16 @@ static const struct dmi_system_id reboot +@@ -486,6 +486,16 @@ static const struct dmi_system_id reboot }, }, From 1cd098784eeb0e3ba0d05cd3e71ebf1a106138e9 Mon Sep 17 00:00:00 2001 From: Kabuli Chana Date: Tue, 9 Mar 2021 19:19:12 -0700 Subject: [PATCH 18/32] kernel: bump 5.10 to 5.10.23 update kernel to 5.10.23, rebase patches, deleted upstreamed patch: target/linux/generic/backport-5.10/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch compile / test - mvebu / mamba, rango Signed-off-by: Kabuli Chana [refresh again] Signed-off-by: Adrian Schmutzler --- include/kernel-version.mk | 4 +- ..._nvram-rename-finding-function-and-i.patch | 11 +--- ..._nvram-add-helper-checking-for-NVRAM.patch | 9 +-- ...7xx_nvram-extract-code-copying-NVRAM.patch | 14 ++--- ..._nvram-look-for-NVRAM-with-for-inste.patch | 7 +-- ..._nvram-inline-code-checking-NVRAM-si.patch | 11 +--- ...usb-qmi_wwan-support-ZTE-P685M-modem.patch | 60 ------------------- .../hack-5.10/904-debloat_dma_buf.patch | 2 +- ...dd-support-for-threaded-NAPI-polling.patch | 2 +- .../810-uvc-add-iPassion-iP2970-support.patch | 2 +- 10 files changed, 18 insertions(+), 104 deletions(-) delete mode 100644 target/linux/generic/backport-5.10/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 7e326d60b6..72c2fdc9a3 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -7,10 +7,10 @@ ifdef CONFIG_TESTING_KERNEL endif LINUX_VERSION-5.4 = .105 -LINUX_VERSION-5.10 = .20 +LINUX_VERSION-5.10 = .23 LINUX_KERNEL_HASH-5.4.105 = 244e4cd16184285df55ec5a9501daba011aa8b85c5527ee05eab4592e70fb8b6 -LINUX_KERNEL_HASH-5.10.20 = 9be37146feba42be05137cf900a7d9012990b5a1d5e59bc0c8da1f86952930a3 +LINUX_KERNEL_HASH-5.10.23 = f6e21c03ec6ff85b26d77c59fdab81e64707792a57593643307df192749edb6a remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch b/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch index 711ec28f52..19938704b7 100644 --- a/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch +++ b/target/linux/generic/backport-5.10/800-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch @@ -17,11 +17,9 @@ Signed-off-by: Thomas Bogendoerfer drivers/firmware/broadcom/bcm47xx_nvram.c | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) -diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c -index 835ece9c00f1..b04007adc79f 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c -@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem *end) +@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem return 0; } @@ -38,7 +36,7 @@ index 835ece9c00f1..b04007adc79f 100644 u32 size; if (nvram_len) { -@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __iomem *iobase, u32 lim) +@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __io } /* TODO: when nvram is on nand flash check for bad blocks first. */ @@ -71,7 +69,7 @@ index 835ece9c00f1..b04007adc79f 100644 if (header->magic == NVRAM_MAGIC) { size = NVRAM_SPACE; goto found; -@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base, u32 lim) +@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base if (!iobase) return -ENOMEM; @@ -80,6 +78,3 @@ index 835ece9c00f1..b04007adc79f 100644 iounmap(iobase); --- -2.26.2 - diff --git a/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch b/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch index beef1cf675..6ab072883d 100644 --- a/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch +++ b/target/linux/generic/backport-5.10/800-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch @@ -14,8 +14,6 @@ Signed-off-by: Thomas Bogendoerfer drivers/firmware/broadcom/bcm47xx_nvram.c | 30 ++++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) -diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c -index b04007adc79f..99f3ec180be6 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c @@ -34,14 +34,20 @@ static char nvram_buf[NVRAM_SPACE]; @@ -42,7 +40,7 @@ index b04007adc79f..99f3ec180be6 100644 return nvram_sizes[i]; } -@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(v { struct nvram_header __iomem *header; size_t flash_size; @@ -50,7 +48,7 @@ index b04007adc79f..99f3ec180be6 100644 u32 size; if (nvram_len) { -@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(v /* Windowed flash access */ size = find_nvram_size(flash_start + flash_size); if (size) { @@ -90,6 +88,3 @@ index b04007adc79f..99f3ec180be6 100644 if (nvram_len > size) { pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); nvram_len = size; --- -2.26.2 - diff --git a/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch b/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch index 67ec157f5e..a1351f1197 100644 --- a/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch +++ b/target/linux/generic/backport-5.10/800-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch @@ -15,15 +15,12 @@ Signed-off-by: Thomas Bogendoerfer drivers/firmware/broadcom/bcm47xx_nvram.c | 43 +++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) -diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c -index 99f3ec180be6..09f51b95849e 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c -@@ -54,12 +54,35 @@ static u32 find_nvram_size(void __iomem *end) - return 0; +@@ -55,11 +55,34 @@ static u32 find_nvram_size(void __iomem } -+/** + /** + * bcm47xx_nvram_copy - copy NVRAM to internal buffer + */ +static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size) @@ -47,7 +44,7 @@ index 99f3ec180be6..09f51b95849e 100644 + nvram_len = copy_size; +} + - /** ++/** * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it */ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) @@ -56,7 +53,7 @@ index 99f3ec180be6..09f51b95849e 100644 size_t flash_size; size_t offset; u32 size; -@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(v return -ENXIO; found: @@ -81,6 +78,3 @@ index 99f3ec180be6..09f51b95849e 100644 return 0; } --- -2.26.2 - diff --git a/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch b/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch index 0dadc601a9..059a13220b 100644 --- a/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch +++ b/target/linux/generic/backport-5.10/800-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch @@ -16,11 +16,9 @@ Signed-off-by: Thomas Bogendoerfer drivers/firmware/broadcom/bcm47xx_nvram.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) -diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c -index 09f51b95849e..1d2271b1e07a 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c -@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(v } /* TODO: when nvram is on nand flash check for bad blocks first. */ @@ -37,6 +35,3 @@ index 09f51b95849e..1d2271b1e07a 100644 } /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ --- -2.26.2 - diff --git a/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch b/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch index 065543184f..21d250049e 100644 --- a/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch +++ b/target/linux/generic/backport-5.10/800-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch @@ -19,11 +19,9 @@ Signed-off-by: Thomas Bogendoerfer drivers/firmware/broadcom/bcm47xx_nvram.c | 25 +++++++---------------- 1 file changed, 7 insertions(+), 18 deletions(-) -diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c -index 1d2271b1e07a..bd235833b687 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c -@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void __iomem *nvram) +@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; } @@ -42,7 +40,7 @@ index 1d2271b1e07a..bd235833b687 100644 /** * bcm47xx_nvram_copy - copy NVRAM to internal buffer */ -@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(v { size_t flash_size; size_t offset; @@ -51,7 +49,7 @@ index 1d2271b1e07a..bd235833b687 100644 if (nvram_len) { pr_warn("nvram already initialized\n"); -@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz +@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(v } /* TODO: when nvram is on nand flash check for bad blocks first. */ @@ -70,6 +68,3 @@ index 1d2271b1e07a..bd235833b687 100644 } } --- -2.26.2 - diff --git a/target/linux/generic/backport-5.10/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch b/target/linux/generic/backport-5.10/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch deleted file mode 100644 index af3b17cc91..0000000000 --- a/target/linux/generic/backport-5.10/830-v5.12-0001-net-usb-qmi_wwan-support-ZTE-P685M-modem.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 88eee9b7b42e69fb622ddb3ff6f37e8e4347f5b2 Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Tue, 23 Feb 2021 19:34:56 +0100 -Subject: net: usb: qmi_wwan: support ZTE P685M modem -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Now that interface 3 in "option" driver is no longer mapped, add device -ID matching it to qmi_wwan. - -The modem is used inside ZTE MF283+ router and carriers identify it as -such. -Interface mapping is: -0: QCDM, 1: AT (PCUI), 2: AT (Modem), 3: QMI, 4: ADB - -T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 -D: Ver= 2.01 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 -P: Vendor=19d2 ProdID=1275 Rev=f0.00 -S: Manufacturer=ZTE,Incorporated -S: Product=ZTE Technologies MSM -S: SerialNumber=P685M510ZTED0000CP&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&0 -C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA -I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option -E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option -E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option -E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan -E: Ad=87(I) Atr=03(Int.) MxPS= 8 Ivl=32ms -E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) -E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms - -Acked-by: Bjørn Mork -Signed-off-by: Lech Perczak -Link: https://lore.kernel.org/r/20210223183456.6377-1-lech.perczak@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/usb/qmi_wwan.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/usb/qmi_wwan.c -+++ b/drivers/net/usb/qmi_wwan.c -@@ -1258,6 +1258,7 @@ static const struct usb_device_id produc - {QMI_FIXED_INTF(0x19d2, 0x1255, 4)}, - {QMI_FIXED_INTF(0x19d2, 0x1256, 4)}, - {QMI_FIXED_INTF(0x19d2, 0x1270, 5)}, /* ZTE MF667 */ -+ {QMI_FIXED_INTF(0x19d2, 0x1275, 3)}, /* ZTE P685M */ - {QMI_FIXED_INTF(0x19d2, 0x1401, 2)}, - {QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */ - {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, diff --git a/target/linux/generic/hack-5.10/904-debloat_dma_buf.patch b/target/linux/generic/hack-5.10/904-debloat_dma_buf.patch index 3c5af9d666..2f5f685063 100644 --- a/target/linux/generic/hack-5.10/904-debloat_dma_buf.patch +++ b/target/linux/generic/hack-5.10/904-debloat_dma_buf.patch @@ -62,7 +62,7 @@ Signed-off-by: Felix Fietkau +MODULE_LICENSE("GPL"); --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -3054,6 +3054,7 @@ int wake_up_state(struct task_struct *p, +@@ -3051,6 +3051,7 @@ int wake_up_state(struct task_struct *p, { return try_to_wake_up(p, state, 0); } diff --git a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch index 626bac99f6..9b1bd6e976 100644 --- a/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch +++ b/target/linux/generic/pending-5.10/690-net-add-support-for-threaded-NAPI-polling.patch @@ -288,7 +288,7 @@ Signed-off-by: Felix Fietkau /* Some drivers may have called napi_schedule * prior to exhausting their budget. */ -@@ -11291,6 +11352,10 @@ static int __init net_dev_init(void) +@@ -11333,6 +11394,10 @@ static int __init net_dev_init(void) sd->backlog.weight = weight_p; } diff --git a/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch index 410f369f70..e0703db1bc 100644 --- a/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch +++ b/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch @@ -13,7 +13,7 @@ Signed-off-by: John Crispin --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c -@@ -2969,6 +2969,18 @@ static const struct usb_device_id uvc_id +@@ -2972,6 +2972,18 @@ static const struct usb_device_id uvc_id .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, From 8a35ebe375d1c27e55dd2cb8c14f25440bc48821 Mon Sep 17 00:00:00 2001 From: Alin Nastac Date: Tue, 23 Feb 2021 13:05:09 +0100 Subject: [PATCH 19/32] gre: use alternative way to check if kernel support is enabled When necessary support is built in kernel, gre protocol support is not enabled in netifd. Signed-off-by: Alin Nastac --- package/network/config/gre/Makefile | 2 +- package/network/config/gre/files/gre.sh | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/package/network/config/gre/Makefile b/package/network/config/gre/Makefile index b16dd72cde..c920abeb0d 100644 --- a/package/network/config/gre/Makefile +++ b/package/network/config/gre/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gre -PKG_RELEASE:=12 +PKG_RELEASE:=13 PKG_LICENSE:=GPL-2.0 include $(INCLUDE_DIR)/package.mk diff --git a/package/network/config/gre/files/gre.sh b/package/network/config/gre/files/gre.sh index eb3df5b48c..b57d5d4cdb 100755 --- a/package/network/config/gre/files/gre.sh +++ b/package/network/config/gre/files/gre.sh @@ -291,8 +291,6 @@ proto_grev6tap_init_config() { } [ -n "$INCLUDE_ONLY" ] || { - [ -f /lib/modules/$(uname -r)/gre.ko ] && add_protocol gre - [ -f /lib/modules/$(uname -r)/gre.ko ] && add_protocol gretap - [ -f /lib/modules/$(uname -r)/ip6_gre.ko ] && add_protocol grev6 - [ -f /lib/modules/$(uname -r)/ip6_gre.ko ] && add_protocol grev6tap + [ -d /sys/module/ip_gre ] && { add_protocol gre; add_protocol gretap; } + [ -d /sys/module/ip6_gre ] && { add_protocol grev6; add_protocol grev6tap; } } From 65ca980b4872ee43157c6621896e84e817c9aeab Mon Sep 17 00:00:00 2001 From: Alin Nastac Date: Mon, 1 Mar 2021 09:49:43 +0100 Subject: [PATCH 20/32] vti: use alternative way to check if kernel support is enabled When necessary support is built in kernel, vti protocol support is not enabled in netifd. Signed-off-by: Alin Nastac --- package/network/config/vti/Makefile | 2 +- package/network/config/vti/files/vti.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/config/vti/Makefile b/package/network/config/vti/Makefile index ffac77ab91..292ab111e5 100644 --- a/package/network/config/vti/Makefile +++ b/package/network/config/vti/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=vti -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_LICENSE:=GPL-2.0 include $(INCLUDE_DIR)/package.mk diff --git a/package/network/config/vti/files/vti.sh b/package/network/config/vti/files/vti.sh index ebfd9d41e1..96b65e76d9 100755 --- a/package/network/config/vti/files/vti.sh +++ b/package/network/config/vti/files/vti.sh @@ -149,6 +149,6 @@ proto_vti6_init_config() { } [ -n "$INCLUDE_ONLY" ] || { - [ -f /lib/modules/$(uname -r)/ip_vti.ko ] && add_protocol vti - [ -f /lib/modules/$(uname -r)/ip6_vti.ko ] && add_protocol vti6 + [ -d /sys/module/ip_vti ] && add_protocol vti + [ -d /sys/module/ip6_vti ] && add_protocol vti6 } From 8704d138df5e7a30fb084a5450b07460d128a15a Mon Sep 17 00:00:00 2001 From: Alin Nastac Date: Mon, 1 Mar 2021 09:51:31 +0100 Subject: [PATCH 21/32] xfrm: simplify the check for necessary kernel support [ -d /sys/module/xfrm_interface ] is enough to check if CONFIG_XFRM_INTERFACE support was enabled in kernel. Signed-off-by: Alin Nastac --- package/network/config/xfrm/Makefile | 2 +- package/network/config/xfrm/files/xfrm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/network/config/xfrm/Makefile b/package/network/config/xfrm/Makefile index bcee89f82c..777f20c77c 100644 --- a/package/network/config/xfrm/Makefile +++ b/package/network/config/xfrm/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=xfrm -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_LICENSE:=GPL-2.0 include $(INCLUDE_DIR)/package.mk diff --git a/package/network/config/xfrm/files/xfrm.sh b/package/network/config/xfrm/files/xfrm.sh index ca7c3380e6..bdebd4b9c3 100755 --- a/package/network/config/xfrm/files/xfrm.sh +++ b/package/network/config/xfrm/files/xfrm.sh @@ -68,5 +68,5 @@ proto_xfrm_init_config() { [ -n "$INCLUDE_ONLY" ] || { - [ -f /lib/modules/$(uname -r)/xfrm_interface.ko -o -d /sys/module/xfrm_interface ] && add_protocol xfrm + [ -d /sys/module/xfrm_interface ] && add_protocol xfrm } From b0235c0d8de476c178a30dee1aa5e35db8bb4063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Cabanelas?= Date: Sat, 13 Mar 2021 12:57:46 +0100 Subject: [PATCH 22/32] mvebu: LS421DE: make cosmetics changes in dts file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make some cosmetic changes in the Buffalo LinkStation LS421DE NAS: - Delete pointless #xxx-cells - bootargs: replace earlyprintk with earlycon and remove unneeded args. - Separate pinmux nodes with empty lines. Signed-off-by: Daniel González Cabanelas --- .../arm/boot/dts/armada-370-buffalo-ls421de.dts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/target/linux/mvebu/files/arch/arm/boot/dts/armada-370-buffalo-ls421de.dts b/target/linux/mvebu/files/arch/arm/boot/dts/armada-370-buffalo-ls421de.dts index 57f1acf5f1..4e176554c6 100644 --- a/target/linux/mvebu/files/arch/arm/boot/dts/armada-370-buffalo-ls421de.dts +++ b/target/linux/mvebu/files/arch/arm/boot/dts/armada-370-buffalo-ls421de.dts @@ -25,7 +25,7 @@ }; chosen { - bootargs = "console=ttyS0,115200 earlyprintk noinitrd rootfstype=squashfs"; + bootargs = "earlycon"; stdout-path = "serial0:115200n8"; append-rootblock = "nullparameter="; /* override the bootloader args */ }; @@ -127,8 +127,6 @@ gpio_keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; pinctrl-0 = <&pmx_buttons>; pinctrl-names = "default"; @@ -361,8 +359,6 @@ pinctrl-names = "default"; spi-flash@0 { - #address-cells = <1>; - #size-cells = <1>; compatible = "mxicy,mx25l8005", "jedec,spi-nor"; reg = <0>; /* Chip select 0 */ spi-max-frequency = <50000000>; @@ -390,42 +386,52 @@ marvell,pins = "mpp4"; marvell,function = "vdd"; }; + pmx_power_usb: pmx-power-usb { marvell,pins = "mpp5"; marvell,function = "gpo"; }; + pmx_power_hdd1: pmx-power-hdd1 { marvell,pins = "mpp8"; marvell,function = "gpio"; }; + pmx_power_hdd2: pmx-power-hdd2 { marvell,pins = "mpp9"; marvell,function = "gpo"; }; + pmx_fan_lock: pmx-fan-lock { marvell,pins = "mpp10"; marvell,function = "gpio"; }; + pmx_hdd_present: pmx-hdd-present { marvell,pins = "mpp11", "mpp12"; marvell,function = "gpio"; }; + pmx_fan_high: pmx-fan-high { marvell,pins = "mpp13"; marvell,function = "gpio"; }; + pmx_fan_low: pmx-fan-low { marvell,pins = "mpp14"; marvell,function = "gpio"; }; + pmx_buttons: pmx-buttons { marvell,pins = "mpp15", "mpp16"; marvell,function = "gpio"; }; + pmx_leds1: pmx-leds { marvell,pins = "mpp7", "mpp54", "mpp59", "mpp61"; marvell,function = "gpo"; }; + pmx_leds2: pmx-leds { marvell,pins = "mpp55", "mpp57", "mpp62"; marvell,function = "gpio"; From 79b6a4bd3cabf6ae711e1e8f82ce43f717696cf4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 13 Mar 2021 19:07:09 +0000 Subject: [PATCH 23/32] uboot-mediatek: import fix for AHCI and enable SATA Import patch form Frank Wunderlich to fix build of MediaTek AHCI SATA driver. Enable that driver on Bananapi BPi-R64. Signed-off-by: Daniel Golle --- ...iatek-fix-missing-dev_err-definition.patch | 24 +++++++++++++++++++ .../403-add-bananapi_bpi-r64_defconfigs.patch | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 package/boot/uboot-mediatek/patches/010-ahci-mediatek-fix-missing-dev_err-definition.patch diff --git a/package/boot/uboot-mediatek/patches/010-ahci-mediatek-fix-missing-dev_err-definition.patch b/package/boot/uboot-mediatek/patches/010-ahci-mediatek-fix-missing-dev_err-definition.patch new file mode 100644 index 0000000000..5e2b4aa39b --- /dev/null +++ b/package/boot/uboot-mediatek/patches/010-ahci-mediatek-fix-missing-dev_err-definition.patch @@ -0,0 +1,24 @@ +From 7089c413216f1c0e374d71187030fe41ae4b3071 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 3 Nov 2020 19:45:30 +0100 +Subject: [PATCH] ahci: mediatek: fix missing dev_err definition + +--- + drivers/ata/mtk_ahci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/ata/mtk_ahci.c b/drivers/ata/mtk_ahci.c +index 554175bc00..2c5227df30 100644 +--- a/drivers/ata/mtk_ahci.c ++++ b/drivers/ata/mtk_ahci.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #define SYS_CFG 0x14 + #define SYS_CFG_SATA_MSK GENMASK(31, 30) +-- +2.30.2 + diff --git a/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch index 5a7101a7fe..9d52cc4feb 100644 --- a/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch +++ b/package/boot/uboot-mediatek/patches/403-add-bananapi_bpi-r64_defconfigs.patch @@ -111,7 +111,7 @@ +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_PHY_FIXED=y -+# CONFIG_MTK_AHCI is not set ++CONFIG_MTK_AHCI=y +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y +CONFIG_PCI=y @@ -315,7 +315,7 @@ +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_PHY_FIXED=y -+# CONFIG_MTK_AHCI is not set ++CONFIG_MTK_AHCI=y +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y +CONFIG_PCI=y From c1f3c52564fdec85394e7c338f56df0943ce8b10 Mon Sep 17 00:00:00 2001 From: Hannu Nyman Date: Tue, 9 Mar 2021 17:46:52 +0200 Subject: [PATCH 24/32] busybox: backport fixes for 1.33.0 Backport two fixes for 1.33.0 * history file storing * traceroute command option parsing Signed-off-by: Hannu Nyman --- package/utils/busybox/Makefile | 2 +- ...backport1330fix-ash-make-strdup-copy.patch | 40 +++++++++++++++++++ .../002-backport1330fix-traceroute.patch | 26 ++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 package/utils/busybox/patches/001-backport1330fix-ash-make-strdup-copy.patch create mode 100644 package/utils/busybox/patches/002-backport1330fix-traceroute.patch diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index 3fef000c62..9df358ef78 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=busybox PKG_VERSION:=1.33.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_FLAGS:=essential PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 diff --git a/package/utils/busybox/patches/001-backport1330fix-ash-make-strdup-copy.patch b/package/utils/busybox/patches/001-backport1330fix-ash-make-strdup-copy.patch new file mode 100644 index 0000000000..b495227d9f --- /dev/null +++ b/package/utils/busybox/patches/001-backport1330fix-ash-make-strdup-copy.patch @@ -0,0 +1,40 @@ +From 67cc582d4289c5de521d11b08307c8ab26ee1e28 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko +Date: Sun, 3 Jan 2021 10:55:39 +0100 +Subject: ash: make a strdup copy of $HISTFILE for line editing + +Otherwise if $HISTFILE is unset or reassigned, bad things can happen. + +function old new delta +ash_main 1210 1218 +8 + +Signed-off-by: Denys Vlasenko +--- + shell/ash.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/shell/ash.c b/shell/ash.c +index f16d7fb6a..ecbfbf091 100644 +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -14499,7 +14499,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) + + if (sflag || minusc == NULL) { + #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY +- if (iflag) { ++ if (line_input_state) { + const char *hp = lookupvar("HISTFILE"); + if (!hp) { + hp = lookupvar("HOME"); +@@ -14513,7 +14513,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) + } + } + if (hp) +- line_input_state->hist_file = hp; ++ line_input_state->hist_file = xstrdup(hp); + # if ENABLE_FEATURE_SH_HISTFILESIZE + hp = lookupvar("HISTFILESIZE"); + line_input_state->max_history = size_from_HISTFILESIZE(hp); +-- +cgit v1.2.1 + diff --git a/package/utils/busybox/patches/002-backport1330fix-traceroute.patch b/package/utils/busybox/patches/002-backport1330fix-traceroute.patch new file mode 100644 index 0000000000..eb03094eee --- /dev/null +++ b/package/utils/busybox/patches/002-backport1330fix-traceroute.patch @@ -0,0 +1,26 @@ +From 89358a7131d3e75c74af834bb117b4fad7914983 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko +Date: Tue, 2 Feb 2021 13:48:21 +0100 +Subject: traceroute: fix option parsing + +Signed-off-by: Denys Vlasenko +--- + networking/traceroute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/networking/traceroute.c b/networking/traceroute.c +index 3f1a9ab46..29f5e480b 100644 +--- a/networking/traceroute.c ++++ b/networking/traceroute.c +@@ -896,7 +896,7 @@ traceroute_init(int op, char **argv) + + op |= getopt32(argv, "^" + OPT_STRING +- "\0" "-1:x-x" /* minimum 1 arg */ ++ "\0" "-1" /* minimum 1 arg */ + , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str + , &source, &waittime_str, &pausemsecs_str, &first_ttl_str + ); +-- +cgit v1.2.1 + From 29e2be69c4689f3438340f23a6eb5649516f0c6d Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Tue, 26 Jan 2021 14:37:04 -0800 Subject: [PATCH 25/32] elfutils: remove host build from target package Commit f4da28c301 ("elfutils: Add host build") supplied a libelf host library to fix a glib2 host build error, but this need was later removed by b6212c8769 ("glib2: don't use libelf during host build"). More importantly, there are already two sources for libelf host libraries: OpenWRT build prerequisites [1] and tools/libelf. A third is not needed. Ref [1]: https://openwrt.org/docs/guide-developer/build-system/install-buildsystem#prerequisites Signed-off-by: Tony Ambardar --- package/libs/elfutils/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/package/libs/elfutils/Makefile b/package/libs/elfutils/Makefile index aa6743e688..dd0b8ecdde 100644 --- a/package/libs/elfutils/Makefile +++ b/package/libs/elfutils/Makefile @@ -25,7 +25,6 @@ PKG_USE_MIPS16:=0 PKG_BUILD_DEPENDS:=!USE_GLIBC:argp-standalone include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/nls.mk define Package/elfutils/Default @@ -99,4 +98,3 @@ endef $(eval $(call BuildPackage,libelf)) $(eval $(call BuildPackage,libdw)) $(eval $(call BuildPackage,libasm)) -$(eval $(call HostBuild)) From bf4aa0c6a2f57951f995b2ac6f394c45ac852b9d Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Thu, 11 Mar 2021 17:45:05 -0800 Subject: [PATCH 26/32] tools/libelf: remove unneeded host library This old ELF library dating to 2009 used to be necessary on MacOS but is not required for building the kernel or tools since [1]. On Linux systems, libelf is already an OpenWRT build-system prerequisite [2]. Presence of the older library can mask or conflict with the system libelf and lead to build errors, as seen compiling Linux kernels since v5.8 or host tools such as dwarves (e.g. pahole). Remove the unnecessary tools/libelf library and avoid the related issues. [1] 5f8e587240 ("build: force disable stack validation during kernel build on non-linux systems") [2] https://openwrt.org/docs/guide-developer/build-system/install-buildsystem#prerequisites Tested-by: Rosen Penev (Linux) Tested-by: Georgi Valkov (MacOS) Signed-off-by: Tony Ambardar --- tools/Makefile | 3 +- tools/libelf/Makefile | 58 ----- .../900-fix-undefined-macro-access.patch | 198 ------------------ 3 files changed, 1 insertion(+), 258 deletions(-) delete mode 100644 tools/libelf/Makefile delete mode 100644 tools/libelf/patches/900-fix-undefined-macro-access.patch diff --git a/tools/Makefile b/tools/Makefile index 1d7da0756d..8752a3e2b5 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -28,7 +28,7 @@ tools-y += mklibs mm-macros mtd-utils mtools padjffs2 patch-image tools-y += patchelf pkgconf quilt squashfskit4 sstrip xxd zip zlib zstd tools-$(BUILD_B43_TOOLS) += b43-tools tools-$(BUILD_ISL) += isl -tools-$(BUILD_TOOLCHAIN) += expat gmp libelf mpc mpfr +tools-$(BUILD_TOOLCHAIN) += expat gmp mpc mpfr tools-$(CONFIG_TARGET_apm821xx)$(CONFIG_TARGET_gemini) += genext2fs tools-$(CONFIG_TARGET_ath79) += lzma-old squashfs tools-$(CONFIG_TARGET_mxs) += elftosb sdimage @@ -53,7 +53,6 @@ $(curdir)/flex/compile := $(curdir)/libtool/compile $(curdir)/gengetopt/compile := $(curdir)/libtool/compile $(curdir)/gmp/compile := $(curdir)/libtool/compile $(curdir)/isl/compile := $(curdir)/gmp/compile -$(curdir)/libelf/compile := $(curdir)/libtool/compile $(curdir)/libressl/compile := $(curdir)/pkgconf/compile $(curdir)/libtool/compile := $(curdir)/m4/compile $(curdir)/autoconf/compile $(curdir)/automake/compile $(curdir)/missing-macros/compile $(curdir)/lzma-old/compile := $(curdir)/zlib/compile diff --git a/tools/libelf/Makefile b/tools/libelf/Makefile deleted file mode 100644 index 726c4776bf..0000000000 --- a/tools/libelf/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (C) 2010 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=libelf -PKG_VERSION:=0.8.13 -PKG_HASH:=591a9b4ec81c1f2042a97aa60564e0cb79d041c52faa7416acb38bc95bd2c76d -PKG_RELEASE:=1 - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:= \ - http://distfiles.gentoo.org/distfiles/ \ - http://distcache.freebsd.org/ports-distfiles/ -HOST_BUILD_PARALLEL:=1 - -HOST_FIXUP:=autoreconf - -include $(INCLUDE_DIR)/host-build.mk - -PKG_REMOVE_FILES := - -HOST_CONFIGURE_ARGS += \ - --disable-shared \ - --enable-elf64 - -define Host/Configure - (cd $(HOST_BUILD_DIR)/$(3); \ - $(HOST_CONFIGURE_CMD) \ - $(HOST_CONFIGURE_ARGS); \ - ) -endef - - -define Host/Compile - +$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR)/lib/ libelf.a -endef - -define Host/Install - $(INSTALL_DIR) $(STAGING_DIR_HOST)/{lib/pkgconfig,include/libelf} - $(CP) $(HOST_BUILD_DIR)/lib/{elf_repl.h,gelf.h,libelf.h,nlist.h,sys_elf.h} \ - $(STAGING_DIR_HOST)/include/libelf/ - $(CP) $(HOST_BUILD_DIR)/lib/libelf.a $(STAGING_DIR_HOST)/lib/ - $(CP) $(HOST_BUILD_DIR)/libelf.pc $(STAGING_DIR_HOST)/lib/pkgconfig/ -endef - -define Host/Clean - rm -rf $(STAGING_DIR_HOST)/include/libelf - rm -f $(STAGING_DIR_HOST)/lib/libelf.a - rm -f $(STAGING_DIR_HOST)/lib/pkgconfig/libelf.pc - $(call Host/Clean/Default) -endef - -$(eval $(call HostBuild)) diff --git a/tools/libelf/patches/900-fix-undefined-macro-access.patch b/tools/libelf/patches/900-fix-undefined-macro-access.patch deleted file mode 100644 index 21e7d1ba8f..0000000000 --- a/tools/libelf/patches/900-fix-undefined-macro-access.patch +++ /dev/null @@ -1,198 +0,0 @@ ---- a/lib/elf_repl.h -+++ b/lib/elf_repl.h -@@ -45,7 +45,7 @@ typedef __libelf_u32_t Elf32_Word; - #define ELF32_FSZ_SWORD 4 - #define ELF32_FSZ_WORD 4 - --#if __LIBELF64 -+#if defined(__LIBELF64) - - typedef __libelf_u64_t Elf64_Addr; - typedef __libelf_u16_t Elf64_Half; -@@ -93,7 +93,7 @@ typedef struct { - Elf32_Half e_shstrndx; - } Elf32_Ehdr; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - unsigned char e_ident[EI_NIDENT]; - Elf64_Half e_type; -@@ -307,7 +307,7 @@ typedef struct { - Elf32_Word sh_entsize; - } Elf32_Shdr; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Word sh_name; - Elf64_Word sh_type; -@@ -434,7 +434,7 @@ typedef struct { - Elf32_Half st_shndx; - } Elf32_Sym; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Word st_name; - unsigned char st_info; -@@ -457,7 +457,7 @@ typedef struct { - #define ELF32_ST_TYPE(i) ((i)&0xf) - #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) - --#if __LIBELF64 -+#if defined(__LIBELF64) - #define ELF64_ST_BIND(i) ((i)>>4) - #define ELF64_ST_TYPE(i) ((i)&0xf) - #define ELF64_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) -@@ -495,7 +495,7 @@ typedef struct { - * Macros for manipulating st_other - */ - #define ELF32_ST_VISIBILITY(o) ((o)&0x3) --#if __LIBELF64 -+#if defined(__LIBELF64) - #define ELF64_ST_VISIBILITY(o) ((o)&0x3) - #endif /* __LIBELF64 */ - -@@ -521,7 +521,7 @@ typedef struct { - Elf32_Sword r_addend; - } Elf32_Rela; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Addr r_offset; - Elf64_Xword r_info; -@@ -541,7 +541,7 @@ typedef struct { - #define ELF32_R_TYPE(i) ((unsigned char)(i)) - #define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) - --#if __LIBELF64 -+#if defined(__LIBELF64) - #define ELF64_R_SYM(i) ((Elf64_Xword)(i)>>32) - #define ELF64_R_TYPE(i) ((i)&0xffffffffL) - #define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+((t)&0xffffffffL)) -@@ -556,7 +556,7 @@ typedef struct { - Elf32_Word n_type; /* descriptor type */ - } Elf32_Nhdr; - --#if __LIBELF64 -+#if defined(__LIBELF64) - /* Solaris and GNU use this layout. Be compatible. */ - /* XXX: Latest ELF specs say it's 64-bit!!! */ - typedef struct { -@@ -587,7 +587,7 @@ typedef struct { - Elf32_Word p_align; - } Elf32_Phdr; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Word p_type; - Elf64_Word p_flags; -@@ -654,7 +654,7 @@ typedef struct { - } d_un; - } Elf32_Dyn; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Sxword d_tag; - union { -@@ -798,7 +798,7 @@ typedef struct { - Elf32_Half si_flags; - } Elf32_Syminfo; - --#if __LIBELF64 -+#if defined(__LIBELF64) - typedef struct { - Elf64_Half si_boundto; - Elf64_Half si_flags; -@@ -863,7 +863,7 @@ typedef struct { - - typedef Elf32_Half Elf32_Versym; - --#if __LIBELF64 -+#if defined(__LIBELF64) - - typedef struct { - Elf64_Half vd_version; -@@ -933,7 +933,7 @@ typedef Elf64_Half Elf64_Versym; - /* - * Move section - */ --#if __LIBELF64 -+#if defined(__LIBELF64) - - typedef struct { - Elf32_Lword m_value; -@@ -973,7 +973,7 @@ typedef struct { - } c_un; - } Elf32_Cap; - --#if __LIBELF64 -+#if defined(__LIBELF64) - - typedef struct { - Elf64_Xword c_tag; ---- a/lib/gelf.h -+++ b/lib/gelf.h -@@ -22,15 +22,15 @@ - #ifndef _GELF_H - #define _GELF_H - --#if __LIBELF_INTERNAL__ -+#if defined(__LIBELF_INTERNAL__) - #include - #else /* __LIBELF_INTERNAL__ */ - #include - #endif /* __LIBELF_INTERNAL__ */ - --#if __LIBELF_NEED_LINK_H -+#if defined(__LIBELF_NEED_LINK_H) - #include --#elif __LIBELF_NEED_SYS_LINK_H -+#elif defined(__LIBELF_NEED_SYS_LINK_H) - #include - #endif /* __LIBELF_NEED_LINK_H */ - -@@ -71,7 +71,7 @@ typedef Elf64_Sym GElf_Sym; - /* - * Symbol versioning - */ --#if __LIBELF_SYMBOL_VERSIONS -+#if defined(__LIBELF_SYMBOL_VERSIONS) - typedef Elf64_Verdef GElf_Verdef; - typedef Elf64_Verneed GElf_Verneed; - typedef Elf64_Verdaux GElf_Verdaux; ---- a/lib/libelf.h -+++ b/lib/libelf.h -@@ -25,7 +25,7 @@ - #include /* for size_t */ - #include - --#if __LIBELF_INTERNAL__ -+#if defined(__LIBELF_INTERNAL__) - #include - #else /* __LIBELF_INTERNAL__ */ - #include -@@ -224,7 +224,7 @@ extern Elf_Data *elf32_xlatetom __P((Elf - */ - extern long elf32_checksum __P((Elf *__elf)); - --#if __LIBELF64 -+#if defined(__LIBELF64) - /* - * 64-bit ELF functions - * Not available on all platforms ---- a/lib/sys_elf.h.in -+++ b/lib/sys_elf.h.in -@@ -116,7 +116,7 @@ Foundation, Inc., 51 Franklin Street, Fi - # define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+((t)&0xffffffffL)) - # endif /* ELF64_R_SYM */ - --# if __LIBELF64_LINUX -+# if defined(__LIBELF64_LINUX) - typedef __libelf_u64_t Elf64_Addr; - typedef __libelf_u16_t Elf64_Half; - typedef __libelf_u64_t Elf64_Off; From 28dcb74de3a15fbdb0fd9afa16457b2de1181cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Mon, 1 Mar 2021 08:21:59 +0100 Subject: [PATCH 27/32] bmips: add experimental ethernet support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds experimental ethernet support for BCM6318, BCM6328, BCM6362, BCM6368 and BCM63268. BCM6358 needs a different driver, so there's no support for now. Working devices: - Comtrend AR-5315u - Comtrend AR-5387un - Comtrend VR-3025u - Comtrend VR-3032u Not working devices: - Netgear DGND3700 v2 (no idea on how the external switch is connected) - Huawei HG556a ver B (BCM6358 needs a separate driveer) Signed-off-by: Álvaro Fernández Rojas --- target/linux/bmips/Makefile | 2 +- target/linux/bmips/config-5.10 | 18 + .../bmips/dts/bcm63168-comtrend-vr-3032u.dts | 38 + .../bmips/dts/bcm6318-comtrend-ar-5315u.dts | 38 + target/linux/bmips/dts/bcm6318.dtsi | 98 ++ target/linux/bmips/dts/bcm63268.dtsi | 100 ++ .../bmips/dts/bcm6328-comtrend-ar-5387un.dts | 38 + target/linux/bmips/dts/bcm6328.dtsi | 94 ++ .../bmips/dts/bcm6362-netgear-dgnd3700-v2.dts | 6 + target/linux/bmips/dts/bcm6362.dtsi | 94 ++ .../bmips/dts/bcm6368-comtrend-vr-3025u.dts | 38 + target/linux/bmips/dts/bcm6368.dtsi | 93 ++ .../net/ethernet/broadcom/bcm6368-enetsw.c | 1116 +++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 17 + .../nand/base-files/etc/board.d/02_network | 15 + ...0-net-dsa-b53-relax-is63xx-condition.patch | 29 + ...dsa-b53-mmap-Add-device-tree-support.patch | 82 ++ ...b53-support-tags-for-legacy-switches.patch | 209 +++ ...add-BCM6368-enetsw-controller-driver.patch | 46 + ...-Add-BCM6368-MDIO-mux-bus-controller.patch | 231 ++++ 20 files changed, 2401 insertions(+), 1 deletion(-) create mode 100644 target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c create mode 100644 target/linux/bmips/generic/base-files/etc/board.d/02_network create mode 100644 target/linux/bmips/nand/base-files/etc/board.d/02_network create mode 100644 target/linux/bmips/patches-5.10/500-net-dsa-b53-relax-is63xx-condition.patch create mode 100644 target/linux/bmips/patches-5.10/501-net-dsa-b53-mmap-Add-device-tree-support.patch create mode 100644 target/linux/bmips/patches-5.10/502-net-dsa-b53-support-tags-for-legacy-switches.patch create mode 100644 target/linux/bmips/patches-5.10/503-net-broadcom-add-BCM6368-enetsw-controller-driver.patch create mode 100644 target/linux/bmips/patches-5.10/504-net-mdio-Add-BCM6368-MDIO-mux-bus-controller.patch diff --git a/target/linux/bmips/Makefile b/target/linux/bmips/Makefile index 0adc8cd97e..14eff38bb6 100644 --- a/target/linux/bmips/Makefile +++ b/target/linux/bmips/Makefile @@ -18,6 +18,6 @@ endef include $(INCLUDE_DIR)/target.mk -DEFAULT_PACKAGES += kmod-gpio-button-hotplug +DEFAULT_PACKAGES += ethtool kmod-gpio-button-hotplug $(eval $(call BuildTarget)) diff --git a/target/linux/bmips/config-5.10 b/target/linux/bmips/config-5.10 index 749cc0eb69..96a7547593 100644 --- a/target/linux/bmips/config-5.10 +++ b/target/linux/bmips/config-5.10 @@ -3,8 +3,15 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_MMAP_RND_BITS_MAX=15 CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15 CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_B53=y +# CONFIG_B53_MDIO_DRIVER is not set +CONFIG_B53_MMAP_DRIVER=y +# CONFIG_B53_SERDES is not set +CONFIG_B53_SPI_DRIVER=y +# CONFIG_B53_SRAB_DRIVER is not set CONFIG_BCM6345_EXT_IRQ=y CONFIG_BCM6345_L1_IRQ=y +CONFIG_BCM6368_ENETSW=y CONFIG_BCM63XX_POWER=y CONFIG_BCM7038_L1_IRQ=y CONFIG_BCM7038_WDT=y @@ -103,6 +110,7 @@ CONFIG_GPIOLIB=y # CONFIG_GPIO_BRCMSTB is not set CONFIG_GPIO_GENERIC=y CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GRO_CELLS=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y @@ -128,6 +136,8 @@ CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y CONFIG_MDIO_BUS=y +CONFIG_MDIO_BUS_MUX=y +CONFIG_MDIO_BUS_MUX_BCM6368=y CONFIG_MDIO_DEVICE=y CONFIG_MEMFD_CREATE=y CONFIG_MFD_SYSCON=y @@ -163,7 +173,14 @@ CONFIG_MTD_CFI_STAA=y CONFIG_MTD_JEDECPROBE=y # CONFIG_MTD_PARSER_IMAGETAG is not set CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_TAG_BRCM=y +CONFIG_NET_DSA_TAG_BRCM_COMMON=y +CONFIG_NET_DSA_TAG_BRCM_LEGACY=y +CONFIG_NET_DSA_TAG_BRCM_PREPEND=y CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_SWITCHDEV=y CONFIG_NO_EXCEPT_FILL=y CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y CONFIG_NR_CPUS=2 @@ -181,6 +198,7 @@ CONFIG_PCI_DRIVERS_LEGACY=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y +CONFIG_PHYLINK=y CONFIG_PHYSICAL_START=0x80010000 CONFIG_PHY_BCM63XX_USBH=y # CONFIG_PHY_BRCM_SATA is not set diff --git a/target/linux/bmips/dts/bcm63168-comtrend-vr-3032u.dts b/target/linux/bmips/dts/bcm63168-comtrend-vr-3032u.dts index ed7f51890c..d82247d26c 100644 --- a/target/linux/bmips/dts/bcm63168-comtrend-vr-3032u.dts +++ b/target/linux/bmips/dts/bcm63168-comtrend-vr-3032u.dts @@ -39,6 +39,12 @@ status = "okay"; }; +ðernet { + status = "okay"; + + mtd-mac-address = <&cferom 0x6a0>; +}; + &leds { status = "okay"; @@ -177,6 +183,38 @@ status = "okay"; }; +&switch0 { + ports { + port@0 { + reg = <0>; + label = "lan2"; + + phy-handle = <&phy1>; + }; + + port@1 { + reg = <1>; + label = "lan3"; + + phy-handle = <&phy2>; + }; + + port@2 { + reg = <2>; + label = "lan4"; + + phy-handle = <&phy3>; + }; + + port@3 { + reg = <3>; + label = "lan1"; + + phy-handle = <&phy4>; + }; + }; +}; + &uart0 { status = "okay"; }; diff --git a/target/linux/bmips/dts/bcm6318-comtrend-ar-5315u.dts b/target/linux/bmips/dts/bcm6318-comtrend-ar-5315u.dts index 35c74fd3ac..a5ae435a3a 100644 --- a/target/linux/bmips/dts/bcm6318-comtrend-ar-5315u.dts +++ b/target/linux/bmips/dts/bcm6318-comtrend-ar-5315u.dts @@ -37,6 +37,12 @@ status = "okay"; }; +ðernet { + status = "okay"; + + mtd-mac-address = <&cfe 0x6a0>; +}; + &hsspi { status = "okay"; @@ -168,6 +174,38 @@ }; }; +&switch0 { + ports { + port@0 { + reg = <0>; + label = "lan4"; + + phy-handle = <&phy1>; + }; + + port@1 { + reg = <1>; + label = "lan3"; + + phy-handle = <&phy2>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + + phy-handle = <&phy3>; + }; + + port@3 { + reg = <3>; + label = "lan1"; + + phy-handle = <&phy4>; + }; + }; +}; + &uart0 { status = "okay"; }; diff --git a/target/linux/bmips/dts/bcm6318.dtsi b/target/linux/bmips/dts/bcm6318.dtsi index f5cfd77438..e7dc38e937 100644 --- a/target/linux/bmips/dts/bcm6318.dtsi +++ b/target/linux/bmips/dts/bcm6318.dtsi @@ -346,5 +346,103 @@ status = "disabled"; }; + + switch0: switch@10080000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-switch"; + reg = <0x10080000 0x8000>; + big-endian; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@8 { + reg = <8>; + label = "cpu"; + + phy-mode = "internal"; + ethernet = <ðernet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + mdio: mdio@100800b0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6368-mdio-mux"; + reg = <0x100800b0 0x8>; + + mdio_int: mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + }; + + phy4: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; + + mdio_ext: mdio@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; + + ethernet: ethernet@10088000 { + compatible = "brcm,bcm6318-enetsw"; + reg = <0x10088000 0x80>, + <0x10088200 0x80>, + <0x10088400 0x80>; + reg-names = "dma", + "dma-channels", + "dma-sram"; + + interrupt-parent = <&periph_intc>; + interrupts = , + ; + interrupt-names = "rx", + "tx"; + + clocks = <&periph_clk BCM6318_CLK_ROBOSW250>, + <&periph_clk BCM6318_CLK_ROBOSW025>, + <&ubus_clk BCM6318_UCLK_ROBOSW>; + + resets = <&periph_rst BCM6318_RST_ENETSW>, + <&periph_rst BCM6318_RST_EPHY>; + + power-domains = <&periph_pwr BCM6318_POWER_DOMAIN_EPHY0>, + <&periph_pwr BCM6318_POWER_DOMAIN_EPHY1>, + <&periph_pwr BCM6318_POWER_DOMAIN_EPHY2>, + <&periph_pwr BCM6318_POWER_DOMAIN_EPHY3>; + + dma-rx = <0>; + dma-tx = <1>; + + status = "disabled"; + }; }; }; diff --git a/target/linux/bmips/dts/bcm63268.dtsi b/target/linux/bmips/dts/bcm63268.dtsi index bf9998a552..284d2c8ef0 100644 --- a/target/linux/bmips/dts/bcm63268.dtsi +++ b/target/linux/bmips/dts/bcm63268.dtsi @@ -432,5 +432,105 @@ status = "disabled"; }; + + ethernet: ethernet@1000d800 { + compatible = "brcm,bcm63268-enetsw"; + reg = <0x1000d800 0x80>, + <0x1000da00 0x80>, + <0x1000dc00 0x80>; + reg-names = "dma", + "dma-channels", + "dma-sram"; + + interrupt-parent = <&periph_intc>; + interrupts = , + ; + interrupt-names = "rx", + "tx"; + + clocks = <&periph_clk BCM63268_CLK_GMAC>, + <&periph_clk BCM63268_CLK_ROBOSW>, + <&periph_clk BCM63268_CLK_ROBOSW250>, + <&timer_clk BCM63268_TCLK_EPHY1>, + <&timer_clk BCM63268_TCLK_EPHY2>, + <&timer_clk BCM63268_TCLK_EPHY3>, + <&timer_clk BCM63268_TCLK_GPHY1>; + + resets = <&periph_rst BCM63268_RST_ENETSW>, + <&periph_rst BCM63268_RST_EPHY>, + <&periph_rst BCM63268_RST_GPHY>; + + power-domains = <&periph_pwr BCM63268_POWER_DOMAIN_ROBOSW>; + + dma-rx = <0>; + dma-tx = <1>; + + status = "disabled"; + }; + + switch0: switch@10700000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-switch"; + reg = <0x10700000 0x8000>; + big-endian; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@8 { + reg = <8>; + label = "cpu"; + + phy-mode = "internal"; + ethernet = <ðernet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + mdio: mdio@107000b0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6368-mdio-mux"; + reg = <0x107000b0 0x8>; + + mdio_int: mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + }; + + phy4: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; + + mdio_ext: mdio@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; }; }; diff --git a/target/linux/bmips/dts/bcm6328-comtrend-ar-5387un.dts b/target/linux/bmips/dts/bcm6328-comtrend-ar-5387un.dts index a3192dffa4..9ebd6c5c4d 100644 --- a/target/linux/bmips/dts/bcm6328-comtrend-ar-5387un.dts +++ b/target/linux/bmips/dts/bcm6328-comtrend-ar-5387un.dts @@ -30,6 +30,12 @@ status = "okay"; }; +ðernet { + status = "okay"; + + mtd-mac-address = <&cfe 0x6a0>; +}; + &hsspi { status = "okay"; @@ -113,6 +119,38 @@ }; }; +&switch0 { + ports { + port@0 { + reg = <0>; + label = "lan1"; + + phy-handle = <&phy1>; + }; + + port@1 { + reg = <1>; + label = "lan2"; + + phy-handle = <&phy2>; + }; + + port@2 { + reg = <2>; + label = "lan3"; + + phy-handle = <&phy3>; + }; + + port@3 { + reg = <3>; + label = "lan4"; + + phy-handle = <&phy4>; + }; + }; +}; + &uart0 { status = "okay"; }; diff --git a/target/linux/bmips/dts/bcm6328.dtsi b/target/linux/bmips/dts/bcm6328.dtsi index aa90cc2a9b..64fd04142c 100644 --- a/target/linux/bmips/dts/bcm6328.dtsi +++ b/target/linux/bmips/dts/bcm6328.dtsi @@ -368,5 +368,99 @@ status = "disabled"; }; + + ethernet: ethernet@1000d800 { + compatible = "brcm,bcm6328-enetsw"; + reg = <0x1000d800 0x80>, + <0x1000da00 0x80>, + <0x1000dc00 0x80>; + reg-names = "dma", + "dma-channels", + "dma-sram"; + + interrupt-parent = <&periph_intc>; + interrupts = , + ; + interrupt-names = "rx", + "tx"; + + clocks = <&periph_clk BCM6328_CLK_ROBOSW>; + + resets = <&periph_rst BCM6328_RST_ENETSW>, + <&periph_rst BCM6328_RST_EPHY>; + + power-domains = <&periph_pwr BCM6328_POWER_DOMAIN_ROBOSW>, + <&periph_pwr BCM6328_POWER_DOMAIN_EPHY>; + + dma-rx = <0>; + dma-tx = <1>; + + status = "disabled"; + }; + + switch0: switch@10e00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-switch"; + reg = <0x10e00000 0x8000>; + big-endian; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@8 { + reg = <8>; + label = "cpu"; + + phy-mode = "internal"; + ethernet = <ðernet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + mdio: mdio@10e000b0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6368-mdio-mux"; + reg = <0x10e000b0 0x8>; + + mdio_int: mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + }; + + phy4: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; + + mdio_ext: mdio@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; }; }; diff --git a/target/linux/bmips/dts/bcm6362-netgear-dgnd3700-v2.dts b/target/linux/bmips/dts/bcm6362-netgear-dgnd3700-v2.dts index 4da673cafa..fe26ebeed0 100644 --- a/target/linux/bmips/dts/bcm6362-netgear-dgnd3700-v2.dts +++ b/target/linux/bmips/dts/bcm6362-netgear-dgnd3700-v2.dts @@ -62,6 +62,12 @@ status = "okay"; }; +ðernet { + status = "okay"; + + mtd-mac-address = <&cferom 0x6a0>; +}; + &leds { status = "okay"; diff --git a/target/linux/bmips/dts/bcm6362.dtsi b/target/linux/bmips/dts/bcm6362.dtsi index f46074045c..9a3d9c1f66 100644 --- a/target/linux/bmips/dts/bcm6362.dtsi +++ b/target/linux/bmips/dts/bcm6362.dtsi @@ -465,5 +465,99 @@ status = "disabled"; }; + + ethernet: ethernet@1000d800 { + compatible = "brcm,bcm6362-enetsw"; + reg = <0x1000d800 0x80>, + <0x1000da00 0x80>, + <0x1000dc00 0x80>; + reg-names = "dma", + "dma-channels", + "dma-sram"; + + interrupt-parent = <&periph_intc>; + interrupts = ; + interrupt-names = "rx"; + + clocks = <&periph_clk BCM6362_CLK_SWPKT_USB>, + <&periph_clk BCM6362_CLK_SWPKT_SAR>, + <&periph_clk BCM6362_CLK_ROBOSW>; + + resets = <&periph_rst BCM6362_RST_ENETSW>, + <&periph_rst BCM6362_RST_EPHY>; + + power-domains = <&periph_pwr BCM6362_POWER_DOMAIN_ROBOSW>, + <&periph_pwr BCM6362_POWER_DOMAIN_GMII_PADS>; + + dma-rx = <0>; + dma-tx = <1>; + + status = "disabled"; + }; + + switch0: switch@10e00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-switch"; + reg = <0x10e00000 0x8000>; + big-endian; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@8 { + reg = <8>; + label = "cpu"; + + phy-mode = "internal"; + ethernet = <ðernet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + mdio: mdio@10e000b0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6368-mdio-mux"; + reg = <0x10e000b0 0x8>; + + mdio_int: mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + }; + + phy4: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; + + mdio_ext: mdio@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; }; }; diff --git a/target/linux/bmips/dts/bcm6368-comtrend-vr-3025u.dts b/target/linux/bmips/dts/bcm6368-comtrend-vr-3025u.dts index 683b01875e..b597a05f3a 100644 --- a/target/linux/bmips/dts/bcm6368-comtrend-vr-3025u.dts +++ b/target/linux/bmips/dts/bcm6368-comtrend-vr-3025u.dts @@ -59,6 +59,12 @@ status = "okay"; }; +ðernet { + status = "okay"; + + mtd-mac-address = <&cfe 0x6a0>; +}; + &ohci { status = "okay"; }; @@ -96,6 +102,38 @@ &pinctrl_ephy2_led &pinctrl_ephy3_led>; }; +&switch0 { + ports { + port@0 { + reg = <0>; + label = "lan1"; + + phy-handle = <&phy1>; + }; + + port@1 { + reg = <1>; + label = "lan2"; + + phy-handle = <&phy2>; + }; + + port@2 { + reg = <2>; + label = "lan3"; + + phy-handle = <&phy3>; + }; + + port@3 { + reg = <3>; + label = "lan4"; + + phy-handle = <&phy4>; + }; + }; +}; + &uart0 { status = "okay"; }; diff --git a/target/linux/bmips/dts/bcm6368.dtsi b/target/linux/bmips/dts/bcm6368.dtsi index 5aa2b82221..5b5064b29e 100644 --- a/target/linux/bmips/dts/bcm6368.dtsi +++ b/target/linux/bmips/dts/bcm6368.dtsi @@ -467,6 +467,99 @@ resets = <&periph_rst BCM6368_RST_IPSEC>; }; + + ethernet: ethernet@10006800 { + compatible = "brcm,bcm6368-enetsw"; + reg = <0x10006800 0x80>, + <0x10006a00 0x80>, + <0x10006c00 0x80>; + reg-names = "dma", + "dma-channels", + "dma-sram"; + + interrupt-parent = <&periph_intc>; + interrupts = , + ; + interrupt-names = "rx", + "tx"; + + clocks = <&periph_clk BCM6368_CLK_SWPKT_USB>, + <&periph_clk BCM6368_CLK_SWPKT_SAR>, + <&periph_clk BCM6368_CLK_ROBOSW>; + + resets = <&periph_rst BCM6368_RST_SWITCH>, + <&periph_rst BCM6368_RST_EPHY>; + + dma-rx = <0>; + dma-tx = <1>; + + status = "disabled"; + }; + + switch0: switch@10f00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6328-switch"; + reg = <0x10f00000 0x8000>; + big-endian; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@8 { + reg = <8>; + label = "cpu"; + + phy-mode = "internal"; + ethernet = <ðernet>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + mdio: mdio@10f000b0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6368-mdio-mux"; + reg = <0x10f000b0 0x8>; + + mdio_int: mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + }; + + phy4: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; + + mdio_ext: mdio@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; }; pflash: nor@18000000 { diff --git a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c new file mode 100644 index 0000000000..dc55e3ccb9 --- /dev/null +++ b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c @@ -0,0 +1,1116 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * BCM6368 Ethernet Switch Controller Driver + * + * Copyright (C) 2021 Álvaro Fernández Rojas + * Copyright (C) 2015 Jonas Gorski + * Copyright (C) 2008 Maxime Bizon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* MTU */ +#define ENETSW_TAG_SIZE 6 +#define ENETSW_MTU_OVERHEAD (VLAN_ETH_HLEN + VLAN_HLEN + \ + ENETSW_TAG_SIZE) + +/* default number of descriptor */ +#define ENETSW_DEF_RX_DESC 64 +#define ENETSW_DEF_TX_DESC 32 +#define ENETSW_DEF_CPY_BREAK 128 + +/* maximum burst len for dma (4 bytes unit) */ +#define ENETSW_DMA_MAXBURST 8 + +/* DMA channels */ +#define DMA_CHAN_WIDTH 0x10 + +/* Controller Configuration Register */ +#define DMA_CFG_REG (0x0) +#define DMA_CFG_EN_SHIFT 0 +#define DMA_CFG_EN_MASK (1 << DMA_CFG_EN_SHIFT) +#define DMA_CFG_FLOWCH_MASK(x) (1 << ((x >> 1) + 1)) + +/* Flow Control Descriptor Low Threshold register */ +#define DMA_FLOWCL_REG(x) (0x4 + (x) * 6) + +/* Flow Control Descriptor High Threshold register */ +#define DMA_FLOWCH_REG(x) (0x8 + (x) * 6) + +/* Flow Control Descriptor Buffer Alloca Threshold register */ +#define DMA_BUFALLOC_REG(x) (0xc + (x) * 6) +#define DMA_BUFALLOC_FORCE_SHIFT 31 +#define DMA_BUFALLOC_FORCE_MASK (1 << DMA_BUFALLOC_FORCE_SHIFT) + +/* Channel Configuration register */ +#define DMAC_CHANCFG_REG (0x0) +#define DMAC_CHANCFG_EN_SHIFT 0 +#define DMAC_CHANCFG_EN_MASK (1 << DMAC_CHANCFG_EN_SHIFT) +#define DMAC_CHANCFG_PKTHALT_SHIFT 1 +#define DMAC_CHANCFG_PKTHALT_MASK (1 << DMAC_CHANCFG_PKTHALT_SHIFT) +#define DMAC_CHANCFG_BUFHALT_SHIFT 2 +#define DMAC_CHANCFG_BUFHALT_MASK (1 << DMAC_CHANCFG_BUFHALT_SHIFT) +#define DMAC_CHANCFG_CHAINING_SHIFT 2 +#define DMAC_CHANCFG_CHAINING_MASK (1 << DMAC_CHANCFG_CHAINING_SHIFT) +#define DMAC_CHANCFG_WRAP_EN_SHIFT 3 +#define DMAC_CHANCFG_WRAP_EN_MASK (1 << DMAC_CHANCFG_WRAP_EN_SHIFT) +#define DMAC_CHANCFG_FLOWC_EN_SHIFT 4 +#define DMAC_CHANCFG_FLOWC_EN_MASK (1 << DMAC_CHANCFG_FLOWC_EN_SHIFT) + +/* Interrupt Control/Status register */ +#define DMAC_IR_REG (0x4) +#define DMAC_IR_BUFDONE_MASK (1 << 0) +#define DMAC_IR_PKTDONE_MASK (1 << 1) +#define DMAC_IR_NOTOWNER_MASK (1 << 2) + +/* Interrupt Mask register */ +#define DMAC_IRMASK_REG (0x8) + +/* Maximum Burst Length */ +#define DMAC_MAXBURST_REG (0xc) + +/* Ring Start Address register */ +#define DMAS_RSTART_REG (0x0) + +/* State Ram Word 2 */ +#define DMAS_SRAM2_REG (0x4) + +/* State Ram Word 3 */ +#define DMAS_SRAM3_REG (0x8) + +/* State Ram Word 4 */ +#define DMAS_SRAM4_REG (0xc) + +struct bcm6368_enetsw_desc { + u32 len_stat; + u32 address; +}; + +/* control */ +#define DMADESC_LENGTH_SHIFT 16 +#define DMADESC_LENGTH_MASK (0xfff << DMADESC_LENGTH_SHIFT) +#define DMADESC_OWNER_MASK (1 << 15) +#define DMADESC_EOP_MASK (1 << 14) +#define DMADESC_SOP_MASK (1 << 13) +#define DMADESC_ESOP_MASK (DMADESC_EOP_MASK | DMADESC_SOP_MASK) +#define DMADESC_WRAP_MASK (1 << 12) +#define DMADESC_USB_NOZERO_MASK (1 << 1) +#define DMADESC_USB_ZERO_MASK (1 << 0) + +/* status */ +#define DMADESC_UNDER_MASK (1 << 9) +#define DMADESC_APPEND_CRC (1 << 8) +#define DMADESC_OVSIZE_MASK (1 << 4) +#define DMADESC_RXER_MASK (1 << 2) +#define DMADESC_CRC_MASK (1 << 1) +#define DMADESC_OV_MASK (1 << 0) +#define DMADESC_ERR_MASK (DMADESC_UNDER_MASK | \ + DMADESC_OVSIZE_MASK | \ + DMADESC_RXER_MASK | \ + DMADESC_CRC_MASK | \ + DMADESC_OV_MASK) + +struct bcm6368_enetsw { + void __iomem *dma_base; + void __iomem *dma_chan; + void __iomem *dma_sram; + + struct device **pm; + struct device_link **link_pm; + int num_pms; + + struct clk **clock; + unsigned int num_clocks; + + struct reset_control **reset; + unsigned int num_resets; + + int copybreak; + + int irq_rx; + int irq_tx; + + /* hw view of rx & tx dma ring */ + dma_addr_t rx_desc_dma; + dma_addr_t tx_desc_dma; + + /* allocated size (in bytes) for rx & tx dma ring */ + unsigned int rx_desc_alloc_size; + unsigned int tx_desc_alloc_size; + + struct napi_struct napi; + + /* dma channel id for rx */ + int rx_chan; + + /* number of dma desc in rx ring */ + int rx_ring_size; + + /* cpu view of rx dma ring */ + struct bcm6368_enetsw_desc *rx_desc_cpu; + + /* current number of armed descriptor given to hardware for rx */ + int rx_desc_count; + + /* next rx descriptor to fetch from hardware */ + int rx_curr_desc; + + /* next dirty rx descriptor to refill */ + int rx_dirty_desc; + + /* size of allocated rx skbs */ + unsigned int rx_skb_size; + + /* list of skb given to hw for rx */ + struct sk_buff **rx_skb; + + /* used when rx skb allocation failed, so we defer rx queue + * refill */ + struct timer_list rx_timeout; + + /* lock rx_timeout against rx normal operation */ + spinlock_t rx_lock; + + /* dma channel id for tx */ + int tx_chan; + + /* number of dma desc in tx ring */ + int tx_ring_size; + + /* maximum dma burst size */ + int dma_maxburst; + + /* cpu view of rx dma ring */ + struct bcm6368_enetsw_desc *tx_desc_cpu; + + /* number of available descriptor for tx */ + int tx_desc_count; + + /* next tx descriptor avaiable */ + int tx_curr_desc; + + /* next dirty tx descriptor to reclaim */ + int tx_dirty_desc; + + /* list of skb given to hw for tx */ + struct sk_buff **tx_skb; + + /* lock used by tx reclaim and xmit */ + spinlock_t tx_lock; + + /* network device reference */ + struct net_device *net_dev; + + /* platform device reference */ + struct platform_device *pdev; + + /* dma channel enable mask */ + u32 dma_chan_en_mask; + + /* dma channel interrupt mask */ + u32 dma_chan_int_mask; + + /* dma channel width */ + unsigned int dma_chan_width; + + /* dma descriptor shift value */ + unsigned int dma_desc_shift; +}; + +static inline void dma_writel(struct bcm6368_enetsw *priv, u32 val, u32 off) +{ + __raw_writel(val, priv->dma_base + off); +} + +static inline u32 dma_readl(struct bcm6368_enetsw *priv, u32 off, int chan) +{ + return __raw_readl(priv->dma_chan + off + chan * priv->dma_chan_width); +} + +static inline void dmac_writel(struct bcm6368_enetsw *priv, u32 val, + u32 off, int chan) +{ + __raw_writel(val, priv->dma_chan + off + chan * priv->dma_chan_width); +} + +static inline void dmas_writel(struct bcm6368_enetsw *priv, u32 val, + u32 off, int chan) +{ + __raw_writel(val, priv->dma_sram + off + chan * priv->dma_chan_width); +} + +/* + * refill rx queue + */ +static int bcm6368_enetsw_refill_rx(struct net_device *dev) +{ + struct bcm6368_enetsw *priv; + + priv = netdev_priv(dev); + + while (priv->rx_desc_count < priv->rx_ring_size) { + struct bcm6368_enetsw_desc *desc; + struct sk_buff *skb; + dma_addr_t p; + int desc_idx; + u32 len_stat; + + desc_idx = priv->rx_dirty_desc; + desc = &priv->rx_desc_cpu[desc_idx]; + + if (!priv->rx_skb[desc_idx]) { + skb = netdev_alloc_skb(dev, priv->rx_skb_size); + if (!skb) + break; + priv->rx_skb[desc_idx] = skb; + p = dma_map_single(&priv->pdev->dev, skb->data, + priv->rx_skb_size, + DMA_FROM_DEVICE); + desc->address = p; + } + + len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT; + len_stat |= DMADESC_OWNER_MASK; + if (priv->rx_dirty_desc == priv->rx_ring_size - 1) { + len_stat |= (DMADESC_WRAP_MASK >> + priv->dma_desc_shift); + priv->rx_dirty_desc = 0; + } else { + priv->rx_dirty_desc++; + } + wmb(); + desc->len_stat = len_stat; + + priv->rx_desc_count++; + + /* tell dma engine we allocated one buffer */ + dma_writel(priv, 1, DMA_BUFALLOC_REG(priv->rx_chan)); + } + + /* If rx ring is still empty, set a timer to try allocating + * again at a later time. */ + if (priv->rx_desc_count == 0 && netif_running(dev)) { + dev_warn(&priv->pdev->dev, "unable to refill rx ring\n"); + priv->rx_timeout.expires = jiffies + HZ; + add_timer(&priv->rx_timeout); + } + + return 0; +} + +/* + * timer callback to defer refill rx queue in case we're OOM + */ +static void bcm6368_enetsw_refill_rx_timer(struct timer_list *t) +{ + struct bcm6368_enetsw *priv = from_timer(priv, t, rx_timeout); + struct net_device *dev = priv->net_dev; + + spin_lock(&priv->rx_lock); + bcm6368_enetsw_refill_rx(dev); + spin_unlock(&priv->rx_lock); +} + +/* + * extract packet from rx queue + */ +static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) +{ + struct bcm6368_enetsw *priv; + struct device *kdev; + int processed; + + priv = netdev_priv(dev); + kdev = &priv->pdev->dev; + processed = 0; + + /* don't scan ring further than number of refilled + * descriptor */ + if (budget > priv->rx_desc_count) + budget = priv->rx_desc_count; + + do { + struct bcm6368_enetsw_desc *desc; + struct sk_buff *skb; + int desc_idx; + u32 len_stat; + unsigned int len; + + desc_idx = priv->rx_curr_desc; + desc = &priv->rx_desc_cpu[desc_idx]; + + /* make sure we actually read the descriptor status at + * each loop */ + rmb(); + + len_stat = desc->len_stat; + + /* break if dma ownership belongs to hw */ + if (len_stat & DMADESC_OWNER_MASK) + break; + + processed++; + priv->rx_curr_desc++; + if (priv->rx_curr_desc == priv->rx_ring_size) + priv->rx_curr_desc = 0; + priv->rx_desc_count--; + + /* if the packet does not have start of packet _and_ + * end of packet flag set, then just recycle it */ + if ((len_stat & (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) + != (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) { + dev->stats.rx_dropped++; + continue; + } + + /* valid packet */ + skb = priv->rx_skb[desc_idx]; + len = (len_stat & DMADESC_LENGTH_MASK) + >> DMADESC_LENGTH_SHIFT; + /* don't include FCS */ + len -= 4; + + if (len < priv->copybreak) { + struct sk_buff *nskb; + + nskb = napi_alloc_skb(&priv->napi, len); + if (!nskb) { + /* forget packet, just rearm desc */ + dev->stats.rx_dropped++; + continue; + } + + dma_sync_single_for_cpu(kdev, desc->address, + len, DMA_FROM_DEVICE); + memcpy(nskb->data, skb->data, len); + dma_sync_single_for_device(kdev, desc->address, + len, DMA_FROM_DEVICE); + skb = nskb; + } else { + dma_unmap_single(&priv->pdev->dev, desc->address, + priv->rx_skb_size, DMA_FROM_DEVICE); + priv->rx_skb[desc_idx] = NULL; + } + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + netif_receive_skb(skb); + } while (--budget > 0); + + if (processed || !priv->rx_desc_count) { + bcm6368_enetsw_refill_rx(dev); + + /* kick rx dma */ + dmac_writel(priv, priv->dma_chan_en_mask, + DMAC_CHANCFG_REG, priv->rx_chan); + } + + return processed; +} + +/* + * try to or force reclaim of transmitted buffers + */ +static int bcm6368_enetsw_tx_reclaim(struct net_device *dev, int force) +{ + struct bcm6368_enetsw *priv; + int released; + + priv = netdev_priv(dev); + released = 0; + + while (priv->tx_desc_count < priv->tx_ring_size) { + struct bcm6368_enetsw_desc *desc; + struct sk_buff *skb; + + /* We run in a bh and fight against start_xmit, which + * is called with bh disabled */ + spin_lock(&priv->tx_lock); + + desc = &priv->tx_desc_cpu[priv->tx_dirty_desc]; + + if (!force && (desc->len_stat & DMADESC_OWNER_MASK)) { + spin_unlock(&priv->tx_lock); + break; + } + + /* ensure other field of the descriptor were not read + * before we checked ownership */ + rmb(); + + skb = priv->tx_skb[priv->tx_dirty_desc]; + priv->tx_skb[priv->tx_dirty_desc] = NULL; + dma_unmap_single(&priv->pdev->dev, desc->address, skb->len, + DMA_TO_DEVICE); + + priv->tx_dirty_desc++; + if (priv->tx_dirty_desc == priv->tx_ring_size) + priv->tx_dirty_desc = 0; + priv->tx_desc_count++; + + spin_unlock(&priv->tx_lock); + + if (desc->len_stat & DMADESC_UNDER_MASK) + dev->stats.tx_errors++; + + dev_kfree_skb(skb); + released++; + } + + if (netif_queue_stopped(dev) && released) + netif_wake_queue(dev); + + return released; +} + +/* + * poll func, called by network core + */ +static int bcm6368_enetsw_poll(struct napi_struct *napi, int budget) +{ + struct bcm6368_enetsw *priv; + struct net_device *dev; + int rx_work_done; + + priv = container_of(napi, struct bcm6368_enetsw, napi); + dev = priv->net_dev; + + /* ack interrupts */ + dmac_writel(priv, priv->dma_chan_int_mask, + DMAC_IR_REG, priv->rx_chan); + dmac_writel(priv, priv->dma_chan_int_mask, + DMAC_IR_REG, priv->tx_chan); + + /* reclaim sent skb */ + bcm6368_enetsw_tx_reclaim(dev, 0); + + spin_lock(&priv->rx_lock); + rx_work_done = bcm6368_enetsw_receive_queue(dev, budget); + spin_unlock(&priv->rx_lock); + + if (rx_work_done >= budget) { + /* rx queue is not yet empty/clean */ + return rx_work_done; + } + + /* no more packet in rx/tx queue, remove device from poll + * queue */ + napi_complete_done(napi, rx_work_done); + + /* restore rx/tx interrupt */ + dmac_writel(priv, priv->dma_chan_int_mask, + DMAC_IRMASK_REG, priv->rx_chan); + dmac_writel(priv, priv->dma_chan_int_mask, + DMAC_IRMASK_REG, priv->tx_chan); + + return rx_work_done; +} + +/* + * rx/tx dma interrupt handler + */ +static irqreturn_t bcm6368_enetsw_isr_dma(int irq, void *dev_id) +{ + struct net_device *dev; + struct bcm6368_enetsw *priv; + + dev = dev_id; + priv = netdev_priv(dev); + + /* mask rx/tx interrupts */ + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->rx_chan); + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->tx_chan); + + napi_schedule(&priv->napi); + + return IRQ_HANDLED; +} + +/* + * tx request callback + */ +static netdev_tx_t +bcm6368_enetsw_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bcm6368_enetsw *priv; + struct bcm6368_enetsw_desc *desc; + u32 len_stat; + netdev_tx_t ret; + + priv = netdev_priv(dev); + + /* lock against tx reclaim */ + spin_lock(&priv->tx_lock); + + /* make sure the tx hw queue is not full, should not happen + * since we stop queue before it's the case */ + if (unlikely(!priv->tx_desc_count)) { + netif_stop_queue(dev); + dev_err(&priv->pdev->dev, "xmit called with no tx desc " + "available?\n"); + ret = NETDEV_TX_BUSY; + goto out_unlock; + } + + /* pad small packets */ + if (skb->len < 64) { + int needed = 64 - skb->len; + char *data; + + if (unlikely(skb_tailroom(skb) < needed)) { + struct sk_buff *nskb; + + nskb = skb_copy_expand(skb, 0, needed, GFP_ATOMIC); + if (!nskb) { + ret = NETDEV_TX_BUSY; + goto out_unlock; + } + dev_kfree_skb(skb); + skb = nskb; + } + data = skb_put_zero(skb, needed); + } + + /* point to the next available desc */ + desc = &priv->tx_desc_cpu[priv->tx_curr_desc]; + priv->tx_skb[priv->tx_curr_desc] = skb; + + /* fill descriptor */ + desc->address = dma_map_single(&priv->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + + len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK; + len_stat |= (DMADESC_ESOP_MASK >> priv->dma_desc_shift) | + DMADESC_APPEND_CRC | DMADESC_OWNER_MASK; + + priv->tx_curr_desc++; + if (priv->tx_curr_desc == priv->tx_ring_size) { + priv->tx_curr_desc = 0; + len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift); + } + priv->tx_desc_count--; + + /* dma might be already polling, make sure we update desc + * fields in correct order */ + wmb(); + desc->len_stat = len_stat; + wmb(); + + /* kick tx dma */ + dmac_writel(priv, priv->dma_chan_en_mask, DMAC_CHANCFG_REG, + priv->tx_chan); + + /* stop queue if no more desc available */ + if (!priv->tx_desc_count) + netif_stop_queue(dev); + + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + ret = NETDEV_TX_OK; + +out_unlock: + spin_unlock(&priv->tx_lock); + return ret; +} + +/* + * disable dma in given channel + */ +static void bcm6368_enetsw_disable_dma(struct bcm6368_enetsw *priv, int chan) +{ + int limit; + + dmac_writel(priv, 0, DMAC_CHANCFG_REG, chan); + + limit = 1000; + do { + u32 val; + + val = dma_readl(priv, DMAC_CHANCFG_REG, chan); + if (!(val & DMAC_CHANCFG_EN_MASK)) + break; + udelay(1); + } while (limit--); +} + +static int bcm6368_enetsw_open(struct net_device *dev) +{ + struct bcm6368_enetsw *priv; + struct device *kdev; + int i, ret; + unsigned int size; + void *p; + u32 val; + + priv = netdev_priv(dev); + kdev = &priv->pdev->dev; + + /* mask all interrupts and request them */ + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->rx_chan); + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->tx_chan); + + ret = request_irq(priv->irq_rx, bcm6368_enetsw_isr_dma, + 0, dev->name, dev); + if (ret) + goto out_freeirq; + + if (priv->irq_tx != -1) { + ret = request_irq(priv->irq_tx, bcm6368_enetsw_isr_dma, + 0, dev->name, dev); + if (ret) + goto out_freeirq_rx; + } + + /* allocate rx dma ring */ + size = priv->rx_ring_size * sizeof(struct bcm6368_enetsw_desc); + p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); + if (!p) { + dev_err(kdev, "cannot allocate rx ring %u\n", size); + ret = -ENOMEM; + goto out_freeirq_tx; + } + + memset(p, 0, size); + priv->rx_desc_alloc_size = size; + priv->rx_desc_cpu = p; + + /* allocate tx dma ring */ + size = priv->tx_ring_size * sizeof(struct bcm6368_enetsw_desc); + p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); + if (!p) { + dev_err(kdev, "cannot allocate tx ring\n"); + ret = -ENOMEM; + goto out_free_rx_ring; + } + + memset(p, 0, size); + priv->tx_desc_alloc_size = size; + priv->tx_desc_cpu = p; + + priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size, + GFP_KERNEL); + if (!priv->tx_skb) { + dev_err(kdev, "cannot allocate rx skb queue\n"); + ret = -ENOMEM; + goto out_free_tx_ring; + } + + priv->tx_desc_count = priv->tx_ring_size; + priv->tx_dirty_desc = 0; + priv->tx_curr_desc = 0; + spin_lock_init(&priv->tx_lock); + + /* init & fill rx ring with skbs */ + priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size, + GFP_KERNEL); + if (!priv->rx_skb) { + dev_err(kdev, "cannot allocate rx skb queue\n"); + ret = -ENOMEM; + goto out_free_tx_skb; + } + + priv->rx_desc_count = 0; + priv->rx_dirty_desc = 0; + priv->rx_curr_desc = 0; + + /* initialize flow control buffer allocation */ + dma_writel(priv, DMA_BUFALLOC_FORCE_MASK | 0, + DMA_BUFALLOC_REG(priv->rx_chan)); + + if (bcm6368_enetsw_refill_rx(dev)) { + dev_err(kdev, "cannot allocate rx skb queue\n"); + ret = -ENOMEM; + goto out; + } + + /* write rx & tx ring addresses */ + dmas_writel(priv, priv->rx_desc_dma, + DMAS_RSTART_REG, priv->rx_chan); + dmas_writel(priv, priv->tx_desc_dma, + DMAS_RSTART_REG, priv->tx_chan); + + /* clear remaining state ram for rx & tx channel */ + dmas_writel(priv, 0, DMAS_SRAM2_REG, priv->rx_chan); + dmas_writel(priv, 0, DMAS_SRAM2_REG, priv->tx_chan); + dmas_writel(priv, 0, DMAS_SRAM3_REG, priv->rx_chan); + dmas_writel(priv, 0, DMAS_SRAM3_REG, priv->tx_chan); + dmas_writel(priv, 0, DMAS_SRAM4_REG, priv->rx_chan); + dmas_writel(priv, 0, DMAS_SRAM4_REG, priv->tx_chan); + + /* set dma maximum burst len */ + dmac_writel(priv, priv->dma_maxburst, + DMAC_MAXBURST_REG, priv->rx_chan); + dmac_writel(priv, priv->dma_maxburst, + DMAC_MAXBURST_REG, priv->tx_chan); + + /* set flow control low/high threshold to 1/3 / 2/3 */ + val = priv->rx_ring_size / 3; + dma_writel(priv, val, DMA_FLOWCL_REG(priv->rx_chan)); + val = (priv->rx_ring_size * 2) / 3; + dma_writel(priv, val, DMA_FLOWCH_REG(priv->rx_chan)); + + /* all set, enable mac and interrupts, start dma engine and + * kick rx dma channel + */ + wmb(); + dma_writel(priv, DMA_CFG_EN_MASK, DMA_CFG_REG); + dmac_writel(priv, DMAC_CHANCFG_EN_MASK, + DMAC_CHANCFG_REG, priv->rx_chan); + + /* watch "packet transferred" interrupt in rx and tx */ + dmac_writel(priv, DMAC_IR_PKTDONE_MASK, + DMAC_IR_REG, priv->rx_chan); + dmac_writel(priv, DMAC_IR_PKTDONE_MASK, + DMAC_IR_REG, priv->tx_chan); + + /* make sure we enable napi before rx interrupt */ + napi_enable(&priv->napi); + + dmac_writel(priv, DMAC_IR_PKTDONE_MASK, + DMAC_IRMASK_REG, priv->rx_chan); + dmac_writel(priv, DMAC_IR_PKTDONE_MASK, + DMAC_IRMASK_REG, priv->tx_chan); + + netif_carrier_on(dev); + netif_start_queue(dev); + + return 0; + +out: + for (i = 0; i < priv->rx_ring_size; i++) { + struct bcm6368_enetsw_desc *desc; + + if (!priv->rx_skb[i]) + continue; + + desc = &priv->rx_desc_cpu[i]; + dma_unmap_single(kdev, desc->address, priv->rx_skb_size, + DMA_FROM_DEVICE); + kfree_skb(priv->rx_skb[i]); + } + kfree(priv->rx_skb); + +out_free_tx_skb: + kfree(priv->tx_skb); + +out_free_tx_ring: + dma_free_coherent(kdev, priv->tx_desc_alloc_size, + priv->tx_desc_cpu, priv->tx_desc_dma); + +out_free_rx_ring: + dma_free_coherent(kdev, priv->rx_desc_alloc_size, + priv->rx_desc_cpu, priv->rx_desc_dma); + +out_freeirq_tx: + if (priv->irq_tx != -1) + free_irq(priv->irq_tx, dev); + +out_freeirq_rx: + free_irq(priv->irq_rx, dev); + +out_freeirq: + return ret; +} + +static int bcm6368_enetsw_stop(struct net_device *dev) +{ + struct bcm6368_enetsw *priv; + struct device *kdev; + int i; + + priv = netdev_priv(dev); + kdev = &priv->pdev->dev; + + netif_stop_queue(dev); + napi_disable(&priv->napi); + del_timer_sync(&priv->rx_timeout); + + /* mask all interrupts */ + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->rx_chan); + dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->tx_chan); + + /* disable dma & mac */ + bcm6368_enetsw_disable_dma(priv, priv->tx_chan); + bcm6368_enetsw_disable_dma(priv, priv->rx_chan); + + /* force reclaim of all tx buffers */ + bcm6368_enetsw_tx_reclaim(dev, 1); + + /* free the rx skb ring */ + for (i = 0; i < priv->rx_ring_size; i++) { + struct bcm6368_enetsw_desc *desc; + + if (!priv->rx_skb[i]) + continue; + + desc = &priv->rx_desc_cpu[i]; + dma_unmap_single_attrs(kdev, desc->address, priv->rx_skb_size, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + kfree_skb(priv->rx_skb[i]); + } + + /* free remaining allocated memory */ + kfree(priv->rx_skb); + kfree(priv->tx_skb); + dma_free_coherent(kdev, priv->rx_desc_alloc_size, + priv->rx_desc_cpu, priv->rx_desc_dma); + dma_free_coherent(kdev, priv->tx_desc_alloc_size, + priv->tx_desc_cpu, priv->tx_desc_dma); + if (priv->irq_tx != -1) + free_irq(priv->irq_tx, dev); + free_irq(priv->irq_rx, dev); + + return 0; +} + +static const struct net_device_ops bcm6368_enetsw_ops = { + .ndo_open = bcm6368_enetsw_open, + .ndo_stop = bcm6368_enetsw_stop, + .ndo_start_xmit = bcm6368_enetsw_start_xmit, +}; + +static int bcm6368_enetsw_probe(struct platform_device *pdev) +{ + struct bcm6368_enetsw *priv; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct net_device *ndev; + struct resource *res; + const void *mac; + unsigned i; + int ret; + + ndev = alloc_etherdev(sizeof(*priv)); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + + priv->num_pms = of_count_phandle_with_args(node, "power-domains", + "#power-domain-cells"); + if (priv->num_pms > 1) { + priv->pm = devm_kcalloc(dev, priv->num_pms, + sizeof(struct device *), GFP_KERNEL); + if (!priv->pm) + return -ENOMEM; + + priv->link_pm = devm_kcalloc(dev, priv->num_pms, + sizeof(struct device_link *), + GFP_KERNEL); + if (!priv->link_pm) + return -ENOMEM; + + for (i = 0; i < priv->num_pms; i++) { + priv->pm[i] = genpd_dev_pm_attach_by_id(dev, i); + if (IS_ERR(priv->pm[i])) { + dev_err(dev, "error getting pm %d\n", i); + return -EINVAL; + } + + priv->link_pm[i] = device_link_add(dev, priv->pm[i], + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + } + } + + pm_runtime_enable(dev); + pm_runtime_no_callbacks(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_disable(dev); + dev_info(dev, "PM prober defer: ret=%d\n", ret); + return -EPROBE_DEFER; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); + priv->dma_base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->dma_base)) + return PTR_ERR(priv->dma_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "dma-channels"); + priv->dma_chan = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->dma_chan)) + return PTR_ERR(priv->dma_chan); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma-sram"); + priv->dma_sram = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->dma_sram)) + return PTR_ERR(priv->dma_sram); + + priv->irq_rx = platform_get_irq_byname(pdev, "rx"); + if (!priv->irq_rx) + return -ENODEV; + + priv->irq_tx = platform_get_irq_byname(pdev, "tx"); + if (!priv->irq_tx) + return -ENODEV; + else if (priv->irq_tx < 0) + priv->irq_tx = -1; + + if (device_property_read_u32(dev, "dma-rx", &priv->rx_chan)) + return -ENODEV; + + if (device_property_read_u32(dev, "dma-tx", &priv->tx_chan)) + return -ENODEV; + + priv->rx_ring_size = ENETSW_DEF_RX_DESC; + priv->tx_ring_size = ENETSW_DEF_TX_DESC; + + priv->dma_maxburst = ENETSW_DMA_MAXBURST; + + priv->copybreak = ENETSW_DEF_CPY_BREAK; + + priv->dma_chan_en_mask = DMAC_CHANCFG_EN_MASK; + priv->dma_chan_int_mask = DMAC_IR_PKTDONE_MASK; + priv->dma_chan_width = DMA_CHAN_WIDTH; + + mac = of_get_mac_address(node); + if (!IS_ERR_OR_NULL(mac)) { + memcpy(ndev->dev_addr, mac, ETH_ALEN); + dev_info(dev, "mtd mac %pM\n", ndev->dev_addr); + } else { + random_ether_addr(ndev->dev_addr); + dev_info(dev, "random mac %pM\n", ndev->dev_addr); + } + + priv->rx_skb_size = ALIGN(ndev->mtu + ENETSW_MTU_OVERHEAD, + priv->dma_maxburst * 4); + + priv->num_clocks = of_clk_get_parent_count(node); + if (priv->num_clocks) { + priv->clock = devm_kcalloc(dev, priv->num_clocks, + sizeof(struct clk *), GFP_KERNEL); + if (!priv->clock) + return -ENOMEM; + } + for (i = 0; i < priv->num_clocks; i++) { + priv->clock[i] = of_clk_get(node, i); + if (IS_ERR(priv->clock[i])) { + dev_err(dev, "error getting clock %d\n", i); + return -EINVAL; + } + + ret = clk_prepare_enable(priv->clock[i]); + if (ret) { + dev_err(dev, "error enabling clock %d\n", i); + return ret; + } + } + + priv->num_resets = of_count_phandle_with_args(node, "resets", + "#reset-cells"); + if (priv->num_resets) { + priv->reset = devm_kcalloc(dev, priv->num_resets, + sizeof(struct reset_control *), + GFP_KERNEL); + if (!priv->reset) + return -ENOMEM; + } + for (i = 0; i < priv->num_resets; i++) { + priv->reset[i] = devm_reset_control_get_by_index(dev, i); + if (IS_ERR(priv->reset[i])) { + dev_err(dev, "error getting reset %d\n", i); + return -EINVAL; + } + + ret = reset_control_reset(priv->reset[i]); + if (ret) { + dev_err(dev, "error performing reset %d\n", i); + return ret; + } + } + + spin_lock_init(&priv->rx_lock); + + timer_setup(&priv->rx_timeout, bcm6368_enetsw_refill_rx_timer, 0); + + /* register netdevice */ + ndev->netdev_ops = &bcm6368_enetsw_ops; + ndev->min_mtu = ETH_ZLEN; + ndev->mtu = ETH_DATA_LEN + ENETSW_TAG_SIZE; + ndev->max_mtu = ETH_DATA_LEN + ENETSW_TAG_SIZE; + netif_napi_add(ndev, &priv->napi, bcm6368_enetsw_poll, 16); + SET_NETDEV_DEV(ndev, dev); + + ret = register_netdev(ndev); + if (ret) + goto out_disable_clk; + + netif_carrier_off(ndev); + platform_set_drvdata(pdev, ndev); + priv->pdev = pdev; + priv->net_dev = ndev; + + return 0; + +out_disable_clk: + for (i = 0; i < priv->num_resets; i++) + reset_control_assert(priv->reset[i]); + + for (i = 0; i < priv->num_clocks; i++) + clk_disable_unprepare(priv->clock[i]); + + return ret; +} + +static int bcm6368_enetsw_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct net_device *ndev = platform_get_drvdata(pdev); + struct bcm6368_enetsw *priv = netdev_priv(ndev); + unsigned int i; + + unregister_netdev(ndev); + + pm_runtime_put_sync(dev); + for (i = 0; priv->pm && i < priv->num_pms; i++) { + dev_pm_domain_detach(priv->pm[i], true); + device_link_del(priv->link_pm[i]); + } + + for (i = 0; i < priv->num_resets; i++) + reset_control_assert(priv->reset[i]); + + for (i = 0; i < priv->num_clocks; i++) + clk_disable_unprepare(priv->clock[i]); + + free_netdev(ndev); + + return 0; +} + +static const struct of_device_id bcm6368_enetsw_of_match[] = { + { .compatible = "brcm,bcm6318-enetsw", }, + { .compatible = "brcm,bcm6328-enetsw", }, + { .compatible = "brcm,bcm6362-enetsw", }, + { .compatible = "brcm,bcm6368-enetsw", }, + { .compatible = "brcm,bcm63268-enetsw", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm6368_mdio_ids); + +static struct platform_driver bcm6368_enetsw_driver = { + .driver = { + .name = "bcm6368-enetsw", + .of_match_table = of_match_ptr(bcm6368_enetsw_of_match), + }, + .probe = bcm6368_enetsw_probe, + .remove = bcm6368_enetsw_remove, +}; +module_platform_driver(bcm6368_enetsw_driver); diff --git a/target/linux/bmips/generic/base-files/etc/board.d/02_network b/target/linux/bmips/generic/base-files/etc/board.d/02_network new file mode 100644 index 0000000000..3e60660331 --- /dev/null +++ b/target/linux/bmips/generic/base-files/etc/board.d/02_network @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +comtrend,ar-5315u |\ +comtrend,ar-5387un |\ +comtrend,vr-3025u) + ucidef_set_interface_lan "lan1 lan2 lan3 lan4" + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/bmips/nand/base-files/etc/board.d/02_network b/target/linux/bmips/nand/base-files/etc/board.d/02_network new file mode 100644 index 0000000000..db62e61287 --- /dev/null +++ b/target/linux/bmips/nand/base-files/etc/board.d/02_network @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +comtrend,vr-3032u) + ucidef_set_interface_lan "lan1 lan2 lan3 lan4" + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/bmips/patches-5.10/500-net-dsa-b53-relax-is63xx-condition.patch b/target/linux/bmips/patches-5.10/500-net-dsa-b53-relax-is63xx-condition.patch new file mode 100644 index 0000000000..f5dd4e2c59 --- /dev/null +++ b/target/linux/bmips/patches-5.10/500-net-dsa-b53-relax-is63xx-condition.patch @@ -0,0 +1,29 @@ +From cd6906754bbe3e0665ecaeca2cfb26d927fe9277 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Mon, 1 Mar 2021 07:29:29 +0100 +Subject: [PATCH 1/3] net: dsa: b53: relax is63xx() condition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM63xx switches are present on bcm63xx and bmips devices. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/net/dsa/b53/b53_priv.h | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -185,11 +185,7 @@ static inline int is531x5(struct b53_dev + + static inline int is63xx(struct b53_device *dev) + { +-#ifdef CONFIG_BCM63XX + return dev->chip_id == BCM63XX_DEVICE_ID; +-#else +- return 0; +-#endif + } + + static inline int is5301x(struct b53_device *dev) diff --git a/target/linux/bmips/patches-5.10/501-net-dsa-b53-mmap-Add-device-tree-support.patch b/target/linux/bmips/patches-5.10/501-net-dsa-b53-mmap-Add-device-tree-support.patch new file mode 100644 index 0000000000..e9eb87cb5c --- /dev/null +++ b/target/linux/bmips/patches-5.10/501-net-dsa-b53-mmap-Add-device-tree-support.patch @@ -0,0 +1,82 @@ +From f5419e7f362ae1c462baf28a2da7360267f8e4f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Mon, 1 Mar 2021 07:32:32 +0100 +Subject: [PATCH 2/3] net: dsa: b53: mmap: Add device tree support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add device tree support to b53_mmap.c while keeping platform devices support. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/net/dsa/b53/b53_mmap.c | 36 ++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/net/dsa/b53/b53_mmap.c ++++ b/drivers/net/dsa/b53/b53_mmap.c +@@ -228,12 +228,64 @@ static const struct b53_io_ops b53_mmap_ + .write64 = b53_mmap_write64, + }; + ++static int b53_mmap_probe_of(struct platform_device *pdev, ++ struct b53_platform_data **ppdata) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *of_ports, *of_port; ++ struct b53_platform_data *pdata; ++ void __iomem *mem; ++ ++ mem = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mem)) ++ return PTR_ERR(mem); ++ ++ pdata = devm_kzalloc(dev, sizeof(struct b53_platform_data), ++ GFP_KERNEL); ++ if (!pdata) ++ return -ENOMEM; ++ ++ pdata->regs = mem; ++ pdata->chip_id = BCM63XX_DEVICE_ID; ++ pdata->big_endian = of_property_read_bool(np, "big-endian"); ++ ++ of_ports = of_get_child_by_name(np, "ports"); ++ if (!of_ports) { ++ dev_err(dev, "no ports child node found\n"); ++ return -EINVAL; ++ } ++ ++ for_each_available_child_of_node(of_ports, of_port) { ++ u32 reg; ++ ++ if (of_property_read_u32(of_port, "reg", ®)) ++ continue; ++ ++ if (reg < B53_CPU_PORT) ++ pdata->enabled_ports |= BIT(reg); ++ } ++ ++ *ppdata = pdata; ++ ++ return 0; ++} ++ + static int b53_mmap_probe(struct platform_device *pdev) + { ++ struct device_node *np = pdev->dev.of_node; + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_mmap_priv *priv; + struct b53_device *dev; + ++ if (np) { ++ int ret = b53_mmap_probe_of(pdev, &pdata); ++ if (ret) { ++ dev_err(&pdev->dev, "OF probe error\n"); ++ return ret; ++ } ++ } ++ + if (!pdata) + return -EINVAL; + diff --git a/target/linux/bmips/patches-5.10/502-net-dsa-b53-support-tags-for-legacy-switches.patch b/target/linux/bmips/patches-5.10/502-net-dsa-b53-support-tags-for-legacy-switches.patch new file mode 100644 index 0000000000..b8aa8b844d --- /dev/null +++ b/target/linux/bmips/patches-5.10/502-net-dsa-b53-support-tags-for-legacy-switches.patch @@ -0,0 +1,209 @@ +From 3bc3d79efdff6e29b80bf35f7a56baaa36e4d8fe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Fri, 12 Mar 2021 12:35:39 +0100 +Subject: [PATCH] net: dsa: b53: support tags for legacy switches +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/net/dsa/b53/Kconfig | 1 + + drivers/net/dsa/b53/b53_common.c | 6 +++ + include/net/dsa.h | 2 + + net/dsa/Kconfig | 7 +++ + net/dsa/tag_brcm.c | 93 ++++++++++++++++++++++++++++++++ + 5 files changed, 109 insertions(+) + +--- a/drivers/net/dsa/b53/Kconfig ++++ b/drivers/net/dsa/b53/Kconfig +@@ -3,6 +3,7 @@ menuconfig B53 + tristate "Broadcom BCM53xx managed switch support" + depends on NET_DSA + select NET_DSA_TAG_BRCM ++ select NET_DSA_TAG_BRCM_LEGACY + select NET_DSA_TAG_BRCM_PREPEND + help + This driver adds support for Broadcom managed switch chips. It supports +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1992,6 +1992,7 @@ static bool b53_can_enable_brcm_tags(str + + switch (tag_protocol) { + case DSA_TAG_PROTO_BRCM: ++ case DSA_TAG_PROTO_BRCM_LEGACY: + case DSA_TAG_PROTO_BRCM_PREPEND: + dev_warn(ds->dev, + "Port %d is stacked to Broadcom tag switch\n", port); +@@ -2013,12 +2014,16 @@ enum dsa_tag_protocol b53_get_tag_protoc + /* Older models (5325, 5365) support a different tag format that we do + * not support in net/dsa/tag_brcm.c yet. + */ +- if (is5325(dev) || is5365(dev) || +- !b53_can_enable_brcm_tags(ds, port, mprot)) { ++ if (!b53_can_enable_brcm_tags(ds, port, mprot)) { + dev->tag_protocol = DSA_TAG_PROTO_NONE; + goto out; + } + ++ if (is5325(dev) || is5365(dev) || is63xx(dev)) { ++ dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY; ++ goto out; ++ } ++ + /* Broadcom BCM58xx chips have a flow accelerator on Port 8 + * which requires us to use the prepended Broadcom tag type + */ +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -45,10 +45,12 @@ struct phylink_link_state; + #define DSA_TAG_PROTO_OCELOT_VALUE 15 + #define DSA_TAG_PROTO_AR9331_VALUE 16 + #define DSA_TAG_PROTO_RTL4_A_VALUE 17 ++#define DSA_TAG_PROTO_BRCM_LEGACY_VALUE 22 + + enum dsa_tag_protocol { + DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, + DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE, ++ DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE, + DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE, + DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE, + DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE, +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -47,6 +47,13 @@ config NET_DSA_TAG_BRCM + Say Y if you want to enable support for tagging frames for the + Broadcom switches which place the tag after the MAC source address. + ++config NET_DSA_TAG_BRCM_LEGACY ++ tristate "Tag driver for Broadcom legacy switches using in-frame headers" ++ select NET_DSA_TAG_BRCM_COMMON ++ help ++ Say Y if you want to enable support for tagging frames for the ++ Broadcom legacy switches which place the tag after the MAC source ++ address. + + config NET_DSA_TAG_BRCM_PREPEND + tristate "Tag driver for Broadcom switches using prepended headers" +--- a/net/dsa/tag_brcm.c ++++ b/net/dsa/tag_brcm.c +@@ -8,9 +8,23 @@ + #include + #include + #include ++#include + + #include "dsa_priv.h" + ++struct bcm_legacy_tag { ++ uint16_t type; ++#define BRCM_LEG_TYPE 0x8874 ++ ++ uint32_t tag; ++#define BRCM_LEG_TAG_PORT_ID (0xf) ++#define BRCM_LEG_TAG_MULTICAST (1 << 29) ++#define BRCM_LEG_TAG_EGRESS (2 << 29) ++#define BRCM_LEG_TAG_INGRESS (3 << 29) ++} __attribute__((packed)); ++ ++#define BRCM_LEG_TAG_LEN sizeof(struct bcm_legacy_tag) ++ + /* This tag length is 4 bytes, older ones were 6 bytes, we do not + * handle them + */ +@@ -197,6 +211,85 @@ DSA_TAG_DRIVER(brcm_netdev_ops); + MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM); + #endif + ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) ++static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct bcm_legacy_tag *brcm_tag; ++ ++ if (skb_cow_head(skb, BRCM_LEG_TAG_LEN) < 0) ++ return NULL; ++ ++ /* The Ethernet switch we are interfaced with needs packets to be at ++ * least 64 bytes (including FCS) otherwise they will be discarded when ++ * they enter the switch port logic. When Broadcom tags are enabled, we ++ * need to make sure that packets are at least 70 bytes ++ * (including FCS and tag) because the length verification is done after ++ * the Broadcom tag is stripped off the ingress packet. ++ * ++ * Let dsa_slave_xmit() free the SKB ++ */ ++ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) ++ return NULL; ++ ++ skb_push(skb, BRCM_LEG_TAG_LEN); ++ ++ memmove(skb->data, skb->data + BRCM_LEG_TAG_LEN, 2 * ETH_ALEN); ++ ++ brcm_tag = (struct bcm_legacy_tag *) (skb->data + 2 * ETH_ALEN); ++ ++ brcm_tag->type = BRCM_LEG_TYPE; ++ brcm_tag->tag = BRCM_LEG_TAG_EGRESS; ++ brcm_tag->tag |= dp->index & BRCM_LEG_TAG_PORT_ID; ++ ++ return skb; ++} ++ ++ ++static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, ++ struct net_device *dev, ++ struct packet_type *pt) ++{ ++ int source_port; ++ struct bcm_legacy_tag *brcm_tag; ++ ++ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN))) ++ return NULL; ++ ++ brcm_tag = (struct bcm_legacy_tag *) (skb->data - 2); ++ ++ source_port = brcm_tag->tag & BRCM_LEG_TAG_PORT_ID; ++ ++ skb->dev = dsa_master_find_slave(dev, 0, source_port); ++ if (!skb->dev) ++ return NULL; ++ ++ /* Remove Broadcom tag and update checksum */ ++ skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN); ++ ++ skb->offload_fwd_mark = 1; ++ ++ /* Move the Ethernet DA and SA */ ++ memmove(skb->data - ETH_HLEN, ++ skb->data - ETH_HLEN - BRCM_LEG_TAG_LEN, ++ 2 * ETH_ALEN); ++ ++ return skb; ++} ++ ++static const struct dsa_device_ops brcm_legacy_netdev_ops = { ++ .name = "brcm-legacy", ++ .proto = DSA_TAG_PROTO_BRCM_LEGACY, ++ .xmit = brcm_leg_tag_xmit, ++ .rcv = brcm_leg_tag_rcv, ++ .overhead = BRCM_LEG_TAG_LEN, ++}; ++ ++DSA_TAG_DRIVER(brcm_legacy_netdev_ops); ++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY); ++#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */ ++ + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) + static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb, + struct net_device *dev) +@@ -229,6 +322,9 @@ static struct dsa_tag_driver *dsa_tag_dr + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM) + &DSA_TAG_DRIVER_NAME(brcm_netdev_ops), + #endif ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) ++ &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops), ++#endif + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) + &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops), + #endif diff --git a/target/linux/bmips/patches-5.10/503-net-broadcom-add-BCM6368-enetsw-controller-driver.patch b/target/linux/bmips/patches-5.10/503-net-broadcom-add-BCM6368-enetsw-controller-driver.patch new file mode 100644 index 0000000000..c2c2e968e9 --- /dev/null +++ b/target/linux/bmips/patches-5.10/503-net-broadcom-add-BCM6368-enetsw-controller-driver.patch @@ -0,0 +1,46 @@ +From 590b60fb08cb1e70fe02d3f407c6b3dbe9ad06ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Mon, 1 Mar 2021 07:34:39 +0100 +Subject: [PATCH 3/4] net: broadcom: add BCM6368 enetsw controller driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This controller is present on BCM6318, BCM6328, BCM6362, BCM6368 and BCM63268 +SoCs. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/net/ethernet/broadcom/Kconfig | 8 + + drivers/net/ethernet/broadcom/Makefile | 1 + + .../net/ethernet/broadcom/bcm6368-enetsw.c | 1111 +++++++++++++++++ + 3 files changed, 1120 insertions(+) + create mode 100644 drivers/net/ethernet/broadcom/bcm6368-enetsw.c + +--- a/drivers/net/ethernet/broadcom/Kconfig ++++ b/drivers/net/ethernet/broadcom/Kconfig +@@ -60,6 +60,14 @@ config BCM63XX_ENET + This driver supports the ethernet MACs in the Broadcom 63xx + MIPS chipset family (BCM63XX). + ++config BCM6368_ENETSW ++ tristate "Broadcom BCM6368 internal mac support" ++ depends on BMIPS_GENERIC || COMPILE_TEST ++ default y ++ help ++ This driver supports Ethernet controller integrated into Broadcom ++ BCM6368 family SoCs. ++ + config BCMGENET + tristate "Broadcom GENET internal MAC support" + depends on HAS_IOMEM +--- a/drivers/net/ethernet/broadcom/Makefile ++++ b/drivers/net/ethernet/broadcom/Makefile +@@ -5,6 +5,7 @@ + + obj-$(CONFIG_B44) += b44.o + obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o ++obj-$(CONFIG_BCM6368_ENETSW) += bcm6368-enetsw.o + obj-$(CONFIG_BCMGENET) += genet/ + obj-$(CONFIG_BNX2) += bnx2.o + obj-$(CONFIG_CNIC) += cnic.o diff --git a/target/linux/bmips/patches-5.10/504-net-mdio-Add-BCM6368-MDIO-mux-bus-controller.patch b/target/linux/bmips/patches-5.10/504-net-mdio-Add-BCM6368-MDIO-mux-bus-controller.patch new file mode 100644 index 0000000000..a869681312 --- /dev/null +++ b/target/linux/bmips/patches-5.10/504-net-mdio-Add-BCM6368-MDIO-mux-bus-controller.patch @@ -0,0 +1,231 @@ +From b6ecb2bca2b8ff80ae4b1b15f09dcf071f4ceaf4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Mon, 1 Mar 2021 16:42:12 +0100 +Subject: [PATCH] net: mdio: Add BCM6368 MDIO mux bus controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This controller is present on BCM6318, BCM6328, BCM6362, BCM6368 and BCM63268 +SoCs. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/net/mdio/Kconfig | 11 ++ + drivers/net/mdio/Makefile | 1 + + drivers/net/mdio/mdio-mux-bcm6368.c | 179 ++++++++++++++++++++++++++++ + 3 files changed, 191 insertions(+) + create mode 100644 drivers/net/mdio/mdio-mux-bcm6368.c + +--- a/drivers/net/mdio/Kconfig ++++ b/drivers/net/mdio/Kconfig +@@ -200,6 +200,17 @@ config MDIO_BUS_MUX_MESON_G12A + the amlogic g12a SoC. The multiplexers connects either the external + or the internal MDIO bus to the parent bus. + ++config MDIO_BUS_MUX_BCM6368 ++ tristate "Broadcom BCM6368 MDIO bus multiplexers" ++ depends on OF && OF_MDIO && (BMIPS_GENERIC || COMPILE_TEST) ++ select MDIO_BUS_MUX ++ default BMIPS_GENERIC ++ help ++ This module provides a driver for MDIO bus multiplexers found in ++ BCM6368 based Broadcom SoCs. This multiplexer connects one of several ++ child MDIO bus to a parent bus. Buses could be internal as well as ++ external and selection logic lies inside the same multiplexer. ++ + config MDIO_BUS_MUX_BCM_IPROC + tristate "Broadcom iProc based MDIO bus multiplexers" + depends on OF && OF_MDIO && (ARCH_BCM_IPROC || COMPILE_TEST) +--- a/drivers/net/mdio/Makefile ++++ b/drivers/net/mdio/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_THUNDER) += mdio-thun + obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o + + obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o ++obj-$(CONFIG_MDIO_BUS_MUX_BCM6368) += mdio-mux-bcm6368.o + obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o + obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o + obj-$(CONFIG_MDIO_BUS_MUX_MESON_G12A) += mdio-mux-meson-g12a.o +--- /dev/null ++++ b/drivers/net/mdio/mdio-mux-bcm6368.c +@@ -0,0 +1,179 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Broadcom BCM6368 mdiomux bus controller driver ++ * ++ * Copyright (C) 2021 Álvaro Fernández Rojas ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MDIOC_REG 0x0 ++#define MDIOC_EXT_MASK BIT(16) ++#define MDIOC_REG_SHIFT 20 ++#define MDIOC_PHYID_SHIFT 25 ++#define MDIOC_RD_MASK BIT(30) ++#define MDIOC_WR_MASK BIT(31) ++ ++#define MDIOD_REG 0x4 ++ ++struct bcm6368_mdiomux_desc { ++ void *mux_handle; ++ void __iomem *base; ++ struct device *dev; ++ struct mii_bus *mii_bus; ++ int ext_phy; ++}; ++ ++static int bcm6368_mdiomux_read(struct mii_bus *bus, int phy_id, int loc) ++{ ++ struct bcm6368_mdiomux_desc *md = bus->priv; ++ uint32_t reg; ++ int ret; ++ ++ __raw_writel(0, md->base + MDIOC_REG); ++ ++ reg = MDIOC_RD_MASK | ++ (phy_id << MDIOC_PHYID_SHIFT) | ++ (loc << MDIOC_REG_SHIFT); ++ if (md->ext_phy) ++ reg |= MDIOC_EXT_MASK; ++ ++ __raw_writel(reg, md->base + MDIOC_REG); ++ udelay(50); ++ ret = __raw_readw(md->base + MDIOD_REG); ++ ++ return ret; ++} ++ ++static int bcm6368_mdiomux_write(struct mii_bus *bus, int phy_id, int loc, ++ uint16_t val) ++{ ++ struct bcm6368_mdiomux_desc *md = bus->priv; ++ uint32_t reg; ++ ++ __raw_writel(0, md->base + MDIOC_REG); ++ ++ reg = MDIOC_WR_MASK | ++ (phy_id << MDIOC_PHYID_SHIFT) | ++ (loc << MDIOC_REG_SHIFT); ++ if (md->ext_phy) ++ reg |= MDIOC_EXT_MASK; ++ reg |= val; ++ ++ __raw_writel(reg, md->base + MDIOC_REG); ++ udelay(50); ++ ++ return 0; ++} ++ ++static int bcm6368_mdiomux_switch_fn(int current_child, int desired_child, ++ void *data) ++{ ++ struct bcm6368_mdiomux_desc *md = data; ++ ++ md->ext_phy = desired_child; ++ ++ return 0; ++} ++ ++static int bcm6368_mdiomux_probe(struct platform_device *pdev) ++{ ++ struct bcm6368_mdiomux_desc *md; ++ struct mii_bus *bus; ++ struct resource *res; ++ int rc; ++ ++ md = devm_kzalloc(&pdev->dev, sizeof(*md), GFP_KERNEL); ++ if (!md) ++ return -ENOMEM; ++ md->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ ++ /* Just ioremap, as this MDIO block is usually integrated into an ++ * Ethernet MAC controller register range ++ */ ++ md->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (!md->base) { ++ dev_err(&pdev->dev, "failed to ioremap register\n"); ++ return -ENOMEM; ++ } ++ ++ md->mii_bus = devm_mdiobus_alloc(&pdev->dev); ++ if (!md->mii_bus) { ++ dev_err(&pdev->dev, "mdiomux bus alloc failed\n"); ++ return ENOMEM; ++ } ++ ++ bus = md->mii_bus; ++ bus->priv = md; ++ bus->name = "BCM6368 MDIO mux bus"; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); ++ bus->parent = &pdev->dev; ++ bus->read = bcm6368_mdiomux_read; ++ bus->write = bcm6368_mdiomux_write; ++ bus->phy_mask = 0x3f; ++ bus->dev.of_node = pdev->dev.of_node; ++ ++ rc = mdiobus_register(bus); ++ if (rc) { ++ dev_err(&pdev->dev, "mdiomux registration failed\n"); ++ return rc; ++ } ++ ++ platform_set_drvdata(pdev, md); ++ ++ rc = mdio_mux_init(md->dev, md->dev->of_node, ++ bcm6368_mdiomux_switch_fn, &md->mux_handle, md, ++ md->mii_bus); ++ if (rc) { ++ dev_info(md->dev, "mdiomux initialization failed\n"); ++ goto out_register; ++ } ++ ++ dev_info(&pdev->dev, "Broadcom BCM6368 MDIO mux bus\n"); ++ ++ return 0; ++ ++out_register: ++ mdiobus_unregister(bus); ++ return rc; ++} ++ ++static int bcm6368_mdiomux_remove(struct platform_device *pdev) ++{ ++ struct bcm6368_mdiomux_desc *md = platform_get_drvdata(pdev); ++ ++ mdio_mux_uninit(md->mux_handle); ++ mdiobus_unregister(md->mii_bus); ++ ++ return 0; ++} ++ ++static const struct of_device_id bcm6368_mdiomux_ids[] = { ++ { .compatible = "brcm,bcm6368-mdio-mux", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, bcm6368_mdiomux_ids); ++ ++static struct platform_driver bcm6368_mdiomux_driver = { ++ .driver = { ++ .name = "bcm6368-mdio-mux", ++ .of_match_table = bcm6368_mdiomux_ids, ++ }, ++ .probe = bcm6368_mdiomux_probe, ++ .remove = bcm6368_mdiomux_remove, ++}; ++module_platform_driver(bcm6368_mdiomux_driver); From 41a8f093fb26f372fc94e0016cf544ac65718b0b Mon Sep 17 00:00:00 2001 From: Dominick Grift Date: Sun, 14 Mar 2021 12:42:29 +0100 Subject: [PATCH 28/32] selinux-policy: update to version v0.8 3d7da7a igmpproxy tidy some loose ends c84ba0f rcigmpproxy: add entries to /etc when creating /etc/igmpproxy.conf 5a18967 adds igmpproxy skeleton 7e6a218 logread: support resolving dns names e39ca8b netifd: add support for /etc/udhcpc.user 7952bd0 odhcp6c: support /etc/odhcp6c.user ba0eb4e swconfig, fwenv, agent 4556b8a pppd cosmetic 9324d9d pppd: sends AT commands to model using /dev/ttyUSBN 417b14a ttydev: add some more ttyUSB ed739dc example: dont depend on policycoreutils 97613f9 dropbear: using dropbear as scp: dns name resolving 12c193b dropbear tcp connect ssh ports for scp c050077 rcdnsmasq: remove redundant rule and make rcsysntpd optional 8c5de35 this is a bug 8d5c463 uhttpd rcboot rcdnsmasq 094266e hostapd and wpa_supplicant aef0bd7 mountroot: maintains /tmp/sysupgrade.tar 24f0406 dropbear: allow it to read tmp.fs files 2901433 firstboot mkfsf2fs rcboot 2c4afb7 blockmount mmc 465ca98 adds industrial i/o (iio) nodedev 82f686e mtd stordev: back that ubiblock0_4p1 up with a filecon 7df78bd ubus: "support" older ubusd versions that run as root 4458bce swconfig: allow using terminal (to print output) e8d606d sslcert: openssl linked: this shaves off 200 bytes 93afffb jshn ntpdhotplug 0b847f0 wpad: reads /etc/ssl/openssl.cnf f14ee34 indent fix a0c7cad mtd, uhttpd, ubus and ntpdhotplug d74f98f adds a not about checkreqprot requirement in some scenarios affacce example: add policycoreutils-setfiles for make check 4f944dc kmodloader and fwenv: efe36a3 netifd: adds a comment/reminder 581b087 more fw_printenv loose ends 30177a4 fw_setenv: needs mtd write access to set and delete env da28f4c fw_printenv: some minor clean ups a062053 fw_printenv missing rules 244ba5f blockmount: extroot and /rwm 0745a6a squid: allow squid to run sslcrtd with domain transition b851df6 squid fix 8c55acd squid: adds certfile and allow connect http but... b7c1f6d Makefile: exclude tinyproxy from mintesttgt (using squid) 5ff39bd squid: forgot about luci 5366c97 squid/rcsquid some basic fill in 8743da6 squid skeleton 687a43b adds squid 3128 port to httpproxy port Signed-off-by: Dominick Grift --- package/system/selinux-policy/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/system/selinux-policy/Makefile b/package/system/selinux-policy/Makefile index 759a8eff93..4980ed6f21 100644 --- a/package/system/selinux-policy/Makefile +++ b/package/system/selinux-policy/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=selinux-policy PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://git.defensec.nl/selinux-policy.git -PKG_VERSION:=0.7 -PKG_MIRROR_HASH:=f9c555dfa2bb16e6bfd86f1481aad26fce72e5aa45e297e1b39636b6dd0ce021 +PKG_VERSION:=0.8 +PKG_MIRROR_HASH:=3b58f751a21394e3aef47fd6c9fe9430fadde6427deb5c79f08478904837ec91 PKG_SOURCE_VERSION:=v$(PKG_VERSION) PKG_BUILD_DEPENDS:=secilc/host policycoreutils/host From c6c8d597e18300cd679bf5ea88a46ed18709da01 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 24 Feb 2021 22:03:39 +0100 Subject: [PATCH 29/32] realtek: Add generic zyxel_gs1900 image definition Add a new common device definition for the Zyxel GS1900 line of switches. Signed-off-by: Hauke Mehrtens --- target/linux/realtek/image/Makefile | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index 424726c8a9..759653d4b5 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -84,37 +84,37 @@ define Device/netgear_gs110tpp-v1 endef TARGET_DEVICES += netgear_gs110tpp-v1 -define Device/zyxel_gs1900-10hp +define Device/zyxel_gs1900 SOC := rtl8380 IMAGE_SIZE := 6976k DEVICE_VENDOR := ZyXEL - DEVICE_MODEL := GS1900-10HP UIMAGE_MAGIC := 0x83800000 - KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAZI | uImage gzip + KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers $$$$(ZYXEL_VERS) | \ + uImage gzip +endef + +define Device/zyxel_gs1900-10hp + $(Device/zyxel_gs1900) + DEVICE_MODEL := GS1900-10HP + ZYXEL_VERS := AAZI endef TARGET_DEVICES += zyxel_gs1900-10hp define Device/zyxel_gs1900-8hp-v1 - SOC := rtl8380 - IMAGE_SIZE := 6976k - DEVICE_VENDOR := ZyXEL + $(Device/zyxel_gs1900) DEVICE_MODEL := GS1900-8HP DEVICE_VARIANT := v1 + ZYXEL_VERS := AAHI DEVICE_PACKAGES += lua-rs232 - UIMAGE_MAGIC := 0x83800000 - KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAHI | uImage gzip endef TARGET_DEVICES += zyxel_gs1900-8hp-v1 define Device/zyxel_gs1900-8hp-v2 - SOC := rtl8380 - IMAGE_SIZE := 6976k - DEVICE_VENDOR := ZyXEL + $(Device/zyxel_gs1900) DEVICE_MODEL := GS1900-8HP DEVICE_VARIANT := v2 + ZYXEL_VERS := AAHI DEVICE_PACKAGES += lua-rs232 - UIMAGE_MAGIC := 0x83800000 - KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAHI | uImage gzip endef TARGET_DEVICES += zyxel_gs1900-8hp-v2 From e6ba970b6ef2289a2a4d3dd6c0c158ee8d10160f Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 27 Jan 2021 22:16:11 +0100 Subject: [PATCH 30/32] realtek: Add ZyXEL GS1900-8 The ZyXEL GS1900-8 is a 8 port switch without any PoE functionality or SFP ports, but otherwise similar to the other GS1900 switches. Specifications -------------- * Device: ZyXEL GS1900-8 v1.2 * SoC: Realtek RTL8380M 500 MHz MIPS 4KEc * Flash: Macronix MX25L12835F 16 MiB * RAM: Nanya NT5TU128M8GE-AC 128 MiB DDR2 SDRAM * Ethernet: 8x 10/100/1000 Mbit * LEDs: 1 PWR LED (green, not configurable) 1 SYS LED (green, configurable) 8 ethernet port status LEDs (green, SoC controlled) * Buttons: 1 on-off glide switch at the back (not configurable) 1 reset button at the right side, behind the air-vent (not configurable) 1 reset button on front panel (configurable) * Power 12V 1A barrel connector * UART: 1 serial header (JP2) with populated standard pin connector on the left side of the PCB, towards the back. Pins are labelled: + VCC (3.3V) + TX (really RX) + RX (really TX) + GND the labelling is done from the usb2serial connector's point of view, so RX/ TX are mixed up. Serial connection parameters for both devices: 115200 8N1. Installation ------------ Instructions are identical to those for the GS1900-10HP and GS1900-8HP. * Configure your client with a static 192.168.1.x IP (e.g. 192.168.1.10). * Set up a TFTP server on your client and make it serve the initramfs image. * Connect serial, power up the switch, interrupt U-boot by hitting the space bar, and enable the network: > rtk network on * Since the GS1900-10HP is a dual-partition device, you want to keep the OEM firmware on the backup partition for the time being. OpenWrt can only boot off the first partition anyway (hardcoded in the DTS). To make sure we are manipulating the first partition, issue the following commands: > setsys bootpartition 0 > savesys * Download the image onto the device and boot from it: > tftpboot 0x84f00000 192.168.1.10:openwrt-realtek-generic-zyxel_gs1900-8-initramfs-kernel.bin > bootm * Once OpenWrt has booted, scp the sysupgrade image to /tmp and flash it: > sysupgrade /tmp/openwrt-realtek-generic-zyxel_gs1900-8-squashfs-sysupgrade.bin Signed-off-by: Hauke Mehrtens --- package/boot/uboot-envtools/files/realtek | 1 + target/linux/realtek/dts/rtl8380_zyxel_gs1900-8.dts | 12 ++++++++++++ target/linux/realtek/image/Makefile | 7 +++++++ 3 files changed, 20 insertions(+) create mode 100644 target/linux/realtek/dts/rtl8380_zyxel_gs1900-8.dts diff --git a/package/boot/uboot-envtools/files/realtek b/package/boot/uboot-envtools/files/realtek index 9573e8944f..a91ca82604 100644 --- a/package/boot/uboot-envtools/files/realtek +++ b/package/boot/uboot-envtools/files/realtek @@ -11,6 +11,7 @@ case "$board" in d-link,dgs-1210-16|\ d-link,dgs-1210-28|\ d-link,dgs-1210-10p|\ +zyxel,gs1900-8|\ zyxel,gs1900-8hp-v1|\ zyxel,gs1900-8hp-v2|\ zyxel,gs1900-10hp) diff --git a/target/linux/realtek/dts/rtl8380_zyxel_gs1900-8.dts b/target/linux/realtek/dts/rtl8380_zyxel_gs1900-8.dts new file mode 100644 index 0000000000..e9c5efe603 --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_zyxel_gs1900-8.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rtl8380_zyxel_gs1900.dtsi" + +/ { + compatible = "zyxel,gs1900-8", "realtek,rtl838x-soc"; + model = "ZyXEL GS1900-8 Switch"; +}; + +&gpio1 { + /delete-node/ poe_enable; +}; diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index 759653d4b5..d867d2a3d9 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -100,6 +100,13 @@ define Device/zyxel_gs1900-10hp endef TARGET_DEVICES += zyxel_gs1900-10hp +define Device/zyxel_gs1900-8 + $(Device/zyxel_gs1900) + DEVICE_MODEL := GS1900-8 + ZYXEL_VERS := AAHH +endef +TARGET_DEVICES += zyxel_gs1900-8 + define Device/zyxel_gs1900-8hp-v1 $(Device/zyxel_gs1900) DEVICE_MODEL := GS1900-8HP From 4a81b00a0510d30f1f1e29a76cb0d5fbbe49091c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sun, 14 Mar 2021 14:21:48 +0100 Subject: [PATCH 31/32] bmips: reorganize patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename and reorganize backported patches. Signed-off-by: Álvaro Fernández Rojas --- ...rlier.patch => 020-v5.12-mips-bmips-init-clocks-earlier.patch} | 0 ...ntime.patch => 021-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch} | 0 ...ime.patch => 022-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch} | 0 ...ings.patch => 040-v5.13-mips-smp-bmips-fix-CPU-mappings.patch} | 0 ...v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch} | 0 ...042-v5.13-dt-bindings-rng-bcm2835-add-clock-constraints.patch} | 0 ...43-v5.13-dt-bindings-rng-bcm2835-document-reset-support.patch} | 0 ...port.patch => 044-v5.13-hwrng-bcm2835-add-reset-support.patch} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename target/linux/bmips/patches-5.10/{040-v5.12-mips-bmips-init-clocks-earlier.patch => 020-v5.12-mips-bmips-init-clocks-earlier.patch} (100%) rename target/linux/bmips/patches-5.10/{041-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch => 021-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch} (100%) rename target/linux/bmips/patches-5.10/{042-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch => 022-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch} (100%) rename target/linux/bmips/patches-5.10/{050-v5.13-mips-smp-bmips-fix-CPU-mappings.patch => 040-v5.13-mips-smp-bmips-fix-CPU-mappings.patch} (100%) rename target/linux/bmips/patches-5.10/{051-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch => 041-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch} (100%) rename target/linux/bmips/patches-5.10/{052-dt-bindings-rng-bcm2835-add-clock-constraints.patch => 042-v5.13-dt-bindings-rng-bcm2835-add-clock-constraints.patch} (100%) rename target/linux/bmips/patches-5.10/{053-dt-bindings-rng-bcm2835-document-reset-support.patch => 043-v5.13-dt-bindings-rng-bcm2835-document-reset-support.patch} (100%) rename target/linux/bmips/patches-5.10/{054-hwrng-bcm2835-add-reset-support.patch => 044-v5.13-hwrng-bcm2835-add-reset-support.patch} (100%) diff --git a/target/linux/bmips/patches-5.10/040-v5.12-mips-bmips-init-clocks-earlier.patch b/target/linux/bmips/patches-5.10/020-v5.12-mips-bmips-init-clocks-earlier.patch similarity index 100% rename from target/linux/bmips/patches-5.10/040-v5.12-mips-bmips-init-clocks-earlier.patch rename to target/linux/bmips/patches-5.10/020-v5.12-mips-bmips-init-clocks-earlier.patch diff --git a/target/linux/bmips/patches-5.10/041-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch b/target/linux/bmips/patches-5.10/021-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch similarity index 100% rename from target/linux/bmips/patches-5.10/041-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch rename to target/linux/bmips/patches-5.10/021-v5.12-spi-bcm63xx-spi-fix-pm_runtime.patch diff --git a/target/linux/bmips/patches-5.10/042-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch b/target/linux/bmips/patches-5.10/022-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch similarity index 100% rename from target/linux/bmips/patches-5.10/042-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch rename to target/linux/bmips/patches-5.10/022-v5.12-spi-bcm63xx-hsspi-fix-pm_runtime.patch diff --git a/target/linux/bmips/patches-5.10/050-v5.13-mips-smp-bmips-fix-CPU-mappings.patch b/target/linux/bmips/patches-5.10/040-v5.13-mips-smp-bmips-fix-CPU-mappings.patch similarity index 100% rename from target/linux/bmips/patches-5.10/050-v5.13-mips-smp-bmips-fix-CPU-mappings.patch rename to target/linux/bmips/patches-5.10/040-v5.13-mips-smp-bmips-fix-CPU-mappings.patch diff --git a/target/linux/bmips/patches-5.10/051-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch b/target/linux/bmips/patches-5.10/041-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch similarity index 100% rename from target/linux/bmips/patches-5.10/051-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch rename to target/linux/bmips/patches-5.10/041-v5.13-mtd-rawnand-brcmnand-fix-OOB-R-W-with-Hamming-ECC.patch diff --git a/target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch b/target/linux/bmips/patches-5.10/042-v5.13-dt-bindings-rng-bcm2835-add-clock-constraints.patch similarity index 100% rename from target/linux/bmips/patches-5.10/052-dt-bindings-rng-bcm2835-add-clock-constraints.patch rename to target/linux/bmips/patches-5.10/042-v5.13-dt-bindings-rng-bcm2835-add-clock-constraints.patch diff --git a/target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch b/target/linux/bmips/patches-5.10/043-v5.13-dt-bindings-rng-bcm2835-document-reset-support.patch similarity index 100% rename from target/linux/bmips/patches-5.10/053-dt-bindings-rng-bcm2835-document-reset-support.patch rename to target/linux/bmips/patches-5.10/043-v5.13-dt-bindings-rng-bcm2835-document-reset-support.patch diff --git a/target/linux/bmips/patches-5.10/054-hwrng-bcm2835-add-reset-support.patch b/target/linux/bmips/patches-5.10/044-v5.13-hwrng-bcm2835-add-reset-support.patch similarity index 100% rename from target/linux/bmips/patches-5.10/054-hwrng-bcm2835-add-reset-support.patch rename to target/linux/bmips/patches-5.10/044-v5.13-hwrng-bcm2835-add-reset-support.patch From ecc058b6a04bb333b6a60f13b990fb4f97b70e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sun, 14 Mar 2021 14:22:53 +0100 Subject: [PATCH 32/32] bmips: minor ethernet driver cleanups and fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some minor ethernet driver cleanups and fixes to improve code quality. Signed-off-by: Álvaro Fernández Rojas --- .../net/ethernet/broadcom/bcm6368-enetsw.c | 97 +++++++------------ 1 file changed, 35 insertions(+), 62 deletions(-) diff --git a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c index dc55e3ccb9..2a27118aa7 100644 --- a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c +++ b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c @@ -38,7 +38,7 @@ #define DMA_CHAN_WIDTH 0x10 /* Controller Configuration Register */ -#define DMA_CFG_REG (0x0) +#define DMA_CFG_REG 0x0 #define DMA_CFG_EN_SHIFT 0 #define DMA_CFG_EN_MASK (1 << DMA_CFG_EN_SHIFT) #define DMA_CFG_FLOWCH_MASK(x) (1 << ((x >> 1) + 1)) @@ -55,7 +55,7 @@ #define DMA_BUFALLOC_FORCE_MASK (1 << DMA_BUFALLOC_FORCE_SHIFT) /* Channel Configuration register */ -#define DMAC_CHANCFG_REG (0x0) +#define DMAC_CHANCFG_REG 0x0 #define DMAC_CHANCFG_EN_SHIFT 0 #define DMAC_CHANCFG_EN_MASK (1 << DMAC_CHANCFG_EN_SHIFT) #define DMAC_CHANCFG_PKTHALT_SHIFT 1 @@ -70,28 +70,28 @@ #define DMAC_CHANCFG_FLOWC_EN_MASK (1 << DMAC_CHANCFG_FLOWC_EN_SHIFT) /* Interrupt Control/Status register */ -#define DMAC_IR_REG (0x4) +#define DMAC_IR_REG 0x4 #define DMAC_IR_BUFDONE_MASK (1 << 0) #define DMAC_IR_PKTDONE_MASK (1 << 1) #define DMAC_IR_NOTOWNER_MASK (1 << 2) /* Interrupt Mask register */ -#define DMAC_IRMASK_REG (0x8) +#define DMAC_IRMASK_REG 0x8 /* Maximum Burst Length */ -#define DMAC_MAXBURST_REG (0xc) +#define DMAC_MAXBURST_REG 0xc /* Ring Start Address register */ -#define DMAS_RSTART_REG (0x0) +#define DMAS_RSTART_REG 0x0 /* State Ram Word 2 */ -#define DMAS_SRAM2_REG (0x4) +#define DMAS_SRAM2_REG 0x4 /* State Ram Word 3 */ -#define DMAS_SRAM3_REG (0x8) +#define DMAS_SRAM3_REG 0x8 /* State Ram Word 4 */ -#define DMAS_SRAM4_REG (0xc) +#define DMAS_SRAM4_REG 0xc struct bcm6368_enetsw_desc { u32 len_stat; @@ -224,9 +224,6 @@ struct bcm6368_enetsw { /* dma channel width */ unsigned int dma_chan_width; - - /* dma descriptor shift value */ - unsigned int dma_desc_shift; }; static inline void dma_writel(struct bcm6368_enetsw *priv, u32 val, u32 off) @@ -256,9 +253,7 @@ static inline void dmas_writel(struct bcm6368_enetsw *priv, u32 val, */ static int bcm6368_enetsw_refill_rx(struct net_device *dev) { - struct bcm6368_enetsw *priv; - - priv = netdev_priv(dev); + struct bcm6368_enetsw *priv = netdev_priv(dev); while (priv->rx_desc_count < priv->rx_ring_size) { struct bcm6368_enetsw_desc *desc; @@ -284,8 +279,7 @@ static int bcm6368_enetsw_refill_rx(struct net_device *dev) len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT; len_stat |= DMADESC_OWNER_MASK; if (priv->rx_dirty_desc == priv->rx_ring_size - 1) { - len_stat |= (DMADESC_WRAP_MASK >> - priv->dma_desc_shift); + len_stat |= DMADESC_WRAP_MASK; priv->rx_dirty_desc = 0; } else { priv->rx_dirty_desc++; @@ -328,13 +322,9 @@ static void bcm6368_enetsw_refill_rx_timer(struct timer_list *t) */ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) { - struct bcm6368_enetsw *priv; - struct device *kdev; - int processed; - - priv = netdev_priv(dev); - kdev = &priv->pdev->dev; - processed = 0; + struct bcm6368_enetsw *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + int processed = 0; /* don't scan ring further than number of refilled * descriptor */ @@ -369,8 +359,7 @@ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) /* if the packet does not have start of packet _and_ * end of packet flag set, then just recycle it */ - if ((len_stat & (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) - != (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) { + if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) { dev->stats.rx_dropped++; continue; } @@ -427,11 +416,8 @@ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) */ static int bcm6368_enetsw_tx_reclaim(struct net_device *dev, int force) { - struct bcm6368_enetsw *priv; - int released; - - priv = netdev_priv(dev); - released = 0; + struct bcm6368_enetsw *priv = netdev_priv(dev); + int released = 0; while (priv->tx_desc_count < priv->tx_ring_size) { struct bcm6368_enetsw_desc *desc; @@ -482,13 +468,10 @@ static int bcm6368_enetsw_tx_reclaim(struct net_device *dev, int force) */ static int bcm6368_enetsw_poll(struct napi_struct *napi, int budget) { - struct bcm6368_enetsw *priv; - struct net_device *dev; + struct bcm6368_enetsw *priv = container_of(napi, struct bcm6368_enetsw, napi); + struct net_device *dev = priv->net_dev; int rx_work_done; - priv = container_of(napi, struct bcm6368_enetsw, napi); - dev = priv->net_dev; - /* ack interrupts */ dmac_writel(priv, priv->dma_chan_int_mask, DMAC_IR_REG, priv->rx_chan); @@ -525,11 +508,8 @@ static int bcm6368_enetsw_poll(struct napi_struct *napi, int budget) */ static irqreturn_t bcm6368_enetsw_isr_dma(int irq, void *dev_id) { - struct net_device *dev; - struct bcm6368_enetsw *priv; - - dev = dev_id; - priv = netdev_priv(dev); + struct net_device *dev = dev_id; + struct bcm6368_enetsw *priv = netdev_priv(dev); /* mask rx/tx interrupts */ dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->rx_chan); @@ -546,13 +526,11 @@ static irqreturn_t bcm6368_enetsw_isr_dma(int irq, void *dev_id) static netdev_tx_t bcm6368_enetsw_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct bcm6368_enetsw *priv; + struct bcm6368_enetsw *priv = netdev_priv(dev); struct bcm6368_enetsw_desc *desc; u32 len_stat; netdev_tx_t ret; - priv = netdev_priv(dev); - /* lock against tx reclaim */ spin_lock(&priv->tx_lock); @@ -567,8 +545,8 @@ bcm6368_enetsw_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* pad small packets */ - if (skb->len < 64) { - int needed = 64 - skb->len; + if (skb->len < (ETH_ZLEN + ETH_FCS_LEN)) { + int needed = (ETH_ZLEN + ETH_FCS_LEN) - skb->len; char *data; if (unlikely(skb_tailroom(skb) < needed)) { @@ -579,6 +557,7 @@ bcm6368_enetsw_start_xmit(struct sk_buff *skb, struct net_device *dev) ret = NETDEV_TX_BUSY; goto out_unlock; } + dev_kfree_skb(skb); skb = nskb; } @@ -594,13 +573,13 @@ bcm6368_enetsw_start_xmit(struct sk_buff *skb, struct net_device *dev) DMA_TO_DEVICE); len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK; - len_stat |= (DMADESC_ESOP_MASK >> priv->dma_desc_shift) | - DMADESC_APPEND_CRC | DMADESC_OWNER_MASK; + len_stat |= DMADESC_ESOP_MASK | DMADESC_APPEND_CRC | + DMADESC_OWNER_MASK; priv->tx_curr_desc++; if (priv->tx_curr_desc == priv->tx_ring_size) { priv->tx_curr_desc = 0; - len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift); + len_stat |= DMADESC_WRAP_MASK; } priv->tx_desc_count--; @@ -632,33 +611,30 @@ out_unlock: */ static void bcm6368_enetsw_disable_dma(struct bcm6368_enetsw *priv, int chan) { - int limit; + int limit = 1000; dmac_writel(priv, 0, DMAC_CHANCFG_REG, chan); - limit = 1000; do { u32 val; val = dma_readl(priv, DMAC_CHANCFG_REG, chan); if (!(val & DMAC_CHANCFG_EN_MASK)) break; + udelay(1); } while (limit--); } static int bcm6368_enetsw_open(struct net_device *dev) { - struct bcm6368_enetsw *priv; - struct device *kdev; + struct bcm6368_enetsw *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; int i, ret; unsigned int size; void *p; u32 val; - priv = netdev_priv(dev); - kdev = &priv->pdev->dev; - /* mask all interrupts and request them */ dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->rx_chan); dmac_writel(priv, 0, DMAC_IRMASK_REG, priv->tx_chan); @@ -828,13 +804,10 @@ out_freeirq: static int bcm6368_enetsw_stop(struct net_device *dev) { - struct bcm6368_enetsw *priv; - struct device *kdev; + struct bcm6368_enetsw *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; int i; - priv = netdev_priv(dev); - kdev = &priv->pdev->dev; - netif_stop_queue(dev); napi_disable(&priv->napi); del_timer_sync(&priv->rx_timeout); @@ -1103,7 +1076,7 @@ static const struct of_device_id bcm6368_enetsw_of_match[] = { { .compatible = "brcm,bcm63268-enetsw", }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, bcm6368_mdio_ids); +MODULE_DEVICE_TABLE(of, bcm6368_enetsw_of_match); static struct platform_driver bcm6368_enetsw_driver = { .driver = {