Linux DMA Device Tree Bindings- Free Linux Device Drivers Tutorial


Linux DMA Device Tree Bindings
Free Linux Kernel Development Course — Chapter 12, Lecture 6
Reading Time
16 Minutes
Level
Intermediate
Kernel Version
6.x

Keywords Covered In This Lecture

linux dma device tree binding
dmas property
dma-names
dma_request_chan
free linux device drivers course
free embedded linux course

Every real-world Linux DMA device tree binding is what connects a DMA controller on your SoC to the peripheral driver that wants to use it. In the earlier lectures of this free Linux kernel development course, you learned how to request a DMA channel in C code and how to submit and complete a transfer. This lecture fills the missing piece: how the kernel knows which channel belongs to which device, purely from the device tree, without hardcoding channel numbers anywhere in your driver.

What You Will Learn

  • Why DMA channels are described in the device tree instead of being hardcoded
  • The structure of a DMA controller node: compatible, #dma-cells, dma-channels
  • The structure of a consumer node: the dmas and dma-names properties
  • How #dma-cells decides the shape of every DMA specifier in the tree
  • How a name string in dma-names maps to the string you pass to dma_request_chan()
  • Writing an original platform driver plus a matching device tree overlay for two named channels
  • Common mistakes, debugging tips, and best practices for DMA device tree bindings

Prerequisites

  • Completion of the earlier DMA engine lectures in this free embedded Linux course (channel requesting, slave config, submission, completion callback)
  • Basic device tree concepts — nodes, phandles, and properties (covered earlier in this free linux kernel development course)
  • A cross-compiled kernel 6.x source tree and a board or QEMU target with an out-of-tree module build environment

Why DMA Needs Its Own Device Tree Binding

A DMA controller on a modern SoC usually exposes many channels, and every peripheral that wants DMA has its own request line into that controller. Instead of writing the channel number directly into the driver, the kernel asks the device tree: “give me the channel that this device tree node calls tx.” This is exactly the same philosophy the kernel uses for clocks, interrupts, and regulators — the driver only knows a symbolic name, and the device tree wires the real hardware behind it.

DMA Device Tree Binding Flow
DMA Controller Node –describes–> #dma-cells, channel count
|
| phandle reference
v
Consumer Device Node –dmas property–> &controller + specifier
|
| dma-names property
v
Driver calls dma_request_chan(dev, “tx”)
|
v
DMA Core matches name -> phandle -> real channel

The DMA Controller Node

The DMA controller node is written once by the SoC vendor’s device tree and almost never touched by application driver authors. Three properties matter most for understanding how consumers bind to it.

Property Meaning
compatible Identifies the DMA controller driver that should bind to this node
#dma-cells Number of cells (integers) that follow the phandle in every consumer’s specifier
dma-channels Total number of physical channels the controller exposes (informational, driver specific)

A minimal controller node, written for this course as a generic teaching example rather than any specific vendor’s binding, looks like this:

ep_dma_ctrl: dma-controller@50000000 {
    compatible = "ep,dma-controller";
    reg = <0x50000000 0x1000>;
    interrupts = <0 42 4>;
    #dma-cells = <2>;
    dma-channels = <8>;
};

#dma-cells = <2> tells every consumer of this controller that its DMA specifier must contain the phandle followed by exactly two integers — typically a channel/request-line ID and a slave configuration flag. The exact meaning of those two integers is defined by the controller’s own binding document, not by the generic DMA framework.

The Consumer Node: dmas and dma-names

The peripheral node — the one your driver actually binds to — declares which channels it needs using two properties that always travel together.

ep_uart0: serial@60000000 {
    compatible = "ep,uart";
    reg = <0x60000000 0x100>;
    interrupts = <0 17 4>;
    dmas = <&ep_dma_ctrl 4 0>, <&ep_dma_ctrl 5 0>;
    dma-names = "rx", "tx";
};

Read this node exactly the way dma_request_chan() will read it later: the dmas property is a list of specifiers, and dma-names is a parallel list of strings. The first specifier is named "rx", the second is named "tx". Each specifier itself starts with the controller phandle followed by #dma-cells integers — here, two, because the controller declared #dma-cells = <2>.

Consumer Property Purpose
dmas List of &controller <cells...> specifiers, one per requested channel
dma-names Human-readable name for each entry in dmas, used by the driver at runtime

From Device Tree Name To dma_request_chan()

Once the binding exists in the device tree, the driver side is intentionally simple — the driver never touches the raw specifier numbers at all:

struct dma_chan *rx_chan, *tx_chan;

rx_chan = dma_request_chan(dev, "rx");
if (IS_ERR(rx_chan))
    return PTR_ERR(rx_chan);

tx_chan = dma_request_chan(dev, "tx");
if (IS_ERR(tx_chan)) {
    dma_release_channel(rx_chan);
    return PTR_ERR(tx_chan);
}

The string "rx" passed to dma_request_chan() is matched against the dma-names array of the device’s own device tree node. The DMA core then resolves the corresponding phandle in dmas, hands the specifier cells to the controller driver, and returns a ready-to-use struct dma_chan *.

Original Example: A DT-Bound DMA Consumer Driver

The following ep_dma_dt_demo platform driver is written for this course. It requests two named DMA channels straight from its own device tree node, configures them, and releases them cleanly. It is deliberately hardware-agnostic so you can adapt the controller phandle to whatever DMA controller is available on your own board or QEMU model.

Step 1: Device Tree Node

ep_dma_demo0: ep-dma-demo@60010000 {
    compatible = "ep,dma-dt-demo";
    reg = <0x60010000 0x100>;
    dmas = <&ep_dma_ctrl 6 0>, <&ep_dma_ctrl 7 0>;
    dma-names = "rx", "tx";
    status = "okay";
};

Step 2: Driver Source

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/dmaengine.h>

struct ep_dma_demo {
    struct dma_chan *rx_chan;
    struct dma_chan *tx_chan;
};

static int ep_dma_demo_probe(struct platform_device *pdev)
{
    struct ep_dma_demo *priv;
    struct device *dev = &pdev->dev;

    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->rx_chan = dma_request_chan(dev, "rx");
    if (IS_ERR(priv->rx_chan)) {
        dev_err(dev, "failed to get rx channel from DT\n");
        return PTR_ERR(priv->rx_chan);
    }

    priv->tx_chan = dma_request_chan(dev, "tx");
    if (IS_ERR(priv->tx_chan)) {
        dev_err(dev, "failed to get tx channel from DT\n");
        dma_release_channel(priv->rx_chan);
        return PTR_ERR(priv->tx_chan);
    }

    platform_set_drvdata(pdev, priv);
    dev_info(dev, "ep_dma_dt_demo: rx and tx channels bound from device tree\n");
    return 0;
}

static void ep_dma_demo_remove(struct platform_device *pdev)
{
    struct ep_dma_demo *priv = platform_get_drvdata(pdev);

    dma_release_channel(priv->tx_chan);
    dma_release_channel(priv->rx_chan);
    dev_info(&pdev->dev, "ep_dma_dt_demo: channels released\n");
}

static const struct of_device_id ep_dma_demo_of_match[] = {
    { .compatible = "ep,dma-dt-demo" },
    { }
};
MODULE_DEVICE_TABLE(of, ep_dma_demo_of_match);

static struct platform_driver ep_dma_demo_driver = {
    .probe  = ep_dma_demo_probe,
    .remove = ep_dma_demo_remove,
    .driver = {
        .name = "ep_dma_dt_demo",
        .of_match_table = ep_dma_demo_of_match,
    },
};
module_platform_driver(ep_dma_demo_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala DMA device tree binding demo");

Step 3: Build And Load

$ make -C /lib/modules/$(uname -r)/build M=$PWD modules
$ sudo insmod ep_dma_dt_demo.ko
$ dmesg | tail

Expected dmesg Output

[  102.441021] ep_dma_dt_demo: rx and tx channels bound from device tree
[  108.220334] ep_dma_dt_demo: channels released

Note: if your board’s overlay does not define a matching ep,dma-dt-demo node, probe() will never be called, and if the node exists but the controller cannot supply a channel named "rx" or "tx", dma_request_chan() returns -ENODEV or -EPROBE_DEFER instead of a valid channel.

Legacy Filter-Based Binding vs Modern DT Binding

Aspect Legacy dma_request_channel() + filter_fn Modern DT-based dma_request_chan()
Channel identity Encoded in a C filter function and board file Encoded declaratively in dmas/dma-names
Board portability Driver must know board-specific channel IDs Driver only knows a symbolic name string
Where covered lddch12_5 in this series This lecture, lddch12_6
Kernel direction Discouraged for new drivers Preferred for all new device tree platforms

Common Mistakes With DMA Device Tree Bindings

  • Mismatched #dma-cells: writing three integers in a dmas specifier when the controller declares #dma-cells = <2> causes a device tree parse error at boot.
  • dma-names order mismatch: the order of strings in dma-names must exactly match the order of specifiers in dmas; swapping them silently swaps rx and tx at runtime.
  • Forgetting dma_release_channel(): every successful dma_request_chan() must be paired with dma_release_channel() in the remove path, or the channel stays reserved after unbind.
  • Assuming immediate success: a valid binding can still return -EPROBE_DEFER if the DMA controller driver has not probed yet; your probe function must return the error code as-is so the driver core can retry.

Best Practices

  • Always name channels by function ("rx", "tx", "mem") rather than by number, so the binding stays portable across boards.
  • Document the meaning of each #dma-cells integer in your controller’s own binding documentation for driver authors.
  • Use devm_ style allocations for private driver state so cleanup on probe failure stays automatic.
  • Always propagate -EPROBE_DEFER instead of treating it as a hard failure.

Performance And Security Considerations

From a performance standpoint, device tree binding itself has zero runtime cost after boot — it is resolved once during probe, not on every transfer. From a security standpoint, a consumer node should only request channels it actually needs; over-broad DMA channel access from an untrusted or hot-pluggable device increases the surface for memory-corruption style attacks if that peripheral is ever compromised.

Summary And Key Takeaways

  • DMA device tree bindings connect a controller node to a consumer node without hardcoding channel numbers in driver code
  • #dma-cells on the controller decides the shape of every specifier in dmas
  • dma-names gives each specifier a symbolic name that the driver looks up with dma_request_chan()
  • Always release every requested channel in the remove path

Conclusion

With this lecture, the device tree side of the DMA engine subsystem is complete: you now know how a controller advertises its channels, how a consumer names the ones it needs, and how that name turns into a working struct dma_chan * inside your driver. Combined with the channel requesting, slave configuration, submission, and completion topics from earlier lectures in this free linux device drivers course, you have the full picture needed to write a production-quality DMA consumer driver from scratch.

Frequently Asked Questions

What does #dma-cells actually control?

It sets how many integer cells follow the controller phandle inside every dmas specifier in the device tree, so the parser knows how much data to read for each channel request.

Can a device request more than two DMA channels from the device tree?

Yes. Both dmas and dma-names are simple lists, so a node can list as many named channels as the device needs.

What happens if dma-names has more entries than dmas?

The device tree compiler or the DMA core will fail to match a specifier for the extra name, and dma_request_chan() for that name returns an error.

Is dma_request_chan() the same as the older dma_request_slave_channel()?

They serve the same purpose, but dma_request_chan() is the current recommended API on kernel 6.x and returns a proper error pointer instead of NULL on failure.

Do I need a device tree overlay to test this on QEMU?

Yes, unless your QEMU machine model already exposes a matching DMA controller and consumer node, you will need to add an overlay describing both nodes shown in this lecture.

What error code means the DMA controller driver has not loaded yet?

-EPROBE_DEFER, which the driver core uses to automatically retry your probe function later.

Where is the meaning of the #dma-cells integers defined?

In the specific DMA controller’s own binding documentation, since the generic DMA device tree binding only fixes the cell count, not its meaning.

 

Continue The Free Linux Kernel Development Course

Master DMA, device tree, and device driver internals with EmbeddedPathashala’s free embedded systems course.

Leave a Reply

Your email address will not be published. Required fields are marked *