ramips: add support for TP-Link TL-WR840N v4 and TL-WR841N v13

TP-Link TL-WR840N v4 and TL-WR841N v13 are simple N300 routers with
5-port FE switch and non-detachable antennas. Both are very similar
and are based on MediaTek MT7628NN (aka MT7628N) WiSoC.

The difference between these two models is in number of available
LEDs, buttons and power input switch.

This work is partially based on GitHub PR#974.

Specification:

- MT7628N/N (580 MHz)
- 64 MB of RAM (DDR2)
- 8 MB of FLASH
- 2T2R 2.4 GHz
- 5x 10/100 Mbps Ethernet
- 2x external, non-detachable antennas
- UART (J1) header on PCB (115200 8n1)
- TL-WR840N v4: 5x LED (GPIO-controlled), 1x button
- TL-WR841N v13: 8x LED (GPIO-controlled*), 2x button, power input
  switch

* WAN LED in TL-WR841N v13 is a dual-color, dual-leads type which isn't
  (fully) supported by gpio-leds driver. This type of LED requires both
  GPIOs state change at the same time to select color or turn it off.
  For now, we support/use only the green part of the LED.

Factory image notes:

These devices use version 3 of TP-Link header, fortunately without RSA
signature (at least in case of devices sold in Europe). The difference
lays in the requirement for a non-zero value in "Additional Hardware
Version" field. Ideally, it should match the value stored in vendor
firmware header on device ("0x4"/"0x13" for these devices) but it seems
that anything other than "0" is correct.

We are able to prepare factory firwmare file which is accepted and
(almost) correctly flashed from the vendor GUI. As it turned out, it
accepts files without U-Boot image with second header at the beginning
but due to some kind of bug in upgrade routine, flashed image gets
corrupted before it's written to flash.

Tests showed that the GUI upgrade routine copies value of "Additional
Hardware Version" from existing firmware into offset "0x2023c" in
provided file, _before_ storing it in flash. In case of vendor firmware
upgrade files (which all include U-Boot image and two headers), this
offset points to the matching field in kernel+rootfs firmware part
header. Unfortunately, in case of LEDE factory image file which contains
only one header, it points to the offset "0x2023c" in kernel image. This
leads to a corrupted kernel and ends up with a "soft-bricked" device.

The good news is that U-Boot in these devices contains well known tftp
recovery mode, which can be triggered with "reset" button. What's more,
in comparison to some of older MediaTek based TP-Link devices, this
recovery mode doesn't write whole file at offset "0x0" in flash, without
verifying provided file in advance. In case of recovery mode in these
devices, first "0x20000" bytes are always skipped and "0x7a0000" bytes
from rest of the file are stored in flash at offset "0x20000".

Flash instruction:

Until (if at all) TP-Link fixes described problem, the only way to flash
LEDE image in these devices is to use tftp recovery mode in U-Boot:

1. Configure PC with static IP 192.168.0.66/24 and tftp server.
2. Rename "lede-ramips-mt7628-tl-wr84...-squashfs-tftp-recovery.bin"
   to "tp_recovery.bin" and place it in tftp server directory.
3. Connect PC with one of LAN ports, press the reset button, power up
   the router and keep button pressed for around 6-7 seconds, until
   device starts downloading the file.
4. Router will download file from server, write it to flash and reboot.

To access U-Boot CLI, keep pressed "4" key during boot.

Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
This commit is contained in:
Piotr Dymacz 2017-06-21 14:16:15 +02:00
parent c55fadcacb
commit 24043a0d2e
12 changed files with 287 additions and 1 deletions

View file

@ -336,6 +336,19 @@ tiny-ac)
set_wifi_led "$board:orange:wifi" set_wifi_led "$board:orange:wifi"
set_usb_led "$board:green:usb" set_usb_led "$board:green:usb"
;; ;;
tl-wr840n-v4)
set_wifi_led "$board:green:wlan"
ucidef_set_led_switch "lan" "lan" "$board:green:lan" "switch0" "0x1e"
ucidef_set_led_switch "wan" "wan" "$board:green:wan" "switch0" "0x01"
;;
tl-wr841n-v13)
set_wifi_led "$board:green:wlan"
ucidef_set_led_switch "lan1" "lan1" "$board:green:lan1" "switch0" "0x2"
ucidef_set_led_switch "lan2" "lan2" "$board:green:lan2" "switch0" "0x4"
ucidef_set_led_switch "lan3" "lan3" "$board:green:lan3" "switch0" "0x8"
ucidef_set_led_switch "lan4" "lan4" "$board:green:lan4" "switch0" "0x10"
ucidef_set_led_switch "wan" "wan" "$board:green:wan" "switch0" "0x01"
;;
vocore-8M|\ vocore-8M|\
vocore-16M) vocore-16M)
ucidef_set_led_netdev "eth" "ETH" "vocore:orange:eth" "eth0" ucidef_set_led_netdev "eth" "ETH" "vocore:orange:eth" "eth0"

View file

@ -169,6 +169,8 @@ ramips_setup_interfaces()
mzk-wdpr|\ mzk-wdpr|\
rb750gr3|\ rb750gr3|\
rt-n14u|\ rt-n14u|\
tl-wr840n-v4|\
tl-wr841n-v13|\
ubnt-erx|\ ubnt-erx|\
ubnt-erx-sfp|\ ubnt-erx-sfp|\
ur-326n4g|\ ur-326n4g|\

View file

@ -35,6 +35,8 @@ get_status_led() {
nbg-419n2|\ nbg-419n2|\
pwh2004|\ pwh2004|\
r6220|\ r6220|\
tl-wr840n-v4|\
tl-wr841n-v13|\
vr500|\ vr500|\
wnce2001|\ wnce2001|\
wndr3700v5|\ wndr3700v5|\

View file

@ -487,6 +487,12 @@ ramips_board_detect() {
*"Timecloud") *"Timecloud")
name="timecloud" name="timecloud"
;; ;;
*"TL-WR840N v4")
name="tl-wr840n-v4"
;;
*"TL-WR841N v13")
name="tl-wr841n-v13"
;;
*"UBNT-ERX") *"UBNT-ERX")
name="ubnt-erx" name="ubnt-erx"
;; ;;

View file

@ -230,7 +230,9 @@ platform_check_image() {
;; ;;
c20i|\ c20i|\
c50|\ c50|\
mr200) mr200|\
tl-wr840n-v4|\
tl-wr841n-v13)
[ "$magic" != "03000000" ] && { [ "$magic" != "03000000" ] && {
echo "Invalid image type." echo "Invalid image type."
return 1 return 1

View file

@ -0,0 +1,62 @@
/dts-v1/;
#include "TL-WR84XN.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
compatible = "tplink,tl-wr840n-v4", "mediatek,mt7628an-soc";
model = "TP-Link TL-WR840N v4";
gpio-keys-polled {
compatible = "gpio-keys-polled";
#address-cells = <1>;
#size-cells = <0>;
poll-interval = <20>;
reset {
label = "reset";
gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
gpio-leds {
compatible = "gpio-leds";
lan {
label = "tl-wr840n-v4:green:lan";
gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
power {
label = "tl-wr840n-v4:green:power";
gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
};
wan {
label = "tl-wr840n-v4:green:wan";
gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
};
wlan {
label = "tl-wr840n-v4:green:wlan";
gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
};
wps {
label = "tl-wr840n-v4:green:wps";
gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
};
};
};
&pinctrl {
state_default: pinctrl0 {
gpio {
ralink,group = "p0led_an", "p2led_an", "perst", "refclk", "wdt", "wled_an";
ralink,function = "gpio";
};
};
};

View file

@ -0,0 +1,88 @@
/dts-v1/;
#include "TL-WR84XN.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
compatible = "tplink,tl-wr841n-v13", "mediatek,mt7628an-soc";
model = "TP-Link TL-WR841N v13";
gpio-keys-polled {
compatible = "gpio-keys-polled";
#address-cells = <1>;
#size-cells = <0>;
poll-interval = <20>;
reset {
label = "reset";
gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
rfkill {
label = "rfkill";
gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RFKILL>;
};
};
gpio-leds {
compatible = "gpio-leds";
power {
label = "tl-wr841n-v13:green:power";
gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
};
wps {
label = "tl-wr841n-v13:green:wps";
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
};
lan1 {
label = "tl-wr841n-v13:green:lan1";
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
};
lan2 {
label = "tl-wr841n-v13:green:lan2";
gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
lan3 {
label = "tl-wr841n-v13:green:lan3";
gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
};
lan4 {
label = "tl-wr841n-v13:green:lan4";
gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
};
wan_green {
label = "tl-wr841n-v13:green:wan";
gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
};
wan_orange {
label = "tl-wr841n-v13:orange:wan";
gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
};
wlan {
label = "tl-wr841n-v13:green:wlan";
gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
};
};
};
&pinctrl {
state_default: pinctrl0 {
gpio {
ralink,group = "gpio", "p0led_an", "p1led_an", "p2led_an", "p3led_an", "p4led_an", "perst", "refclk", "uart1", "wdt", "wled_an";
ralink,function = "gpio";
};
};
};

View file

@ -0,0 +1,67 @@
#include "mt7628an.dtsi"
/ {
chosen {
bootargs = "console=ttyS0,115200";
};
memory@0 {
device_type = "memory";
reg = <0x0 0x4000000>;
};
};
&spi0 {
status = "okay";
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <10000000>;
m25p,chunked-io = <32>;
partition@0 {
label = "boot";
reg = <0x0 0x20000>;
read-only;
};
partition@20000 {
label = "firmware";
reg = <0x20000 0x7a0000>;
};
partition@7c0000 {
label = "config";
reg = <0x7c0000 0x10000>;
read-only;
};
factory: partition@7d0000 {
label = "factory";
reg = <0x7d0000 0x30000>;
read-only;
};
};
};
&ehci {
status = "disabled";
};
&ohci {
status = "disabled";
};
&wmac {
status = "okay";
mtd-mac-address = <&factory 0xf100>;
mediatek,mtd-eeprom = <&factory 0x20000>;
};
&ethernet {
mtd-mac-address = <&factory 0xf100>;
mediatek,portmap = "llllw";
};

View file

@ -2,6 +2,8 @@
# MT7628 Profiles # MT7628 Profiles
# #
DEVICE_VARS += TPLINK_BOARD_ID
define Device/mt7628 define Device/mt7628
DTS := MT7628 DTS := MT7628
BLOCKSIZE := 64k BLOCKSIZE := 64k
@ -26,6 +28,28 @@ define Device/miwifi-nano
endef endef
TARGET_DEVICES += miwifi-nano TARGET_DEVICES += miwifi-nano
define Device/tl-wr840n-v4
DTS := TL-WR840NV4
IMAGE_SIZE := 7808k
DEVICE_TITLE := TP-Link TL-WR840N v4
TPLINK_BOARD_ID := TL-WR840NV4
KERNEL := $(KERNEL_DTB)
IMAGES += tftp-recovery.bin
IMAGE/factory.bin := tplink-v2-image
IMAGE/tftp-recovery.bin := pad-extra 128k | $$(IMAGE/factory.bin)
IMAGE/sysupgrade.bin := tplink-v2-image -s | append-metadata | \
check-size $$$$(IMAGE_SIZE)
endef
TARGET_DEVICES += tl-wr840n-v4
define Device/tl-wr841n-v13
$(Device/tl-wr840n-v4)
DTS := TL-WR841NV13
DEVICE_TITLE := TP-Link TL-WR841N v13
TPLINK_BOARD_ID := TL-WR841NV13
endef
TARGET_DEVICES += tl-wr841n-v13
define Device/gl-mt300n-v2 define Device/gl-mt300n-v2
DTS := GL-MT300N-V2 DTS := GL-MT300N-V2
IMAGE_SIZE := 16064k IMAGE_SIZE := 16064k

View file

@ -138,6 +138,7 @@ CONFIG_MTD_NAND_MT7620=y
CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_TRX_FW=y CONFIG_MTD_SPLIT_TRX_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_DMA_MAP_STATE=y
@ -191,6 +192,7 @@ CONFIG_SPI_MT7621=y
# CONFIG_SPI_RT2880 is not set # CONFIG_SPI_RT2880 is not set
CONFIG_SRCU=y CONFIG_SRCU=y
CONFIG_SWCONFIG=y CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y CONFIG_SYS_HAS_CPU_MIPS32_R2=y

View file

@ -140,6 +140,7 @@ CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_TRX_FW=y CONFIG_MTD_SPLIT_TRX_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_DMA_MAP_STATE=y
@ -193,6 +194,7 @@ CONFIG_SPI_MT7621=y
# CONFIG_SPI_RT2880 is not set # CONFIG_SPI_RT2880 is not set
CONFIG_SRCU=y CONFIG_SRCU=y
CONFIG_SWCONFIG=y CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWPHY=y CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y CONFIG_SYS_HAS_CPU_MIPS32_R1=y

View file

@ -207,6 +207,22 @@ static struct board_info boards[] = {
.layout_id = "8MLmtk", .layout_id = "8MLmtk",
.hdr_ver = 3, .hdr_ver = 3,
.endian_swap = true, .endian_swap = true,
}, {
.id = "TL-WR840NV4",
.hw_id = 0x08400004,
.hw_rev = 0x1,
.hw_ver_add = 0x4,
.layout_id = "8Mmtk",
.hdr_ver = 3,
.endian_swap = true,
}, {
.id = "TL-WR841NV13",
.hw_id = 0x08410013,
.hw_rev = 0x268,
.hw_ver_add = 0x13,
.layout_id = "8Mmtk",
.hdr_ver = 3,
.endian_swap = true,
}, { }, {
/* terminating entry */ /* terminating entry */
} }