dma: lpc32xx: add DMA driver

Incorporate DMA driver from legacy LPCLinux NXP BSP.
The files taken from the legacy patch are:
- lpc32xx DMA driver
- lpc3250 header file DMA registers definition.

The legacy driver was updated and clean-up as part of the integration with the latest u-boot.

Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com>
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Vladimir Zapolskiy <vz@mleia.com>
diff --git a/drivers/dma/lpc32xx_dma.c b/drivers/dma/lpc32xx_dma.c
new file mode 100644
index 0000000..955adfe
--- /dev/null
+++ b/drivers/dma/lpc32xx_dma.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008 by NXP Semiconductors
+ * @Author: Kevin Wells
+ * @Descr: LPC3250 DMA controller interface support functions
+ *
+ * Copyright (c) 2015 Tyco Fire Protection Products.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+
+/* DMA controller channel register structure */
+struct dmac_chan_reg {
+	u32 src_addr;
+	u32 dest_addr;
+	u32 lli;
+	u32 control;
+	u32 config_ch;
+	u32 reserved[3];
+};
+
+/* DMA controller register structures */
+struct dma_reg {
+	u32 int_stat;
+	u32 int_tc_stat;
+	u32 int_tc_clear;
+	u32 int_err_stat;
+	u32 int_err_clear;
+	u32 raw_tc_stat;
+	u32 raw_err_stat;
+	u32 chan_enable;
+	u32 sw_burst_req;
+	u32 sw_single_req;
+	u32 sw_last_burst_req;
+	u32 sw_last_single_req;
+	u32 config;
+	u32 sync;
+	u32 reserved[50];
+	struct dmac_chan_reg dma_chan[8];
+};
+
+#define DMA_NO_OF_CHANNELS	8
+
+/* config register definitions */
+#define DMAC_CTRL_ENABLE	(1 << 0) /* For enabling the DMA controller */
+
+static u32 alloc_ch;
+
+static struct dma_reg *dma = (struct dma_reg *)DMA_BASE;
+
+int lpc32xx_dma_get_channel(void)
+{
+	int i;
+
+	if (!alloc_ch) { /* First time caller */
+		/*
+		 * DMA clock are enable by "lpc32xx_dma_init()" and should
+		 * be call by board "board_early_init_f()" function.
+		 */
+
+		/*
+		 * Make sure DMA controller and all channels are disabled.
+		 * Controller is in little-endian mode. Disable sync signals.
+		 */
+		writel(0, &dma->config);
+		writel(0, &dma->sync);
+
+		/* Clear interrupt and error statuses */
+		writel(0xFF, &dma->int_tc_clear);
+		writel(0xFF, &dma->raw_tc_stat);
+		writel(0xFF, &dma->int_err_clear);
+		writel(0xFF, &dma->raw_err_stat);
+
+		/* Enable DMA controller */
+		writel(DMAC_CTRL_ENABLE, &dma->config);
+	}
+
+	i = ffz(alloc_ch);
+
+	/* Check if all the available channels are busy */
+	if (unlikely(i == DMA_NO_OF_CHANNELS))
+		return -1;
+	alloc_ch |= BIT_MASK(i);
+	return i;
+}
+
+int lpc32xx_dma_start_xfer(unsigned int channel,
+			   const struct lpc32xx_dmac_ll *desc, u32 config)
+{
+	if (unlikely(((BIT_MASK(channel) & alloc_ch) == 0) ||
+		     (channel >= DMA_NO_OF_CHANNELS))) {
+		error("Request for xfer on unallocated channel %d", channel);
+		return -1;
+	}
+	writel(BIT_MASK(channel), &dma->int_tc_clear);
+	writel(BIT_MASK(channel), &dma->int_err_clear);
+	writel(desc->dma_src, &dma->dma_chan[channel].src_addr);
+	writel(desc->dma_dest, &dma->dma_chan[channel].dest_addr);
+	writel(desc->next_lli, &dma->dma_chan[channel].lli);
+	writel(desc->next_ctrl, &dma->dma_chan[channel].control);
+	writel(config, &dma->dma_chan[channel].config_ch);
+
+	return 0;
+}
+
+int lpc32xx_dma_wait_status(unsigned int channel)
+{
+	unsigned long start;
+	u32 reg;
+
+	/* Check if given channel is valid */
+	if (unlikely(channel >= DMA_NO_OF_CHANNELS)) {
+		error("Request for status on unallocated channel %d", channel);
+		return -1;
+	}
+
+	start = get_timer(0);
+	while (1) {
+		reg = readl(&dma->raw_tc_stat);
+		reg |= readl(dma->raw_err_stat);
+		if (reg & BIT_MASK(channel))
+			break;
+
+		if (get_timer(start) > CONFIG_SYS_HZ) {
+			error("DMA status timeout channel %d\n", channel);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	if (unlikely(readl(&dma->raw_err_stat) & BIT_MASK(channel))) {
+		setbits_le32(&dma->int_err_clear, BIT_MASK(channel));
+		setbits_le32(&dma->raw_err_stat, BIT_MASK(channel));
+		error("DMA error on channel %d\n", channel);
+		return -1;
+	}
+	setbits_le32(&dma->int_tc_clear, BIT_MASK(channel));
+	setbits_le32(&dma->raw_tc_stat, BIT_MASK(channel));
+	return 0;
+}