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

Commit 527c680f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull second set of slave-dmaengine updates from Vinod Koul:
 "Arnd's patch moves the dw_dmac to use generic DMA binding.  I agreed
  to merge this late as it will avoid the conflicts between trees.

  The second patch from Matt adding a dma_request_slave_channel_compat
  API was supposed to be picked up, but somehow never got picked up.
  Some patches dependent on this are already in -next :("

* 'next' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: dw_dmac: move to generic DMA binding
  dmaengine: add dma_request_slave_channel_compat()
parents 23caaeea f9c6a655
Loading
Loading
Loading
Loading
+36 −34
Original line number Original line Diff line number Diff line
@@ -3,59 +3,61 @@
Required properties:
Required properties:
- compatible: "snps,dma-spear1340"
- compatible: "snps,dma-spear1340"
- reg: Address range of the DMAC registers
- reg: Address range of the DMAC registers
- interrupt-parent: Should be the phandle for the interrupt controller
  that services interrupts for this device
- interrupt: Should contain the DMAC interrupt number
- interrupt: Should contain the DMAC interrupt number
- nr_channels: Number of channels supported by hardware
- dma-channels: Number of channels supported by hardware
- is_private: The device channels should be marked as private and not for by the
- dma-requests: Number of DMA request lines supported, up to 16
  general purpose DMA channel allocator. False if not passed.
- dma-masters: Number of AHB masters supported by the controller
- #dma-cells: must be <3>
- chan_allocation_order: order of allocation of channel, 0 (default): ascending,
- chan_allocation_order: order of allocation of channel, 0 (default): ascending,
  1: descending
  1: descending
- chan_priority: priority of channels. 0 (default): increase from chan 0->n, 1:
- chan_priority: priority of channels. 0 (default): increase from chan 0->n, 1:
  increase from chan n->0
  increase from chan n->0
- block_size: Maximum block size supported by the controller
- block_size: Maximum block size supported by the controller
- nr_masters: Number of AHB masters supported by the controller
- data_width: Maximum data width supported by hardware per AHB master
- data_width: Maximum data width supported by hardware per AHB master
  (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
  (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
- slave_info:

	- bus_id: name of this device channel, not just a device name since

	  devices may have more than one channel e.g. "foo_tx". For using the
Optional properties:
	  dw_generic_filter(), slave drivers must pass exactly this string as
- interrupt-parent: Should be the phandle for the interrupt controller
	  param to filter function.
  that services interrupts for this device
	- cfg_hi: Platform-specific initializer for the CFG_HI register
- is_private: The device channels should be marked as private and not for by the
	- cfg_lo: Platform-specific initializer for the CFG_LO register
  general purpose DMA channel allocator. False if not passed.
	- src_master: src master for transfers on allocated channel.
	- dst_master: dest master for transfers on allocated channel.


Example:
Example:


	dma@fc000000 {
	dmahost: dma@fc000000 {
		compatible = "snps,dma-spear1340";
		compatible = "snps,dma-spear1340";
		reg = <0xfc000000 0x1000>;
		reg = <0xfc000000 0x1000>;
		interrupt-parent = <&vic1>;
		interrupt-parent = <&vic1>;
		interrupts = <12>;
		interrupts = <12>;


		nr_channels = <8>;
		dma-channels = <8>;
		dma-requests = <16>;
		dma-masters = <2>;
		#dma-cells = <3>;
		chan_allocation_order = <1>;
		chan_allocation_order = <1>;
		chan_priority = <1>;
		chan_priority = <1>;
		block_size = <0xfff>;
		block_size = <0xfff>;
		nr_masters = <2>;
		data_width = <3 3 0 0>;
		data_width = <3 3 0 0>;

		slave_info {
			uart0-tx {
				bus_id = "uart0-tx";
				cfg_hi = <0x4000>;	/* 0x8 << 11 */
				cfg_lo = <0>;
				src_master = <0>;
				dst_master = <1>;
			};
			spi0-tx {
				bus_id = "spi0-tx";
				cfg_hi = <0x2000>;	/* 0x4 << 11 */
				cfg_lo = <0>;
				src_master = <0>;
				dst_master = <0>;
			};
	};
	};

DMA clients connected to the Designware DMA controller must use the format
described in the dma.txt file, using a four-cell specifier for each channel.
The four cells in order are:

1. A phandle pointing to the DMA controller
2. The DMA request line number
3. Source master for transfers on allocated channel
4. Destination master for transfers on allocated channel

Example:
	
	serial@e0000000 {
		compatible = "arm,pl011", "arm,primecell";
		reg = <0xe0000000 0x1000>;
		interrupts = <0 35 0x4>;
		status = "disabled";
		dmas = <&dmahost 12 0 1>,
			<&dmahost 13 0 1 0>;
		dma-names = "rx", "rx";
	};
	};
+72 −73
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
@@ -171,7 +172,13 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
	if (dwc->initialized == true)
	if (dwc->initialized == true)
		return;
		return;


	if (dws) {
	if (dws && dws->cfg_hi == ~0 && dws->cfg_lo == ~0) {
		/* autoconfigure based on request line from DT */
		if (dwc->direction == DMA_MEM_TO_DEV)
			cfghi = DWC_CFGH_DST_PER(dwc->request_line);
		else if (dwc->direction == DMA_DEV_TO_MEM)
			cfghi = DWC_CFGH_SRC_PER(dwc->request_line);
	} else if (dws) {
		/*
		/*
		 * We need controller-specific data to set up slave
		 * We need controller-specific data to set up slave
		 * transfers.
		 * transfers.
@@ -1226,49 +1233,64 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}
}


bool dw_dma_generic_filter(struct dma_chan *chan, void *param)
struct dw_dma_filter_args {
	struct dw_dma *dw;
	unsigned int req;
	unsigned int src;
	unsigned int dst;
};

static bool dw_dma_generic_filter(struct dma_chan *chan, void *param)
{
{
	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
	struct dw_dma *dw = to_dw_dma(chan->device);
	struct dw_dma *dw = to_dw_dma(chan->device);
	static struct dw_dma *last_dw;
	struct dw_dma_filter_args *fargs = param;
	static char *last_bus_id;
	struct dw_dma_slave *dws = &dwc->slave;
	int i = -1;


	/*
	/* ensure the device matches our channel */
	 * dmaengine framework calls this routine for all channels of all dma
        if (chan->device != &fargs->dw->dma)
	 * controller, until true is returned. If 'param' bus_id is not
	 * registered with a dma controller (dw), then there is no need of
	 * running below function for all channels of dw.
	 *
	 * This block of code does this by saving the parameters of last
	 * failure. If dw and param are same, i.e. trying on same dw with
	 * different channel, return false.
	 */
	if ((last_dw == dw) && (last_bus_id == param))
                return false;
                return false;
	/*
	 * Return true:
	 * - If dw_dma's platform data is not filled with slave info, then all
	 *   dma controllers are fine for transfer.
	 * - Or if param is NULL
	 */
	if (!dw->sd || !param)
		return true;


	while (++i < dw->sd_count) {
	dws->dma_dev	= dw->dma.dev;
		if (!strcmp(dw->sd[i].bus_id, param)) {
	dws->cfg_hi	= ~0;
			chan->private = &dw->sd[i];
	dws->cfg_lo	= ~0;
			last_dw = NULL;
	dws->src_master	= fargs->src;
			last_bus_id = NULL;
	dws->dst_master	= fargs->dst;

	dwc->request_line = fargs->req;

	chan->private = dws;


	return true;
	return true;
}
}
	}


	last_dw = dw;
static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec,
	last_bus_id = param;
					 struct of_dma *ofdma)
	return false;
{
	struct dw_dma *dw = ofdma->of_dma_data;
	struct dw_dma_filter_args fargs = {
		.dw = dw,
	};
	dma_cap_mask_t cap;

	if (dma_spec->args_count != 3)
		return NULL;

	fargs.req = be32_to_cpup(dma_spec->args+0);
	fargs.src = be32_to_cpup(dma_spec->args+1);
	fargs.dst = be32_to_cpup(dma_spec->args+2);

	if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
		    fargs.src >= dw->nr_masters ||
		    fargs.dst >= dw->nr_masters))
		return NULL;

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

	/* TODO: there should be a simpler way to do this */
	return dma_request_channel(cap, dw_dma_generic_filter, &fargs);
}
}
EXPORT_SYMBOL(dw_dma_generic_filter);


/* --------------------- Cyclic DMA API extensions -------------------- */
/* --------------------- Cyclic DMA API extensions -------------------- */


@@ -1554,9 +1576,8 @@ static void dw_dma_off(struct dw_dma *dw)
static struct dw_dma_platform_data *
static struct dw_dma_platform_data *
dw_dma_parse_dt(struct platform_device *pdev)
dw_dma_parse_dt(struct platform_device *pdev)
{
{
	struct device_node *sn, *cn, *np = pdev->dev.of_node;
	struct device_node *np = pdev->dev.of_node;
	struct dw_dma_platform_data *pdata;
	struct dw_dma_platform_data *pdata;
	struct dw_dma_slave *sd;
	u32 tmp, arr[4];
	u32 tmp, arr[4];


	if (!np) {
	if (!np) {
@@ -1568,7 +1589,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
	if (!pdata)
	if (!pdata)
		return NULL;
		return NULL;


	if (of_property_read_u32(np, "nr_channels", &pdata->nr_channels))
	if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
		return NULL;
		return NULL;


	if (of_property_read_bool(np, "is_private"))
	if (of_property_read_bool(np, "is_private"))
@@ -1583,7 +1604,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
	if (!of_property_read_u32(np, "block_size", &tmp))
	if (!of_property_read_u32(np, "block_size", &tmp))
		pdata->block_size = tmp;
		pdata->block_size = tmp;


	if (!of_property_read_u32(np, "nr_masters", &tmp)) {
	if (!of_property_read_u32(np, "dma-masters", &tmp)) {
		if (tmp > 4)
		if (tmp > 4)
			return NULL;
			return NULL;


@@ -1595,36 +1616,6 @@ dw_dma_parse_dt(struct platform_device *pdev)
		for (tmp = 0; tmp < pdata->nr_masters; tmp++)
		for (tmp = 0; tmp < pdata->nr_masters; tmp++)
			pdata->data_width[tmp] = arr[tmp];
			pdata->data_width[tmp] = arr[tmp];


	/* parse slave data */
	sn = of_find_node_by_name(np, "slave_info");
	if (!sn)
		return pdata;

	/* calculate number of slaves */
	tmp = of_get_child_count(sn);
	if (!tmp)
		return NULL;

	sd = devm_kzalloc(&pdev->dev, sizeof(*sd) * tmp, GFP_KERNEL);
	if (!sd)
		return NULL;

	pdata->sd = sd;
	pdata->sd_count = tmp;

	for_each_child_of_node(sn, cn) {
		sd->dma_dev = &pdev->dev;
		of_property_read_string(cn, "bus_id", &sd->bus_id);
		of_property_read_u32(cn, "cfg_hi", &sd->cfg_hi);
		of_property_read_u32(cn, "cfg_lo", &sd->cfg_lo);
		if (!of_property_read_u32(cn, "src_master", &tmp))
			sd->src_master = tmp;

		if (!of_property_read_u32(cn, "dst_master", &tmp))
			sd->dst_master = tmp;
		sd++;
	}

	return pdata;
	return pdata;
}
}
#else
#else
@@ -1705,8 +1696,6 @@ static int dw_probe(struct platform_device *pdev)
	clk_prepare_enable(dw->clk);
	clk_prepare_enable(dw->clk);


	dw->regs = regs;
	dw->regs = regs;
	dw->sd = pdata->sd;
	dw->sd_count = pdata->sd_count;


	/* get hardware configuration parameters */
	/* get hardware configuration parameters */
	if (autocfg) {
	if (autocfg) {
@@ -1837,6 +1826,14 @@ static int dw_probe(struct platform_device *pdev)


	dma_async_device_register(&dw->dma);
	dma_async_device_register(&dw->dma);


	if (pdev->dev.of_node) {
		err = of_dma_controller_register(pdev->dev.of_node,
						 dw_dma_xlate, dw);
		if (err && err != -ENODEV)
			dev_err(&pdev->dev,
				"could not register of_dma_controller\n");
	}

	return 0;
	return 0;
}
}


@@ -1845,6 +1842,8 @@ static int dw_remove(struct platform_device *pdev)
	struct dw_dma		*dw = platform_get_drvdata(pdev);
	struct dw_dma		*dw = platform_get_drvdata(pdev);
	struct dw_dma_chan	*dwc, *_dwc;
	struct dw_dma_chan	*dwc, *_dwc;


	if (pdev->dev.of_node)
		of_dma_controller_free(pdev->dev.of_node);
	dw_dma_off(dw);
	dw_dma_off(dw);
	dma_async_device_unregister(&dw->dma);
	dma_async_device_unregister(&dw->dma);


+3 −4
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/dw_dmac.h>
#include <linux/dw_dmac.h>


#define DW_DMA_MAX_NR_CHANNELS	8
#define DW_DMA_MAX_NR_CHANNELS	8
#define DW_DMA_MAX_NR_REQUESTS	16


/* flow controller */
/* flow controller */
enum dw_dma_fc {
enum dw_dma_fc {
@@ -211,6 +212,8 @@ struct dw_dma_chan {
	/* hardware configuration */
	/* hardware configuration */
	unsigned int		block_size;
	unsigned int		block_size;
	bool			nollp;
	bool			nollp;
	unsigned int		request_line;
	struct dw_dma_slave	slave;


	/* configuration passed via DMA_SLAVE_CONFIG */
	/* configuration passed via DMA_SLAVE_CONFIG */
	struct dma_slave_config dma_sconfig;
	struct dma_slave_config dma_sconfig;
@@ -239,10 +242,6 @@ struct dw_dma {
	struct tasklet_struct	tasklet;
	struct tasklet_struct	tasklet;
	struct clk		*clk;
	struct clk		*clk;


	/* slave information */
	struct dw_dma_slave	*sd;
	unsigned int		sd_count;

	u8			all_chan_mask;
	u8			all_chan_mask;


	/* hardware configuration */
	/* hardware configuration */
+16 −0
Original line number Original line Diff line number Diff line
@@ -1001,6 +1001,22 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
struct dma_chan *net_dma_find_channel(void);
struct dma_chan *net_dma_find_channel(void);
#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
#define dma_request_slave_channel_compat(mask, x, y, dev, name) \
	__dma_request_slave_channel_compat(&(mask), x, y, dev, name)

static inline struct dma_chan
*__dma_request_slave_channel_compat(dma_cap_mask_t *mask, dma_filter_fn fn,
				  void *fn_param, struct device *dev,
				  char *name)
{
	struct dma_chan *chan;

	chan = dma_request_slave_channel(dev, name);
	if (chan)
		return chan;

	return __dma_request_channel(mask, fn, fn_param);
}


/* --- Helper iov-locking functions --- */
/* --- Helper iov-locking functions --- */


+0 −5
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
 */
 */
struct dw_dma_slave {
struct dw_dma_slave {
	struct device		*dma_dev;
	struct device		*dma_dev;
	const char		*bus_id;
	u32			cfg_hi;
	u32			cfg_hi;
	u32			cfg_lo;
	u32			cfg_lo;
	u8			src_master;
	u8			src_master;
@@ -60,9 +59,6 @@ struct dw_dma_platform_data {
	unsigned short	block_size;
	unsigned short	block_size;
	unsigned char	nr_masters;
	unsigned char	nr_masters;
	unsigned char	data_width[4];
	unsigned char	data_width[4];

	struct dw_dma_slave *sd;
	unsigned int sd_count;
};
};


/* bursts size */
/* bursts size */
@@ -114,6 +110,5 @@ void dw_dma_cyclic_stop(struct dma_chan *chan);
dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan);
dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan);


dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan);
dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan);
bool dw_dma_generic_filter(struct dma_chan *chan, void *param);


#endif /* DW_DMAC_H */
#endif /* DW_DMAC_H */