IPQ4019: Adding Support For Tp Link Deco M9 Plus

Hi everyone, I just wanted to re-spawn this thread and also see if the great work for M5 on this thread is usable: IPQ4019: Adding support for TP-Link Deco M5

The chips on M5 seem very similar AFAIK so it might be useful for getting support for M9 plus.

earlier thread which did not get much traction:

I have 3 M9 plus devices and I have ordered a serial connector and plan to open one up and try my hand at capturing OEM boot logs. if anyone else here also has devices and have tried similar things or have stuff working then please do share!

tagging people from M5 thread:
@DropDemBits @brada4 @undisputed-seraphim

fcc page:
https://fcc.report/FCC-ID/TE7M9PLUSV2/4549756

Good timing. Thank's to naf's excellent work on Deco exploits I just yesterday tested his M9 Plus version and got root. I also have some pictures of the board and have dumped the SPI flash.

1 Like

That did not work for me.
my m9 is on version:

M9Plus(2.0)

1.5.0 Build 20201211 Rel. 42330

the ui says upgrading... then rebooting.. and then I get connection refused on port 2222.(80/443/20001 are open as per nmap.)

Edit: never mind. It works. I did not have the deco connected to internet to download the reverse shell.

@naf

It has:

  1. dmesg output from oem firmware v1_5_0
  2. all mtd devices
  3. mtd.txt - list of devices.
  4. system log from web gui

i believe there are two different sources of existing-but-not-mainline ipq4019 deco-like boards to base your m9+ openwrt changes on:

either appears to provide a good example of what needs to be done AFAICT.

and remember to specify which hw version you are referring to. i believe @meshing has a v2 and @troed has a v1

Huh. Interesting difference between your v2 hw and my v1.

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00030000 00010000 "0:SBL1"
mtd1: 00010000 00010000 "0:BOOTCONFIG"
mtd2: 00010000 00010000 "0:MIBIB"
mtd3: 00010000 00010000 "0:BOOTCONFIG1"
mtd4: 00060000 00010000 "0:QSEE"
mtd5: 00010000 00010000 "0:CDT"
mtd6: 00010000 00010000 "0:DDRPARAMS"
mtd7: 00010000 00010000 "0:APPSBLENV"
mtd8: 00080000 00010000 "0:APPSBL"
mtd9: 00010000 00010000 "0:ART"
mtd10: 00150000 00010000 "OPAQUE"
mtd11: 00010000 00010000 "0:HLOS"
mtd12: 00050000 00010000 "0:rootfs"
mtd13: 00080000 00010000 "0:APPSBL_1"
mtd14: 00010000 00010000 "1:HLOS"
mtd15: 00440000 00010000 "1:rootfs"

linksys ea8300 seems like exactly the same hardware.. maybe the mtd needs to be adjusted and that's all.

How interesting is it to see if the bootloader is exploitable same as nvrammanager? I've compared the update code between them and it's wildly different. In the compareable function to where fw-type and md5 is checked in nvrammanager both of those are missing in the bootloader. Have they been similar in the other product fw:s you've looked at?

edit: That sounded as if I was done decompiling - I'm not. There could still be some checks, but if so not with reused codebase.

For OpenWRT purposes I think the "user mode" exploit is easy enough to use though.

all deco devices are a little different. some devices used to have the matching buggy/exploitable signature check in both bootloader and usermode (then fixed it in usermode only in later revisions of fw updates), some (porobably more recent) devices have the fix in bootloader as well, some dont check signatures at all, S4V2 additionally supports a completely different (unsigned) format, some have no validity check at all, some have tftp, etc.

if your v1 BL is like the v2, signature check is there but without the buggy fw-type check. easy to find if you look for uses of the public key "BgIAAACkAA". then again it could just be a "we dont do a check" device.

ya enough hacking, one of yall needs to get an openwrt image going :slight_smile:

hah. hacking is the fun part :smiley:

Signature checking is there, it's the md5 ("md5 verify error!") and fw-type (so no sscanf) code that's missing in the bootloader compared to nvrammanager. Otherwise the code is similar enough to easily follow along in both.

I also looked at replicating the popen port forward access exploit named in the paper. However, unless you already have an exploit to get the private key to be able to connect to dropbear at port 20001 the initial step of brute forcing it makes it not worth it compared to downgrading to a usermode exploitable firmware.

okie I finally opened it up but now I have no idea where the uart is and nothing is obviously jumping out. Does any of you have a picture or a hint ?

You need at least three pins. They're usually in a bank of four as they also have VCC. UART is push pull and they'll probably be "high".

Other than hooking up rx pin and ground of your ttl uart (ensuring your uart doesn't have a high pullup or high burden current with an LED or something...) or going around with a logic analyser looking for test points and pads I can't help you.

You can help with high resolution PCB pictures of front and back. With the cans off if that's not destructive operation and it covers the CPU.


black is tx, white is gnd and grey is rx

any guesses for the username password ? or is it random for every device ?

I just built this:

(m4v3 target)
and tried to load the .itb file via tftpboot from uboot and I am stuck at this. It does not go any further. I have waited 10 minutes.
Anybody knows what's going on ?

(IPQ40xx) # setenv serverip 192.168.0.2
(IPQ40xx) # setenv ipaddr 192.168.0.1
(IPQ40xx) # tftpboot 0x82000000 openwrt-ipq40xx-generic-tp-link_deco-m4r-v3-initramfs-uImage.itb
eth0 PHY0 Down Speed :10 Half duplex
eth0 PHY1 Down Speed :10 Half duplex
eth0 PHY2 Down Speed :10 Half duplex
eth0 PHY3 Down Speed :10 Half duplex
eth0 PHY4 up Speed :1000 Full duplex
Using eth0 device
TFTP from server 192.168.0.2; our IP address is 192.168.0.1
Filename 'openwrt-ipq40xx-generic-tp-link_deco-m4r-v3-initramfs-uImage.itb'.
Load address: 0x82000000
Loading: *#################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 ############################
done
Bytes transferred = 8993692 (893b9c hex)
(IPQ40xx) # bootm 0x82000000
## Booting kernel from FIT Image at 82000000 ...
   Using 'config@1' configuration
   Trying 'kernel@1' kernel subimage
     Description:  ARM OpenWrt Linux-5.15.167
     Type:         Kernel Image
     Compression:  gzip compressed
     Data Start:   0x820000e4
     Data Size:    8973348 Bytes = 8.6 MiB
     Architecture: ARM
     OS:           Linux
     Load Address: 0x80208000
     Entry Point:  0x80208000
     Hash algo:    crc32
     Hash value:   47d22440
     Hash algo:    sha1
     Hash value:   f9557b60f4c5ee90b6f3e489484c02b7a0b1607a
   Verifying Hash Integrity ... crc32+ sha1+ OK
## Flattened Device Tree from FIT Image at 82000000
   Using 'config@1' configuration
   Trying 'fdt@1' FDT blob subimage
     Description:  ARM OpenWrt tp-link_deco-m4r-v3 device tree blob
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0x8288ee48
     Data Size:    18448 Bytes = 18 KiB
     Architecture: ARM
     Hash algo:    crc32
     Hash value:   1f0b149a
     Hash algo:    sha1
     Hash value:   e3216a6a5ff745e3e2511c0efb2fa21ae0696804
   Verifying Hash Integrity ... crc32+ sha1+ OK
   Booting using the fdt blob at 0x8288ee48
   Uncompressing Kernel Image ... OK
   Loading Device Tree to 862a8000, end 862af80f ... OK
Device nand2 not found!
eth0 MAC Address from ART is not valid
eth1 MAC Address from ART is not valid
Using machid 0x8010006 from environment

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 5.15.167 (nitin@kali1) (arm-openwrt-linux-muslgnueabi-gcc (OpenWrt GCC 12.3.0 r24130-c66dd32246) 12.3.0, GNU ld (GNU Binutils) 2.40.0) #0 SMP Fri Nov 29 14:16:49 2024
[    0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: TP-Link Deco M4R v3
[    0.000000] Memory policy: Data cache writealloc
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000080000000-0x000000009fffffff]
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080000000-0x0000000087dfffff]
[    0.000000]   node   0: [mem 0x0000000087e00000-0x0000000087ffffff]
[    0.000000]   node   0: [mem 0x0000000088000000-0x000000009fffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x000000009fffffff]
[    0.000000] percpu: Embedded 12 pages/cpu s19340 r8192 d21620 u49152
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 129920
[    0.000000] Kernel command line: 
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] Memory: 494576K/524288K available (6544K kernel code, 608K rwdata, 1672K rodata, 12288K init, 239K bss, 29712K reserved, 0K cma-reserved, 0K highmem)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] 	Tracing variant of Tasks RCU enabled.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] arch_timer: cp15 timer(s) running at 48.00MHz (virt).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0xb11fd3bfb, max_idle_ns: 440795203732 ns
[    0.000001] sched_clock: 56 bits at 48MHz, resolution 20ns, wraps every 4398046511096ns
[    0.000024] Switching to timer-based delay loop, resolution 20ns
[    0.000319] Calibrating delay loop (skipped), value calculated using timer frequency.. 96.00 BogoMIPS (lpj=480000)
[    0.000347] CPU: Testing write buffer coherency: ok
[    0.000405] pid_max: default: 32768 minimum: 301
[    0.001246] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.001277] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.003247] qcom_scm: convention: smc legacy
[    0.004439] Setting up static identity map for 0x80300000 - 0x8030003c
[    0.004618] rcu: Hierarchical SRCU implementation.
[    0.005211] smp: Bringing up secondary CPUs ...
[    0.008698] smp: Brought up 1 node, 4 CPUs
[    0.008734] SMP: Total of 4 processors activated (384.00 BogoMIPS).
[    0.008751] CPU: All CPU(s) started in SVC mode.
[    0.015131] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
[    0.015292] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.015329] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
[    0.015698] pinctrl core: initialized pinctrl subsystem
[    0.017743] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    0.018062] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.019378] thermal_sys: Registered thermal governor 'step_wise'
[    0.019816] cpuidle: using governor ladder
[    0.019878] cpuidle: using governor menu
[    0.045507] cryptd: max_cpu_qlen set to 1000
[    0.050220] usbcore: registered new interface driver usbfs
[    0.050302] usbcore: registered new interface driver hub
[    0.050367] usbcore: registered new device driver usb
[    0.050457] pps_core: LinuxPPS API ver. 1 registered
[    0.050471] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.050503] PTP clock support registered
[    0.052673] clocksource: Switched to clocksource arch_sys_counter
[    0.053889] NET: Registered PF_INET protocol family
[    0.054125] IP idents hash table entries: 8192 (order: 4, 65536 bytes, linear)
[    0.055297] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)
[    0.055342] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.055365] TCP established hash table entries: 4096 (order: 2, 16384 bytes, linear)
[    0.055430] TCP bind hash table entries: 4096 (order: 3, 32768 bytes, linear)
[    0.055525] TCP: Hash tables configured (established 4096 bind 4096)
[    0.055663] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.055709] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.056053] NET: Registered PF_UNIX/PF_LOCAL protocol family
[    0.056109] PCI: CLS 0 bytes, default 64
[    0.064751] workingset: timestamp_bits=14 max_order=17 bucket_order=3
[    0.070667] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.070708] jffs2: version 2.2 (NAND) (SUMMARY) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
[    0.207942] bam-dma-engine 8e04000.dma: num-channels unspecified in dt
[    0.207976] bam-dma-engine 8e04000.dma: num-ees unspecified in dt
[    0.208708] tcsr 194b000.tcsr: setting usb hs phy mode select = e700e7
[    0.208855] tcsr 1953000.ess_tcsr: setting ess interface select = 0
[    0.208953] tcsr 1949000.tcsr: setting wifi_glb_cfg = 41000000
[    0.209046] tcsr 1957000.tcsr: setting wifi_noc_memtype_m0_m2 = 2222222
[    0.209404] Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
[    0.210067] msm_serial 78af000.serial: msm_serial: detected port #0
[    0.210120] msm_serial 78af000.serial: uartclk = 1843200
[    0.210173] 78af000.serial: ttyMSM0 at MMIO 0x78af000 (irq = 34, base_baud = 115200) is a MSM
[    0.210210] msm_serial: console setup on port #0
[    0.747571] printk: console [ttyMSM0] enabled
[    0.752796] msm_serial 78b0000.serial: msm_serial: detected port #1
[    0.756518] msm_serial 78b0000.serial: uartclk = 1843200
[    0.762606] 78b0000.serial: ttyMSM1 at MMIO 0x78b0000 (irq = 35, base_baud = 115200) is a MSM
[    0.768560] msm_serial: driver initialized
[    0.782776] loop: module loaded
[    0.783873] spi_qup 78b5000.spi: IN:block:16, fifo:64, OUT:block:16, fifo:64
[    0.785750] spi-nor spi0.0: unrecognized JEDEC id bytes: ff ff ff ff ff ff
[    0.792033] spi-nor: probe of spi0.0 failed with error -2
[    0.880153] i2c_dev: i2c /dev entries driver
[    0.880419] i2c_qup 78b7000.i2c: using default clock-frequency 100000
[    0.886283] sdhci: Secure Digital Host Controller Interface driver
[    0.889840] sdhci: Copyright(c) Pierre Ossman
[    0.895936] sdhci-pltfm: SDHCI platform and OF driver helper
[    0.904294] NET: Registered PF_INET6 protocol family
[    0.907737] Segment Routing with IPv6
[    0.911083] In-situ OAM (IOAM) with IPv6
[    0.914717] NET: Registered PF_PACKET protocol family
[    0.918896] 8021q: 802.1Q VLAN Support v1.8
[    0.923587] Registering SWP/SWPB emulation handler
[    0.949ò[    0.972187] Freeing unused kernel image (initmem) memory: 12288K
[    0.972494] Run /init as init process
[    1.328695] init: Console is alive
[    1.329078] init: - watchdog -
[    1.340851] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[    1.572119] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    1.572204] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 1
[    1.576849] xhci-hcd xhci-hcd.0.auto: hcc params 0x0228f665 hci version 0x100 quirks 0x0000008002010010
[    1.584167] xhci-hcd xhci-hcd.0.auto: irq 71, io mem 0x08a00000
[    1.593699] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    1.599394] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 2
[    1.604940] xhci-hcd xhci-hcd.0.auto: Host supports USB 3.0 SuperSpeed
[    1.613241] hub 1-0:1.0: USB hub found
[    1.619104] hub 1-0:1.0: 1 port detected
[    1.628386] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[    1.629051] hub 2-0:1.0: USB hub found
[    1.635653] hub 2-0:1.0: 1 port detected
[    1.639655] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[    1.643250] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 3
[    1.648708] xhci-hcd xhci-hcd.1.auto: hcc params 0x0220f665 hci version 0x100 quirks 0x0000008002010010
[    1.656130] xhci-hcd xhci-hcd.1.auto: irq 72, io mem 0x06000000
[    1.665655] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[    1.671352] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 4
[    1.676902] xhci-hcd xhci-hcd.1.auto: Host supports USB 3.0 SuperSpeed
[    1.685222] hub 3-0:1.0: USB hub found
[    1.691093] hub 3-0:1.0: 1 port detected
[    1.695225] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
[    1.699419] hub 4-0:1.0: USB hub found
[    1.708097] hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)
[    1.713106] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[    1.725287] init: - preinit -
get_mac_binary: file /dev/mtd10 not found!
ip: SIOCGIFINDEX: No such device
/etc/preinit: line 229: arithmetic syntax error
ip: SIOCGIFINDEX: No such device
[    2.086737] random: jshn: uninitialized urandom read (4 bytes read)
[    2.132627] random: jshn: uninitialized urandom read (4 bytes read)
[    2.165805] random: jshn: uninitialized urandom read (4 bytes read)
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
[    4.613869] procd: - early -
[    4.614085] procd: - watchdog -
[    5.149260] procd: - watchdog -
[    5.149930] procd: - ubus -
[    5.157646] random: ubusd: uninitialized urandom read (4 bytes read)
[    5.201864] random: ubusd: uninitialized urandom read (4 bytes read)
[    5.202263] random: ubusd: uninitialized urandom read (4 bytes read)
[    5.210122] procd: - init -
Please press Enter to activate this console.
[    5.517754] kmodloader: loading kernel modules from /etc/modules.d/*
[    5.527686] Loading modules backported from Linux version v6.1.110-0-g5f55cad62cc9d
[    5.527739] Backport generated by backports.git v6.1.110-1-0-g965f73fc
[    5.632303] PPP generic driver version 2.4.2
[    5.633603] NET: Registered PF_PPPOX protocol family
[    6.333853] urngd: v1.0.2 started.
[    6.463403] ath10k_ahb a000000.wifi: qca4019 hw1.0 target 0x01000000 chip_id 0x003b00ff sub 0000:0000
[    6.463478] ath10k_ahb a000000.wifi: kconfig debug 0 debugfs 1 tracing 0 dfs 1 testmode 0
[    6.475466] ath10k_ahb a000000.wifi: firmware ver 10.4b-ct-4019-fW-13-5ae337bb1 api 5 features mfp,peer-flow-ctrl,txstatus-noack,wmi-10.x-CT,ratemask-CT,regdump-CT,txrate-CT,flush-all-CT,pingpong-CT,ch-regs-CT,nop-CT,set-special-CT,tx-rc-CT,cust-stats-CT,txrate2-CT,beacon-cb-CT,wmi-block-ack-CT,wmi-bcn-rc-CT crc32 6b2b5c5b
[    6.503714] ath10k_ahb a000000.wifi: Loading BDF type 0
[    6.512956] ath10k_ahb a000000.wifi: failed to fetch board data for bus=ahb,vendor=0000,device=0000,subsystem-vendor=0000,subsystem-device=0000,variant=TP-Link_Deco_M4 from ath10k/QCA4019/hw1.0/board-2.bin
[    6.690035] ath10k_ahb a000000.wifi: failed to fetch board-2.bin or board.bin from ath10k/QCA4019/hw1.0
[    6.690098] ath10k_ahb a000000.wifi: failed to fetch board file: -12
[    6.698451] ath10k_ahb a000000.wifi: could not probe fw (-12)
[    6.869491] random: crng init done
[    6.869538] random: 30 urandom warning(s) missed due to ratelimiting
[    7.516189] ath10k_ahb a800000.wifi: qca4019 hw1.0 target 0x01000000 chip_id 0x003b00ff sub 0000:0000
[    7.516257] ath10k_ahb a800000.wifi: kconfig debug 0 debugfs 1 tracing 0 dfs 1 testmode 0
[    7.528421] ath10k_ahb a800000.wifi: firmware ver 10.4b-ct-4019-fW-13-5ae337bb1 api 5 features mfp,peer-flow-ctrl,txstatus-noack,wmi-10.x-CT,ratemask-CT,regdump-CT,txrate-CT,flush-all-CT,pingpong-CT,ch-regs-CT,nop-CT,set-special-CT,tx-rc-CT,cust-stats-CT,txrate2-CT,beacon-cb-CT,wmi-block-ack-CT,wmi-bcn-rc-CT crc32 6b2b5c5b
[    7.556512] ath10k_ahb a800000.wifi: Loading BDF type 0
[    7.565686] ath10k_ahb a800000.wifi: failed to fetch board data for bus=ahb,vendor=0000,device=0000,subsystem-vendor=0000,subsystem-device=0000,variant=TP-Link_Deco_M4 from ath10k/QCA4019/hw1.0/board-2.bin
[    7.742021] ath10k_ahb a800000.wifi: failed to fetch board-2.bin or board.bin from ath10k/QCA4019/hw1.0
[    7.742101] ath10k_ahb a800000.wifi: failed to fetch board file: -12
[    7.750547] ath10k_ahb a800000.wifi: could not probe fw (-12)
[    7.764672] kmodloader: done loading kernel modules from /etc/modules.d/*

@caeklol any thoughts?

ill take the low hanging fruit:
i would think that you (and @caeklol) should change all instances of get_mac_binary "/dev/mtd10" to something more like mtd_get_mac_binary "0:ART"

hopefully someone smarter will come along and remind us all how to determine what needs to get in your dts to fix your network cards not getting picked up and the device hanging...

fwiw I also tried openwrt/main with this patch:

It stops here:

(IPQ40xx) # bootm 0x82000000
## Booting kernel from FIT Image at 82000000 ...
   Using 'config@1' configuration
   Trying 'kernel-1' kernel subimage
     Description:  ARM OpenWrt Linux-6.6.58
     Type:         Kernel Image
     Compression:  uncompressed
     Data Start:   0x820000e4
     Data Size:    6976040 Bytes = 6.7 MiB
     Architecture: ARM
     OS:           Linux
     Load Address: 0x80208000
     Entry Point:  0x80208000
     Hash algo:    crc32
     Hash value:   607cbe57
     Hash algo:    sha1
     Hash value:   123afa4f1f104bc9067bd6bf6ecdabbed3a1904b
   Verifying Hash Integrity ... crc32+ sha1+ OK
## Flattened Device Tree from FIT Image at 82000000
   Using 'config@1' configuration
   Trying 'fdt-1' FDT blob subimage
     Description:  ARM OpenWrt tplink_deco-m9plus-v2 device tree blob
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0x826a744c
     Data Size:    18753 Bytes = 18.3 KiB
     Architecture: ARM
     Hash algo:    crc32
     Hash value:   f3c14ddf
     Hash algo:    sha1
     Hash value:   74b5721343ec89b553858b087ee66dd0556405e1
   Verifying Hash Integrity ... crc32+ sha1+ OK
   Booting using the fdt blob at 0x826a744c
   Loading Kernel Image ... OK
OK
   Loading Device Tree to 862a7000, end 862ae940 ... OK
Device nand2 not found!
eth0 MAC Address from ART is not valid
eth1 MAC Address from ART is not valid
Using machid 0x8010006 from environment

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 6.6.58 (nitin@kali1) (arm-openwrt-linux-muslgnueabi-gcc (OpenWrt GCC 13.3.0 r27914-63ea5710d9) 13.3.0, GNU ld (GNU Binutils) 2.42) #0 SMP Sun Oct 27 11:45:16 2024
[    0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: TP-Link Deco M9Plus v2
[    0.000000] Memory policy: Data cache writealloc
[    0.000000] OF: reserved mem: 0x87e00000..0x87e7ffff (512 KiB) nomap non-reusable smem@87e00000
[    0.000000] OF: reserved mem: 0x87e80000..0x87ffffff (1536 KiB) nomap non-reusable tz@87e80000
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000080000000-0x000000009fffffff]
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080000000-0x0000000087dfffff]
[    0.000000]   node   0: [mem 0x0000000087e00000-0x0000000087ffffff]
[    0.000000]   node   0: [mem 0x0000000088000000-0x000000009fffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x000000009fffffff]
[    0.000000] percpu: Embedded 13 pages/cpu s21076 r8192 d23980 u53248
[    0.000000] Kernel command line:  root=/dev/mtdblock16
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 129920
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] Memory: 492476K/524288K available (7406K kernel code, 641K rwdata, 1944K rodata, 13312K init, 240K bss, 31812K reserved, 0K cma-reserved, 0K highmem)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] 	Tracing variant of Tasks RCU enabled.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
[    0.000000] arch_timer: cp15 timer(s) running at 48.00MHz (virt).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0xb11fd3bfb, max_idle_ns: 440795203732 ns
[    0.000001] sched_clock: 56 bits at 48MHz, resolution 20ns, wraps every 4398046511096ns
[    0.000021] Switching to timer-based delay loop, resolution 20ns
[    0.000318] Calibrating delay loop (skipped), value calculated using timer frequency.. 96.00 BogoMIPS (lpj=480000)
[    0.000339] CPU: Testing write buffer coherency: ok
[    0.000392] pid_max: default: 32768 minimum: 301
[    0.010382] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.010406] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.018943] qcom_scm: convention: smc legacy
[    0.020385] RCU Tasks Trace: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1.
[    0.020551] Setting up static identity map for 0x80300000 - 0x8030003c
[    0.020757] rcu: Hierarchical SRCU implementation.
[    0.020766] rcu: 	Max phase no-delay instances is 1000.
[    0.021468] smp: Bringing up secondary CPUs ...
[    0.025200] smp: Brought up 1 node, 4 CPUs
[    0.025223] SMP: Total of 4 processors activated (384.00 BogoMIPS).
[    0.025237] CPU: All CPU(s) started in SVC mode.
[    0.032642] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
[    0.032828] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.032858] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
[    0.037873] pinctrl core: initialized pinctrl subsystem
[    0.041995] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    0.042349] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.043869] thermal_sys: Registered thermal governor 'step_wise'
[    0.043972] cpuidle: using governor ladder
[    0.044014] cpuidle: using governor menu
[    0.061203] cryptd: max_cpu_qlen set to 1000
[    0.067652] usbcore: registered new interface driver usbfs
[    0.067735] usbcore: registered new interface driver hub
[    0.067794] usbcore: registered new device driver usb
[    0.067876] pps_core: LinuxPPS API ver. 1 registered
[    0.067883] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.067913] PTP clock support registered
[    0.070504] clocksource: Switched to clocksource arch_sys_counter
[    0.081203] NET: Registered PF_INET protocol family
[    0.081469] IP idents hash table entries: 8192 (order: 4, 65536 bytes, linear)
[    0.083244] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)
[    0.083285] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.083306] TCP established hash table entries: 4096 (order: 2, 16384 bytes, linear)
[    0.083366] TCP bind hash table entries: 4096 (order: 4, 65536 bytes, linear)
[    0.083519] TCP: Hash tables configured (established 4096 bind 4096)
[    0.084605] MPTCP token hash table entries: 512 (order: 1, 8192 bytes, linear)
[    0.084995] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.085061] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.085815] NET: Registered PF_UNIX/PF_LOCAL protocol family
[    0.085865] PCI: CLS 0 bytes, default 64
[    0.087452] workingset: timestamp_bits=14 max_order=17 bucket_order=3
[    0.089753] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.089776] jffs2: version 2.2 (NAND) (SUMMARY) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
[    0.336012] tcsr 194b000.tcsr: setting usb hs phy mode select = e700e7
[    0.336126] tcsr 1949000.tcsr: setting wifi_glb_cfg = 41000000
[    0.336219] tcsr 1957000.tcsr: setting wifi_noc_memtype_m0_m2 = 2222222
[    0.336308] tcsr 1953000.ess_tcsr: setting ess interface select = 0
[    0.336714] Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
[    0.337716] msm_serial 78af000.serial: msm_serial: detected port #0
[    0.337759] msm_serial 78af000.serial: uartclk = 1843200
[    0.338131] 78af000.serial: ttyMSM0 at MMIO 0x78af000 (irq = 31, base_baud = 115200) is a MSM
[    0.338169] msm_serial: console setup on port #0
[    0.338222] printk: console [ttyMSM0] enabled
[    0.913724] msm_serial 78b0000.serial: msm_serial: detected port #1
[    0.917471] msm_serial 78b0000.serial: uartclk = 1843200
[    0.923907] 78b0000.serial: ttyMSM1 at MMIO 0x78b0000 (irq = 32, base_baud = 115200) is a MSM
[    0.929488] msm_serial: driver initialized
[    0.944906] loop: module loaded
[    0.946422] spi_qup 78b5000.spi: IN:block:16, fifo:64, OUT:block:16, fifo:64
[    0.946983] m25p80@0 enforce active low on GPIO handle
[    0.955334] spi-nor spi0.0: unrecognized JEDEC id bytes: ff ff ff ff ff ff
[    1.045483] ipqess-edma c080000.ethernet: using random MAC address 46:33:e4:b5:7f:cf
[    1.072078] i2c_dev: i2c /dev entries driver
[    1.072405] i2c_qup 78b7000.i2c: using default clock-frequency 100000
[    1.078436] sdhci: Secure Digital Host Controller Interface driver
[    1.081845] sdhci: Copyright(c) Pierre Ossman
[    1.087844] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.095792] NET: Registered PF_INET6 protocol family
[    1.100164] Segment Routing with IPv6
[    1.103101] In-situ OAM (IOAM) with IPv6
[    1.106623] NET: Registered PF_PACKET protocol family
[    1.110921] 8021q: 802.1Q VLAN Support v1.8
[    1.115534] Registering SWP/SWPB emulation handler
[    1.155583] qca8k-ipq4019 c000000.switch: configuring for fixed/internal link mode
[    1.155965] qca8k-ipq4019 c000000.switch: Link is Up - 1Gbps/Full - flow control rx/tx
[    1.362371] qca8k-ipq4019 c000000.switch lan (uninitialized): PHY [90000.mdio-1:03] driver [Qualcomm QCA8072] (irq=POLL)
[    1.441334] qca8k-ipq4019 c000000.switch wan (uninitialized): PHY [90000.mdio-1:04] driver [Qualcomm QCA8072] (irq=POLL)
[    1.442486] ipqess-edma c080000.ethernet eth0: entered promiscuous mode
[    1.451443] DSA: tree 0 setup
þ[    1.486103] Freeing unused kernel image (initmem) memory: 13312K
[    1.486449] Run /init as init process
[    1.883405] init: Console is alive
[    1.883765] init: - watchdog -
[    1.897788] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[    1.900672] gpio_button_hotplug: loading out-of-tree module taints kernel.
[    2.130924] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    2.131012] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 1
[    2.135579] xhci-hcd xhci-hcd.0.auto: hcc params 0x0228f665 hci version 0x100 quirks 0x0000008002000010
[    2.143009] xhci-hcd xhci-hcd.0.auto: irq 60, io mem 0x08a00000
[    2.152487] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    2.158179] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 2
[    2.163756] xhci-hcd xhci-hcd.0.auto: Host supports USB 3.0 SuperSpeed
[    2.172099] hub 1-0:1.0: USB hub found
[    2.177922] hub 1-0:1.0: 1 port detected
[    2.182188] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[    2.186341] hub 2-0:1.0: USB hub found
[    2.200626] hub 2-0:1.0: 1 port detected
[    2.201823] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[    2.203699] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 3
[    2.209233] xhci-hcd xhci-hcd.1.auto: USB3 root hub has no ports
[    2.216574] xhci-hcd xhci-hcd.1.auto: hcc params 0x0220f665 hci version 0x100 quirks 0x0000008002000010
[    2.222883] xhci-hcd xhci-hcd.1.auto: irq 61, io mem 0x06000000
[    2.232874] hub 3-0:1.0: USB hub found
[    2.237819] hub 3-0:1.0: 1 port detected
[    2.244783] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[    2.253533] init: - preinit -
[    6.180521] random: crng init done
Cannot parse config file '/etc/fw_env.config': No such file or directory
Failed to find NVMEM device
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
[   10.843440] procd: - early -
[   10.843675] procd: - watchdog -
[   11.381894] procd: - watchdog -
[   11.382754] procd: - ubus -
[   11.437516] procd: - init -
Please press Enter to activate this console.
[   11.814361] kmodloader: loading kernel modules from /etc/modules.d/*
[   11.824489] Loading modules backported from Linux version v6.11.2-0-g7aa21fec187b
[   11.824548] Backport generated by backports.git v6.1.110-1-32-gc61f71fe0942
[   11.942190] PPP generic driver version 2.4.2
[   11.943477] NET: Registered PF_PPPOX protocol family
[   12.691840] urngd: v1.0.2 started.
[   12.906842] ath10k_ahb a000000.wifi: qca4019 hw1.0 target 0x01000000 chip_id 0x003b00ff sub 0000:0000
[   12.906945] ath10k_ahb a000000.wifi: kconfig debug 0 debugfs 1 tracing 0 dfs 1 testmode 0
[   12.918976] ath10k_ahb a000000.wifi: firmware ver 10.4b-ct-4019-fW-13-5ae337bb1 api 5 features mfp,peer-flow-ctrl,txstatus-noack,wmi-10.x-CT,ratemask-CT,regdump-CT,txrate-CT,flush-all-CT,pingpong-CT,ch-regs-CT,nop-CT,set-special-CT,tx-rc-CT,cust-stats-CT,txrate2-CT,beacon-cb-CT,wmi-block-ack-CT,wmi-bcn-rc-CT crc32 6b2b5c5b
[   12.958820] ath10k_ahb a000000.wifi: failed to fetch board data for bus=ahb,vendor=0000,device=0000,subsystem-vendor=0000,subsystem-device=0000,variant=TP-Link_Deco_M9 from ath10k/QCA4019/hw1.0/board-2.bin
[   13.168159] ath10k_ahb a000000.wifi: failed to fetch board-2.bin or board.bin from ath10k/QCA4019/hw1.0
[   13.168224] ath10k_ahb a000000.wifi: failed to fetch board file: -12
[   13.176656] ath10k_ahb a000000.wifi: could not probe fw (-12)
[   14.094538] ath10k_ahb a800000.wifi: qca4019 hw1.0 target 0x01000000 chip_id 0x003b00ff sub 0000:0000
[   14.094613] ath10k_ahb a800000.wifi: kconfig debug 0 debugfs 1 tracing 0 dfs 1 testmode 0
[   14.106584] ath10k_ahb a800000.wifi: firmware ver 10.4b-ct-4019-fW-13-5ae337bb1 api 5 features mfp,peer-flow-ctrl,txstatus-noack,wmi-10.x-CT,ratemask-CT,regdump-CT,txrate-CT,flush-all-CT,pingpong-CT,ch-regs-CT,nop-CT,set-special-CT,tx-rc-CT,cust-stats-CT,txrate2-CT,beacon-cb-CT,wmi-block-ack-CT,wmi-bcn-rc-CT crc32 6b2b5c5b
[   14.139251] ath10k_ahb a800000.wifi: failed to fetch board data for bus=ahb,vendor=0000,device=0000,subsystem-vendor=0000,subsystem-device=0000,variant=TP-Link_Deco_M9 from ath10k/QCA4019/hw1.0/board-2.bin
[   14.353826] ath10k_ahb a800000.wifi: failed to fetch board-2.bin or board.bin from ath10k/QCA4019/hw1.0
[   14.353912] ath10k_ahb a800000.wifi: failed to fetch board file: -12
[   14.362301] ath10k_ahb a800000.wifi: could not probe fw (-12)
[   14.375104] kmodloader: done loading kernel modules from /etc/modules.d/*
[   29.199508] ipqess-edma c080000.ethernet eth0: configuring for fixed/internal link mode
[   29.200365] ipqess-edma c080000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx

Patch file:

diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
index 4732a14b1b..aa56aa87e2 100644
--- a/package/firmware/ipq-wifi/Makefile
+++ b/package/firmware/ipq-wifi/Makefile
@@ -54,6 +54,7 @@ ALLWIFIBOARDS:= \
 	skspruce_wia3300-20 \
 	spectrum_sax1v1k \
 	tplink_eap660hd-v1 \
+  tplink_deco-m9plus \
 	wallys_dr40x9 \
 	xiaomi_ax3600 \
 	xiaomi_ax9000 \
@@ -181,6 +182,7 @@ $(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_eap660hd-v1,TP-Link EAP660 HD v1))
+$(eval $(call generate-ipq-wifi-package,tplink_deco-m9plus,TP-Link Deco M9Plus v2))
 $(eval $(call generate-ipq-wifi-package,wallys_dr40x9,Wallys DR40X9))
 $(eval $(call generate-ipq-wifi-package,xiaomi_ax3600,Xiaomi AX3600))
 $(eval $(call generate-ipq-wifi-package,xiaomi_ax9000,Xiaomi AX9000))
diff --git a/package/firmware/ipq-wifi/board-tplink_deco-m9plus.qca4019 b/package/firmware/ipq-wifi/board-tplink_deco-m9plus.qca4019
new file mode 100644
index 0000000000..834ee55272
Binary files /dev/null and b/package/firmware/ipq-wifi/board-tplink_deco-m9plus.qca4019 differ
diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
index e3a6e24228..1a4668fda5 100644
--- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
@@ -129,6 +129,10 @@ ipq40xx_setup_interfaces()
 		ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
 		ucidef_set_interface "wan" device "/dev/cdc-wdm0" protocol "qmi"
 		;;
+	tplink,deco-m9plus-v2)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" "1" "1"
+		;;
 	netgear,lbr20)
 		ucidef_set_interface_lan "lan1 lan2"
 		ucidef_set_interface "wan" device "/dev/cdc-wdm0" protocol "qmi"
diff --git a/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dts b/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dts
new file mode 100644
index 0000000000..0839e88ae9
--- /dev/null
+++ b/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dts
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: ISC
+// Copyright (c) 2015, The Linux Foundation. All rights reserved.
+// Copyright (c) 2021, Frank Veltmans <veltmans.frank@gmail.com>
+#include "qcom-ipq4019-deco-m9plus-v2.dtsi"
+/ {
+	model = "TP-Link Deco M9Plus v2";
+	compatible = "tplink,deco-m9plus-v2";
+	leds {
+		compatible = "gpio-leds";
+		led_red: led-0 {
+			label = "red:fault";
+			gpios = <&tlmm 28 GPIO_ACTIVE_LOW>;
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+		led_green: led-1 {
+			label = "green:power";
+			gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+		};
+		led_blue: led-2 {
+			label = "blue:boot";
+			gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
+			color = <LED_COLOR_ID_BLUE>;
+			function = LED_FUNCTION_BOOT;
+		};
+	};
+};
diff --git a/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dtsi b/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dtsi
new file mode 100644
index 0000000000..85afb5c00d
--- /dev/null
+++ b/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-deco-m9plus-v2.dtsi
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: ISC
+// Copyright (c) 2015, The Linux Foundation. All rights reserved.
+// Copyright (c) 2021, Frank Veltmans <veltmans.frank@gmail.com>
+#include "qcom-ipq4019.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+#include <dt-bindings/leds/common.h>
+/ {
+	chosen {
+		bootargs-append = " root=/dev/mtdblock16";
+	};
+	aliases {
+		led-boot = &led_blue;
+		led-failsafe = &led_red;
+		led-running = &led_green;
+		led-upgrade = &led_red;
+		label-mac-device = &swport4;
+	};
+	keys {
+		compatible = "gpio-keys";
+		reset {
+			label = "reset";
+			gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+	soc {
+		tcsr@194b000 {
+			compatible = "qcom,tcsr";
+			reg = <0x194b000 0x100>;
+			qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
+			status = "okay";
+		};
+		tcsr@1949000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1949000 0x100>;
+			qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+		};
+		tcsr@1957000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1957000 0x100>;
+			qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
+		};
+		ess_tcsr@1953000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1953000 0x1000>;
+			qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
+		};
+	};
+};
+&tlmm {
+	serial_0_pins: serial_0_pinmux {
+		pinmux {
+			pins = "gpio16", "gpio17";
+			function = "blsp_uart0";
+			bias-disable;
+		};
+	};
+	serial_1_pins: serial_1_pinmux {
+		pinmux {
+			pins = "gpio8", "gpio9", "gpio10", "gpio11";
+			function = "blsp_uart1";
+			bias-disable;
+		};
+	};
+	spi_0_pins: spi_0_pinmux {
+		pinmux {
+			pins = "gpio13", "gpio14", "gpio15";
+			function = "blsp_spi0";
+			drive-strength = <12>;
+			bias-disable;
+		};
+		pinmux_cs {
+			pins = "gpio12";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-disable;
+			output-high;
+		};
+	};
+	i2c_0_pins: i2c_0_pinmux {
+		pinmux {
+			pins = "gpio20", "gpio21";
+			function = "blsp_i2c0";
+			drive-strength = <16>;
+			bias-disable;
+		};
+	};
+	wifi_pins: wifi_pinmux {
+		pinmux_1 {
+			pins = "gpio37";
+			function = "gpio";
+			drive-strength = <6>;
+			bias-pull-up;
+			output-high;
+		};
+		pinmux_2 {
+			pins = "gpio42";
+			function = "gpio";
+			drive-strength = <6>;
+			bias-pull-up;
+			output-high;
+		};
+		pinmux_3 {
+			pins = "gpio43";
+			function = "gpio";
+			drive-strength = <6>;
+			bias-pull-up;
+		};
+	};
+};
+&blsp_dma {
+	status = "okay";
+};
+&blsp1_i2c3 {
+	pinctrl-0 = <&i2c_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+&blsp1_uart1 {
+	pinctrl-0 = <&serial_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+&blsp1_uart2 {
+	pinctrl-0 = <&serial_1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+&blsp1_spi1 {
+	pinctrl-0 = <&spi_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+	m25p80@0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <24000000>;
+		partitions {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fixed-partitions";
+			partition@0 {
+				label = "0:SBL1";
+				reg = <0x00000000 0x00030000>;
+				read-only;
+			};
+			partition@30000 {
+				label = "0:BOOTCONFIG";
+				reg = <0x00030000 0x00010000>;
+				read-only;
+			};
+			partition@40000 {
+				label = "0:MIBIB";
+				reg = <0x00040000 0x00010000>;
+				read-only;
+			};
+			partition@50000 {
+				label = "0:BOOTCONFIG1";
+				reg = <0x00050000 0x00010000>;
+				read-only;
+			};
+			partition@60000 {
+				label = "0:QSEE";
+				reg = <0x00060000 0x00060000>;
+				read-only;
+			};
+			partition@c0000 {
+				label = "0:CDT";
+				reg = <0x000c0000 0x00010000>;
+				read-only;
+			};
+			partition@d0000 {
+				label = "0:DDRPARAMS";
+				reg = <0x000d0000 0x00010000>;
+				read-only;
+			};
+			partition@e0000 {
+				label = "0:APPSBLENV";
+				reg = <0x000e0000 0x00010000>;
+				read-only;
+			};
+			partition@f0000 {
+				label = "0:APPSBL";
+				reg = <0x000f0000 0x00080000>;
+				read-only;
+			};
+			partition@170000 {
+				label = "0:ART";
+				reg = <0x00170000 0x00010000>;
+				read-only;
+				compatible = "nvmem-cells";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				precal_art_1000: precal@1000 {
+					reg = <0x1000 0x2f20>;
+				};
+				precal_art_5000: precal@5000 {
+					reg = <0x5000 0x2f20>;
+				};
+			};
+			partition@180000 {
+				label = "OPAQUE";
+				reg = <0x00180000 0x000c0000>;
+				read-only;
+				compatible = "nvmem-cells";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				macaddr_config_0: macaddr@0 {
+					reg = <0x8 0x6>;
+				};
+			};
+			partition@240000 {
+				label = "0:HLOS";
+				reg = <0x00240000 0x00300000>;
+				read-only;
+			};
+			partition@540000 {
+				label = "0:rootfs";
+				reg = <0x00540000 0x007d0000>;
+				read-only;
+			};
+			partition@d10000 {
+				label = "0:APPSBL_1";
+				reg = <0x00d10000 0x00080000>;
+				read-only;
+			};
+			partition@d90000 {
+				label = "firmware";
+				reg = <0x00d90000 0x01040000>;
+			};
+		};
+	};
+};
+&crypto {
+	status = "okay";
+};
+&cryptobam {
+	status = "okay";
+};
+&usb2 {
+	status = "okay";
+};
+&usb2_hs_phy {
+	status = "okay";
+};
+&usb3 {
+	status = "okay";
+};
+&usb3_hs_phy {
+	status = "okay";
+};
+&usb3_ss_phy {
+	status = "okay";
+};
+&mdio {
+	status = "okay";
+};
+&watchdog {
+	status = "okay";
+};
+&gmac {
+	status = "okay";
+};
+&switch {
+	status = "okay";
+};
+&swport4 {
+	status = "okay";
+	label = "lan";
+	nvmem-cell-names = "mac-address";
+	nvmem-cells = <&macaddr_config_0>;
+};
+&swport5 {
+	status = "okay";
+	label = "wan";
+	nvmem-cell-names = "mac-address";
+	nvmem-cells = <&macaddr_config_0>;
+	mac-address-increment = <1>;
+};
+&wifi0 {
+	pinctrl-0 = <&wifi_pins>;
+	pinctrl-names = "default";
+	qcom,ath10k-calibration-variant = "TP-Link_Deco_M9Plus_v2.0";
+	status = "okay";
+	nvmem-cell-names = "pre-calibration", "mac-address";
+	nvmem-cells = <&precal_art_1000>, <&macaddr_config_0>;
+	mac-address-increment = <2>;
+};
+&wifi1 {
+	qcom,ath10k-calibration-variant = "TP-Link_Deco_M9Plus_v2.0";
+	status = "okay";
+	nvmem-cell-names = "pre-calibration", "mac-address";
+	nvmem-cells = <&precal_art_5000>, <&macaddr_config_0>;
+	mac-address-increment = <3>;
+};
diff --git a/target/linux/ipq40xx/image/generic.mk b/target/linux/ipq40xx/image/generic.mk
index 478e399d0c..88bd87c31a 100644
--- a/target/linux/ipq40xx/image/generic.mk
+++ b/target/linux/ipq40xx/image/generic.mk
@@ -2,6 +2,7 @@
 DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID
 DEVICE_VARS += RAS_BOARD RAS_ROOTFS_SIZE RAS_VERSION
 DEVICE_VARS += WRGG_DEVNAME WRGG_SIGNATURE
+DEVICE_VARS += TPLINK_BOARD_ID
 
 define Build/netgear-fit-padding
 	./netgear-fit-padding.py $@ $@.new
@@ -1117,6 +1118,26 @@ define Device/sony_ncp-hg100-cellular
 endef
 TARGET_DEVICES += sony_ncp-hg100-cellular
 
+define Device/tplink-zImage
+	DEVICE_VENDOR := TP-Link
+	IMAGES += factory.bin
+	IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
+	IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade | append-metadata
+	KERNEL_SUFFIX := -zImage.itb
+	KERNEL = kernel-bin | fit none $(KDIR)/image-$$(DEVICE_DTS).dtb
+	KERNEL_NAME := zImage
+	SOC := qcom-ipq4019
+	TPLINK_BOARD_ID :=
+endef
+define Device/tplink_deco-m9plus-v2
+	$(call Device/tplink-zImage)
+	DEVICE_MODEL := Deco-M9Plus
+	DEVICE_VARIANT := v2
+	TPLINK_BOARD_ID := DECO-M9Plus
+	IMAGE_SIZE := 16640k
+endef
+TARGET_DEVICES += tplink_deco-m9plus-v2
+
 define Device/teltonika_rutx10
 	$(call Device/FitImage)
 	$(call Device/UbiFit)