Other Parts Discussed in Thread: SK-AM64B, SK-AM62B
Overview
The UART boot mode available on AM6x processors (and other similar TI devices) is a valuable tool often used during development and board bringup. To load the initial boot binary (tiboot3.bin) the ROM code configures the UART peripheral to a speed of 115,200 Baud (bps) and then performs the actual download using the X-Modem serial transfer protocol. Given that those boot binaries are usually in the range of 300+ KB, the download just of the first stage over UART using X-Modem typically takes 10s of seconds to complete. This FAQ discusses different concepts on how the time needed for binary transfers can be reduced.
Optimizing Latency when using FTDI-based USB-to-UART Converters
USB-to-UART serial converters from FTDI are commonly used for connecting a host PC to an embedded target board. Those are used either in an on-board fashion for easier development and product evaluation such as on TI's SK-AM62B, SK-AM64B (and many other) boards, but are also used in a cable-fashion, where the USB-to-UART converter IC is integrated into the USB-A connector.
In order to optimize USB traffic the driver associated with those devices buffers data being send from the host, which typically involves collecting data until no more data is available as determined by a driver-internal timer called "latency timer". While this works well enough for general applications, in case of doing an X-Modem based data transfer with an embedded platform for example this leads to an increase of the overall time needed to send data due to the block-based operation of such protocols.
Fortunately, this behavior of the FTDI driver can be controlled through a UART-instance specific device node that is exposed in the Linux sysfs as /sys/bus/usb-serial/drivers/ftdi_sio/ttyUSB*/latency_timer
. By default, the current FTDI driver uses a latency setting of 16 which stands for 16ms. We can query this default timeout as follows:
# Read the latency timer timeout setting for 'ttyUSB14' $ cat /sys/bus/usb-serial/drivers/ftdi_sio/ttyUSB14/latency_timer 16
This default value is defined in the ftdi_port_probe() driver function, see https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/drivers/usb/serial/ftdi_sio.c?h=ti-linux-6.1.y#n2211
We can eliminate the delaying effect of the latency timer by setting this property to 0 (0ms) like this:
# Set timeout to 0ms $ echo 0 | sudo tee /sys/bus/usb-serial/drivers/ftdi_sio/ttyUSB14/latency_timer 0 # Double check setting is active by reading back the value $ cat /sys/bus/usb-serial/drivers/ftdi_sio/ttyUSB14/latency_timer 0
Performing a couple of X-Modem based file transfers in U-Boot for example using a tiboot3.bin file with a size of 311,168 bytes and comparing the effect of the default setting vs. the optimized setting we can see that the optimized setting will take 25% less time to transfer the file:
latency_timer = 16 (Driver Default) |
latency_timer = 0 (Optimized Setting) |
|
Test Run #1 | 40.4s | 30.1s |
Test Run #2 | 40.5s | 30.3s |
Test Run #3 | 40.7s | 30.3s |
Average | 40.5s | 30.2s |
Improvement | -25.4% |
Here are the associated commands of how this test was performed:
# Perform X-Modem based boot an SK-AM62P board with the default latency timer settings # Note the time shown as 'elapsed' in the log $ picocom -b 115200 /dev/ttyUSB14 --send-cmd "time sx -vv" picocom v3.1 port is : /dev/ttyUSB14 flowcontrol : none baudrate is : 115200 parity is : none databits are : 8 stopbits are : 1 escape is : C-a local echo is : no noinit is : no noreset is : no hangup is : no nolock is : no send_cmd is : time sx -vv receive_cmd is : rz -vv -E imap is : omap is : emap is : crcrlf,delbs, logfile is : none initstring : none exit_after is : not set exit is : no Type [C-a] [C-h] to see available commands Terminal ready 02000000011a0000616d3632707800000000000048534653000001000000010002a6000000000000ade976fcfd18ebf60229bee902edcec6d5fd07d1b2101101198c7ff4f552a9436bda045679d54baa04a1cb85d16fffe0f21e32f7f341c769534d7a560364a908ad0bc40b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d2e869a56fe12ea91f5297011b92f1b13cf03dccc04ac3bf86210f8b41e0a24aCCC *** file: tiboot3.bin $ time sx -vv tiboot3.bin Sending tiboot3.bin, 2430 blocks: Give your local XMODEM receive command now. Bytes Sent: 311168 BPS:7995 Transfer complete 0.08user 0.22system 0:38.92elapsed 0%CPU (0avgtext+0avgdata 2560maxresident)k 0inputs+0outputs (0major+112minor)pagefaults 0swaps *** exit status: 0 *** U-Boot SPL 2023.04-g71b8c840ca (Nov 27 2023 - 08:55:35 +0000) SYSFW ABI: 3.1 (firmware rev 0x0009 '9.1.8--v09.01.08 (Kool Koala)') <...snip...> # Now set timeout to 0ms $ echo 0 | sudo tee /sys/bus/usb-serial/drivers/ftdi_sio/ttyUSB14/latency_timer 0 # Repeat previous test. Note the improvement in 'elapsed' time. $ picocom -b 115200 /dev/ttyUSB14 --send-cmd "time sx -vv" picocom v3.1 port is : /dev/ttyUSB14 flowcontrol : none baudrate is : 115200 parity is : none databits are : 8 stopbits are : 1 escape is : C-a local echo is : no noinit is : no noreset is : no hangup is : no nolock is : no send_cmd is : time sx -vv receive_cmd is : rz -vv -E imap is : omap is : emap is : crcrlf,delbs, logfile is : none initstring : none exit_after is : not set exit is : no Type [C-a] [C-h] to see available commands Terminal ready => mw.l 0x43000030 0x00000c3b && reset resetting ... 02000000011a0000616d3632707800000000000048534653000001000000010002a6000000000000ade976fcfd18ebf60229bee902edcec6d5fd07d1b2101101198c7ff4f552a9436bda045679d54baa04a1cb85d16fffe0f21e32f7f341c769534d7a560364a908ad0 bc40b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d2e869a56fe12ea91f5297011b92f1b13cf03dccc04ac3bf86210f8b41e0a24aCCC *** file: tiboot3.bin $ time sx -vv tiboot3.bin Sending tiboot3.bin, 2430 blocks: Give your local XMODEM receive command now. Bytes Sent: 311168 BPS:10534 Transfer complete 0.01user 0.03system 0:29.53elapsed 0%CPU (0avgtext+0avgdata 2560maxresident)k 0inputs+0outputs (0major+111minor)pagefaults 0swaps *** exit status: 0 *** U-Boot SPL 2023.04-g71b8c840ca (Nov 27 2023 - 08:55:35 +0000) SYSFW ABI: 3.1 (firmware rev 0x0009 '9.1.8--v09.01.08 (Kool Koala)') <...snip...>
More information on this parameter and also how to change it on a Windows-based system can be found in the following FTDI Knowledge Base Article: https://www.ftdichip.com/Support/Knowledgebase/index.html?settingacustomdefaultlaten.htm
Ideas for Further Optimization
While we are limited to optimizing transfer latencies when trying to speed up the ROM bootloading process of the initial boot binary, there are additional ways to optimize the transfer speed once we are past this initial stage.
- Once in U-Boot, when needing to do additional transfers, such as loading a kernel image, or an initramfs for example during early board bringup (see this E2E FAQ for more info), consider using the "baud" parameter of the loadx command. This will require you to drop in and out of your terminal emulator to change the host baud rate accordingly or performing the transfers in a scripted fashion, but doing so once can easily double or quadruple the baud rate and with this cut down the download time accordingly.
=> help loadx loadx - load binary file over serial line (xmodem mode) Usage: loadx [ addr [ baud ] ] - load binary file over serial line at address 'addr' with baudrate 'baud
- Consider using the Y-Modem protocol for additional downloads from the U-Boot prompt. It uses larger block sizes and the resulting reduced overhead will result in a (slightly) better performance. This approach is best combined with the increased baud rate suggested above.
=> help loady loady - load binary file over serial line (ymodem mode) Usage: loady [ addr [ baud ] ] - load binary file over serial line at address 'addr' with baudrate 'baud'
- This is a bit of an advanced topic and is left to the reader, but in case of the typical AM6x boot flow of...
[Boot ROM] --> tiboot3.bin --> tispl.bin --> u-boot.img --> [U-Boot Prompt]
...consider updating the U-Boot source code to double or quadruple the Baudrate starting with the tiboot3.bin stage by updating various device tree properties accordingly. While the initial boot stage will still get loaded by the ROM at 115,200 Baud, the other stages (which are also larger) will get loaded faster, resulting in a significant speed-up overall. Due to the mid-flight Baud-rate change this approach is best done in a scripted fashion. - Perform UART boot in a scripted fashion. While the basic principle for this is discussed in the Linux SDK User's Guide (e.g., see https://software-dl.ti.com/processor-sdk-linux/esd/AM62X/09_01_00_08/exports/docs/linux/Foundational_Components/U-Boot/UG-UART.html), real-world testing has shown the below script to be more complete and generally working well:
$ cat ~/bin/boot-uart-am62.sh #!/bin/sh # exit when any command fails set -e # set ports - adjust as needed # (here it's done 'by-id' to keep the assignment consistent independent of # devices connected, or their order) MAIN_DEV=/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_07231140132-if00-port0 # set binaries to download - adjust as needed TIBOOT3_BIN=.out_r5/tiboot3.bin TISPL_BIN=.out_a53/tispl.bin U_BOOT_IMG=.out_a53/u-boot.img # echo commands set -x # configure serial port(s) stty -F $MAIN_DEV 115200 cs8 -cstopb -parenb # ROM can only do X-Modem. U-Boot [SPL] can do both. sb -vv --xmodem --disable-timeouts $TIBOOT3_BIN > $MAIN_DEV < $MAIN_DEV sb -vv --ymodem $TISPL_BIN > $MAIN_DEV < $MAIN_DEV sleep 2 sb -vv --ymodem $U_BOOT_IMG > $MAIN_DEV < $MAIN_DEV