Recovering a TP-Link Archer C59 Router
I had tinkered with OpenWrt on my TP-Link Archer C59 (v1) AC1350 (US) Router, but decided it’s not for me. I appreciate all the work put into that project, but I didn’t like the experience and wanted to restore my router to it’s original stock OEM firmware.
This is where I made a mistake. I uploaded an incorrect firmware file to restore things and rendered my router unusable or “bricked” (not permanently, thankfully). It would not boot into a state where I could use it. The admin web UI was inaccessible and only one LED light was on. I put it in a closet for a few months before trying to restore it. I don’t remember much about exactly what firmware file I uploaded to break things.
I decided I needed to open things up and see if there were any
debugging abilities on the board. There were four unpopulated pins
near a JP1
label. With some research I determined
that this was a serial port I could connect to via a UART device.
I (poorly) soldered four header pins to the board.

Using a video on YouTube and a multimeter I figured out which pin was GND. Notes for a similar board online helped me figure out which pin was TX, RX, and VCC, and I confirmed how to wire the UART cable to the pins. I read that the UART cable I have is 3.3V, which seemed most likely what my router’s board required. I wired up the pins and was able to get data over the serial connection.

I used minicom
to connect to the device.
sudo minicom -b 115200 -D /dev/ttyUSB0
I could see that U-Boot was loading! I could also see an error.
Bad Magic Number
.
U-Boot 1.1.4 (Jul 16 2016 - 18:05:34)
ap151 - Dragonfly 1.0
DRAM: 128 MB
Top of RAM usable for U-Boot at: 88000000
Reserving 342k for U-Boot at: 87fa8000
Reserving 32832k for malloc() at: 85f98000
Reserving 44 Bytes for Board Info at: 85f97fd4
Reserving 36 Bytes for Global Data at: 85f97fb0
Reserving 128k for boot params() at: 85f77fb0
Stack Pointer at: 85f77f98
Now running in RAM - U-Boot at: 87fa8000
Flash Manuf Id 0xef, DeviceId0 0x40, DeviceId1 0x18
flash size 16MB, sector count = 256
Flash: 16 MB
Using default environment
In: serial
Out: serial
Err: serial
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
Dragonfly----> S27 PHY *
: cfg1 0x80000000 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
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 :50
athrs27_phy_setup ATHR_PHY_CONTROL 1 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 1 :50
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :50
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :50
eth1 up
eth0, eth1
Setting 0x181162c0 to 0x82
Autobooting in 1 seconds
## Booting image at 9f020000 ...
Bad Magic Number
ath>
Running tftpboot
with no arguments from the UART
console revealed some helpful information.
ath> tftpboot
Trying eth0
eth0 link down
FAIL
Trying eth1
enet1 port0 up
dup 1 speed 1000
*** Warning: no boot file name; using '0200A8C0.img'
Using eth1 device
TFTP from server 192.168.0.10; our IP address is 192.168.0.2
Filename '0200A8C0.img'.
It seems that the router’s U-Boot shell has a client IP of
192.168.0.2
(statically assigned, because
there’s no DHCP server in play here) and is looking for a
tftp server at 192.168.0.10
and a boot image of
0200A8C0.img
.
printenv
reveals some variables defined on the
router, which confirms the IP addresses used by
tftpboot
.
ath> printenv
bootargs=console=ttyS0,115200 board=AP151 rootfstype=squashfs init=/etc/preinit mtdparts=spi0.0:128k(u-boot),1152k(uImage),15040k(rootfs),64k@0xff0000(ART) mem=128M
bootcmd=bootm 0x9f020000
bootdelay=1
baudrate=115200
ethaddr=0x00:0xaa:0xbb:0xcc:0xdd:0xee
ipaddr=192.168.0.2
serverip=192.168.0.10
dir=
lu=tftp 0x80060000 ${dir}tuboot.bin&&erase 0x9f000000 +$filesize&&cp.b $fileaddr 0x9f000000 $filesize
lf=tftp 0x80060000 ${dir}ap151${bc}-jffs2&&erase 0x9f010000 +$filesize&&cp.b $fileaddr 0x9f010000 $filesize
lk=tftp 0x80060000 ${dir}vmlinux${bc}.lzma.uImage&&erase 0x9f300000 +$filesize&&cp.b $fileaddr 0x9f300000 $filesize
stdin=serial
stdout=serial
stderr=serial
ethact=eth0
Environment size: 681/65532 bytes
It seemed like the pieces were in place for booting the router via
tftp. I wired a laptop to the router using an ethernet cable. I
set a static IP on the ethernet interface of the laptop to match
the IP the router expected for tftpboot
.
ip address flush dev eth0
ip address add 192.168.0.10/24 dev eth0
I set up a dnsmasq
tftp server on the laptop to
handle tftp requests.
dnsmasq \
-i "${device}" \
--enable-tftp \
--tftp-root=/tmp/tftp \
--bootp-dynamic \
--port=0 `# disable DNS. Not needed` \
--no-daemon
Initially, I tried to tftpboot
an OpenWrt
bin
image file I obtained for my router. My thinking
was that I had left the router in a state where perhaps a
bootloader for OpenWrt was installed, but I had improperly
clobbered the boot image somehow, and so maybe
tftpboot
ing to a recent OpenWRT image would fix
things.
tftpboot 192.168.0.10 openwrt-24.10.0-ath79-generic-tplink_archer-c59-v1-squashfs-factory.bin
I saw the corresponding request logged by the
dnsmasq
server.
dnsmasq: started, version 2.90 DNS disabled
dnsmasq: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset nftset auth cryptohash DNSSEC loop-detect inotify dumpfile
dnsmasq-dhcp: DHCP, IP range 10.1.1.50 -- 10.1.1.100, lease time 1h
dnsmasq-tftp: TFTP root is /tmp/tftp
dnsmasq-tftp: sent /tmp/tftp/openwrt-24.10.0-ath79-generic-tplink_archer-c59-v1-squashfs-factory.bin to 192.168.0.2
Back on the router, I did see that the tftpboot
did
seem to work, and loaded the boot image.
ath> tftpboot 192.168.0.10 openwrt-24.10.0-ath79-generic-tplink_archer-c59-v1-squashfs-factory.bin
Trying eth0
eth0 link down
FAIL
Trying eth1
enet1 port2 up
dup 1 speed 1000
Using eth1 device
TFTP from server 192.168.0.10; our IP address is 192.168.0.2
Filename 'openwrt-24.10.0-ath79-generic-tplink_archer-c59-v1-squashfs-factory.bin'.
Load address: 0x192
Loading: #################################################################
#################################################################
... (continued) ...
done
Bytes transferred = 7209888 (6e03a0 hex)
The image was loaded, but nothing was happening. Based on some
Googling, and the output of printenv
, it looked like
the bootcmd
was set to
bootcmd=bootm 0x9f020000
.
However, running that left the system in a state where it was hanging and stuck and had to be rebooted.
ath> bootm 0x9f0200000
## Booting image at f0200000 ...
I tried various mechanisms like go
and
bootm
with various addresses, but could not seem to
get this image to actually boot. I threw a lot of different
commands at the wall to see if something would stick.
My lack of understanding about U-Boot and the format of these boot images was not helping here.
Eventually, I tried something much more rudimentary. I ran the stock recovery process for my router. I…
- Turned the router off
- Held down the reset button
- While the reset button was still held down, I powered on the router
I could see via minicom
that this resulted in a
slightly different state. Without a serial connection, and only
using LEDs to debug, this process previously seemed pointless.
With the serial connection I could see much more helpful
information.
TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'tp_recovery.bin'.
This was interesting. I could see that the router’s reset sequence triggered a specific command for U-Boot.
A note on OpenWrt’s website, which previously seemed odd to me, now made much more sense.
Comment recovery: TFTP recovery filename: tp_recovery.bin (use factory image)
https://openwrt.org/toh/hwdata/tp-link/tp-link_archer_c59_v1
I downloaded the stock TP-Link firmware for my device, renamed it
to tp_recovery.bin
, and put it in my tftp
server’s directory. I also changed the laptop’s IP
address to correspond to what the recovery process seemed to need.
ip address flush dev eth0
ip address add 192.168.0.66/24 dev eth0
I restarted dnsmasq
, used the reset boot sequence
again, and…
eth0 link down
FAIL
Trying eth1
enet1 port2 up
dup 1 speed 1000
Using eth1 device
TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'tp_recovery.bin'.
Load address: 0x80800000
Loading: #################################################################
#################################################################
... (continued) ...
done
Bytes transferred = 11768817 (b393f1 hex)
Firmware recovery: FLASH_SIZE = 16 filesize = 0xb393f1.
Reading Partition Table from NVRAM ... OK
Parsing Partition Table ... OK
File Length:11768817
[Error]sysmgr_proinfo_buildStruct(): 587 @ unknown id(hw_id), skip it.
[Error]sysmgr_proinfo_buildStruct(): 587 @ unknown id(oem_id), skip it.
[Error]sysmgr_cfg_checkSupportList(): 909 @ 00000000 NOT Match.
Firmwave supports, check OK.
Firmware Checking Passed.
######################################################################
######################################################################
##############################################
Done.
All Done!
U-Boot 1.1.4 (Jul 16 2016 - 18:05:34)
...
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :50
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :50
eth1 up
eth0, eth1
Setting 0x181162c0 to 0x82
Autobooting in 1 seconds
## Booting image at 9f020000 ...
Image Name: MIPS OpenWrt Linux-3.3.8
Created: 2016-07-19 9:52:32 UTC
Image Type: MIPS Linux Multi-File Image (lzma compressed)
Data Size: 1069313 Bytes = 1 MB
Load Address: 80060000
Entry Point: 80060000
Contents:
Image 0: 1069305 Bytes = 1 MB
Verifying Checksum at 0x9f020040 ...OK
Uncompressing Multi-File Image ... OK
No initrd
## Transferring control to Linux (at address 80060000) ...
## Giving linux memsize in bytes, 134217728
Starting kernel ...
[ 0.000000] Linux version 3.3.8 (tplink@tplink) (gcc version 4.6.3 20120201 (prerelease) (Linaro GCC 4.6-2012.02) ) #1 Tue Jul 19 17:51:52 HKT 2016
[ 0.000000] bootconsole [early0] enabled
[ 0.000000] CPU revision is: 00019750 (MIPS 74Kc)
[ 0.000000] SoC: Qualcomm Atheros QCA956X rev 0
[ 0.000000] Clocks: CPU:775.000MHz, DDR:650.000MHz, AHB:258.333MHz, Ref:25.000MHz
[ 0.000000] Determined physical RAM map:
[ 0.000000] memory: 08000000 @ 00000000 (usable)
[ 0.000000] User-defined physical RAM map:
[ 0.000000] memory: 08000000 @ 00000000 (usable)
[ 0.000000] Initrd not found or empty - disabling initrd
[ 0.000000] Zone PFN ranges:
Voila. It booted a kernel! So, it seems like I must’ve had the stock TP-Link firmware after all, and just needed a stock recovery image.
Now running in RAM - U-Boot at: 87fa8000
Flash Manuf Id 0xef, DeviceId0 0x40, DeviceId1 0x18
flash size 16MB, sector count = 256
Flash: 16 MB
Using default environment
In: serial
Out: serial
Err: serial
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
Dragonfly----> S27 PHY *
: cfg1 0x80000000 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
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 :50
athrs27_phy_setup ATHR_PHY_CONTROL 1 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 1 :50
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :50
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :50
eth1 up
eth0, eth1
Setting 0x181162c0 to 0x82
Trying eth0
eth0 link down
FAIL
Trying eth1
enet1 port2 up
dup 1 speed 1000
Using eth1 device
TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'tp_recovery.bin'.
Load address: 0x80800000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
########################
done
Bytes transferred = 11768817 (b393f1 hex)
Firmware recovery: FLASH_SIZE = 16 filesize = 0xb393f1.
Reading Partition Table from NVRAM ... OK
Parsing Partition Table ... OK
File Length:11768817
[Error]sysmgr_proinfo_buildStruct(): 587 @ unknown id(hw_id), skip it.
[Error]sysmgr_proinfo_buildStruct(): 587 @ unknown id(oem_id), skip it.
[Error]sysmgr_cfg_checkSupportList(): 909 @ 00000000 NOT Match.
Firmwave supports, check OK.
Firmware Checking Passed.
######################################################################
######################################################################
##############################################
Done.
All Done!
U-Boot 1.1.4 (Jul 16 2016 - 18:05:34)
ap151 - Dragonfly 1.0
DRAM: 128 MB
Top of RAM usable for U-Boot at: 88000000
Reserving 342k for U-Boot at: 87fa8000
Reserving 32832k for malloc() at: 85f98000
Reserving 44 Bytes for Board Info at: 85f97fd4
Reserving 36 Bytes for Global Data at: 85f97fb0
Reserving 128k for boot params() at: 85f77fb0
Stack Pointer at: 85f77f98
Now running in RAM - U-Boot at: 87fa8000
Flash Manuf Id 0xef, DeviceId0 0x40, DeviceId1 0x18
flash size 16MB, sector count = 256
Flash: 16 MB
Using default environment
In: serial
Out: serial
Err: serial
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
Dragonfly----> S27 PHY *
: cfg1 0x80000000 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
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 :50
athrs27_phy_setup ATHR_PHY_CONTROL 1 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 1 :50
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :50
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :50
eth1 up
eth0, eth1
Setting 0x181162c0 to 0x82
Autobooting in 1 seconds
## Booting image at 9f020000 ...
Image Name: MIPS OpenWrt Linux-3.3.8
Created: 2016-07-19 9:52:32 UTC
Image Type: MIPS Linux Multi-File Image (lzma compressed)
Data Size: 1069313 Bytes = 1 MB
Load Address: 80060000
Entry Point: 80060000
Contents:
Image 0: 1069305 Bytes = 1 MB
Verifying Checksum at 0x9f020040 ...OK
Uncompressing Multi-File Image ... OK
No initrd
## Transferring control to Linux (at address 80060000) ...
## Giving linux memsize in bytes, 134217728
Starting kernel ...
[ 0.000000] Linux version 3.3.8 (tplink@tplink) (gcc version 4.6.3 20120201 (prerelease) (Linaro GCC 4.6-2012.02) ) #1 Tue Jul 19 17:51:52 HKT 2016
[ 0.000000] bootconsole [early0] enabled
[ 0.000000] CPU revision is: 00019750 (MIPS 74Kc)
[ 0.000000] SoC: Qualcomm Atheros QCA956X rev 0
[ 0.000000] Clocks: CPU:775.000MHz, DDR:650.000MHz, AHB:258.333MHz, Ref:25.000MHz
[ 0.000000] Determined physical RAM map:
[ 0.000000] memory: 08000000 @ 00000000 (usable)
[ 0.000000] User-defined physical RAM map:
[ 0.000000] memory: 08000000 @ 00000000 (usable)
[ 0.000000] Initrd not found or empty - disabling initrd
[ 0.000000] Zone PFN ranges:
[ 0.000000] Normal 0x00000000 -> 0x00008000
[ 0.000000] Movable zone start PFN for each node
[ 0.000000] Early memory PFN ranges
[ 0.000000] 0: 0x00000000 -> 0x00008000
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512
[ 0.000000] Kernel command line: console=ttyS0,115200 board=AP151 rootfstype=squashfs init=/etc/preinit mtdparts=spi0.0:128k(u-boot),1152k(uImage),15040k(rootfs),64k@0xff0000(ART) mem=128M rootfstype=squashfs,jffs2 nd
[ 0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
...
After a few reboots, and setting up my router
“normally” using the OEM process, it was back to life.
I could even get a standard Linux shell over UART after hitting
Enter
after the kernel log messages.
BusyBox v1.19.4 (2016-07-16 17:16:48 HKT) built-in shell (ash)
Enter 'help' for a list of built-in commands.
MM NM MMMMMMM M M
$MMMMM MMMMM MMMMMMMMMMM MMM MMM
MMMMMMMM MM MMMMM. MMMMM:MMMMMM: MMMM MMMMM
MMMM= MMMMMM MMM MMMM MMMMM MMMM MMMMMM MMMM MMMMM'
MMMM= MMMMM MMMM MM MMMMM MMMM MMMM MMMMNMMMMM
MMMM= MMMM MMMMM MMMMM MMMM MMMM MMMMMMMM
MMMM= MMMM MMMMMM MMMMM MMMM MMMM MMMMMMMMM
MMMM= MMMM MMMMM, NMMMMMMMM MMMM MMMM MMMMMMMMMMM
MMMM= MMMM MMMMMM MMMMMMMM MMMM MMMM MMMM MMMMMM
MMMM= MMMM MM MMMM MMMM MMMM MMMM MMMM MMMM
MMMM$ ,MMMMM MMMMM MMMM MMM MMMM MMMMM MMMM MMMM
MMMMMMM: MMMMMMM M MMMMMMMMMMMM MMMMMMM MMMMMMM
MMMMMM MMMMN M MMMMMMMMM MMMM MMMM
MMMM M MMMMMMM M M
M
---------------------------------------------------------------
For those about to rock... (%C, %R)
---------------------------------------------------------------
root@Archer_C59:/#
I took the opportunity to log some information for my router in Linux.
root@Archer_C59:/# uname -a
Linux Archer_C59 3.3.8 #1 Tue Jul 19 17:51:52 HKT 2016 mips GNU/Linux
root@Archer_C59:/# cat /proc/cmdline
console=ttyS0,115200 board=AP151 rootfstype=squashfs init=/etc/preinit mtdparts=spi0.0:128k(u-boot),1152k(uImage),15040k(rootfs),64k@0xff0000(ART) mem=128M rootfstype=squashfs,jffs2 noinitrd
- https://openwrt.org/toh/hwdata/tp-link/tp-link_archer_c59_v1
- https://openwrt.org/toh/tp-link/archer_c60_v2#serial
- https://www.youtube.com/watch?v=Fi0pC_ON5Vo&t=29s
- https://blog.rpanachi.com/howto-unbrick-wifi-router-after-bad-openwrt-firmware-flashing
- https://openwrt.org/docs/guide-user/installation/generic.flashing.tftp
- https://openwrt.org/toh/hwdata/tp-link/tp-link_archer_c59_v1
- https://openwrt.org/toh/tp-link/archer-c9
- https://www.youtube.com/watch?v=t35Pei_eb6o
- https://techinfodepot.shoutwiki.com/wiki/TP-LINK_Archer_C59_v1.x
- https://www.youtube.com/watch?v=bpUHwImRFFw
- https://forum.openwrt.org/t/support-for-archer-c58/2699/7