The Qualcomm Snapdragon888 hardware development kit (HDK) is a single-board computer (SBC) built on the Snapdragon 888 mobile platform.

Specifications:

  • CPU: Qualcomm Kryo 680 (4xCortex-A73 + 4xCortex-A53)
  • GPU: Qualcomm Adreno 660 GPU
  • SoC: SM8350P - Codename lahaina
  • Model Name: HDK8350
  • Arch: ARM64

The stock OS shipped with the board is Android 11.

Mainline Linux kernel support was added in release v5.13-rc1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/sm8350-hdk.dts?h=v5.13-rc1

Power control

The board is powered via a DC Power Jack 12V/5A DC input.

Serial console

The UART serial console can be accessed via the USB 2.0 micro-B port.

Network connectivity

The board has a standard Gigabit Ethernet RJ45 connector for Ethernet connectivity.

Wi-Fi 802.11a/b/g/n/ac/ax 2.4/5GHz is also supported.

Fastboot

The stock bootloader supports the fastboot protocol via the USB 3.1 Type C port.

The board can be booted in fastboot mode by keeping the vol- button pressed along with the PON button.

The stock Android bootloader can be forced to enter fastboot mode at every boot, by wiping the boot_a/boot_b partitions:

fastboot erase boot_X

Bootloader

The SM8350-HDK board runs XBL (eXtensible BootLoader), which contains:

  • A SBL (Secondary BootLoader) that initializes the RAM
  • The UEFI firmware; this in turn loads abl. abl is built on top of Tianocore/EDK2 and contains a UEFI application that implements both the fastboot protocol and a Linux bootloader.

The stock Android bootloader allows to load kernel images up to 49.5MB in size (uncompressed): see https://git.codelinaro.org/clo/la/abl/tianocore/edk2/-/blob/LA.UM.9.12.r1-14600-SMxx50.QSSI13.0/QcomModulePkg/QcomModulePkg.dec#L149).

The memory layout can be changed to enable bigger images if needed, see e.g. https://git.linaro.org/landing-teams/working/qualcomm/abl.git/commit/?id=d8a9dc3ccc0342e77ba5251ab675b4a86ae737c1.

Arbitrary kernel+dtb+ramdisk combinations can be loaded by the stock Android bootloader using the fastboot boot command, without flashing the images onto the device.

A bootable image can be built using the mkbootimg tool (included in the android-tools-mkbootimg package for Debian) - e.g.:

$ mkbootimg --kernel Image+dtb --pagesize 4096 --base 0x80000000 --ramdisk bullseye-initramfs-arm64.cpio.gz -o boot.img

Note: Extra command line options can be appended through the --cmdline option.

The dtb blob has been appended to the kernel Image first, with:

$ cat Image.gz sm8350-hdk.dtb > Image+dtb

The image can then be loaded on the device with:

$ fastboot boot boot.img

Lab notes and trouble shooting

  • The board powers on automatically as soon the USB-C cable is connected, without the need to press the PON button.

  • In order to switch off the power completely, the USB-C cable needs to be unplugged along with the main power adapter jack.

  • An YKUSH switchable hub can be used to automate the connection/disconnection of the USB-C cable in LAVA.

  • The bootable slot can be set using the following command:

    $ fastboot set_active <a/b>
    
  • ABL keeps count of the successful boots on the active slot. Userspace is supposed to mark the slot as bootable upon success. This does not happen when booting Linux distros such as Debian; ABL marks the active slot as unbootable after a few attempts and eventually switches to the _b slot (i.e. the Slot _a is unbootable, trying alternate slot error is printed and fastboot reports FAILED (remote: 'Failed to load/authenticate boot image: Load Error')). A way to circumvent the problem when not implementing a/b updates is to run fastboot set_active a before booting/flashing the image. In LAVA, this can be added as a command in the boot action:

    - boot:
        method: fastboot
        commands:
        - 'set_active a'
    ...
    

Board setup for LAVA integration

In order to setup the board for automation in LAVA using fastboot and keeping the stock bootloader, the boards needs to be set up to enter fastboot mode at boot:

  1. Install fastboot on the host (e.g. apt install fastboot on Debian).
  2. Connect a USB-to-USB micro-B cable to the USB 2.0 micro-B port.
  3. Power on the board by connecting the power.
  4. While keeping the vol- button pressed, press the PON button for ~1 second. The bootloader will enter fastboot mode and the following should be reported in the serial console:
    KeyPress:2, BootReason:0
    Fastboot=1, Recovery:0
    
  5. Connect the USB-to-USB type-C cable to the USB 3.1 Type C port.
  6. Check that the device is correctly detected by the host:
    $ fastboot devices
    3658e3af        fastboot
    
  7. Wipe the boot and dtbo partitions:
    $ fastboot erase boot_a
    $ fastboot erase dtbo_a
    
  8. Power cycle the board; the bootloader should enter fastboot mode automatically.

Example LAVA job definitions for ramdisk and NFS tests

Notes:

  • The download deploy method can be used to fetch the kernel image, the dtb blob and the ramdisk archive; the postprocess command can then be used to assemble the boot image. Any extra command line option needs to be specified in the --cmdline option on the mkbootimg command.

  • Docker images with support for fastboot and mkbootimg are available in the health-check-docker registry. These can be used to assemble the boot image within the LAVA job and to boot the board without the need to install mkbootimg or fastboot on the dispatchers. This also help preventing concurrency problems when trying to access more than one fastboot device at once on the same worker (see: https://docs.lavasoftware.org/lava/integrate-fastboot.html#fastboot).

  • When booting just a ramdisk in LAVA, the test overlay can be unpacked after the boot+login phase using the transfer_overlay property.

  • NFS boot using the latest stable kernel (i.e. v5.19.14 at the time of writing) configured w/ the stock defconfig fails; the drivers for the onboard USB controller and for the onboard USB to Ethernet Controller (i.e. LAN7800 -> http://ww1.microchip.com/downloads/en/DeviceDoc/50002552A.pdf) come up too late in the boot process, preventing the IP from being assigned in time for mounting the NFS (both drivers are compiled as modules). NFS boot succeeds with the following changes in the defconfig:

    --- a/arch/arm64/configs/defconfig
    +++ b/arch/arm64/configs/defconfig
    @@ -379,7 +379,7 @@ CONFIG_USB_BRCMSTB=m
    CONFIG_USB_PEGASUS=m
    CONFIG_USB_RTL8150=m
    CONFIG_USB_RTL8152=m
    -CONFIG_USB_LAN78XX=m
    +CONFIG_USB_LAN78XX=y
    CONFIG_USB_USBNET=m
    CONFIG_USB_NET_DM9601=m
    CONFIG_USB_NET_SR9800=m
    @@ -1193,7 +1193,7 @@ CONFIG_PHY_HISI_INNO_USB2=y
    CONFIG_PHY_MVEBU_CP110_COMPHY=y
    CONFIG_PHY_MTK_TPHY=y
    CONFIG_PHY_QCOM_PCIE2=m
    -CONFIG_PHY_QCOM_QMP=m
    +CONFIG_PHY_QCOM_QMP=y
    CONFIG_PHY_QCOM_QUSB2=m
    CONFIG_PHY_QCOM_USB_HS=y
    CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
    

Example LAVA jobs for ramdisk and NFS boot are reported below for reference.

Ramdisk

device_type: sm8350-hdk

job_name: sm8350-hdk ramdisk test

timeouts:
  job:
    minutes: 10
  action:
    minutes: 5
  connection:
    minutes: 1
priority: high
visibility: public

actions:
  - deploy:
      to: downloads
      images:
          kernel:
              url: https://images.collabora.com/qa/kernel/linux-v5.19.14/arm64/defconfig/gcc-10/Image
          dtb:
              url: https://images.collabora.com/qa/kernel/linux-v5.19.14/arm64/defconfig/gcc-10/dtbs/qcom/sm8350-hdk.dtb
          ramdisk:
              url: https://gitlab.collabora.com/lava/health-check-images/-/jobs/artifacts/main/raw/bullseye/bullseye-initramfs-arm64.cpio.gz?job=build+bullseye+image:+[arm64,+initramfs]
              compression: gz
              format: cpio.newc
              overlays:
                  modules:
                    url: https://images.collabora.com/qa/kernel/linux-v5.19.14/arm64/defconfig/gcc-10/modules.tar.xz
                    compression: xz
                    format: tar
                    path: /
      postprocess:
          docker:
              image: registry.gitlab.collabora.com/lava/health-check-docker
              steps:
                  - gzip Image
                  - cat Image.gz sm8350-hdk.dtb > Image.gz+dtb
                  - mkbootimg --kernel Image.gz+dtb --ramdisk bullseye-initramfs-arm64.cpio.gz --pagesize 4096 --base 0x80000000 -o boot.img
  - deploy:
      to: fastboot
      docker:
          image: registry.gitlab.collabora.com/lava/health-check-docker
      images:
        boot:
          url: downloads://boot.img

  - boot:
      method: fastboot
      docker:
          image: registry.gitlab.collabora.com/lava/health-check-docker
      commands:
        - 'set_active a'
      auto_login:
        login_prompt: 'login:'
        username: 'user'
        password_prompt: 'Password:'
        password: user
        login_commands:
          - sudo su
          - /usr/lib/systemd/systemd-time-wait-sync
      transfer_overlay:
        transfer_method: http
        download_command: wget -S --progress=dot:giga
        unpack_command: tar -C / -xzf
      prompts:
        - 'user@health'
        - 'root@health'

  - test:
      definitions:
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: dmesg/dmesg.yaml
        name: dmesg-tests
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: temperature/temperature.yaml
        name: temperature-tests
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: network/network.yaml
        name: network-tests
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: network/device_ip.yaml
        name: device-ip-tests

NFS

device_type: sm8350-hdk

job_name: sm8350-hdk nfs test

timeouts:
  job:
    minutes: 10
  action:
    minutes: 5
  connection:
    minutes: 1
priority: high
visibility: public

actions:
  - deploy:
      to: nfs
      nfsrootfs:
        url: https://gitlab.collabora.com/lava/health-check-images/-/jobs/artifacts/main/raw/bullseye/bullseye-rootfs-arm64.tar.gz?job=build+bullseye+image:+[arm64,+rootfs]
        compression: gz
      modules:
        url: https://images.collabora.com/lava/boot/sm8350-hdk/modules.tar.gz
        compression: gz

  - deploy:
      to: downloads
      images:
          kernel:
              url: https://images.collabora.com/lava/boot/sm8350-hdk/Image.gz
          dtb:
              url: https://images.collabora.com/lava/boot/sm8350-hdk/sm8350-hdk.dtb
          ramdisk:
              url: https://gitlab.collabora.com/lava/health-check-images/-/jobs/artifacts/main/raw/bullseye/bullseye-rootfs-arm64-initramfs.gz?job=build+bullseye+image:+[arm64,+rootfs]
              compression: gz
              format: cpio.newc
              overlays:
                  modules:
                    url: https://images.collabora.com/lava/boot/sm8350-hdk/modules.tar.gz
                    compression: gz
                    format: tar
                    path: /
      postprocess:
          docker:
              image: registry.gitlab.collabora.com/lava/health-check-docker
              steps:
                  - cat Image.gz sm8350-hdk.dtb > Image.gz+dtb
                  - mkbootimg --kernel Image.gz+dtb --cmdline "console=ttyMSM0,115200n8 root=/dev/nfs rw nfsroot=$NFS_SERVER_IP:$NFS_ROOTFS,tcp,hard rootwait ip=dhcp" --ramdisk bullseye-rootfs-arm64-initramfs.gz --pagesize 4096 --base 0x80000000 -o boot.img
  - deploy:
      to: fastboot
      docker:
          image: registry.gitlab.collabora.com/lava/health-check-docker
      images:
        boot:
          url: downloads://boot.img

  - boot:
      method: fastboot
      docker:
          image: registry.gitlab.collabora.com/lava/health-check-docker
      commands:
        - 'set_active a'
      auto_login:
        login_prompt: 'login:'
        username: 'user'
        password_prompt: 'Password:'
        password: user
        login_commands:
          - sudo su
          - /usr/lib/systemd/systemd-time-wait-sync
      prompts:
        - 'user@health'
        - 'root@health'

  - test:
      definitions:
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: dmesg/dmesg.yaml
        name: dmesg-tests
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: temperature/temperature.yaml
        name: temperature-tests
      - repository: https://gitlab.collabora.com/lava/functional-tests.git
        from: git
        history: no
        path: network/network.yaml
        name: network-tests