[openwrt/openwrt] qualcommax: ipq60xx: add TP-Link EAP610-Outdoor support

LEDE Commits lede-commits at lists.infradead.org
Sun Jan 12 07:54:54 PST 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/a00ff9f6d13f6ff5eae57be70a270ccd668d5240

commit a00ff9f6d13f6ff5eae57be70a270ccd668d5240
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
AuthorDate: Sun Aug 7 10:15:35 2022 -0500

    qualcommax: ipq60xx: add TP-Link EAP610-Outdoor support
    
    TP-Link EAP610-Outdoor is a 802.11ax AP claiming AX1800 support. It is
    wall or pole mountable, and rated for outdoor use. It can only be
    powered via PoE.
    
    Specifications:
    ---------------
    * CPU: Qualcomm IPQ6018 Quad core Cortex-A53
    * RAM: 512 MB
    * Storage: ESMT PSR1GA30DT 128MB NAND
    * Ethernet:
      * Gigabit RJ45 port with PoE input
    * WLAN:
      * 2.4GHz/5GHz
    * LEDs:
      * Multi-color System LED (Green/Amber)
    * Buttons:
      * 1x Reset
    * UART: 4-pin unpopulated header
      * 1.8 V level, Pinout 1 - TX, 2 - RX, 3 - GND, 4 - 1.8V
    
    Installation:
    =============
    
    Web UI method
    -------------
    
    Set up the device using the vendor's web UI. After that go to
    Management->SSH and enable the "SSH Login" checkbox. Select "Save".
    The connect to the machine via SSH:
    
        ssh -o hostkeyalgorithms=ssh-rsa <ip_of_device>
    
    Disable signature verification:
    
        cliclientd stopcs
    
    Rename the "-web-ui-factory" image to something less than 63
    characters, maintaining the ".bin" suffix.
     * Go to System -> Firmware Update.
     * Under "New Firmware File", click "Browse" and select the image
     * Select "Update" and confirm by clicking "OK".
    
    If the update fails, the web UI should show an error message.
    Otherwise, the device should reboot into OpenWRT.
    
    TFTP method
    -----------
    
    To flash via tftp, first place the initramfs image on the TFTP server.
    
        setenv serverip <ip of tftp server>
        setenv ipaddr <ip in same subnet as tftp server>
        tftpboot tplink_eap610-outdoor-initramfs-uImage.itb
        bootm
    
    This should boot OpenWRT. Once booted, flash the sysupgrade.bin image
    using either luci or the commandline.
    
    The tplink2022 image format
    ============================
    
    The vendor images of this device are packaged in a format that does
    not match any previous tplink formats. In order for flashing to work
    from the vendor's web UI, firmware updates need to be packaged in
    this format. The `tplink-mkimage-2022.py` is provided for this
    purpose.
    
    This script can also analyze vendor images, and extract the required
    "support" string. This string is checked by the vendor firmware, and
    images with a missing or incorrect string are rejected.
    
    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
    Link: https://github.com/openwrt/openwrt/pull/14922
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 include/image-commands.mk                          |   8 +
 .../boot/uboot-envtools/files/qualcommax_ipq60xx   |   4 +
 package/firmware/ipq-wifi/Makefile                 |   2 +
 scripts/tplink-mkimage-2022.py                     | 198 +++++++++++++++++++++
 .../arm64/boot/dts/qcom/ipq6018-eap610-outdoor.dts | 151 ++++++++++++++++
 target/linux/qualcommax/image/ipq60xx.mk           |  18 ++
 .../ipq60xx/base-files/etc/board.d/02_network      |   7 +
 .../etc/hotplug.d/firmware/11-ath11k-caldata       |   7 +
 .../base-files/lib/preinit/09_mount_factory_data   |  19 ++
 .../ipq60xx/base-files/lib/upgrade/platform.sh     |  76 ++++++++
 10 files changed, 490 insertions(+)

diff --git a/include/image-commands.mk b/include/image-commands.mk
index 2e129e0347..aa48e19399 100644
--- a/include/image-commands.mk
+++ b/include/image-commands.mk
@@ -626,6 +626,14 @@ define Build/sysupgrade-tar
 		$@
 endef
 
+define Build/tplink-image-2022
+	$(TOPDIR)/scripts/tplink-mkimage-2022.py  \
+		--create $@.new \
+		--rootfs $@ \
+		--support "$(TPLINK_SUPPORT_STRING)"
+	@mv $@.new $@
+endef
+
 define Build/tplink-safeloader
 	-$(STAGING_DIR_HOST)/bin/tplink-safeloader \
 		-B $(TPLINK_BOARD_ID) \
diff --git a/package/boot/uboot-envtools/files/qualcommax_ipq60xx b/package/boot/uboot-envtools/files/qualcommax_ipq60xx
index eec99ce8f9..77c96da24a 100644
--- a/package/boot/uboot-envtools/files/qualcommax_ipq60xx
+++ b/package/boot/uboot-envtools/files/qualcommax_ipq60xx
@@ -25,6 +25,10 @@ netgear,wax214)
 	[ -n "$idx" ] && \
 		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x40000" "0x20000"
 	;;
+tplink,eap610-outdoor)
+	idx="$(find_mtd_index 0:appsblenv)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x40000" "0x20000"
 yuncore,fap650)
 	idx="$(find_mtd_index 0:appsblenv)"
 	[ -n "$idx" ] && \
diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
index 679a144211..9821e39a85 100644
--- a/package/firmware/ipq-wifi/Makefile
+++ b/package/firmware/ipq-wifi/Makefile
@@ -55,6 +55,7 @@ ALLWIFIBOARDS:= \
 	redmi_ax6 \
 	skspruce_wia3300-20 \
 	spectrum_sax1v1k \
+	tplink_eap610-outdoor \
 	tplink_eap620hd-v1 \
 	tplink_eap660hd-v1 \
 	wallys_dr40x9 \
@@ -185,6 +186,7 @@ $(eval $(call generate-ipq-wifi-package,prpl_haze,prpl Haze))
 $(eval $(call generate-ipq-wifi-package,redmi_ax6,Redmi AX6))
 $(eval $(call generate-ipq-wifi-package,skspruce_wia3300-20,SKSpruce WIA3300-20))
 $(eval $(call generate-ipq-wifi-package,spectrum_sax1v1k,Spectrum SAX1V1K))
+$(eval $(call generate-ipq-wifi-package,tplink_eap610-outdoor,TPLink EAP610-Outdoor))
 $(eval $(call generate-ipq-wifi-package,tplink_eap620hd-v1,TP-Link EAP620 HD v1))
 $(eval $(call generate-ipq-wifi-package,tplink_eap660hd-v1,TP-Link EAP660 HD v1))
 $(eval $(call generate-ipq-wifi-package,wallys_dr40x9,Wallys DR40X9))
diff --git a/scripts/tplink-mkimage-2022.py b/scripts/tplink-mkimage-2022.py
new file mode 100755
index 0000000000..4db69409c9
--- /dev/null
+++ b/scripts/tplink-mkimage-2022.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+
+'''A program for manipulating tplink2022 images.
+
+A tplink2022 is an image format encountered on TP-Link devices around the year
+2022. This was seen at least on the EAP610-Outdoor. The format is a container
+for a rootfs, and has optional fields for the "software" version. It also
+ requires a "support" string that describes the list of compatible devices.
+
+This module is intended for creating such images with an OpenWRT UBI image, but
+also supports analysis and extraction of vendor images. Altough tplink2022
+images can be signed, this program does not support signing image.
+
+To get an explanation of the commandline arguments, run this program with the
+"--help" argument.
+'''
+
+import argparse
+import hashlib
+import os
+import pprint
+import struct
+
+def decode_header(datafile):
+    '''Read the tplink2022 image header anbd decode it into a dictionary'''
+    header = {}
+    fmt = '>2I'
+
+    datafile.seek(0x1014)
+    raw_header = datafile.read(8)
+    fields = struct.unpack(fmt, raw_header)
+
+    header['rootfs_size'] = fields[0]
+    header['num_items'] = fields[1]
+    header['items'] = []
+
+    rootfs = {}
+    rootfs['name'] = 'rootfs.ubi'
+    rootfs['offset'] = 0
+    rootfs['size'] = header['rootfs_size']
+    header['items'].append(rootfs)
+
+    for _ in range(header['num_items']):
+        entry = datafile.read(0x2c)
+        fmt = '>I32s2I'
+        fields = struct.unpack(fmt, entry)
+
+        section = {}
+        section['name'] = fields[1].decode("utf-8").rstrip('\0')
+        section['type'] = fields[0]
+        section['offset'] = fields[2]
+        section['size'] = fields[3]
+        header['items'].append(section)
+    return header
+
+def extract(datafile):
+    '''Extract the sections of the tplink2022 image to separate files'''
+    header = decode_header(datafile)
+
+    pretty = pprint.PrettyPrinter(indent=4, sort_dicts=False)
+    pretty.pprint(header)
+
+    for section in header['items']:
+        datafile.seek(0x1814 + section['offset'])
+        section_contents = datafile.read(section['size'])
+
+        with open(f"{section['name']}.bin", 'wb') as section_file:
+            section_file.write(section_contents)
+
+    with open('leftover.bin', 'wb') as extras_file:
+        extras_file.write(datafile.read())
+
+def get_section_contents(section):
+    '''I don't remember what this does. It's been a year since I wrote this'''
+    if section.get('data'):
+        data = section['data']
+    elif section.get('file'):
+        with open(section['file'], 'rb') as section_file:
+            data = section_file.read()
+    else:
+        data = bytes()
+
+    if section['size'] != len(data):
+        raise ValueError("Wrong section size", len(data))
+
+    return data
+
+def write_image(output_image, header):
+    '''Write a tplink2022 image with the contents in the "header" dictionary'''
+    with open(output_image, 'w+b') as out_file:
+        # header MD5
+        salt = [ 0x7a, 0x2b, 0x15, 0xed,
+             0x9b, 0x98, 0x59, 0x6d,
+             0xe5, 0x04, 0xab, 0x44,
+             0xac, 0x2a, 0x9f, 0x4e
+        ]
+
+        out_file.seek(4)
+        out_file.write(bytes(salt))
+
+        # unknown section
+        out_file.write(bytes([0xff] * 0x1000))
+
+        # Table of contents
+        raw_header = struct.pack('>2I', header['rootfs_size'],
+                        header['num_items'])
+        out_file.write(raw_header)
+
+        for section in header['items']:
+            if section['name'] == 'rootfs.ubi':
+                continue
+
+            hdr = struct.pack('>I32s2I',
+                section.get('type', 0),
+                section['name'].encode('utf-8'),
+                section['offset'],
+                section['size']
+            )
+
+            out_file.write(hdr)
+
+        for section in header['items']:
+            out_file.seek(0x1814 + section['offset'])
+            out_file.write(get_section_contents(section))
+
+        size = out_file.tell()
+
+        out_file.seek(4)
+        md5_sum = hashlib.md5(out_file.read())
+
+        out_file.seek(0)
+        out_file.write(struct.pack('>I16s', size, md5_sum.digest()))
+
+def encode_soft_verson():
+    '''Not sure of the meaning of version. Also doesn't appear to be needed.'''
+    return struct.pack('>4B1I2I', 0xff, 1, 0 ,0, 0x2020202, 30000, 1)
+
+def create_image(output_image, root, support):
+    '''Create an image with a ubi "root" and a "support" string.'''
+    header = {}
+
+    header['rootfs_size'] = os.path.getsize(root)
+    header['items'] = []
+
+    rootfs = {}
+    rootfs['name'] = 'rootfs.ubi'
+    rootfs['file'] = root
+    rootfs['offset'] = 0
+    rootfs['size'] = header['rootfs_size']
+    header['items'].append(rootfs)
+
+    support_list = {}
+    support_list['name'] = 'support-list'
+    support_list['data'] = support.replace(" ", "\r\n").encode('utf-8')
+    support_list['offset'] = header['rootfs_size']
+    support_list['size'] = len(support_list['data'])
+    header['items'].append(support_list)
+
+    sw_version = {}
+    sw_version['name'] = 'soft-version'
+    sw_version['type'] = 1
+    sw_version['data'] = encode_soft_verson()
+    sw_version['offset'] = support_list['offset'] + support_list['size']
+    sw_version['size'] = len(sw_version['data'])
+    header['items'].append(sw_version)
+
+    header['num_items'] = len(header['items']) - 1
+    write_image(output_image, header)
+
+def main(args):
+    '''We support image analysis,extraction, and creation'''
+    if args.extract:
+        with open(args.image, 'rb') as image:
+            extract(image)
+    elif args.create:
+        if not args.rootfs or not args.support:
+            raise ValueError('To create an image, specify rootfs and support list')
+        create_image(args.image, args.rootfs, args.support)
+    else:
+        with open(args.image, 'rb') as image:
+            header = decode_header(image)
+
+            pretty = pprint.PrettyPrinter(indent=4, sort_dicts=False)
+            pretty.pprint(header)
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='EAP extractor')
+    parser.add_argument('--info', action='store_true')
+    parser.add_argument('--extract', action='store_true')
+    parser.add_argument('--create', action='store_true')
+    parser.add_argument('image', type=str,
+                    help='Name of image to create or decode')
+    parser.add_argument('--rootfs', type=str,
+                    help='When creating an EAP image, UBI image with rootfs and kernel')
+    parser.add_argument('--support', type=str,
+                    help='String for the "support-list" section')
+
+    main(parser.parse_args())
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6018-eap610-outdoor.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6018-eap610-outdoor.dts
new file mode 100644
index 0000000000..165fc3ef1b
--- /dev/null
+++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6018-eap610-outdoor.dts
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+/dts-v1/;
+
+#include "ipq6018.dtsi"
+#include "ipq6018-cp-cpu.dtsi"
+#include "ipq6018-ess.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "TP-Link EAP610-Outdoor";
+	compatible = "tplink,eap610-outdoor", "qcom,ipq6018";
+
+	aliases {
+		serial0 = &blsp1_uart3;
+		led-boot = &led_sys_green;
+		led-failsafe = &led_sys_amber;
+		led-running = &led_sys_green;
+		led-upgrade = &led_sys_amber;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs-append = " ubi.block=0,rootfs root=/dev/ubiblock0_1";
+	};
+
+	keys {
+		compatible = "gpio-keys";
+
+		reset {
+			label = "reset";
+			gpios = <&tlmm 9 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_sys_amber: led-0 {
+			function = "system";
+			color = <LED_COLOR_ID_AMBER>;
+			gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;
+		};
+
+		led_sys_green: led-1 {
+			function = "system";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
+		open-source;
+	};
+};
+
+&blsp1_uart3 {
+	pinctrl-0 = <&serial_3_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&tlmm {
+	mdio_pins: mdio-pins {
+		mdc {
+			pins = "gpio64";
+			function = "mdc";
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+
+		mdio {
+			pins = "gpio65";
+			function = "mdio";
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+	};
+
+	led_enable {
+		gpio-hog;
+		output-high;
+		gpios = <36 GPIO_ACTIVE_HIGH>;
+		line-name = "enable-leds";
+	};
+};
+
+&dp5 {
+	phy-handle = <&rtl8211f_4>;
+	phy-mode = "sgmii";
+	label = "lan";
+	status = "okay";
+};
+
+&edma {
+	status = "okay";
+};
+
+&mdio {
+	pinctrl-0 = <&mdio_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>;
+	reset-delay-us = <10000>;
+	reset-post-delay-us = <50000>;
+	status = "okay";
+
+	rtl8211f_4: ethernet-phy at 4 {
+		reg = <4>;
+	};
+};
+
+&switch {
+	switch_lan_bmp = <ESS_PORT5>;
+	switch_mac_mode1 = <MAC_MODE_SGMII_CHANNEL0>;
+	status = "okay";
+
+	qcom,port_phyinfo {
+		port at 4 {
+			port_id = <5>;
+			phy_address = <4>;
+		};
+	};
+};
+
+&qpic_bam {
+	status = "okay";
+};
+
+&qpic_nand {
+	status = "okay";
+
+	nand at 0 {
+		reg = <0>;
+
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+	};
+};
+
+&wifi {
+	ieee80211-freq-limit = <2402000 5835000>;
+	qcom,ath11k-calibration-variant = "TP-Link-EAP610-Outdoor";
+	status = "okay";
+};
diff --git a/target/linux/qualcommax/image/ipq60xx.mk b/target/linux/qualcommax/image/ipq60xx.mk
index 0b7cd413c3..c7e0be1181 100644
--- a/target/linux/qualcommax/image/ipq60xx.mk
+++ b/target/linux/qualcommax/image/ipq60xx.mk
@@ -68,6 +68,24 @@ define Device/qihoo_360v6
 endef
 TARGET_DEVICES += qihoo_360v6
 
+define Device/tplink_eap610-outdoor
+	$(call Device/FitImage)
+	$(call Device/UbiFit)
+	DEVICE_VENDOR := TP-Link
+	DEVICE_MODEL := EAP610-Outdoor
+	BLOCKSIZE := 128k
+	PAGESIZE := 2048
+	SOC := ipq6018
+	DEVICE_PACKAGES := ipq-wifi-tplink_eap610-outdoor
+	IMAGES += web-ui-factory.bin
+	IMAGE/web-ui-factory.bin := append-ubi | tplink-image-2022
+	TPLINK_SUPPORT_STRING := SupportList: \
+		EAP610-Outdoor(TP-Link|UN|AX1800-D):1.0 \
+		EAP610-Outdoor(TP-Link|JP|AX1800-D):1.0 \
+		EAP610-Outdoor(TP-Link|CA|AX1800-D):1.0
+endef
+TARGET_DEVICES += tplink_eap610-outdoor
+
 define Device/yuncore_fap650
 	$(call Device/FitImage)
 	$(call Device/UbiFit)
diff --git a/target/linux/qualcommax/ipq60xx/base-files/etc/board.d/02_network b/target/linux/qualcommax/ipq60xx/base-files/etc/board.d/02_network
index ecc9e57117..44c0ba7049 100644
--- a/target/linux/qualcommax/ipq60xx/base-files/etc/board.d/02_network
+++ b/target/linux/qualcommax/ipq60xx/base-files/etc/board.d/02_network
@@ -23,6 +23,9 @@ ipq60xx_setup_interfaces()
 	qihoo,360v6)
 		ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
 		;;
+	tplink,eap610-outdoor)
+		ucidef_set_interface_lan "lan" "dhcp"
+		;;
 	linksys,mr7350|\
 	yuncore,fap650)
 		ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan"
@@ -51,6 +54,10 @@ ipq60xx_setup_macs()
 		wan_mac=$(macaddr_add "$lan_mac" 1)
 		label_mac=$lan_mac
 		;;
+	tplink,eap610-outdoor)
+		label_mac=$(get_mac_binary /tmp/factory_data/default-mac 0)
+		lan_mac=$label_mac
+		;;
 	esac
 
 	[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
diff --git a/target/linux/qualcommax/ipq60xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata b/target/linux/qualcommax/ipq60xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
index 3380cc8653..cf3e400586 100644
--- a/target/linux/qualcommax/ipq60xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
+++ b/target/linux/qualcommax/ipq60xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
@@ -32,6 +32,13 @@ case "$FIRMWARE" in
 		ath11k_patch_mac $(macaddr_add $label_mac 2) 1
 		ath11k_set_macflag
 		;;
+	tplink,eap610-outdoor)
+		caldata_from_file "/tmp/factory_data/radio" 0 0x10000
+		label_mac=$(get_mac_binary /tmp/factory_data/default-mac 0)
+		ath11k_patch_mac $label_mac 1
+		ath11k_patch_mac $(macaddr_add $label_mac 1) 0
+		ath11k_set_macflag
+		;;
 	yuncore,fap650)
 		caldata_extract "0:art" 0x1000 0x20000
 		;;
diff --git a/target/linux/qualcommax/ipq60xx/base-files/lib/preinit/09_mount_factory_data b/target/linux/qualcommax/ipq60xx/base-files/lib/preinit/09_mount_factory_data
new file mode 100644
index 0000000000..97608db55d
--- /dev/null
+++ b/target/linux/qualcommax/ipq60xx/base-files/lib/preinit/09_mount_factory_data
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+preinit_mount_factory_data() {
+	local mtd_path
+
+	. /lib/functions.sh
+	. /lib/functions/system.sh
+
+	case $(board_name) in
+	tplink,eap610-outdoor)
+		mtd_path=$(find_mtd_chardev "factory_data")
+		ubiattach --dev-path="$mtd_path" --devn=1
+		mkdir /tmp/factory_data
+		mount -o ro,noatime -t ubifs ubi1:ubi_factory_data /tmp/factory_data
+		;;
+	esac
+}
+
+boot_hook_add preinit_main preinit_mount_factory_data
diff --git a/target/linux/qualcommax/ipq60xx/base-files/lib/upgrade/platform.sh b/target/linux/qualcommax/ipq60xx/base-files/lib/upgrade/platform.sh
index 411570715c..f9d446ff1f 100644
--- a/target/linux/qualcommax/ipq60xx/base-files/lib/upgrade/platform.sh
+++ b/target/linux/qualcommax/ipq60xx/base-files/lib/upgrade/platform.sh
@@ -4,6 +4,79 @@ REQUIRE_IMAGE_METADATA=1
 RAMFS_COPY_BIN='fw_printenv fw_setenv head'
 RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
 
+remove_oem_ubi_volume() {
+	local oem_volume_name="$1"
+	local oem_ubivol
+	local mtdnum
+	local ubidev
+
+	mtdnum=$(find_mtd_index "$CI_UBIPART")
+	if [ ! "$mtdnum" ]; then
+		return
+	fi
+
+	ubidev=$(nand_find_ubi "$CI_UBIPART")
+	if [ ! "$ubidev" ]; then
+		ubiattach --mtdn="$mtdnum"
+		ubidev=$(nand_find_ubi "$CI_UBIPART")
+	fi
+
+	if [ "$ubidev" ]; then
+		oem_ubivol=$(nand_find_volume "$ubidev" "$oem_volume_name")
+		[ "$oem_ubivol" ] && ubirmvol "/dev/$ubidev" --name="$oem_volume_name"
+	fi
+}
+
+tplink_get_boot_part() {
+	local cur_boot_part
+	local args
+
+	# Try to find rootfs from kernel arguments
+	read -r args < /proc/cmdline
+	for arg in $args; do
+		local ubi_mtd_arg=${arg#ubi.mtd=}
+		case "$ubi_mtd_arg" in
+		rootfs|rootfs_1)
+			echo "$ubi_mtd_arg"
+			return
+		;;
+		esac
+	done
+
+	# Fallback to u-boot env (e.g. when running initramfs)
+	cur_boot_part="$(/usr/sbin/fw_printenv -n tp_boot_idx)"
+	case $cur_boot_part in
+	1)
+		echo rootfs_1
+		;;
+	0|*)
+		echo rootfs
+		;;
+	esac
+}
+
+tplink_do_upgrade() {
+	local new_boot_part
+
+	case $(tplink_get_boot_part) in
+	rootfs)
+		CI_UBIPART="rootfs_1"
+		new_boot_part=1
+	;;
+	rootfs_1)
+		CI_UBIPART="rootfs"
+		new_boot_part=0
+	;;
+	esac
+
+	fw_setenv -s - <<-EOF
+		tp_boot_idx $new_boot_part
+	EOF
+
+	remove_oem_ubi_volume ubi_rootfs
+	nand_do_upgrade "$1"
+}
+
 platform_check_image() {
 	return 0;
 }
@@ -55,6 +128,9 @@ platform_do_upgrade() {
 	qihoo,360v6)
 		nand_do_upgrade "$1"
 		;;
+	tplink,eap610-outdoor)
+		tplink_do_upgrade "$1"
+		;;
 	yuncore,fap650)
 		[ "$(fw_printenv -n owrt_env_ver 2>/dev/null)" != "7" ] && yuncore_fap650_env_setup
 		local active="$(fw_printenv -n owrt_slotactive 2>/dev/null)"




More information about the lede-commits mailing list