Device-Type enablement

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

Hardware support

In this guide, we suppose that the LAA provides the necessary hardware features to automate the new device-type.

For example, the board may be powered by 1.8V, 3.3V, 5V, 12V or from USB-PD.

laam laacli

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

Platform Considerations

The first step a user must perform is to make the platform “automatable.” This means you’ll be able to to reset, power cycle, flash, and connect to the platform with zero manual intervention. If your platform requires hardware patch wiring to support automation in a Linaro Remote Lab, these modifications should be completed at this stage. It’s recommended to document the H/W mods as well as reworking platforms ahead of time in preparation for integration. Preparing the DUTs before receiving the LAA is recommended, allowing you to move directly into the LAA integration phase upon its arrival. Ideally, consider preparing multiple platforms in advance to have a backup on hand if any platform failures occur.

Note: The most common reason for requiring automation is hardware-imposed special cases during firmware installation at reset. For example, if entering a specific boot mode requires pressing buttons or toggling jumpers/switches during reset or power-on, the DUT must be modified for automation. This may involve adding jumper wires, removing a switch, or a combination of both. Refer to the Introduction to Automation section of this document for a quick overview.

Choosing a MIB

Start by selecting a MIB that will allow you 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

Power Sequencing Definition

It is necessary to define the ordering of power rail activation/deactivation for the proper functioning of your new device-type. You may use the template\

USB powered

If the DUT is powered via USB, connect the LAA USB port 1 to the appropriate 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 need to connect a wire to each contact 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 a serial console.

Direct UART

Connect the UART to one of the available UARTs on the MIB or the SIB header.

UART port

We advise 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 LAA USB port 2.

ser2net configuration

ser2net is a project which allows exposing serial ports as sockets for network communication.

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 userspace applications.

You will need to write two jinja2 files:

  • device-type template: device-type generic information

  • device dictionary: DUT specific configuration

laam dut helper

The laam utility provides 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 describes to LAVA the supported features for the device-type.

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

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

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 appropriate values for your device.

Device Dictionary

The device dictionary is DUT specific and indicates 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 a Raspberry Pi 4 Model B 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 this 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.