Application-specific data

As mentioned earlier, the device tree is commonly used to carry specific information, so that a single driver can manage similar pieces of hardware. For example, if the hardware is an LCD display driver, the information about its pixel dimensions and maybe even physical dimensions may appear in the device tree. Serial port interface hardware (i.e. RS-232, UART) is likely to inform the driver about what clock frequency is driving the logic, so that the driver can set up the clock division registers correctly. And so on.

In the simplest, and most common form, this information is conveyed by a simple assignment in the peripheral’s entry, e.g.

      xlnx,slv-awidth = <0x20>;

The “xlnx,” prefix merely protects against name collisions. The name string is arbitrary, but some kind of prefix is recommended at least for the sake of clarity. The “xlnx,” prefix is common, because it’s used by the automatic tool that generates device trees for the Microblaze soft processor.

To grab this information, the kernel code says something like

void *ptr;
  ptr = of_get_property(op->dev.of_node, "xlnx,slv-awidth", NULL);

  if (!ptr) {
    /* Couldn't find the entry */
  }

The third argument in the call, NULL, is possibly a pointer to an int variable, to which the length of the data is written.

To access the actual data, assuming that it’s a number, go

int value;
  value = be32_to_cpup(ptr);

The be32_to_cpup reads the data from the address given by “ptr”, converts from Big Endian to the processor’s native Little Endian, so “value” will contain the integer one expects it to contain.

There are plenty of other API functions for reading arrays etc. See drivers/of/base.c in the Linux sources.

Summary

All in all, setting up a device tree entry for a custom IP peripheral is quite simple:

  • Pick a “magic string” for the “compatible” assignment, possibly the name+version format employed by the automatic tools.
  • Look up the address allocation on the bus in XPS, and write the “reg=” assignment accordingly
  • Add the “interrupt-parent = <&gic>” line (if interrupts are used)
  • Look up the interrupt allocation in XPS, and write the “interrupt=” assignment (if applicable)
  • Add any custom parameters as needed

And that’s it. Good luck!