Adding OpenWrt support for Xiaomi "Redmi Router AX6S"/"Xiaomi Router AX3200"

Thank you, will try that as the second option, right now I think I succeeded marking bad block, works so far, let's see for how long. I took most of the info from here: https://stackoverflow.com/questions/58083109/u-boot-nand-markbad-has-no-effect
and my flash chip datasheet: https://datasheet.lcsc.com/lcsc/2105241807_GigaDevice-Semicon-Beijing-GD5F1GQ5UEYIGR_C2829047.pdf
I learned that bad block (or better to say page?) marker is stored in the first byte (or 2 bytes?) of OOB area following each NAND page. Page size for my flash chip is 2048 bytes, OOB size is 112 bytes. If the marker is 0xFF it means the page is good, 0x00 - the page is bad.
My version of UBoot does not mark bad blocks (even though it says it does), so I marked it manually with UBoot low-level nand read/write functions:
nand read.raw 0x41000000 0x17C0000 1
0x41000000 is the address of RAM area that seems to be unused, 0x17C0000 is the address of the bad page, 1 is number of pages to read.
Show the page contents:
md 0x41000000 0x21C
0x21C = (2048+112)/4 is the number of 4-byte words to display
OOB starts at 0x41000800, the first byte shows 0xFF, I need to change it to 0x00:
mm 0x41000800, type 0, Enter, 'q', Enter
write modified page back to flash:
nand write.raw 0x41000000 0x17C0000 1
Then I repeated first two commands (nand read.raw and md) to verify that address 0x17C0800 actually changed to 0x00000000, and verified again with


MT7622> nand bad

Device 0 bad blocks:
Bad block detected at 0xec00, oob_buf[0] is 0x0
Bad block detected at 0xec00, oob_buf[0] is 0x0

I have yet to understand the meaning of address 0xec00 and how it is related to my address 0x17C0000 and why it shows this messages twice, but I'm quite sure it refers to the right NAND page.

The next thing I learned is that preserving bad page mark is a challenge. Every time stock firmware or openwrt firmware is installed, it erases flash along with OOB data and the mark is gone. So I repeated the procedure right after the first boot of the openwrt firmware, rebooted several times - and the bad page is still there!

Here is how to confirm it from within openwrt:

root@OpenWrt:/# dmesg | grep PEB
[    2.163126] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[    2.183743] ubi0: good PEBs: 887, bad PEBs: 1, corrupted PEBs: 0
[    2.206097] ubi0: available PEBs: 0, total reserved PEBs: 887, PEBs reserved for bad PEB handling: 18

or with nand-utils:

root@OpenWrt:/# nanddump /dev/mtd9
ECC failed: 0
ECC corrected: 0
Number of bad blocks: 1
Number of bbt blocks: 0

Now let's see if this works in the long run.

2 Likes

@Mushoz, your problem isn't the same as @dyarkovoy's? Would you mind testing the first OpenWrt boot with the mentioned nanddump?

That sounds exactly like my problem! What would you like me to do exactly? I could try a nanddump, but is that even going to do anything without manually marking bad blocks first?

I just don't know! I newer had bad blocks on my routers. :sweat_smile:
I hoped it could find it by itself ... if it doesn't you have to make that serial access.

I think the first thing to do is to hook up to router's UART and see why it enters into boot loop, should be pretty obvious from the serial console

In my case nanddump was useful only to confirm that the bad block was marked. If it is not, nanddump is of no use

1 Like

Unfortunately, I do not have any UART cable. Never even tried it before. Maybe I should bite the bullet and try it? From what I know, baud rate and voltage are very important to get right. But that's about the extend of my knowledge. Any pointers what this router requires? I should probably have a look at the wiki page for the router.

You can use this guide: https://github.com/mikeeq/xiaomi_ax3200_openwrt#uart-flash

  • Google for 'uart to usb 3v3' or 'usb to ttl 3v3' to see what adapters are available in your local stores. On Windows you may need drivers for the specific adapter (easily found by googling adapter's chip). I used FT232RL-based adapter. The ones with CH340 chip should also do the job. They come in 5v or 3.3v versions, make sure to get 3.3v one.
  • Connect GND, RX and TX pins as explained in the guide. You do not need to connect the power line (VCC). Make sure to swap RX and TX. If you connect without opening the case, keep in mind that the picture of the router UART pins was taken from the top of the mainboard.
  • Baud rate is 115200, 8N1

I have a Redmi AX6S configured as an access point and switch running OpenWrt 23.05.2. When connecting a 100Mbps wired device (LG TV) to the AP, the Wi-Fi speed drops from around 600-700 Mbps to approximately 60 Mbps. Notably, this only affects the SSID that is bridged onto the same VLAN as the connected Ethernet device. It does not affect the other SSIDs bridged to networks on other VLANs. WiFi is unaffected when only gigabit devices are connected, and other wired devices on the same VLAN also remain unaffected when a 100Mbps device is connected. Where can I start to fix this?

1 Like

I've happily been using 3 AX3200s as dumb APs around the house. They're still running a very old version (22.03.0-rc6 with proprietary wifi drivers). The proprietary drivers seemed to be the best setup at the time, but as I'm considering updating to a more recent stable version - I wanted to ask how the open source wifi drivers compare to the proprietary ones in the latest release/snapshot?

Given a lack of recent comments with custom builds, I am guessing that the wifi works pretty well out of the box these days? Any major caveats?

2 Likes

I'm also using three AX3200 as dumb APs. The major issue I had (low performance of 802.11ax) has been solved, and the recent 23.05.2 release has been rock solid so far.

The only recommendation I have is not to use the maximum Wifi power (OpenWrt defaults to 27dBm in my country). For some reason (amplifier saturation?) this resulted in slower/unstable speeds in 5GHz band (I have not tested 2.4GHz). I have manually reduced it to 1 dBM less (to 26dBm) and it did solve this issue.

3 Likes

Hi, did you finally connect to the device?
Yesterday, after flashing, my Xiaomi got "blinking yellow led". After connecting via UART, I got same result (and I test it on 2 different serial interfaces). I tried to push the image via tftp [1] or via MIWIFI repair tool [2] and after second attempt, even tftp stops working in rescue mode. I think that the memory died and nothing I can do more.
If someone have any idea, please share. Thanks

Maybe related due to powerbrick not powerful enough to provide enough power?

After 1 day, I came back to unbrick AX3200, where UART was raising strange output.
Shortcut of the procedure:

mkdir -p /tmp/debrick
# from https://miuirom.org/miwifi/mi-router-ax3200
curl -SL https://cdn.awsde0-fusion.fds.api.mi-img.com/xiaoqiang/rom/rb01/miwifi_rb01_firmware_bbc77_1.0.71_INT.bin > /tmp/debrick/C0A81F04.img
chmod 0766 /tmp/debrick/C0A81F04.img

NETWORK_INTERFACE=enp9s0u1u4u2u4
sudo dnsmasq -i $NETWORK_INTERFACE -p 0 -d -z --enable-tftp --tftp-root /tmp/debrick --tftp-unique-root --tftp-no-fail --dhcp-range 192.168.31.2,192.168.31.10,255.255.255.0,12h

After it print:

dnsmasq-dhcp: DHCPREQUEST(enp9s0u1u4u2u4) 192.168.31.4 5c:02:14:b0:55:00
dnsmasq-dhcp: DHCPACK(enp9s0u1u4u2u4) 192.168.31.4 5c:02:14:b0:55:00
dnsmasq-tftp: sent /tmp/debrick/C0A81F04.img to 192.168.31.4

Wait 10 minutes (there should be blinking blue light) and the unplug power and plug it back. After it, it should be available via 192.168.31.1

Hi
after almost 2 years, more than happy to get back to the scene
Now that I've stumbled upon xmir-patcher (thanks a lot @remittor)

currently on RB01 1.0.83
Step 2 in xmir-patcher (ssh) seems to work* (I'll get back to that in a minute)
I have ssh to the router and telnet is open according fac_info

{"telnet":true,"init":true,"wl0_ssid":"XXXX","ssh":true,"version":"1.0.83","facmode":false,"4kblock":false,"secboot":false,"wl1_ssid":"XXXX","uart":true}

when trying step 7 (installing fw)
I'm getting this error:

Select: 7

Detect valid SSH server on port 22 (auth OK)
device: "RB01"
img_write = True
Image files in directory "firmware/":
  "firmware/openwrt-23.05.2-mediatek-mt7622-xiaomi_redmi-router-ax6s-squashfs-factory.bin"
Download file: "/tmp/dmesg.log" ....
ERROR on downloading "/tmp/dmesg.log"
Download file: "/tmp/mtd_list.txt" ....

ERROR: Partition list is empty! (solution: disable all WiFi modules and reboot device)

I've tried to turn off all wifi via the router web configure with no luck.

So I thought, I have telnet and SSH, I'll try manually and see if I can get more info in the issue.
But when I'm trying to connect via telnet , I get connection refused.
I checked using netstat -tln on the router and indeed no one is listening to port 23.
tried to restart the service via /etc/init.d/telnet restart, didn't help...

Any thoughts/assumptions/investigation leads will be appreciated
Thanks

Try to execute 3 option in main menu.

Same.. :

Select: 3

Detect valid SSH server on port 22 (auth OK)
Download file: "/tmp/dmesg.log" ....
ERROR on downloading "/tmp/dmesg.log"
Download file: "/tmp/mtd_list.txt" ....

ERROR: Partition list is empty! (solution: disable all WiFi modules and reboot device)

(I also get this but seems like a minor issue

Select: /usr/lib/python3.9/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 1 leaked shared_memory objects to clean up at shutdown

)

Perhaps Python does not have enough rights to create files inside its directory.

You are probably right..
Although I ran it as root from my raspberry pi2 connected to the router,
It gave me this error.

once I've tried to run it straight from my Mac, it worked perfectly
The router is now flashed with 23.05.2
Thanks a lot!

UBoot 2021

  setenv("bootargs", "$");
  if ( boot_fw_num )
  {
    setenv("flag_boot_rootfs", "1");
    sprintf(boot_cmd, "%s", "run boot_fw1");
  }
  else
  {
    setenv("flag_boot_rootfs", "0");
    sprintf(boot_cmd, "%s", "run boot_fw0");
  }
  save_env();
  printf("Booting System %d\n", boot_fw_num);
  sub_41E03BAC((int)boot_cmd);

UBoot 2022

  set_nvram_param("bootargs", cmdline);
  if ( boot_part_num )
  {
    set_nvram_param("flag_boot_rootfs", "1");
    sprintf((int)bootm_cmd, "%s", "run boot_fw1");
    sprintf((int)try_value, "%d", __try_sys2 + 1);
    try_name = "flag_try_sys2_failed";
  }
  else
  {
    set_nvram_param("flag_boot_rootfs", "0");
    sprintf((int)bootm_cmd, "%s", "run boot_fw0");
    sprintf((int)try_value, "%d", _try_sys1 + 1);
    try_name = "flag_try_sys1_failed";
  }
  set_nvram_param(try_name, try_value);
  saveenv();
  log("Booting System %d\n", boot_part_num);
  bootm(bootm_cmd, 0);

On new Xiaomi bootloaders, the flag_try_sysX_failed counter increases with each reboot. The stock firmware resets the flag_try_sysX_failed counter to 0 after a successful boot.

It probably makes sense to do the same in OpenWRT firmware.
Example of a similar task: https://github.com/openwrt/openwrt/blob/ced3fbcda18e200315cb077f7e2b362ae52ee065/target/linux/ramips/mt76x8/base-files/etc/init.d/bootcount#L11-L14

Official installation manual: https://openwrt.org/toh/xiaomi/ax3200

For the 2022 bootloader, this option is incorrect!

For a new bootloader you should do this:

nvram set boot_fw1="run boot_rd_img;bootm"
nvram set flag_try_sys1_failed=8
nvram set flag_try_sys2_failed=8
nvram set flag_boot_rootfs=0
nvram set flag_boot_success=1
nvram set flag_last_success=1
nvram commit

Example: https://github.com/openwrt/openwrt/commit/18bea173a646518a64ca05ea26f87eab0540feb9#diff-0a263858df577cc26996da59d6407fd35d3e8744454266ca76109ac7c6c29618R34-R37

Uboot 2021
  _try_sys = flag_try_sys2_failed > 1;
  if ( flag_try_sys2_failed <= 1 )
    _try_sys = flag_try_sys1_failed > 1;
  if ( _try_sys )
    boot_fw_num = 1;
  else
    boot_fw_num = 0;
  if ( _try_sys )
  {
    boot_fw_num = 0;
  }
Uboot 2022
  flag_ota_reboot_is_2 = flag_ota_reboot > 1;
  if ( flag_ota_reboot <= 1 )
    flag_ota_reboot_is_2 = flag_last_success > 1;
  if ( flag_ota_reboot_is_2 )
  {
    boot_part_num = 0;
  }
  else
  {
    try_sys_is_OK = try_sys2 == 0;
    if ( try_sys2 )
      try_sys_is_OK = try_sys1 == 0;
    if ( !try_sys_is_OK )
      log("Boot failure detected on both systems\n");
    if ( flag_ota_reboot )
    {
      ...
    }
    else
    {
      if ( flag_last_success )
        _try_sys = try_sys2 > 5;
      else
        _try_sys = try_sys1 > 5;
      if ( _try_sys )
        boot_part_num = 1 - flag_last_success;
      else
        boot_part_num = flag_last_success;
    }
  }
Stock firmware after boot: /etc/init.d/boot_check
START=99

RCSTATFILE='/tmp/rc.timing'
BOOTCHECKCODEFILE='/tmp/rc.done'

set_setup_flag(){
	local flg=0
	local flag_boot_rootfs=$(nvram get flag_boot_rootfs)
	local flag_ota_root=$(nvram get flag_ota_reboot)
	local flag_boot_success=$(nvram get flag_boot_success)
	local flag_try_sys1_failed=$(nvram get flag_try_sys1_failed)
	local flag_try_sys2_failed=$(nvram get flag_try_sys2_failed)
	local flag_last_success=$(nvram get flag_last_success)
	
	[ "$flag_ota_root" != "0" ] && {
		flg=1
		nvram set flag_ota_reboot=0
	}
	[ "$flag_boot_success" != "1" ] && {
		flg=1
		nvram set flag_boot_success=1
	}
	[ "$flag_try_sys1_failed" != "0" ] && {
		flg=1
		nvram set flag_try_sys1_failed=0
	}
	[ "$flag_try_sys2_failed" != "0" ] && {
		flg=1
		nvram set flag_try_sys2_failed=0
	}

	[ "$flag_boot_rootfs" = "0" -o "$flag_boot_rootfs" = "1" ] && [ "$flag_boot_rootfs" != "$flag_last_success" ] && {
		flg=1
		nvram set flag_last_success=$flag_boot_rootfs
	}

	[ "$flg" = "1" ] && nvram commit
}

start() {
	...
	# set bootup flag
	set_setup_flag

	...

	# boot finished	
	xqled sys_ok
	echo "BOOTCHECKCODE=0;" > $BOOTCHECKCODEFILE	
	echo "boot_done" > /tmp/boot_check_done
	elog "Booting up finished."
}
  
1 Like

I did a quick update in the Wiki adding in the step 5 a reference to your post above. Quick question: how a user can tell which bootloader (2021 or 2022) version? We can add this information to the Wiki.