struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
metal_init(&metal_param);
- Initialize libmetal environment with call to metal_init().
- Add devices:
- This step is only needed for Baremetal or FreeRTOS as there is no standard such as device tree used in Baremetal to describe devices.
- Statically define the libmetal device and register it to the appropriate bus.
- The following code snippet shows how to statically define the Triple Timer Counter device for Baremetal or FreeRTOS.
- 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 */
metal_register_generic_device(static_dev);
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>;
};
};
- 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);