Start Libmetal Environment, Add and Open the Devices - 2022.1 English

Libmetal and OpenAMP User Guide (UG1186)

Document ID
Release Date
2022.1 English

1. Initialize libmetal environment with call to metal_init().

struct metal_init_params metal_param = METAL_INIT_DEFAULTS;


2. Add devices:

a. This step is only needed for Baremetal or FreeRTOS as there is no standard such as device tree used in Baremetal to describe devices.

b. Statically define the libmetal device and register it to the appropriate bus.

c. The following code snippet shows how to statically define the Triple Timer Counter device for Baremetal or FreeRTOS.

d. When initializing the metal_device struct provide the following: a name string, a bus for the device, the number of regions, table of each region in the device, a node to keep track of the device for the appropriate bus, the number of IRQs per device and an IRQ ID if necessary.

const metal_phys_addr ipi_phy_addr = 0xff310000;

static struct metal_device static_dev = {

.name = "ff310000.ipi",

.bus = NULL, /* will be set later in metal_device_open() */

.num_regions = 1, /* number of I/O regions */

.regions = {


.virt = (void *) 0xff310000, /* virtual address */

.physmap = &ipi_phy_addr, /* pointer to base physical address of the I/O region */

.size = 0x1000, /* size of the region */

.page_shift = (-1UL), /* page shift. In baremetal/FreeRTOS, memory is flat, no pages */

.page_mask = (-1UL), /* page mask */

.mem_flags = DEVICE_NONSHARED | PRIV_RW_USER_RW, /* memory attributes */

.ops = {NULL}, /* no user specific I/O region operations. If don't want to use the default ones, you can define yours. */



.node = {NULL}, /* will be set by libmetal later. used to keep track of the devices list */

.irq_num = 1, /* number of interrupts of this device */

.irq_info = (void *)65, /* interrupt information, here is the irq vector id */


For libmetal in Linux userspace, devices need to be placed in the device tree. Here is an example:

amba {

ipi_amp: ipi@ff340000 {

compatible = "ipi_uio"; /* used just as a label as libmetal will bind this device as UIO device */

reg = <00x 0xff340000 0x0 0x1000>;

interrupt-parent = <&gic>;

interrupts = <0 29 4>;



3. Open Devices.

Next, open the device to access the memory mapped device I/O regions and retrieve interrupts if applicable.

struct metal_device *dev;

… // instantiate device here

metal_device_open(BUS_NAME, DEVICE_NAME, &dev);