Fixing broken TP-Link TL-MR100

TL;DR: the problem is usually in corrupted data in SPI NAND flash, you need to download the original config data and flash back working modem firmware.

I noticed there is quite a lot of offers with used not working 4G router TL-MR100 in aukro.cz . I bought one with hope I can easily fix and use it. But the fix turned out to be not that easy.

The router boots, shows WiFi network, you can connect to it but the problem is that the web management doesn’t work. I’ve found out that the device consists of two interconnected systems:
– MT7628AN SoC providing WiFi and Ethernet
– some “NezhaC” 4G modem providing web management and mobile connectivity via USB interface

The first one was working fine but its logs were showing problems to communicate with the modem and indeed – the modem was not booting. I de-soldered the flash dedicated to the modem and tried to dump it but there were ECC errors and the data was damaged. So I obtained another working device to get a working flash contents and it worked: I dumped the whole flash, flashed to my broken one and I’ve got a clone of the working one (including IMEI which is quite a problem).

From the logs I discovered, that there is only a short block (0x20000 – 0x60000) containing device specific data (IMEI, calibration, configuration,…) so I copied the block from my broken device over to the working image and… Great success!

I also found (J10: 115200, 1-Tx, 2-Rx, 3-GND) an UART interface of the modem (I had to buy 1.8V compatible USB-TTL adapter) and I could see the modem booting:

0x00000000
PMIC ID: 
0x00000013
Cold power up
switch clk to XO
NO Production Mode
GuiLin Buck1 active voltage Reg: 
0x00000098
GuiLin Buck1 active voltage Reg: 
0x0000009c
cpcore -> 624M
AXI -> 208M
DDR -> 1066M
FlashNumber: 
0x0000001a
Bus clock: 13MHz QSPI_CLK_RES_CTRL: 0x5b
tx_desc: 0x7c188e0
use_intr=1 en_tx_dma=1 use_xip=1
SPI-NAND: GD5F1GQ4RBxIG is found in table
SPI-NAND type mfr_id: c8, dev_id: c1
Set rx_pins: 4 tx_pins: 4
AHB data transfer size: 512
XIP Read mode enabled
Fixed LUT bit-map: 0x3fc
block_size=0x20000 page_size=0x800 bitflip_threshold=6
Bus clock: 78MHz QSPI_CLK_RES_CTRL: 0x19b
pFlashP->NumBlocks: 1020
Tr069 Config Init Done
BoardType: 
0x00000000
PlatformCI2Ready
PlatformCI2Ready end
Wait for USB ready
USB Enum timeout
Allow to boot up
LTG_LWG_Version_Flag: 
0xffffffff
No need to upgrade
TR069 return
0x00000001
LWG/LTG switch flag
0xffffffff
Select to 3Mnde LWG
CRC check OK with flash address
0x00020000
MRD FlashAddress Passed to CP:
0x00020000
CRC check OK with flash address
0x00040000
LWG uboot
Primary/Backup MRD are both OK
cpcore -> 208M
DDR -> 533M
end...
0 buadrate=0

UART Boot Completed
0 GPIOPhase2Init:[zc]---Before set ICU GPIO_INT 30
0 FPIOPhase2Init:[zc]---After set ICU GPIO_INT 3f
0 UsimDetectTaskEntry:enter
1 GPIOPhase2Init:[zc]---Usim_Detect_Gpio default level =0
2 Board Type: NezhaC MIFI DKB
2 Project Type: Nezha PCIE Dongle
3 PMIC Type: 88PM801/Ustica
4 Mode Type: LWG Only
4 BSP board type: 0x0
4 Software version: NEZHAC_CP_1.064.004 Jan 17 2021 15:26:46
5 Compilation date: Jan 17 2021 and time: 15:26:46
6 Last time is not silent reset
7 Sildnt Reset Magic =f55555d5 55155d5d
8 ======= CIU register =======
8 0xd4282d00: 0x2
9 0xd4282d04: 0x100
9 0xd4282d08: 0x0
9 0xd4282d38: 0x0
a 0xd4282d3c: 0x0
a 0xd4282d40: 0x0
a 0xd4282d44: 0x100
b 0xd4282d48: 0x80010
b 0xd4282d4c: 0x20000
b OBM set Flash type: SPI Nand
c Manufacture ID: 0xc8, Device ID: 0xc1
d SPINAND is already unprotected, protection 0x0
e sn_feature: 0x11
e Flash Type: 8, NumBlocks: 1020, BlkSize: 131072, PageSize: 2048
10 FlashManager_Init:Version= 30400
11 [BBT: 0]

11 FlashManager_Init done
11 BlockCacheCount 3, FlashBlockSize 131072
22 BMT0 Version 0x73

32 BMT1 Version 0x72

32 [Version 0x73] The next update partition 1
42 FATTable1=2, FATTable2=25, FATsecs=23, MaxClusters=6140
43 RootSector=32, SecPerClust=16, UserData=82, RootDirectory=48
44 Read guard sector 80
55 psm header size:0x20, buffer addr:0x79b0014
56 flash addr:0x40e0000
5e flash addr:0x40e0000, ddr addr:0x7138680
5e magic num:0x5a5a5a5a,0xefefefef
5f flash addr:0x4100000
67 flash addr:0x4100000, ddr addr:0x71386e0
68 blk_num:1,len:0x0
68 flash addr:0x4120000
70 flash addr:0x4120000, ddr addr:0x7138740
71 blk_num:2,len:0x0
71 flash addr:0x4140000
79 flash addr:0x4140000, ddr addr:0x71387a0
7a blk_num:3,len:0x45b
7a psm file is not NULL
7a psm_block_init, file_num is 0,blk1 is 3
7b psm_block_init psm_fdi_info[0] is 3
7c psm_block_init, file_num is 1,blk1 is 1
7d psm_block_init psm_fdi_info[1] is 1
7d psm_block_init, file_num is 2,blk1 is 2
7e psm_block_init psm_fdi_info[2] is 2
ab BOOTING COMPLETED

There is also list of supported SPI NANDs in the firmware:
GD5F1GQ4RBxIG – this is ours
GD5F2GQ4RBxIG
W25N01GWxxIx
W25N02GWxxIx
DS35M1GAxx
ZD35M1GAxx
PN26Q01AWSIUG
F50D1G41LB
MT29F1G01ABBFD

How to fix your device

Download my repo with tools: https://github.com/danielkucera/tl-mr100-fix

Remove the top cover of your device – I haven’t found a way to open it without breaking tabs, maybe you will have more luck than me:

De-solder the flash – I use a hot plate because there is a huge GND pad on the bottom side of the flash:

I use 1.27mm pin headers to conveniently plug/unplug the flash to my programmer so I always solder an adapter board and the connector. I started using a self-made WSON8 adapter board with pogo-pins. The flash is supposed to work with 1.8V VCC but it happily works on 3.3V too.

Next, it’s time to dump the original NAND contents:

You can use SNANDer to dump the NAND. By default, you will probably see this message because your flash is corrupted:

$ ~/Apps/SNANDer/src/SNANDer -r nand-230104.bin

SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.5 by McMCC <mcmcc@mail.ru>

Found programmer device: WinChipHead (WCH) - CH341A
Device revision is 3.0.4
spi_nand_probe: mfr_id = 0xc8, dev_id = 0xc1, dev_id_2 = 0xc8
Get Status Register 1: 0x00
Get Status Register 2: 0x01
Using Flash ECC.
Detected SPI NAND Flash: GIGADEVICE GD5F1GQ4UA, Flash Size: 128 MB
READ:
Read addr = 0x0000000000000000, len = 0x0000000008000000
[spinand_ecc_fail_check] : ECC cannot recover detected !, page = 0x31
spi_nand_read_page: Bad Block, ECC cannot recovery detecte, page = 0x31
Status: BAD(-1)

To overcome this, you can specify -d parameter and the program will happily dump your flash:

$ ~/Apps/SNANDer/src/SNANDer -d -r nand-230104.bin

SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.5 by McMCC <mcmcc@mail.ru>

Found programmer device: WinChipHead (WCH) - CH341A
Device revision is 3.0.4
spi_nand_probe: mfr_id = 0xc8, dev_id = 0xc1, dev_id_2 = 0xc8
Get Status Register 1: 0x00
Get Status Register 2: 0x11
Disable Flash ECC.
Detected SPI NAND Flash: GIGADEVICE GD5F1GQ4UA, Flash Size: 128 MB
READ:
Read addr = 0x0000000000000000, len = 0x0000000008400000
Read 100% [138412032] of [138412032] bytes      
Elapsed time: 1118 seconds
Status: OK

The interface is slow so it will take several minutes. Now you need to truncate the ECC bytes which are appended after each block with:

python3 cut-ecc.py nand-230104.bin

This will create nand-230104.bin.noecc file. Now you can dump the config block:

dd if=nand-230104.bin.noecc bs=1 skip=$((0x20000)) count=$((0x40000)) of=config-230104.bin

There are actually two config blocks there: 0x20000 and 0x40000 with the same contents for redundancy. You can compare and review them using Meld with following script and try to fix potential corruptions:

./compare.sh config-230104.bin

If you are happy with the contents, you can now assemble the final firmware file, erase flash and write the file to it using a script:

$ ./mkfix.sh 230104
262144+0 records in
262144+0 records out
262144 bytes (262 kB, 256 KiB) copied, 0,622619 s, 421 kB/s

SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.5 by McMCC <mcmcc@mail.ru>

Found programmer device: WinChipHead (WCH) - CH341A
Device revision is 3.0.4
spi_nand_probe: mfr_id = 0xc8, dev_id = 0xc1, dev_id_2 = 0xc8
Get Status Register 1: 0x00
Get Status Register 2: 0x01
Using Flash ECC.
Detected SPI NAND Flash: GIGADEVICE GD5F1GQ4UA, Flash Size: 128 MB
ERASE:
Set full erase chip!
Erase addr = 0x0000000000000000, len = 0x0000000008000000
spi_nand_erase_block : erase block fail, block = 0x3ff, status = 0x4
spi_nand_erase_internal : Erase Fail at addr = 0x7fe0000, len = 0x8000000, block_idx = 0x3ff
Erase 100% [134217728] of [134217728] bytes      
Status: BAD(-1)

SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.5 by McMCC <mcmcc@mail.ru>

Found programmer device: WinChipHead (WCH) - CH341A
Device revision is 3.0.4
spi_nand_probe: mfr_id = 0xc8, dev_id = 0xc1, dev_id_2 = 0xc8
Get Status Register 1: 0x00
Get Status Register 2: 0x11
Using Flash ECC.
Detected SPI NAND Flash: GIGADEVICE GD5F1GQ4UA, Flash Size: 128 MB
WRITE:
Write addr = 0x0000000000000000, len = 0x0000000008000000
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc0, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc1, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc2, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc3, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc4, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc5, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc6, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc7, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc8, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffc9, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffca, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffcb, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffcc, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffcd, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffce, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffcf, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd0, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd1, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd2, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd3, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd4, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd5, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd6, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd7, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd8, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffd9, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffda, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffdb, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffdc, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffdd, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffde, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffdf, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe0, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe1, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe2, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe3, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe4, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe5, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe6, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe7, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe8, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffe9, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffea, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffeb, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffec, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffed, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffee, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffef, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff0, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff1, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff2, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff3, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff4, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff5, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff6, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff7, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff8, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfff9, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfffa, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfffb, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfffc, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfffd, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xfffe, status = 0xc
spi_nand_write_page : Program Fail at addr_offset = 0x0, page_number = 0xffff, status = 0xc
Written 100% [134217728] of [134217728] bytes      
Status: BAD(-1)

You can ignore the errors at the end, it will work just fine. Now you can insert or solder the flash back to board and after boot, you should be able to access the web configuration.

If your main SoC firmware is not 1.4, you also need to upgrade v1.4. Copy included tp_recovery.bin to a tftp server, connect with the router, set server IP to 192.168.0.225 and start the router while holding reset button. Release the button when you see all LEDs flash. This is what you should see on the UART if you are watching:

U-Boot 1.1.3 (Mar  2 2020 - 13:55:27)

Board: Ralink APSoC DRAM:  32 MB
gpiomode1 55054404.
gpiomode2 05550555.
######GPIO CTRL 1 for GPIO 32~64 OUTPUT tmp(0x00005f90)#####
######GPIO CTRL 1 for GPIO 32~64 INPUT tmp(0x00005f90)#####
flash manufacture id: 1c, device id 70 16
find flash: EN25QH32B
============================================ 
Ralink UBoot Version: 4.3.0.0
-------------------------------------------- 
ASIC 7628_MP (Port5<->None)
DRAM component: 256 Mbits DDR, width 16
DRAM bus: 16 bit
Total memory: 32 MBytes
Flash component: SPI Flash
Date:Mar  2 2020  Time:13:55:27
============================================ 
icache: sets:512, ways:4, linesz:32 ,total:65536
dcache: sets:256, ways:4, linesz:32 ,total:32768 

 ##### The CPU freq = 580 MHZ #### 
 estimate memory size =32 Mbytes
RESET MT7628 PHY!!!!!!..................................................
starting recovery...
TODO, Read MAC Address from Flash


 netboot_common, argc= 3 

 KSEG1ADDR(NetTxPacket) = 0xA1FE7380 

 NetLoop,call eth_halt ! 

 NetLoop,call eth_init ! 

 Waitting for RX_DMA_BUSY status Start... done


 ETH_STATE_ACTIVE!! 
TFTP from server 192.168.0.225; our IP address is 192.168.0.2
Filename 'tp_recovery.bin'.

 TIMEOUT_COUNT=10,Load address: 0x80060000
Loading: T Got ARP REPLY, set server/gtwy eth addr (50:7b:9d:6a:42:ba)
Got it
#################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ###########################Got ARP REQUEST, return our IP
######################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #
done
Bytes transferred = 17641990 (10d3206 hex)
NetBootFileXferSize= 010d3206

 Erase flash !!
From 0x10000 length 0x3D0000
.............................................................

 Copy 0x80080000 to 0x00010000, count 0x3D0000.... 
.............................................................

You are welcome 🙂

One thought on “Fixing broken TP-Link TL-MR100”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.