Skip to main content

Fixing UART DMA Issues on NVIDIA Jetpack 6.2.2

Introduction​

This guide explains how to fix UART receive/transmit issues on NVIDIA Jetpack 6.2.2 platforms by forcing selected UART ports to run in PIO mode instead of DMA mode.

On affected JetPack 6 systems, some UART ports may receive corrupted data when the NVIDIA serial-tegra driver uses DMA. The workaround is to remove the dmas and dma-names properties from the relevant UART device-tree nodes using a device-tree overlay. When those properties are removed, the driver falls back to PIO mode.

This guide covers how to:

  • Identify the UART device-tree nodes.
  • Disable DMA for serial@3100000 and serial@3110000.
  • Compile the overlay into a .dtbo.
  • Install the overlay using the JetsonHacks jetson-orin-uart installer flow.
  • Verify that the UART ports are running in PIO mode after reboot.

What You Will Need​

Before starting, make sure you have the following:

  • NVIDIA Jetson Orin device
    Jetson Orin Nano, Orin NX.

  • **JetPack 6.2.2 / L4T R36.5 This workaround is intended for JetPack 6 systems where the UART DMA issue appears.

  • Terminal access
    Local terminal or SSH access to the Jetson.

  • Root privileges
    The installation modifies files under /boot, so sudo is required.

  • device-tree-compiler
    The dtc tool is required to compile .dts overlays into .dtbo files.

  • JetsonHacks UART overlay repository
    The guide assumes the jetson-orin-uart repository is cloned on the Jetson.

Background: DMA Mode vs PIO Mode​

Jetson UART ports are exposed through the Linux serial-tegra driver. Depending on the device-tree configuration, the driver may use DMA or PIO for UART data movement.

DMA Mode​

In DMA mode, the UART driver uses the DMA engine to move UART data between hardware and memory. This reduces CPU involvement and is generally preferred for high-throughput serial traffic.

A UART node configured for DMA usually contains properties similar to:

dmas = <...>;
dma-names = "rx", "tx";

PIO Mode​

PIO means Programmed I/O. In PIO mode, the CPU and UART driver move data through the UART registers directly, usually interrupt-driven.

The UART protocol, pins, baud rate, and Linux device name do not change. Only the internal data-transfer mechanism changes.

After the workaround is applied, the kernel log should show messages similar to:

serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode

Step 1: Clone the JetsonHacks UART Fix Repository​

Clone the repository on the Jetson:

git clone https://github.com/jetsonhacks/jetson-orin-uart.git
cd jetson-orin-uart

The repository includes an install.sh script that:

  • Compiles disable-uart1-dma.dts into a device-tree overlay.
  • Copies the resulting .dtbo file to /boot.
  • Detects the board FDT.
  • Updates /boot/extlinux/extlinux.conf.
  • Adds a new boot entry while keeping the previous entry as a fallback.

Step 2: Replace the DTS Overlay​

Create or replace the overlay source file:

cat > disable-uart1-dma.dts <<'EOF'
/dts-v1/;
/plugin/;

/ {
overlay-name = "Disable UART DMA for 3100000 and 3110000";

fragment@0 {
target-path = "/bus@0/serial@3100000";
delete_prop = "dmas", "dma-names";

__overlay__ {
status = "okay";
};
};

fragment@1 {
target-path = "/bus@0/serial@3110000";
delete_prop = "dmas", "dma-names";

__overlay__ {
status = "okay";
};
};
};
EOF

This overlay removes the DMA properties from both UART nodes:

/bus@0/serial@3100000
/bus@0/serial@3110000

Removing dmas and dma-names causes the serial-tegra driver to fall back to PIO mode for those UARTs.

NOTE: The command above overwrites disable-uart1-dma.dts. If you want to keep the original file, back it up first:

cp disable-uart1-dma.dts disable-uart1-dma.dts.bak

Step 3: Install device-tree-compiler​

Install dtc if it is not already available:

sudo apt update
sudo apt install -y device-tree-compiler

Verify that dtc is installed:

dtc --version

Step 4: Compile the Overlay Manually​

Compile the .dts file into a .dtbo file:

dtc -@ -I dts -O dtb -o disable-uart1-dma.dtbo disable-uart1-dma.dts

Verify that the .dtbo was generated:

ls -l disable-uart1-dma.dtbo

You can also decompile it to inspect the result:

dtc -I dtb -O dts disable-uart1-dma.dtbo

Step 5: Run the Installer​

Run the JetsonHacks install script:

sudo bash install.sh

The installer compiles the overlay again and installs it into:

/boot/disable-uart1-dma.dtbo

It also modifies:

/boot/extlinux/extlinux.conf

The installer creates a new boot entry named UARTFix and leaves the previous boot entry available as a fallback.

Step 6: Reboot​

Reboot the Jetson:

sudo reboot

After reboot, the UARTFix boot entry should load the overlay.

Step 7: Verify PIO Mode​

After the system comes back up, check the kernel log:

sudo dmesg | grep -iE '3100000|3110000|pio|dma|serial-tegra'

Look for lines similar to:

serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode

If those lines appear, the UART ports are running in PIO mode.

Step 8: Confirm the Overlay Was Added to extlinux.conf​

Check the boot configuration:

grep -nA20 -B5 "UARTFix" /boot/extlinux/extlinux.conf

You should see an entry that references:

/boot/disable-uart1-dma.dtbo

You can also check for the overlay path directly:

grep -n "disable-uart1-dma.dtbo" /boot/extlinux/extlinux.conf

Step 9: Inspect the Running Device Tree​

The running device tree is available under /proc/device-tree.

Check whether the UART nodes still expose DMA properties:

ls /proc/device-tree/bus@0/serial@3100000 | grep dma || true
ls /proc/device-tree/bus@0/serial@3110000 | grep dma || true

If the overlay was applied correctly, dmas and dma-names should not appear for those nodes.

You can also decompile the running device tree:

sudo dtc -I fs -O dts /proc/device-tree -o /tmp/running.dts

Then inspect the UART sections:

grep -nA30 "serial@3100000" /tmp/running.dts
grep -nA30 "serial@3110000" /tmp/running.dts

One-Step Patch, Compile, and Install Script​

Instead of running the steps manually, you can use this wrapper script inside the cloned jetson-orin-uart directory.

Create the script:

cat > fix-uart-dma-and-install.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DTS="${REPO_DIR}/disable-uart1-dma.dts"
DTBO="${REPO_DIR}/disable-uart1-dma.dtbo"
INSTALL="${REPO_DIR}/install.sh"

if [[ "${EUID}" -ne 0 ]]; then
echo "[ERROR] Run this script with sudo:"
echo " sudo bash $0"
exit 1
fi

if [[ ! -f "${INSTALL}" ]]; then
echo "[ERROR] install.sh not found in ${REPO_DIR}"
echo " Run this script from inside the jetson-orin-uart repo."
exit 1
fi

if ! command -v dtc >/dev/null 2>&1; then
echo "[INFO] Installing device-tree-compiler..."
apt update
apt install -y device-tree-compiler
fi

if [[ -f "${DTS}" ]]; then
cp "${DTS}" "${DTS}.bak.$(date +%Y%m%d%H%M%S)"
echo "[INFO] Backed up existing DTS."
fi

cat > "${DTS}" <<'DTS_EOF'
/dts-v1/;
/plugin/;

/ {
overlay-name = "Disable UART DMA for 3100000 and 3110000";

fragment@0 {
target-path = "/bus@0/serial@3100000";
delete_prop = "dmas", "dma-names";

__overlay__ {
status = "okay";
};
};

fragment@1 {
target-path = "/bus@0/serial@3110000";
delete_prop = "dmas", "dma-names";

__overlay__ {
status = "okay";
};
};
};
DTS_EOF

echo "[INFO] Wrote patched DTS:"
echo " ${DTS}"

echo "[INFO] Compiling local DTBO for verification..."
dtc -@ -I dts -O dtb -o "${DTBO}" "${DTS}"

echo "[INFO] Decompile check:"
dtc -I dtb -O dts "${DTBO}" 2>/dev/null | grep -E 'serial@3100000|serial@3110000|delete_prop|dma-names|dmas' || true

echo "[INFO] Running original install.sh..."
bash "${INSTALL}"

echo
echo "[INFO] Done."
echo "[INFO] Reboot to apply:"
echo " sudo reboot"
echo
echo "[INFO] After reboot, check:"
echo " sudo dmesg | grep -iE '3100000|3110000|pio|dma|serial-tegra'"
EOF

Make it executable and run it:

chmod +x fix-uart-dma-and-install.sh
sudo bash ./fix-uart-dma-and-install.sh

Summary​

You now have a device-tree overlay that disables UART DMA for:

/bus@0/serial@3100000
/bus@0/serial@3110000

The overlay removes:

dmas
dma-names

from those UART nodes. Without DMA properties, the serial-tegra driver falls back to PIO mode.

The expected result after reboot is:

serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode

This confirms that both UART nodes are no longer using DMA.