From b066dae0cf46b00580ebd9a16753f5384a93125b Mon Sep 17 00:00:00 2001
From: Chen Minqiang <ptpt52@gmail.com>
Date: Mon, 22 Dec 2025 19:18:58 +0800
Subject: [PATCH 1/2] kernel: mtd: spi-nor: core: add force-sr-unprotect
 support

---
 ...-add-force-sr-unprotect-support-via-.patch | 69 +++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 target/linux/generic/hack-6.12/999-Z-9010-mtd-spi-nor-core-add-force-sr-unprotect-support-via-.patch

diff --git a/target/linux/generic/hack-6.12/999-Z-9010-mtd-spi-nor-core-add-force-sr-unprotect-support-via-.patch b/target/linux/generic/hack-6.12/999-Z-9010-mtd-spi-nor-core-add-force-sr-unprotect-support-via-.patch
new file mode 100644
index 00000000000000..c3c465e595b345
--- /dev/null
+++ b/target/linux/generic/hack-6.12/999-Z-9010-mtd-spi-nor-core-add-force-sr-unprotect-support-via-.patch
@@ -0,0 +1,69 @@
+From 0deed4a3423b8d95cff6e079548c0bce311ce131 Mon Sep 17 00:00:00 2001
+From: Chen Minqiang <ptpt52@gmail.com>
+Date: Mon, 22 Dec 2025 14:07:57 +0800
+Subject: [PATCH] mtd: spi-nor: core: add force-sr-unprotect support via DT
+
+Some SPI-NOR flash chips may have their block protection (BP) bits set
+in the status register by the bootloader or factory default, which
+effectively makes the flash or certain regions of it read-only.
+
+While the MTD layer might report success on erase or write operations,
+the actual data remains unchanged because the hardware-level protection
+silently ignores these commands.
+
+This patch introduces a new DT property "force-sr-unprotect":
+1. Add SNOR_F_SR_UNPROTECT flag to spi_nor_option_flags.
+2. Read "force-sr-unprotect" from Device Tree to enable this flag.
+3. During spi_nor_init(), if the flag is set, explicitly clear the
+   BP0-BP2 and SRWD bits in the Status Register to ensure the flash
+   is writable.
+
+Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
+---
+ drivers/mtd/spi-nor/core.c | 18 ++++++++++++++++++
+ drivers/mtd/spi-nor/core.h |  1 +
+ 2 files changed, 19 insertions(+)
+
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -2768,6 +2768,9 @@ static void spi_nor_init_flags(struct sp
+ 	if (of_property_read_bool(np, "broken-flash-reset"))
+ 		nor->flags |= SNOR_F_BROKEN_RESET;
+ 
++	if (of_property_read_bool(np, "force-sr-unprotect"))
++		nor->flags |= SNOR_F_SR_UNPROTECT;
++
+ 	if (of_property_read_bool(np, "no-wp"))
+ 		nor->flags |= SNOR_F_NO_WP;
+ 
+@@ -3119,6 +3122,20 @@ static int spi_nor_init(struct spi_nor *
+ {
+ 	int err;
+ 
++	if (nor->flags & SNOR_F_SR_UNPROTECT) {
++		u8 status_old, status_new;
++		err = spi_nor_read_sr(nor, nor->bouncebuf);
++		if (err)
++			return err;
++		status_old = nor->bouncebuf[0];
++		status_new = status_old & ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_SRWD);
++		if (status_new != status_old)
++		{
++			spi_nor_write_enable(nor);
++			spi_nor_write_sr_and_check(nor, status_new);
++		}
++	}
++
+ 	err = spi_nor_set_octal_dtr(nor, true);
+ 	if (err) {
+ 		dev_dbg(nor->dev, "octal mode not supported\n");
+--- a/drivers/mtd/spi-nor/core.h
++++ b/drivers/mtd/spi-nor/core.h
+@@ -140,6 +140,7 @@ enum spi_nor_option_flags {
+ 	SNOR_F_RWW		= BIT(14),
+ 	SNOR_F_ECC		= BIT(15),
+ 	SNOR_F_NO_WP		= BIT(16),
++	SNOR_F_SR_UNPROTECT	= BIT(17),
+ };
+ 
+ struct spi_nor_read_command {

From bd6119144e6583883058b8cd7e117535a329db76 Mon Sep 17 00:00:00 2001
From: Chen Minqiang <ptpt52@gmail.com>
Date: Fri, 19 Dec 2025 22:27:57 +0800
Subject: [PATCH 2/2] mediatek: init add Tenda AX12L Pro

---
 .../mediatek/dts/mt7981b-tenda-ax12l-pro.dts  | 215 ++++++++++++++++++
 .../filogic/base-files/etc/board.d/02_network |   6 +
 .../etc/hotplug.d/ieee80211/11_fix_wifi_mac   |   5 +
 .../base-files/lib/preinit/10_fix_eth_mac.sh  |   6 +
 .../base-files/lib/upgrade/platform.sh        |   6 +
 target/linux/mediatek/image/filogic.mk        |  20 ++
 6 files changed, 258 insertions(+)
 create mode 100644 target/linux/mediatek/dts/mt7981b-tenda-ax12l-pro.dts

diff --git a/target/linux/mediatek/dts/mt7981b-tenda-ax12l-pro.dts b/target/linux/mediatek/dts/mt7981b-tenda-ax12l-pro.dts
new file mode 100644
index 00000000000000..5b953cd89164ba
--- /dev/null
+++ b/target/linux/mediatek/dts/mt7981b-tenda-ax12l-pro.dts
@@ -0,0 +1,215 @@
+/dts-v1/;
+
+#include "mt7981b.dtsi"
+
+/ {
+	model = "Tenda AX12L Pro";
+	compatible = "tenda,ax12l-pro", "mediatek,mt7981";
+
+	aliases {
+		led-boot = &led_status_green;
+		led-failsafe = &led_status_red;
+		led-running = &led_status_green;
+		led-upgrade = &led_status_red;
+		serial0 = &uart0;
+		label-mac-device = &gmac0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs-override = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		reset {
+			label = "reset";
+			linux,code = <KEY_RESTART>;
+			gpios = <&pio 1 GPIO_ACTIVE_LOW>;
+		};
+
+		wps {
+			label = "wps";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_status_green: status_green {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&pio 13 GPIO_ACTIVE_HIGH>;
+		};
+
+		led_status_red: status_red {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_RED>;
+			gpios = <&pio 7 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mdio_pins>;
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+};
+
+&mdio_bus {
+	switch: switch@1f {
+		compatible = "mediatek,mt7531";
+		reg = <31>;
+		reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&pio>;
+		interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+	};
+};
+
+&switch {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+			label = "lan1";
+		};
+
+		port@1 {
+			reg = <1>;
+			label = "lan2";
+		};
+
+		port@2 {
+			reg = <2>;
+			label = "lan3";
+		};
+
+		wan: port@3 {
+			reg = <3>;
+			label = "wan";
+		};
+
+		port@6 {
+			reg = <6>;
+			ethernet = <&gmac0>;
+			phy-mode = "2500base-x";
+
+			fixed-link {
+				speed = <2500>;
+				full-duplex;
+				pause;
+			};
+		};
+	};
+};
+
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_flash_pins>;
+	status = "okay";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+
+		force-sr-unprotect;
+
+		spi-max-frequency = <52000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@00000 {
+				label = "BL2";
+				reg = <0x00000 0x0040000>;
+				read-only;
+			};
+			partition@40000 {
+				label = "u-boot-env";
+				reg = <0x40000 0x0010000>;
+			};
+			factory: partition@50000 {
+				label = "Factory";
+				reg = <0x50000 0x00A0000>; /* 640K */
+				read-only;
+			};
+			partition@f0000 {
+				label = "FIP";
+				reg = <0xF0000 0x0090000>; /* 576K */
+				read-only;
+			};
+			partition@180000 {
+				label = "firmware";
+				reg = <0x180000 0x0E50000>;
+			};
+			partition@fd0000 {
+				label = "CFG";
+				reg = <0xfd0000 0x0010000>; /* 64k */
+				read-only;
+			};
+			partition@fe0000 {
+				label = "MISC2";
+				reg = <0xfe0000 0x0010000>; /* 64k */
+				read-only;
+			};
+		};
+	};
+};
+
+&pio {
+	spi2_flash_pins: spi2-pins {
+		mux {
+			function = "spi";
+			groups = "spi2", "spi2_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+};
+
+&wifi {
+	mediatek,mtd-eeprom = <&factory 0x0>;
+
+	status = "okay";
+};
diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network
index 4ffff062cdee7a..5d54188204b229 100644
--- a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network
+++ b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network
@@ -58,6 +58,7 @@ mediatek_setup_interfaces()
 	routerich,ax3000|\
 	routerich,ax3000-ubootmod|\
 	routerich,be7200|\
+	tenda,ax12l-pro|\
 	tenbay,wr3000k)
 		ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" wan
 		;;
@@ -275,6 +276,11 @@ mediatek_setup_macs()
 		wan_mac=$label_mac
 		lan_mac=$(macaddr_add "$label_mac" 1)
 		;;
+	tenda,ax12l-pro)
+		label_mac=$(cat /sys/class/net/eth0/address)
+		wan_mac=$label_mac
+		lan_mac=$(macaddr_add "$label_mac" 1)
+		;;
 	tplink,fr365-v1)
 		lan_mac=$(strings /dev/mtd11 | grep 'option macaddr' | awk -F"'" '{print $2}')
 		wan_mac="$(macaddr_add $lan_mac 1)"
diff --git a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac
index 907dd00d364c02..1c3d2dc5291093 100644
--- a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac
+++ b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac
@@ -208,6 +208,11 @@ case "$board" in
 		[ "$PHYNBR" = "0" ] && macaddr_add $addr 2 > /sys${DEVPATH}/macaddress
 		[ "$PHYNBR" = "1" ] && macaddr_add $addr 3 > /sys${DEVPATH}/macaddress
 		;;
+	tenda,ax12l-pro)
+		addr=$(cat /sys/class/net/eth0/address)
+		[ "$PHYNBR" = "0" ] && macaddr_add $addr 2 > /sys${DEVPATH}/macaddress
+		[ "$PHYNBR" = "1" ] && macaddr_add $addr 3 > /sys${DEVPATH}/macaddress
+		;;
 	tplink,fr365-v1)
 		addr=$(strings /dev/mtd11 | grep 'option macaddr' | awk -F"'" '{print $2}')
 		[ "$PHYNBR" = "0" ] && echo $addr > /sys${DEVPATH}/macaddress
diff --git a/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh b/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh
index 0d4c165e485394..9fb9f77623f16d 100644
--- a/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh
+++ b/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh
@@ -45,6 +45,12 @@ preinit_set_mac_address() {
 		addr=$(get_mac_binary "/tmp/tp_data/default-mac" 0)
 		ip link set dev eth1 address "$(macaddr_add $addr 1)"
 		;;
+	tenda,ax12l-pro)
+		addr=$(mtd_get_mac_ascii CFG "TENDA.lan_mac")
+		ip link set eth0 down
+		ip link set dev eth0 address "$addr"
+		ip link set eth0 up
+		;;
 	tplink,be450)
 		addr=$(get_mac_binary "/tmp/tp_data/default-mac" 0)
 		ip link set dev eth1 address "$(macaddr_add $addr 1)"
diff --git a/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh b/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh
index dde54a053df6f0..b0e38525f221ce 100644
--- a/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh
+++ b/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh
@@ -220,6 +220,9 @@ platform_do_upgrade() {
 		CI_UBIPART="$(cmdline_get_var ubi.mtd)"
 		nand_do_upgrade "$1"
 		;;
+	tenda,ax12l-pro)
+		default_do_upgrade "$1"
+		;;
 	nradio,c8-668gl)
 		CI_DATAPART="rootfs_data"
 		CI_KERNPART="kernel_2nd"
@@ -307,6 +310,9 @@ platform_check_image() {
 		fit_check_image "$1"
 		return $?
 		;;
+	tenda,ax12l-pro)
+		return 0
+		;;
 	creatlentem,clt-r30b1|\
 	creatlentem,clt-r30b1-112m|\
 	nradio,c8-668gl)
diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk
index b9b89780b327ec..56f23456f8800e 100644
--- a/target/linux/mediatek/image/filogic.mk
+++ b/target/linux/mediatek/image/filogic.mk
@@ -2602,6 +2602,26 @@ define Device/tenbay_wr3000k
 endef
 TARGET_DEVICES += tenbay_wr3000k
 
+define Device/tenda_ax12l-pro
+  DEVICE_VENDOR := Tenda
+  DEVICE_MODEL := AX12L Pro
+  DEVICE_ALT0_VENDOR := Tenda
+  DEVICE_ALT0_MODEL := JD12L Pro
+  DEVICE_ALT1_VENDOR := Tenda
+  DEVICE_ALT1_MODEL := RX12L Pro
+  DEVICE_ALT2_VENDOR := Tenda
+  DEVICE_ALT2_MODEL := TX12L Pro
+  DEVICE_DTS := mt7981b-tenda-ax12l-pro
+  DEVICE_DTS_DIR := ../dts
+  DEVICE_PACKAGES := kmod-mt7915e kmod-mt7981-firmware mt7981-wo-firmware uboot-envtools
+  KERNEL_LOADADDR := 0x40000000
+  KERNEL_INITRAMFS := kernel-bin | lzma | \
+        fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd | pad-to 64k
+  IMAGE_SIZE := 14528k
+  IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | pad-rootfs | check-size | append-metadata
+endef
+TARGET_DEVICES += tenda_ax12l-pro
+
 define Device/tenda_be12-pro
   DEVICE_VENDOR := Tenda
   DEVICE_MODEL := BE12 Pro
