Devicetree
 help / color / mirror / Atom feed
* [PATCH V3 3/4] mailbox: xgene: base driver for APM X-Gene SoC QMTM
From: Ravi Patel @ 2014-02-15  2:22 UTC (permalink / raw)
  To: arnd, gregkh, davem
  Cc: netdev, linux-kernel, devicetree, linux-arm-kernel, jcm, patches,
	Ravi Patel, Keyur Chudgar
In-Reply-To: <1392430922-24643-1-git-send-email-rapatel@apm.com>

This patch adds APM X-Gene SoC Queue Manager/Traffic Manager base driver.
QMTM is requried by Ethernet, PktDMA (XOR Engine) and Security subsystems.

Signed-off-by: Ravi Patel <rapatel@apm.com>
Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
---
 MAINTAINERS                              |    9 +
 drivers/mailbox/Kconfig                  |    2 +
 drivers/mailbox/Makefile                 |    1 +
 drivers/mailbox/xgene/Kconfig            |    9 +
 drivers/mailbox/xgene/Makefile           |    7 +
 drivers/mailbox/xgene/xgene_qmtm_main.c  |  516 ++++++++++++++++++++++++++++++
 drivers/mailbox/xgene/xgene_qmtm_main.h  |  112 +++++++
 drivers/mailbox/xgene/xgene_qmtm_storm.c |  358 +++++++++++++++++++++
 include/linux/platform_data/xgene_qmtm.h |  300 +++++++++++++++++
 9 files changed, 1314 insertions(+)
 create mode 100644 drivers/mailbox/xgene/Kconfig
 create mode 100644 drivers/mailbox/xgene/Makefile
 create mode 100644 drivers/mailbox/xgene/xgene_qmtm_main.c
 create mode 100644 drivers/mailbox/xgene/xgene_qmtm_main.h
 create mode 100644 drivers/mailbox/xgene/xgene_qmtm_storm.c
 create mode 100644 include/linux/platform_data/xgene_qmtm.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 2507f38..3e09f39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -678,6 +678,15 @@ S:	Maintained
 F:	drivers/net/appletalk/
 F:	net/appletalk/
 
+APPLIEDMICRO (APM) X-GENE SOC QUEUE MANAGER/TRAFFIC MANAGER (QMTM) DRIVER
+M:	Ravi Patel <rapatel@apm.com>
+M:	Keyur Chudgar <kchudgar@apm.com>
+S:	Maintained
+F:	drivers/mailbox/xgene/
+F:	include/linux/platform_data/xgene_qmtm.h
+F:	Documentation/devicetree/bindings/mailbox/apm-xgene-qmtm.txt
+F:	Documentation/mailbox/apm-xgene-qmtm
+
 APTINA CAMERA SENSOR PLL
 M:	Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
 L:	linux-media@vger.kernel.org
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c8b5c13..52653d4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -50,4 +50,6 @@ config OMAP_MBOX_KFIFO_SIZE
 	  Specify the default size of mailbox's kfifo buffers (bytes).
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
+
+source "drivers/mailbox/xgene/Kconfig"
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index e0facb3..6faee7e 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_OMAP1_MBOX)	+= mailbox_omap1.o
 mailbox_omap1-objs		:= mailbox-omap1.o
 obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox_omap2.o
 mailbox_omap2-objs		:= mailbox-omap2.o
+obj-$(CONFIG_XGENE_MBOX)	+= xgene/
diff --git a/drivers/mailbox/xgene/Kconfig b/drivers/mailbox/xgene/Kconfig
new file mode 100644
index 0000000..0843303
--- /dev/null
+++ b/drivers/mailbox/xgene/Kconfig
@@ -0,0 +1,9 @@
+config XGENE_MBOX
+	tristate "APM X-Gene Queue Manager/Traffic Manager Mailbox"
+	depends on ARM64 || COMPILE_TEST
+	default y
+	help
+	  This option enables APM X-Gene Queue Manager Traffic Manager (QMTM)
+	  mailbox support.
+	  QMTM is required for Ethernet, PktDMA (XOR Engine) and Security
+	  Engine.
diff --git a/drivers/mailbox/xgene/Makefile b/drivers/mailbox/xgene/Makefile
new file mode 100644
index 0000000..574e1b8
--- /dev/null
+++ b/drivers/mailbox/xgene/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for APM X-GENE Queue Manager Traffic Manager mailbox
+#
+
+obj-$(CONFIG_XGENE_MBOX) += xgene-qmtm.o
+
+xgene-qmtm-objs := xgene_qmtm_main.o xgene_qmtm_storm.o
diff --git a/drivers/mailbox/xgene/xgene_qmtm_main.c b/drivers/mailbox/xgene/xgene_qmtm_main.c
new file mode 100644
index 0000000..bc50cd9
--- /dev/null
+++ b/drivers/mailbox/xgene/xgene_qmtm_main.c
@@ -0,0 +1,516 @@
+/*
+ * AppliedMicro X-Gene SoC Queue Manager/Traffic Manager driver
+ *
+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
+ * Author: Ravi Patel <rapatel@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include "xgene_qmtm_main.h"
+
+#define XGENE_QMTM_DRIVER_VER	"1.0"
+#define XGENE_QMTM_DRIVER_NAME	"xgene-qmtm"
+#define XGENE_QMTM_DRIVER_DESC	"APM X-Gene QMTM driver"
+
+/* CSR Address Macros */
+#define CSR_QM_CONFIG_ADDR	0x00000004
+#define  QM_ENABLE_WR(src)	(((u32)(src)<<31) & 0x80000000)
+
+#define CSR_PBM_ADDR		0x00000008
+#define  OVERWRITE_WR(src)	(((u32)(src)<<31) & 0x80000000)
+#define  SLVID_PBN_WR(src)	(((u32)(src)) & 0x000003ff)
+
+#define CSR_PBM_BUF_WR_ADDR	0x0000000c
+#define CSR_PBM_BUF_RD_ADDR	0x00000010
+#define  PB_SIZE_WR(src)	(((u32)(src)<<31) & 0x80000000)
+#define  PREFETCH_BUF_EN_SET(dst, src) \
+	(((dst) & ~0x00200000) | (((u32)(src)<<21) & 0x00200000))
+#define  IS_FREE_POOL_SET(dst, src) \
+	(((dst) & ~0x00100000) | (((u32)(src)<<20) & 0x00100000))
+#define  TLVQ_SET(dst, src) \
+	(((dst) & ~0x00080000) | (((u32)(src)<<19) & 0x00080000))
+#define  CORRESPONDING_QNUM_SET(dst, src) \
+	(((dst) & ~0x0007fe00) | (((u32)(src)<<9) & 0x0007fe00))
+
+#define CSR_THRESHOLD0_SET1_ADDR	0x00000030
+#define CSR_THRESHOLD1_SET1_ADDR	0x00000034
+#define CSR_HYSTERESIS_ADDR		0x00000068
+#define CSR_QM_MBOX_NE_INT_MODE_ADDR	0x0000017c
+#define CSR_QMLITE_PBN_MAP_0_ADDR	0x00000228
+
+#define CSR_RECOMB_CTRL_0_ADDR		0x00000230
+#define  RECOMB_EN0_SET(dst, src) \
+	(((dst) & ~0x00000001) | (((u32)(src)) & 0x00000001))
+
+/* QMTM Diag CSR */
+#define QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET	0xd000
+#define QM_CFG_MEM_RAM_SHUTDOWN_ADDR		0x00000070
+#define QM_CFG_MEM_RAM_SHUTDOWN_DEFAULT		0xffffffff
+
+static struct of_device_id xgene_qmtm_match[] = {
+	{
+		.compatible = "apm,xgene-qmtm",
+		.data = &storm_qmtm_ops,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, xgene_qmtm_match);
+
+void xgene_qmtm_wr32(struct xgene_qmtm *qmtm, u32 offset, u32 data)
+{
+	writel(data, qmtm->csr_vaddr + offset);
+}
+
+void xgene_qmtm_rd32(struct xgene_qmtm *qmtm, u32 offset, u32 *data)
+{
+	*data = readl(qmtm->csr_vaddr + offset);
+}
+
+static void xgene_qmtm_pbm_get(struct xgene_mbox *mbox)
+{
+	u16 is_fp = QMTM_QTYPE_FP(mbox);
+	u16 is_vq = QMTM_QTYPE_VQ(mbox);
+	u32 val = 0;
+	u32 pbm = SLVID_PBN_WR(mbox->pbm) | OVERWRITE_WR(1);
+
+	if (mbox->qmtm->qmtm_ip == QMTM0 || mbox->qmtm->qmtm_ip == QMTM2)
+		val |= PB_SIZE_WR(1);
+
+	val = CORRESPONDING_QNUM_SET(val, mbox->qid);
+	val = IS_FREE_POOL_SET(val, is_fp);
+	val = TLVQ_SET(val, is_vq);
+	val = PREFETCH_BUF_EN_SET(val, 1);
+	xgene_qmtm_wr32(mbox->qmtm, CSR_PBM_ADDR, pbm);
+	xgene_qmtm_wr32(mbox->qmtm, CSR_PBM_BUF_WR_ADDR, val);
+}
+
+static void xgene_qmtm_pbm_put(struct xgene_mbox *mbox)
+{
+	u32 pbm = SLVID_PBN_WR(mbox->pbm) | OVERWRITE_WR(1);
+	xgene_qmtm_wr32(mbox->qmtm, CSR_PBM_ADDR, pbm);
+	xgene_qmtm_wr32(mbox->qmtm, CSR_PBM_BUF_WR_ADDR, 0);
+}
+
+/**
+ * xgene_mbox_get - Create and configure a queue
+ * @dev: device that requests this queue
+ * @s: the queue name string as given in the dt data
+ *
+ * This API will be called by APM X-Gene SoC Ethernet, PktDMA (XOR Engine),
+ * and Security Engine subsystems to create and configure a queue.
+ *
+ * Returns the mbox associated with the given phandle value,
+ * after getting a refcount to it, -ENODEV if there is no such queue,
+ * -ENOMEM if out of memory or -EINVAL for other error conditions.
+ * The caller is responsible for calling xgene_mbox_put() to release
+ * that count.
+ */
+struct xgene_mbox *xgene_mbox_get(struct device *dev, const char *s)
+{
+	struct module *module = THIS_MODULE;
+	struct xgene_mbox *mbox = ERR_PTR(-EINVAL);
+	struct xgene_qmtm *qmtm;
+	int ret;
+	struct of_phandle_args args;
+	u64 qfabric_paddr;
+	u32 qsize = 0;
+	u16 qid = 0;
+	u8 cfgqsize;
+
+	if (!dev->of_node) {
+		dev_err(dev, "Invalid device tree\n");
+		goto _err_mbox_get;
+	}
+
+	ret = of_property_match_string(dev->of_node, "mailbox-names", s);
+	if (ret < 0) {
+		mbox = ERR_PTR(-ENODEV);
+		goto _err_mbox_get;
+	}
+
+	memset(&args, 0, sizeof(args));
+	ret = of_parse_phandle_with_args(dev->of_node, "mailboxes",
+			"#mailbox-cells", ret, &args);
+	if (ret || !args.np) {
+		dev_err(dev, "failed to get mailbox in %s node\n",
+				dev->of_node->full_name);
+		goto _err_mbox_get;
+	}
+
+	if (!try_module_get(module))
+		goto _err_mbox_get;
+
+	qmtm = platform_get_drvdata(of_find_device_by_node(args.np));
+	if (qmtm == NULL) {
+		dev_err(dev, "failed to get QMTM for %s node\n",
+				dev->of_node->full_name);
+		goto _module_put;
+	}
+
+	qfabric_paddr = ((u64)args.args[0] << 32) | args.args[1];
+	if (qfabric_paddr > (qmtm->fabric_paddr |
+				((u64)(QMTM_MAX_QUEUES - 1) << 6)) ||
+			qfabric_paddr < qmtm->fabric_paddr) {
+		dev_err(dev, "Invalid qfabric address for %s node\n",
+				dev->of_node->full_name);
+		goto _module_put;
+	}
+	qid = (qfabric_paddr - qmtm->fabric_paddr) >> 6;
+
+	qsize = args.args[2];
+	switch (qsize) {
+	case 0x00200:
+		cfgqsize = QSIZE_512B;
+		break;
+	case 0x00800:
+		cfgqsize = QSIZE_2KB;
+		break;
+	case 0x04000:
+		cfgqsize = QSIZE_16KB;
+		break;
+	case 0x10000:
+		cfgqsize = QSIZE_64KB;
+		break;
+	case 0x80000:
+		cfgqsize = QSIZE_512KB;
+		break;
+	default:
+		dev_err(dev, "Unsupported queue size %d\n", qsize);
+		goto _module_put;
+	}
+
+	mbox = kzalloc(sizeof(struct xgene_mbox), GFP_KERNEL);
+	if (mbox == NULL) {
+		dev_err(dev, "Unable to allocate mbox\n");
+		goto _module_put;
+	}
+
+	mbox->qaddr = dma_zalloc_coherent(&qmtm->pdev->dev, qsize,
+		&mbox->dma, GFP_KERNEL);
+	if (mbox->qaddr == NULL) {
+		dev_err(dev, "Unable to allocate qaddr\n");
+		kfree(mbox);
+		mbox = NULL;
+		goto _module_put;
+	}
+	mbox->qsize = qsize;
+	mbox->pbm = args.args[3];
+	mbox->qid = qid;
+	mbox->slots = cfgqsize;
+	mbox->qfabric = qmtm->fabric_vaddr + (qid << 6);
+	mbox->level = mbox->qfabric + 0x2C;
+	mbox->qmtm = qmtm;
+	qmtm->ops.set_qstate(mbox);
+	xgene_qmtm_pbm_get(mbox);
+	mbox->slots = QMTM_QTYPE_FP(mbox) ? qsize / 16 : qsize / 32;
+	mbox->qstate[6] = qmtm->qmtm_ip;
+
+	if (QMTM_SLAVE_ID(mbox) == QMTM_SLAVE_ID_CPU &&
+			!QMTM_QTYPE_FP(mbox) &&
+			!QMTM_QTYPE_VQ(mbox)) {
+		u32 s, data;
+		for (s = 0; s < mbox->slots; s++) {
+			u32 *slot = (u32 *)&mbox->msg32[s];
+			slot[EMPTY_SLOT_INDEX] = EMPTY_SLOT;
+		}
+		xgene_qmtm_rd32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, &data);
+		data |= (u32) (1 << (31 - QMTM_PBN(mbox)));
+		xgene_qmtm_wr32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, data);
+		mbox->irq = qmtm->dequeue_irq[QMTM_PBN(mbox)];
+	}
+
+	qmtm->mbox[qid] = mbox;
+	return mbox;
+
+_module_put:
+	module_put(module);
+
+_err_mbox_get:
+	return mbox;
+}
+EXPORT_SYMBOL_GPL(xgene_mbox_get);
+
+/**
+ * xgene_mbox_put - Unconfigure and delete a queue
+ * @mbox: the mbox returned by xgene_mbox_get()
+ *
+ * This API will be called by APM X-Gene SoC Ethernet, PktDMA (XOR Engine),
+ * and Security Engine subsystems to unconfigure and delete a queue.
+ *
+ * Releases a refcount the caller received from xgene_mbox_get().
+ */
+void xgene_mbox_put(struct xgene_mbox *mbox)
+{
+	struct xgene_qmtm *qmtm = mbox->qmtm;
+	struct module *module = THIS_MODULE;
+
+	if (QMTM_SLAVE_ID(mbox) == QMTM_SLAVE_ID_CPU &&
+			!QMTM_QTYPE_FP(mbox) &&
+			!QMTM_QTYPE_VQ(mbox)) {
+		u32 data;
+		xgene_qmtm_rd32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, &data);
+		data &= ~(u32) (1 << (31 - QMTM_PBN(mbox)));
+		xgene_qmtm_wr32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, data);
+	}
+
+	xgene_qmtm_pbm_put(mbox);
+	qmtm->ops.clr_qstate(mbox);
+	dma_free_coherent(&qmtm->pdev->dev, mbox->qsize,
+		mbox->qaddr, mbox->dma);
+	qmtm->mbox[mbox->qid] = NULL;
+	kfree(mbox);
+	module_put(module);
+}
+EXPORT_SYMBOL_GPL(xgene_mbox_put);
+
+/**
+ * xgene_mbox_level - Read number of message in queue
+ * @mbox: read number of message for mbox
+ *
+ * This API will be called by APM X-Gene SoC Ethernet, PktDMA (XOR Engine),
+ * and Security Engine subsystems to read number of message for mbox.
+ *
+ * Returns number of messages in mbox
+ */
+u32 xgene_mbox_level(struct xgene_mbox *mbox)
+{
+	return mbox->qmtm->ops.read_level(mbox->qfabric);
+}
+EXPORT_SYMBOL_GPL(xgene_mbox_level);
+
+static int xgene_qmtm_enable(struct xgene_qmtm *qmtm)
+{
+	struct xgene_mbox mbox;
+	struct device *dev = &qmtm->pdev->dev;
+	int rc, mwait = 0, inum = 1;
+	u32 val;
+	u32 qid;
+
+	qmtm->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(qmtm->clk)) {
+		dev_err(dev, "can't get clock\n");
+		return PTR_ERR(qmtm->clk);
+	}
+
+	rc = clk_prepare_enable(qmtm->clk);
+	if (rc < 0) {
+		dev_err(dev, "clock prepare enable failed\n");
+		return rc;
+	}
+
+	xgene_qmtm_wr32(qmtm, QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET +
+			QM_CFG_MEM_RAM_SHUTDOWN_ADDR, 0);
+	do {
+		/* Wait for Memory to come out of shutdown */
+		usleep_range(1000, 2000);
+		xgene_qmtm_rd32(qmtm, QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET +
+				QM_CFG_MEM_RAM_SHUTDOWN_ADDR, &val);
+
+		if (mwait++ >= 1000) {
+			rc = -EIO;
+			dev_err(dev, "RAM not out of shutdown %d\n", rc);
+			clk_disable_unprepare(qmtm->clk);
+			return rc;
+		}
+	} while (val == QM_CFG_MEM_RAM_SHUTDOWN_DEFAULT);
+
+	rc = qmtm->ops.init(qmtm);
+	if (rc < 0) {
+		dev_err(dev, "not supported on your system\n");
+		return rc;
+	}
+
+	for (inum = qmtm->irq_start; inum < (qmtm->irq_start +
+				qmtm->irq_count); inum++) {
+		int irq = platform_get_irq(qmtm->pdev,
+			inum - qmtm->irq_start + 1);
+		if (irq < 0) {
+			dev_err(dev, "Failed to map QMTM%d PBN %d IRQ\n",
+				qmtm->qmtm_ip, inum);
+			continue;
+		}
+		qmtm->dequeue_irq[inum] = irq;
+	}
+
+	switch (qmtm->qmtm_ip) {
+	case QMTM0:
+	case QMTM2:
+		xgene_qmtm_rd32(qmtm, CSR_RECOMB_CTRL_0_ADDR, &val);
+		val = RECOMB_EN0_SET(val, 1);
+		xgene_qmtm_wr32(qmtm, CSR_RECOMB_CTRL_0_ADDR, val);
+		break;
+	case QMTM3:
+		xgene_qmtm_wr32(qmtm, CSR_QMLITE_PBN_MAP_0_ADDR, 0x00000000);
+	}
+
+	/* program threshold set 1 and all hysteresis */
+	xgene_qmtm_wr32(qmtm, CSR_THRESHOLD0_SET1_ADDR, 100);
+	xgene_qmtm_wr32(qmtm, CSR_THRESHOLD1_SET1_ADDR, 200);
+	xgene_qmtm_wr32(qmtm, CSR_HYSTERESIS_ADDR, 0xFFFFFFFF);
+
+	/* Enable QPcore */
+	xgene_qmtm_wr32(qmtm, CSR_QM_CONFIG_ADDR, QM_ENABLE_WR(1));
+
+	/* Clear all HW queue state in case they were not de-activated */
+	memset(&mbox, 0, sizeof(mbox));
+	mbox.qmtm = qmtm;
+
+	for (qid = 0; qid < QMTM_MAX_QUEUES; qid++) {
+		mbox.qid = qid;
+		qmtm->ops.clr_qstate(&mbox);
+	}
+
+	return rc;
+}
+
+static int xgene_qmtm_disable(struct xgene_qmtm *qmtm)
+{
+	u32 qid;
+
+	for (qid = 0; qid < QMTM_MAX_QUEUES; qid++) {
+		if (qmtm->mbox[qid]) {
+			dev_err(&qmtm->pdev->dev,
+				"QMTM %d Queue ID %d Resource in use\n",
+				qmtm->qmtm_ip, qid);
+			return -EAGAIN;
+		}
+	}
+
+	/* Disable QPcore */
+	xgene_qmtm_wr32(qmtm, CSR_QM_CONFIG_ADDR, QM_ENABLE_WR(0));
+	clk_disable_unprepare(qmtm->clk);
+
+	return 0;
+}
+
+static struct xgene_qmtm *xgene_alloc_qmtm(struct platform_device *pdev)
+{
+	struct xgene_qmtm *qmtm;
+
+	qmtm = devm_kzalloc(&pdev->dev, sizeof(struct xgene_qmtm), GFP_KERNEL);
+	if (qmtm == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate QMTM context\n");
+		return NULL;
+	}
+
+	qmtm->pdev = pdev;
+	platform_set_drvdata(pdev, qmtm);
+	qmtm->mbox = devm_kzalloc(&pdev->dev,
+		QMTM_MAX_QUEUES * (sizeof(struct xgene_qmtm_info *)),
+		GFP_KERNEL);
+	if (qmtm->mbox == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate QMTM Queue context\n");
+		return NULL;
+	}
+
+	return qmtm;
+}
+
+static int xgene_get_qmtm(struct xgene_qmtm *qmtm)
+{
+	struct platform_device *pdev = qmtm->pdev;
+	const struct of_device_id *match;
+	struct resource *res;
+
+	/* Get Match Table */
+	match = of_match_device(xgene_qmtm_match, &pdev->dev);
+	if (!match)
+		return -EINVAL;
+	memcpy(&qmtm->ops, match->data, sizeof(struct xgene_qmtm_ops));
+
+	/* Retrieve QM CSR register address and size */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get QMTM CSR region\n");
+		return -ENODEV;
+	}
+
+	qmtm->csr_vaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(qmtm->csr_vaddr)) {
+		dev_err(&pdev->dev, "Invalid QMTM CSR region\n");
+		return PTR_ERR(qmtm->csr_vaddr);
+	}
+
+	/* Retrieve Primary Fabric address and size */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get QMTM Fabric region\n");
+		return -ENODEV;
+	}
+
+	qmtm->fabric_vaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(qmtm->fabric_vaddr)) {
+		dev_err(&pdev->dev, "Invalid QMTM Fabric region\n");
+		return PTR_ERR(qmtm->fabric_vaddr);
+	}
+	qmtm->fabric_paddr = res->start;
+
+	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
+		return dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+
+	return 0;
+}
+
+static int xgene_qmtm_probe(struct platform_device *pdev)
+{
+	struct xgene_qmtm *qmtm;
+	int rc;
+
+	qmtm = xgene_alloc_qmtm(pdev);
+	if (qmtm == NULL)
+		return -ENOMEM;
+
+	rc = xgene_get_qmtm(qmtm);
+	if (rc)
+		return rc;
+
+	return xgene_qmtm_enable(qmtm);
+}
+
+static int xgene_qmtm_remove(struct platform_device *pdev)
+{
+	struct xgene_qmtm *qmtm = platform_get_drvdata(pdev);
+	return xgene_qmtm_disable(qmtm);
+}
+
+static struct platform_driver xgene_qmtm_driver = {
+	.driver = {
+		   .name = XGENE_QMTM_DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = xgene_qmtm_match,
+		   },
+	.probe = xgene_qmtm_probe,
+	.remove = xgene_qmtm_remove,
+};
+
+static int __init xgene_qmtm_init(void)
+{
+	return platform_driver_register(&xgene_qmtm_driver);
+}
+subsys_initcall(xgene_qmtm_init);
+
+static void __exit xgene_qmtm_exit(void)
+{
+	platform_driver_unregister(&xgene_qmtm_driver);
+}
+module_exit(xgene_qmtm_exit);
+
+MODULE_VERSION(XGENE_QMTM_DRIVER_VER);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ravi Patel <rapatel@apm.com>");
+MODULE_DESCRIPTION(XGENE_QMTM_DRIVER_DESC);
diff --git a/drivers/mailbox/xgene/xgene_qmtm_main.h b/drivers/mailbox/xgene/xgene_qmtm_main.h
new file mode 100644
index 0000000..1a9de03
--- /dev/null
+++ b/drivers/mailbox/xgene/xgene_qmtm_main.h
@@ -0,0 +1,112 @@
+/*
+ * AppliedMicro X-Gene SoC Queue Manager/Traffic Manager driver
+ *
+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
+ * Author: Ravi Patel <rapatel@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __XGENE_QMTM_MAIN_H__
+#define __XGENE_QMTM_MAIN_H__
+
+#include <linux/of_platform.h>
+#include <linux/platform_data/xgene_qmtm.h>
+
+/* QMTM IP Blocks */
+enum xgene_qmtm_ip {
+	QMTM0,
+	QMTM1,
+	QMTM2,
+	QMTM3,
+};
+
+#define QMTM_MAX_QUEUES	1024
+#define QMTM_MAX_PBN	32
+
+/* QMTM Queue types */
+enum xgene_qmtm_qtype {
+	QTYPE_DISABLED,		/* Queue Type is un-configured or disabled */
+	QTYPE_PQ,		/* Queue Type is Physical Work Queue */
+	QTYPE_FP,		/* Queue Type is Free Pool Queue */
+	QTYPE_VQ,		/* Queue Type is Virtual Queue */
+};
+
+/* QMTM Queue possible sizes */
+enum xgene_qmtm_qsize {
+	QSIZE_512B,
+	QSIZE_2KB,
+	QSIZE_16KB,
+	QSIZE_64KB,
+	QSIZE_512KB,
+	QSIZE_MAX,
+};
+
+struct xgene_qmtm_ops {
+	int (*init)(struct xgene_qmtm *qmtm);
+	void (*set_qstate)(struct xgene_mbox *mbox);
+	void (*clr_qstate)(struct xgene_mbox *mbox);
+	u32 (*read_level)(void *qfabric);
+};
+
+struct xgene_qmtm {
+	struct xgene_qmtm_ops ops;
+	void *csr_vaddr;
+	void *fabric_vaddr;
+	u64 fabric_paddr;
+	u16 qmtm_ip;		/* qmtm_ip, see xgene_qmtm_ip */
+	u16 irq_start;
+	u16 irq_count;
+	u16 error_irq;
+	u16 dequeue_irq[QMTM_MAX_PBN];
+	char error_irq_s[16];
+	char error_queue_irq_s[16];
+	struct xgene_mbox *(*mbox);
+	struct xgene_mbox *error_mbox;
+	struct clk *clk;
+	struct platform_device *pdev;
+};
+
+/* QMTM Slave IDs */
+enum xgene_qmtm_slave_id {
+	QMTM_SLAVE_ID_ETH0,
+	QMTM_SLAVE_ID_ETH1,
+	QMTM_SLAVE_ID_RES2,
+	QMTM_SLAVE_ID_PKTDMA,
+	QMTM_SLAVE_ID_CTX,
+	QMTM_SLAVE_ID_SEC,
+	QMTM_SLAVE_ID_CLASS,
+	QMTM_SLAVE_ID_MSLIM,
+	QMTM_SLAVE_ID_RES8,
+	QMTM_SLAVE_ID_RES9,
+	QMTM_SLAVE_ID_RESA,
+	QMTM_SLAVE_ID_RESB,
+	QMTM_SLAVE_ID_RESC,
+	QMTM_SLAVE_ID_PMPRO,
+	QMTM_SLAVE_ID_SMPRO,
+	QMTM_SLAVE_ID_CPU,
+	QMTM_SLAVE_ID_MAX,
+};
+
+/* QMTM Free Pool Queue modes */
+enum xgene_qmtm_fp_mode {
+	MSG_NO_CHANGE,
+	ROUND_ADDR,
+	REDUCE_LEN,
+	CHANGE_LEN,
+};
+
+extern struct xgene_qmtm_ops storm_qmtm_ops;
+/* QMTM CSR read/write routine */
+void xgene_qmtm_wr32(struct xgene_qmtm *qmtm, u32 offset, u32 data);
+void xgene_qmtm_rd32(struct xgene_qmtm *qmtm, u32 offset, u32 *data);
+
+#endif /* __XGENE_QMTM_MAIN_H__ */
diff --git a/drivers/mailbox/xgene/xgene_qmtm_storm.c b/drivers/mailbox/xgene/xgene_qmtm_storm.c
new file mode 100644
index 0000000..e214d28
--- /dev/null
+++ b/drivers/mailbox/xgene/xgene_qmtm_storm.c
@@ -0,0 +1,358 @@
+/**
+ * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver
+ *
+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
+ * Author: Ravi Patel <rapatel@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *         Fushen Chen <fchen@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include "xgene_qmtm_main.h"
+
+#define CSR_IPBRR_ADDR		0x00000000
+#define CSR_IPBRR_QMTM0_DEFAULT	0x00000520
+#define CSR_IPBRR_QMTM1_DEFAULT	0x00000521
+#define CSR_IPBRR_QMTM2_DEFAULT	0x00000522
+#define CSR_IPBRR_QMTM3_DEFAULT	0x000005E0
+
+#define CSR_QSTATE_ADDR		0x0000006c
+#define QNUMBER_WR(src)		(((u32)(src)) & 0x000003ff)
+
+#define CSR_QSTATE_WR_0_ADDR	0x00000070
+#define CSR_QSTATE_WR_1_ADDR	0x00000074
+#define CSR_QSTATE_WR_2_ADDR	0x00000078
+#define CSR_QSTATE_WR_3_ADDR	0x0000007c
+#define CSR_QSTATE_WR_4_ADDR	0x00000080
+
+/* QMTM Queue State */
+struct storm_qmtm_csr_qstate {
+	u32 w0;
+	u32 w1;
+	u32 w2;
+	u32 w3;
+	u32 w4;
+} __packed;
+
+/*
+ * Physical or free pool queue state (pq or fp)
+ */
+struct storm_qmtm_pq_fp_qstate {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	/* register word 0 (bit 31:0) */
+	u32 cpu_notify:8;           /* 31:24 */
+	u32 cfgsaben:1;             /* 23 enable SAB broadcasting */
+	u32 cfgtmvq:10;             /* 22:13 parent vq */
+	u32 cfgtmvqen:1;            /* 12 enable pq to belong to vq */
+	u32 resize_done:1;          /* 11 */
+	u32 resize_start:1;         /* 10 */
+	u32 resize_qid:10;          /* 9:0 */
+
+	/* register word 1 (bit 63:32) */
+	u32 headptr:15;             /* 63:49 */
+	u32 nummsg:16;              /* 48:33 */
+	u32 cfgnotifyqne:1;         /* 32 enable Q not empty intr */
+
+	/* register word 2 (bit 95:64) */
+	u32 cfgstartaddrL:27;       /* 95:69 split 7/27 */
+	u32 qcoherent:1;            /* 68 */
+	u32 rid:3;                  /* 67:65 */
+	u32 cfgcrid:1;              /* 64 */
+
+	/* register word 3 (bit 127:96) */
+	u32 cfgRecombBufTimeoutL:4; /* 127:124 split 3/4 */
+	u32 cfgRecombBuf:1;         /* 123 */
+	u32 qstatelock:1;           /* 122 */
+	u32 cfgqsize:3;             /* 121:119 queue size */
+	u32 fp_mode:3;              /* 118:116 free pool mode */
+	u32 cfgacceptlerr:1;        /* 115 */
+	u32 reserved_0:1;           /* 114 */
+	u32 stashing:1;             /* 113 */
+	u32 slot_pending:8;         /* 112:105 */
+	u32 vc_chanid:2;            /* 104:103 */
+	u32 cfgstartaddrH:7;        /* 102:96 split 7/27 */
+
+	/* register word 4 (bit 159:128) */
+	u32 resv1:11;               /* 159:149 */
+	u32 cfgqtype:2;             /* 148:147 queue type */
+	u32 resv2:5;                /* 146:142 */
+	u32 half_64B_override:3;    /* 141:139 */
+	u32 resv3:4;                /* 138:135 */
+	u32 CfgSupressCmpl:1;       /* 134 */
+	u32 cfgselthrsh:3;          /* 133:131 associated threshold set */
+	u32 cfgRecombBufTimeoutH:3; /* 130:128 split 3/4 */
+#else
+	/* register word 0 (bit 31:0) */
+	u32 resize_qid:10;          /* 9:0 */
+	u32 resize_start:1;         /* 10 */
+	u32 resize_done:1;          /* 11 */
+	u32 cfgtmvqen:1;            /* 12 enable pq to belong to vq */
+	u32 cfgtmvq:10;             /* 22:13 parent vq */
+	u32 cfgsaben:1;             /* 23 enable SAB broadcasting */
+	u32 cpu_notify:8;           /* 31:24 */
+
+	/* register word 1 (bit 63:32) */
+	u32 cfgnotifyqne:1;         /* 32 enable Q not empty intr */
+	u32 nummsg:16;              /* 48:33 */
+	u32 headptr:15;             /* 63:49 */
+
+	/* register word 2 (bit 95:64) */
+	u32 cfgcrid:1;              /* 64 */
+	u32 rid:3;                  /* 67:65 */
+	u32 qcoherent:1;            /* 68 */
+	u32 cfgstartaddrL:27;       /* 95:69 split 7/27 */
+
+	/* register word 3 (bit 127:96) */
+	u32 cfgstartaddrH:7;        /* 102:96 split 7/27 */
+	u32 vc_chanid:2;            /* 104:103 */
+	u32 slot_pending:8;         /* 112:105 */
+	u32 stashing:1;             /* 113 */
+	u32 reserved_0:1;           /* 114 */
+	u32 cfgacceptlerr:1;        /* 115 */
+	u32 fp_mode:3;              /* 118:116 free pool mode */
+	u32 cfgqsize:3;             /* 121:119 queue size */
+	u32 qstatelock:1;           /* 122 */
+	u32 cfgRecombBuf:1;         /* 123 */
+	u32 cfgRecombBufTimeoutL:4; /* 127:124 split 3/4 */
+
+	/* register word 4 (bit 159:128) */
+	u32 cfgRecombBufTimeoutH:3; /* 130:128 split 3/4 */
+	u32 cfgselthrsh:3;          /* 133:131 associated threshold set */
+	u32 CfgSupressCmpl:1;       /* 134 */
+	u32 resv3:4;                /* 138:135 */
+	u32 half_64B_override:3;    /* 141:139 */
+	u32 resv2:5;                /* 146:142 */
+	u32 cfgqtype:2;             /* 148:147 queue type */
+	u32 resv1:11;               /* 159:149 */
+#endif
+} __packed;
+
+/*
+ * Virtual queue state (vq)
+ */
+struct storm_qmtm_vq_qstate {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	/* register word 0 (bit 31:0) */
+	u32 rid:3;          /* 31:29 */
+	u32 cpu_notify:8;   /* 28:21 */
+	u32 cfgcrid:1;      /* 20 critical rid config */
+	u32 cfgnotifyqne:1; /* 19 enable Q not empty intr */
+	u32 cfgsaben:1;     /* 18 enable SAB broadcasting */
+	u32 nummsg:18;      /* 17:0 */
+
+	/* register word 1 (bit 63:32) */
+	u32 q5reqvld:1;     /* 63 */
+	u32 q5txallowed:1;  /* 62 */
+	u32 q5selarb:2;     /* 61:60 */
+	u32 q6_sel:10;      /* 59:50 */
+	u32 q6reqvld:1;     /* 49 */
+	u32 q6txallowed:1;  /* 48 */
+	u32 q6selarb:2;     /* 47:46 */
+	u32 q7_sel:10;      /* 45:36 */
+	u32 q7reqvld:1;     /* 35 */
+	u32 q7txallowed:1;  /* 34 */
+	u32 q7selarb:2;     /* 33:32 */
+
+	/* register word 2 (bit 95:64) */
+	u32 q3_selL:4;      /* 95:92 split 4/6 */
+	u32 q3reqvld:1;     /* 91 */
+	u32 q3txallowed:1;  /* 90 */
+	u32 q3selarb:2;     /* 89:88 */
+	u32 q4_sel:10;      /* 87:78 */
+	u32 q4reqvld:1;     /* 77 */
+	u32 q4txallowed:1;  /* 76 */
+	u32 q4selarb:2;     /* 75:74 */
+	u32 q5_sel:10;      /* 73:64 */
+
+	/* register word 3 (bit 127:96) */
+	u32 q1_selL:8;      /* 127:120 split 2/8 */
+	u32 q1reqvld:1;     /* 119 */
+	u32 q1txallowed:1;  /* 118 */
+	u32 q1selarb:2;     /* 117:116 */
+	u32 q2_sel:10;      /* 115:106 */
+	u32 q2reqvld:1;     /* 105 */
+	u32 q2txallowed:1;  /* 104 */
+	u32 q2selarb:2;     /* 103:102 */
+	u32 q3_selH:6;      /* 101:96 split 4/6 */
+
+	/* register word 4 (bit 159:128) */
+	u32 resv1:11;       /* 159:149 */
+	u32 cfgqtype:2;     /* 148:147 queue type */
+	u32 cfgselthrsh:3;  /* 146:144 associated threshold set */
+	u32 q0_sel:10;      /* 143:134 */
+	u32 q0reqvld:1;     /* 133 */
+	u32 q0txallowed:1;  /* 132 */
+	u32 q0selarb:2;     /* 131:130 */
+	u32 q1_selH:2;      /* 129:128 split 2/8 */
+#else
+	/* register word 0 (bit 31:0) */
+	u32 nummsg:18;      /* 17:0 */
+	u32 cfgsaben:1;     /* 18 enable SAB broadcasting */
+	u32 cfgnotifyqne:1; /* 19 enable Q not empty intr */
+	u32 cfgcrid:1;      /* 20 critical rid config */
+	u32 cpu_notify:8;   /* 28:21 */
+	u32 rid:3;          /* 31:29 */
+
+	/* register word 1 (bit 63:32) */
+	u32 q7selarb:2;     /* 33:32 */
+	u32 q7txallowed:1;  /* 34 */
+	u32 q7reqvld:1;     /* 35 */
+	u32 q7_sel:10;      /* 45:36 */
+	u32 q6selarb:2;     /* 47:46 */
+	u32 q6txallowed:1;  /* 48 */
+	u32 q6reqvld:1;     /* 49 */
+	u32 q6_sel:10;      /* 59:50 */
+	u32 q5selarb:2;     /* 61:60 */
+	u32 q5txallowed:1;  /* 62 */
+	u32 q5reqvld:1;     /* 63 */
+
+	/* register word 2 (bit 95:64) */
+	u32 q5_sel:10;      /* 73:64 */
+	u32 q4selarb:2;     /* 75:74 */
+	u32 q4txallowed:1;  /* 76 */
+	u32 q4reqvld:1;     /* 77 */
+	u32 q4_sel:10;      /* 87:78 */
+	u32 q3selarb:2;     /* 89:88 */
+	u32 q3txallowed:1;  /* 90 */
+	u32 q3reqvld:1;     /* 91 */
+	u32 q3_selL:4;      /* 95:92 split 4/6 */
+
+	/* register word 3 (bit 127:96) */
+	u32 q3_selH:6;      /* 101:96 split 4/6 */
+	u32 q2selarb:2;     /* 103:102 */
+	u32 q2txallowed:1;  /* 104 */
+	u32 q2reqvld:1;     /* 105 */
+	u32 q2_sel:10;      /* 115:106 */
+	u32 q1selarb:2;     /* 117:116 */
+	u32 q1txallowed:1;  /* 118 */
+	u32 q1reqvld:1;     /* 119 */
+	u32 q1_selL:8;      /* 127:120 split 2/8 */
+
+	/* register word 4 (bit 159:128) */
+	u32 q1_selH:2;      /* 129:128 split 2/8 */
+	u32 q0selarb:2;     /* 131:130 */
+	u32 q0txallowed:1;  /* 132 */
+	u32 q0reqvld:1;     /* 133 */
+	u32 q0_sel:10;      /* 143:134 */
+	u32 cfgselthrsh:3;  /* 146:144 associated threshold set */
+	u32 cfgqtype:2;     /* 148:147 queue type */
+	u32 resv1:11;       /* 159:149 */
+#endif
+} __packed;
+
+union storm_qmtm_qstate {
+	struct storm_qmtm_csr_qstate csr;
+	struct storm_qmtm_pq_fp_qstate pq;
+	struct storm_qmtm_pq_fp_qstate fp;
+	struct storm_qmtm_vq_qstate vq;
+} __packed;
+
+/* Storm QMTM operations */
+static void storm_qmtm_write_qstate(struct xgene_mbox *mbox)
+{
+	struct xgene_qmtm *qmtm = mbox->qmtm;
+	struct storm_qmtm_csr_qstate *csr_qstate =
+	    &((union storm_qmtm_qstate *)mbox->qstate)->csr;
+
+	/* write queue number */
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_ADDR, QNUMBER_WR(mbox->qid));
+
+	/* write queue state */
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_0_ADDR, csr_qstate->w0);
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_1_ADDR, csr_qstate->w1);
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_2_ADDR, csr_qstate->w2);
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_3_ADDR, csr_qstate->w3);
+	xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_4_ADDR, csr_qstate->w4);
+}
+
+static void storm_qmtm_set_qstate(struct xgene_mbox *mbox)
+{
+	struct storm_qmtm_pq_fp_qstate *pq_fp =
+	    &((union storm_qmtm_qstate *)(mbox->qstate))->pq;
+
+	if (QMTM_QTYPE_VQ(mbox))
+		pq_fp->cfgqtype = QTYPE_VQ;
+	else if (QMTM_QTYPE_FP(mbox))
+		pq_fp->cfgqtype = QTYPE_FP;
+	else
+		pq_fp->cfgqtype = QTYPE_PQ;
+
+	/* if its a free queue, ask QMTM to set len to 0 when dealloc */
+	if (pq_fp->cfgqtype == QTYPE_FP)
+		pq_fp->fp_mode = CHANGE_LEN;
+
+	if (QMTM_SLAVE_ID(mbox) == QMTM_SLAVE_ID_ETH0 ||
+			QMTM_SLAVE_ID(mbox) == QMTM_SLAVE_ID_ETH1) {
+		pq_fp->cfgRecombBuf = 1;
+		pq_fp->cfgRecombBufTimeoutL = 0xf;
+		pq_fp->cfgRecombBufTimeoutH = 0x7;
+	}
+
+	pq_fp->cfgselthrsh = 1;
+	/*  Allow the queue to accept message with non-zero LErr */
+	pq_fp->cfgacceptlerr = 1;
+	pq_fp->qcoherent = 1;
+	pq_fp->cfgstartaddrL = (u32)((mbox->dma >> 8) & (u32)(BIT(27) - 1));
+	pq_fp->cfgstartaddrH = (u32)(mbox->dma >> 35);
+	pq_fp->cfgqsize = mbox->slots;
+	storm_qmtm_write_qstate(mbox);
+}
+
+static void storm_qmtm_clr_qstate(struct xgene_mbox *mbox)
+{
+	memset(mbox->qstate, 0, sizeof(union storm_qmtm_qstate));
+	storm_qmtm_write_qstate(mbox);
+}
+
+static u32 storm_qmtm_read_level(void *qfabric)
+{
+	return (readl(&(((u32 *)qfabric)[1])) & 0x1fffe) >> 1;
+}
+
+static int storm_qmtm_init(struct xgene_qmtm *qmtm)
+{
+	int ret = 0, val;
+	xgene_qmtm_rd32(qmtm, CSR_IPBRR_ADDR, &val);
+	switch (val) {
+	case CSR_IPBRR_QMTM0_DEFAULT:
+		qmtm->qmtm_ip = QMTM0;
+		qmtm->irq_start = 0;
+		qmtm->irq_count = 16;
+		break;
+	case CSR_IPBRR_QMTM1_DEFAULT:
+		qmtm->qmtm_ip = QMTM1;
+		qmtm->irq_start = 0;
+		qmtm->irq_count = 32;
+		break;
+	case CSR_IPBRR_QMTM2_DEFAULT:
+		qmtm->qmtm_ip = QMTM2;
+		qmtm->irq_start = 16;
+		qmtm->irq_count = 16;
+		break;
+	case CSR_IPBRR_QMTM3_DEFAULT:
+		qmtm->qmtm_ip = QMTM3;
+		qmtm->irq_start = 0;
+		qmtm->irq_count = 1;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+struct xgene_qmtm_ops storm_qmtm_ops = {
+	.init = storm_qmtm_init,
+	.set_qstate = storm_qmtm_set_qstate,
+	.clr_qstate = storm_qmtm_clr_qstate,
+	.read_level = storm_qmtm_read_level,
+};
diff --git a/include/linux/platform_data/xgene_qmtm.h b/include/linux/platform_data/xgene_qmtm.h
new file mode 100644
index 0000000..23e630c
--- /dev/null
+++ b/include/linux/platform_data/xgene_qmtm.h
@@ -0,0 +1,300 @@
+/*
+ * AppliedMicro X-Gene SoC Queue Manager/Traffic Manager driver
+ *
+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
+ * Author: Ravi Patel <rapatel@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *         Fushen Chen <fchen@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __XGENE_QMTM_H__
+#define __XGENE_QMTM_H__
+
+/* QMTM Data Length encoded as per QM message format */
+enum xgene_mbox_data_len {
+	DATA_LEN_256B = 0x0100,
+	DATA_LEN_1K = 0x0400,
+	DATA_LEN_2K = 0x0800,
+	DATA_LEN_4K = 0x1000,
+	DATA_LEN_16K = 0x4000,
+};
+
+enum xgene_mbox_mask_len {
+	MASK_LEN_256B = (DATA_LEN_256B - 1),
+	MASK_LEN_1K = (DATA_LEN_1K - 1),
+	MASK_LEN_2K = (DATA_LEN_2K - 1),
+	MASK_LEN_4K = (DATA_LEN_4K - 1),
+	MASK_LEN_16K = (DATA_LEN_16K - 1),
+};
+
+/* QMTM Buffer Length encoded as per QM message format */
+enum xgene_mbox_buf_len {
+	BUF_LEN_256B = 0x7000,
+	BUF_LEN_1K = 0x6000,
+	BUF_LEN_2K = 0x5000,
+	BUF_LEN_4K = 0x4000,
+	BUF_LEN_16K = 0x0000,
+};
+
+/* QMTM messaging structures */
+/* 16 byte QMTM message format */
+struct xgene_mbox_msg16 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	/* memory word 0 (bit 31:0) */
+	u32 UserInfo;
+
+	/* memory word 1 (bit 63:32) */
+	u32 HL:1;
+	u32 LErr:3;
+	u32 RType:4;
+	u32 IN:1;
+	u32 Rv:1;
+	u32 HB:1;
+	u32 PB:1;
+	u32 LL:1;
+	u32 NV:1;
+	u32 LEI:2;
+	u32 ELErr:2;
+	u32 Rv2:2;
+	u32 FPQNum:12;
+
+	/* memory word 2 (bit 95:64) */
+	u32 DataAddrL;    /* split 10/32 */
+
+	/* memory word 3 (bit 127:96) */
+	u32 C:1;
+	u32 BufDataLen:15;
+	u32 Rv6:6;
+	u32 DataAddrH:10; /* split 10/32 */
+#else
+	/* memory word 0 (bit 31:0) */
+	u32 UserInfo;
+
+	/* memory word 1 (bit 63:32) */
+	u32 FPQNum:12;
+	u32 Rv2:2;
+	u32 ELErr:2;
+	u32 LEI:2;
+	u32 NV:1;
+	u32 LL:1;
+	u32 PB:1;
+	u32 HB:1;
+	u32 Rv:1;
+	u32 IN:1;
+	u32 RType:4;
+	u32 LErr:3;
+	u32 HL:1;
+
+	/* memory word 2 (bit 95:64) */
+	u32 DataAddrL;    /* split 10/32 */
+
+	/* memory word 3 (bit 127:96) */
+	u32 DataAddrH:10; /* split 10/32 */
+	u32 Rv6:6;
+	u32 BufDataLen:15;
+	u32 C:1;
+#endif
+} __packed;
+
+/* Higher 16 byte portion of 32 byte of QMTM message format */
+struct xgene_mbox_msg16H {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	/* memory word 4 (bit 159:128) */
+	u32 H0Info_msbL;    /* split 16/32 */
+
+	/* memory word 5 (bit 191:160) */
+	u32 HR:1;
+	u32 Rv0:1;
+	u32 DR:1;
+	u32 Rv1:1;
+	u32 TotDataLengthLinkListLSBs:12;
+	u16 H0Info_msbH; /* split 16/32 */
+
+	/* memory word 6 (bit 223:192) */
+	u32 H0Info_lsbL; /* split 16/32 */
+
+	/* memory word 7 (bit 255:224) */
+	u32 H0FPSel:4;
+	u32 H0Enq_Num:12;
+	u16 H0Info_lsbH; /* split 16/32 */
+#else
+	/* memory word 4 (bit 159:128) */
+	u32 H0Info_msbL; /* split 16/32 */
+
+	/* memory word 5 (bit 191:160) */
+	u16 H0Info_msbH; /* split 16/32 */
+	u32 TotDataLengthLinkListLSBs:12;
+	u32 Rv1:1;
+	u32 DR:1;
+	u32 Rv0:1;
+	u32 HR:1;
+
+	/* memory word 6 (bit 223:192) */
+	u32 H0Info_lsbL; /* split 16/32 */
+
+	/* memory word 7 (bit 255:224) */
+	u16 H0Info_lsbH; /* split 16/32 */
+	u32 H0Enq_Num:12;
+	u32 H0FPSel:4;
+#endif
+} __packed;
+
+/* 8 byte portion of QMTM extended (64B) message format */
+struct xgene_mbox_msg8 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	u32 NxtDataAddrL;
+	u32 Rv1:1;
+	u32 NxtBufDataLength:15;
+	u32 NxtFPQNum:4;
+	u32 Rv2:2;
+	u32 NxtDataAddrH:10;
+#else
+	u32 NxtDataAddrL;
+	u32 NxtDataAddrH:10;
+	u32 Rv2:2;
+	u32 NxtFPQNum:4;
+	u32 NxtBufDataLength:15;
+	u32 Rv1:1;
+#endif
+} __packed;
+
+/* 8 byte Link list portion of QMTM extended (64B) message format */
+struct xgene_mbox_msg8_list {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	u32 NxtDataPtrL;
+	u8  TotDataLengthLinkListMSBs;
+	u8  NxtLinkListength;
+	u32 NxtFPQNum:4;
+	u32 Rv2:2;
+	u32 NxtDataPtrH:10;
+#else
+	u32 NxtDataPtrL;
+	u32 NxtDataPtrH:10;
+	u32 Rv2:2;
+	u32 NxtFPQNum:4;
+	u8  NxtLinkListength;
+	u8  TotDataLengthLinkListMSBs;
+#endif
+} __packed;
+
+/* This structure represents 32 byte QMTM message format */
+struct xgene_mbox_msg32 {
+	struct xgene_mbox_msg16 msg16;
+	struct xgene_mbox_msg16H msg16H;
+} __packed;
+
+ /* Higher 32 byte of QMTM extended (64B) message format */
+struct xgene_mbox_msg32H {
+	struct xgene_mbox_msg8 msg8_2;
+	struct xgene_mbox_msg8 msg8_1;
+	union {
+		struct xgene_mbox_msg8 msg8_4;
+		struct xgene_mbox_msg8_list msg8_list;
+	};
+	struct xgene_mbox_msg8 msg8_3;
+} __packed;
+
+/* 64 byte QMTM message format */
+struct xgene_mbox_msg64 {
+	struct xgene_mbox_msg32 msg32;
+	struct xgene_mbox_msg32H msg32H;
+} __packed;
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define xgene_mbox_msg_le32(word, words) \
+	do { \
+		int w; \
+		for (w = 0; w < words; w++) \
+			*(word + w) = cpu_to_le32(*(word + w)); \
+	} while (0)
+#else
+#define xgene_mbox_msg_le32(word, words) \
+	do {} while (0)
+#endif
+
+/* Empty Slot Soft Signature */
+#define EMPTY_SLOT_INDEX	7
+#define EMPTY_SLOT		0x22222222
+
+/* Encoding Destination QMTM (2 MSB) and Queue ID */
+#define QMTM_QUEUE_ID(q)	(((u16)(q->qstate[6]) << 10) | q->qid)
+
+/* Decoding PBM signal */
+#define QMTM_PBN(q)		(q->pbm & 0x003F)
+#define QMTM_SLAVE_ID(q)	((q->pbm & 0x03C0) >> 6)
+#define QMTM_QTYPE_FP(q)	(q->pbm & 0x0020)
+#define QMTM_QTYPE_VQ(q)	(q->pbm & 0x0400)
+
+/* Per queue state database */
+struct xgene_mbox {
+	u16 pbm;
+	u16 qid;
+	u16 qhead;
+	u16 qtail;
+	u16 slots;
+	u16 irq;
+	u32 qsize;
+	u32 pbm_state;
+	u32 qstate[7];
+	void *qfabric;
+	void *level;
+	dma_addr_t dma;
+	union {
+		void *qaddr;
+		struct xgene_mbox_msg16 *msg16;
+		struct xgene_mbox_msg32 *msg32;
+	};
+	struct xgene_qmtm *qmtm;
+};
+
+static inline u16 xgene_mbox_encode_bufdatalen(u32 len)
+{
+	if (len <= DATA_LEN_256B)
+		return BUF_LEN_256B | (len & MASK_LEN_256B);
+	else if (len <= DATA_LEN_1K)
+		return BUF_LEN_1K | (len & MASK_LEN_1K);
+	else if (len <= DATA_LEN_2K)
+		return BUF_LEN_2K | (len & MASK_LEN_2K);
+	else if (len <= DATA_LEN_4K)
+		return BUF_LEN_4K | (len & MASK_LEN_4K);
+	else if (len < DATA_LEN_16K)
+		return BUF_LEN_16K | (len & MASK_LEN_16K);
+	else
+		return BUF_LEN_16K;
+}
+
+static inline u16 xgene_mbox_encode_datalen(u32 len)
+{
+	return len & MASK_LEN_16K;
+}
+
+static inline u32 xgene_mbox_decode_datalen(u16 bufdatalen)
+{
+	switch (bufdatalen & BUF_LEN_256B) {
+	case BUF_LEN_256B:
+		return bufdatalen & MASK_LEN_256B ? : DATA_LEN_256B;
+	case BUF_LEN_1K:
+		return bufdatalen & MASK_LEN_1K ? : DATA_LEN_1K;
+	case BUF_LEN_2K:
+		return bufdatalen & MASK_LEN_2K ? : DATA_LEN_2K;
+	case BUF_LEN_4K:
+		return bufdatalen & MASK_LEN_4K ? : DATA_LEN_4K;
+	default:
+		return bufdatalen & MASK_LEN_16K ? : DATA_LEN_16K;
+	};
+}
+
+struct xgene_mbox *xgene_mbox_get(struct device *dev, const char *s);
+void xgene_mbox_put(struct xgene_mbox *mbox);
+u32 xgene_mbox_level(struct xgene_mbox *mbox);
+
+#endif /* __XGENE_QMTM_H__ */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH V3 4/4] arm64: boot: dts: entries for APM X-Gene SoC QMTM
From: Ravi Patel @ 2014-02-15  2:22 UTC (permalink / raw)
  To: arnd, gregkh, davem
  Cc: netdev, linux-kernel, devicetree, linux-arm-kernel, jcm, patches,
	Ravi Patel, Keyur Chudgar
In-Reply-To: <1392430922-24643-1-git-send-email-rapatel@apm.com>

This patch adds APM X-Gene SoC Queue Manager/Traffic Manager DTS entries.

Signed-off-by: Ravi Patel <rapatel@apm.com>
Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
---
 arch/arm64/boot/dts/apm-storm.dtsi |   18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index d37d736..70b2725 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -148,10 +148,15 @@
 				compatible = "apm,xgene-device-clock";
 				#clock-cells = <1>;
 				clocks = <&socplldiv2 0>;
-				clock-names = "qmlclk";
+				clock-names = "socplldiv2";
 				reg = <0x0 0x1703C000 0x0 0x1000>;
 				reg-names = "csr-reg";
 				clock-output-names = "qmlclk";
+				status = "ok";
+				csr-offset = <0x0>;
+				csr-mask = <0x3>;
+				enable-offset = <0x8>;
+				enable-mask = <0x3>;
 			};
 
 			ethclk: ethclk {
@@ -187,5 +192,16 @@
 			interrupt-parent = <&gic>;
 			interrupts = <0x0 0x4c 0x4>;
 		};
+
+		qmlite: mailbox@17030000 {
+			compatible = "apm,xgene-qmtm";
+			#mailbox-cells = <4>;
+			status = "ok";
+			reg = <0x0 0x17030000 0x0 0x10000>,
+			      <0x0 0x10000000 0x0 0x400000>;
+			interrupts = <0x0 0x40 0x4>,
+				     <0x0 0x3c 0x4>;
+			clocks = <&qmlclk 0>;
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related

* Re: [RFC 0/6] mailbox: add common framework and port drivers
From: Jassi Brar @ 2014-02-15  3:32 UTC (permalink / raw)
  To: Courtney Cavin
  Cc: Anna, Suman, Rob Herring, Rafael J. Wysocki, Mark Langsdorf,
	Tony Lindgren, Omar Ramirez Luna (omar.ramirez@copitl.com),
	Greg Kroah-Hartman, Pawel Moll, mark.rutland, ijc+devicetree,
	galak, rob, linux-doc, devicetree, lkml, Loic Pallardy,
	LeyFoon Tan, Craig McGeachie
In-Reply-To: <1391820619-25487-1-git-send-email-courtney.cavin@sonymobile.com>

Hi,

On 8 February 2014 06:20, Courtney Cavin <courtney.cavin@sonymobile.com> wrote:
> There is currently no common framework for mailbox drivers, so this is my
> attempt to come up with something suitable.  There seems to be a need for
> making this generic, so I have attempted to do just that.  Most of this is
> modeled pretty strongly after the pwm core, with some influences from the clock
> core.
>
> Looking at the existing use-cases, and some new ones, it would appear that the
> requirements here are rather simple. We need essentially two things for
> consumers:
>         - put_message
>         - callback for receiving messages
>
> The code currently uses atomic notifiers for callbacks.  The common omap core
> deals with fifos and work-queues in order to escape atomic contexts, but from
> what I can see, this is unneeded.  I am also of the opinion that the contexts
> can be much better managed in the drivers which are working with these
> contexts, rather than generically.
>
> Hopefully this will be suitable for the plethora of other drivers around the
> kernel which implement mailboxes, as well.  In any case, I'm rather interested
> to see what the rest of the world thinks.
>
> Keep in mind that while the pl320 & omap code should compile, I don't currently
> have a platform on which I can perform proper testing.  I also removed the
> context save/restore code from omap2 mailbox support, because I think it should
> be able to be done via driver suspend/resume, but haven't done a full
> investigation just yet.
>
> I'm also aware that breaking omap, just to fix it again probably isn't the best
> course of action, and I'm open to suggestions.
>
Did you try to look up the history of mailbox api development?  Google
search: 'mailbox common api'

I (Linaro/Fujitsu), Suman Anna (TI), LeyFoon Tan (Intel), Craig
McGeachie(Broadcom) and Loic Pallardy(ST) already worked a generic
Mailbox framework and infact have controller drivers working over
them.
 For some confidentiality and some lazy and some confusion or whatever
reasons the final version of drivers and API wasn't submitted upstream
yet.

 I think the shortest path to have some generic mailbox framework
upstream is for you to adapt your controller driver to that api and
maybe help pushing it upstream. (I should have clearance to push my
controller driver in a couple of weeks).
It might need a bit api update
https://github.com/sumananna/mailbox/commits/jassiv3-3.10-omap

Thanks
Jassi

^ permalink raw reply

* Re: [RFC 0/6] mailbox: add common framework and port drivers
From: Greg Kroah-Hartman @ 2014-02-15  3:40 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Courtney Cavin, Anna, Suman, Rob Herring, Rafael J. Wysocki,
	Mark Langsdorf, Tony Lindgren,
	Omar Ramirez Luna (omar.ramirez@copitl.com), Pawel Moll,
	mark.rutland, ijc+devicetree, galak, rob, linux-doc, devicetree,
	lkml, Loic Pallardy, LeyFoon Tan, Craig McGeachie
In-Reply-To: <CAJe_ZhfgNUN5=azLrjyLLkh262zv2oBP-ioS8xtBWPonOPacrA@mail.gmail.com>

On Sat, Feb 15, 2014 at 09:02:07AM +0530, Jassi Brar wrote:
> Hi,
> 
> On 8 February 2014 06:20, Courtney Cavin <courtney.cavin@sonymobile.com> wrote:
> > There is currently no common framework for mailbox drivers, so this is my
> > attempt to come up with something suitable.  There seems to be a need for
> > making this generic, so I have attempted to do just that.  Most of this is
> > modeled pretty strongly after the pwm core, with some influences from the clock
> > core.
> >
> > Looking at the existing use-cases, and some new ones, it would appear that the
> > requirements here are rather simple. We need essentially two things for
> > consumers:
> >         - put_message
> >         - callback for receiving messages
> >
> > The code currently uses atomic notifiers for callbacks.  The common omap core
> > deals with fifos and work-queues in order to escape atomic contexts, but from
> > what I can see, this is unneeded.  I am also of the opinion that the contexts
> > can be much better managed in the drivers which are working with these
> > contexts, rather than generically.
> >
> > Hopefully this will be suitable for the plethora of other drivers around the
> > kernel which implement mailboxes, as well.  In any case, I'm rather interested
> > to see what the rest of the world thinks.
> >
> > Keep in mind that while the pl320 & omap code should compile, I don't currently
> > have a platform on which I can perform proper testing.  I also removed the
> > context save/restore code from omap2 mailbox support, because I think it should
> > be able to be done via driver suspend/resume, but haven't done a full
> > investigation just yet.
> >
> > I'm also aware that breaking omap, just to fix it again probably isn't the best
> > course of action, and I'm open to suggestions.
> >
> Did you try to look up the history of mailbox api development?  Google
> search: 'mailbox common api'
> 
> I (Linaro/Fujitsu), Suman Anna (TI), LeyFoon Tan (Intel), Craig
> McGeachie(Broadcom) and Loic Pallardy(ST) already worked a generic
> Mailbox framework and infact have controller drivers working over
> them.
>  For some confidentiality and some lazy and some confusion or whatever
> reasons the final version of drivers and API wasn't submitted upstream
> yet.

Then, in all reality, it doesn't exist at all, and so, we will evaluate
this submission instead.

Just because you all can't send something for merging, doesn't mean you
get to block someone else who has got their act together, that's not
fair.

sorry,

greg k-h

^ permalink raw reply

* Re: [RFC 0/6] mailbox: add common framework and port drivers
From: Jassi Brar @ 2014-02-15  3:57 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Courtney Cavin, Anna, Suman, Rob Herring, Rafael J. Wysocki,
	Mark Langsdorf, Tony Lindgren,
	Omar Ramirez Luna (omar.ramirez@copitl.com), Pawel Moll,
	mark.rutland, ijc+devicetree, galak, rob, linux-doc, devicetree,
	lkml, Loic Pallardy, LeyFoon Tan, Craig McGeachie
In-Reply-To: <20140215034046.GA26468@kroah.com>

On 15 February 2014 09:10, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Sat, Feb 15, 2014 at 09:02:07AM +0530, Jassi Brar wrote:
>> Hi,
>>
>> On 8 February 2014 06:20, Courtney Cavin <courtney.cavin@sonymobile.com> wrote:
>> > There is currently no common framework for mailbox drivers, so this is my
>> > attempt to come up with something suitable.  There seems to be a need for
>> > making this generic, so I have attempted to do just that.  Most of this is
>> > modeled pretty strongly after the pwm core, with some influences from the clock
>> > core.
>> >
>> > Looking at the existing use-cases, and some new ones, it would appear that the
>> > requirements here are rather simple. We need essentially two things for
>> > consumers:
>> >         - put_message
>> >         - callback for receiving messages
>> >
>> > The code currently uses atomic notifiers for callbacks.  The common omap core
>> > deals with fifos and work-queues in order to escape atomic contexts, but from
>> > what I can see, this is unneeded.  I am also of the opinion that the contexts
>> > can be much better managed in the drivers which are working with these
>> > contexts, rather than generically.
>> >
>> > Hopefully this will be suitable for the plethora of other drivers around the
>> > kernel which implement mailboxes, as well.  In any case, I'm rather interested
>> > to see what the rest of the world thinks.
>> >
>> > Keep in mind that while the pl320 & omap code should compile, I don't currently
>> > have a platform on which I can perform proper testing.  I also removed the
>> > context save/restore code from omap2 mailbox support, because I think it should
>> > be able to be done via driver suspend/resume, but haven't done a full
>> > investigation just yet.
>> >
>> > I'm also aware that breaking omap, just to fix it again probably isn't the best
>> > course of action, and I'm open to suggestions.
>> >
>> Did you try to look up the history of mailbox api development?  Google
>> search: 'mailbox common api'
>>
>> I (Linaro/Fujitsu), Suman Anna (TI), LeyFoon Tan (Intel), Craig
>> McGeachie(Broadcom) and Loic Pallardy(ST) already worked a generic
>> Mailbox framework and infact have controller drivers working over
>> them.
>>  For some confidentiality and some lazy and some confusion or whatever
>> reasons the final version of drivers and API wasn't submitted upstream
>> yet.
>
> Then, in all reality, it doesn't exist at all, and so, we will evaluate
> this submission instead.
>
> Just because you all can't send something for merging, doesn't mean you
> get to block someone else who has got their act together, that's not
> fair.
>
Yup probably not much fair. But then also one usually look for any
early development efforts. IIRC only I and Anna started. Others later
joined us looking at archives. Not to vindicate our gang though.

 Now we could either punish us and have this api tread the same
development path where everyone had their requirements (and the
only-waiting-for-approval controller drivers to convert) .... OR we
could see if our/original/old API just works for the purposes of Sony
as well (which it will most probably) and then we could upstream it
with one more 'works-for-me-too'.

Thanks.

^ permalink raw reply

* Re: [RFC 0/6] mailbox: add common framework and port drivers
From: Greg Kroah-Hartman @ 2014-02-15  4:11 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Courtney Cavin, Anna, Suman, Rob Herring, Rafael J. Wysocki,
	Mark Langsdorf, Tony Lindgren,
	Omar Ramirez Luna (omar.ramirez@copitl.com), Pawel Moll,
	mark.rutland, ijc+devicetree, galak, rob, linux-doc, devicetree,
	lkml, Loic Pallardy, LeyFoon Tan, Craig McGeachie
In-Reply-To: <CAJe_Zhe-n6bYUYcbhfHhZ6Cc-8h5Ag7D69hd4G9AtFPjFkWsug@mail.gmail.com>

On Sat, Feb 15, 2014 at 09:27:48AM +0530, Jassi Brar wrote:
> On 15 February 2014 09:10, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> > On Sat, Feb 15, 2014 at 09:02:07AM +0530, Jassi Brar wrote:
> >> Hi,
> >>
> >> On 8 February 2014 06:20, Courtney Cavin <courtney.cavin@sonymobile.com> wrote:
> >> > There is currently no common framework for mailbox drivers, so this is my
> >> > attempt to come up with something suitable.  There seems to be a need for
> >> > making this generic, so I have attempted to do just that.  Most of this is
> >> > modeled pretty strongly after the pwm core, with some influences from the clock
> >> > core.
> >> >
> >> > Looking at the existing use-cases, and some new ones, it would appear that the
> >> > requirements here are rather simple. We need essentially two things for
> >> > consumers:
> >> >         - put_message
> >> >         - callback for receiving messages
> >> >
> >> > The code currently uses atomic notifiers for callbacks.  The common omap core
> >> > deals with fifos and work-queues in order to escape atomic contexts, but from
> >> > what I can see, this is unneeded.  I am also of the opinion that the contexts
> >> > can be much better managed in the drivers which are working with these
> >> > contexts, rather than generically.
> >> >
> >> > Hopefully this will be suitable for the plethora of other drivers around the
> >> > kernel which implement mailboxes, as well.  In any case, I'm rather interested
> >> > to see what the rest of the world thinks.
> >> >
> >> > Keep in mind that while the pl320 & omap code should compile, I don't currently
> >> > have a platform on which I can perform proper testing.  I also removed the
> >> > context save/restore code from omap2 mailbox support, because I think it should
> >> > be able to be done via driver suspend/resume, but haven't done a full
> >> > investigation just yet.
> >> >
> >> > I'm also aware that breaking omap, just to fix it again probably isn't the best
> >> > course of action, and I'm open to suggestions.
> >> >
> >> Did you try to look up the history of mailbox api development?  Google
> >> search: 'mailbox common api'
> >>
> >> I (Linaro/Fujitsu), Suman Anna (TI), LeyFoon Tan (Intel), Craig
> >> McGeachie(Broadcom) and Loic Pallardy(ST) already worked a generic
> >> Mailbox framework and infact have controller drivers working over
> >> them.
> >>  For some confidentiality and some lazy and some confusion or whatever
> >> reasons the final version of drivers and API wasn't submitted upstream
> >> yet.
> >
> > Then, in all reality, it doesn't exist at all, and so, we will evaluate
> > this submission instead.
> >
> > Just because you all can't send something for merging, doesn't mean you
> > get to block someone else who has got their act together, that's not
> > fair.
> >
> Yup probably not much fair. But then also one usually look for any
> early development efforts. IIRC only I and Anna started. Others later
> joined us looking at archives. Not to vindicate our gang though.
> 
>  Now we could either punish us and have this api tread the same
> development path where everyone had their requirements (and the
> only-waiting-for-approval controller drivers to convert) .... OR we
> could see if our/original/old API just works for the purposes of Sony
> as well (which it will most probably) and then we could upstream it
> with one more 'works-for-me-too'.

What is stopping you submitting your patches right now?

^ permalink raw reply

* Re: [RFC 0/6] mailbox: add common framework and port drivers
From: Jassi Brar @ 2014-02-15  4:14 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Courtney Cavin, Anna, Suman, Rob Herring, Rafael J. Wysocki,
	Mark Langsdorf, Tony Lindgren,
	Omar Ramirez Luna (omar.ramirez@copitl.com), Pawel Moll,
	mark.rutland, ijc+devicetree, Kumar Gala, Rob Landley, linux-doc,
	devicetree, lkml, Loic Pallardy, LeyFoon Tan, Craig McGeachie
In-Reply-To: <20140215041119.GA29012@kroah.com>

On 15 February 2014 09:41, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Sat, Feb 15, 2014 at 09:27:48AM +0530, Jassi Brar wrote:
>> On 15 February 2014 09:10, Greg Kroah-Hartman
>> <gregkh@linuxfoundation.org> wrote:
>> > On Sat, Feb 15, 2014 at 09:02:07AM +0530, Jassi Brar wrote:
>> >> Hi,
>> >>
>> >> On 8 February 2014 06:20, Courtney Cavin <courtney.cavin@sonymobile.com> wrote:
>> >> > There is currently no common framework for mailbox drivers, so this is my
>> >> > attempt to come up with something suitable.  There seems to be a need for
>> >> > making this generic, so I have attempted to do just that.  Most of this is
>> >> > modeled pretty strongly after the pwm core, with some influences from the clock
>> >> > core.
>> >> >
>> >> > Looking at the existing use-cases, and some new ones, it would appear that the
>> >> > requirements here are rather simple. We need essentially two things for
>> >> > consumers:
>> >> >         - put_message
>> >> >         - callback for receiving messages
>> >> >
>> >> > The code currently uses atomic notifiers for callbacks.  The common omap core
>> >> > deals with fifos and work-queues in order to escape atomic contexts, but from
>> >> > what I can see, this is unneeded.  I am also of the opinion that the contexts
>> >> > can be much better managed in the drivers which are working with these
>> >> > contexts, rather than generically.
>> >> >
>> >> > Hopefully this will be suitable for the plethora of other drivers around the
>> >> > kernel which implement mailboxes, as well.  In any case, I'm rather interested
>> >> > to see what the rest of the world thinks.
>> >> >
>> >> > Keep in mind that while the pl320 & omap code should compile, I don't currently
>> >> > have a platform on which I can perform proper testing.  I also removed the
>> >> > context save/restore code from omap2 mailbox support, because I think it should
>> >> > be able to be done via driver suspend/resume, but haven't done a full
>> >> > investigation just yet.
>> >> >
>> >> > I'm also aware that breaking omap, just to fix it again probably isn't the best
>> >> > course of action, and I'm open to suggestions.
>> >> >
>> >> Did you try to look up the history of mailbox api development?  Google
>> >> search: 'mailbox common api'
>> >>
>> >> I (Linaro/Fujitsu), Suman Anna (TI), LeyFoon Tan (Intel), Craig
>> >> McGeachie(Broadcom) and Loic Pallardy(ST) already worked a generic
>> >> Mailbox framework and infact have controller drivers working over
>> >> them.
>> >>  For some confidentiality and some lazy and some confusion or whatever
>> >> reasons the final version of drivers and API wasn't submitted upstream
>> >> yet.
>> >
>> > Then, in all reality, it doesn't exist at all, and so, we will evaluate
>> > this submission instead.
>> >
>> > Just because you all can't send something for merging, doesn't mean you
>> > get to block someone else who has got their act together, that's not
>> > fair.
>> >
>> Yup probably not much fair. But then also one usually look for any
>> early development efforts. IIRC only I and Anna started. Others later
>> joined us looking at archives. Not to vindicate our gang though.
>>
>>  Now we could either punish us and have this api tread the same
>> development path where everyone had their requirements (and the
>> only-waiting-for-approval controller drivers to convert) .... OR we
>> could see if our/original/old API just works for the purposes of Sony
>> as well (which it will most probably) and then we could upstream it
>> with one more 'works-for-me-too'.
>
> What is stopping you submitting your patches right now?
>
Nothing. I'll freshen it up and submit today.

Thanks.

^ permalink raw reply

* Re: [PATCH 2/2] of: search the best compatible match first in __of_match_node()
From: Stephen N Chivers @ 2014-02-15  5:19 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Kumar Gala,
	Grant Likely, Kevin Hao, linuxppc-dev, Stephen N Chivers,
	Sebastian Hesselbarth, Chris Proctor
In-Reply-To: <CAL_JsqKq4_1K8EF+PZoP=0=H6tiRxbgdzs9UHHVdbHS014n74Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote on 02/15/2014 02:53:40 AM:

> From: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> To: Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: "devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org" <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>, 
> linuxppc-dev <linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org>, Sebastian Hesselbarth 
> <sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>, Stephen N Chivers 
> <schivers-znpAAEhiOVUQrrorzV6ljw@public.gmane.org>, Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Rob 
> Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>, Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Date: 02/15/2014 02:53 AM
> Subject: Re: [PATCH 2/2] of: search the best compatible match first 
> in __of_match_node()
> 
> On Thu, Feb 13, 2014 at 11:22 PM, Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > Currently, of_match_node compares each given match against all node's
> > compatible strings with of_device_is_compatible.
> >
> > To achieve multiple compatible strings per node with ordering from
> > specific to generic, this requires given matches to be ordered from
> > specific to generic. For most of the drivers this is not true and also
> > an alphabetical ordering is more sane there.
> >
> > Therefore, this patch introduces a function to match each of the 
node's
> > compatible strings against all given compatible matches without type 
and
> > name first, before checking the next compatible string. This implies
> > that node's compatibles are ordered from specific to generic while
> > given matches can be in any order. If we fail to find such a match
> > entry, then fall-back to the old method in order to keep 
compatibility.
> >
> > Cc: Sebastian Hesselbarth <sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > Signed-off-by: Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> 
> Looks good to me. I'll put this in next for a few days. I'd really
> like to see some acks and tested-by's before sending to Linus.
> 
Tested-by: Stephen Chivers <schivers-SmukeSwxQOQ@public.gmane.org>

I have tested the patch for the four PowerPC platforms
available to me.

They are:

MPC8349_MITXGP - Works.
MVME5100        - Works.
MVME4100 - Works.
SAM440EP - Works.

The MPC8349_MITXGP platform is present in Linux-3.13 and previous 
releases.
The MVME5100 is a "revived" platform that is in Linux-3.14-rc2.
The MVME4100 is a work in progress and is the 85xx platform that the
original failure report was for.
The SAM440EP is present in Linux-3.13 and previous releases.

The MPC8349_MITXGP is one of the 49 DTS files with the serial compatible:

compatible = "fsl,ns16550", "ns16550";

For the SAM440EP, the patch improves things from Linux-3.13. In that
release the same sort of problem as reported in:

"Linux-3.14-rc2: Order of serial node compatibles in DTS files."

occurs with slightly different symptoms:

of_serial ef600300.serial: Port found
of_serial ef600300.serial: Port found
of_serial ef600300.serial: Unknown serial port found, ignored
of_serial ef600400.serial: Port found
of_serial ef600400.serial: Port found
of_serial ef600400.serial: Unknown serial port found, ignored
of_serial ef600500.serial: Port found
of_serial ef600500.serial: Port found
of_serial ef600500.serial: Unknown serial port found, ignored
of_serial ef600600.serial: Port found
of_serial ef600600.serial: Port found
of_serial ef600600.serial: Unknown serial port found, ignored

The SAM440EP has a IBM/AMCC 440EP PowerPC CPU and so simply has
"ns16550" as its serial compatible.


> We could be a bit more strict here and fallback to the old matching if
> the match table has any entries with name or type. I don't think that
> should be necessary though.
> 
> Rob
Stephen Chivers,
CSC Australia Pty. Ltd.
> 
> > ---
> >  drivers/of/base.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 42 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/of/base.c b/drivers/of/base.c
> > index ba195fbce4c6..10b51106c854 100644
> > --- a/drivers/of/base.c
> > +++ b/drivers/of/base.c
> > @@ -730,13 +730,49 @@ out:
> >  }
> >  EXPORT_SYMBOL(of_find_node_with_property);
> >
> > +static const struct of_device_id *
> > +of_match_compatible(const struct of_device_id *matches,
> > +                       const struct device_node *node)
> > +{
> > +       const char *cp;
> > +       int cplen, l;
> > +       const struct of_device_id *m;
> > +
> > +       cp = __of_get_property(node, "compatible", &cplen);
> > +       while (cp && (cplen > 0)) {
> > +               m = matches;
> > +               while (m->name[0] || m->type[0] || m->compatible[0]) {
> > +                       /* Only match for the entries without type
> and name */
> > +                       if (m->name[0] || m->type[0] ||
> > +                               of_compat_cmp(m->compatible, cp,
> > +                                        strlen(m->compatible)))
> > +                               m++;
> > +                       else
> > +                               return m;
> > +               }
> > +
> > +               /* Get node's next compatible string */
> > +               l = strlen(cp) + 1;
> > +               cp += l;
> > +               cplen -= l;
> > +       }
> > +
> > +       return NULL;
> > +}
> > +
> >  static
> >  const struct of_device_id *__of_match_node(const struct 
> of_device_id *matches,
> >                                            const struct device_node 
*node)
> >  {
> > +       const struct of_device_id *m;
> > +
> >         if (!matches)
> >                 return NULL;
> >
> > +       m = of_match_compatible(matches, node);
> > +       if (m)
> > +               return m;
> > +
> >         while (matches->name[0] || matches->type[0] || 
> matches->compatible[0]) {
> >                 int match = 1;
> >                 if (matches->name[0])
> > @@ -760,7 +796,12 @@ const struct of_device_id *__of_match_node
> (const struct of_device_id *matches,
> >   *     @matches:       array of of device match structures to search 
in
> >   *     @node:          the of device structure to match against
> >   *
> > - *     Low level utility function used by device matching.
> > + *     Low level utility function used by device matching. We have 
two ways
> > + *     of matching:
> > + *     - Try to find the best compatible match by comparing each 
compatible
> > + *       string of device node with all the given matches 
respectively.
> > + *     - If the above method failed, then try to match the 
> compatible by using
> > + *       __of_device_is_compatible() besides the match in type and 
name.
> >   */
> >  const struct of_device_id *of_match_node(const struct 
> of_device_id *matches,
> >                                          const struct device_node 
*node)
> > --
> > 1.8.5.3
> >

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v3 3/3] ARM: dts: add dts files for xyref5260 board
From: Rahul Sharma @ 2014-02-15  9:24 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Rahul Sharma, linux-samsung-soc, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Kukjin Kim, sunil joshi
In-Reply-To: <52FE672A.6070803@gmail.com>

Thanks Tomasz,

On 15 February 2014 00:27, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Rahul,
>
> The patch looks good, except one issue pointed inline.
>
>
> On 14.02.2014 14:37, Rahul Sharma wrote:
>>
>> diff --git a/arch/arm/boot/dts/exynos5260-xyref5260-evt0.dts
>> b/arch/arm/boot/dts/exynos5260-xyref5260-evt0.dts
>> new file mode 100644
>> index 0000000..c4efc1e
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/exynos5260-xyref5260-evt0.dts
>
>
> [snip]
>
>
>> +&mmc_0 {
>> +       status = "okay";
>> +       num-slots = <1>;
>> +       broken-cd;
>> +       bypass-smu;
>> +       supports-highspeed;
>> +       supports-hs200-mode; /* 200 Mhz */
>> +       fifo-depth = <0x40>;
>
>
> This is a SoC-level property and it is already specified in your
> exynos5260.dtsi.
>

Tomasz,

yea correct. I will put these inside SoC node.

Regards,
Rahul Sharma.

>
>> +       card-detect-delay = <200>;
>> +       samsung,dw-mshc-ciu-div = <3>;
>> +       samsung,dw-mshc-sdr-timing = <0 4>;
>> +       samsung,dw-mshc-ddr-timing = <0 2>;
>> +       pinctrl-names = "default";
>> +       pinctrl-0 = <&sd0_rdqs &sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4
>> &sd0_bus8>;
>> +
>> +       slot@0 {
>> +               reg = <0>;
>> +               bus-width = <8>;
>> +       };
>> +};
>> +
>> +&mmc_2 {
>> +       status = "okay";
>> +       num-slots = <1>;
>> +       supports-highspeed;
>> +       fifo-depth = <0x40>;
>
>
> Ditto.
>
> Best regards,
> Tomasz

^ permalink raw reply

* Re: [PATCH v5 3/3] Documentation: add the binding file for Freescale vf610 ADC driver
From: Jonathan Cameron @ 2014-02-15 10:19 UTC (permalink / raw)
  To: Fugang Duan
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	sachin.kamat-QSEj5FYQhm4dnm+yROfE0A,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, lars-Qo5EllUWu/uELgA04lAiVw,
	mark.rutland-5wv7dgnIgG8, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1390714773-23066-4-git-send-email-B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

On 26/01/14 05:39, Fugang Duan wrote:
> The patch adds the binding file for Freescale vf610 ADC driver.
>
> CC: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> CC: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> CC: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> CC: Otavio Salvador <otavio-fKevB0iiKLMBZ+LybsDmbA@public.gmane.org>
> CC: Peter Meerwald <pmeerw-jW+XmwGofnusTnJN9+BGXg@public.gmane.org>
> CC: Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
> Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
It's been near enough 3 weeks without a comment from the Device Tree maintainers.
(admittedly it wasn't cc'd to the devicetree list).  I'm going to take this through
the IIO tree.

Applied to the togreg branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
though will go out briefly as the testing branch to let the autobuilders play.

> ---
>   .../devicetree/bindings/iio/adc/vf610-adc.txt      |   22 ++++++++++++++++++++
>   1 files changed, 22 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> new file mode 100644
> index 0000000..dcebff1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
> @@ -0,0 +1,22 @@
> +Freescale vf610 Analog to Digital Converter bindings
> +
> +The devicetree bindings are for the new ADC driver written for
> +vf610/i.MX6slx and upward SoCs from Freescale.
> +
> +Required properties:
> +- compatible: Should contain "fsl,vf610-adc"
> +- reg: Offset and length of the register set for the device
> +- interrupts: Should contain the interrupt for the device
> +- clocks: The clock is needed by the ADC controller, ADC clock source is ipg clock.
> +- clock-names: Must contain "adc", matching entry in the clocks property.
> +- vref-supply: The regulator supply ADC refrence voltage.
> +
> +Example:
> +adc0: adc@4003b000 {
> +	compatible = "fsl,vf610-adc";
> +	reg = <0x4003b000 0x1000>;
> +	interrupts = <0 53 0x04>;
> +	clocks = <&clks VF610_CLK_ADC0>;
> +	clock-names = "adc";
> +	vref-supply = <&reg_vcc_3v3_mcu>;
> +};
>

^ permalink raw reply

* [PATCH v2 10/23] ARM: MM: Add DT binding for Feroceon L2 cache
From: Andrew Lunn @ 2014-02-15 10:20 UTC (permalink / raw)
  To: Jason Cooper, Sebastian Hesselbarth, Gregory Clement
  Cc: linux ARM, Andrew Lunn, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1392459621-24003-1-git-send-email-andrew-g2DYL2Zd6BY@public.gmane.org>

Instantiate the L2 cache from DT. Indicate in DT where the cache
control register is and if write through should be made.

Signed-off-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
---
v2:
Change compatible strings to follow l2x0 convention
Only expect register for kirkwood-cache.
Default to write through if no DT node.
Rename writethrough to wt-override to follow l2cc binding.
Split kirkwood.dtsi change into a patch of its own.
---
 .../devicetree/bindings/arm/mrvl/feroceon.txt      | 17 +++++++
 arch/arm/include/asm/hardware/cache-feroceon-l2.h  |  2 +
 arch/arm/mach-kirkwood/board-dt.c                  | 15 +------
 arch/arm/mm/cache-feroceon-l2.c                    | 52 ++++++++++++++++++++++
 4 files changed, 72 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mrvl/feroceon.txt

diff --git a/Documentation/devicetree/bindings/arm/mrvl/feroceon.txt b/Documentation/devicetree/bindings/arm/mrvl/feroceon.txt
new file mode 100644
index 000000000000..d6d7d6195ed1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/feroceon.txt
@@ -0,0 +1,17 @@
+* Marvell Feroceon Cache
+
+Required properties:
+- compatible : Should be either "marvell,ferocean-cache" or
+  	       "marvell,kirkwood-cache".
+
+Optional properties:
+- wt-override: If present then L2 is forced to Write through mode
+- reg        : Address of the L2 cache control register. Mandatory for
+  	       "marvell,kirkwood-cache", not used by "marvell,ferocean-cache"
+
+
+Example:
+		l2: l2-cache@20128 {
+			compatible = "marvell,kirkwood-cache";
+			reg = <0x20128 0x4>;
+		};
diff --git a/arch/arm/include/asm/hardware/cache-feroceon-l2.h b/arch/arm/include/asm/hardware/cache-feroceon-l2.h
index 8edd330aabf6..12e1588dc4f1 100644
--- a/arch/arm/include/asm/hardware/cache-feroceon-l2.h
+++ b/arch/arm/include/asm/hardware/cache-feroceon-l2.h
@@ -9,3 +9,5 @@
  */
 
 extern void __init feroceon_l2_init(int l2_wt_override);
+extern int __init feroceon_of_init(void);
+
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index 34c35510fd17..2ef59ee2182d 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -42,19 +42,6 @@ static void __init kirkwood_map_io(void)
 	iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc));
 }
 
-static void __init kirkwood_l2_init(void)
-{
-#ifdef CONFIG_CACHE_FEROCEON_L2
-#ifdef CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH
-	writel(readl(L2_CONFIG_REG) | L2_WRITETHROUGH, L2_CONFIG_REG);
-	feroceon_l2_init(1);
-#else
-	writel(readl(L2_CONFIG_REG) & ~L2_WRITETHROUGH, L2_CONFIG_REG);
-	feroceon_l2_init(0);
-#endif
-#endif
-}
-
 static struct resource kirkwood_cpufreq_resources[] = {
 	[0] = {
 		.start  = CPU_CONTROL_PHYS,
@@ -211,7 +198,7 @@ static void __init kirkwood_dt_init(void)
 
 	BUG_ON(mvebu_mbus_dt_init());
 
-	kirkwood_l2_init();
+	feroceon_of_init();
 
 	kirkwood_cpufreq_init();
 	kirkwood_cpuidle_init();
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 898362e7972b..17a1ecd7a40c 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -13,11 +13,16 @@
  */
 
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/highmem.h>
+#include <linux/io.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/hardware/cache-feroceon-l2.h>
 
+#define L2_WRITETHROUGH_KIRKWOOD	BIT(4)
+
 /*
  * Low-level cache maintenance operations.
  *
@@ -350,3 +355,50 @@ void __init feroceon_l2_init(int __l2_wt_override)
 	printk(KERN_INFO "Feroceon L2: Cache support initialised%s.\n",
 			 l2_wt_override ? ", in WT override mode" : "");
 }
+#ifdef CONFIG_OF
+static const struct of_device_id feroceon_ids[] __initconst = {
+	{ .compatible = "marvell,kirkwood-cache"},
+	{ .compatible = "marvell,feroceon-cache"},
+	{}
+};
+
+int __init feroceon_of_init(void)
+{
+	struct device_node *node;
+	void __iomem *base;
+	bool l2_wt_override = false;
+	struct resource res;
+
+	node = of_find_matching_node(NULL, feroceon_ids);
+	if (!node) {
+		/*
+		 * If we don't know the write through state then
+		 * assume it is write back, as that is the safest
+		 * option.
+		 */
+		feroceon_l2_init(0);
+		return 0;
+	}
+
+	if (of_device_is_compatible(node, "marvell,kirkwood-cache")) {
+		if (of_property_read_bool(node, "wt-override"))
+			l2_wt_override = true;
+
+		if (of_address_to_resource(node, 0, &res))
+			return -ENODEV;
+
+		base = ioremap(res.start, resource_size(&res));
+		if (!base)
+			return -ENOMEM;
+
+		if (l2_wt_override)
+			writel(readl(base) | L2_WRITETHROUGH_KIRKWOOD, base);
+		else
+			writel(readl(base) & ~L2_WRITETHROUGH_KIRKWOOD, base);
+	}
+
+	feroceon_l2_init(l2_wt_override);
+
+	return 0;
+}
+#endif
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 0/4] DT support for kirkwood based Synology NAS boxes
From: Andrew Lunn @ 2014-02-15 11:01 UTC (permalink / raw)
  To: Jason Cooper; +Cc: linux ARM, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn

This patchset adds support for around 30 kirkwood bases Synology NAS
boxes. Patch #1 generalized the qnap power off driver so that i can
also be used for Synology devices. Patch #2 and #3 document vendor
prefixes and i2c trivial devices. Patch #4 adds the synology DT files.

v2:
Typo fix in qnap-poweroff.c
Use ricoy stock ticker instead of ricoh
Describe the lego structure of the hardware

Andrew Lunn (4):
  Power: Reset: Generalize qnap-poweroff to with on Synology devices.
  DT: Vender prefixes: Add ricoh, ssi and synology
  DT: i2c: Trivial: Add sii,s35390a, fix ricoh vendor prefix
  ARM: Kirkwood: Add support for many Synology NAS devices

 .../devicetree/bindings/i2c/trivial-devices.txt    |   3 +-
 .../bindings/power_supply/qnap-poweroff.txt        |   5 +-
 .../devicetree/bindings/vendor-prefixes.txt        |   3 +
 arch/arm/boot/dts/Makefile                         |  15 +++
 arch/arm/boot/dts/kirkwood-ds109.dts               |  33 ++++++
 arch/arm/boot/dts/kirkwood-ds110jv10.dts           |  33 ++++++
 arch/arm/boot/dts/kirkwood-ds111.dts               |  33 ++++++
 arch/arm/boot/dts/kirkwood-ds112.dts               |  34 +++++++
 arch/arm/boot/dts/kirkwood-ds209.dts               |  33 ++++++
 arch/arm/boot/dts/kirkwood-ds210.dts               |  35 +++++++
 arch/arm/boot/dts/kirkwood-ds212.dts               |  37 +++++++
 arch/arm/boot/dts/kirkwood-ds212j.dts              |  34 +++++++
 arch/arm/boot/dts/kirkwood-ds409.dts               |  34 +++++++
 arch/arm/boot/dts/kirkwood-ds409slim.dts           |  32 ++++++
 arch/arm/boot/dts/kirkwood-ds411.dts               |  35 +++++++
 arch/arm/boot/dts/kirkwood-ds411j.dts              |  34 +++++++
 arch/arm/boot/dts/kirkwood-ds411slim.dts           |  34 +++++++
 arch/arm/boot/dts/kirkwood-rs212.dts               |  34 +++++++
 arch/arm/boot/dts/kirkwood-rs409.dts               |  33 ++++++
 arch/arm/boot/dts/kirkwood-rs411.dts               |  34 +++++++
 arch/arm/boot/dts/synology/alarm-led-12.dtsi       |  28 ++++++
 arch/arm/boot/dts/synology/common.dtsi             | 112 +++++++++++++++++++++
 arch/arm/boot/dts/synology/ethernet-1.dtsi         |  15 +++
 arch/arm/boot/dts/synology/fan-alarm-18.dtsi       |  22 ++++
 arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi     |  22 ++++
 arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi     |  32 ++++++
 arch/arm/boot/dts/synology/fan-gpios-15.dtsi       |  34 +++++++
 arch/arm/boot/dts/synology/fan-gpios-32.dtsi       |  34 +++++++
 arch/arm/boot/dts/synology/fan-speed-100.dtsi      |  20 ++++
 arch/arm/boot/dts/synology/fan-speed-120.dtsi      |  20 ++++
 arch/arm/boot/dts/synology/fan-speed-150.dtsi      |  20 ++++
 arch/arm/boot/dts/synology/hdd-leds-20.dtsi        |  90 +++++++++++++++++
 arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi      |  36 +++++++
 arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi      |  52 ++++++++++
 arch/arm/boot/dts/synology/hdd-leds-36.dtsi        | 103 +++++++++++++++++++
 arch/arm/boot/dts/synology/hdd-leds-38.dtsi        |  52 ++++++++++
 arch/arm/boot/dts/synology/hdd-power-29.dtsi       |  56 +++++++++++
 arch/arm/boot/dts/synology/hdd-power-30-1.dtsi     |  40 ++++++++
 arch/arm/boot/dts/synology/hdd-power-30-2.dtsi     |  56 +++++++++++
 arch/arm/boot/dts/synology/hdd-power-30-4.dtsi     |  89 ++++++++++++++++
 arch/arm/boot/dts/synology/hdd-power-31.dtsi       |  40 ++++++++
 arch/arm/boot/dts/synology/hdd-power-34.dtsi       |  73 ++++++++++++++
 arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi      |  18 ++++
 arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi      |  18 ++++
 arch/arm/boot/dts/synology/pcie-2.dtsi             |  19 ++++
 drivers/power/reset/qnap-poweroff.c                |  46 +++++++--
 46 files changed, 1703 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm/boot/dts/kirkwood-ds109.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds110jv10.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds111.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds112.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds209.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds210.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds212.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds212j.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds409.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds409slim.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411j.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411slim.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs212.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs409.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs411.dts
 create mode 100644 arch/arm/boot/dts/synology/alarm-led-12.dtsi
 create mode 100644 arch/arm/boot/dts/synology/common.dtsi
 create mode 100644 arch/arm/boot/dts/synology/ethernet-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-18.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-gpios-15.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-gpios-32.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-100.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-120.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-150.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-20.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-36.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-38.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-29.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-2.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-4.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-31.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-34.dtsi
 create mode 100644 arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi
 create mode 100644 arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi
 create mode 100644 arch/arm/boot/dts/synology/pcie-2.dtsi

-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2 1/4] Power: Reset: Generalize qnap-poweroff to with on Synology devices.
From: Andrew Lunn @ 2014-02-15 11:01 UTC (permalink / raw)
  To: Jason Cooper
  Cc: linux ARM, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn,
	Anton Vorontsov, Dmitry Eremin-Solenikov, David Woodhouse
In-Reply-To: <1392462094-25097-1-git-send-email-andrew-g2DYL2Zd6BY@public.gmane.org>

The Synology NAS devices use a very similar mechanism to QNAP NAS
devices to power off. Both send a single charactor command to a PIC,
over the second serial port. However the baud rate and the command
differ. Generalize the driver to support this.

Signed-off-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Acked-by: Jason Cooper <jason-NLaQJdtUoK4Be96aLqz0jA@public.gmane.org>
Cc: Anton Vorontsov <anton-9xeibp6oKSgdnm+yROfE0A@public.gmane.org>
Cc: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
---
v2:
s/9660/9600
---
 .../bindings/power_supply/qnap-poweroff.txt        |  5 ++-
 drivers/power/reset/qnap-poweroff.c                | 46 +++++++++++++++++-----
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
index 0347d8350d94..af25e77c0e0c 100644
--- a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
+++ b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
@@ -6,8 +6,11 @@ Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the
 microcontroller to turn the power off. This driver adds a handler to
 pm_power_off which is called to turn the power off.
 
+Synology NAS devices use a similar scheme, but a different baud rate,
+9600, and a different character, '1'.
+
 Required Properties:
-- compatible: Should be "qnap,power-off"
+- compatible: Should be "qnap,power-off" or "synology,power-off"
 
 - reg: Address and length of the register set for UART1
 - clocks: tclk clock
diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c
index 37f56f7ee926..10c91fa2466c 100644
--- a/drivers/power/reset/qnap-poweroff.c
+++ b/drivers/power/reset/qnap-poweroff.c
@@ -1,5 +1,5 @@
 /*
- * QNAP Turbo NAS Board power off
+ * QNAP Turbo NAS Board power off. Can also be used on Synology devices.
  *
  * Copyright (C) 2012 Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
  *
@@ -25,17 +25,42 @@
 
 #define UART1_REG(x)	(base + ((UART_##x) << 2))
 
+struct power_off_cfg {
+	u32 baud;
+	char cmd;
+};
+
+static const struct power_off_cfg qnap_power_off_cfg = {
+	.baud = 19200,
+	.cmd = 'A',
+};
+
+static const struct power_off_cfg synology_power_off_cfg = {
+	.baud = 9600,
+	.cmd = '1',
+};
+
+static const struct of_device_id qnap_power_off_of_match_table[] = {
+	{ .compatible = "qnap,power-off",
+	  .data = (void *) &qnap_power_off_cfg,
+	},
+	{ .compatible = "synology,power-off",
+	  .data = (void *) &synology_power_off_cfg,
+	},
+	{}
+};
+
 static void __iomem *base;
 static unsigned long tclk;
+static struct power_off_cfg *cfg;
 
 static void qnap_power_off(void)
 {
-	/* 19200 baud divisor */
-	const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200));
+	const unsigned divisor = ((tclk + (8 * cfg->baud)) / (16 * cfg->baud));
 
 	pr_err("%s: triggering power-off...\n", __func__);
 
-	/* hijack UART1 and reset into sane state (19200,8n1) */
+	/* hijack UART1 and reset into sane state */
 	writel(0x83, UART1_REG(LCR));
 	writel(divisor & 0xff, UART1_REG(DLL));
 	writel((divisor >> 8) & 0xff, UART1_REG(DLM));
@@ -44,16 +69,21 @@ static void qnap_power_off(void)
 	writel(0x00, UART1_REG(FCR));
 	writel(0x00, UART1_REG(MCR));
 
-	/* send the power-off command 'A' to PIC */
-	writel('A', UART1_REG(TX));
+	/* send the power-off command to PIC */
+	writel(cfg->cmd, UART1_REG(TX));
 }
 
 static int qnap_power_off_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	struct clk *clk;
 	char symname[KSYM_NAME_LEN];
 
+	const struct of_device_id *match =
+		of_match_node(qnap_power_off_of_match_table, np);
+	cfg = (struct power_off_cfg *)match->data;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "Missing resource");
@@ -94,10 +124,6 @@ static int qnap_power_off_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id qnap_power_off_of_match_table[] = {
-	{ .compatible = "qnap,power-off", },
-	{}
-};
 MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table);
 
 static struct platform_driver qnap_power_off_driver = {
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 2/4] DT: Vender prefixes: Add ricoh, ssi and synology
From: Andrew Lunn @ 2014-02-15 11:01 UTC (permalink / raw)
  To: Jason Cooper; +Cc: linux ARM, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn
In-Reply-To: <1392462094-25097-1-git-send-email-andrew-g2DYL2Zd6BY@public.gmane.org>

The following patches make use of vendor names ricoh, ssi and
synology.  Add them to the vendor prefix list.

Signed-off-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Acked-by: Jason Cooper <jason-NLaQJdtUoK4Be96aLqz0jA@public.gmane.org>
---
v2:
Use stock ticker for Ricoh as vendor name
s/Richoh/Ricoh/
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 3f900cd51bf0..9cef5cad9019 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -69,6 +69,7 @@ ralink	Mediatek/Ralink Technology Corp.
 ramtron	Ramtron International
 realtek Realtek Semiconductor Corp.
 renesas	Renesas Electronics Corporation
+ricoy	Ricoh Co. Ltd.
 rockchip	Fuzhou Rockchip Electronics Co., Ltd
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
@@ -76,11 +77,13 @@ schindler	Schindler
 sil	Silicon Image
 silabs	Silicon Laboratories
 simtek
+sii	Seiko Instruments, Inc.
 sirf	SiRF Technology, Inc.
 snps 	Synopsys, Inc.
 st	STMicroelectronics
 ste	ST-Ericsson
 stericsson	ST-Ericsson
+synology	Synology, Inc.
 ti	Texas Instruments
 tlm	Trusted Logic Mobility
 toshiba	Toshiba Corporation
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 3/4] DT: i2c: Trivial: Add sii,s35390a, fix ricoh vendor prefix
From: Andrew Lunn @ 2014-02-15 11:01 UTC (permalink / raw)
  To: Jason Cooper; +Cc: linux ARM, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn
In-Reply-To: <1392462094-25097-1-git-send-email-andrew-g2DYL2Zd6BY@public.gmane.org>

Add the Seiko Instruments Inc S35390a to the list of trivial i2c
devices. At the same time, correct the vendor prefix for ricoh, which
should be the ticker symbol ricoy.

Signed-off-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Acked-by: Jason Cooper <jason-NLaQJdtUoK4Be96aLqz0jA@public.gmane.org>
---
 Documentation/devicetree/bindings/i2c/trivial-devices.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 1a1ac2e560e9..5f371914a93b 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -56,8 +56,9 @@ ovti,ov5642		OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an
 pericom,pt7c4338	Real-time Clock Module
 plx,pex8648		48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
 ramtron,24c64		i2c serial eeprom  (24cxx)
-ricoh,rs5c372a		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+ricoy,rs5c372a		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 samsung,24ad0xd1	S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
+sii,s35390a		2-wire CMOS real-time clock
 st-micro,24c256		i2c serial eeprom  (24cxx)
 stm,m41t00		Serial Access TIMEKEEPER
 stm,m41t62		Serial real-time clock (RTC) with alarm
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 4/4] ARM: Kirkwood: Add support for many Synology NAS devices
From: Andrew Lunn @ 2014-02-15 11:01 UTC (permalink / raw)
  To: Jason Cooper
  Cc: linux ARM, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn,
	Ben Peddell
In-Reply-To: <1392462094-25097-1-git-send-email-andrew-g2DYL2Zd6BY@public.gmane.org>

Add device tree fragments and files to support many of the kirkwood
based Synology NAS devices. This is a translation of the board setup
file maintained by Ben Peddell <klightspeed-aslSrjg9ejhWX4hkXwHRhw@public.gmane.org>

Synology hardware is designed like lego. There are two RTC blocks,
three fan alarm blocks, four led blocks, etc. To build a product, a
common base is taken, and then blocks added. This is reflected in the
DT description. Each block has a .dtsi file. The common part is also
described in a .dtsi file. Each board dts file then just includes the
common and needed blocks.

Signed-off-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Tested by Ben Peddell <klightspeed-aslSrjg9ejhWX4hkXwHRhw@public.gmane.org>
cc: Ben Peddell <klightspeed-aslSrjg9ejhWX4hkXwHRhw@public.gmane.org>
---

v2:
Fix gpio's which should be gpo.
Rebase onto v3-14-rc1
Update RTC nodes with vendor name.
Update SPI flash node with vendor name.
Add a description of the lego
Use ricoy, i.e. the stock ticker
---
 arch/arm/boot/dts/Makefile                     |  15 ++++
 arch/arm/boot/dts/kirkwood-ds109.dts           |  33 ++++++++
 arch/arm/boot/dts/kirkwood-ds110jv10.dts       |  33 ++++++++
 arch/arm/boot/dts/kirkwood-ds111.dts           |  33 ++++++++
 arch/arm/boot/dts/kirkwood-ds112.dts           |  34 ++++++++
 arch/arm/boot/dts/kirkwood-ds209.dts           |  33 ++++++++
 arch/arm/boot/dts/kirkwood-ds210.dts           |  35 ++++++++
 arch/arm/boot/dts/kirkwood-ds212.dts           |  37 ++++++++
 arch/arm/boot/dts/kirkwood-ds212j.dts          |  34 ++++++++
 arch/arm/boot/dts/kirkwood-ds409.dts           |  34 ++++++++
 arch/arm/boot/dts/kirkwood-ds409slim.dts       |  32 +++++++
 arch/arm/boot/dts/kirkwood-ds411.dts           |  35 ++++++++
 arch/arm/boot/dts/kirkwood-ds411j.dts          |  34 ++++++++
 arch/arm/boot/dts/kirkwood-ds411slim.dts       |  34 ++++++++
 arch/arm/boot/dts/kirkwood-rs212.dts           |  34 ++++++++
 arch/arm/boot/dts/kirkwood-rs409.dts           |  33 ++++++++
 arch/arm/boot/dts/kirkwood-rs411.dts           |  34 ++++++++
 arch/arm/boot/dts/synology/alarm-led-12.dtsi   |  28 +++++++
 arch/arm/boot/dts/synology/common.dtsi         | 112 +++++++++++++++++++++++++
 arch/arm/boot/dts/synology/ethernet-1.dtsi     |  15 ++++
 arch/arm/boot/dts/synology/fan-alarm-18.dtsi   |  22 +++++
 arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi |  22 +++++
 arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi |  32 +++++++
 arch/arm/boot/dts/synology/fan-gpios-15.dtsi   |  34 ++++++++
 arch/arm/boot/dts/synology/fan-gpios-32.dtsi   |  34 ++++++++
 arch/arm/boot/dts/synology/fan-speed-100.dtsi  |  20 +++++
 arch/arm/boot/dts/synology/fan-speed-120.dtsi  |  20 +++++
 arch/arm/boot/dts/synology/fan-speed-150.dtsi  |  20 +++++
 arch/arm/boot/dts/synology/hdd-leds-20.dtsi    |  90 ++++++++++++++++++++
 arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi  |  36 ++++++++
 arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi  |  52 ++++++++++++
 arch/arm/boot/dts/synology/hdd-leds-36.dtsi    | 103 +++++++++++++++++++++++
 arch/arm/boot/dts/synology/hdd-leds-38.dtsi    |  52 ++++++++++++
 arch/arm/boot/dts/synology/hdd-power-29.dtsi   |  56 +++++++++++++
 arch/arm/boot/dts/synology/hdd-power-30-1.dtsi |  40 +++++++++
 arch/arm/boot/dts/synology/hdd-power-30-2.dtsi |  56 +++++++++++++
 arch/arm/boot/dts/synology/hdd-power-30-4.dtsi |  89 ++++++++++++++++++++
 arch/arm/boot/dts/synology/hdd-power-31.dtsi   |  40 +++++++++
 arch/arm/boot/dts/synology/hdd-power-34.dtsi   |  73 ++++++++++++++++
 arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi  |  18 ++++
 arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi  |  18 ++++
 arch/arm/boot/dts/synology/pcie-2.dtsi         |  19 +++++
 42 files changed, 1658 insertions(+)
 create mode 100644 arch/arm/boot/dts/kirkwood-ds109.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds110jv10.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds111.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds112.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds209.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds210.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds212.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds212j.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds409.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds409slim.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411j.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-ds411slim.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs212.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs409.dts
 create mode 100644 arch/arm/boot/dts/kirkwood-rs411.dts
 create mode 100644 arch/arm/boot/dts/synology/alarm-led-12.dtsi
 create mode 100644 arch/arm/boot/dts/synology/common.dtsi
 create mode 100644 arch/arm/boot/dts/synology/ethernet-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-18.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-gpios-15.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-gpios-32.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-100.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-120.dtsi
 create mode 100644 arch/arm/boot/dts/synology/fan-speed-150.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-20.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-36.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-leds-38.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-29.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-1.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-2.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-30-4.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-31.dtsi
 create mode 100644 arch/arm/boot/dts/synology/hdd-power-34.dtsi
 create mode 100644 arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi
 create mode 100644 arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi
 create mode 100644 arch/arm/boot/dts/synology/pcie-2.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b9d6a8b485e0..6cf3a54ef7f1 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -89,6 +89,18 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \
 	kirkwood-dns325.dtb \
 	kirkwood-dockstar.dtb \
 	kirkwood-dreamplug.dtb \
+	kirkwood-ds109.dtb \
+	kirkwood-ds110jv10.dtb \
+	kirkwood-ds111.dtb \
+	kirkwood-ds209.dtb \
+	kirkwood-ds210.dtb \
+	kirkwood-ds212.dtb \
+	kirkwood-ds212j.dtb \
+	kirkwood-ds409.dtb \
+	kirkwood-ds409slim.dtb \
+	kirkwood-ds411.dtb \
+	kirkwood-ds411j.dtb \
+	kirkwood-ds411slim.dtb \
 	kirkwood-goflexnet.dtb \
 	kirkwood-guruplug-server-plus.dtb \
 	kirkwood-ib62x0.dtb \
@@ -111,6 +123,9 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \
 	kirkwood-nsa310a.dtb \
 	kirkwood-openblocks_a6.dtb \
 	kirkwood-openblocks_a7.dtb \
+	kirkwood-rs212.dtb \
+	kirkwood-rs409.dtb \
+	kirkwood-rs411.dtb \
 	kirkwood-sheevaplug.dtb \
 	kirkwood-sheevaplug-esata.dtb \
 	kirkwood-topkick.dtb \
diff --git a/arch/arm/boot/dts/kirkwood-ds109.dts b/arch/arm/boot/dts/kirkwood-ds109.dts
new file mode 100644
index 000000000000..bea085ad540a
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds109.dts
@@ -0,0 +1,33 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-ricoh.dtsi"
+#include "synology/fan-speed-150.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-1.dtsi"
+
+/ {
+	model = "Synology DS109, DS110, DS110jv20";
+	compatible = "synology,ds109", "synology,ds110jv20",
+		     "synology,ds110", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds110jv10.dts b/arch/arm/boot/dts/kirkwood-ds110jv10.dts
new file mode 100644
index 000000000000..d6b746952947
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds110jv10.dts
@@ -0,0 +1,33 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-150.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-1.dtsi"
+
+/ {
+	model = "Synology DS110j v10 and v30";
+	compatible = "synology,ds110jv10", "synology,ds110jv30",
+		     "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds111.dts b/arch/arm/boot/dts/kirkwood-ds111.dts
new file mode 100644
index 000000000000..5f51e088903f
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds111.dts
@@ -0,0 +1,33 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-1.dtsi"
+
+/ {
+	model = "Synology DS111";
+	compatible = "synology,ds111", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds112.dts b/arch/arm/boot/dts/kirkwood-ds112.dts
new file mode 100644
index 000000000000..cda3203a0824
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds112.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35.dtsi"
+#include "synology/hdd-leds-21-2.dtsi"
+#include "synology/hdd-power-30.dtsi"
+
+/ {
+	model = "Synology DS111";
+	compatible = "synology,ds111", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds209.dts b/arch/arm/boot/dts/kirkwood-ds209.dts
new file mode 100644
index 000000000000..b2ebb423e129
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds209.dts
@@ -0,0 +1,33 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-ricoh.dtsi"
+#include "synology/fan-speed-150.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-2.dtsi"
+#include "synology/hdd-power-31.dtsi"
+
+/ {
+	model = "Synology DS209";
+	compatible = "synology,ds209", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds210.dts b/arch/arm/boot/dts/kirkwood-ds210.dts
new file mode 100644
index 000000000000..8623dd63f44d
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds210.dts
@@ -0,0 +1,35 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-150.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-2.dtsi"
+#include "synology/hdd-power-31.dtsi"
+
+/ {
+	model = "Synology DS210 v10, v20, v30, DS211j";
+	compatible = "synology,ds210jv10", "synology,ds210jv20",
+		     "synology,ds210jv30", "synology,ds211j",
+		     "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds212.dts b/arch/arm/boot/dts/kirkwood-ds212.dts
new file mode 100644
index 000000000000..89e091ce2174
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds212.dts
@@ -0,0 +1,37 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-2.dtsi"
+#include "synology/hdd-power-30-2.dtsi"
+
+/ {
+	model = "Synology DS212, DS212p v10, v20, DS213air v10, DS213 v10";
+	compatible = "synology,ds212", "synology,ds212pv10",
+		     "synology,ds212pv10", "synology,ds212pv20",
+		     "synology,ds213airv10", "synology,ds213v10",
+		     "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds212j.dts b/arch/arm/boot/dts/kirkwood-ds212j.dts
new file mode 100644
index 000000000000..ed14b7bb695e
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds212j.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-21-2.dtsi"
+#include "synology/hdd-power-29.dtsi"
+
+/ {
+	model = "Synology DS212j v10, v20";
+	compatible = "synology,ds212jv10", "synology,ds212jv20",
+		     "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds409.dts b/arch/arm/boot/dts/kirkwood-ds409.dts
new file mode 100644
index 000000000000..7000de1add08
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds409.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-ricoh.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-120.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-18.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+#include "synology/alarm-led-12.dtsi"
+
+/ {
+	model = "Synology DS409, DS410j";
+	compatible = "synology,ds409", "synology,ds410j", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds409slim.dts b/arch/arm/boot/dts/kirkwood-ds409slim.dts
new file mode 100644
index 000000000000..0ba525a594f7
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds409slim.dts
@@ -0,0 +1,32 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-ricoh.dtsi"
+#include "synology/fan-speed-120.dtsi"
+#include "synology/fan-gpios-32.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-20.dtsi"
+
+/ {
+	model = "Synology 409slim";
+	compatible = "synology,ds409slim", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds411.dts b/arch/arm/boot/dts/kirkwood-ds411.dts
new file mode 100644
index 000000000000..4c1ca8e85559
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds411.dts
@@ -0,0 +1,35 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+#include "synology/hdd-power-34.dtsi"
+
+/ {
+	model = "Synology DS411, DS413jv10";
+	compatible = "synology,ds411", "synology,ds413jv10", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds411j.dts b/arch/arm/boot/dts/kirkwood-ds411j.dts
new file mode 100644
index 000000000000..7f08a46ddabb
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds411j.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-120.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-18.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+#include "synology/alarm-led-12.dtsi"
+
+/ {
+	model = "Synology DS411j";
+	compatible = "synology,ds411j", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-ds411slim.dts b/arch/arm/boot/dts/kirkwood-ds411slim.dts
new file mode 100644
index 000000000000..2e6d66f37002
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ds411slim.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-1.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+
+/ {
+	model = "Synology DS411slim";
+	compatible = "synology,ds411slim", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-rs212.dts b/arch/arm/boot/dts/kirkwood-rs212.dts
new file mode 100644
index 000000000000..edc797464983
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-rs212.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-3.dtsi"
+#include "synology/hdd-leds-38.dtsi"
+#include "synology/hdd-power-30-2.dtsi"
+
+/ {
+	model = "Synology RS212";
+	compatible = "synology,rs212", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-rs409.dts b/arch/arm/boot/dts/kirkwood-rs409.dts
new file mode 100644
index 000000000000..906664a99602
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-rs409.dts
@@ -0,0 +1,33 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-ricoh.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-120.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-18.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+
+/ {
+	model = "Synology RS409";
+	compatible = "synology,rs409", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/kirkwood-rs411.dts b/arch/arm/boot/dts/kirkwood-rs411.dts
new file mode 100644
index 000000000000..75c806ea0dc9
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-rs411.dts
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6282.dtsi"
+#include "synology/pcie-2.dtsi"
+#include "synology/common.dtsi"
+#include "synology/i2c-rtc-seiko.dtsi"
+#include "synology/ethernet-1.dtsi"
+#include "synology/fan-speed-100.dtsi"
+#include "synology/fan-gpios-15.dtsi"
+#include "synology/fan-alarm-35-3.dtsi"
+#include "synology/hdd-leds-36.dtsi"
+
+/ {
+	model = "Synology RS411 RS812";
+	compatible = "synology,rs411", "synology,rs812", "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/alarm-led-12.dtsi b/arch/arm/boot/dts/synology/alarm-led-12.dtsi
new file mode 100644
index 000000000000..e6ea8f07d1a5
--- /dev/null
+++ b/arch/arm/boot/dts/synology/alarm-led-12.dtsi
@@ -0,0 +1,28 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_12: pmx-led-12 {
+				marvell,pins = "mpp12";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_12>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:alarm";
+			gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/common.dtsi b/arch/arm/boot/dts/synology/common.dtsi
new file mode 100644
index 000000000000..fb078c4f9a62
--- /dev/null
+++ b/arch/arm/boot/dts/synology/common.dtsi
@@ -0,0 +1,112 @@
+/*
+ * Nodes which are common to all Synology devices
+ *
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	mbus {
+		pcie-controller {
+			status = "okay";
+
+			pcie@1,0 {
+				status = "okay";
+			};
+		};
+	};
+	ocp@f1000000 {
+		i2c@11000 {
+			status = "okay";
+			clock-frequency = <400000>;
+			pinctrl-0 = <&pmx_twsi0>;
+			pinctrl-names = "default";
+		};
+		serial@12000 {
+			status = "okay";
+			pinctrl-0 = <&pmx_uart0>;
+			pinctrl-names = "default";
+		};
+		serial@12100 {
+			status = "okay";
+			pinctrl-0 = <&pmx_uart1>;
+			pinctrl-names = "default";
+		};
+		poweroff@12100 {
+			compatible = "synology,power-off";
+			reg = <0x12000 0x100>;
+			clocks = <&gate_clk 7>;
+		};
+		spi@10600 {
+			status = "okay";
+			pinctrl-0 = <&pmx_spi>;
+			pinctrl-names = "default";
+
+			m25p80@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "st,m25p80";
+				reg = <0>;
+				spi-max-frequency = <20000000>;
+				mode = <0>;
+
+				partition@00000000 {
+					reg = <0x00000000 0x00080000>;
+					label = "RedBoot";
+				};
+
+				partition@00080000 {
+					reg = <0x00080000 0x00200000>;
+					label = "zImage";
+				};
+
+				partition@00280000 {
+					reg = <0x00280000 0x00140000>;
+					label = "rd.gz";
+				};
+				partition@003c0000 {
+					reg = <0x003c0000 0x00010000>;
+					label = "vendor";
+				};
+				partition@003d0000 {
+					reg = <0x003d0000 0x00020000>;
+					label = "RedBoot config";
+				};
+				partition@003f0000 {
+					reg = <0x003f0000 0x00010000>;
+					label = "FIS directory";
+				};
+			};
+		};
+		sata@80000 {
+			pinctrl-0 = <&pmx_sata0 &pmx_sata1>;
+			pinctrl-names = "default";
+			status = "okay";
+			nr-ports = <2>;
+		};
+	};
+	gpio_fan {
+		compatible = "gpio-fan";
+	};
+};
+
+&mdio {
+	status = "okay";
+
+	ethphy0: ethernet-phy {
+		device_type = "ethernet-phy";
+		reg = <8>;
+	};
+};
+
+&eth0 {
+	status = "okay";
+	ethernet0-port@0 {
+		phy-handle = <&ethphy0>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/ethernet-1.dtsi b/arch/arm/boot/dts/synology/ethernet-1.dtsi
new file mode 100644
index 000000000000..bf00eff53bbc
--- /dev/null
+++ b/arch/arm/boot/dts/synology/ethernet-1.dtsi
@@ -0,0 +1,15 @@
+&mdio {
+	status = "okay";
+
+	ethphy1: ethernet-phy {
+		device_type = "ethernet-phy";
+		reg = <9>;
+	};
+};
+
+&eth0 {
+	status = "okay";
+	ethernet1-port@0 {
+		phy-handle = <&ethphy1>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-alarm-18.dtsi b/arch/arm/boot/dts/synology/fan-alarm-18.dtsi
new file mode 100644
index 000000000000..d323eb0d2109
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-alarm-18.dtsi
@@ -0,0 +1,22 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_fan_18: pmx-fan-18 {
+				marvell,pins = "mpp18";
+				marvell,function = "gpo";
+			};
+		};
+	};
+	gpio_fan {
+		alarm-gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi b/arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi
new file mode 100644
index 000000000000..12e52fdae870
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-alarm-35-1.dtsi
@@ -0,0 +1,22 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_fan_35: pmx-fan-35 {
+				marvell,pins = "mpp35";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio_fan {
+		alarm-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi b/arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi
new file mode 100644
index 000000000000..e2a44f402bf0
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-alarm-35-3.dtsi
@@ -0,0 +1,32 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_fan_35: pmx-fan-35 {
+				marvell,pins = "mpp35";
+				marvell,function = "gpio";
+			};
+			pmx_fan_44: pmx-fan-44 {
+				marvell,pins = "mpp44";
+				marvell,function = "gpio";
+			};
+			pmx_fan_45: pmx-fan-45 {
+				marvell,pins = "mpp45";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio_fan {
+		alarm-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH
+			       &gpio1 12 GPIO_ACTIVE_HIGH
+			       &gpio1 13 GPIO_ACTIVE_HIGH>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-gpios-15.dtsi b/arch/arm/boot/dts/synology/fan-gpios-15.dtsi
new file mode 100644
index 000000000000..e27cba942eed
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-gpios-15.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_fan_15: pmx-fan-15 {
+				marvell,pins = "mpp15";
+				marvell,function = "gpio";
+			};
+			pmx_fan_16: pmx-fan-16 {
+				marvell,pins = "mpp16";
+				marvell,function = "gpio";
+			};
+			pmx_fan_17: pmx-fan-17 {
+				marvell,pins = "mpp17";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio_fan {
+		pinctrl-0 = <&pmx_fan_15 &pmx_fan_16 &pmx_fan_17>;
+		pinctrl-names = "default";
+		gpios = <&gpio0 15 GPIO_ACTIVE_HIGH
+			 &gpio0 16 GPIO_ACTIVE_HIGH
+			 &gpio0 17 GPIO_ACTIVE_HIGH>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-gpios-32.dtsi b/arch/arm/boot/dts/synology/fan-gpios-32.dtsi
new file mode 100644
index 000000000000..d4fd393e71a8
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-gpios-32.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_fan_32: pmx-fan-32 {
+				marvell,pins = "mpp32";
+				marvell,function = "gpio";
+			};
+			pmx_fan_33: pmx-fan-33 {
+				marvell,pins = "mpp33";
+				marvell,function = "gpo";
+			};
+			pmx_fan_34: pmx-fan-34 {
+				marvell,pins = "mpp34";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio_fan {
+		pinctrl-0 = <&pmx_fan_32 &pmx_fan_33 &pmx_fan_34>;
+		pinctrl-names = "default";
+		gpios = <&gpio1 0 GPIO_ACTIVE_HIGH
+			 &gpio1 1 GPIO_ACTIVE_HIGH
+			 &gpio1 2 GPIO_ACTIVE_HIGH>;
+	};
+};
diff --git a/arch/arm/boot/dts/synology/fan-speed-100.dtsi b/arch/arm/boot/dts/synology/fan-speed-100.dtsi
new file mode 100644
index 000000000000..5188ba59a9b2
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-speed-100.dtsi
@@ -0,0 +1,20 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	gpio_fan {
+		gpio-fan,speed-map = <    0 0
+				       2500 1
+				       3100 2
+				       3800 3
+				       4600 4
+				       4800 5
+				       4900 6
+				       5000 7 >;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/fan-speed-120.dtsi b/arch/arm/boot/dts/synology/fan-speed-120.dtsi
new file mode 100644
index 000000000000..90157070492c
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-speed-120.dtsi
@@ -0,0 +1,20 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	gpio_fan {
+		gpio-fan,speed-map = <    0 0
+				       2500 1
+				       2700 2
+				       3000 4
+				       3600 3
+				       3800 5
+				       3900 6
+				       4300 7 >;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/fan-speed-150.dtsi b/arch/arm/boot/dts/synology/fan-speed-150.dtsi
new file mode 100644
index 000000000000..6abc36915886
--- /dev/null
+++ b/arch/arm/boot/dts/synology/fan-speed-150.dtsi
@@ -0,0 +1,20 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	gpio_fan {
+		gpio-fan,speed-map = <    0 0
+				       2200 1
+				       2500 2
+				       3000 4
+				       3300 3
+				       3700 5
+				       3800 6
+				       4200 7 >;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-leds-20.dtsi b/arch/arm/boot/dts/synology/hdd-leds-20.dtsi
new file mode 100644
index 000000000000..e6663ea7014c
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-leds-20.dtsi
@@ -0,0 +1,90 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_20: pmx-led-20 {
+				marvell,pins = "mpp20";
+				marvell,function = "gpio";
+			};
+			pmx_led_21: pmx-led-21 {
+				marvell,pins = "mpp21";
+				marvell,function = "gpio";
+			};
+			pmx_led_22: pmx-led-22 {
+				marvell,pins = "mpp22";
+				marvell,function = "gpio";
+			};
+			pmx_led_23: pmx-led-23 {
+				marvell,pins = "mpp23";
+				marvell,function = "gpio";
+			};
+			pmx_led_24: pmx-led-24 {
+				marvell,pins = "mpp24";
+				marvell,function = "gpio";
+			};
+			pmx_led_25: pmx-led-25 {
+				marvell,pins = "mpp25";
+				marvell,function = "gpio";
+			};
+			pmx_led_26: pmx-led-26 {
+				marvell,pins = "mpp26";
+				marvell,function = "gpio";
+			};
+			pmx_led_27: pmx-led-27 {
+				marvell,pins = "mpp27";
+				marvell,function = "gpio";
+			};
+			pmx_led_28: pmx-led-28 {
+				marvell,pins = "mpp28";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_20 &pmx_led_21 &pmx_led_22
+			     &pmx_led_23 &pmx_led_24 &pmx_led_25
+			     &pmx_led_26 &pmx_led_27>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:green:hdd1";
+			gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
+		};
+		hdd1-amber {
+			label = "synology:amber:hdd1";
+			gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-green {
+			label = "synology:green:hdd2";
+			gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-amber {
+			label = "synology:amber:hdd2";
+			gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
+		};
+		hdd3-green {
+			label = "synology:green:hdd3";
+			gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
+		};
+		hdd3-amber {
+			label = "synology:amber:hdd3";
+			gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
+		};
+		hdd4-green {
+			label = "synology:green:hdd4";
+			gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
+		};
+		hdd4-amber {
+			label = "synology:amber:hdd4";
+			gpios = <&gpio0 27 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi b/arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi
new file mode 100644
index 000000000000..034323f9ffb0
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-leds-21-1.dtsi
@@ -0,0 +1,36 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_21: pmx-led-21 {
+				marvell,pins = "mpp21";
+				marvell,function = "gpio";
+			};
+			pmx_led_23: pmx-led-23 {
+				marvell,pins = "mpp23";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_21 &pmx_led_23>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:green:hdd1";
+			gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		};
+		hdd1-amber {
+			label = "synology:amber:hdd1";
+			gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi b/arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi
new file mode 100644
index 000000000000..446a28f2200b
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-leds-21-2.dtsi
@@ -0,0 +1,52 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_20: pmx-led-20 {
+				marvell,pins = "mpp20";
+				marvell,function = "gpio";
+			};
+			pmx_led_21: pmx-led-21 {
+				marvell,pins = "mpp21";
+				marvell,function = "gpio";
+			};
+			pmx_led_22: pmx-led-22 {
+				marvell,pins = "mpp22";
+				marvell,function = "gpio";
+			};
+			pmx_led_23: pmx-led-23 {
+				marvell,pins = "mpp23";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_21 &pmx_led_23 &pmx_led_20 &pmx_led_22>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:green:hdd1";
+			gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		};
+		hdd1-amber {
+			label = "synology:amber:hdd1";
+			gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-green {
+			label = "synology:green:hdd2";
+			gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-amber {
+			label = "synology:amber:hdd2";
+			gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-leds-36.dtsi b/arch/arm/boot/dts/synology/hdd-leds-36.dtsi
new file mode 100644
index 000000000000..9541c0c943e6
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-leds-36.dtsi
@@ -0,0 +1,103 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_36: pmx-led-36 {
+				marvell,pins = "mpp36";
+				marvell,function = "gpio";
+			};
+			pmx_led_37: pmx-led-37 {
+				marvell,pins = "mpp37";
+				marvell,function = "gpio";
+			};
+			pmx_led_38: pmx-led-38 {
+				marvell,pins = "mpp38";
+				marvell,function = "gpio";
+			};
+			pmx_led_39: pmx-led-39 {
+				marvell,pins = "mpp39";
+				marvell,function = "gpio";
+			};
+			pmx_led_40: pmx-led-40 {
+				marvell,pins = "mpp40";
+				marvell,function = "gpio";
+			};
+			pmx_led_41: pmx-led-41 {
+				marvell,pins = "mpp41";
+				marvell,function = "gpio";
+			};
+			pmx_led_42: pmx-led-42 {
+				marvell,pins = "mpp42";
+				marvell,function = "gpio";
+			};
+			pmx_led_43: pmx-led-43 {
+				marvell,pins = "mpp43";
+				marvell,function = "gpio";
+			};
+			pmx_led_44: pmx-led-44 {
+				marvell,pins = "mpp44";
+				marvell,function = "gpio";
+			};
+			pmx_led_45: pmx-led-45 {
+				marvell,pins = "mpp45";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_36 &pmx_led_37 &pmx_led_38
+			     &pmx_led_39 &pmx_led_40 &pmx_led_41
+			     &pmx_led_42 &pmx_led_43 &pmx_led_44
+			     &pmx_led_45>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:green:hdd1";
+			gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+		};
+		hdd1-amber {
+			label = "synology:amber:hdd1";
+			gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-green {
+			label = "synology:green:hdd2";
+			gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-amber {
+			label = "synology:amber:hdd2";
+			gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+		};
+		hdd3-green {
+			label = "synology:green:hdd3";
+			gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+		};
+		hdd3-amber {
+			label = "synology:amber:hdd3";
+			gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+		};
+		hdd4-green {
+			label = "synology:green:hdd4";
+			gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+		};
+		hdd4-amber {
+			label = "synology:amber:hdd4";
+			gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
+		};
+		hdd5-green {
+			label = "synology:green:hdd5";
+			gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		};
+		hdd5-amber {
+			label = "synology:amber:hdd5";
+			gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-leds-38.dtsi b/arch/arm/boot/dts/synology/hdd-leds-38.dtsi
new file mode 100644
index 000000000000..d2fe351a0808
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-leds-38.dtsi
@@ -0,0 +1,52 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_led_38: pmx-led-38 {
+				marvell,pins = "mpp38";
+				marvell,function = "gpio";
+			};
+			pmx_led_39: pmx-led-39 {
+				marvell,pins = "mpp39";
+				marvell,function = "gpio";
+			};
+			pmx_led_36: pmx-led-36 {
+				marvell,pins = "mpp36";
+				marvell,function = "gpio";
+			};
+			pmx_led_37: pmx-led-37 {
+				marvell,pins = "mpp37";
+				marvell,function = "gpio";
+			};
+		};
+	};
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pmx_led_38 &pmx_led_39 &pmx_led_36 &pmx_led_37>;
+		pinctrl-names = "default";
+		hdd1-green {
+			label = "synology:green:hdd1";
+			gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
+		};
+		hdd1-amber {
+			label = "synology:amber:hdd1";
+			gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-green {
+			label = "synology:green:hdd2";
+			gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+		};
+		hdd2-amber {
+			label = "synology:amber:hdd2";
+			gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-29.dtsi b/arch/arm/boot/dts/synology/hdd-power-29.dtsi
new file mode 100644
index 000000000000..8b08c86ab942
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-29.dtsi
@@ -0,0 +1,56 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd1_pwr_29: pmx-hdd1-pwr-29 {
+				marvell,pins = "mpp29";
+				marvell,function = "gpio";
+			};
+			pmx_hdd2_pwr_31: pmx-hdd2-pwr-31 {
+				marvell,pins = "mpp31";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd1_pwr_29 &pmx_hdd2_pwr_31>;
+		pinctrl-names = "default";
+
+		hdd1_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "hdd1power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+		};
+		hdd2_power: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "hdd2power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 31 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-30-1.dtsi b/arch/arm/boot/dts/synology/hdd-power-30-1.dtsi
new file mode 100644
index 000000000000..b0998d4e231f
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-30-1.dtsi
@@ -0,0 +1,40 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd1_pwr_30: pmx-hdd-pwr-30 {
+				marvell,pins = "mpp30";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd1_pwr_30>;
+		pinctrl-names = "default";
+
+		hdd1_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "hdd1power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 30 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-30-2.dtsi b/arch/arm/boot/dts/synology/hdd-power-30-2.dtsi
new file mode 100644
index 000000000000..766e6352d5af
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-30-2.dtsi
@@ -0,0 +1,56 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd1_pwr_30: pmx-hdd-pwr-30 {
+				marvell,pins = "mpp30";
+				marvell,function = "gpio";
+			};
+			pmx_hdd2_pwr_34: pmx-hdd2-pwr-34 {
+				marvell,pins = "mpp34";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd1_pwr_30 &pmx_hdd2_pwr_34>;
+		pinctrl-names = "default";
+
+		hdd1_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "hdd1power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 30 GPIO_ACTIVE_HIGH>;
+		};
+		hdd2_power: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "hdd2power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-30-4.dtsi b/arch/arm/boot/dts/synology/hdd-power-30-4.dtsi
new file mode 100644
index 000000000000..5bbced207965
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-30-4.dtsi
@@ -0,0 +1,89 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd1_pwr_30: pmx-hdd-pwr-30 {
+				marvell,pins = "mpp30";
+				marvell,function = "gpio";
+			};
+			pmx_hdd2_pwr_34: pmx-hdd2-pwr-34 {
+				marvell,pins = "mpp34";
+				marvell,function = "gpio";
+			};
+			pmx_hdd3_pwr_44: pmx-hdd3-pwr-44 {
+				marvell,pins = "mpp44";
+				marvell,function = "gpio";
+			};
+			pmx_hdd4_pwr_45: pmx-hdd4-pwr-45 {
+				marvell,pins = "mpp45";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd1_pwr_30 &pmx_hdd2_pwr_34
+			     &pmx_hdd3_pwr_44 &pmx_hdd4_pwr_45>;
+		pinctrl-names = "default";
+
+		hdd1_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "hdd1power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 30 GPIO_ACTIVE_HIGH>;
+		};
+		hdd2_power: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "hdd2power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+		};
+		hdd3_power: regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "hdd3power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+		};
+		hdd4_power: regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "hdd3power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 32 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-31.dtsi b/arch/arm/boot/dts/synology/hdd-power-31.dtsi
new file mode 100644
index 000000000000..0774ecdcaf64
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-31.dtsi
@@ -0,0 +1,40 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd2_pwr_31: pmx-hdd2-pwr-31 {
+				marvell,pins = "mpp31";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd2_pwr_31>;
+		pinctrl-names = "default";
+
+		hdd2_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "hdd2power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio0 31 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/hdd-power-34.dtsi b/arch/arm/boot/dts/synology/hdd-power-34.dtsi
new file mode 100644
index 000000000000..d90becf582f1
--- /dev/null
+++ b/arch/arm/boot/dts/synology/hdd-power-34.dtsi
@@ -0,0 +1,73 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		pinctrl: pinctrl@10000 {
+
+			pmx_hdd2_pwr_34: pmx-hdd2-pwr-34 {
+				marvell,pins = "mpp34";
+				marvell,function = "gpio";
+			};
+			pmx_hdd3_pwr_44: pmx-hdd3-pwr-44 {
+				marvell,pins = "mpp44";
+				marvell,function = "gpio";
+			};
+			pmx_hdd4_pwr_45: pmx-hdd4-pwr-45 {
+				marvell,pins = "mpp45";
+				marvell,function = "gpio";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_hdd2_pwr_34 &pmx_hdd3_pwr_44
+			     &pmx_hdd4_pwr_45>;
+		pinctrl-names = "default";
+
+		hdd2_power: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "hdd2power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+		};
+		hdd3_power: regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "hdd3power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+		};
+		hdd4_power: regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "hdd3power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			startup-delay-us = <5000000>;
+			gpio = <&gpio1 32 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi b/arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi
new file mode 100644
index 000000000000..2305bc8b0a06
--- /dev/null
+++ b/arch/arm/boot/dts/synology/i2c-rtc-ricoh.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		i2c@11000 {
+			rs5c372: rs5c372@32 {
+				compatible = "ricoy,rs5c372a";
+				reg = <0x32>;
+			};
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi b/arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi
new file mode 100644
index 000000000000..4b5054bb4a87
--- /dev/null
+++ b/arch/arm/boot/dts/synology/i2c-rtc-seiko.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	ocp@f1000000 {
+		i2c@11000 {
+			s35390a: s35390a@30 {
+				compatible = "sii,s35390a";
+				reg = <0x30>;
+			};
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/synology/pcie-2.dtsi b/arch/arm/boot/dts/synology/pcie-2.dtsi
new file mode 100644
index 000000000000..e34ebb5515c2
--- /dev/null
+++ b/arch/arm/boot/dts/synology/pcie-2.dtsi
@@ -0,0 +1,19 @@
+/*
+ * Nodes which are common to all Synology devices
+ *
+ * Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/ {
+	mbus {
+		pcie-controller {
+			pcie@2,0 {
+				status = "okay";
+			};
+		};
+	};
+};
\ No newline at end of file
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v3 4/6] iio: Add ABI docs for pulse capture devices
From: Jonathan Cameron @ 2014-02-15 11:40 UTC (permalink / raw)
  To: Matt Porter, Grant Likely, Rob Herring, Benoît Cousson,
	Tony Lindgren, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Thierry Reding
  Cc: Linux IIO List, Linux Kernel Mailing List, Devicetree List,
	Linux PWM List, Linux OMAP List, Linux ARM Kernel List,
	Lars-Peter Clausen
In-Reply-To: <1391626901-31684-5-git-send-email-mporter@linaro.org>

On 05/02/14 19:01, Matt Porter wrote:
> Add standard ABI entries for pulse capture devices. Also add
> a separate ABI entry for the TI ECAP driver polarity option.
>
> Signed-off-by: Matt Porter <mporter@linaro.org>
Lars, I've cc'd you for the various Analog devices dds and frequency devices.
Ideally we want a consistent interface for devices capturing info about these
waveforms and devices generating them.  Please CC anyone else who might have
opinions.  This interface is not obvious, so we need to spend some time getting
it right.
> ---
>   Documentation/ABI/testing/sysfs-bus-iio              | 18 ++++++++++++++++++
>   Documentation/ABI/testing/sysfs-bus-iio-pulse-tiecap |  9 +++++++++
>   2 files changed, 27 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-pulse-tiecap
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 6e02c50..918a201 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -210,6 +210,14 @@ Contact:	linux-iio@vger.kernel.org
>   Description:
>   		Scaled humidity measurement in milli percent.
>
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulseY_raw
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulse_raw
> +KernelVersion:	3.15
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		Raw pulse measurement from channel Y. Units after
> +		application of scale and offset are nanoseconds.
> +
I wonder if we are being a little bit too specific in this interface.  What other things
might we want to capture about a pulse?  Right now you have it either capturing the
'high width' or the 'low width'.  Presumably there are devices that will capture
both via different 'channels'?

So lets list what we might capture about a wave - including values computable from
the base quantities.
* High time
* Low time
* Mark Space Ratio
* Period (rising edge to rising edge  or falling edge to falling edge).
(This might be treated as instantaneous frequency - as would be done in
frequency modulation)
* Peak to peak Amplitude.

For imperfect waves
* Rise time,
* Fall time,

Funnily enough this is pretty much what an oscilloscope will allow you to automatically
measure on a square wave...

So next question is base units for the time measurements.
I'd prefer the base to be seconds rather than nano seconds
for consistency with the other time measurements already in the ABI.  All it will do is
change the type for scale factors output in sysfs.  Userspace can trivially convert
back to nano seconds if that is what it wants.  If we need to futher expand our small
units, then that is fine.

Next, the question is do we want to cover other waveform types. The dds drivers that
are most relevant are still in staging, so we can mess around with their interfaces
without 'too' much pain.  They allow specifying of a waveform 'type' (square, triangle,
sine so far I think).

So do we want to have an iio type corresponding to a time feature of a waveform then
use modifiers for the various characteristics. I'll describe this in the sysfs attribute
names (they translate directly into the buffer channels, but are easier to read!)


We do have a few modifiers that lead to different units already so there is precedence
e.g. IIO_MOD_SUM_SQUARED_X_Y_Z, (often (m/s^2)^2
for the following (as long as well documented!)
in_waveformX_type - (Square, triangle etc).

in_waveformX_hightime_raw
in_waveformX_lowtime_raw
in_waveformX_period_raw
in_waveformX_markspace_raw
in_waveformX_peaktopeak_raw (similar to existing peak abi elements - these are not typically
                             read from a buffer and hence we have rushed them in as a modifier).
in_waveformX_risetime_raw
in_waveformX_falltime_raw


Would this work for both this sort of capture device and for synthesis chips?



>   What:		/sys/bus/iio/devices/iio:deviceX/in_accel_offset
>   What:		/sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
>   What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
> @@ -220,6 +228,8 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_tempY_offset
>   What:		/sys/bus/iio/devices/iio:deviceX/in_temp_offset
>   What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
>   What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_offset
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulseY_offset
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulse_offset
>   KernelVersion:	2.6.35
>   Contact:	linux-iio@vger.kernel.org
>   Description:
> @@ -251,6 +261,8 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
>   What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
>   What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
>   What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulseY_scale
> +What:		/sys/bus/iio/devices/iio:deviceX/in_pulse_scale
>   KernelVersion:	2.6.35
>   Contact:	linux-iio@vger.kernel.org
>   Description:
> @@ -784,6 +796,8 @@ What:		/sys/.../iio:deviceX/scan_elements/in_incli_x_en
>   What:		/sys/.../iio:deviceX/scan_elements/in_incli_y_en
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressureY_en
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressure_en
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulseY_en
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulse_en
>   KernelVersion:	2.6.37
>   Contact:	linux-iio@vger.kernel.org
>   Description:
> @@ -799,6 +813,8 @@ What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
>   What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_type
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressureY_type
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressure_type
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulseY_type
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulse_type
>   KernelVersion:	2.6.37
>   Contact:	linux-iio@vger.kernel.org
>   Description:
> @@ -845,6 +861,8 @@ What:		/sys/.../iio:deviceX/scan_elements/in_incli_y_index
>   What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_index
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressureY_index
>   What:		/sys/.../iio:deviceX/scan_elements/in_pressure_index
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulseY_index
> +What:		/sys/.../iio:deviceX/scan_elements/in_pulse_index
>   KernelVersion:	2.6.37
>   Contact:	linux-iio@vger.kernel.org
>   Description:
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-pulse-tiecap b/Documentation/ABI/testing/sysfs-bus-iio-pulse-tiecap
> new file mode 100644
> index 0000000..a9e4a9f
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-pulse-tiecap
> @@ -0,0 +1,9 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/pulse_polarityY
> +What:		/sys/bus/iio/devices/iio:deviceX/pulse_polarity
> +Date:		January 2014
> +KernelVersion:	3.15
> +Contact:	Matt Porter <mporter@linaro.org>
> +Description:
> +		Get and set the polarity of the pulse signal to be captured
> +		for channel Y.  1 indicates a high pulse signal and 0
> +		indicates a low pulse signal.
>


^ permalink raw reply

* Re: [PATCH v3 3/6] iio: enable selection and build of pulse drivers
From: Jonathan Cameron @ 2014-02-15 11:41 UTC (permalink / raw)
  To: Matt Porter, Grant Likely, Rob Herring, Benoît Cousson,
	Tony Lindgren, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Thierry Reding
  Cc: Linux IIO List, Linux Kernel Mailing List, Devicetree List,
	Linux PWM List, Linux OMAP List, Linux ARM Kernel List
In-Reply-To: <1391626901-31684-4-git-send-email-mporter-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On 05/02/14 19:01, Matt Porter wrote:
> Add the pulse driver subdirectory when configuring and building
> IIO.
>
> Signed-off-by: Matt Porter <mporter-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hi Matt,

This wants rolling into the driver patch before it.  No point it giving it
it's own patch.  This will just lead to confusion on git bisections etc.


Jonathan
> ---
>   drivers/iio/Kconfig  | 1 +
>   drivers/iio/Makefile | 1 +
>   2 files changed, 2 insertions(+)
>
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index 5dd0e12..286acc3 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -74,6 +74,7 @@ if IIO_TRIGGER
>      source "drivers/iio/trigger/Kconfig"
>   endif #IIO_TRIGGER
>   source "drivers/iio/pressure/Kconfig"
> +source "drivers/iio/pulse/Kconfig"
>   source "drivers/iio/temperature/Kconfig"
>
>   endif # IIO
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> index 887d390..9a953c9 100644
> --- a/drivers/iio/Makefile
> +++ b/drivers/iio/Makefile
> @@ -24,5 +24,6 @@ obj-y += light/
>   obj-y += magnetometer/
>   obj-y += orientation/
>   obj-y += pressure/
> +obj-y += pulse/
>   obj-y += temperature/
>   obj-y += trigger/
>

^ permalink raw reply

* Re: [PATCH v3 6/6] ARM: dts: AM33XX: Add ecap interrupt properties
From: Jonathan Cameron @ 2014-02-15 11:43 UTC (permalink / raw)
  To: Matt Porter, Grant Likely, Rob Herring, Benoît Cousson,
	Tony Lindgren, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Thierry Reding
  Cc: Linux IIO List, Linux Kernel Mailing List, Devicetree List,
	Linux PWM List, Linux OMAP List, Linux ARM Kernel List
In-Reply-To: <1391626901-31684-7-git-send-email-mporter@linaro.org>

On 05/02/14 19:01, Matt Porter wrote:
> Add missing interrupt properties to the ecap0, ecap1, and ecap2
> nodes.
>
> Signed-off-by: Matt Porter <mporter@linaro.org>
This one is unconnected from the rest of the series really so should go
into the relevant arch tree whenever it make sense.

Jonathan
> ---
>   arch/arm/boot/dts/am33xx.dtsi | 6 ++++++
>   1 file changed, 6 insertions(+)
>
> diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
> index 6d95d3d..b4139ba 100644
> --- a/arch/arm/boot/dts/am33xx.dtsi
> +++ b/arch/arm/boot/dts/am33xx.dtsi
> @@ -582,6 +582,8 @@
>   				compatible = "ti,am33xx-ecap";
>   				#pwm-cells = <3>;
>   				reg = <0x48300100 0x80>;
> +				interrupts = <31>;
> +				interrupt-names = "ecap0";
>   				ti,hwmods = "ecap0";
>   				status = "disabled";
>   			};
> @@ -610,6 +612,8 @@
>   				compatible = "ti,am33xx-ecap";
>   				#pwm-cells = <3>;
>   				reg = <0x48302100 0x80>;
> +				interrupts = <47>;
> +				interrupt-names = "ecap1";
>   				ti,hwmods = "ecap1";
>   				status = "disabled";
>   			};
> @@ -638,6 +642,8 @@
>   				compatible = "ti,am33xx-ecap";
>   				#pwm-cells = <3>;
>   				reg = <0x48304100 0x80>;
> +				interrupts = <61>;
> +				interrupt-names = "ecap2";
>   				ti,hwmods = "ecap2";
>   				status = "disabled";
>   			};
>


^ permalink raw reply

* Re: [PATCH v3 0/6] IIO pulse capture support for TI ECAP
From: Jonathan Cameron @ 2014-02-15 11:48 UTC (permalink / raw)
  To: Sergei Shtylyov, Matt Porter, Grant Likely, Rob Herring,
	Benoît Cousson, Tony Lindgren, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Thierry Reding
  Cc: Devicetree List, Linux PWM List, Linux IIO List,
	Linux Kernel Mailing List, Linux OMAP List, Linux ARM Kernel List
In-Reply-To: <52F29DBD.9050305-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

On 05/02/14 20:23, Sergei Shtylyov wrote:
> Hello.
>
> On 02/05/2014 10:01 PM, Matt Porter wrote:
>
> [...]
>
>> This series adds support for PWM capture devices within IIO and
>> adds a TI ECAP IIO driver.
>
>> PWM capture devices are supported using a new IIO "pulse" channel type.
>
>> The IIO ECAP driver implements interrupt driven triggered buffer capture
>> only as raw sample reads are not applicable to this hardware.
>> Initially, the driver supports a single pulse width measurement with
>> configurable polarity. The ECAP hardware can support measurement of a
>> complete period and duty cycle but this is not yet implemented.
>

> How about pulse counting? I have the hardware that can also
> countpulses in addition to measuring the periods, so I'm interested
> in this work (initially I supported it in driver/misc/ but it got
> turned down for iio).
>
I'm afraid I'd forgotten this completely if you can dig out some links
to that discussion it would be great. Only one I can find right now
is a request that you post an ABI introducing this as a generic pulse
counter rather than a speed measurement.

Good point though - under my previous sketched outline, perhaps

in_waveform_cyclecount_input?  (I would imagine that it doesn't come
out needing scaling!)

> WBR, Sergei
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v3 0/3] Add Xilinx AXI Video DMA Engine driver
From: Srikanth Thokala @ 2014-02-15 12:00 UTC (permalink / raw)
  To: dan.j.williams, vinod.koul, michal.simek, grant.likely, robh+dt
  Cc: devicetree, levex, lars, linux-kernel, Srikanth Thokala,
	dmaengine, andriy.shevchenko, linux-arm-kernel

Hi,

This is the driver for Xilinx AXI Video Direct Memory Access Engine.
It is a soft IP core, which provides high-bandwidth direct memory
access between memory and AXI4-Stream video type target peripherals
including peripherals which support AXI4-Stream Video Protocol. The
core provides efficient two dimensional DMA operations with independent
asynchronous read and write channel operation.

For more information on the IP, please refer to
http://www.xilinx.com/support/documentation/ip_documentation/axi_vdma/v6_1/pg020_axi_vdma.pdf

This patch also provides a test client, which assumes read and write channels
of the core are configured in a back-to-back connection.  It transfers
data on the write channel, read and verify the data on the read channel.

Use cases:
++++++++++
1. Xilinx Video Targeted Reference design
   http://www.wiki.xilinx.com/Zynq+Base+TRD+14.5
2. Common Display Framework
   http://events.linuxfoundation.org/sites/events/files/slides/20131024-elce.pdf

Regards,
Srikanth

Changes in v3:
- Created a separate patch for the DT binding documentation as suggested by
  Vinod, Thanks.
- Added support for interleaved frames with non-contiguous memory as suggested
  by Lars, Thanks.
- Rebased on v3.14.0-rc2 

Srikanth Thokala (3):
  dma: Support multiple interleaved frames with non-contiguous memory
  dma: Add Xilinx Video DMA DT Binding Documentation
  dma: Add Xilinx AXI Video Direct Memory Access Engine driver support

 .../devicetree/bindings/dma/xilinx/xilinx_vdma.txt |   75 ++
 Documentation/dmaengine.txt                        |    2 +-
 drivers/dma/Kconfig                                |   14 +
 drivers/dma/Makefile                               |    1 +
 drivers/dma/imx-dma.c                              |    3 +-
 drivers/dma/sirf-dma.c                             |    3 +-
 drivers/dma/xilinx/Makefile                        |    1 +
 drivers/dma/xilinx/xilinx_vdma.c                   | 1388 ++++++++++++++++++++
 drivers/media/platform/m2m-deinterlace.c           |    2 +-
 include/linux/amba/xilinx_dma.h                    |   46 +
 include/linux/dmaengine.h                          |    6 +-
 11 files changed, 1534 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
 create mode 100644 drivers/dma/xilinx/Makefile
 create mode 100644 drivers/dma/xilinx/xilinx_vdma.c
 create mode 100644 include/linux/amba/xilinx_dma.h

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v3 1/3] dma: Support multiple interleaved frames with non-contiguous memory
From: Srikanth Thokala @ 2014-02-15 12:00 UTC (permalink / raw)
  To: dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	vinod.koul-ral2JQCrhuEAvxtiuMwx3w,
	michal.simek-gjFFaj9aHVfQT0dZR+AlfA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A
  Cc: levex-vYTEC60ixJUAvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Srikanth Thokala
In-Reply-To: <1392465619-27614-1-git-send-email-sthokal-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>

The current implementation of interleaved DMA API support multiple
frames only when the memory is contiguous by incrementing src_start/
dst_start members of interleaved template.

But, when the memory is non-contiguous it will restrict slave device
to not submit multiple frames in a batch.  This patch handles this
issue by allowing the slave device to send array of interleaved dma
templates each having a different memory location.

Signed-off-by: Srikanth Thokala <sthokal-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
---
 Documentation/dmaengine.txt              |    2 +-
 drivers/dma/imx-dma.c                    |    3 ++-
 drivers/dma/sirf-dma.c                   |    3 ++-
 drivers/media/platform/m2m-deinterlace.c |    2 +-
 include/linux/dmaengine.h                |    6 +++---
 5 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt
index 879b6e3..c642614 100644
--- a/Documentation/dmaengine.txt
+++ b/Documentation/dmaengine.txt
@@ -94,7 +94,7 @@ The slave DMA usage consists of following steps:
 		size_t period_len, enum dma_data_direction direction);
 
 	struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
-		struct dma_chan *chan, struct dma_interleaved_template *xt,
+		struct dma_chan *chan, struct dma_interleaved_template **xts,
 		unsigned long flags);
 
    The peripheral driver is expected to have mapped the scatterlist for
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 6f9ac20..e2c52ce 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -954,12 +954,13 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
-	struct dma_chan *chan, struct dma_interleaved_template *xt,
+	struct dma_chan *chan, struct dma_interleaved_template **xts,
 	unsigned long flags)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
 	struct imxdma_desc *desc;
+	struct dma_interleaved_template *xt = *xts;
 
 	dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%llx dst_start=0x%llx\n"
 		"   src_sgl=%s dst_sgl=%s numf=%zu frame_size=%zu\n", __func__,
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index d4d3a31..b6a150b 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -509,12 +509,13 @@ sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 }
 
 static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
-	struct dma_chan *chan, struct dma_interleaved_template *xt,
+	struct dma_chan *chan, struct dma_interleaved_template **xts,
 	unsigned long flags)
 {
 	struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
 	struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
 	struct sirfsoc_dma_desc *sdesc = NULL;
+	struct dma_interleaved_template *xt = *xts;
 	unsigned long iflags;
 	int ret;
 
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 6bb86b5..468110a 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -343,7 +343,7 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
 	ctx->xt->dst_sgl = true;
 	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 
-	tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
+	tx = dmadev->device_prep_interleaved_dma(chan, &ctx->xt, flags);
 	if (tx == NULL) {
 		v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep error\n");
 		return;
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c5c92d5..2f77a9a 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -675,7 +675,7 @@ struct dma_device {
 		size_t period_len, enum dma_transfer_direction direction,
 		unsigned long flags, void *context);
 	struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
-		struct dma_chan *chan, struct dma_interleaved_template *xt,
+		struct dma_chan *chan, struct dma_interleaved_template **xts,
 		unsigned long flags);
 	int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		unsigned long arg);
@@ -752,10 +752,10 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
 }
 
 static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
-		struct dma_chan *chan, struct dma_interleaved_template *xt,
+		struct dma_chan *chan, struct dma_interleaved_template **xts,
 		unsigned long flags)
 {
-	return chan->device->device_prep_interleaved_dma(chan, xt, flags);
+	return chan->device->device_prep_interleaved_dma(chan, xts, flags);
 }
 
 static inline int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v3 2/3] dma: Add Xilinx Video DMA DT Binding Documentation
From: Srikanth Thokala @ 2014-02-15 12:00 UTC (permalink / raw)
  To: dan.j.williams, vinod.koul, michal.simek, grant.likely, robh+dt
  Cc: levex, lars, andriy.shevchenko, dmaengine, linux-arm-kernel,
	linux-kernel, devicetree, Srikanth Thokala
In-Reply-To: <1392465619-27614-1-git-send-email-sthokal@xilinx.com>

Device-tree binding documentation of Xilinx Video DMA Engine

Signed-off-by: Srikanth Thokala <sthokal@xilinx.com>
---
Changes in v3:
None

Changes in v2:
- Removed device-id DT property, as suggested by Arnd Bergmann
- Properly documented DT bindings as suggested by Arnd Bergmann
---
 .../devicetree/bindings/dma/xilinx/xilinx_vdma.txt |   75 ++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt

diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
new file mode 100644
index 0000000..ab8be1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
@@ -0,0 +1,75 @@
+Xilinx AXI VDMA engine, it does transfers between memory and video devices.
+It can be configured to have one channel or two channels. If configured
+as two channels, one is to transmit to the video device and another is
+to receive from the video device.
+
+Required properties:
+- compatible: Should be "xlnx,axi-vdma-1.00.a"
+- #dma-cells: Should be <1>, see "dmas" property below
+- reg: Should contain VDMA registers location and length.
+- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
+- dma-channel child node: Should have atleast one channel and can have upto
+	two channels per device. This node specifies the properties of each
+	DMA channel (see child node properties below).
+
+Optional properties:
+- xlnx,include-sg: Tells whether configured for Scatter-mode in
+	the hardware.
+- xlnx,flush-fsync: Tells whether which channel to Flush on Frame sync.
+	It takes following values:
+	{1}, flush both channels
+	{2}, flush mm2s channel
+	{3}, flush s2mm channel
+
+Required child node properties:
+- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or
+	"xlnx,axi-vdma-s2mm-channel".
+- interrupts: Should contain per channel VDMA interrupts.
+- xlnx,data-width: Should contain the stream data width, take values
+	{32,64...1024}.
+
+Option child node properties:
+- xlnx,include-dre: Tells whether hardware is configured for Data
+	Realignment Engine.
+- xlnx,genlock-mode: Tells whether Genlock synchronization is
+	enabled/disabled in hardware.
+
+Example:
+++++++++
+
+axi_vdma_0: axivdma@40030000 {
+	compatible = "xlnx,axi-vdma-1.00.a";
+	#dma_cells = <1>;
+	reg = < 0x40030000 0x10000 >;
+	xlnx,num-fstores = <0x8>;
+	xlnx,flush-fsync = <0x1>;
+	dma-channel@40030000 {
+		compatible = "xlnx,axi-vdma-mm2s-channel";
+		interrupts = < 0 54 4 >;
+		xlnx,datawidth = <0x40>;
+	} ;
+	dma-channel@40030030 {
+		compatible = "xlnx,axi-vdma-s2mm-channel";
+		interrupts = < 0 53 4 >;
+		xlnx,datawidth = <0x40>;
+	} ;
+} ;
+
+
+* DMA client
+
+Required properties:
+- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
+	where Channel ID is '0' for write/tx and '1' for read/rx
+	channel.
+- dma-names: a list of DMA channel names, one per "dmas" entry
+
+Example:
+++++++++
+
+vdmatest_0: vdmatest@0 {
+	compatible ="xlnx,axi-vdma-test-1.00.a";
+	dmas = <&axi_vdma_0 0
+		&axi_vdma_0 1>;
+	dma-names = "vdma0", "vdma1";
+} ;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v3 3/3] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Srikanth Thokala @ 2014-02-15 12:00 UTC (permalink / raw)
  To: dan.j.williams, vinod.koul, michal.simek, grant.likely, robh+dt
  Cc: levex, lars, andriy.shevchenko, dmaengine, linux-arm-kernel,
	linux-kernel, devicetree, Srikanth Thokala
In-Reply-To: <1392465619-27614-1-git-send-email-sthokal@xilinx.com>

This is the driver for the AXI Video Direct Memory Access (AXI
VDMA) core, which is a soft Xilinx IP core that provides high-
bandwidth direct memory access between memory and AXI4-Stream
type video target peripherals. The core provides efficient two
dimensional DMA operations with independent asynchronous read
and write channel operation.

This module works on Zynq (ARM Based SoC) and Microblaze platforms.

Signed-off-by: Srikanth Thokala <sthokal@xilinx.com>
Reviewed-by: Levente Kurusa <levex@linux.com>
---
NOTE:
- Created a separate directory 'dma/xilinx' as Xilinx has two more
  DMA IPs and we are also planning to upstream these drivers soon.

Changes in v3:
- Implemented interleaved DMA API as suggested by Vinod and Lars, Thanks.
- Use dma_slave_config generic API as suggested by Vinod and Lars, Thanks.
- Simplified cookie implementation as sugguested by Vinod, Thanks.
- Simplified *_xlate function by using dma_get_slave_channel() as
  suggested by Lars, Thanks.
- Proper indentation of constants and maintained same multi-line of
  comments as suggested by Andy Shevchenko, Thanks.
- Modified to use request_irq() instead of devm_request_irq as suggested
  by Lars, Thanks.
- Fixed minor comments suggested by Andy and Levente, Thanks.

Changes in v2:
- Removed DMA Test client module from the patchset as suggested
  by Andy Shevchenko
- Returning with error, if registration of DMA to node fails
- Fixed typo errors
- Used BIT() macro at applicable places
- Added missing header file to the patchset
- Changed copyright year to include 2014
---
 drivers/dma/Kconfig              |   14 +
 drivers/dma/Makefile             |    1 +
 drivers/dma/xilinx/Makefile      |    1 +
 drivers/dma/xilinx/xilinx_vdma.c | 1388 ++++++++++++++++++++++++++++++++++++++
 include/linux/amba/xilinx_dma.h  |   46 ++
 5 files changed, 1450 insertions(+)
 create mode 100644 drivers/dma/xilinx/Makefile
 create mode 100644 drivers/dma/xilinx/xilinx_vdma.c
 create mode 100644 include/linux/amba/xilinx_dma.h

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9bed1a2..53a1fa6 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -350,6 +350,20 @@ config MOXART_DMA
 	help
 	  Enable support for the MOXA ART SoC DMA controller.
 
+config XILINX_VDMA
+	tristate "Xilinx AXI VDMA Engine"
+	depends on (ARCH_ZYNQ || MICROBLAZE)
+	select DMA_ENGINE
+	help
+	  Enable support for Xilinx AXI VDMA Soft IP.
+
+	  This engine provides high-bandwidth direct memory access
+	  between memory and AXI4-Stream video type target
+	  peripherals including peripherals which support AXI4-
+	  Stream Video Protocol.  It has two stream interfaces/
+	  channels, Memory Mapped to Stream (MM2S) and Stream to
+	  Memory Mapped (S2MM) for the data transfers.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a029d0f4..fa38a77 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
 obj-$(CONFIG_TI_CPPI41) += cppi41.o
 obj-$(CONFIG_K3_DMA) += k3dma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
+obj-y += xilinx/
diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile
new file mode 100644
index 0000000..3c4e9f2
--- /dev/null
+++ b/drivers/dma/xilinx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
new file mode 100644
index 0000000..fde6a9c
--- /dev/null
+++ b/drivers/dma/xilinx/xilinx_vdma.c
@@ -0,0 +1,1388 @@
+/*
+ * DMA driver for Xilinx Video DMA Engine
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * Based on the Freescale DMA driver.
+ *
+ * Description:
+ * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
+ * core that provides high-bandwidth direct memory access between memory
+ * and AXI4-Stream type video target peripherals. The core provides efficient
+ * two dimensional DMA operations with independent asynchronous read (S2MM)
+ * and write (MM2S) channel operation. It can be configured to have either
+ * one channel or two channels. If configured as two channels, one is to
+ * transmit to the video device (MM2S) and another is to receive from the
+ * video device (S2MM). Initialization, status, interrupt and management
+ * registers are accessed through an AXI4-Lite slave interface.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/amba/xilinx_dma.h>
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+#include "../dmaengine.h"
+
+/* Register/Descriptor Offsets */
+#define XILINX_VDMA_MM2S_CTRL_OFFSET		0x0000
+#define XILINX_VDMA_S2MM_CTRL_OFFSET		0x0030
+#define XILINX_VDMA_MM2S_DESC_OFFSET		0x0050
+#define XILINX_VDMA_S2MM_DESC_OFFSET		0x00a0
+
+/* Control Registers */
+#define XILINX_VDMA_REG_DMACR			0x0000
+#define XILINX_VDMA_DMACR_DELAY_MAX		0xff
+#define XILINX_VDMA_DMACR_DELAY_SHIFT		24
+#define XILINX_VDMA_DMACR_FRAME_COUNT_MAX	0xff
+#define XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT	16
+#define XILINX_VDMA_DMACR_ERR_IRQ		BIT(14)
+#define XILINX_VDMA_DMACR_DLY_CNT_IRQ		BIT(13)
+#define XILINX_VDMA_DMACR_FRM_CNT_IRQ		BIT(12)
+#define XILINX_VDMA_DMACR_MASTER_SHIFT		8
+#define XILINX_VDMA_DMACR_FSYNCSRC_SHIFT	5
+#define XILINX_VDMA_DMACR_FRAMECNT_EN		BIT(4)
+#define XILINX_VDMA_DMACR_GENLOCK_EN		BIT(3)
+#define XILINX_VDMA_DMACR_RESET			BIT(2)
+#define XILINX_VDMA_DMACR_CIRC_EN		BIT(1)
+#define XILINX_VDMA_DMACR_RUNSTOP		BIT(0)
+#define XILINX_VDMA_DMACR_FSYNCSRC_MASK		GENMASK(6, 5)
+
+#define XILINX_VDMA_REG_DMASR			0x0004
+#define XILINX_VDMA_DMASR_EOL_LATE_ERR		BIT(15)
+#define XILINX_VDMA_DMASR_ERR_IRQ		BIT(14)
+#define XILINX_VDMA_DMASR_DLY_CNT_IRQ		BIT(13)
+#define XILINX_VDMA_DMASR_FRM_CNT_IRQ		BIT(12)
+#define XILINX_VDMA_DMASR_SOF_LATE_ERR		BIT(11)
+#define XILINX_VDMA_DMASR_SG_DEC_ERR		BIT(10)
+#define XILINX_VDMA_DMASR_SG_SLV_ERR		BIT(9)
+#define XILINX_VDMA_DMASR_EOF_EARLY_ERR		BIT(8)
+#define XILINX_VDMA_DMASR_SOF_EARLY_ERR		BIT(7)
+#define XILINX_VDMA_DMASR_DMA_DEC_ERR		BIT(6)
+#define XILINX_VDMA_DMASR_DMA_SLAVE_ERR		BIT(5)
+#define XILINX_VDMA_DMASR_DMA_INT_ERR		BIT(4)
+#define XILINX_VDMA_DMASR_IDLE			BIT(1)
+#define XILINX_VDMA_DMASR_HALTED		BIT(0)
+#define XILINX_VDMA_DMASR_DELAY_MASK		GENMASK(31, 24)
+#define XILINX_VDMA_DMASR_FRAME_COUNT_MASK	GENMASK(23, 16)
+
+#define XILINX_VDMA_REG_CURDESC			0x0008
+#define XILINX_VDMA_REG_TAILDESC		0x0010
+#define XILINX_VDMA_REG_REG_INDEX		0x0014
+#define XILINX_VDMA_REG_FRMSTORE		0x0018
+#define XILINX_VDMA_REG_THRESHOLD		0x001c
+#define XILINX_VDMA_REG_FRMPTR_STS		0x0024
+#define XILINX_VDMA_REG_PARK_PTR		0x0028
+#define XILINX_VDMA_PARK_PTR_WR_REF_SHIFT	8
+#define XILINX_VDMA_PARK_PTR_RD_REF_SHIFT	0
+#define XILINX_VDMA_REG_VDMA_VERSION		0x002c
+
+/* Register Direct Mode Registers */
+#define XILINX_VDMA_REG_VSIZE			0x0000
+#define XILINX_VDMA_REG_HSIZE			0x0004
+
+#define XILINX_VDMA_REG_FRMDLY_STRIDE		0x0008
+#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT	24
+#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT	0
+
+#define XILINX_VDMA_REG_START_ADDRESS(n)	(0x000c + 4 * (n))
+
+/* HW specific definitions */
+#define XILINX_VDMA_MAX_CHANS_PER_DEVICE	0x2
+
+#define XILINX_VDMA_DMAXR_ALL_IRQ_MASK	\
+		(XILINX_VDMA_DMASR_FRM_CNT_IRQ | \
+		 XILINX_VDMA_DMASR_DLY_CNT_IRQ | \
+		 XILINX_VDMA_DMASR_ERR_IRQ)
+
+#define XILINX_VDMA_DMASR_ALL_ERR_MASK	\
+		(XILINX_VDMA_DMASR_EOL_LATE_ERR | \
+		 XILINX_VDMA_DMASR_SOF_LATE_ERR | \
+		 XILINX_VDMA_DMASR_SG_DEC_ERR | \
+		 XILINX_VDMA_DMASR_SG_SLV_ERR | \
+		 XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
+		 XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
+		 XILINX_VDMA_DMASR_DMA_DEC_ERR | \
+		 XILINX_VDMA_DMASR_DMA_SLAVE_ERR | \
+		 XILINX_VDMA_DMASR_DMA_INT_ERR)
+
+/*
+ * Recoverable errors are DMA Internal error, SOF Early, EOF Early
+ * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
+ * is enabled in the h/w system.
+ */
+#define XILINX_VDMA_DMASR_ERR_RECOVER_MASK	\
+		(XILINX_VDMA_DMASR_SOF_LATE_ERR | \
+		 XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
+		 XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
+		 XILINX_VDMA_DMASR_DMA_INT_ERR)
+
+/* Axi VDMA Flush on Fsync bits */
+#define XILINX_VDMA_FLUSH_S2MM		3
+#define XILINX_VDMA_FLUSH_MM2S		2
+#define XILINX_VDMA_FLUSH_BOTH		1
+
+/* Delay loop counter to prevent hardware failure */
+#define XILINX_VDMA_LOOP_COUNT		1000000
+
+/**
+ * struct xilinx_vdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @pad1: Reserved @0x04
+ * @buf_addr: Buffer address @0x08
+ * @pad2: Reserved @0x0C
+ * @vsize: Vertical Size @0x10
+ * @hsize: Horizontal Size @0x14
+ * @stride: Number of bytes between the first
+ *	    pixels of each horizontal line @0x18
+ */
+struct xilinx_vdma_desc_hw {
+	u32 next_desc;
+	u32 pad1;
+	u32 buf_addr;
+	u32 pad2;
+	u32 vsize;
+	u32 hsize;
+	u32 stride;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_vdma_tx_segment {
+	struct xilinx_vdma_desc_hw hw;
+	struct list_head node;
+	dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @segments: TX segments list
+ * @node: Node in the channel descriptors list
+ */
+struct xilinx_vdma_tx_descriptor {
+	struct dma_async_tx_descriptor async_tx;
+	struct list_head segments;
+	struct list_head node;
+};
+
+/**
+ * struct xilinx_vdma_chan - Driver specific VDMA channel structure
+ * @xdev: Driver specific device structure
+ * @ctrl_offset: Control registers offset
+ * @desc_offset: TX descriptor registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @active_desc: Active descriptor
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool: Descriptors pool
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @id: Channel ID
+ * @direction: Transfer direction
+ * @num_frms: Number of frames
+ * @has_sg: Support scatter transfers
+ * @genlock: Support genlock mode
+ * @err: Channel has errors
+ * @tasklet: Cleanup work after irq
+ * @config: Device configuration info
+ * @flush_on_fsync: Flush on Frame sync
+ */
+struct xilinx_vdma_chan {
+	struct xilinx_vdma_device *xdev;
+	u32 ctrl_offset;
+	u32 desc_offset;
+	spinlock_t lock;
+	struct list_head pending_list;
+	struct xilinx_vdma_tx_descriptor *active_desc;
+	struct list_head done_list;
+	struct dma_chan common;
+	struct dma_pool *desc_pool;
+	struct device *dev;
+	int irq;
+	int id;
+	enum dma_transfer_direction direction;
+	int num_frms;
+	bool has_sg;
+	bool genlock;
+	bool err;
+	struct tasklet_struct tasklet;
+	struct xilinx_vdma_config config;
+	bool flush_on_fsync;
+};
+
+/**
+ * struct xilinx_vdma_device - VDMA device structure
+ * @regs: I/O mapped base address
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific VDMA channel
+ * @has_sg: Specifies whether Scatter-Gather is present or not
+ * @flush_on_fsync: Flush on frame sync
+ */
+struct xilinx_vdma_device {
+	void __iomem *regs;
+	struct device *dev;
+	struct dma_device common;
+	struct xilinx_vdma_chan *chan[XILINX_VDMA_MAX_CHANS_PER_DEVICE];
+	bool has_sg;
+	u32 flush_on_fsync;
+};
+
+/* Macros */
+#define to_xilinx_chan(chan) \
+	container_of(chan, struct xilinx_vdma_chan, common)
+#define to_vdma_tx_descriptor(tx) \
+	container_of(tx, struct xilinx_vdma_tx_descriptor, async_tx)
+#define to_xilinx_vdma_config(cfg) \
+	container_of(cfg, struct xilinx_vdma_config, slvcfg)
+
+/* IO accessors */
+static inline u32 vdma_read(struct xilinx_vdma_chan *chan, u32 reg)
+{
+	return ioread32(chan->xdev->regs + reg);
+}
+
+static inline void vdma_write(struct xilinx_vdma_chan *chan, u32 reg, u32 value)
+{
+	iowrite32(value, chan->xdev->regs + reg);
+}
+
+static inline void vdma_desc_write(struct xilinx_vdma_chan *chan, u32 reg,
+				   u32 value)
+{
+	vdma_write(chan, chan->desc_offset + reg, value);
+}
+
+static inline u32 vdma_ctrl_read(struct xilinx_vdma_chan *chan, u32 reg)
+{
+	return vdma_read(chan, chan->ctrl_offset + reg);
+}
+
+static inline void vdma_ctrl_write(struct xilinx_vdma_chan *chan, u32 reg,
+				   u32 value)
+{
+	vdma_write(chan, chan->ctrl_offset + reg, value);
+}
+
+static inline void vdma_ctrl_clr(struct xilinx_vdma_chan *chan, u32 reg,
+				 u32 clr)
+{
+	vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) & ~clr);
+}
+
+static inline void vdma_ctrl_set(struct xilinx_vdma_chan *chan, u32 reg,
+				 u32 set)
+{
+	vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) | set);
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors and segments alloc and free
+ */
+
+/**
+ * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_segment *
+xilinx_vdma_alloc_tx_segment(struct xilinx_vdma_chan *chan)
+{
+	struct xilinx_vdma_tx_segment *segment;
+	dma_addr_t phys;
+
+	segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
+	if (!segment)
+		return NULL;
+
+	memset(segment, 0, sizeof(*segment));
+	segment->phys = phys;
+
+	return segment;
+}
+
+/**
+ * xilinx_vdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific VDMA channel
+ * @segment: VDMA transaction segment
+ */
+static void xilinx_vdma_free_tx_segment(struct xilinx_vdma_chan *chan,
+					struct xilinx_vdma_tx_segment *segment)
+{
+	dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_vdma_tx_descriptor - Allocate transaction descriptor
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: The allocated descriptor on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_descriptor *
+xilinx_vdma_alloc_tx_descriptor(struct xilinx_vdma_chan *chan)
+{
+	struct xilinx_vdma_tx_descriptor *desc;
+
+	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return NULL;
+
+	INIT_LIST_HEAD(&desc->segments);
+
+	return desc;
+}
+
+/**
+ * xilinx_vdma_free_tx_descriptor - Free transaction descriptor
+ * @chan: Driver specific VDMA channel
+ * @desc: VDMA transaction descriptor
+ */
+static void
+xilinx_vdma_free_tx_descriptor(struct xilinx_vdma_chan *chan,
+			       struct xilinx_vdma_tx_descriptor *desc)
+{
+	struct xilinx_vdma_tx_segment *segment, *next;
+
+	if (!desc)
+		return;
+
+	list_for_each_entry_safe(segment, next, &desc->segments, node) {
+		list_del(&segment->node);
+		xilinx_vdma_free_tx_segment(chan, segment);
+	}
+
+	kfree(desc);
+}
+
+/* Required functions */
+
+/**
+ * xilinx_vdma_free_desc_list - Free descriptors list
+ * @chan: Driver specific VDMA channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xilinx_vdma_free_desc_list(struct xilinx_vdma_chan *chan,
+					struct list_head *list)
+{
+	struct xilinx_vdma_tx_descriptor *desc, *next;
+
+	list_for_each_entry_safe(desc, next, list, node) {
+		list_del(&desc->node);
+		xilinx_vdma_free_tx_descriptor(chan, desc);
+	}
+}
+
+/**
+ * xilinx_vdma_free_descriptors - Free channel descriptors
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_free_descriptors(struct xilinx_vdma_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->lock, flags);
+
+	xilinx_vdma_free_desc_list(chan, &chan->pending_list);
+	xilinx_vdma_free_desc_list(chan, &chan->done_list);
+
+	xilinx_vdma_free_tx_descriptor(chan, chan->active_desc);
+	chan->active_desc = NULL;
+
+	spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xilinx_vdma_free_chan_resources(struct dma_chan *dchan)
+{
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+	dev_dbg(chan->dev, "Free all channel resources.\n");
+
+	xilinx_vdma_free_descriptors(chan);
+	dma_pool_destroy(chan->desc_pool);
+	chan->desc_pool = NULL;
+}
+
+/**
+ * xilinx_vdma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_chan_desc_cleanup(struct xilinx_vdma_chan *chan)
+{
+	struct xilinx_vdma_tx_descriptor *desc, *next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->lock, flags);
+
+	list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+		dma_async_tx_callback callback;
+		void *callback_param;
+
+		/* Remove from the list of running transactions */
+		list_del(&desc->node);
+
+		/* Run the link descriptor callback function */
+		callback = desc->async_tx.callback;
+		callback_param = desc->async_tx.callback_param;
+		if (callback) {
+			spin_unlock_irqrestore(&chan->lock, flags);
+			callback(callback_param);
+			spin_lock_irqsave(&chan->lock, flags);
+		}
+
+		/* Run any dependencies, then free the descriptor */
+		dma_run_dependencies(&desc->async_tx);
+		xilinx_vdma_free_tx_descriptor(chan, desc);
+	}
+
+	spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx VDMA channel structure
+ */
+static void xilinx_vdma_do_tasklet(unsigned long data)
+{
+	struct xilinx_vdma_chan *chan = (struct xilinx_vdma_chan *)data;
+
+	xilinx_vdma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xilinx_vdma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+	/* Has this channel already been allocated? */
+	if (chan->desc_pool)
+		return 0;
+
+	/*
+	 * We need the descriptor to be aligned to 64bytes
+	 * for meeting Xilinx VDMA specification requirement.
+	 */
+	chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
+				chan->dev,
+				sizeof(struct xilinx_vdma_tx_segment),
+				__alignof__(struct xilinx_vdma_tx_segment), 0);
+	if (!chan->desc_pool) {
+		dev_err(chan->dev,
+			"unable to allocate channel %d descriptor pool\n",
+			chan->id);
+		return -ENOMEM;
+	}
+
+	dma_cookie_init(dchan);
+	return 0;
+}
+
+/**
+ * xilinx_vdma_tx_status - Get VDMA transaction status
+ * @dchan: DMA channel
+ * @cookie: Transaction identifier
+ * @txstate: Transaction state
+ *
+ * Return: DMA transaction status
+ */
+static enum dma_status xilinx_vdma_tx_status(struct dma_chan *dchan,
+					dma_cookie_t cookie,
+					struct dma_tx_state *txstate)
+{
+	return dma_cookie_status(dchan, cookie, txstate);
+}
+
+/**
+ * xilinx_vdma_is_running - Check if VDMA channel is running
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '1' if running, '0' if not.
+ */
+static int xilinx_vdma_is_running(struct xilinx_vdma_chan *chan)
+{
+	return !(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+		 XILINX_VDMA_DMASR_HALTED) &&
+		(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+		 XILINX_VDMA_DMACR_RUNSTOP);
+}
+
+/**
+ * xilinx_vdma_is_idle - Check if VDMA channel is idle
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '1' if idle, '0' if not.
+ */
+static int xilinx_vdma_is_idle(struct xilinx_vdma_chan *chan)
+{
+	return vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+		XILINX_VDMA_DMASR_IDLE;
+}
+
+/**
+ * xilinx_vdma_halt - Halt VDMA channel
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan)
+{
+	int loop = XILINX_VDMA_LOOP_COUNT;
+
+	vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
+
+	/* Wait for the hardware to halt */
+	do {
+		if (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+		    XILINX_VDMA_DMASR_HALTED)
+			break;
+	} while (loop--);
+
+	if (!loop) {
+		dev_err(chan->dev, "Cannot stop channel %p: %x\n",
+			chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+		chan->err = true;
+	}
+
+	return;
+}
+
+/**
+ * xilinx_vdma_start - Start VDMA channel
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_start(struct xilinx_vdma_chan *chan)
+{
+	int loop = XILINX_VDMA_LOOP_COUNT;
+
+	vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
+
+	/* Wait for the hardware to start */
+	do {
+		if (!(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+		      XILINX_VDMA_DMASR_HALTED))
+			break;
+	} while (loop--);
+
+	if (!loop) {
+		dev_err(chan->dev, "Cannot start channel %p: %x\n",
+			chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+
+		chan->err = true;
+	}
+
+	return;
+}
+
+/**
+ * xilinx_vdma_start_transfer - Starts VDMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
+{
+	struct xilinx_vdma_config *config = &chan->config;
+	struct xilinx_vdma_tx_descriptor *desc;
+	unsigned long flags;
+	u32 reg;
+	struct xilinx_vdma_tx_segment *head, *tail = NULL;
+
+	if (chan->err)
+		return;
+
+	spin_lock_irqsave(&chan->lock, flags);
+
+	/* There's already an active descriptor, bail out. */
+	if (chan->active_desc)
+		goto out_unlock;
+
+	if (list_empty(&chan->pending_list))
+		goto out_unlock;
+
+	desc = list_first_entry(&chan->pending_list,
+				struct xilinx_vdma_tx_descriptor, node);
+
+	/* If it is SG mode and hardware is busy, cannot submit */
+	if (chan->has_sg && xilinx_vdma_is_running(chan) &&
+	    !xilinx_vdma_is_idle(chan)) {
+		dev_dbg(chan->dev, "DMA controller still busy\n");
+		goto out_unlock;
+	}
+
+	if (chan->err)
+		goto out_unlock;
+
+	/*
+	 * If hardware is idle, then all descriptors on the running lists are
+	 * done, start new transfers
+	 */
+	if (chan->has_sg) {
+		head = list_first_entry(&desc->segments,
+					struct xilinx_vdma_tx_segment, node);
+		tail = list_entry(desc->segments.prev,
+				  struct xilinx_vdma_tx_segment, node);
+
+		vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC, head->phys);
+	}
+
+	/* Configure the hardware using info in the config structure */
+	reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
+
+	if (config->frm_cnt_en)
+		reg |= XILINX_VDMA_DMACR_FRAMECNT_EN;
+	else
+		reg &= ~XILINX_VDMA_DMACR_FRAMECNT_EN;
+
+	/*
+	 * With SG, start with circular mode, so that BDs can be fetched.
+	 * In direct register mode, if not parking, enable circular mode
+	 */
+	if (chan->has_sg || !config->park)
+		reg |= XILINX_VDMA_DMACR_CIRC_EN;
+
+	if (config->park)
+		reg &= ~XILINX_VDMA_DMACR_CIRC_EN;
+
+	vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, reg);
+
+	if (config->park && (config->park_frm >= 0) &&
+			(config->park_frm < chan->num_frms)) {
+		if (chan->direction == DMA_MEM_TO_DEV)
+			vdma_write(chan, XILINX_VDMA_REG_PARK_PTR,
+				config->park_frm <<
+					XILINX_VDMA_PARK_PTR_RD_REF_SHIFT);
+		else
+			vdma_write(chan, XILINX_VDMA_REG_PARK_PTR,
+				config->park_frm <<
+					XILINX_VDMA_PARK_PTR_WR_REF_SHIFT);
+	}
+
+	/* Start the hardware */
+	xilinx_vdma_start(chan);
+
+	if (chan->err)
+		goto out_unlock;
+
+	/* Start the transfer */
+	if (chan->has_sg) {
+		vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC, tail->phys);
+	} else {
+		struct xilinx_vdma_tx_segment *segment, *last = NULL;
+		int i = 0;
+
+		list_for_each_entry(segment, &desc->segments, node) {
+			vdma_desc_write(chan,
+					XILINX_VDMA_REG_START_ADDRESS(i++),
+					segment->hw.buf_addr);
+			last = segment;
+		}
+
+		if (!last)
+			goto out_unlock;
+
+		/* HW expects these parameters to be same for one transaction */
+		vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, last->hw.hsize);
+		vdma_desc_write(chan, XILINX_VDMA_REG_FRMDLY_STRIDE,
+				last->hw.stride);
+		vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, last->hw.vsize);
+	}
+
+	list_del(&desc->node);
+	chan->active_desc = desc;
+
+out_unlock:
+	spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xilinx_vdma_issue_pending(struct dma_chan *dchan)
+{
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+	xilinx_vdma_start_transfer(chan);
+}
+
+/**
+ * xilinx_vdma_complete_descriptor - Mark the active descriptor as complete
+ * @chan : xilinx DMA channel
+ *
+ * CONTEXT: hardirq
+ */
+static void xilinx_vdma_complete_descriptor(struct xilinx_vdma_chan *chan)
+{
+	struct xilinx_vdma_tx_descriptor *desc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->lock, flags);
+
+	desc = chan->active_desc;
+	if (!desc) {
+		dev_dbg(chan->dev, "no running descriptors\n");
+		goto out_unlock;
+	}
+
+	dma_cookie_complete(&desc->async_tx);
+	list_add_tail(&desc->node, &chan->done_list);
+
+	chan->active_desc = NULL;
+
+out_unlock:
+	spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_reset - Reset VDMA channel
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan)
+{
+	int loop = XILINX_VDMA_LOOP_COUNT;
+	u32 tmp;
+
+	vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RESET);
+
+	tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+		XILINX_VDMA_DMACR_RESET;
+
+	/* Wait for the hardware to finish reset */
+	do {
+		tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+			XILINX_VDMA_DMACR_RESET;
+	} while (loop-- && tmp);
+
+	if (!loop) {
+		dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
+			vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR),
+			vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+		return -ETIMEDOUT;
+	}
+
+	chan->err = false;
+
+	return 0;
+}
+
+/**
+ * xilinx_vdma_chan_reset - Reset VDMA channel and enable interrupts
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_chan_reset(struct xilinx_vdma_chan *chan)
+{
+	int err;
+
+	/* Reset VDMA */
+	err = xilinx_vdma_reset(chan);
+	if (err)
+		return err;
+
+	/* Enable interrupts */
+	vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR,
+		      XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+	return 0;
+}
+
+/**
+ * xilinx_vdma_irq_handler - VDMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx VDMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
+{
+	struct xilinx_vdma_chan *chan = data;
+	u32 status;
+
+	/* Read the status and ack the interrupts. */
+	status = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR);
+	if (!(status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK))
+		return IRQ_NONE;
+
+	vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR,
+			status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+	if (status & XILINX_VDMA_DMASR_ERR_IRQ) {
+		/*
+		 * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
+		 * error is recoverable, ignore it. Otherwise flag the error.
+		 *
+		 * Only recoverable errors can be cleared in the DMASR register,
+		 * make sure not to write to other error bits to 1.
+		 */
+		u32 errors = status & XILINX_VDMA_DMASR_ALL_ERR_MASK;
+		vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR,
+				errors & XILINX_VDMA_DMASR_ERR_RECOVER_MASK);
+
+		if (!chan->flush_on_fsync ||
+		    (errors & ~XILINX_VDMA_DMASR_ERR_RECOVER_MASK)) {
+			dev_err(chan->dev,
+				"Channel %p has errors %x, cdr %x tdr %x\n",
+				chan, errors,
+				vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC),
+				vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC));
+			chan->err = true;
+		}
+	}
+
+	if (status & XILINX_VDMA_DMASR_DLY_CNT_IRQ) {
+		/*
+		 * Device takes too long to do the transfer when user requires
+		 * responsiveness.
+		 */
+		dev_dbg(chan->dev, "Inter-packet latency too long\n");
+	}
+
+	if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) {
+		xilinx_vdma_complete_descriptor(chan);
+		xilinx_vdma_start_transfer(chan);
+	}
+
+	tasklet_schedule(&chan->tasklet);
+	return IRQ_HANDLED;
+}
+
+/**
+ * xilinx_vdma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xilinx_vdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct xilinx_vdma_tx_descriptor *desc = to_vdma_tx_descriptor(tx);
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(tx->chan);
+	dma_cookie_t cookie;
+	unsigned long flags;
+	int err;
+
+	if (chan->err) {
+		/*
+		 * If reset fails, need to hard reset the system.
+		 * Channel is no longer functional
+		 */
+		err = xilinx_vdma_chan_reset(chan);
+		if (err < 0)
+			return err;
+	}
+
+	spin_lock_irqsave(&chan->lock, flags);
+
+	cookie = dma_cookie_assign(tx);
+
+	/* Append the transaction to the pending transactions queue. */
+	list_add_tail(&desc->node, &chan->pending_list);
+
+	spin_unlock_irqrestore(&chan->lock, flags);
+
+	return cookie;
+}
+
+/**
+ * xilinx_vdma_prep_slave_sg - prepare a descriptor for a DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xts: Array of interleaved template structs
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
+				 struct dma_interleaved_template **xts,
+				 unsigned long flags)
+{
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+	struct xilinx_vdma_tx_descriptor *desc;
+	struct xilinx_vdma_tx_segment *segment;
+	struct xilinx_vdma_tx_segment *prev = NULL;
+	struct dma_interleaved_template *xt = *xts;
+	u32 frmno = 0;
+
+	/* Count number of frames */
+	for (; xts[frmno] != NULL; frmno++)
+		;
+
+	if (frmno != chan->num_frms) {
+		dev_err(chan->dev,
+			"number of entries %d not the same as num stores %d\n",
+			frmno, chan->num_frms);
+		return NULL;
+	}
+
+	/* Allocate a transaction descriptor. */
+	desc = xilinx_vdma_alloc_tx_descriptor(chan);
+	if (!desc)
+		return NULL;
+
+	dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+	desc->async_tx.tx_submit = xilinx_vdma_tx_submit;
+	desc->async_tx.cookie = 0;
+	async_tx_ack(&desc->async_tx);
+
+	/* Build the list of transaction segments. */
+	for (; (xt = *xts); xts++) {
+		struct xilinx_vdma_desc_hw *hw;
+
+		if ((xt->dir != DMA_MEM_TO_DEV) && (xt->dir != DMA_DEV_TO_MEM))
+			goto error;
+
+		if (!xt->numf || !xt->sgl[0].size)
+			goto error;
+
+		/* Allocate the link descriptor from DMA pool */
+		segment = xilinx_vdma_alloc_tx_segment(chan);
+		if (!segment)
+			goto error;
+
+		/* Fill in the hardware descriptor */
+		hw = &segment->hw;
+		if (xt->dir != DMA_MEM_TO_DEV)
+			hw->buf_addr = xt->dst_start;
+		else
+			hw->buf_addr = xt->src_start;
+		hw->vsize = xt->numf;
+		hw->hsize = xt->sgl[0].size;
+		hw->stride = (chan->config.frm_dly <<
+			      XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT) |
+			     (xt->sgl[0].icg <<
+			      XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT);
+
+		if (prev)
+			prev->hw.next_desc = segment->phys;
+
+		/* Insert the segment into the descriptor segments list. */
+		list_add_tail(&segment->node, &desc->segments);
+
+		prev = segment;
+	}
+
+	/* Link the last hardware descriptor with the first. */
+	segment = list_first_entry(&desc->segments,
+				   struct xilinx_vdma_tx_segment, node);
+	prev->hw.next_desc = segment->phys;
+
+	return &desc->async_tx;
+
+error:
+	xilinx_vdma_free_tx_descriptor(chan, desc);
+	return NULL;
+}
+
+/**
+ * xilinx_vdma_terminate_all - Halt the channel and free descriptors
+ * @chan: Driver specific VDMA Channel pointer
+ */
+static void xilinx_vdma_terminate_all(struct xilinx_vdma_chan *chan)
+{
+	/* Halt the DMA engine */
+	xilinx_vdma_halt(chan);
+
+	/* Remove and free all of the descriptors in the lists */
+	xilinx_vdma_free_descriptors(chan);
+}
+
+/**
+ * xilinx_vdma_slave_config - Configure VDMA channel
+ * Run-time configuration for Axi VDMA, supports:
+ * . halt the channel
+ * . configure interrupt coalescing and inter-packet delay threshold
+ * . start/stop parking
+ * . enable genlock
+ *
+ * @chan: Driver specific VDMA Channel pointer
+ * @slvcfg: DMA Slave configuration pointer
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_slave_config(struct xilinx_vdma_chan *chan,
+				    struct dma_slave_config *slvcfg)
+{
+	u32 dmacr;
+	struct xilinx_vdma_config *cfg = to_xilinx_vdma_config(slvcfg);
+
+	if (cfg->reset)
+		return xilinx_vdma_chan_reset(chan);
+
+	dmacr = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
+
+	chan->config.frm_dly = cfg->frm_dly;
+	chan->config.park = cfg->park;
+
+	/* genlock settings */
+	chan->config.gen_lock = cfg->gen_lock;
+	chan->config.master = cfg->master;
+
+	if (cfg->gen_lock && chan->genlock) {
+		dmacr |= XILINX_VDMA_DMACR_GENLOCK_EN;
+		dmacr |= cfg->master << XILINX_VDMA_DMACR_MASTER_SHIFT;
+	}
+
+	chan->config.frm_cnt_en = cfg->frm_cnt_en;
+	if (cfg->park)
+		chan->config.park_frm = cfg->park_frm;
+	else
+		chan->config.park_frm = -1;
+
+	chan->config.coalesc = cfg->coalesc;
+	chan->config.delay = cfg->delay;
+
+	if (cfg->coalesc <= XILINX_VDMA_DMACR_FRAME_COUNT_MAX) {
+		dmacr |= cfg->coalesc << XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT;
+		chan->config.coalesc = cfg->coalesc;
+	}
+
+	if (cfg->delay <= XILINX_VDMA_DMACR_DELAY_MAX) {
+		dmacr |= cfg->delay << XILINX_VDMA_DMACR_DELAY_SHIFT;
+		chan->config.delay = cfg->delay;
+	}
+
+	/* FSync Source selection */
+	dmacr &= ~XILINX_VDMA_DMACR_FSYNCSRC_MASK;
+	dmacr |= cfg->ext_fsync << XILINX_VDMA_DMACR_FSYNCSRC_SHIFT;
+
+	vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr);
+	return 0;
+}
+
+/**
+ * xilinx_vdma_device_control - Configure DMA channel of the device
+ * @dchan: DMA Channel pointer
+ * @cmd: DMA control command
+ * @arg: Channel configuration
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_device_control(struct dma_chan *dchan,
+				      enum dma_ctrl_cmd cmd, unsigned long arg)
+{
+	struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		xilinx_vdma_terminate_all(chan);
+		return 0;
+	case DMA_SLAVE_CONFIG:
+		return xilinx_vdma_slave_config(chan,
+						(struct dma_slave_config *)arg);
+	default:
+		return -ENXIO;
+	}
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+/**
+ * xilinx_vdma_chan_remove - Per Channel remove function
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_chan_remove(struct xilinx_vdma_chan *chan)
+{
+	/* Disable all interrupts */
+	vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR,
+		      XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+	if (chan->irq > 0)
+		free_irq(chan->irq, chan);
+
+	tasklet_kill(&chan->tasklet);
+
+	list_del(&chan->common.device_node);
+}
+
+/**
+ * xilinx_vdma_chan_probe - Per Channel Probing
+ * It get channel features from the device tree entry and
+ * initialize special channel handling routines
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev,
+				  struct device_node *node)
+{
+	struct xilinx_vdma_chan *chan;
+	bool has_dre = false;
+	u32 value, width;
+	int err;
+
+	/* Allocate and initialize the channel structure */
+	chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
+	if (!chan)
+		return -ENOMEM;
+
+	chan->dev = xdev->dev;
+	chan->xdev = xdev;
+	chan->has_sg = xdev->has_sg;
+
+	spin_lock_init(&chan->lock);
+	INIT_LIST_HEAD(&chan->pending_list);
+	INIT_LIST_HEAD(&chan->done_list);
+
+	/* Retrieve the channel properties from the device tree */
+	has_dre = of_property_read_bool(node, "xlnx,include-dre");
+
+	chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
+
+	err = of_property_read_u32(node, "xlnx,datawidth", &value);
+	if (err) {
+		dev_err(xdev->dev, "missing xlnx,datawidth property\n");
+		return err;
+	}
+	width = value >> 3; /* Convert bits to bytes */
+
+	/* If data width is greater than 8 bytes, DRE is not in hw */
+	if (width > 8)
+		has_dre = false;
+
+	if (!has_dre)
+		xdev->common.copy_align = fls(width - 1);
+
+	if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) {
+		chan->direction = DMA_MEM_TO_DEV;
+		chan->id = 0;
+
+		chan->ctrl_offset = XILINX_VDMA_MM2S_CTRL_OFFSET;
+		chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
+
+		if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
+		    xdev->flush_on_fsync == XILINX_VDMA_FLUSH_MM2S)
+			chan->flush_on_fsync = true;
+	} else if (of_device_is_compatible(node,
+					    "xlnx,axi-vdma-s2mm-channel")) {
+		chan->direction = DMA_DEV_TO_MEM;
+		chan->id = 1;
+
+		chan->ctrl_offset = XILINX_VDMA_S2MM_CTRL_OFFSET;
+		chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
+
+		if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
+		    xdev->flush_on_fsync == XILINX_VDMA_FLUSH_S2MM)
+			chan->flush_on_fsync = true;
+	} else {
+		dev_err(xdev->dev, "Invalid channel compatible node\n");
+		return -EINVAL;
+	}
+
+	/* Request the interrupt */
+	chan->irq = irq_of_parse_and_map(node, 0);
+	err = request_irq(chan->irq, xilinx_vdma_irq_handler, IRQF_SHARED,
+			  "xilinx-vdma-controller", chan);
+	if (err) {
+		dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
+		return err;
+	}
+
+	/* Initialize the tasklet */
+	tasklet_init(&chan->tasklet, xilinx_vdma_do_tasklet,
+			(unsigned long)chan);
+
+	/*
+	 * Initialize the DMA channel and add it to the DMA engine channels
+	 * list.
+	 */
+	chan->common.device = &xdev->common;
+
+	list_add_tail(&chan->common.device_node, &xdev->common.channels);
+	xdev->chan[chan->id] = chan;
+
+	/* Reset the channel */
+	err = xilinx_vdma_chan_reset(chan);
+	if (err < 0) {
+		dev_err(xdev->dev, "Reset channel failed\n");
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * of_dma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
+						struct of_dma *ofdma)
+{
+	struct xilinx_vdma_device *xdev = ofdma->of_dma_data;
+	int chan_id = dma_spec->args[0];
+
+	if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE)
+		return NULL;
+
+	return dma_get_slave_channel(&xdev->chan[chan_id]->common);
+}
+
+/**
+ * xilinx_vdma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct xilinx_vdma_device *xdev;
+	struct device_node *child;
+	struct resource *io;
+	u32 num_frames;
+	int i, err;
+
+	dev_info(&pdev->dev, "Probing xilinx axi vdma engine\n");
+
+	/* Allocate and initialize the DMA engine structure */
+	xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+	if (!xdev)
+		return -ENOMEM;
+
+	xdev->dev = &pdev->dev;
+
+	/* Request and map I/O memory */
+	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	xdev->regs = devm_ioremap_resource(&pdev->dev, io);
+	if (IS_ERR(xdev->regs))
+		return PTR_ERR(xdev->regs);
+
+	/* Retrieve the DMA engine properties from the device tree */
+	xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+
+	err = of_property_read_u32(node, "xlnx,num-fstores", &num_frames);
+	if (err < 0) {
+		dev_err(xdev->dev, "missing xlnx,num-fstores property\n");
+		return err;
+	}
+
+	err = of_property_read_u32(node, "xlnx,flush-fsync",
+					&xdev->flush_on_fsync);
+	if (err < 0)
+		dev_warn(xdev->dev, "missing xlnx,flush-fsync property\n");
+
+	/* Initialize the DMA engine */
+	xdev->common.dev = &pdev->dev;
+
+	INIT_LIST_HEAD(&xdev->common.channels);
+	dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
+	dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
+
+	xdev->common.device_alloc_chan_resources =
+				xilinx_vdma_alloc_chan_resources;
+	xdev->common.device_free_chan_resources =
+				xilinx_vdma_free_chan_resources;
+	xdev->common.device_prep_interleaved_dma =
+				xilinx_vdma_dma_prep_interleaved;
+	xdev->common.device_control = xilinx_vdma_device_control;
+	xdev->common.device_tx_status = xilinx_vdma_tx_status;
+	xdev->common.device_issue_pending = xilinx_vdma_issue_pending;
+
+	platform_set_drvdata(pdev, xdev);
+
+	/* Initialize the channels */
+	for_each_child_of_node(node, child) {
+		err = xilinx_vdma_chan_probe(xdev, child);
+		if (err < 0)
+			goto error;
+	}
+
+	for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+		if (xdev->chan[i])
+			xdev->chan[i]->num_frms = num_frames;
+
+	/* Register the DMA engine with the core */
+	dma_async_device_register(&xdev->common);
+
+	err = of_dma_controller_register(node, of_dma_xilinx_xlate,
+					 xdev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+		dma_async_device_unregister(&xdev->common);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+		if (xdev->chan[i])
+			xilinx_vdma_chan_remove(xdev->chan[i]);
+
+	return err;
+}
+
+/**
+ * xilinx_vdma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int xilinx_vdma_remove(struct platform_device *pdev)
+{
+	struct xilinx_vdma_device *xdev = platform_get_drvdata(pdev);
+	int i;
+
+	of_dma_controller_free(pdev->dev.of_node);
+
+	dma_async_device_unregister(&xdev->common);
+
+	for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+		if (xdev->chan[i])
+			xilinx_vdma_chan_remove(xdev->chan[i]);
+
+	return 0;
+}
+
+static const struct of_device_id xilinx_vdma_of_ids[] = {
+	{ .compatible = "xlnx,axi-vdma-1.00.a",},
+	{}
+};
+
+static struct platform_driver xilinx_vdma_driver = {
+	.driver = {
+		.name = "xilinx-vdma",
+		.owner = THIS_MODULE,
+		.of_match_table = xilinx_vdma_of_ids,
+	},
+	.probe = xilinx_vdma_probe,
+	.remove = xilinx_vdma_remove,
+};
+
+module_platform_driver(xilinx_vdma_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx VDMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/amba/xilinx_dma.h b/include/linux/amba/xilinx_dma.h
new file mode 100644
index 0000000..146406c
--- /dev/null
+++ b/include/linux/amba/xilinx_dma.h
@@ -0,0 +1,46 @@
+/*
+ * Xilinx DMA Engine drivers support header file
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DMA_XILINX_DMA_H
+#define __DMA_XILINX_DMA_H
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+
+/**
+ * struct xilinx_vdma_config - VDMA Configuration structure
+ * @slvcfg: DMA Slave configuration
+ * @frm_dly: Frame delay
+ * @gen_lock: Whether in gen-lock mode
+ * @master: Master that it syncs to
+ * @frm_cnt_en: Enable frame count enable
+ * @park: Whether wants to park
+ * @park_frm: Frame to park on
+ * @coalesc: Interrupt coalescing threshold
+ * @delay: Delay counter
+ * @reset: Reset Channel
+ * @ext_fsync: External Frame Sync source
+ */
+struct xilinx_vdma_config {
+	struct dma_slave_config slvcfg;
+	int frm_dly;
+	int gen_lock;
+	int master;
+	int frm_cnt_en;
+	int park;
+	int park_frm;
+	int coalesc;
+	int delay;
+	int reset;
+	int ext_fsync;
+};
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH 1/3] mmc: add support for power-on sequencing through DT
From: Arnd Bergmann @ 2014-02-15 12:18 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-arm-kernel, mark.rutland, devicetree, Ulf Hansson,
	Pawel Moll, Ian Campbell, Tomasz Figa, linux-mmc, Tomasz Figa,
	Chris Ball, robh+dt, Kumar Gala, Olof Johansson, Fabio Estevam,
	Sascha Hauer
In-Reply-To: <1626419.Ta3A7zgHIt@wuerfel>

On Thursday 13 February 2014 17:13:14 Arnd Bergmann wrote:
> 
> Aside from the power-on problem, my suggestion would at the same
> time solve the second problem of having a place to stick arbitrary
> DT properties for the sdio function. Again looking at the cw1200
> example, they may require passing an IRQ descriptor, a MAC address,
> the device clock rate, and two flags for things that are not
> detectable by looking at the device ID (whether a 5GHz antenna is
> connected and something about odd block size transfers).
> This is probably the main difference between the two approaches.

I just realized one more thing: Some devices have multiple
alternative bus interfaces and it would be nice to use just
one binding for the device, independent of the interface.

If a wlan adapter has both SPI and SDIO front-ends, the external
dependencies (reset, clock, voltage, ...) will be the same, and
from the kernel perspective the main difference is that SPI cannot
be probed at all, while SDIO can be probed as long as the device
is powered on already. If we do what I suggested and add a way to
the SDIO core to probe a device just from DT information, both
the binding and much of the device driver code can be shared
between the bus front-end glues, which would not be possible
if we rely on the SDIO bus probe and add the power-on sequencing
to the SDIO core.

	Arnd

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox