Introduction
This guide documents the process of adapting OpenWrt firmware for the TP-Link Deco M9 Plus version 2.0 router, which is based on the Qualcomm IPQ4019 chipset. While OpenWrt already supports the IPQ4019 platform, adding support for a specific device requires careful configuration of device-specific parameters including memory layout, flash partitioning, network interfaces, and GPIO assignments.
Hardware Overview
The target device features the following specifications:
Software Adaptation
Device Profile Creation
Working within the IPQ40xx target directory, we establish a new device profile following OpenWrt's naming conventions. Based on existing Deco series entries, the identifeir tplink,deco-m9-plus-v2 is adopted.
The integration involves updating several key files in the base system:
Network Configuration
## File: target/linux/ipq40xx/base-files/etc/board.d/02_network
## Add the new device to the interface mapping
case "$board" in
tplink,deco-m9-plus-v2|\
asus,map-ac2200|\
edgecore,ecw5211|\
...)
ucidef_set_interfaces_lan_wan "eth1" "eth2"
;;
esac
Wireless Calibration Data
## File: target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
## Extract calibration data from ART partition
"ath10k/pre-cal-pci-0000:01:00.0.bin")
case "$board" in
tplink,deco-m9-plus-v2|\
asus,map-ac2200)
caldata_extract_ubi "art" 0x9000 0x2f20
;;
esac
;;
"ath10k/pre-cal-ahb-a000000.wifi.bin")
case "$board" in
tplink,deco-m9-plus-v2|\
asus,map-ac2200|\
asus,rt-ac58u)
caldata_extract_ubi "art" 0x1000 0x2f20
;;
esac
;;
MAC Address Assignment
## File: target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh
## Configure interface MAC addresses based on factory data
preinit_configure_mac_addresses() {
case $(board_name) in
tplink,deco-m9-plus-v2)
base_mac=$(mtd_get_mac_binary_ubi Factory 0x1006)
ip link set dev eth1 address $(macaddr_add "$base_mac" 1)
ip link set dev eth2 address $(macaddr_add "$base_mac" 3)
;;
esac
}
Image Build Configuration
## File: target/linux/ipq40xx/image/generic.mk
## Define build parameters for the new device
define Device/tplink_deco-m9-plus-v2
$(call Device/FitzImage)
$(call Device/UbiFit)
DEVICE_VENDOR := TP-Link
DEVICE_MODEL := Deco M9 Plus
DEVICE_VARIANT := v2
SOC := qcom-ipq4019
DEVICE_DTS_CONFIG := config@ap.dk07.1-c1
KERNEL_INITRAMFS_SUFFIX := -recovery.itb
IMAGE/factory.ubi := append-ubi
PAGESIZE := 2048
BLOCKSIZE := 128k
KERNEL_SIZE := 4096k
IMAGE_SIZE := 31232k
KERNEL_IN_UBI := 1
DEVICE_PACKAGES := ath10k-firmware-qca9888-ct \
kmod-fs-ext4 kmod-mmc kmod-spi-dev mkf2fs e2fsprogs kmod-fs-f2fs
endef
TARGET_DEVICES += tplink_deco-m9-plus-v2
Device Tree Configuration
The Device Tree Source (DTS) file is the most critical component. Create qcom-ipq4019-deco-m9-plus-v2.dts in the appropriate directory. Many elements can be inherited from the common IPQ4019 DTSI file.
Memory Layout
Configure the 512MB memory mapping:
memory {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
Flash Partitioning
Based on the bootloader output, define the NAND partitions. The ART partition contains calibration data and MAC addresses:
&nand {
status = "okay";
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "sbl1";
reg = <0x0 0x100000>;
read-only;
};
partition@100000 {
label = "mibib";
reg = <0x100000 0x100000>;
read-only;
};
/* ... additional bootloader partitions ... */
partition@880000 {
label = "art";
reg = <0x880000 0x80000>;
read-only;
compatible = "nvmem-cells";
#address-cells = <1>;
#size-cells = <1>;
wifi_cal_2g: caldata@1000 {
reg = <0x1000 0x2f20>;
};
wifi_cal_5g_primary: caldata@5000 {
reg = <0x5000 0x2f20>;
};
wifi_cal_5g_secondary: caldata@9000 {
reg = <0x9000 0x2f20>;
};
mac_base: macaddr@0 {
reg = <0x0 0x6>;
};
};
partition@900000 {
label = "ubi";
reg = <0x900000 0x7680000>;
};
};
};
Wireless Radios Configuration
Configure the three wireless interfaces (2.4GHz, 5GHz primary, and 5GHz secondary):
&wifi0 {
status = "okay";
qcom,ath10k-calibration-variant = "Deco-M9-Plus-v2";
nvmem-cell-names = "pre-calibration", "mac-address";
nvmem-cells = <&wifi_cal_2g>, <&mac_base>;
mac-address-increment = <1>;
};
&wifi1 {
status = "okay";
qcom,ath10k-calibration-variant = "Deco-M9-Plus-v2";
nvmem-cell-names = "pre-calibration", "mac-address";
nvmem-cells = <&wifi_cal_5g_primary>, <&mac_base>;
mac-address-increment = <2>;
};
&pcie0 {
status = "okay";
perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 40 GPIO_ACTIVE_LOW>;
bridge@0,0 {
reg = <0x00000000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
ranges;
wifi2: wifi@1,0 {
compatible = "qcom,ath10k";
reg = <0x00010000 0 0 0 0>;
qcom,ath10k-calibration-variant = "Deco-M9-Plus-v2";
nvmem-cell-names = "pre-calibration", "mac-address";
nvmem-cells = <&wifi_cal_5g_secondary>, <&mac_base>;
};
};
};
Ethernet Ports
&swport4 {
status = "okay";
label = "eth2";
nvmem-cell-names = "mac-address";
nvmem-cells = <&mac_base>;
};
&swport5 {
status = "okay";
label = "eth1";
nvmem-cell-names = "mac-address";
nvmem-cells = <&mac_base>;
};
GPIO Assignments
LED indicators and reset button configuration:
leds {
compatible = "gpio-leds";
system_red: led-0 {
label = "red:system";
gpios = <&tlmm 0 GPIO_ACTIVE_LOW>;
};
system_green: led-1 {
label = "green:system";
gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
};
system_blue: led-2 {
label = "blue:system";
gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
};
};
keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
linux,code = <key_restart>;
};
};
</key_restart>
Build Process
After completing the configuration files, build the firmware:
make menuconfig
# Select Target System: Qualcomm Atheros IPQ40xx
# Select Target Profile: TP-Link Deco M9 Plus v2
make -j$(nproc) V=s
Successful compilation produces these artifacts:
openwrt-ipq40xx-generic-tplink_deco-m9-plus-v2-initramfs-recovery.itb
openwrt-ipq40xx-generic-tplink_deco-m9-plus-v2-squashfs-factory.ubi
openwrt-ipq40xx-generic-tplink_deco-m9-plus-v2-squashfs-sysupgrade.bin
Installation
Flash via U-Boot console:
# Erase UBI partition
nand erase 0x900000 0x7680000
# Load factory image via TFTP
setenv serverip 192.168.0.66
setenv ipaddr 192.168.0.171
tftpboot openwrt-ipq40xx-generic-tplink_deco-m9-plus-v2-squashfs-factory.ubi
# Write to NAND
nand write 0x84000000 0x900000 $filesize
# Configure boot environment
setenv bootargs 'ubi.mtd=ubi root=/dev/ubiblock0_1 rootfstype=squashfs,ubi'
setenv mtdids 'nand0=nand0'
setenv mtdparts 'mtdparts=nand0:0x900000@0x0(boot),0x7680000@0x900000(fs)'
setenv bootkernel 'ubi read 0x84000000 kernel && bootm'
setenv bootcmd 'run bootkernel'
# Save and boot
saveenv
boot
Troubleshooting
If the QCA9886 radio fails to initialize with firmware errors, ensure the correct packages are included in the build configuration:
CONFIG_PACKAGE_ath10k-firmware-qca9888=y
CONFIG_PACKAGE_ath10k-board-qca9888=y
These packages provide the necessary firmware files for the secondary 5GHz radio.