Skip to main content
Qualcomm Device Loader (QDL) is a cross-platform command-line flashing tool for Qualcomm devices. Use this method when you need full control over the flash process, are running in a headless environment, or want to script automated flashing. For a GUI-based alternative, see Flash Ubuntu using Qualcomm Launcher.
Flashing erases all data on the device. Back up anything important before you begin.

What you need

  • IQ-8275 EVK with 12 V power supply
  • USB Type-C cable (USB0 port on the EVK → host computer)
  • Host computer running Ubuntu, Windows, or macOS

Select your host OS and follow the complete path

Download QDL for your host OS from the Qualcomm Software Center.

Download the Ubuntu image

Download the prebuilt Ubuntu image and boot firmware from the Canonical Ubuntu site.
Always verify the latest build availability on the Canonical Ubuntu website. The links below are pinned to the latest validated release.
  1. Run the following script to download and assemble the flashable image folder. Pass --server or --desktop depending on the image you want:
    ./prepare_iq8275_ubuntu_flashable.sh --server
    
    ./prepare_iq8275_ubuntu_flashable.sh --desktop
    
    This generates the flashable images in iq8275_flash_prep_work/IQ8275_ubuntu_images — referred to as <path-to-image> below.
    To update to a new Canonical release, edit CANONICAL_BASE, SERVER_IMG_XZ, DESKTOP_IMG_XZ, and BOOT_FW_URL_DEFAULT in the script.
    #!/usr/bin/env bash
    set -euo pipefail
    
    FLAVOR="${FLAVOR:-server}"     # server | desktop
    OUT_DIR="${OUT_DIR:-IQ8275_ubuntu_images}"
    WORK_DIR="${WORK_DIR:-$PWD/iq8275_flash_prep_work}"
    
    CANONICAL_BASE="https://people.canonical.com/~platform/images/qualcomm-iot/ubuntu-24.04/ubuntu-24.04-x08"
    SERVER_DIR="${CANONICAL_BASE}/ubuntu-server-24.04"
    DESKTOP_DIR="${CANONICAL_BASE}/ubuntu-desktop-24.04"
    
    SERVER_IMG_XZ="iot-qualcomm-dragonwing-classic-server-2404-x08-20260210.4096b.img.xz"
    DESKTOP_IMG_XZ="iot-qualcomm-dragonwing-classic-desktop-2404-x08-20260210.4096b.img.xz"
    
    BOOT_FW_URL_DEFAULT="https://artifacts.codelinaro.org/artifactory/qli-ci/flashable-binaries/ubuntu-fw/QCS8300/QLI.1.7-Ver.1.1/QLI.1.7-Ver.1.1-ubuntu-QCS8300-nhlos-bins.tar.gz"
    BOOT_FW_URL="${BOOT_FW_URL:-$BOOT_FW_URL_DEFAULT}"
    
    usage() {
      cat <<EOF
    Usage: $(basename "$0") [--server|--desktop] [--out <folder>] [--work <folder>]
    
    Examples:
      ./prepare_iq8275_ubuntu_flashable.sh --server
      ./prepare_iq8275_ubuntu_flashable.sh --desktop --out IQ8275_ubuntu_images_desktop
    
    Environment overrides:
      FLAVOR=server|desktop
      OUT_DIR=...
      WORK_DIR=...
      BOOT_FW_URL=...
    EOF
    }
    
    while [[ $# -gt 0 ]]; do
      case "$1" in
        --server)  FLAVOR="server"; shift ;;
        --desktop) FLAVOR="desktop"; shift ;;
        --out)     OUT_DIR="$2"; shift 2 ;;
        --work)    WORK_DIR="$2"; shift 2 ;;
        -h|--help) usage; exit 0 ;;
        *) echo "Unknown option: $1"; usage; exit 1 ;;
      esac
    done
    
    need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "ERROR: missing '$1'"; exit 1; }; }
    need_cmd curl; need_cmd tar; need_cmd unxz; need_cmd file
    need_cmd find; need_cmd cp; need_cmd head; need_cmd ls; need_cmd mkdir; need_cmd rm
    
    download() {
      local url="$1" dst="$2"
      echo "Downloading: $url"
      curl -L --fail --retry 3 --retry-delay 2 -o "$dst" "$url"
    }
    
    mkdir -p "$WORK_DIR" "$OUT_DIR"
    cd "$WORK_DIR"
    
    if [[ "$FLAVOR" == "server" ]]; then
      BASE_DIR="$SERVER_DIR"; IMG_XZ="$SERVER_IMG_XZ"
    elif [[ "$FLAVOR" == "desktop" ]]; then
      BASE_DIR="$DESKTOP_DIR"; IMG_XZ="$DESKTOP_IMG_XZ"
    else
      echo "ERROR: FLAVOR must be 'server' or 'desktop'"; exit 1
    fi
    
    IMG_URL="${BASE_DIR}/${IMG_XZ}"
    DTB_URL="${BASE_DIR}/dtb.bin"
    RAWPROGRAM_URL="${BASE_DIR}/rawprogram0.xml"
    
    download "$IMG_URL" "$IMG_XZ"
    echo "Extracting OS image: $IMG_XZ"
    unxz -f "$IMG_XZ"
    IMG="${IMG_XZ%.xz}"
    
    download "$DTB_URL" "dtb.bin"
    download "$RAWPROGRAM_URL" "rawprogram0.xml"
    
    BOOT_FW_TAR="$(basename "$BOOT_FW_URL")"
    download "$BOOT_FW_URL" "$BOOT_FW_TAR"
    
    if file "$BOOT_FW_TAR" | grep -qi "HTML"; then
      echo "ERROR: Boot firmware download is HTML, not a tar.gz. Use the direct /artifactory/ endpoint."; exit 1
    fi
    
    if ! tar -tzf "$BOOT_FW_TAR" >/dev/null 2>&1; then
      echo "ERROR: Boot firmware is not a valid gzip tarball."; exit 1
    fi
    
    BOOT_FW_EXTRACT_DIR="$WORK_DIR/boot_fw_extract"
    rm -rf "$BOOT_FW_EXTRACT_DIR"; mkdir -p "$BOOT_FW_EXTRACT_DIR"
    tar -xzf "$BOOT_FW_TAR" -C "$BOOT_FW_EXTRACT_DIR"
    
    mapfile -t TOP_LEVEL_DIRS < <(find "$BOOT_FW_EXTRACT_DIR" -mindepth 1 -maxdepth 1 -type d)
    TOP_DIR="${#TOP_LEVEL_DIRS[@]}" && [[ ${#TOP_LEVEL_DIRS[@]} -eq 1 ]] && TOP_DIR="${TOP_LEVEL_DIRS[0]}" || TOP_DIR="$BOOT_FW_EXTRACT_DIR"
    cp -a "$TOP_DIR"/. "$OUT_DIR"/
    cp -a "dtb.bin" "$OUT_DIR"/ && cp -a "rawprogram0.xml" "$OUT_DIR"/ && cp -a "$IMG" "$OUT_DIR"/
    
    echo "✅ Flashable folder ready: $(realpath "$OUT_DIR")"
    ls -lh "$OUT_DIR" | sed -n '1,200p'
    

Download QDL

  1. Download the QDL tool for Linux (x64) and unzip it. The unzipped folder contains the qdl binary — referred to as <qdl_dir> below.
  2. Install the required libraries (skip if already installed):
    sudo apt-get install libxml2-dev libudev-dev libusb-1.0-0-dev
    
    We recommend extracting the image folder and QDL into the same parent folder. This keeps all paths under one root.

Set up QDL driver

Ubuntu requires a udev rule so the kernel grants your user permission to communicate with the device when it enters EDL mode.
  1. Check whether the rule already exists:
    ls /etc/udev/rules.d/51-qcom-usb.rules
    
  2. If the file is not present, create it in one command:
    echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="9008", MODE="0664", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/51-qcom-usb.rules
    
    If the file already exists, verify the rule is present:
    cat /etc/udev/rules.d/51-qcom-usb.rules
    
  3. Reload udev to apply the rule:
    sudo systemctl restart udev
    
    If the USB cable was already connected, disconnect and reconnect it.

Set up QDL path

  1. Make QDL executable:
    chmod +x <qdl_dir>/qdl
    
  2. Verify QDL is working:
    <qdl_dir>/qdl --help
    
    You should see the QDL usage output. If you get an error, check the path.

Put the device in EDL mode

  1. Turn on the SW2-3 DIP switch — push it up. SW2-3 DIP switch location
  2. Connect the 12 V power supply to the EVK.
  3. Connect the USB Type-C cable from USB0 on the EVK to your host. Flash setup — USB and power connections
  4. Toggle the power switch to turn on the device.
  5. Confirm the device is in EDL mode:
    lsusb
    
    Expected output:
    Bus 002 Device 014: ID 05c6:9008 Qualcomm, Inc. Gobi Wireless Modem (QDL mode)
    
    If the device doesn’t appear, recheck SW2-3 and the USB-C cable.

Provision UFS

UFS (Universal Flash Storage) provisioning divides the internal storage into separate logical unit numbers (LUNs). This step is required when switching from Qualcomm Linux to Ubuntu.Run UFS provisioning if any of the following apply:
  • This is a brand-new board that has never been flashed.
  • You are upgrading to a new image version.
  • You are switching distributions (Qualcomm Linux ↔ Ubuntu).
  1. Download and unzip the provision file:
    wget https://artifacts.codelinaro.org/artifactory/codelinaro-le/Qualcomm_Linux/QCS8300/provision.zip
    unzip provision.zip
    
  2. Provision UFS from the unzipped provision directory:
    cd provision
    <qdl_dir>/qdl --storage ufs prog_firehose_ddr.elf provision_1_3.xml
    
    Expected output:
    UFS provisioning succeeded
    
After UFS provisioning completes, the device disconnects from USB. Toggle the power switch off and on to reboot it back into EDL mode before continuing.

Flash CDT

CDT provides platform-dependent data used by drivers and firmware to initialize the platform correctly.
  1. Download and unzip the CDT file:
    wget https://artifacts.codelinaro.org/artifactory/codelinaro-le/Qualcomm_Linux/QCS8300/cdt/qcs8275-iq-8275-evk-pro-sku.zip
    unzip qcs8275-iq-8275-evk-pro-sku.zip
    
  2. Flash CDT from the unzipped directory:
    <qdl_dir>/qdl prog_firehose_ddr.elf rawprogram3.xml patch3.xml
    
    Expected output:
    flashed "cdt" successfully
    13 patches applied
    
After CDT flashing completes, the device disconnects from USB. Toggle the power switch off and on to reboot it back into EDL mode before continuing.

Flash SAIL firmware

The Safety Island (SAIL) is a separate, isolated processor that handles safety-critical functions independently from the main application processor. Its firmware lives on a dedicated spinor flash partition.
  1. Navigate to the sail_nor subfolder inside the image folder:
    cd <path-to-image>/sail_nor
    
  2. Flash the SAIL firmware:
    <qdl_dir>/qdl --storage spinor prog_firehose_ddr.elf rawprogram0.xml patch0.xml
    
    Expected output:
    flashed "SAIL_HYP" successfully
    flashed "SAIL_SW1" successfully
    flashed "SAIL_HYP_BKUP" successfully
    flashed "SAIL_SW1_BKUP" successfully
    11 patches applied
    

Flash Ubuntu

  1. Navigate to the main image folder:
    cd <path-to-image>
    
  2. Flash the image:
    <qdl_dir>/qdl prog_firehose_ddr.elf rawprogram0.xml rawprogram1.xml rawprogram2.xml rawprogram3.xml rawprogram4.xml patch1.xml patch2.xml patch3.xml patch4.xml
    
    The flash is complete when the final line reads:
    partition 1 is now bootable
    
If flashing fails at any point, disconnect the USB cable and power supply, reconnect them, and retry from the EDL mode step.

Finish

  1. Turn off the SW2-3 DIP switch — push it down.
  2. Power-cycle the device. It boots into the newly flashed Ubuntu image.

Next steps

Continue to Set up the device to connect the serial console, verify the software version, and bring up the network, SSH, and display.