Skip to content

Instantly share code, notes, and snippets.

@inoremap
Last active September 8, 2022 13:03
Show Gist options
  • Save inoremap/9f846a625d1573b33024b40898ed4c6c to your computer and use it in GitHub Desktop.
Save inoremap/9f846a625d1573b33024b40898ed4c6c to your computer and use it in GitHub Desktop.
diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk
index 2e21392016..1fdd5aa7df 100644
--- a/include/kernel-defaults.mk
+++ b/include/kernel-defaults.mk
@@ -118,7 +118,7 @@ define Kernel/Configure/Default
cp $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.prev; \
}
$(_SINGLE) [ -d $(LINUX_DIR)/user_headers ] || $(KERNEL_MAKE) INSTALL_HDR_PATH=$(LINUX_DIR)/user_headers headers_install
- grep '=[ym]' $(LINUX_DIR)/.config.set | LC_ALL=C sort | $(MKHASH) md5 > $(LINUX_DIR)/.vermagic
+ grep '=[ym]' $(LINUX_DIR)/.config.set | grep -v CONFIG_MTD_SERCOMM_PARTS | LC_ALL=C sort | $(MKHASH) md5 > $(LINUX_DIR)/.vermagic
endef
define Kernel/Configure/Initramfs
diff --git a/package/boot/uboot-envtools/files/ramips b/package/boot/uboot-envtools/files/ramips
index dfcaf56f81..6688ecb497 100644
--- a/package/boot/uboot-envtools/files/ramips
+++ b/package/boot/uboot-envtools/files/ramips
@@ -31,6 +31,10 @@ ampedwireless,ally-00x19k|\
ampedwireless,ally-r1900k)
ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x20000" "4"
;;
+beeline,smartbox-turbo-plus|\
+sercomm,s3)
+ ubootenv_add_uci_config "/dev/mtd0" "0x80000" "0x1000" "0x20000"
+ ;;
buffalo,wsr-1166dhp|\
buffalo,wsr-600dhp|\
mediatek,linkit-smart-7688|\
diff --git a/scripts/sercomm-kernel-header.py b/scripts/sercomm-kernel-header.py
new file mode 100755
index 0000000000..bfb29c6fe0
--- /dev/null
+++ b/scripts/sercomm-kernel-header.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+"""
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# sercomm-kernel-header.py: Creates Sercomm kernel header
+#
+# Copyright © 2022 Mikhail Zhilkin
+"""
+
+import argparse
+import binascii
+import os
+import struct
+
+KERNEL_HEADER_SIZE = 0x100
+PADDING = 0xff
+ROOTFS_FAKE_HEADER = "UBI#"
+
+def auto_int(x):
+ return int(x, 0)
+
+def create_kernel_header(args):
+ out_file = open(args.header_file, "wb")
+ header = get_kernel_header(args)
+ out_file.write(header)
+ out_file.close()
+
+def get_kernel_header(args):
+ header = bytearray([PADDING] * KERNEL_HEADER_SIZE)
+
+ struct.pack_into('<L', header, 0xc, 0xffffff02)
+ struct.pack_into('<L', header, 0x1c, 0x0)
+ struct.pack_into('<L', header, 0x34, 0x0)
+ struct.pack_into('<L', header, 0x10, args.kernel_offset)
+ struct.pack_into('<L', header, 0x28, args.rootfs_offset)
+
+ if (args.rootfs_file):
+ if (args.rootfs_checking_size):
+ rootfs_size = args.rootfs_checking_size
+ else:
+ rootfs_size = os.path.getsize(args.rootfs_file)
+ buf = open(args.rootfs_file,'rb').read(rootfs_size)
+ crc = binascii.crc32(buf) & 0xffffffff
+ else:
+ rootfs_size = len(ROOTFS_FAKE_HEADER)
+ crc = binascii.crc32(str.encode(ROOTFS_FAKE_HEADER)) & \
+ 0xffffffff
+ struct.pack_into('<L', header, 0x2c, rootfs_size)
+ struct.pack_into('<L', header, 0x30, crc)
+
+ rootfs_end_offset = args.rootfs_offset + rootfs_size
+ struct.pack_into('<L', header, 0x4, rootfs_end_offset)
+
+ kernel_size = os.path.getsize(args.kernel_file)
+ struct.pack_into('<L', header, 0x14, kernel_size)
+
+ buf = open(args.kernel_file,'rb').read()
+ crc = binascii.crc32(buf) & 0xffffffff
+ struct.pack_into('<L', header, 0x18, crc)
+
+ crc = binascii.crc32(header) & 0xffffffff
+ struct.pack_into('<L', header, 0x8, crc)
+
+ struct.pack_into('<L', header, 0x0, 0x726553)
+
+ return header
+
+def main():
+ global args
+
+ parser = argparse.ArgumentParser(description='This script generates \
+ a kernel header for the Sercomm mt7621 devices')
+
+ parser.add_argument('--kernel-image',
+ dest='kernel_file',
+ action='store',
+ type=str,
+ help='Path to a Kernel binary image')
+
+ parser.add_argument('--kernel-offset',
+ dest='kernel_offset',
+ action='store',
+ type=auto_int,
+ help='Kernel offset')
+
+ parser.add_argument('--rootfs-offset',
+ dest='rootfs_offset',
+ action='store',
+ type=auto_int,
+ help='RootFS offset')
+
+ parser.add_argument('--output-header',
+ dest='header_file',
+ action='store',
+ type=str,
+ help='Output kernel header file')
+
+ parser.add_argument('--rootfs-image',
+ dest='rootfs_file',
+ action='store',
+ type=str,
+ help='Path to RootFS binary image (optional)')
+
+ parser.add_argument('--rootfs-checking-size',
+ dest='rootfs_checking_size',
+ action='store',
+ type=auto_int,
+ help='Bytes count for CRC calculation (optional)')
+
+ args = parser.parse_args()
+
+ if ((not args.kernel_file) or
+ (not args.kernel_offset) or
+ (not args.rootfs_offset) or
+ (not args.header_file)):
+ parser.print_help()
+ exit()
+
+ create_kernel_header(args)
+
+main()
diff --git a/scripts/sercomm-pid.py b/scripts/sercomm-pid.py
new file mode 100755
index 0000000000..b89977a5b9
--- /dev/null
+++ b/scripts/sercomm-pid.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+"""
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# sercomm-pid.py: Creates Sercomm device PID
+#
+# Copyright © 2022 Mikhail Zhilkin
+"""
+
+import argparse
+import binascii
+import struct
+
+PID_SIZE = 0x70
+PADDING = 0x30
+PADDING_TAIL = 0x0
+
+def auto_int(x):
+ return int(x, 0)
+
+def create_pid_file(args):
+ pid_file = open(args.pid_file, "wb")
+ buf = get_pid(args)
+ pid_file.write(buf)
+ pid_file.close()
+
+def get_pid(args):
+ buf = bytearray([PADDING] * PID_SIZE)
+
+ enc = args.hw_version.rjust(8, '0').encode('ascii')
+ struct.pack_into('>8s', buf, 0x0, enc)
+
+ enc = binascii.hexlify(args.hw_id.encode())
+ struct.pack_into('>6s', buf, 0x8, enc)
+
+ enc = args.sw_version.rjust(4, '0').encode('ascii')
+ struct.pack_into('>4s', buf, 0x64, enc)
+
+ if (args.extra_padd_size):
+ tail = bytearray([PADDING_TAIL] * args.extra_padd_size)
+ if (args.extra_padd_byte):
+ struct.pack_into ('<i', tail, 0x0,
+ args.extra_padd_byte)
+ buf += tail
+
+ return buf
+
+def main():
+ global args
+
+ parser = argparse.ArgumentParser(description='This script \
+ generates firmware PID for the Sercomm-based devices')
+
+ parser.add_argument('--hw-version',
+ dest='hw_version',
+ action='store',
+ type=str,
+ help='Sercomm hardware version')
+
+ parser.add_argument('--hw-id',
+ dest='hw_id',
+ action='store',
+ type=str,
+ help='Sercomm hardware ID')
+
+ parser.add_argument('--sw-version',
+ dest='sw_version',
+ action='store',
+ type=str,
+ help='Sercomm software version')
+
+ parser.add_argument('--pid-file',
+ dest='pid_file',
+ action='store',
+ type=str,
+ help='Output PID file')
+
+ parser.add_argument('--extra-padding-size',
+ dest='extra_padd_size',
+ action='store',
+ type=auto_int,
+ help='Size of extra NULL padding at the end of the file \
+ (optional)')
+
+ parser.add_argument('--extra-padding-first-byte',
+ dest='extra_padd_byte',
+ action='store',
+ type=auto_int,
+ help='First byte of extra padding (optional)')
+
+ args = parser.parse_args()
+
+ if ((not args.hw_version) or
+ (not args.hw_id) or
+ (not args.sw_version) or
+ (not args.pid_file)):
+ parser.print_help()
+ exit()
+
+ create_pid_file(args)
+
+main()
diff --git a/target/linux/generic/backport-5.10/411-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch b/target/linux/generic/backport-5.10/411-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch
new file mode 100644
index 0000000000..5ed6fd1b3b
--- /dev/null
+++ b/target/linux/generic/backport-5.10/411-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch
@@ -0,0 +1,301 @@
+From 9b78ef0c7997052e9eaa0f7a4513d546fa17358c Mon Sep 17 00:00:00 2001
+From: Mikhail Zhilkin <csharper2005@gmail.com>
+Date: Sun, 29 May 2022 11:07:14 +0000
+Subject: [PATCH] mtd: parsers: add support for Sercomm partitions
+
+This adds an MTD partition parser for the Sercomm partition table that
+is used in some Beeline, Netgear and Sercomm routers.
+
+The Sercomm partition map table contains real partition offsets, which
+may differ from device to device depending on the number and location of
+bad blocks on NAND.
+
+Original patch (proposed by NOGUCHI Hiroshi):
+Link: https://github.com/openwrt/openwrt/pull/1318#issuecomment-420607394
+
+Signed-off-by: NOGUCHI Hiroshi <drvlabo@gmail.com>
+Signed-off-by: Mikhail Zhilkin <csharper2005@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20220529110714.189732-1-csharper2005@gmail.com
+---
+ drivers/mtd/parsers/Kconfig | 9 ++
+ drivers/mtd/parsers/Makefile | 1 +
+ drivers/mtd/parsers/scpart.c | 248 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 258 insertions(+)
+ create mode 100644 drivers/mtd/parsers/scpart.c
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -179,3 +179,12 @@ config MTD_REDBOOT_PARTS_READONLY
+ 'FIS directory' images, enable this option.
+
+ endif # MTD_REDBOOT_PARTS
++
++config MTD_SERCOMM_PARTS
++ tristate "Sercomm partition table parser"
++ depends on MTD && RALINK
++ help
++ This provides partitions table parser for devices with Sercomm
++ partition map. This partition table contains real partition
++ offsets, which may differ from device to device depending on the
++ number and location of bad blocks on NAND.
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -10,5 +10,6 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
++obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o
+ obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+--- /dev/null
++++ b/drivers/mtd/parsers/scpart.c
+@@ -0,0 +1,248 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * drivers/mtd/scpart.c: Sercomm Partition Parser
++ *
++ * Copyright (C) 2018 NOGUCHI Hiroshi
++ * Copyright (C) 2022 Mikhail Zhilkin
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/module.h>
++
++#define MOD_NAME "scpart"
++
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
++
++#define pr_fmt(fmt) MOD_NAME ": " fmt
++
++#define ID_ALREADY_FOUND 0xffffffffUL
++
++#define MAP_OFFS_IN_BLK 0x800
++#define MAP_MIRROR_NUM 2
++
++static const char sc_part_magic[] = {
++ 'S', 'C', 'F', 'L', 'M', 'A', 'P', 'O', 'K', '\0',
++};
++#define PART_MAGIC_LEN sizeof(sc_part_magic)
++
++/* assumes that all fields are set by CPU native endian */
++struct sc_part_desc {
++ uint32_t part_id;
++ uint32_t part_offs;
++ uint32_t part_bytes;
++};
++
++static uint32_t scpart_desc_is_valid(struct sc_part_desc *pdesc)
++{
++ return ((pdesc->part_id != 0xffffffffUL) &&
++ (pdesc->part_offs != 0xffffffffUL) &&
++ (pdesc->part_bytes != 0xffffffffUL));
++}
++
++static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs,
++ struct sc_part_desc **ppdesc)
++{
++ int cnt = 0;
++ int res = 0;
++ int res2;
++ loff_t offs;
++ size_t retlen;
++ struct sc_part_desc *pdesc = NULL;
++ struct sc_part_desc *tmpdesc;
++ uint8_t *buf;
++
++ buf = kzalloc(master->erasesize, GFP_KERNEL);
++ if (!buf) {
++ res = -ENOMEM;
++ goto out;
++ }
++
++ res2 = mtd_read(master, partmap_offs, master->erasesize, &retlen, buf);
++ if (res2 || retlen != master->erasesize) {
++ res = -EIO;
++ goto free;
++ }
++
++ for (offs = MAP_OFFS_IN_BLK;
++ offs < master->erasesize - sizeof(*tmpdesc);
++ offs += sizeof(*tmpdesc)) {
++ tmpdesc = (struct sc_part_desc *)&buf[offs];
++ if (!scpart_desc_is_valid(tmpdesc))
++ break;
++ cnt++;
++ }
++
++ if (cnt > 0) {
++ int bytes = cnt * sizeof(*pdesc);
++
++ pdesc = kcalloc(cnt, sizeof(*pdesc), GFP_KERNEL);
++ if (!pdesc) {
++ res = -ENOMEM;
++ goto free;
++ }
++ memcpy(pdesc, &(buf[MAP_OFFS_IN_BLK]), bytes);
++
++ *ppdesc = pdesc;
++ res = cnt;
++ }
++
++free:
++ kfree(buf);
++
++out:
++ return res;
++}
++
++static int scpart_find_partmap(struct mtd_info *master,
++ struct sc_part_desc **ppdesc)
++{
++ int magic_found = 0;
++ int res = 0;
++ int res2;
++ loff_t offs = 0;
++ size_t retlen;
++ uint8_t rdbuf[PART_MAGIC_LEN];
++
++ while ((magic_found < MAP_MIRROR_NUM) &&
++ (offs < master->size) &&
++ !mtd_block_isbad(master, offs)) {
++ res2 = mtd_read(master, offs, PART_MAGIC_LEN, &retlen, rdbuf);
++ if (res2 || retlen != PART_MAGIC_LEN) {
++ res = -EIO;
++ goto out;
++ }
++ if (!memcmp(rdbuf, sc_part_magic, PART_MAGIC_LEN)) {
++ pr_debug("Signature found at 0x%llx\n", offs);
++ magic_found++;
++ res = scpart_scan_partmap(master, offs, ppdesc);
++ if (res > 0)
++ goto out;
++ }
++ offs += master->erasesize;
++ }
++
++out:
++ if (res > 0)
++ pr_info("Valid 'SC PART MAP' (%d partitions) found at 0x%llx\n", res, offs);
++ else
++ pr_info("No valid 'SC PART MAP' was found\n");
++
++ return res;
++}
++
++static int scpart_parse(struct mtd_info *master,
++ const struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ const char *partname;
++ int n;
++ int nr_scparts;
++ int nr_parts = 0;
++ int res = 0;
++ struct sc_part_desc *scpart_map = NULL;
++ struct mtd_partition *parts = NULL;
++ struct device_node *mtd_node;
++ struct device_node *ofpart_node;
++ struct device_node *pp;
++
++ mtd_node = mtd_get_of_node(master);
++ if (!mtd_node) {
++ res = -ENOENT;
++ goto out;
++ }
++
++ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++ if (!ofpart_node) {
++ pr_info("%s: 'partitions' subnode not found on %pOF.\n",
++ master->name, mtd_node);
++ res = -ENOENT;
++ goto out;
++ }
++
++ nr_scparts = scpart_find_partmap(master, &scpart_map);
++ if (nr_scparts <= 0) {
++ pr_info("No any partitions was found in 'SC PART MAP'.\n");
++ res = -ENOENT;
++ goto free;
++ }
++
++ parts = kcalloc(of_get_child_count(ofpart_node), sizeof(*parts),
++ GFP_KERNEL);
++ if (!parts) {
++ res = -ENOMEM;
++ goto free;
++ }
++
++ for_each_child_of_node(ofpart_node, pp) {
++ u32 scpart_id;
++
++ if (of_property_read_u32(pp, "sercomm,scpart-id", &scpart_id))
++ continue;
++
++ for (n = 0 ; n < nr_scparts ; n++)
++ if ((scpart_map[n].part_id != ID_ALREADY_FOUND) &&
++ (scpart_id == scpart_map[n].part_id))
++ break;
++ if (n >= nr_scparts)
++ /* not match */
++ continue;
++
++ /* add the partition found in OF into MTD partition array */
++ parts[nr_parts].offset = scpart_map[n].part_offs;
++ parts[nr_parts].size = scpart_map[n].part_bytes;
++ parts[nr_parts].of_node = pp;
++
++ if (!of_property_read_string(pp, "label", &partname))
++ parts[nr_parts].name = partname;
++ if (of_property_read_bool(pp, "read-only"))
++ parts[nr_parts].mask_flags |= MTD_WRITEABLE;
++ if (of_property_read_bool(pp, "lock"))
++ parts[nr_parts].mask_flags |= MTD_POWERUP_LOCK;
++
++ /* mark as 'done' */
++ scpart_map[n].part_id = ID_ALREADY_FOUND;
++
++ nr_parts++;
++ }
++
++ if (nr_parts > 0) {
++ *pparts = parts;
++ res = nr_parts;
++ } else
++ pr_info("No partition in OF matches partition ID with 'SC PART MAP'.\n");
++
++ of_node_put(pp);
++
++free:
++ kfree(scpart_map);
++ if (res <= 0)
++ kfree(parts);
++
++out:
++ return res;
++}
++
++static const struct of_device_id scpart_parser_of_match_table[] = {
++ { .compatible = "sercomm,sc-partitions" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, scpart_parser_of_match_table);
++
++static struct mtd_part_parser scpart_parser = {
++ .parse_fn = scpart_parse,
++ .name = "scpart",
++ .of_match_table = scpart_parser_of_match_table,
++};
++module_mtd_part_parser(scpart_parser);
++
++/* mtd parsers will request the module by parser name */
++MODULE_ALIAS("scpart");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("NOGUCHI Hiroshi <drvlabo@gmail.com>");
++MODULE_AUTHOR("Mikhail Zhilkin <csharper2005@gmail.com>");
++MODULE_DESCRIPTION("Sercomm partition parser");
diff --git a/target/linux/generic/pending-5.10/435-mtd-add-routerbootpart-parser-config.patch b/target/linux/generic/pending-5.10/435-mtd-add-routerbootpart-parser-config.patch
index ab1e09a5f1..446bc0bef1 100644
--- a/target/linux/generic/pending-5.10/435-mtd-add-routerbootpart-parser-config.patch
+++ b/target/linux/generic/pending-5.10/435-mtd-add-routerbootpart-parser-config.patch
@@ -16,10 +16,10 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
-@@ -195,3 +195,12 @@ config MTD_REDBOOT_PARTS_READONLY
- 'FIS directory' images, enable this option.
-
- endif # MTD_REDBOOT_PARTS
+@@ -204,3 +204,12 @@ config MTD_SERCOMM_PARTS
+ partition map. This partition table contains real partition
+ offsets, which may differ from device to device depending on the
+ number and location of bad blocks on NAND.
+
+config MTD_ROUTERBOOT_PARTS
+ tristate "RouterBoot flash partition parser"
@@ -31,8 +31,8 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
+ formatted DTS.
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
-@@ -13,3 +13,4 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
- obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
+@@ -14,3 +14,4 @@ obj-$(CONFIG_MTD_PARSER_TRX) += parser_
+ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o
diff --git a/target/linux/ramips/dts/mt7621_beeline_smartbox-turbo-plus.dts b/target/linux/ramips/dts/mt7621_beeline_smartbox-turbo-plus.dts
new file mode 100644
index 0000000000..547848a3c5
--- /dev/null
+++ b/target/linux/ramips/dts/mt7621_beeline_smartbox-turbo-plus.dts
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "mt7621_sercomm_s3.dtsi"
+
+/ {
+ compatible = "beeline,smartbox-turbo-plus", "mediatek,mt7621-soc";
+ model = "Beeline SmartBox TURBO+"; // Sercomm S3 CQR
+
+ aliases {
+ label-mac-device = &gmac0;
+ };
+
+ ubi-concat {
+ compatible = "mtd-concat";
+ devices = <&ubiconcat0 &ubiconcat1 &ubiconcat2>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 { // 81408 KiB = 79,5 MiB
+ label = "ubi";
+ reg = <0x0 0x4f80000>;
+ };
+ };
+ };
+};
+
+&uartlite3 { // ZigBee EFR32 MG1B232GG
+ status = "okay";
+ current-speed = <57600>;
+};
+
+&nand {
+ status = "okay";
+
+ partitions {
+ compatible = "sercomm,sc-partitions", "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "Boot Loader";
+ reg = <0x0 0x100000>;
+ sercomm,scpart-id = <0>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "dynamic partition map";
+ reg = <0x100000 0x100000>;
+ sercomm,scpart-id = <1>;
+ read-only;
+ };
+
+ factory: partition@200000 {
+ label = "Factory";
+ reg = <0x200000 0x100000>;
+ sercomm,scpart-id = <2>;
+ read-only;
+
+ compatible = "nvmem-cells";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ macaddr_factory_21000: macaddr@21000 {
+ reg = <0x21000 0x6>;
+ };
+ };
+
+ partition@300000 {
+ label = "Boot Flag";
+ reg = <0x300000 0x100000>;
+ sercomm,scpart-id = <3>;
+ };
+
+ partition@400000 {
+ label = "kernel"; // Kernel 1
+ reg = <0x400000 0x600000>;
+ sercomm,scpart-id = <4>;
+ };
+
+ partition@a00000 {
+ label = "Kernel 2";
+ reg = <0xa00000 0x600000>;
+ sercomm,scpart-id = <5>;
+ read-only;
+ };
+
+ ubiconcat0: partition@1000000 {
+ label = "File System 1";
+ reg = <0x1000000 0x2000000>;
+ sercomm,scpart-id = <6>;
+ };
+
+ partition@3000000 {
+ label = "File System 2";
+ reg = <0x3000000 0x2000000>;
+ sercomm,scpart-id = <7>;
+ read-only;
+ };
+
+ ubiconcat1: partition@5000000 {
+ label = "Configuration/log";
+ reg = <0x5000000 0x1400000>;
+ sercomm,scpart-id = <8>;
+ };
+
+ ubiconcat2: partition@6400000 {
+ label = "application tmp buffer (Ftool)";
+ reg = <0x6400000 0x1b80000>;
+ sercomm,scpart-id = <9>;
+ };
+
+ /*
+ * 512 KiB Bad Block Table
+ * 0x8000000-0x7f80000=0x80000
+ */
+ };
+};
+
+&gmac0 {
+ nvmem-cells = <&macaddr_factory_21000>;
+ nvmem-cell-names = "mac-address";
+};
+
+&wan {
+ nvmem-cells = <&macaddr_factory_21000>;
+ nvmem-cell-names = "mac-address";
+ mac-address-increment = <1>;
+};
+
+&wlan_2g {
+ mediatek,mtd-eeprom = <&factory 0x0>;
+};
+
+&wlan_5g {
+ mediatek,mtd-eeprom = <&factory 0x8000>;
+};
diff --git a/target/linux/ramips/dts/mt7621_sercomm_s3.dts b/target/linux/ramips/dts/mt7621_sercomm_s3.dts
new file mode 100644
index 0000000000..1203d94d26
--- /dev/null
+++ b/target/linux/ramips/dts/mt7621_sercomm_s3.dts
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "mt7621_sercomm_s3.dtsi"
+
+/ {
+ compatible = "sercomm,s3", "mediatek,mt7621-soc";
+ model = "Sercomm S3"; // Etisalat Sercomm S3 AC2100 (Sercomm S3 DDK)
+
+ aliases {
+ label-mac-device = &gmac0;
+ };
+};
+
+&nand {
+ status = "okay";
+
+ partitions {
+ compatible = "sercomm,sc-partitions", "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "Boot Loader";
+ reg = <0x0 0x100000>;
+ sercomm,scpart-id = <0>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "dynamic partition map";
+ reg = <0x100000 0x100000>;
+ sercomm,scpart-id = <1>;
+ read-only;
+ };
+
+ factory: partition@200000 {
+ label = "Factory";
+ reg = <0x200000 0x100000>;
+ sercomm,scpart-id = <2>;
+ read-only;
+ };
+
+ partition@300000 {
+ label = "Boot Flag";
+ reg = <0x300000 0x100000>;
+ sercomm,scpart-id = <3>;
+ };
+
+ partition@400000 {
+ label = "kernel";
+ reg = <0x400000 0x600000>;
+ sercomm,scpart-id = <4>;
+ };
+
+ partition@a00000 {
+ label = "Kernel 2";
+ reg = <0xa00000 0x600000>;
+ sercomm,scpart-id = <5>;
+ read-only;
+ };
+
+ partition@1000000 {
+ label = "ubi";
+ reg = <0x1000000 0x2000000>;
+ sercomm,scpart-id = <6>;
+ };
+
+ partition@3000000 {
+ label = "File System 2";
+ reg = <0x3000000 0x2000000>;
+ sercomm,scpart-id = <7>;
+ read-only;
+ };
+
+ partition@5000000 {
+ label = "Configuration/log";
+ reg = <0x5000000 0x1400000>;
+ sercomm,scpart-id = <8>;
+ read-only;
+ };
+
+ partition@6400000 {
+ label = "Debug (Ftool)";
+ reg = <0x6400000 0x1b80000>;
+ sercomm,scpart-id = <9>;
+ read-only;
+ };
+
+ /*
+ * 512 KiB bad block reserved
+ */
+ };
+};
+
+&factory {
+ compatible = "nvmem-cells";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ macaddr_factory_21000: macaddr@21000 {
+ reg = <0x21000 0x6>;
+ };
+};
+
+&gmac0 {
+ nvmem-cells = <&macaddr_factory_21000>;
+ nvmem-cell-names = "mac-address";
+};
+
+&wan {
+ nvmem-cells = <&macaddr_factory_21000>;
+ nvmem-cell-names = "mac-address";
+ mac-address-increment = <1>;
+};
+
+&wlan_2g {
+ mediatek,mtd-eeprom = <&factory 0x0>;
+};
+
+&wlan_5g {
+ mediatek,mtd-eeprom = <&factory 0x8000>;
+};
+
+// TODO:
+// ? MACs interfaces
+// LED 2.4 GHz & 5 GHz
+
diff --git a/target/linux/ramips/dts/mt7621_sercomm_s3.dtsi b/target/linux/ramips/dts/mt7621_sercomm_s3.dtsi
new file mode 100644
index 0000000000..c783883b18
--- /dev/null
+++ b/target/linux/ramips/dts/mt7621_sercomm_s3.dtsi
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "mt7621.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+ aliases {
+ led-boot = &led_status_green;
+ led-failsafe = &led_status_red;
+ led-running = &led_status_green;
+ led-upgrade = &led_status_red;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_status_red: status_red {
+ label = "red:status";
+ color = <LED_COLOR_ID_RED>;
+ function = LED_FUNCTION_STATUS;
+ gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
+ };
+
+ led_status_green: status_green {
+ label = "green:status";
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_STATUS;
+ gpios = <&gpio 15 GPIO_ACTIVE_HIGH>;
+ };
+
+ led_status_blue: status_blue {
+ label = "blue:status";
+ color = <LED_COLOR_ID_BLUE>;
+ function = LED_FUNCTION_STATUS;
+ gpios = <&gpio 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ keys {
+ compatible = "gpio-keys";
+
+ wps {
+ label = "WPS Button";
+ gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+
+ reset {
+ label = "Reset Button";
+ gpios = <&gpio 14 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+};
+
+&pcie {
+ status = "okay";
+};
+
+&pcie0 {
+ wlan_5g: wifi@0,0 {
+ compatible = "mediatek,mt76";
+ reg = <0x0 0 0 0 0>;
+ ieee80211-freq-limit = <5000000 6000000>;
+ };
+};
+
+&pcie1 {
+ wlan_2g: wifi@0,0 {
+ compatible = "mediatek,mt76";
+ reg = <0x0 0 0 0 0>;
+ ieee80211-freq-limit = <2400000 2500000>;
+ };
+};
+
+&switch0 {
+ ports {
+ wan: port@0 {
+ status = "okay";
+ label = "wan";
+ };
+
+ port@1 {
+ status = "okay";
+ label = "lan1";
+ };
+
+ port@2 {
+ status = "okay";
+ label = "lan2";
+ };
+
+ port@3 {
+ status = "okay";
+ label = "lan3";
+ };
+
+ port@4 {
+ status = "okay";
+ label = "lan4";
+ };
+ };
+};
+
+&state_default {
+ gpio {
+ groups = "jtag", "uart2";
+ function = "gpio";
+ };
+};
diff --git a/target/linux/ramips/image/Makefile b/target/linux/ramips/image/Makefile
index f481e6e447..d48b220231 100644
--- a/target/linux/ramips/image/Makefile
+++ b/target/linux/ramips/image/Makefile
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
-DEVICE_VARS += LOADER_TYPE LOADER_FLASH_OFFS
+DEVICE_VARS += LOADER_TYPE LOADER_FLASH_OFFS LZMA_TEXT_START
DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID
DEVICE_VARS += BUFFALO_TAG_PLATFORM BUFFALO_TAG_VERSION BUFFALO_TAG_MINOR
DEVICE_VARS += SEAMA_SIGNATURE SEAMA_MTDBLOCK
@@ -22,6 +22,7 @@ ldrplatform-$(CONFIG_TARGET_ramips_mt7621) := mt7621
ldrflashstart-y := 0x1c000000
ldrflashstart-$(CONFIG_TARGET_ramips_mt7621) := 0x1fc00000
+LOADADDR := $(loadaddr-y)
LOADER_PLATFORM := $(ldrplatform-y)
LOADER_FLASH_START := $(ldrflashstart-y)
@@ -45,7 +46,8 @@ define Build/loader-common
PKG_BUILD_DIR="$@.src" \
TARGET_DIR="$(dir $@)" LOADER_NAME="$(notdir $@)" \
BOARD="$(BOARDNAME)" PLATFORM="$(LOADER_PLATFORM)" \
- LZMA_TEXT_START=0x81800000 LOADADDR=$(KERNEL_LOADADDR) \
+ LZMA_TEXT_START=$(LZMA_TEXT_START) \
+ LOADADDR=$(LOADADDR) \
$(1) compile loader.$(LOADER_TYPE)
mv "$@.$(LOADER_TYPE)" "$@"
rm -rf $@.src
@@ -176,6 +178,7 @@ define Device/Default
PROFILES = Default
KERNEL := $(KERNEL_DTB) | uImage lzma
KERNEL_LOADADDR := $(loadaddr-y)
+ LZMA_TEXT_START := 0x81800000
SOC := $(DEFAULT_SOC)
DEVICE_DTS_DIR := ../dts
DEVICE_DTS = $$(SOC)_$(1)
diff --git a/target/linux/ramips/image/common-sercomm.mk b/target/linux/ramips/image/common-sercomm.mk
new file mode 100644
index 0000000000..6e4c22ddea
--- /dev/null
+++ b/target/linux/ramips/image/common-sercomm.mk
@@ -0,0 +1,175 @@
+DEVICE_VARS += SERCOMM_KERNEL_OFFSET SERCOMM_ROOTFS_OFFSET
+DEVICE_VARS += SERCOMM_KERNEL2_OFFSET SERCOMM_ROOTFS2_OFFSET
+
+define Build/sercomm-crypto
+ $(TOPDIR)/scripts/sercomm-crypto.py \
+ --input-file $@ \
+ --key-file $@.key \
+ --output-file $@.ser \
+ --version $(SERCOMM_SWVER)
+ $(STAGING_DIR_HOST)/bin/openssl enc -md md5 -aes-256-cbc \
+ -in $@ \
+ -out $@.enc \
+ -K `cat $@.key` \
+ -iv 00000000000000000000000000000000
+ dd if=$@.enc >> $@.ser 2>/dev/null
+ mv $@.ser $@
+ rm -f $@.enc $@.key
+endef
+
+define Build/sercomm-kernel
+ $(TOPDIR)/scripts/sercomm-kernel-header.py \
+ --kernel-image $@ \
+ --kernel-offset $(SERCOMM_KERNEL_OFFSET) \
+ --rootfs-offset $(SERCOMM_ROOTFS_OFFSET) \
+ --output-header $@.hdr
+ dd if=$@ >> $@.hdr 2>/dev/null
+ mv $@.hdr $@
+endef
+
+define Build/sercomm-tag-hdr-kernel
+ $(TOPDIR)/scripts/sercomm-kernel-header.py \
+ --kernel-image $(word 1,$(1)) \
+ --kernel-offset $(word 2,$(1)) \
+ --rootfs-offset $(word 3,$(1)) \
+ --output-header $(word 4,$(1))
+endef
+
+define Build/sercomm-tag-hdr-kernel-post
+ $(call Build/sercomm-tag-hdr-kernel,$(IMAGE_KERNEL) $(word 1,$(1))
+ $(word 2,$(1)) $@.hdr)
+ dd if=$(IMAGE_KERNEL) >> $@.hdr 2>/dev/null
+ cat $@.hdr $(IMAGE_KERNEL) > $@.new
+ mv $@.new $@
+ rm -f $@.hdrkrn
+endef
+
+define Build/sercomm-part-tag
+ $(call Build/sercomm-part-tag-common,$(word 1,$(1)) $@)
+endef
+
+define Build/sercomm-part-tag-common
+ $(eval file=$(word 2,$(1)))
+ $(TOPDIR)/scripts/sercomm-partition-tag.py \
+ --input-file $(file) \
+ --output-file $(file).tmp \
+ --part-name $(word 1,$(1)) \
+ --part-version $(SERCOMM_SWVER)
+ mv $(file).tmp $(file)
+endef
+
+define Build/sercomm-payload
+ $(TOPDIR)/scripts/sercomm-pid.py \
+ --hw-version $(SERCOMM_HWVER) \
+ --hw-id $(SERCOMM_HWID) \
+ --sw-version $(SERCOMM_SWVER) \
+ --pid-file $@.pid \
+ --extra-padding-size 0x10 \
+ --extra-padding-first-byte 0x0a
+ $(TOPDIR)/scripts/sercomm-payload.py \
+ --input-file $@ \
+ --output-file $@.tmp \
+ --pid "$$(cat $@.pid | od -t x1 -An -v | tr -d '\n')"
+ mv $@.tmp $@
+ rm $@.pid
+endef
+
+define Build/sercomm-pid
+ $(TOPDIR)/scripts/sercomm-pid.py \
+ --hw-version $(SERCOMM_HWVER) \
+ --hw-id $(SERCOMM_HWID) \
+ --sw-version $(SERCOMM_SWVER) \
+ --pid-file $(word 1,$(1))
+endef
+
+define Build/sercomm-prepend-tagged-kernel
+ $(CP) $(IMAGE_KERNEL) $(IMAGE_KERNEL).tagged
+ $(call Build/sercomm-part-tag-common,$(word 1,$(1)) \
+ $(IMAGE_KERNEL).tagged)
+ dd if=$@ >> $(IMAGE_KERNEL).tagged 2>/dev/null
+ mv $(IMAGE_KERNEL).tagged $@
+endef
+
+define Build/sercomm-tag-factory-type-B
+ $(call Build/sercomm-pid,$@.hdrfactory)
+ printf $$(stat -c%s $(IMAGE_KERNEL)) | dd seek=$$((0x70)) of=$@.hdrfactory \
+ bs=1 conv=notrunc 2>/dev/null
+ printf $$(stat -c%s $@) | dd seek=$$((0x80)) of=$@.hdrfactory bs=1 \
+ conv=notrunc 2>/dev/null
+ cat $(IMAGE_KERNEL) $@ | $(MKHASH) md5 | awk '{print $$1}' | \
+ tr -d '\n' | dd seek=$$((0x1e0)) of=$@.hdrfactory bs=1 \
+ conv=notrunc 2>/dev/null
+ $(call Build/sercomm-tag-hdr-kernel,$(IMAGE_KERNEL) $(SERCOMM_KERNEL_OFFSET)
+ $(SERCOMM_ROOTFS_OFFSET) $@.hdrkrn1)
+ $(call Build/sercomm-tag-hdr-kernel,$(IMAGE_KERNEL) $(SERCOMM_KERNEL2_OFFSET)
+ $(SERCOMM_ROOTFS2_OFFSET) $@.hdrkrn2)
+ # Hack CRC for Kernel2. In case of flashing to the Sercomm1 slot,
+ # the uboot drain will switch to the Sercomm0 slot. So far, there is
+ # no support for working from both slots.
+ dd if=/dev/zero of=$@.hdrkrn2 bs=1 seek=$$((0x18)) count=4 conv=notrunc \
+ 2>/dev/null
+ cat $@.hdrfactory $@.hdrkrn1 $@.hdrkrn2 $(IMAGE_KERNEL) $@ > $@.new
+ mv $@.new $@
+ rm -f $@.hdrfactory $@.hdrkrn1 $@.hdrkrn2
+endef
+
+define Device/sercomm_dxx
+ $(Device/dsa-migration)
+ BLOCKSIZE := 128k
+ PAGESIZE := 2048
+ KERNEL_SIZE := 6144k
+ UBINIZE_OPTS := -E 5
+ LOADER_TYPE := bin
+ KERNEL_LOADADDR := 0x81001000
+ LZMA_TEXT_START := 0x82800000
+ KERNEL := kernel-bin | append-dtb | lzma | loader-kernel | lzma -a0 | \
+ uImage lzma | sercomm-kernel
+ KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | loader-kernel | \
+ lzma -a0 | uImage lzma
+ IMAGES += factory.img
+ IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+ IMAGE/factory.img := append-ubi | sercomm-part-tag rootfs | \
+ sercomm-prepend-tagged-kernel kernel | gzip | sercomm-payload | \
+ sercomm-crypto
+ SERCOMM_KERNEL_OFFSET := 0x400100
+ SERCOMM_ROOTFS_OFFSET := 0x1000000
+endef
+
+define Device/sercomm-common
+ $(Device/dsa-migration)
+ $(Device/sercomm-nand)
+ $(Device/uimage-lzma-loader-sercomm)
+ UBINIZE_OPTS := -E 5
+ LZMA_TEXT_START := 0x82800000
+ IMAGE/sysupgrade.bin := append-ubi | sercomm-tag-hdr-kernel-post \
+ $$$$(SERCOMM_KERNEL_OFFSET) $$$$(SERCOMM_ROOTFS_OFFSET) | \
+ sysupgrade-tar kernel=$$$$@ | append-metadata
+ DEVICE_ALT0_VENDOR := Sercomm
+ SERCOMM_HWID = $$(DEVICE_ALT0_VARIANT)
+endef
+
+define Device/sercomm-common-s3
+ $(Device/sercomm-common)
+ DEVICE_ALT0_MODEL := S3
+ KERNEL_SIZE := 6m
+ IMAGE_SIZE := 32m
+ KERNEL_LOADADDR := 0x81001000
+ IMAGES += factory.img
+ IMAGE/factory.img := append-ubi | sercomm-tag-factory-type-B
+ SERCOMM_KERNEL_OFFSET := 0x400100
+ SERCOMM_ROOTFS_OFFSET := 0x1000000
+ SERCOMM_KERNEL2_OFFSET := 0xA00100
+ SERCOMM_ROOTFS2_OFFSET := 0x3000000
+ DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615e kmod-mt7615-firmware \
+ kmod-usb3 uboot-envtools
+endef
+
+define Device/sercomm-nand
+ BLOCKSIZE := 128k
+ PAGESIZE := 2KiB
+endef
+
+define Device/uimage-lzma-loader-sercomm
+ LOADER_TYPE := bin
+ KERNEL := $(KERNEL_DTB) | loader-kernel | lzma -a0 | uImage lzma
+endef
diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk
index 7f903485aa..4af8e171fc 100644
--- a/target/linux/ramips/image/mt7621.mk
+++ b/target/linux/ramips/image/mt7621.mk
@@ -2,6 +2,7 @@
# MT7621 Profiles
#
+include ./common-sercomm.mk
include ./common-tp-link.mk
DEFAULT_SOC := mt7621
@@ -267,6 +268,16 @@ define Device/beeline_smartbox-flash
endef
TARGET_DEVICES += beeline_smartbox-flash
+define Device/beeline_smartbox-turbo-plus
+ $(Device/sercomm-common-s3)
+ DEVICE_VENDOR := Beeline
+ DEVICE_MODEL := SmartBox TURBO+
+ DEVICE_ALT0_VARIANT := CQR
+ SERCOMM_HWVER := 10000
+ SERCOMM_SWVER := 2010
+endef
+TARGET_DEVICES += beeline_smartbox-turbo-plus
+
define Device/buffalo_wsr-1166dhp
$(Device/dsa-migration)
$(Device/uimage-lzma-loader)
diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds
index 15e33e2f16..bd12bfda32 100644
--- a/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds
+++ b/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds
@@ -11,7 +11,8 @@ asus,rt-n56u-b1)
ucidef_set_led_netdev "lan" "LAN link" "blue:lan" "br-lan"
ucidef_set_led_netdev "wan" "WAN link" "blue:wan" "wan"
;;
-beeline,smartbox-flash)
+beeline,smartbox-flash|\
+beeline,smartbox-turbo-plus)
ucidef_set_led_netdev "wan" "wan" "blue:wan" "wan"
;;
cudy,wr2100)
diff --git a/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount b/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount
index 8382bdf0c5..63c17444db 100755
--- a/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount
+++ b/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount
@@ -8,6 +8,13 @@ boot() {
[ -n "$(fw_printenv bootcount bootchanged 2>/dev/null)" ] &&\
echo -e "bootcount\nbootchanged\n" | /usr/sbin/fw_setenv -s -
;;
+ beeline,smartbox-turbo-plus)
+ idx="$(find_mtd_index "Boot Flag")"
+ [ -n "$idx" ] && \
+ [[ $(hexdump -n 1 -e '/1 "%1d"' -s $((0x20001)) /dev/mtd$idx) == \
+ $((0xFF)) ]] || printf '\xFF\xFF' | dd of=/dev/mtdblock$idx \
+ seek=$((0x20001)) count=1 bs=1
+ ;;
linksys,e5600|\
linksys,ea6350-v4|\
linksys,ea7300-v1|\
diff --git a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh
index cf3caff702..293414e510 100755
--- a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh
@@ -55,6 +55,8 @@ platform_do_upgrade() {
asus,rt-ac85p|\
asus,rt-ax53u|\
beeline,smartbox-flash|\
+ beeline,smartbox-turbo-plus|\
+ sercomm,s3|\
dlink,dir-1960-a1|\
dlink,dir-2640-a1|\
dlink,dir-2660-a1|\
diff --git a/target/linux/ramips/mt7621/config-5.10 b/target/linux/ramips/mt7621/config-5.10
index ec6822fa6d..3ad7ae3244 100644
--- a/target/linux/ramips/mt7621/config-5.10
+++ b/target/linux/ramips/mt7621/config-5.10
@@ -163,6 +163,7 @@ CONFIG_MTD_NAND_MTK_BMT=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_ROUTERBOOT_PARTS=y
+CONFIG_MTD_SERCOMM_PARTS=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
CONFIG_MTD_SPLIT_FIT_FW=y
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment