Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa332de5 authored by Lee Jones's avatar Lee Jones Committed by Linus Walleij
Browse files

dmaengine: ste_dma40: Supply full Device Tree parsing support



Using the new DMA DT bindings and API, we can register the DMA40 driver
as Device Tree capable. Now, when a client attempts to allocate a
channel using the DMA DT bindings via its own node, we are able to parse
the request and allocate a channel in the correct manner.

Cc: Dan Williams <djbw@fb.com>
Cc: Per Forlin <per.forlin@stericsson.com>
Cc: Rabin Vincent <rabin@rab.in>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
Acked-by: default avatarVinod Koul <vinod.koul@intel.com>
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 1814a170
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
* DMA40 DMA Controller

Required properties:
- compatible: "stericsson,dma40"
- reg: Address range of the DMAC registers
- reg-names: Names of the above areas to use during resource look-up
- interrupt: Should contain the DMAC interrupt number
- #dma-cells: must be <3>

Optional properties:
- dma-channels: Number of channels supported by hardware - if not present
		the driver will attempt to obtain the information from H/W

Example:

	dma: dma-controller@801C0000 {
		compatible = "stericsson,db8500-dma40", "stericsson,dma40";
		reg = <0x801C0000 0x1000  0x40010000 0x800>;
		reg-names = "base", "lcpa";
		interrupt-parent = <&intc>;
		interrupts = <0 25 0x4>;

		#dma-cells = <2>;
		dma-channels = <8>;
	};

Clients
Required properties:
- dmas: Comma separated list of dma channel requests
- dma-names: Names of the aforementioned requested channels

Each dmas request consists of 4 cells:
  1. A phandle pointing to the DMA controller
  2. Device Type
  3. The DMA request line number (only when 'use fixed channel' is set)
  4. A 32bit mask specifying; mode, direction and endianess [NB: This list will grow]
        0x00000001: Mode:
                Logical channel when unset
                Physical channel when set
        0x00000002: Direction:
                Memory to Device when unset
                Device to Memory when set
        0x00000004: Endianess:
                Little endian when unset
                Big endian when set
        0x00000008: Use fixed channel:
                Use automatic channel selection when unset
                Use DMA request line number when set

Example:

	uart@80120000 {
		compatible = "arm,pl011", "arm,primecell";
		reg = <0x80120000 0x1000>;
		interrupts = <0 11 0x4>;

		dmas = <&dma 13 0 0x2>, /* Logical - DevToMem */
		       <&dma 13 0 0x0>; /* Logical - MemToDev */
		dma-names = "rx", "rx";

		status = "disabled";
	};
+52 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/amba/bus.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_data/dma-ste-dma40.h>
@@ -2422,6 +2423,50 @@ static void d40_set_prio_realtime(struct d40_chan *d40c)
		__d40_set_prio_rt(d40c, d40c->dma_cfg.dev_type, false);
}

#define D40_DT_FLAGS_MODE(flags)       ((flags >> 0) & 0x1)
#define D40_DT_FLAGS_DIR(flags)        ((flags >> 1) & 0x1)
#define D40_DT_FLAGS_BIG_ENDIAN(flags) ((flags >> 2) & 0x1)
#define D40_DT_FLAGS_FIXED_CHAN(flags) ((flags >> 3) & 0x1)

static struct dma_chan *d40_xlate(struct of_phandle_args *dma_spec,
				  struct of_dma *ofdma)
{
	struct stedma40_chan_cfg cfg;
	dma_cap_mask_t cap;
	u32 flags;

	memset(&cfg, 0, sizeof(struct stedma40_chan_cfg));

	dma_cap_zero(cap);
	dma_cap_set(DMA_SLAVE, cap);

	cfg.dev_type = dma_spec->args[0];
	flags = dma_spec->args[2];

	switch (D40_DT_FLAGS_MODE(flags)) {
	case 0: cfg.mode = STEDMA40_MODE_LOGICAL; break;
	case 1: cfg.mode = STEDMA40_MODE_PHYSICAL; break;
	}

	switch (D40_DT_FLAGS_DIR(flags)) {
	case 0:
		cfg.dir = STEDMA40_MEM_TO_PERIPH;
		cfg.dst_info.big_endian = D40_DT_FLAGS_BIG_ENDIAN(flags);
		break;
	case 1:
		cfg.dir = STEDMA40_PERIPH_TO_MEM;
		cfg.src_info.big_endian = D40_DT_FLAGS_BIG_ENDIAN(flags);
		break;
	}

	if (D40_DT_FLAGS_FIXED_CHAN(flags)) {
		cfg.phy_channel = dma_spec->args[1];
		cfg.use_fixed_channel = true;
	}

	return dma_request_channel(cap, stedma40_filter, &cfg);
}

/* DMA ENGINE functions */
static int d40_alloc_chan_resources(struct dma_chan *chan)
{
@@ -3638,6 +3683,13 @@ static int __init d40_probe(struct platform_device *pdev)

	d40_hw_init(base);

	if (np) {
		err = of_dma_controller_register(np, d40_xlate, NULL);
		if (err && err != -ENODEV)
			dev_err(&pdev->dev,
				"could not register of_dma_controller\n");
	}

	dev_info(base->dev, "initialized\n");
	return 0;