wiki:FlattenedDeviceTree

Version 6 (modified by Nicolas Pouillon, 14 years ago) (diff)

--

Around revision [900], MutekH got support for Flattened device trees.

Rationale

Flattened device trees (FDT) are useful to get a list of all available hardware where no hardware-based enumeration exists (aka PnP, like PCI, USB, ... provides).

FDT provides normalized representation of the hardware platform without adding specific initialization code.

The normalization comes from IEEE1275 (aka Open Firmware); while Open Firmware also defined heavy things (like a Forth interpreter), we only use the FDT information.

Using FDT is mainstream, is also used by Linux and BSD, supported by U-Boot and other bootloaders.

References

Implementation

In MutekH, FDT is handled through an hardware enumerator device driver, it behaves like the other enumerators (PCI, ISAPnP).

MutekH-Specific Node syntax quick reference

Processors

Processor nodes look like:

Mips,32@0 {
        name = "Mips,32";
        device_type = "cpu";
        reg = <0>;
};
reg
This is the CPU identification number
device_type
must be "cpu"

There is a couple of optional attributes:

ipi_icudev
This is a reference to the ICU device handling IPIs for this CPU
ipi_no
This is the IPI register number in the said ICU device.

Memories

Memory nodes look like:

memory@0 {
        device_type = "memory";
        cached;
        reg = <0x61100000 0x00100000>;
};
device_type
must be "memory"
reg
must be a couple of <address size> with both the values respecting #address-cells and #size-cells.

There are two optional attributes:

cached
The memory is cacheable
coherent
The memory is cached and coherent (cached is implied, setting it is optional)

References to interrupt controllers

Interrupts controller are referenced from one node to another in order to describe the interrupt tree. References are handled through the following properties:

icudev
Must be a path to an existing ICU device, enclosing in &{} is syntactic
irq
Is the irq number in icudev.

Example:

icu@0 {
        device_type = "soclib:icu";
        input_count = <2>;
        reg = <0x20600000 0x20>;
        icudev = &{/cpus/Mips,32@0};
        irq = <0>;
};

tty@0 {
	device_type = "soclib:tty";
	tty_count = <1>;
	reg = <0x90600000 0x10>;
	icudev = &{/icu@0};
	irq = <1>;
};

Here the ICU device for /tty@0 is /icu@0 (device at address 0x20600000), which in turn references /cpus/Mips,32@0 as its ICU device.

Parameter structure construction for calling _init functions

Some devices require a structure containing parameters in order to correctly initialize them. This case is handled in the FDT description. Let's see the example of the soclib:xicu component. It needs a structure containing:

struct soclib_xicu_param_s
{
        size_t output_line_no;
};

In the driver, the id definition is:

static const struct driver_param_binder_s xicu_param_binder[] =
{
        PARAM_BIND(struct soclib_xicu_param_s, output_line_no, PARAM_DATATYPE_INT),
        { 0 }
};

static const struct devenum_ident_s     xicu_soclib_ids[] =
{
        DEVENUM_FDTNAME_ENTRY("soclib:xicu", sizeof(struct soclib_xicu_param_s), xicu_param_binder),
        { 0 }
};

This informs the FDT parser this device will need a parameter structure, with the parameters described in the xicu_param_binder correctly filled-in.

In this table, there is one entry telling the output_line_no parameter is an integer.

Available data types are:

PARAM_DATATYPE_INT
a simple integer
PARAM_DATATYPE_DEVICE_PTR
a device reference (&{/node/path} in the device tree source), which will be transparently translated to a struct device_s * before filling the structure. Device must exist in the tree.
PARAM_DATATYPE_ADDR
an address, #address-cells will be honored
PARAM_DATATYPE_BOOL
a simple boolean, i.e. a property with no value, if present it is true, if absent it is false (like the cached attribute in memory nodes)

Example

Drivers may export themselves as FDT-aware, and define which device name string to match. For instance, the following subtree defines a tty device:

tty@0 {
	device_type = "soclib:tty";
	tty_count = <1>;
	reg = <0x90600000 0x10>;
	icudev = &{/icu@0};
	irq = <1>;
};

In turn, the SoCLib tty driver declares itself (in source:trunk/mutekh/drivers/device/char/tty-soclib/tty-soclib.c#L146) as:

Note there is no parameter structure definition, so the two last arguments of DEVENUM_FDTNAME_ENTRY are 0.

static const struct devenum_ident_s	tty_soclib_ids[] =
{
	DEVENUM_FDTNAME_ENTRY("soclib:tty", 0, 0),
	{ 0 }
};

const struct driver_s	tty_soclib_drv =
{
  .class		= device_class_char,
  .id_table		= tty_soclib_ids,
  .f_init		= tty_soclib_init,
  .f_cleanup		= tty_soclib_cleanup,
  .f_irq		= tty_soclib_irq,
  .f.chr = {
    .f_request		= tty_soclib_request,
  }
};

This will make the FDT enumerator use the correct driver, matching "soclib:tty"