ramips: add support for TP-Link TL-WR840N v4 and TL-WR841N v13
authorPiotr Dymacz <pepe2k@gmail.com>
Wed, 21 Jun 2017 12:16:15 +0000 (14:16 +0200)
committerPiotr Dymacz <pepe2k@gmail.com>
Thu, 29 Jun 2017 08:37:36 +0000 (10:37 +0200)
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>
12 files changed:
target/linux/ramips/base-files/etc/board.d/01_leds
target/linux/ramips/base-files/etc/board.d/02_network
target/linux/ramips/base-files/etc/diag.sh
target/linux/ramips/base-files/lib/ramips.sh
target/linux/ramips/base-files/lib/upgrade/platform.sh
target/linux/ramips/dts/TL-WR840NV4.dts [new file with mode: 0644]
target/linux/ramips/dts/TL-WR841NV13.dts [new file with mode: 0644]
target/linux/ramips/dts/TL-WR84XN.dtsi [new file with mode: 0644]
target/linux/ramips/image/mt7628.mk
target/linux/ramips/mt7628/config-4.4
target/linux/ramips/mt7628/config-4.9
tools/firmware-utils/src/mktplinkfw2.c

index 61f662b496575355a094c65d52b15d974001920f..61fbf0f3f3b73628ec4e5fa9e0b4dbe379b0be37 100755 (executable)
@@ -336,6 +336,19 @@ tiny-ac)
        set_wifi_led "$board:orange:wifi"
        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-16M)
        ucidef_set_led_netdev "eth" "ETH" "vocore:orange:eth" "eth0"
index 214db9df380bb985cdbb7415bc058195d1b0e71b..22b231bf9662cf40bb98fc9ef9dde5339bc1e2ea 100755 (executable)
@@ -169,6 +169,8 @@ ramips_setup_interfaces()
        mzk-wdpr|\
        rb750gr3|\
        rt-n14u|\
+       tl-wr840n-v4|\
+       tl-wr841n-v13|\
        ubnt-erx|\
        ubnt-erx-sfp|\
        ur-326n4g|\
index 4c8f709efb7c1ccad616a969f412051c96ebbef2..0f4e646ce11c15fe763c8e48e5263c1d0d763015 100644 (file)
@@ -35,6 +35,8 @@ get_status_led() {
        nbg-419n2|\
        pwh2004|\
        r6220|\
+       tl-wr840n-v4|\
+       tl-wr841n-v13|\
        vr500|\
        wnce2001|\
        wndr3700v5|\
index e146d1c4767d79711abd127d13c24e78055d3167..3eb66dc6462a6a0f02f78a3e9bd64f46d4407845 100755 (executable)
@@ -487,6 +487,12 @@ ramips_board_detect() {
        *"Timecloud")
                name="timecloud"
                ;;
+       *"TL-WR840N v4")
+               name="tl-wr840n-v4"
+               ;;
+       *"TL-WR841N v13")
+               name="tl-wr841n-v13"
+               ;;
        *"UBNT-ERX")
                name="ubnt-erx"
                ;;
index 07530837d6e6cf20b4948638829d804d22c677f5..9b5da57146489705bd9b5df60a72225e55b42c68 100755 (executable)
@@ -230,7 +230,9 @@ platform_check_image() {
                ;;
        c20i|\
        c50|\
-       mr200)
+       mr200|\
+       tl-wr840n-v4|\
+       tl-wr841n-v13)
                [ "$magic" != "03000000" ] && {
                        echo "Invalid image type."
                        return 1
diff --git a/target/linux/ramips/dts/TL-WR840NV4.dts b/target/linux/ramips/dts/TL-WR840NV4.dts
new file mode 100644 (file)
index 0000000..f139483
--- /dev/null
@@ -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";
+               };
+       };
+};
diff --git a/target/linux/ramips/dts/TL-WR841NV13.dts b/target/linux/ramips/dts/TL-WR841NV13.dts
new file mode 100644 (file)
index 0000000..40f833c
--- /dev/null
@@ -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";
+               };
+       };
+};
diff --git a/target/linux/ramips/dts/TL-WR84XN.dtsi b/target/linux/ramips/dts/TL-WR84XN.dtsi
new file mode 100644 (file)
index 0000000..c9d0cdd
--- /dev/null
@@ -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";
+};
index f8bd2c18b24159fc1bc795bd7307aa8980b53ff3..fbfc37d9865362967dddec5bd4258701e0aff688 100644 (file)
@@ -2,6 +2,8 @@
 # MT7628 Profiles
 #
 
+DEVICE_VARS += TPLINK_BOARD_ID
+
 define Device/mt7628
   DTS := MT7628
   BLOCKSIZE := 64k
@@ -26,6 +28,28 @@ define Device/miwifi-nano
 endef
 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
   DTS := GL-MT300N-V2
   IMAGE_SIZE := 16064k
index 1dd8c7582407289bcb58d0e5c569b11b1004a855..4b1bddb3c853e9e460d34ba6802bca03415816b2 100644 (file)
@@ -138,6 +138,7 @@ CONFIG_MTD_NAND_MT7620=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
 CONFIG_MTD_SPLIT_TRX_FW=y
 CONFIG_MTD_SPLIT_UIMAGE_FW=y
 CONFIG_NEED_DMA_MAP_STATE=y
@@ -191,6 +192,7 @@ CONFIG_SPI_MT7621=y
 # CONFIG_SPI_RT2880 is not set
 CONFIG_SRCU=y
 CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
 CONFIG_SYSCTL_EXCEPTION_TRACE=y
 CONFIG_SYS_HAS_CPU_MIPS32_R1=y
 CONFIG_SYS_HAS_CPU_MIPS32_R2=y
index 0c6026c9f7f108bd0523ba5b60d61466caa5562e..23ee65cd1e350ff01c002cdb0af9248e6653f1f7 100644 (file)
@@ -140,6 +140,7 @@ CONFIG_MTD_M25P80=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
 CONFIG_MTD_SPLIT_TRX_FW=y
 CONFIG_MTD_SPLIT_UIMAGE_FW=y
 CONFIG_NEED_DMA_MAP_STATE=y
@@ -193,6 +194,7 @@ CONFIG_SPI_MT7621=y
 # CONFIG_SPI_RT2880 is not set
 CONFIG_SRCU=y
 CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
 CONFIG_SWPHY=y
 CONFIG_SYSCTL_EXCEPTION_TRACE=y
 CONFIG_SYS_HAS_CPU_MIPS32_R1=y
index b6dd670b9075b93ec12b0500861fa27d8778d0c9..14c5a492b76cbd46c68890278ce4496952a1a8e8 100644 (file)
@@ -207,6 +207,22 @@ static struct board_info boards[] = {
                .layout_id      = "8MLmtk",
                .hdr_ver        = 3,
                .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 */
        }