OpenWrt support for TP Link EAP115

Why don't you try to flash stock firmware via TP-Link web interface. Stock image contains partition table, product info, kernel and file system. Only missing part is uboot and art (this you don't touch and better backap ASAP)

If it really does replace product info, I may be in luck (are you sure it does??)... but there is no TP-Link web interface to do this from. Hopefully I can do it from recovery (hold reset button when powering on - causes u-boot to download recovery.bin over tftp and boot it), after I put to proper u-boot code in place .... maybe??? :thinking:

I tough you still have stack firmware in ROM :frowning: If not than you need to recover - maybe the idea would be to download stock firmware and decompose it into single partitions (if I remember well tplink-safeloader.c or osafeloader.c utilities can do that). Having separate partition images you can upload them to u-boot session and write to flash one by one.

Can you describe your current status, ROM content?

In a word? "mess" :laughing:

I have a partition table that looks like a CPE210 v3. This was done by overwriting the first 256k with the file offered in the other discussion, then installing an OpenWRT image for CPE210 v3.

I'll look into disassembling the stock image. If that doesn't get me anywhere, I might try writing your u-boot code and product info (etc) early partitions, then attempt a recovery.

Unfortunately it appears that the stock image does not include product-info :frowning:

$ mkdir eap110-stock && ~/openwrt-ws/eap110v4/staging_dir/host/bin/tplink-safeloader -x ~/Desktop/EAP110v4_5.0.4_\[20220216-rel57495\]_up_signed.bin -d eap110-stock
$ cd eap110-stock/
$ ls -al
total 5576
drwxr-xr-x 2 imacdonn imacdonn    4096 Jan  1 14:35 .
drwxrwxrwt 5 root     root        4096 Jan  1 14:35 ..
-rw-r--r-- 1 imacdonn imacdonn 4866048 Jan  1 14:35 file-system
-rw-r--r-- 1 imacdonn imacdonn  820360 Jan  1 14:35 os-image
-rw-r--r-- 1 imacdonn imacdonn    2048 Jan  1 14:35 partition-table
-rw-r--r-- 1 imacdonn imacdonn      24 Jan  1 14:35 soft-version
-rw-r--r-- 1 imacdonn imacdonn     169 Jan  1 14:35 support-list

That's not good. Probably you need to reverse engineer a bit product-info partition. Here is what I've found so far:

offset: content description         
0x0000: 8 times 0x00
0x0008: 6 bytes of MAC address as per label on your device (MSB goes first) trailing with 0xff
0x0020: 40 characters of some ID trailing with 0xff
0x0060: 8*16 bytes (1024-bits) of something (maybe signature key)?
0x0160: 00 00 00 'EU276' - maybe kind of region/country descriptor trailing with 0xff
0x0190: 'signed' text followed by 0xff 
0x1000: Support list followed by 0xff
0x1100: Device type, version, keys and HWID (all text strings); first 4 bytes contains length, while entire text filed starts at 0x1108; all trailing with 0xff
0x2000: Software version (BCD: 0x2009), date (BCD: 0x200C) , release tag (uint32: 0x2010), compatibility value (uint32: 0x2014); first 4 bytes contains length of filed starting at 0x2008

Hope this is good starting point to recreate product-info image for your dev.
Good luck!

Here more structured way to describe product-info partition and its sub-partitions (based on stock image EAP115v4_5.0.4_[20220216-rel57495]_up_signed.bin)

// block: mtd2, base: 0x00030000, size: 64kB
	// base: 0x00030000, size: 4096bytes
		// offset: 0x0000
			u32 lenght = 0x06;
			u32 pad_zero = 0x00000000;

		// offset: 0x0008
		u8 mac_addr[] = "\xAC\x84\xC6..."; 	// six hex from dev label
		// offset: 0x0020
		u8 string[48] = "80...B7";
		// offset: 0x0060
		u8 key[8*16] = '1024bits data chunk'
		// offset: 0x0160
		u32 foo = 0x00000080;			// region code lenght?
		u8 region[8] =  "EU276\x00\x00\x00";
		// offset: 0x0190
		u8 signature_status [] = "signed";
	// base: 0x00031000, size 256bytes
		// offset: 0x0000
			u32 lenght = 0x000000a1;
			u32 pad_zero = 0x00000000;
		// offset: 0x0008
		u8 support_list[] = 	
			"EAP110(TP-LINK|UN|N300-2):4.0  841\r\n"
			"EAP115(TP-LINK|UN|N300-2):4.0  841\r\n"
	// base: 0x00031100, size: 1024bytes
		// offset: 0x0000
			u32 lenght = 0x000001e5;
			u32 pad_zero = 0x00000000;
		// offset: 0x0008
		u8 dev_info[] =
			"EAP115(TP-LINK|UN|N300-2):4.0\r\n"	// device type string
			"key=BgIAAAA......GO7w==\r\n"		//
			"rsaKey=BgIAAACk.....8ffyjr4uQ==\r\n"	//
			"HWID=7E63...51EF\r\n"			// string of 16 hex bytes

	// base: 0x00032000, size: 256bytes
		// offset: 0x0000
			u32 lenght = 0x00000010;
			u32 pad_zero = 0x00000000;
		// offset: 0x0008
		u8 pad = 0xff;
		u8 ver_major = 0x05;		// 5.0.4
		u8 ver_minor = 0x00;
		u8 ver_patch = 0x04;
		u8 year_hi = 0x20;		// 2022-02-16
		u8 year_lo = 0x22;
		u8 month = 0x02;
		u8 day = 0x16;
		u32 rev = 0x0000e097; 		// rel57495
		u32 compat_level = 0x00000001;

Yeah, I think it might be a lost cause - I think I'm going to be stuck with my frankenstein EAP110's that think they're CPE210's.

I was able to write the old u-boot code, but I can't figure out how to get it to boot a recovery image. With the CPE210 version, I hold the reset button while powering on.

I tried copying the os-image and file-system partitions from the stock TP-Link images. I can get it to boot from the EAP110 ones, but it thinks that it's a EAP115, and complains about rsa failures, and no web interface nor ssh server comes up (I do get a login prompt on the serial console, but don't know how to login). Curiously I cannot get it to boot with the EAP115 os-image. Apparently they are different formats:

# binwalk eap110-stock/os-image

0             0x0             ELF, 32-bit MSB MIPS64 executable, MIPS, version 1 (SYSV)
39712         0x9B20          LZMA compressed data, properties: 0x6D, dictionary size: 1048576 bytes, uncompressed size: -1 bytes
# binwalk eap115-stock/os-image

0             0x0             TP-Link firmware header, firmware version: 0.0.0, image version: "", product ID: 0x0, product version: 0, kernel load address: 0x0, kernel entry point: 0x80, kernel offset: 0, kernel length: 512, rootfs offset: 887794, rootfs length: 0, bootloader offset: 0, bootloader length: 0
512           0x200           LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2689332 bytes

Losing hope at this point .. I can still use these with my hacked OpenWRT, but may not be able to help much with testing of your code for official submission....

Don't give up, put a bit of structure here. What I've understood the CPE210 u-boot (256kB) overwritten your original u-boot (128kB), partition-table (64kB) and product-info (64kB) partitions. Is that correct? This is what I would do:

  • u-boot and partition-table taken from my backup (EAP115)
  • product-info recreate as much as possible based on EAP115 example and content described above; use hex-editor; for file analysis don't rely on binwalk - just look inside with hexdump
  • os-image and file-system extract from stock firmware file
  • having all this peaces I would write them in u-boot one by one
  • than restart, maybe if necessary with factory reset (see device manual how to enter it)
    What do you thing about such approach?

If this doesn't work you need to wait until stable OpenWRT is there and flash firmware partition only while others (except art and default-mac) are irrelevant for OpenWRT.

Essentially. Actually it's because the file that was sold as a u-boot replacement actually includes those other partitions as well as u-boot itself.

The problem here is that I don't know what the keys and the HWID are used for, but I'm assuming that I need the right values for my hardware (if I want the stock TP-Link sofware to work), and I don't have those.

[start edit]
EXCEPT ..... as I was composing this post, I found them! I have an old log of the serial console when the stock TP-Link firmware was booting before I clobbered it with CPE210 bits, and it had blurted out:

[NM_Debug](nm_lib_getProductInfoFromNvram) 00928: productinfo from NVRAM is (EAP110(TP-LINK|UN|N300-2):4.0


So now I need to work on injecting that data into the partition image.

I'll send the rest of what I'd composed anyway....
[end edit]

I've tried most of what you're suggesting already - basically I copied all of your stuff into my device (except ART). If I try to boot with that, it fails with ## No elf image at address 0x9f040000. I assume that the u-boot code must be probing something to determine what type of device it's on and deciding what type of kernel it wants based on that. If this is the case, I wonder if the OpenWRT images will need to be built differently for EAP110 vs EAP115 also.

I've also tried writing the os-image and file-system from the TP-Link stock images. With the EAP115 ones, it fails the same way as above. With the EAP110 ones, the TP-Link code boots, but identifies itself as an EAP115, and fails to start up any services, complaining about Rsa verify fail (those keys, presumably)... I can't get it back to being a real EAP110, and I can't get it to be a fake EAP115.

Now where did I put my hex editor?....

You are on good path - crossing fingers

Original TP-LInks u-boot expect self-executable loader at the beginning of kernel to decompress it RAM and start kernel. u-boot executes bootelf 0x9f040000 command therefore your kernel partition has to contain loader (check 4 first bytes against 7f 45 4c 46 '.ELF').

Make sure that the images really contain what you expect. Look into them with hexdump to confrm signatures (ELF for os-system, and hsqs for file-system).

Now hexeditor is your friend :slight_smile:

Hi @Lpcvoid
From GPIO conf files look that your device has external watchdog. Can you list reference and type of all ICs on the board (except SoC and memories). This may be needed to understand HW architecture details and handle it properly in OpenWRT firmware

Quite some activity here, awesome :slight_smile:

I really can't contribute much due to IRL stuff, but here are some better pictures which hopefully help. I will sit down and ID all the ICs later.

Hi All,

We decided that I was hijacking this thread a bit with my attempts to restore my EAP110 v4 to stock state. I was able to get mostly there in the end. A quick summary out findings might be helpful to others, so...

It turns out that there is some device-specific data in the region starting at offset 0x030000 - particularly the MAC address (easy to find and replace), some data about the product (fortunately I was able to recover this from an old serial console log), and some data relating to RSA signature verification, which we don't fully understand yet (and I don't have a copy of mine to restore). Using the data from @gutmaj 's EAP115 v4, I was able to get TP-Link firmware to boot, but it fails signature verification. As a last-ditch effort, I tried changing the string "signed" to "unsigned", and voilà! - the TP-Link firmware works again.

I'd really like to try to get signature verification working again (to get as close to completely stock as possible). If anyone has an unadulterated EAP110 v4 or EAP110-Outdoor v3, it'd be really useful if you could dump your MTD (no need to include the user-config partition, so should be nothing private). Only ssh access (with TP-Link stock firmware installed) is required to capture the dumps.

Thanks to @gutmaj for motivating me to persevere through this!

Here's a summary of the hacking I to do (so far) to get to my current state - all of this pertains to copying data (some of it hacked with a hex editor) to flash with u-boot, via serial console (and data transfer over tftp):

  • u-boot - copy of mtdblock0 from EAP115 v4 (offset 0x000000 size 0x020000)
  • partition table - copy of mtdblock1 from EAP115 v4 backup (offset 0x020000 size 0x010000)
  • device-specific data - MODIFIED copy of mtdblock2 from EAP115 v4 backup (offset 0x030000 size 0x010000)
    • offset 0x08 - substitute MAC address of target device (from sticker)
    • offset 0x190 - replace "signed" string with "unsigned"
    • offset 0x1100 - replace product-info text blob (CRLF betwen lines) with values for EAP110
  • os-image (kernel) - taken from EAP110 stock TP-Link image (extracted with tplink-safeloader) (offset 0x040000 size 0x180000)
  • file-system - taken from EAP110 stock TP-Link image (extracted with tplink-safeloader) (offset 0x1c0000 size 0x600000)
  • user-config - erase - factory config will be used/written on boot (offset 0x7c0000 size 0x030000)

Hello all there.
Here comes build5. It contains flashable factory and sysupgrade images as well initramfs. You will find there also the changes I did and additional DTS files created for EAP11x devices.

Remarks and known issues:

  • to enable flashing from TP-Link's web gui you have to disable RSA signature checking; easiest way is to ssh login and invoke cliclientd stopcs
  • when image boots automatically by u-boot from flash the ethernet switch is inoperable (workaround: interrupt u-boot by Ctrl+B and invoke kernel manually by bootelf 0x9f040000)
  • EAP115-Wall not yet supported (only DTS predisposition created)
  • missing entries in 02_network script for EAP110, EAP100-Outdoor and EAP115-Wall variants; will be fixed with next build.

Hope we will overcome (thanks to @Dseven for concurrent support and testing) ethernet switch issue and will provide new build soon. We are looking for volunteers to test these files on their devices. Step-by-step flashing instruction will follow when stable, solid and operable build available. Nevertheless brave people can rely on the posts above which contains more or less everything needed to backup (important, it's your assurance if something goes wrong!!) and flash.

Stay tuned :slight_smile:

Here some more points related to mac initialization issue. Any help or troubleshooting hints are welecome.

Problem statement: Ethernet switch/port inoperable when automatically boot factory by u-boot. While boot after u-boot interrupt by <Ctrl+B> causes same image to have eth0 operable. It looks that interrupted u-boot initialize SoC mac, while in automatic boot chain it expects mac initialization by kernel.

EAP115 v4 Configuration: there are phy0..4 on the QCA9533 SoC, however for this device only phy4 is physically connected to LAN port (eth0).

Problems observed in `factory` image kernel log when booting automatically
# dmesg output
ag71xx 19000000.eth: Could not connect to PHY device. Deferring probe.

# switch configs not present
root@OpenWrt:/# swconfig dev switch0 show
Failed to connect to the switch. Use the "list" command to see which switches are available.
root@OpenWrt:/# swconfig list
Correct setup when booting manually same 'factory' image from flash
# dmesg output
[    1.154790] switch0: Atheros AR8229 rev. 1 switch registered on mdio.0
[    1.552424] ag71xx 19000000.eth: connected to PHY at mdio.0:1f:04 [uid=004dd042, driver=Generic PHY]
[    1.562723] eth0: Atheros AG71xx at 0xb9000000, irq 4, mode: mii

# swconfig present
root@OpenWrt:/# swconfig dev switch0 show
Global attributes:
        enable_vlan: 0
        ar8xxx_mib_poll_interval: 500
        ar8xxx_mib_type: 0
        enable_mirror_rx: 0
        enable_mirror_tx: 0
        mirror_monitor_port: 0
        mirror_source_port: 0
        arl_table: address resolution table

Port 0:
        mib: No MIB data
        pvid: 0
        link: port:0 link:up speed:1000baseT full-duplex txflow rxflow
Port 1:
        mib: No MIB data
        pvid: 0
        link: port:1 link:down
Port 2:
        mib: No MIB data
        pvid: 0
        link: port:2 link:down
Port 3:
        mib: No MIB data
        pvid: 0
        link: port:3 link:down
Port 4:
        mib: No MIB data
        pvid: 0
        link: port:4 link:down
u-boot mac initialization
Hit Ctrl+B to stop autoboot:  0
Net:   ath_gmac_enet_initialize...
No valid address in Flash. Using fixed address
No valid address in Flash. Using fixed address
ath_gmac_enet_initialize: reset mask:c02200
Scorpion ---->S27 PHY*
S27 reg init
: cfg1 0x800c0000 cfg2 0x7114
eth0: 00:03:7f:09:0b:ad
athrs27_phy_setup ATHR_PHY_CONTROL 4 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 4 :10
eth0 up
Honey Bee ---->  MAC 1 S27 PHY *
S27 reg init
ATHRS27: resetting s27
ATHRS27: s27 reset done
: cfg1 0x800c0000 cfg2 0x7214
eth1: 00:03:7f:09:0b:ad
athrs27_phy_setup ATHR_PHY_CONTROL 0 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 0 :10
athrs27_phy_setup ATHR_PHY_CONTROL 1 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 1 :10
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :10
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :10
eth1 up
eth0, eth1
OEM kernel's mac initialization
[    9.008000] qca953x_GMAC: Length per segment 1536
[    9.012000] 953x_GMAC: qca953x_gmac_attach
[    9.016000] Link Int Enabled
[    9.020000] qca953x_set_gmac_caps  CHECK DMA STATUS
[    9.024000] mac:0 Registering S27....
[    9.028000] qca953x_GMAC: RX TASKLET - Pkts per Intr:18
[    9.036000] qca953x_GMAC: RX TASKLET - Timer Freq r:376
[    9.040000] qca953x_GMAC: RX TASKLET - Rx Desc :128
[    9.048000] qca953x_GMAC: Mac address for unit 0:bfff0000
[    9.052000] qca953x_GMAC: ff:ff:ff:ff:ff:ff
[    9.056000] qca953x_GMAC: Max segments per packet :   1
[    9.064000] qca953x_GMAC: Max tx descriptor count :   128
[    9.068000] qca953x_GMAC: Max rx descriptor count :   128
[    9.076000] qca953x_GMAC: Mac capability flags    :   3581
[    9.080000] 953x_GMAC: qca953x_gmac_attach
[    9.084000] Link Int Enabled
[    9.088000] qca953x_set_gmac_caps  CHECK DMA STATUS
[    9.096000] mac:1 Registering S27....
[    9.100000] qca953x_GMAC: RX TASKLET - Pkts per Intr:18
[    9.104000] qca953x_GMAC: RX TASKLET - Timer Freq r:376
[    9.112000] qca953x_GMAC: RX TASKLET - Rx Desc :128
[    9.116000] qca953x_GMAC: Mac address for unit 1:bfff0006
[    9.120000] qca953x_GMAC: ff:ff:ff:ff:ff:ff
[    9.128000] qca953x_GMAC: Max segments per packet :   1
[    9.132000] qca953x_GMAC: Max tx descriptor count :   128
[    9.140000] qca953x_GMAC: Max rx descriptor count :   128
[    9.144000] qca953x_GMAC: Mac capability flags    :   3D81
[   10.104000] athr_gmac_ring_alloc Allocated 2048 at 0x83ad4000
[   10.112000] athr_gmac_ring_alloc Allocated 2048 at 0x83b1a800
[   10.416000] HONEYBEE ----> S27 PHY MDIO 20180115
[   10.424000] Setting Drop CRC Errors, Pause Frames and Length Error frames
[   10.432000] Setting PHY...
[   14.960000] athr_gmac_ring_alloc Allocated 2048 at 0x82c25000
[   14.964000] athr_gmac_ring_alloc Allocated 2048 at 0x83af6800
[   15.272000] HONEYBEE ----> S27 PHY MDIO 20180115
[   15.276000] ATHRS27: resetting s27
[   15.380000] ATHRS27: s27 reset done
[   15.396000] Setting Drop CRC Errors, Pause Frames and Length Error frames
[   15.404000] Setting PHY...

Some open points to be resolved:
Q1: Is DTS node for eth and mac only a HW description for drivers or it also setups registers of SoC?
Q2: How to readout SoC/MAC register on OEM firmware and OpenWRT to compare and verify their settings?

Q3: GMAC0 or GMAC1 should be used in these devices when phy4 connected to LAN port?
Q4: Should mdio in GMAC0 be in status="okay in device-tree?

Unified view on device-tree I've configured for EAP115v4

/ {
	#address-cells = <0x01>;
	#size-cells = <0x01>;
	compatible = "tplink,eap115-v4\0qca,qca9533";
	model = "TP-Link EAP115 v4";

	interrupt-controller {
		compatible = "qca,ar7100-cpu-intc";
		#interrupt-cells = <0x01>;
		qca,ddr-wb-channel-interrupts = <0x03 0x04 0x05>;
		qca,ddr-wb-channels = <0x01 0x02 0x01 0x00 0x01 0x01>;
		phandle = <0x02>;

	ahb {
		compatible = "simple-bus";
		#address-cells = <0x01>;
		#size-cells = <0x01>;
		interrupt-parent = <0x02>;

		apb {
			compatible = "simple-bus";
			#address-cells = <0x01>;
			#size-cells = <0x01>;
			interrupt-parent = <0x03>;

			interrupt-controller@18060010 {
				compatible = "qca,ar7240-misc-intc";
				reg = <0x18060010 0x04>;
				interrupt-parent = <0x02>;
				interrupts = <0x06>;
				#interrupt-cells = <0x01>;
				phandle = <0x03>;

			memory-controller@18000000 {
				compatible = "qca,qca9530-ddr-controller\0qca,ar7240-ddr-controller";
				reg = <0x18000000 0x128>;
				#qca,ddr-wb-channel-cells = <0x01>;
				phandle = <0x01>;

			uart@18020000 {
				compatible = "ns16550a";
				reg = <0x18020000 0x20>;
				interrupts = <0x03>;
				clocks = <0x04 0x03>;
				clock-names = "uart";
				reg-io-width = <0x04>;
				reg-shift = <0x02>;

			usb-phy@18030000 {
				compatible = "qca,ar7200-usb-phy";
				reg = <0x18030000 0x100>;
				#phy-cells = <0x00>;
				reset-names = "usb-phy-analog\0usb-phy\0usb-suspend-override";
				resets = <0x05 0x0b 0x05 0x04 0x05 0x03>;
				status = "disabled";
				phandle = <0x0e>;

			gpio@18040000 {
				compatible = "qca,qca9530-gpio\0qca,ar9340-gpio";
				reg = <0x18040000 0x28>;
				interrupts = <0x02>;
				ngpios = <0x14>;
				#gpio-cells = <0x02>;
				#interrupt-cells = <0x02>;
				phandle = <0x0f>;

			pinmux@1804002c {
				compatible = "pinctrl-single";
				reg = <0x1804002c 0x48>;
				#size-cells = <0x00>;
				pinctrl-single,register-width = <0x20>;
				pinctrl-single,function-mask = <0x01>;
				#pinctrl-cells = <0x02>;

				pinmux_jtag_disable_pins {
					pinctrl-single,bits = <0x40 0x02 0x02>;

			pll-controller@18050000 {
				compatible = "qca,qca9530-pll\0syscon";
				reg = <0x18050000 0x48>;
				#clock-cells = <0x01>;
				clock-output-names = "cpu\0ddr\0ahb";
				clocks = <0x06>;
				phandle = <0x04>;

			wdt@18060008 {
				compatible = "qca,qca9530-wdt\0qca,ar7130-wdt";
				reg = <0x18060008 0x08>;
				interrupts = <0x04>;
				clocks = <0x04 0x02>;
				clock-names = "wdt";

			reset-controller@1806001c {
				compatible = "qca,qca9530-reset\0qca,ar7100-reset";
				reg = <0x1806001c 0xac>;
				#reset-cells = <0x01>;
				phandle = <0x05>;

				interrupt-controller {
					compatible = "qca,ar9340-intc";
					interrupt-parent = <0x02>;
					interrupts = <0x02>;
					#interrupt-cells = <0x01>;
					qca,int-status-addr = <0xac>;
					qca,pending-bits = <0x0f 0x1f0>;
					qca,ddr-wb-channel-interrupts = <0x00 0x01>;
					qca,ddr-wb-channels = <0x01 0x04 0x01 0x03>;
					phandle = <0x0b>;

		eth@19000000 {
			status = "okay";
			compatible = "qca,qca9530-eth\0syscon";
			reg = <0x19000000 0x200 0x18070000 0x04>;
			interrupts = <0x04>;
			phy-mode = "mii";
			pll-data = <0x82000101 0x80000101 0x80001313>;
			pll-reg = <0x04 0x2c 0x11>;
			pll-handle = <0x04>;
			reset-names = "mac";
			resets = <0x05 0x09>;
			phy-handle = <0x07>;
			nvmem-cells = <0x08>;
			nvmem-cell-names = "mac-address";
			phandle = <0x09>;

			mdio {
				status = "disabled";
				compatible = "qca,ath79-mdio";
				#address-cells = <0x01>;
				#size-cells = <0x00>;
				regmap = <0x09>;
				clocks = <0x04 0x04>;
				clock-names = "ref";

		eth@1a000000 {
			status = "okay";
			compatible = "syscon\0simple-mfd";
			reg = <0x1a000000 0x200>;
			interrupts = <0x05>;
			phy-mode = "gmii";
			resets = <0x05 0x0d>;
			reset-names = "mac";
			phandle = <0x0a>;

			mdio {
				status = "okay";
				compatible = "qca,ath79-mdio";
				#address-cells = <0x01>;
				#size-cells = <0x00>;
				regmap = <0x0a>;
				clocks = <0x04 0x04>;
				clock-names = "ref";
				resets = <0x05 0x17>;
				reset-names = "mdio";

				switch0@1f {
					compatible = "qca,ar8229";
					reg = <0x1f>;
					resets = <0x05 0x08>;
					reset-names = "switch";
					phy-mode = "gmii";
					qca,mib-poll-interval = <0x1f4>;

					mdio-bus {
						#address-cells = <0x01>;
						#size-cells = <0x00>;

						ethernet-phy@0 {
							reg = <0x00>;
							phy-mode = "mii";

						ethernet-phy@4 {
							reg = <0x04>;
							phy-mode = "mii";
							phandle = <0x07>;

			fixed-link {
				speed = <0x3e8>;

		gmac@18070000 {
			compatible = "qca,ar9330-gmac";
			reg = <0x18070000 0x04>;

		pcie-controller@180c0000 {
			compatible = "qcom,ar7240-pci";
			#address-cells = <0x03>;
			#size-cells = <0x02>;
			bus-range = <0x00 0x00>;
			reg = <0x180c0000 0x1000 0x180f0000 0x100 0x14000000 0x1000>;
			reg-names = "crp_base\0ctrl_base\0cfg_base";
			ranges = <0x2000000 0x00 0x10000000 0x10000000 0x00 0x4000000 0x1000000 0x00 0x00 0x00 0x00 0x01>;
			interrupt-parent = <0x0b>;
			interrupts = <0x01>;
			device_type = "pci";
			resets = <0x05 0x06 0x05 0x07>;
			reset-names = "hc\0phy";
			#interrupt-cells = <0x01>;
			interrupt-map-mask = <0x00 0x00 0x00 0x01>;
			interrupt-map = <0x00 0x00 0x00 0x00 0x0c 0x00>;
			status = "disabled";
			phandle = <0x0c>;

		wmac@18100000 {
			compatible = "qca,qca9530-wmac";
			reg = <0x18100000 0x20000>;
			interrupt-parent = <0x0b>;
			interrupts = <0x00>;
			status = "okay";
			mtd-cal-data = <0x0d 0x1000>;
			nvmem-cells = <0x08>;
			nvmem-cell-names = "mac-address";

		usb@1b000000 {
			compatible = "generic-ehci";
			reg = <0x1b000000 0x1000>;
			interrupts = <0x03>;
			resets = <0x05 0x05>;
			reset-names = "usb-host";
			dr_mode = "host";
			caps-offset = <0x100>;
			phy-names = "usb-phy";
			phys = <0x0e>;
			status = "disabled";
			#address-cells = <0x01>;
			#size-cells = <0x00>;

		spi@1f000000 {
			compatible = "qca,ar934x-spi";
			reg = <0x1f000000 0x1c>;
			clocks = <0x04 0x02>;
			status = "okay";
			#address-cells = <0x01>;
			#size-cells = <0x00>;

			flash@0 {
				#address-cells = <0x01>;
				#size-cells = <0x01>;
				compatible = "jedec,spi-nor";
				reg = <0x00>;
				spi-max-frequency = <0x17d7840>;

				partitions {
					compatible = "fixed-partitions";
					#address-cells = <0x01>;
					#size-cells = <0x01>;

					partition@0 {
						label = "u-boot";
						reg = <0x00 0x20000>;

					partition@20000 {
						label = "partition-table";
						reg = <0x20000 0x10000>;

					partition@30000 {
						label = "info";
						reg = <0x30000 0x10000>;
						compatible = "nvmem-cells";
						#address-cells = <0x01>;
						#size-cells = <0x01>;

						macaddr@8 {
							reg = <0x08 0x06>;
							phandle = <0x08>;

					partition@40000 {
						label = "firmware";
						reg = <0x40000 0x780000>;
						compatible = "openwrt,elf";

					partition@7c0000 {
						label = "config";
						reg = <0x7c0000 0x30000>;

					partition@7f0000 {
						label = "art";
						reg = <0x7f0000 0x10000>;
						phandle = <0x0d>;

	chosen {
		bootargs = "console=ttyS0,115200n8";

	cpus {
		#address-cells = <0x01>;
		#size-cells = <0x00>;

		cpu@0 {
			device_type = "cpu";
			compatible = "mips,mips24Kc";
			clocks = <0x04 0x00>;
			reg = <0x00>;

	ref {
		compatible = "fixed-clock";
		#clock-cells = <0x00>;
		clock-output-names = "ref";
		clock-frequency = <0x17d7840>;
		phandle = <0x06>;

	aliases {
		label-mac-device = "/ahb/wmac@18100000";
		led-boot = "/leds/status_green";
		led-failsafe = "/leds/status_amber";
		led-running = "/leds/status_green";
		led-upgrade = "/leds/status_amber";

	keys {
		compatible = "gpio-keys";

		reset {
			label = "Reset button";
			linux,code = <0x198>;
			gpios = <0x0f 0x11 0x01>;
			debounce-interval = <0x3c>;

	leds {
		compatible = "gpio-leds";

		status_green {
			label = "green:status";
			gpios = <0x0f 0x0e 0x00>;
			color = <0x02>;
			function = "status";

		status_amber {
			label = "amber:status";
			gpios = <0x0f 0x0d 0x00>;
			color = <0x04>;
			function = "status";

		status_red {
			label = "red:status";
			gpios = <0x0f 0x10 0x00>;
			color = <0x01>;
			function = "panic";

After some wading around in the ag71xx and ar8216 drivers, although I don't really know what I'm doing, I'm fairly convinced that these drivers need some basic setup to have been done beforehand. It appears that the TP-Link firmware had code added to the kernel to do this (possibly a kernel module named "ag7240_mod" - but I haven't been able to find the source for it), where other devices, like the CPE210 v3, do it in u-boot (whether or not automatic boot gets interrupted). I do wonder how some of the other qca9533-based TP-Link devices (the ones supported by OpenWRT) handle this. Perhaps they all have u-boot that does the network setup always too?

I'm sortof leaning towards using the CPE210 v3 u-boot again (but not overwriting the other device-specific data this time). It doesn't seem to have ELF support, so the images would need to be built differently (I already had this working). I wonder if it's possible to overwrite u-boot from within the stock TP-Link firmware (i.e. not needing serial console access to do the initial install).

Some evidence of the other QCA9533-based devices doing the network setup BEFORE the point where autoboot can be interrupted:

There are two possibilities either bootloader configures it or kernel. In case of stock firmware they use old 2.6 kernel which doesn't have device tree to look in. In OpenWRT there is a device tree to describe (and I hope configure) needed drivers, but it syntax is difficult to me to understand, but progressing slowly. Definitively other users/developers had similar issue (incl. CPE devices), but I couldn't find solid answer how they overcome it.

It may be uImage format, but check in stock firmware.

Probably you could prepare OEM-like image which will have also u-boot partition incorporated. Again dd, hexedit, and osafeloader will be your friends, but I would recommend to use OpenWRT initramfs with kmod-mtd-rw module added/installed (it enable write to every read-only partition; attention - you may brick your device).

Here is what nvrammanager tool displays
$ nvrammanager -s
partition 01: name = fs-uboot        , base = 0x00000000, size = 0x00020000 Bytes, usedFlag = 1
partition 02: name = partition-table , base = 0x00020000, size = 0x00002000 Bytes, usedFlag = 1
partition 03: name = default-mac     , base = 0x00030000, size = 0x00001000 Bytes, usedFlag = 1
partition 04: name = support-list    , base = 0x00031000, size = 0x00000100 Bytes, usedFlag = 1
partition 05: name = product-info    , base = 0x00031100, size = 0x00000400 Bytes, usedFlag = 1
partition 06: name = soft-version    , base = 0x00032000, size = 0x00000100 Bytes, usedFlag = 1
partition 07: name = os-image        , base = 0x00040000, size = 0x00180000 Bytes, usedFlag = 1
partition 08: name = file-system     , base = 0x001c0000, size = 0x00600000 Bytes, usedFlag = 1
partition 09: name = user-config     , base = 0x007c0000, size = 0x00030000 Bytes, usedFlag = 1
partition 10: name = radio           , base = 0x007f0000, size = 0x00010000 Bytes, usedFlag = 1
partition 11: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 12: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 13: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 14: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 15: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 16: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 17: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 18: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 19: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 20: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 21: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 22: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 23: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 24: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 25: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 26: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 27: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 28: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 29: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 30: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 31: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
partition 32: name =                 , base = 0x00000000, size = 0x00000000 Bytes, usedFlag = 0
Other Addition Partition:
partition 01: name = mac             , base = default-mac , size = 6    Bytes, offset = 0    Bytes
partition 02: name = device-id       , base = default-mac , size = 40   Bytes, offset = 32   Bytes
partition 03: name = signature       , base = default-mac , size = 256  Bytes, offset = 96   Bytes
partition 04: name = region          , base = default-mac , size = 8    Bytes, offset = 356  Bytes
partition 05: name = sign-flag       , base = default-mac , size = 6    Bytes, offset = 400  Bytes
partition 06: name = config-info     , base = user-config , size = 0    Bytes, offset = 0    Bytes
partition 07: name = soft-version    , base = soft-version, size = 0    Bytes, offset = 0    Bytes
partition 08: name = flash           , base = (null)      , size = 0    Bytes, offset = 0    Bytes

Why you want to go back to CPE u-boot? Maybe effort should go to understand how the SoC switch is configured on OEM firmware and than translate it to OpenWRT (very likely specific DTS configs).
I'm right now reviewing TP-Links source code/scripts to find something there.

Because I know it works, and it seems to be the one used by other qca9533 devices already supported by OpenWRT.

I looked at the TP-Link GPL sources for all four EAP11x variants, but I can't find the source for ag7240_mod, which seems to be where the GMAC initialisation stuff lives, as rootfs/lib/modules/2.6.31/net/ag7240_mod.ko contains the strings that we see on the console when it's happening (e.g. qca953x_GMAC)

I've found out from their scripts the ssh server dropbear generates pairs of RSA and DSA private/public keys (private ones are stored in /tmp folder, while public are print in the console). Maybe there is a way to configure host ssh client to use these public keys and login to the EAP11X as root. Then we can dump memory/registers and see how the switch has been configured.

Public keys
# these keys are generated probably on each reboot 
Generating 1024 bit rsa key, this may take a while...
Public key portion is:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCOoi1w2JDtPSmCFz7KWQ1X0H3dQAQHNaC7NRUfSKsCoB9tQVoBG6HZAt5CQZ4eOfgsMZJOjtX4s8Bk7JuSx/4ruc1Uz5FLXlrqkrzQaJEafVObbXyyoutNqS4f6xM25q7vtiAMjvBHOzpsLNhWObSheAAnfJlwFFKeGJ2LJ1i9Sw== root@EAP115
Fingerprint: sha1!! 51:a4:e6:18:8e:0b:86:df:3b:b0:7c:63:0e:6a:64:cd:67:27:e4:13

Generating 1024 bit dss key, this may take a while...
Public key portion is:
ssh-dss AAAAB3NzaC1kc3MAAACBANQYHqQzY12K3RHax7HeylsXutUJhp0yTRvm9N6HcF19OcVR0jsWp/PjQF67YvCrYNjEqF1OnrzvfbBzSOZTpSaUohUBBf07t9Zhl5n2OLm0wFvV4r77KIamYwssp5kyTWF5RibnCoDdqUnWQp7C/y/JyZ+Mb+Lz7g/0/WPb3k93AAAAFQC8nqstBtW4qbddh1d+JPmxpZX3HwAAAIAqzFh6FgNfk8noYSwXDaLIqvFfVW93pb0jJ9Ke3LBZmYTmhDNeYC/qtO3BYrpCZ/8FyLEVq9eM1ILwgJeE/uMBsB4/7cs9NyvWAEtYt9Fmbc31SADz1HuCcDZtVp2WoJuDpCW16/qiSVOi9udNq7jDIg5qW8HUyECMsoSwrGMPcQAAAIEAu4P+nx2aLNHO70V8haXwwum493OGUi2pZHEWz4tpywtMpm9q7hUdTWlTCyyok69uEZqvzV5yLM8P6kVgeawCGIhm8QDXs5jpoDFCOi2joHtJX8F5C9x3vFtwcbpUJ+2NwkgupRI5iTdugDnCMYevLaOMFfAvMugtCCZYZgqkmBc= root@EAP115
Fingerprint: sha1!! f7:a9:2a:47:c6:93:41:12:c6:22:6d:13:db:29:ad:d5:2e:24:52:7f
TPL's script generating key pairs /etc/


if ! test -f $RSA_KEY; then /usr/local/sbin/dropbearkey -t rsa -s 1024 -f $RSA_KEY; fi;
if ! test -f $DSS_KEY; then /usr/local/sbin/dropbearkey -t dss -f $DSS_KEY; fi;

if ! test -f $SSH_PORT
	echo "no file $SSH_PORT"
	port=$(cat $SSH_PORT)
	if [ $SSH_PORT != 0 ]
		/usr/local/sbin/dropbear -p $port -r $RSA_KEY -d $DSS_KEY