Support for Edimax RG21S

Hi,

I got the Edimax running including the wifi (MT7615E, at the moment unsupported in the OpenWRT master) using the latest drivers for the MT7615 from https://github.com/LorenzoBianconi/mt76
Flashing via the OEM GUI works, but is rather experimental, I could need some help on the details of the original image format.

If you want to try it out. Pull the latest OpenWRT sources from git, then apply the following patch:

diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile
index a985f90b2a..18227bbd97 100644
--- a/package/kernel/mt76/Makefile
+++ b/package/kernel/mt76/Makefile
@@ -6,10 +6,18 @@ PKG_RELEASE=1
 PKG_LICENSE:=GPLv2
 PKG_LICENSE_FILES:=
 
-PKG_SOURCE_URL:=https://github.com/openwrt/mt76
+#PKG_SOURCE_DATE:=2019-04-13
+#PKG_SOURCE_VERSION:=
+#PKG_SOURCE_URL:=file:///.
+#PKG_HASH:=2545f346eedc40e0a3f795c94fd4848e1ddcecf1bb9ff981cce6fec008d54501
+#PKG_SOURCE:=mt76-master.zip
+#PKG_CAT:=unzip
+#PKG_BUILD_DIR:=$(BUILD_DIR)/mt76-master
+
+PKG_SOURCE_URL:=https://github.com/LorenzoBianconi/mt76/
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_DATE:=2019-03-27
-PKG_SOURCE_VERSION:=a11b67348aeb2d3175c5995c747e7fc050c7df60
+PKG_SOURCE_VERSION:=fd5af7397257e14654a1126388a44644e7772632
 PKG_MIRROR_HASH:=6ea603308fa568c8ab39eddd86d9c8110a10aa93971348f52ceda0e5bd423ec6
 
 PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
@@ -23,7 +31,8 @@ PKG_CONFIG_DEPENDS += \
        CONFIG_PACKAGE_kmod-mt76x2-common \
        CONFIG_PACKAGE_kmod-mt76x2 \
        CONFIG_PACKAGE_kmod-mt76x2u \
-       CONFIG_PACKAGE_kmod-mt7603
+       CONFIG_PACKAGE_kmod-mt7603  \
+       CONFIG_PACKAGE_kmod-mt7615
 
 STAMP_CONFIGURED_DEPENDS := $(STAGING_DIR)/usr/include/mac80211-backport/backport/autoconf.h
 
@@ -138,6 +147,15 @@ define KernelPackage/mt7603
   AUTOLOAD:=$(call AutoProbe,mt7603e)
 endef
 
+define KernelPackage/mt7615
+  $(KernelPackage/mt76-default)
+  TITLE:=MediaTek MT7615 wireless driver
+  DEPENDS+=@PCI_SUPPORT +kmod-mt76-core
+  FILES:=\
+       $(PKG_BUILD_DIR)/mt7615/mt7615e.ko
+  AUTOLOAD:=$(call AutoProbe,mt7615e)
+endef
+
 NOSTDINC_FLAGS = \
        -I$(PKG_BUILD_DIR) \
        -I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
@@ -181,6 +199,9 @@ endif
 ifdef CONFIG_PACKAGE_kmod-mt7603
   PKG_MAKE_FLAGS += CONFIG_MT7603E=m
 endif
+ifdef CONFIG_PACKAGE_kmod-mt7615
+  PKG_MAKE_FLAGS += CONFIG_MT7615E=m
+endif
 
 define Build/Compile
        +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \
@@ -233,6 +254,12 @@ define KernelPackage/mt7603/install
                $(1)/lib/firmware
 endef
 
+define KernelPackage/mt7615/install
+       $(INSTALL_DIR) $(1)/lib/firmware
+       cp $(PKG_BUILD_DIR)/firmware/mt7615_rom_patch.bin $(PKG_BUILD_DIR)/firmware/mt7615_n9.bin $(PKG_BUILD_DIR)/firmware/mt7615_cr4.bin $(1)/lib/firmware
+endef
+
+
 $(eval $(call KernelPackage,mt76-core))
 $(eval $(call KernelPackage,mt76-usb))
 $(eval $(call KernelPackage,mt76x02-usb))
@@ -244,4 +271,5 @@ $(eval $(call KernelPackage,mt76x2-common))
 $(eval $(call KernelPackage,mt76x2u))
 $(eval $(call KernelPackage,mt76x2))
 $(eval $(call KernelPackage,mt7603))
+$(eval $(call KernelPackage,mt7615))
 $(eval $(call KernelPackage,mt76))
diff --git a/target/linux/ramips/base-files/etc/board.d/02_network b/target/linux/ramips/base-files/etc/board.d/02_network
index 96e5b7e1cc..4df3762612 100755
--- a/target/linux/ramips/base-files/etc/board.d/02_network
+++ b/target/linux/ramips/base-files/etc/board.d/02_network
@@ -264,7 +264,8 @@ ramips_setup_interfaces()
        elecom,wrc-1900gst|\
        hg255d|\
        iodata,wn-ax1167gr|\
-       iodata,wn-gx300gr)
+       iodata,wn-gx300gr|\
+       edimax,rg21s)
                ucidef_add_switch "switch0" \
                        "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "0:wan" "6@eth0"
                ;;
@@ -563,6 +564,10 @@ ramips_setup_macs()
        sk-wb8)
                wan_mac=$(mtd_get_mac_binary factory 57350)
                ;;
+    edimax,rg21s)
+        lan_mac=$(mtd_get_mac_ascii u-boot-env ethaddr)
+               wan_mac=$(mtd_get_mac_ascii u-boot-env wanaddr)
+               ;;
        gl-mt300n-v2|\
        whr-g300n)
                wan_mac=$(mtd_get_mac_binary factory 4)
diff --git a/target/linux/ramips/dts/RG21S.dts b/target/linux/ramips/dts/RG21S.dts
new file mode 100644
index 0000000000..fe8be96aab
--- /dev/null
+++ b/target/linux/ramips/dts/RG21S.dts
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/dts-v1/;
+
+#include "mt7621.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       compatible = "edimax,rg21s", "mediatek,mt7621-soc";
+       model = "RG21S";
+
+       aliases {
+               led-boot = &led_power;
+               led-failsafe = &led_power;
+               led-running = &led_power;
+               led-upgrade = &led_power;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x8000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,57600";
+       };
+
+       palmbus: palmbus@1E000000 {
+               i2c@900 {
+                       status = "okay";
+               };
+       };
+
+       keys {
+               compatible = "gpio-keys-polled";
+               poll-interval = <20>;
+
+               reset {
+                       label = "reset";
+                       gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+
+               wps {
+                        label = "wps";
+                        gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
+                        linux,code = <KEY_RESTART>;
+                };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               /* there are 4 red leds, unlabled */
+               led_power: led_1 {
+                       label = "rg21s:red:led1";
+                       gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_2 {
+                       label = "rg21s:red:led2";
+                       gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_3 {
+                       label = "rg21s:red:led3";
+                       gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_4 {
+                       label = "rg21s:red:led4";
+                       gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&sdhci {
+       status = "okay";
+};
+
+&spi0 {
+       status = "okay";
+
+       m25p80@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <10000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0x0 0x30000>;
+                               read-only;
+                       };
+
+                       partition@30000 {
+                               label = "u-boot-env";
+                               reg = <0x30000 0x10000>;
+                               read-only;
+                       };
+
+                       factory: partition@40000 {
+                               label = "factory";
+                               reg = <0x40000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               compatible = "denx,uimage";
+                               label = "firmware";
+                               reg = <0x50000 0xfb0000>;
+                       };
+               };
+       };
+};
+
+&pcie {
+       status = "okay";
+};
+
+&pcie0 {
+       wifi@0,0 {
+               compatible = "pci14c3,7603";
+               reg = <0x0000 0 0 0 0>;
+               mediatek,mtd-eeprom = <&factory 0x0000>;
+               ieee80211-freq-limit = <2400000 2500000>;
+               mtd-mac-address = <&factory 0x4>;
+       };
+};
+
+&pcie1 {
+       wifi@0,0 {
+               compatible = "pci14c3,7662";
+               reg = <0x0000 0 0 0 0>;
+               mediatek,mtd-eeprom = <&factory 0x8000>;
+               ieee80211-freq-limit = <5000000 6000000>;
+               mtd-mac-address = <&factory 0x8004>;
+       };
+};
+
+&ethernet {
+       mediatek,portmap = "wllll";
+       port@5 {
+               status = "disabled";
+       };
+};
+
+&pinctrl {
+       state_default: pinctrl0 {
+               gpio {
+                       ralink,group = "wdt", "rgmii2", "jtag", "mdio";
+                       ralink,function = "gpio";
+               };
+       };
+};
+
+&xhci {
+       status = "disabled";
+};
diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk
index 2eb7feb5bf..a4c3ebc043 100644
--- a/target/linux/ramips/image/mt7621.mk
+++ b/target/linux/ramips/image/mt7621.mk
@@ -324,6 +324,15 @@ define Device/r6220
 endef
 TARGET_DEVICES += r6220
 
+define Device/rg21s
+  DTS := RG21S
+  IMAGE_SIZE := $(ralink_default_fw_size_16M)
+  DEVICE_TITLE := EDIMAX RG21S
+  DEVICE_PACKAGES := \
+        kmod-ata-ahci kmod-mt76x2 kmod-mt7603 kmod-usb3 kmod-mt7615 wpad-basic
+endef
+TARGET_DEVICES += rg21s
+
 define Device/netgear_ex6150
   DTS := EX6150
   DEVICE_TITLE := Netgear EX6150

You then need to package the firmware according to what the router expects. For this you need the following scrip, call it fw_package.py:

#!/usr/bin/python3
import sys
import hashlib

xorKey = [0x88, 0x44, 0xA2, 0xD1, 0x68, 0xB4, 0x5A, 0x2D];

def w32(value):
    global fout
    fout.write( int(value).to_bytes (4, byteorder='big'));
    return

def w16(value):
    global fout
    fout.write( int(value).to_bytes (2, byteorder='big'));
    return

def w8(value):
    global fout
    fout.write( int(value).to_bytes (1, byteorder='big'));
    return

def wString(value):
    global fout
    fout.write(value.encode('ascii'));
    return

print ("Reading:", sys.argv[1])

with open(sys.argv[1], "rb") as fin :
    inArr = bytearray(fin.read())


with open(sys.argv[2], "wb") as fout:
    print ("Writing to:", sys.argv[2])
    
    # Write the header:
    w32(0x00000000)
    w32(0x00000003)  # Seems to mark images vs configuration backups (0x00000007)
    w32(0x00000000)  # Is 0x0300000 in configuration backups
    w32(0x00000000)  # In configuration backups different
    w32(0xcc7f77b7)  # No idea, but notice the repetition of 7fb7, also at the end 
    w32(0xe88b7fb7)  # Magic? Repeated at end, maybe a model number?
    w8 (0x00)        # Padding
    wString("0.0.22") # The version, also found in configuration backups
    w32(0x00000000)
    w32(0x00000000)
    w8 (0x00)        # Padding ?
    w32(0x00000202)  # Version in BCD?
    w8 (0x00)
    wString("83047") # Magic? Is found also in configuration backups
    w32(0x00000000)
    w32(0x00000000)
    w32(0x00000000)
    print ("Image size:", len(inArr))
    w32(len(inArr))
    w32(0x00000000)
    h = hashlib.md5(inArr.decode('latin-1').encode('latin-1'))
    print ("Image hash:", h.hexdigest())
    for i in range(4):
        w32(int(h.hexdigest()[i*8:i*8+8], 16))
    w16(0x0000)
    w32(0x00000000)
    w32(0x01000000)
    w32(0xf8887fb7) # No idea, but notice the repetition of 7fb7, also below
    w32(0xcc7f7fb7)
    w32(0x00000000)
    w32(0x01000000)
    w32(0xd0df7db7) # More magic, and again 7xb7
    w32(0xe88b7fb7)
    w32(0x00000310)
    w32(0x30471688)
    i = 0
    for byte in inArr:
        result = byte ^ xorKey[i]
        fout.write( bytes([result]));
        i = ((i+1) % len(xorKey))

Run with

./fw_package.py openwrt-ramips-mt7621-rg21s-squashfs-sysupgrade.bin openwrt-ramips-mt7621-rg21s-squashfs.bin

in order to package the OpenWRT binary into something the router understands. Finally upload the binary via the Router's orignal firmware upload page. Tested with a Router running 0.22 FW.

If you want to go back to the original firmware / debrick, you can use the information above to unpack an original Edimax image and apply via Serial+TFTP (press 2) or via sysupgrade in OpenWRT.

I would be interested in the headers of any other orginal firmware version and of course feedback on how the router performs.

It looks like the format is the same as the header in I-O DATA WN-AC1167GR and WN-AC733GRx.

WN-AC1167GR:

hexdump -n $((0x80)) -C wnac1167gr_v105.bin
00000000  00 00 00 00 00 00 00 03  47 45 54 5f 53 54 41 47  |........GET_STAG|
00000010  49 4e 47 2f 61 70 70 73  5f 31 2e 35 2e 30 00 00  |ING/apps_1.5.0..|
00000020  00 00 00 00 00 00 00 00  00 00 01 04 00 16 33 30  |..............30|
00000030  34 37 00 00 00 00 00 00  00 00 00 00 00 00 00 35  |47.............5|
00000040  50 00 00 00 00 00 8b 2d  25 78 16 a9 d8 34 7d c7  |P......-%x...4}.|
00000050  42 2f 63 08 9b 25 81 bf  94 1a 02 40 00 00 00 00  |B/c..%.....@....|
00000060  48 6b 02 40 01 00 00 00  00 00 00 00 01 00 00 00  |Hk.@............|
00000070  38 19 02 40 00 00 00 00  00 00 09 c0 30 47 16 88  |8..@........0G..|
00000080

WN-AC733GRx:

hexdump -n $((0x80)) -C wn-ac733gr2_204.bin
00000000  00 00 00 00 00 00 00 03  be 43 cf bf 00 00 00 00  |.........C......|
00000010  dc 5f 01 40 44 44 cf bf  00 32 2e 34 2e 31 00 00  |._.@DD...2.4.1..|
00000020  00 00 00 00 00 00 00 00  00 00 01 04 00 06 33 30  |..............30|
00000030  34 37 00 00 00 00 00 00  00 00 00 00 00 00 00 33  |47.............3|
00000040  c0 00 00 00 00 00 38 7b  7f 17 69 78 c9 31 4b 56  |......8{..ix.1KV|
00000050  73 34 23 f4 69 24 1e 40  00 80 00 00 f4 cf 04 08  |s4#.i$.@........|
00000060  01 a5 04 08 ff ff ff ff  a6 e1 06 40 f4 0f 1e 40  |...........@...@|
00000070  35 e2 06 40 70 f2 00 40  00 00 06 90 30 47 16 88  |5..@p..@....0G..|
00000080

You may also be able to use Build/elx-header in mt7620.mk for your device.

EDIT: For details about the format, I think the output of header command in the stock firmware is very useful.

ex. (WN-AC1167GR):

# header -x wnac1167gr_v105.bin
### Decoding  image ####
Decode source file [wnac1167gr_v105.bin]
------- Header Info -------
Vendor  id:  0x0104
Product id:  0x0016
Hardware id:  0x01040016
Version id:  3047
Code Version:  1.5.0
Type: 0x3 [kernel]
comp_file_len:  3493888
comp_file_sum:  0x0
Header sum:  0x9c0
Magic key:  0x30471688
MD5 chksum:  8b2d257816a9d8347dc7422f6389b25
------------------------------
Decode finished, got file [wnac1167gr_v105.bin.bin] with size 3493888 bytes
header: Return OK

In this model, the check passed even though some properties were missing.

# header -x openwrt-ramips-mt7620-iodata_wn-ac1167gr-squashfs-factory.bin 
### Decoding  image ####
Decode source file [openwrt-ramips-mt7620-iodata_wn-ac1167gr-squashfs-factory.bin]
------- Header Info -------
Vendor  id:  0x0104
Product id:  0x0016
Hardware id:  0x01040016
Version id:  
Code Version:  
Type: 0x3 [kernel]
comp_file_len:  5505028
comp_file_sum:  0x0
Header sum:  0x0
Magic key:  0x0
MD5 chksum:  90ba7450183602a7cbe542bc1a9b436
------------------------------
Decode finished, got file [openwrt-ramips-mt7620-iodata_wn-ac1167gr-squashfs-factory.bin.bin] with size 5505028 bytes
header: Return OK
1 Like

Thanks musashino,

this is of great help! It's very impressive that you identified the header type immediately from the crude reverse-engineering I made. I can't find the header binary in the original firmware. Most of the commands are in some kind of toolbox, similarly to busybox and I don't have access to the running router. I did the reverse engineering by manipulating the file-system of the router on the flash and manipulating the configuration backup process, it then turned out the image had the same format. Anyway, with the information you provided it should be easy to figure out the rest of the fields and use the elx/header to make this device properly supported by OpenWRT.

There is one more problem I have: Namely there are 4 LEDs in the router, all red, which are connected to a single "eye" via a waveguard from the PCB (think Cylon). The router communicates merely by blinking patterns of this eye (where you cannot distinguish the individual LEDs) and the intensity changes with the number of LEDS on, in particular a fading effect is achieved. Is there a possibilty in the led-gpio kernel module to slave other GPIOs to a master one? Or to create patterns with a number of LEDS?

I ran header command on WN-AC1167GR with the stock firmware and got that output. This may be the easiest to try.

And, I extracted the firmware for Edimax RG21S by binwalk, I found header command in cpio-root in kernel binary.

tofu@Tofu-H170W10:~/router/d-router/Edimax/RG21S/RG21S_0.0.22$ tree -L 5 -P "header"
.
└── _RG21S_0.0.22.dec.extracted
    ├── _40.extracted
    │   └── cpio-root
    │       ├── apps
    │       ├── bin
    │       ├── dev
    │       │   └── pts
    │       ├── etc
    │       │   ├── Wireless
    │       │   ├── ppp
    │       │   └── wlan
    │       ├── etc_ro
    │       │   └── Wireless
    │       ├── kernel
    │       ├── lib
    │       │   └── single_sku
    │       ├── mnt
    │       ├── proc
    │       ├── sbin
    │       │   └── header               <--- this

I managed to build a generic factory image for the RG21S, thanks to your hint with the elx-header, musashino. The OEM web-upgrade accepts the image even though several of the fields are not filled in. The make target then is:

define Device/edimax_rg21s
  DTS := RG21S
  IMAGE_SIZE := $(ralink_default_fw_size_16M)
  DEVICE_TITLE := EDIMAX RG21S
  IMAGES += factory.bin
  IMAGE/factory.bin := \
    $$(sysupgrade_bin) | check-size $$$$(IMAGE_SIZE) | \
    elx-header 02020038 8844A2D168B45A2D
  DEVICE_PACKAGES := \
        kmod-ata-ahci kmod-mt76x2 kmod-mt7603 kmod-mt7615 wpad-basic
endef
TARGET_DEVICES += edimax_rg21s

Does anyone know what the policy is for submitting a patch at this point: Do you need to wait until support for the MT7615 wifi chip is in git master, or can the DTS and make target already be submitted although the Wifi will be broken initially?

1 Like

Right now, MediaTek MT7615 driver is available in master.

1 Like

Great, thanks for pointing this out! I am working on a patch that can be submitted.

FYI - Support for RG21S has been added with https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=f285e8634c57d28aa970b80c5c59e85485f35c7d

snapshot images are available for downloading. Installation instructions see the linked git-commit above.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.