davinci: build list of unused EDMA events dynamically

Currently, the edma_noevent list is passed from platform data.
But on some architectures, there will be many EDMA channels
which will not be used at all. This patch scans all the
platform devices and then builds a list of events which are
not being used. The unused event list will be used to allocate
EDMA channels in case of EDMA_CHANNEL_ANY usage instead of the
edma_noevent being used earlier for this purpose.

This patch is based on David Brownells's suggestion at
http://article.gmane.org/gmane.linux.davinci/15176.

Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index 89a3dcc..15dd886 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -226,11 +226,11 @@
 	 */
 	DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
 
-	/* The edma_noevent bit for each channel is clear unless
-	 * it doesn't trigger DMA events on this platform.  It uses a
-	 * bit of SOC-specific initialization code.
+	/* The edma_unused bit for each channel is clear unless
+	 * it is not being used on this platform. It uses a bit
+	 * of SOC-specific initialization code.
 	 */
-	DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
+	DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH);
 
 	unsigned	irq_res_start;
 	unsigned	irq_res_end;
@@ -556,8 +556,27 @@
 	return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);
 }
 
+static int prepare_unused_channel_list(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int i, ctlr;
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
+				(int)pdev->resource[i].start >= 0) {
+			ctlr = EDMA_CTLR(pdev->resource[i].start);
+			clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
+					edma_info[ctlr]->edma_unused);
+		}
+	}
+
+	return 0;
+}
+
 /*-----------------------------------------------------------------------*/
 
+static bool unused_chan_list_done;
+
 /* Resource alloc/free:  dma channels, parameter RAM slots */
 
 /**
@@ -596,6 +615,21 @@
 		enum dma_event_q eventq_no)
 {
 	unsigned i, done = 0, ctlr = 0;
+	int ret = 0;
+
+	if (!unused_chan_list_done) {
+		/*
+		 * Scan all the platform devices to find out the EDMA channels
+		 * used and clear them in the unused list, making the rest
+		 * available for ARM usage.
+		 */
+		ret = bus_for_each_dev(&platform_bus_type, NULL, NULL,
+				prepare_unused_channel_list);
+		if (ret < 0)
+			return ret;
+
+		unused_chan_list_done = true;
+	}
 
 	if (channel >= 0) {
 		ctlr = EDMA_CTLR(channel);
@@ -607,7 +641,7 @@
 			channel = 0;
 			for (;;) {
 				channel = find_next_bit(edma_info[i]->
-						edma_noevent,
+						edma_unused,
 						edma_info[i]->num_channels,
 						channel);
 				if (channel == edma_info[i]->num_channels)
@@ -1222,7 +1256,7 @@
 		unsigned int mask = (1 << (channel & 0x1f));
 
 		/* EDMA channels without event association */
-		if (test_bit(channel, edma_info[ctlr]->edma_noevent)) {
+		if (test_bit(channel, edma_info[ctlr]->edma_unused)) {
 			pr_debug("EDMA: ESR%d %08x\n", j,
 				edma_shadow0_read_array(ctlr, SH_ESR, j));
 			edma_shadow0_write_array(ctlr, SH_ESR, j, mask);
@@ -1347,7 +1381,6 @@
 	const s8		(*queue_tc_mapping)[2];
 	int			i, j, found = 0;
 	int			status = -1;
-	const s8		*noevent;
 	int			irq[EDMA_MAX_CC] = {0, 0};
 	int			err_irq[EDMA_MAX_CC] = {0, 0};
 	struct resource		*r[EDMA_MAX_CC] = {NULL};
@@ -1410,11 +1443,9 @@
 			memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i),
 					&dummy_paramset, PARM_SIZE);
 
-		noevent = info[j].noevent;
-		if (noevent) {
-			while (*noevent != -1)
-				set_bit(*noevent++, edma_info[j]->edma_noevent);
-		}
+		/* Mark all channels as unused */
+		memset(edma_info[j]->edma_unused, 0xff,
+			sizeof(edma_info[j]->edma_unused));
 
 		sprintf(irq_name, "edma%d", j);
 		irq[j] = platform_get_irq_byname(pdev, irq_name);