Device-Type enablement

This guide will quickly explain how to enable a new Device-Type in LAVA using an LAA.

Hardware support

In this guide, we suppose that the LAA does provide the right hardware feature to automate the new device-type.

For example, the board can be powered by 1v8, 3v3, 5v or 12v or from USB PD.

laam laacli

In order to use this guide, you should already be familiar with the laam tool.

Choosing the MIB

Start by choosing the MIB that will allow to automate your new DUT.

Unless your Device-Type is already supported by an existing MIB, use the flylead MIB.

Connect the chosen MIB to the SIB using the SIB header.

Powering the DUT

USB powered

If the DUT is powered via USB, connect the LAA USB port 1 to the right port on the DUT.

The DUT can now be powered-on and off using:

  • laam laacli usb 1 on

  • laam laacli usb 1 off

Power rails

If the DUT can be powered via a pin or a jack port, connect the DUT pin to one of the power rails on the MIB.

The DUT can now be powered-on and off using:

  • laam laacli power <RAIL> on

  • laam laacli power <RAIL> off

Where RAIL would be 1v8, 3v3, 5v or 12v.

Pressing a button

If the DUT does not boot automatically when powering-on and requires a button press, you will have to connect a wire to each end of the button and connect it to an opto coupler.

Virtual button

In order to be consistent, we advice to use the power button for this use case.

The button can then be pressed using laam laacli button power on.

Serial console

In order to interact with the DUT, LAVA will need to have access to the serial console.

Direct UART

Connect the UART to one of the available UARTs on the MIB or the sib-header

UART port

We advice you to use SIB_UART4 as this is already fully configured to be used by LAVA with telnet localhost 2000.

You can use laam to interact with the console from your laptop using laam serial connect ttymxc3.

Serial over USB

Connect the USB cable to the LAA USB port 2.

ser2net configuration

Currently, the following serials are supported by the ser2net configuration:

Device

Type

Baud rates

Configs

Port

Name

/dev/ttymxc3

SIB_UART4

  115200
      9600
1500000
3000000

n81

2000
2100
2200
2300

ttymxc3
ttymxc3-9600
ttymxc3-1_5M
ttymxc3-3M

/dev/ttyUSB0

USB

  115200
      9600
1500000
3000000

n81

2010
2110
2210
2310

ttyUSB0
ttyUSB0-9600
ttyUSB0-1_5M
ttyUSB0-3M

/dev/ttyUSB1

USB

  115200
      9600
1500000
3000000

n81

2011
2111
2211
2311

ttyUSB1
ttyUSB1-9600
ttyUSB1-1_5M
ttyUSB1-3M

/dev/ttyACM0

USB

  115200
      9600
1500000
3000000

n81

2020
2120
2220
2320

ttyACM0
ttyACM0-9600
ttyACM0-1_5M
ttyACM0-3M

/dev/ttyACM1

USB

  115200
      9600
1500000
3000000

n81

2021
2121
2221
2321

ttyACM1
ttyACM1-9600
ttyACM1-1_5M
ttyACM1-3M

You can connect to the device using laam serials connect <NAME>.

LAVA Support

If the above commands are enough to get the DUT to boot into the bootloader, then LAVA will be able to use your DUT to test the OS or user space applications.

You will need to write to jinja2 files:

  • device-type template: device-type generic information

  • device dictionary: DUT specific configuration

laam dut helper

The laam utility provide an helper to generate the device-type template and the device dictionary from a simple configuration file.

See laam dut helper.

Device-type template

The device-type template is a jinja2 template that explains to LAVA the supported features for the device-type.

The list of upstream device-type is available in LAVA sources.

Depending on the bootloader on the DUT, the device-type template and the device dictionary will differt.

u-boot

If using u-boot, the device-type template will look something like:

{# set device_type = "<DTB_NAME>" #}

{% extends 'base-uboot.jinja2' %}

{% set booti_kernel_addr = booti_kernel_addr|default('<BOOTI_KERNEL_ADDR>') %}
{% set booti_ramdisk_addr = booti_ramdisk_addr|default('<BOOTI_RAMDISK_ADDR>') %}
{% set booti_dtb_addr = booti_dtb_addr|default('<BOOTI_DTB_ADDR>') %}

{% set bootm_kernel_addr = bootm_kernel_addr|default('<BOOTM_KERNEL_ADDR>') %}
{% set bootm_ramdisk_addr = bootm_ramdisk_addr|default('<BOOTM_RAMDISK_ADDR>') %}
{% set bootm_dtb_addr = bootm_dtb_addr|default('<BOOTM_DTB_ADDR>') %}

{% set uboot_mkimage_arch = 'arm64' %}

{% set bootloader_prompt = bootloader_prompt|default('U-Boot>') %}
{% set console_device = console_device|default('ttyS1') %}

Adapting the template

Set the variables to the right values for your device-type.

Device-dictionary

The device dictionary is DUT specific and indicate to LAVA how to power on/off/reset the DUT or access the serial console. Based on the initial part of the guide, you should have the list of commands ready now.

{% extends '<DTB_NAME>.jinja2' %}

{% set hard_reset_command = [
    '<LAACLI_POWER_OFF>',
    '<LAACLI_POWER_ON>'
] %}
{% set power_off_command = [
    '<LAACLI_POWER_OFF>'
] %}
{% set power_on_command =  [
    '<LAACLI_POWER_ON>'
] %}

{% set connection_command = 'telnet localhost <SERIAL_PORT>' %}

{% set usbg_ms_commands = {
    'disable': ['laacli', 'usbg-ms', 'off'],
    'enable': ['laacli', 'usbg-ms', 'on', '{IMAGE}']
} %}
{% set docker_shell_extra_arguments = [
    '--volume=/usr/bin/laacli:/usr/bin/laacli:ro',
    '--volume=/usr/bin/lsibcli:/usr/bin/lsibcli:ro',
    '--volume=/run/dbus/system_bus_socket:/run/dbus/system_bus_socket:rw'
] %}

laam dut helper

The laam tool provides a dut helper to create and test LAVA device-type template and device dictionary. The tool is using a custom configuration file that is used to auto-generate the LAVA files.

RPi4

For this guide, we will use an RPi4B as DUT.

Configuration file

Start by creating a new configuration file with:

$ laam dut new rpi4.yaml
Create a new device configuration (u-boot only)
dtb name> bcm2711-rpi-4-b

device-type name

By convention, LAVA uses the dtb filename as device-type name. Following the convention will make upstreaming easier.

The file now contains:

bootloader: u-boot
interrupt: true
name: bcm2711-rpi-4-b
power:
  'off': []
  'on': []
  reset: []
prompt: '=> '
serial: ttymxc3

The parameters are:

  • bootloader: should always be u-boot for the moment

  • interrupt: should u-boot be interrupted

  • name: dtb filename

  • power: dictionary of power commands. Should use laam laacli commands

  • prompt: u-boot prompt

  • serial: name of the serial console

Power commands

Add the power commands (and the bootloader prompt) to the configuration file:

bootloader: u-boot
interrupt: true
name: bcm2711-rpi-4-b
power:
  'off': ["laam laacli power 3v3 off", "laam laacli power 5v off"]
  'on': ["laam laacli power 5v on", "laam laacli power 3v3 on"]
  reset: ["laam laacli power 5v reset", "laam laacli power 3v3 on"]
prompt: 'U-Boot> '
serial: ttymxc3

Boot test

Based on this configuration file, laam can try to boot the DUT:

$ laam dut test rpi4.yaml --usbg-ms boot-rpi4.img
Connect to serial
 => ttymxc3

Push USBG-MS file

Reset the DUT
 => laam laacli power 5v reset
power 5v off
sleep 5
power 5v on
 => laam laacli power 3v3 on

Interrupt bootloader
<serial> Connecting to ws://laa-00006.local/ws/ port 2000
<serial> [Telnet] connected to 127.0.0.1:2000
<serial> 
<serial> ser2net port telnet(rfc2217),tcp,localhost,2000,172.17.0.1,2000 device keepopen,serialdev, /dev/ttymxc3, 115200n81,local [115200N81,CLOCAL,HANGUP_WHEN_DONE] 
<serial> 
<serial> 
<serial> 
<serial> U-Boot 2024.01 (Apr 10 2025 - 11:24:17 +0000)
<serial> 
<serial> DRAM:  947 MiB (effective 3.9 GiB)
<serial> RPI 4 Model B (0xc03114)
[...]
<serial> scanning bus xhci_pci for devices... 3 USB Device(s) found
<serial>        scanning usb for storage devices... 1 Storage Device(s) found

Wait for prompt 'U-Boot> '
<serial> Hit any key to stop autoboot:  0 

Test USB support
<serial> U-Boot> usb start; usb info
<serial> 1: Hub,  USB Revision 3.0
[...]
<serial> 2: Hub,  USB Revision 2.10
[...]
<serial> 3: Mass Storage,  USB Revision 2.1
<serial>  - LAA USB Mass Storage Gadget 123456
<serial>  - Class: (from Interface) Mass Storage
<serial>  - PacketSize: 64  Configurations: 1
<serial>  - Vendor: 0x1d6b  Product 0x0104 Version 0.1
<serial>    Configuration: 1
<serial>    - Interfaces: 1 Bus Powered 500mA
<serial>    - String: "1xMass Storage"
<serial>      Interface: 0
<serial>      - Alternate Setting 0, Endpoints: 2
!!! USB ok !!!
<serial>      - Class Mass Storage, Transp. SCSI, Bulk only
<serial>      - String: "Mass Storage"
<serial>      - Endpoint 1 In Bulk MaxPacket 512
<serial>      - Endpoint 1 Out Bulk MaxPacket 512
<serial> 

Test network support
<serial> U-Boot> dhcp; ping 198.18.0.1
<serial> ethernet@7d580000 Waiting for PHY auto negotiation to complete.... done
[...]
<serial> host 198.18.0.1 is alive
!!! Network ok !!!

Power off the DUT
 => laam laacli power 3v3 off
 => laam laacli power 5v off

USBG-MS

For this specific DUT, the bootloader is provided via USB mass storage emulation so we have to provide an image via --usbg-ms.

This image comes from https://firmwares.lavacloud.io/rpi-4-b/boot.img.zst.

LAVA templates

Based on the configuration file, laam can now generate a device-type template and a device dictionary to use with the LAA:

$ laam dut render rpi4.yaml bcm2711-rpi-4-b.jinja2 rpi4-laa.jinja2
Device-type template: 'bcm2711-rpi-4-b.jinja2' (should be called 'bcm2711-rpi-4-b.jinja2')
Device dictionary: 'rpi4-laa.jinja2'

A simple device-type template as been generated and can be used by LAVA:

{% extends 'base-uboot.jinja2' %}

{% set uboot_needs_interrupt = uboot_needs_interrupt | default(True) %}
{% set bootloader_prompt = bootloader_prompt | default('U-Boot> ') %}

The corresponding device-dictionary that can be used with LAVA and an LAA:

{% extends 'bcm2711-rpi-4-b.jinja2' %}

{% set hard_reset_command = [
    'laacli power 5v reset',
    'laacli power 3v3 on'
] %}
{% set power_off_command = [
    'laacli power 3v3 off',
    'laacli power 5v off'
] %}
{% set power_on_command =  [
    'laacli power 5v on',
    'laacli power 3v3 on'
] %}

{% set connection_command = 'telnet localhost 2000' %}

{% set usbg_ms_commands = {
    'disable': ['laacli', 'usbg-ms', 'off'],
    'enable': ['laacli', 'usbg-ms', 'on', '{IMAGE}']
} %}
{% set docker_shell_extra_arguments = [
    '--add-host=lava-worker.internal:host-gateway',
    '--volume=/usr/bin/laacli:/usr/bin/laacli:ro',
    '--volume=/usr/bin/lsibcli:/usr/bin/lsibcli:ro',
    '--volume=/run/dbus/system_bus_socket:/run/dbus/system_bus_socket:rw'
] %}

Recovery

Recovering from a bad firmware is not considered in the guide yet as this involved more complex setup.