Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v15 2/4] CMDQ: Mediatek CMDQ driver
From: HS Liao @ 2016-10-17 10:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476699117-3001-1-git-send-email-hs.liao@mediatek.com>

This patch is first version of Mediatek Command Queue(CMDQ) driver. The
CMDQ is used to help write registers with critical time limitation,
such as updating display configuration during the vblank. It controls
Global Command Engine (GCE) hardware to achieve this requirement.
Currently, CMDQ only supports display related hardwares, but we expect
it can be extended to other hardwares for future requirements.

Signed-off-by: HS Liao <hs.liao@mediatek.com>
Signed-off-by: CK Hu <ck.hu@mediatek.com>
---
 drivers/mailbox/Kconfig                  |  10 +
 drivers/mailbox/Makefile                 |   2 +
 drivers/mailbox/mtk-cmdq-mailbox.c       | 552 +++++++++++++++++++++++++++++++
 drivers/soc/mediatek/Kconfig             |  11 +
 drivers/soc/mediatek/Makefile            |   1 +
 drivers/soc/mediatek/mtk-cmdq-helper.c   | 310 +++++++++++++++++
 include/linux/mailbox/mtk-cmdq-mailbox.h |  67 ++++
 include/linux/soc/mediatek/mtk-cmdq.h    | 182 ++++++++++
 8 files changed, 1135 insertions(+)
 create mode 100644 drivers/mailbox/mtk-cmdq-mailbox.c
 create mode 100644 drivers/soc/mediatek/mtk-cmdq-helper.c
 create mode 100644 include/linux/mailbox/mtk-cmdq-mailbox.h
 create mode 100644 include/linux/soc/mediatek/mtk-cmdq.h

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 11eebfe..5a4af2d 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -143,4 +143,14 @@ config BCM_PDC_MBOX
 	  Mailbox implementation for the Broadcom PDC ring manager,
 	  which provides access to various offload engines on Broadcom
 	  SoCs. Say Y here if you want to use the Broadcom PDC.
+
+config MTK_CMDQ_MBOX
+	bool "MediaTek CMDQ Mailbox Support"
+	depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
+	select MTK_INFRACFG
+	help
+	  Say yes here to add support for the MediaTek Command Queue (CMDQ)
+	  mailbox driver. The CMDQ is used to help read/write registers with
+	  critical time limitation, such as updating display configuration
+	  during the vblank.
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index ace6fed..b904bed 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
 obj-$(CONFIG_HI6220_MBOX)	+= hi6220-mailbox.o
 
 obj-$(CONFIG_BCM_PDC_MBOX)	+= bcm-pdc-mailbox.o
+
+obj-$(CONFIG_MTK_CMDQ_MBOX)	+= mtk-cmdq-mailbox.o
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
new file mode 100644
index 0000000..d086fd8
--- /dev/null
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox/mtk-cmdq-mailbox.h>
+#include <linux/timer.h>
+
+#define CMDQ_THR_MAX_COUNT		3 /* main, sub, general(misc) */
+#define CMDQ_OP_CODE_MASK		(0xff << CMDQ_OP_CODE_SHIFT)
+#define CMDQ_TIMEOUT_MS			1000
+#define CMDQ_IRQ_MASK			0xffff
+#define CMDQ_NUM_CMD(t)			(t->cmd_buf_size / CMDQ_INST_SIZE)
+
+#define CMDQ_CURR_IRQ_STATUS		0x10
+#define CMDQ_THR_SLOT_CYCLES		0x30
+
+#define CMDQ_THR_BASE			0x100
+#define CMDQ_THR_SIZE			0x80
+#define CMDQ_THR_WARM_RESET		0x00
+#define CMDQ_THR_ENABLE_TASK		0x04
+#define CMDQ_THR_SUSPEND_TASK		0x08
+#define CMDQ_THR_CURR_STATUS		0x0c
+#define CMDQ_THR_IRQ_STATUS		0x10
+#define CMDQ_THR_IRQ_ENABLE		0x14
+#define CMDQ_THR_CURR_ADDR		0x20
+#define CMDQ_THR_END_ADDR		0x24
+#define CMDQ_THR_WAIT_TOKEN		0x30
+
+#define CMDQ_THR_ENABLED		0x1
+#define CMDQ_THR_DISABLED		0x0
+#define CMDQ_THR_SUSPEND		0x1
+#define CMDQ_THR_RESUME			0x0
+#define CMDQ_THR_STATUS_SUSPENDED	BIT(1)
+#define CMDQ_THR_DO_WARM_RESET		BIT(0)
+#define CMDQ_THR_ACTIVE_SLOT_CYCLES	0x3200
+#define CMDQ_THR_IRQ_DONE		0x1
+#define CMDQ_THR_IRQ_ERROR		0x12
+#define CMDQ_THR_IRQ_EN			(CMDQ_THR_IRQ_ERROR | CMDQ_THR_IRQ_DONE)
+#define CMDQ_THR_IS_WAITING		BIT(31)
+
+#define CMDQ_JUMP_BY_OFFSET		0x10000000
+#define CMDQ_JUMP_BY_PA			0x10000001
+
+struct cmdq_thread {
+	struct mbox_chan	*chan;
+	void __iomem		*base;
+	struct list_head	task_busy_list;
+	struct timer_list	timeout;
+	bool			atomic_exec;
+};
+
+struct cmdq_task {
+	struct cmdq		*cmdq;
+	struct list_head	list_entry;
+	dma_addr_t		pa_base;
+	struct cmdq_thread	*thread;
+	struct cmdq_pkt		*pkt; /* the packet sent from mailbox client */
+};
+
+struct cmdq {
+	struct mbox_controller	mbox;
+	void __iomem		*base;
+	u32			irq;
+	struct cmdq_thread	thread[CMDQ_THR_MAX_COUNT];
+	struct clk		*clock;
+};
+
+static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 status;
+
+	writel(CMDQ_THR_SUSPEND, thread->base + CMDQ_THR_SUSPEND_TASK);
+
+	/* If already disabled, treat as suspended successful. */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return 0;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_STATUS,
+			status, status & CMDQ_THR_STATUS_SUSPENDED, 0, 10)) {
+		dev_err(cmdq->mbox.dev, "suspend GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void cmdq_thread_resume(struct cmdq_thread *thread)
+{
+	writel(CMDQ_THR_RESUME, thread->base + CMDQ_THR_SUSPEND_TASK);
+}
+
+static int cmdq_thread_reset(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	u32 warm_reset;
+
+	writel(CMDQ_THR_DO_WARM_RESET, thread->base + CMDQ_THR_WARM_RESET);
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_WARM_RESET,
+			warm_reset, !(warm_reset & CMDQ_THR_DO_WARM_RESET),
+			0, 10)) {
+		dev_err(cmdq->mbox.dev, "reset GCE thread 0x%x failed\n",
+			(u32)(thread->base - cmdq->base));
+		return -EFAULT;
+	}
+	writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
+	return 0;
+}
+
+static void cmdq_thread_disable(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+	cmdq_thread_reset(cmdq, thread);
+	writel(CMDQ_THR_DISABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+}
+
+/* notify GCE to re-fetch commands by setting GCE thread PC */
+static void cmdq_thread_invalidate_fetched_data(struct cmdq_thread *thread)
+{
+	writel(readl(thread->base + CMDQ_THR_CURR_ADDR),
+	       thread->base + CMDQ_THR_CURR_ADDR);
+}
+
+static void cmdq_task_insert_into_thread(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *prev_task = list_last_entry(
+			&thread->task_busy_list, typeof(*task), list_entry);
+	u64 *prev_task_base = prev_task->pkt->va_base;
+
+	/* let previous task jump to this task */
+	dma_sync_single_for_cpu(dev, prev_task->pa_base,
+				prev_task->pkt->cmd_buf_size, DMA_TO_DEVICE);
+	prev_task_base[CMDQ_NUM_CMD(prev_task->pkt) - 1] =
+		(u64)CMDQ_JUMP_BY_PA << 32 | task->pa_base;
+	dma_sync_single_for_device(dev, prev_task->pa_base,
+				   prev_task->pkt->cmd_buf_size, DMA_TO_DEVICE);
+
+	cmdq_thread_invalidate_fetched_data(thread);
+}
+
+static bool cmdq_command_is_wfe(u64 cmd)
+{
+	u64 wfe_option = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	u64 wfe_op = (u64)(CMDQ_CODE_WFE << CMDQ_OP_CODE_SHIFT) << 32;
+	u64 wfe_mask = (u64)CMDQ_OP_CODE_MASK << 32 | 0xffffffff;
+
+	return ((cmd & wfe_mask) == (wfe_op | wfe_option));
+}
+
+/* we assume tasks in the same display GCE thread are waiting the same event. */
+static void cmdq_task_remove_wfe(struct cmdq_task *task)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	u64 *base = task->pkt->va_base;
+	int i;
+
+	dma_sync_single_for_cpu(dev, task->pa_base, task->pkt->cmd_buf_size,
+				DMA_TO_DEVICE);
+	for (i = 0; i < CMDQ_NUM_CMD(task->pkt); i++)
+		if (cmdq_command_is_wfe(base[i]))
+			base[i] = (u64)CMDQ_JUMP_BY_OFFSET << 32 |
+				  CMDQ_JUMP_PASS;
+	dma_sync_single_for_device(dev, task->pa_base, task->pkt->cmd_buf_size,
+				   DMA_TO_DEVICE);
+}
+
+static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread)
+{
+	return readl(thread->base + CMDQ_THR_WAIT_TOKEN) & CMDQ_THR_IS_WAITING;
+}
+
+static void cmdq_thread_wait_end(struct cmdq_thread *thread,
+				 unsigned long end_pa)
+{
+	struct device *dev = thread->chan->mbox->dev;
+	unsigned long curr_pa;
+
+	if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_ADDR,
+			curr_pa, curr_pa == end_pa, 1, 20))
+		dev_err(dev, "GCE thread cannot run to end.\n");
+}
+
+static void cmdq_task_exec(struct cmdq_pkt *pkt, struct cmdq_thread *thread)
+{
+	struct cmdq *cmdq;
+	struct cmdq_task *task;
+	unsigned long curr_pa, end_pa;
+
+	cmdq = dev_get_drvdata(thread->chan->mbox->dev);
+
+	task = kzalloc(sizeof(*task), GFP_ATOMIC);
+	task->cmdq = cmdq;
+	INIT_LIST_HEAD(&task->list_entry);
+	task->pa_base = dma_map_single(cmdq->mbox.dev, pkt->va_base,
+				       pkt->cmd_buf_size, DMA_TO_DEVICE);
+	task->thread = thread;
+	task->pkt = pkt;
+
+	if (list_empty(&thread->task_busy_list)) {
+		WARN_ON(clk_enable(cmdq->clock) < 0);
+		WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
+
+		writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+		writel(task->pa_base + pkt->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
+		writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	} else {
+		WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+		curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+		end_pa = readl(thread->base + CMDQ_THR_END_ADDR);
+
+		/*
+		 * Atomic execution should remove the following wfe, i.e. only
+		 * wait event at first task, and prevent to pause when running.
+		 */
+		if (thread->atomic_exec) {
+			/* GCE is executing if command is not WFE */
+			if (!cmdq_thread_is_in_wfe(thread)) {
+				cmdq_thread_resume(thread);
+				cmdq_thread_wait_end(thread, end_pa);
+				WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				cmdq_task_remove_wfe(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		} else {
+			/* check boundary */
+			if (curr_pa == end_pa - CMDQ_INST_SIZE ||
+			    curr_pa == end_pa) {
+				/* set to this task directly */
+				writel(task->pa_base,
+				       thread->base + CMDQ_THR_CURR_ADDR);
+			} else {
+				cmdq_task_insert_into_thread(task);
+				smp_mb(); /* modify jump before enable thread */
+			}
+		}
+		writel(task->pa_base + pkt->cmd_buf_size,
+		       thread->base + CMDQ_THR_END_ADDR);
+		cmdq_thread_resume(thread);
+	}
+	list_move_tail(&task->list_entry, &thread->task_busy_list);
+}
+
+static void cmdq_task_exec_done(struct cmdq_task *task, bool err)
+{
+	struct device *dev = task->cmdq->mbox.dev;
+	struct cmdq_cb_data cmdq_cb_data;
+
+	dma_unmap_single(dev, task->pa_base, task->pkt->cmd_buf_size,
+			 DMA_TO_DEVICE);
+	if (task->pkt->cb.cb) {
+		cmdq_cb_data.err = err;
+		cmdq_cb_data.data = task->pkt->cb.data;
+		task->pkt->cb.cb(cmdq_cb_data);
+	}
+	list_del(&task->list_entry);
+}
+
+static void cmdq_task_handle_error(struct cmdq_task *task)
+{
+	struct cmdq_thread *thread = task->thread;
+	struct cmdq_task *next_task;
+
+	dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task);
+	WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0);
+	next_task = list_first_entry_or_null(&thread->task_busy_list,
+			struct cmdq_task, list_entry);
+	if (next_task)
+		writel(next_task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+	cmdq_thread_resume(thread);
+}
+
+static void cmdq_thread_irq_handler(struct cmdq *cmdq,
+				    struct cmdq_thread *thread)
+{
+	struct cmdq_task *task, *tmp, *curr_task = NULL;
+	u32 curr_pa, irq_flag, task_end_pa;
+	bool err;
+
+	irq_flag = readl(thread->base + CMDQ_THR_IRQ_STATUS);
+	writel(~irq_flag, thread->base + CMDQ_THR_IRQ_STATUS);
+
+	/*
+	 * When ISR call this function, another CPU core could run
+	 * "release task" right before we acquire the spin lock, and thus
+	 * reset / disable this GCE thread, so we need to check the enable
+	 * bit of this GCE thread.
+	 */
+	if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+		return;
+
+	if (irq_flag & CMDQ_THR_IRQ_ERROR)
+		err = true;
+	else if (irq_flag & CMDQ_THR_IRQ_DONE)
+		err = false;
+	else
+		return;
+
+	curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		task_end_pa = task->pa_base + task->pkt->cmd_buf_size;
+		if (curr_pa >= task->pa_base && curr_pa < task_end_pa)
+			curr_task = task;
+
+		if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
+			cmdq_task_exec_done(task, false);
+			kfree(task);
+		} else if (err) {
+			cmdq_task_exec_done(task, true);
+			cmdq_task_handle_error(curr_task);
+			kfree(task);
+		}
+
+		if (curr_task)
+			break;
+	}
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_disable(cmdq, thread);
+		clk_disable(cmdq->clock);
+	} else {
+		mod_timer(&thread->timeout,
+			  jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+	}
+}
+
+static irqreturn_t cmdq_irq_handler(int irq, void *dev)
+{
+	struct cmdq *cmdq = dev;
+	unsigned long irq_status, flags = 0L;
+	int bit;
+
+	irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK;
+	if (!(irq_status ^ CMDQ_IRQ_MASK))
+		return IRQ_NONE;
+
+	for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) {
+		struct cmdq_thread *thread = &cmdq->thread[bit];
+
+		spin_lock_irqsave(&thread->chan->lock, flags);
+		cmdq_thread_irq_handler(cmdq, thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+	}
+	return IRQ_HANDLED;
+}
+
+static void cmdq_thread_handle_timeout(unsigned long data)
+{
+	struct cmdq_thread *thread = (struct cmdq_thread *)data;
+	struct cmdq *cmdq = container_of(thread->chan->mbox, struct cmdq, mbox);
+	struct cmdq_task *task, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&thread->chan->lock, flags);
+	WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+
+	/*
+	 * Although IRQ is disabled, GCE continues to execute.
+	 * It may have pending IRQ before GCE thread is suspended,
+	 * so check this condition again.
+	 */
+	cmdq_thread_irq_handler(cmdq, thread);
+
+	if (list_empty(&thread->task_busy_list)) {
+		cmdq_thread_resume(thread);
+		spin_unlock_irqrestore(&thread->chan->lock, flags);
+		return;
+	}
+
+	dev_err(cmdq->mbox.dev, "timeout\n");
+	list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+				 list_entry) {
+		cmdq_task_exec_done(task, true);
+		kfree(task);
+	}
+
+	cmdq_thread_resume(thread);
+	cmdq_thread_disable(cmdq, thread);
+	clk_disable(cmdq->clock);
+	spin_unlock_irqrestore(&thread->chan->lock, flags);
+}
+
+static int cmdq_remove(struct platform_device *pdev)
+{
+	struct cmdq *cmdq = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&cmdq->mbox);
+	clk_unprepare(cmdq->clock);
+	return 0;
+}
+
+static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+	cmdq_task_exec(data, chan->con_priv);
+	return 0;
+}
+
+static int cmdq_mbox_startup(struct mbox_chan *chan)
+{
+	return 0;
+}
+
+static void cmdq_mbox_shutdown(struct mbox_chan *chan)
+{
+}
+
+static bool cmdq_mbox_last_tx_done(struct mbox_chan *chan)
+{
+	return true;
+}
+
+static const struct mbox_chan_ops cmdq_mbox_chan_ops = {
+	.send_data = cmdq_mbox_send_data,
+	.startup = cmdq_mbox_startup,
+	.shutdown = cmdq_mbox_shutdown,
+	.last_tx_done = cmdq_mbox_last_tx_done,
+};
+
+static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
+		const struct of_phandle_args *sp)
+{
+	int ind = sp->args[0];
+	struct cmdq_thread *thread;
+
+	if (ind >= mbox->num_chans)
+		return ERR_PTR(-EINVAL);
+
+	thread = mbox->chans[ind].con_priv;
+	thread->atomic_exec = (sp->args[1] != 0);
+	thread->chan = &mbox->chans[ind];
+
+	return &mbox->chans[ind];
+}
+
+static int cmdq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct cmdq *cmdq;
+	int err, i;
+
+	cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
+	if (!cmdq)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cmdq->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cmdq->base)) {
+		dev_err(dev, "failed to ioremap gce\n");
+		return PTR_ERR(cmdq->base);
+	}
+
+	cmdq->irq = platform_get_irq(pdev, 0);
+	if (!cmdq->irq) {
+		dev_err(dev, "failed to get irq\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED,
+			       "mtk_cmdq", cmdq);
+	if (err < 0) {
+		dev_err(dev, "failed to register ISR (%d)\n", err);
+		return err;
+	}
+
+	dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
+		dev, cmdq->base, cmdq->irq);
+
+	cmdq->clock = devm_clk_get(dev, "gce");
+	if (IS_ERR(cmdq->clock)) {
+		dev_err(dev, "failed to get gce clk\n");
+		return PTR_ERR(cmdq->clock);
+	}
+
+	cmdq->mbox.dev = dev;
+	cmdq->mbox.chans = devm_kcalloc(dev, CMDQ_THR_MAX_COUNT,
+					sizeof(*cmdq->mbox.chans), GFP_KERNEL);
+	if (!cmdq->mbox.chans)
+		return -ENOMEM;
+
+	cmdq->mbox.num_chans = CMDQ_THR_MAX_COUNT;
+	cmdq->mbox.ops = &cmdq_mbox_chan_ops;
+	cmdq->mbox.of_xlate = cmdq_xlate;
+
+	/* make use of TXDONE_BY_ACK */
+	cmdq->mbox.txdone_irq = false;
+	cmdq->mbox.txdone_poll = false;
+
+	for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+		cmdq->thread[i].base = cmdq->base + CMDQ_THR_BASE +
+				CMDQ_THR_SIZE * i;
+		INIT_LIST_HEAD(&cmdq->thread[i].task_busy_list);
+		init_timer(&cmdq->thread[i].timeout);
+		cmdq->thread[i].timeout.function = cmdq_thread_handle_timeout;
+		cmdq->thread[i].timeout.data = (unsigned long)&cmdq->thread[i];
+		cmdq->mbox.chans[i].con_priv = &cmdq->thread[i];
+	}
+
+	err = mbox_controller_register(&cmdq->mbox);
+	if (err < 0) {
+		dev_err(dev, "failed to register mailbox: %d\n", err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, cmdq);
+	WARN_ON(clk_prepare(cmdq->clock) < 0);
+	return 0;
+}
+
+static const struct of_device_id cmdq_of_ids[] = {
+	{.compatible = "mediatek,mt8173-gce",},
+	{}
+};
+
+static struct platform_driver cmdq_drv = {
+	.probe = cmdq_probe,
+	.remove = cmdq_remove,
+	.driver = {
+		.name = "mtk_cmdq",
+		.of_match_table = cmdq_of_ids,
+	}
+};
+
+builtin_platform_driver(cmdq_drv);
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0a4ea80..94651ed 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -1,6 +1,17 @@
 #
 # MediaTek SoC drivers
 #
+config MTK_CMDQ
+	bool "MediaTek CMDQ Support"
+	depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
+	select MTK_CMDQ_MBOX
+	select MTK_INFRACFG
+	help
+	  Say yes here to add support for the MediaTek Command Queue (CMDQ)
+	  driver. The CMDQ is used to help read/write registers with critical
+	  time limitation, such as updating display configuration during the
+	  vblank.
+
 config MTK_INFRACFG
 	bool "MediaTek INFRACFG Support"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 12998b0..64ce5ee 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
 obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
 obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
 obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
new file mode 100644
index 0000000..f4002bf
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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/completion.h>
+#include <linux/errno.h>
+#include <linux/mailbox/mtk-cmdq-mailbox.h>
+#include <linux/of_address.h>
+
+#define CMDQ_SUBSYS_SHIFT	16
+#define CMDQ_ARG_A_WRITE_MASK	0xffff
+#define CMDQ_WRITE_ENABLE_MASK	BIT(0)
+#define CMDQ_EOC_IRQ_EN		BIT(0)
+#define CMDQ_EOC_CMD		((u64)((CMDQ_CODE_EOC << CMDQ_OP_CODE_SHIFT)) \
+				<< 32 | CMDQ_EOC_IRQ_EN)
+
+struct cmdq_subsys {
+	u32	base;
+	int	id;
+};
+
+static const struct cmdq_subsys gce_subsys[] = {
+	{0x1400, 1},
+	{0x1401, 2},
+	{0x1402, 3},
+};
+
+static int cmdq_subsys_base_to_id(u32 base)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gce_subsys); i++)
+		if (gce_subsys[i].base == base)
+			return gce_subsys[i].id;
+	return -EFAULT;
+}
+
+static int cmdq_pkt_realloc_cmd_buffer(struct cmdq_pkt *pkt, size_t size)
+{
+	void *new_buf;
+
+	new_buf = krealloc(pkt->va_base, size, GFP_KERNEL | __GFP_ZERO);
+	if (!new_buf)
+		return -ENOMEM;
+	pkt->va_base = new_buf;
+	pkt->buf_size = size;
+	return 0;
+}
+
+struct cmdq_base *cmdq_register_device(struct device *dev)
+{
+	struct cmdq_base *cmdq_base;
+	struct resource res;
+	int subsys;
+	u32 base;
+
+	if (of_address_to_resource(dev->of_node, 0, &res))
+		return NULL;
+	base = (u32)res.start;
+
+	subsys = cmdq_subsys_base_to_id(base >> 16);
+	if (subsys < 0)
+		return NULL;
+
+	cmdq_base = devm_kmalloc(dev, sizeof(*cmdq_base), GFP_KERNEL);
+	if (!cmdq_base)
+		return NULL;
+	cmdq_base->subsys = subsys;
+	cmdq_base->base = base;
+
+	return cmdq_base;
+}
+EXPORT_SYMBOL(cmdq_register_device);
+
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
+{
+	struct cmdq_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	client->client.dev = dev;
+	client->client.tx_block = false;
+	client->chan = mbox_request_channel(&client->client, index);
+	return client;
+}
+EXPORT_SYMBOL(cmdq_mbox_create);
+
+void cmdq_mbox_destroy(struct cmdq_client *client)
+{
+	mbox_free_channel(client->chan);
+	kfree(client);
+}
+EXPORT_SYMBOL(cmdq_mbox_destroy);
+
+int cmdq_pkt_create(struct cmdq_pkt **pkt_ptr)
+{
+	struct cmdq_pkt *pkt;
+	int err;
+
+	pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
+	if (!pkt)
+		return -ENOMEM;
+	err = cmdq_pkt_realloc_cmd_buffer(pkt, PAGE_SIZE);
+	if (err < 0) {
+		kfree(pkt);
+		return err;
+	}
+	*pkt_ptr = pkt;
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_pkt_create);
+
+void cmdq_pkt_destroy(struct cmdq_pkt *pkt)
+{
+	kfree(pkt->va_base);
+	kfree(pkt);
+}
+EXPORT_SYMBOL(cmdq_pkt_destroy);
+
+static bool cmdq_pkt_is_finalized(struct cmdq_pkt *pkt)
+{
+	u64 *expect_eoc;
+
+	if (pkt->cmd_buf_size < CMDQ_INST_SIZE << 1)
+		return false;
+
+	expect_eoc = pkt->va_base + pkt->cmd_buf_size - (CMDQ_INST_SIZE << 1);
+	if (*expect_eoc == CMDQ_EOC_CMD)
+		return true;
+
+	return false;
+}
+
+static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code,
+				   u32 arg_a, u32 arg_b)
+{
+	u64 *cmd_ptr;
+	int err;
+
+	if (WARN_ON(cmdq_pkt_is_finalized(pkt)))
+		return -EBUSY;
+	if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) {
+		err = cmdq_pkt_realloc_cmd_buffer(pkt, pkt->buf_size << 1);
+		if (err < 0)
+			return err;
+	}
+	cmd_ptr = pkt->va_base + pkt->cmd_buf_size;
+	(*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
+	pkt->cmd_buf_size += CMDQ_INST_SIZE;
+	return 0;
+}
+
+int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, struct cmdq_base *base,
+		   u32 offset)
+{
+	u32 arg_a = ((base->base + offset) & CMDQ_ARG_A_WRITE_MASK) |
+		    (base->subsys << CMDQ_SUBSYS_SHIFT);
+	return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value);
+}
+EXPORT_SYMBOL(cmdq_pkt_write);
+
+int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
+			struct cmdq_base *base, u32 offset, u32 mask)
+{
+	u32 offset_mask = offset;
+	int err;
+
+	if (mask != 0xffffffff) {
+		err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask);
+		if (err < 0)
+			return err;
+		offset_mask |= CMDQ_WRITE_ENABLE_MASK;
+	}
+	return cmdq_pkt_write(pkt, value, base, offset_mask);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_mask);
+
+static const u32 cmdq_event_value[CMDQ_MAX_EVENT] = {
+	/* Display start of frame(SOF) events */
+	[CMDQ_EVENT_DISP_OVL0_SOF] = 11,
+	[CMDQ_EVENT_DISP_OVL1_SOF] = 12,
+	[CMDQ_EVENT_DISP_RDMA0_SOF] = 13,
+	[CMDQ_EVENT_DISP_RDMA1_SOF] = 14,
+	[CMDQ_EVENT_DISP_RDMA2_SOF] = 15,
+	[CMDQ_EVENT_DISP_WDMA0_SOF] = 16,
+	[CMDQ_EVENT_DISP_WDMA1_SOF] = 17,
+	/* Display end of frame(EOF) events */
+	[CMDQ_EVENT_DISP_OVL0_EOF] = 39,
+	[CMDQ_EVENT_DISP_OVL1_EOF] = 40,
+	[CMDQ_EVENT_DISP_RDMA0_EOF] = 41,
+	[CMDQ_EVENT_DISP_RDMA1_EOF] = 42,
+	[CMDQ_EVENT_DISP_RDMA2_EOF] = 43,
+	[CMDQ_EVENT_DISP_WDMA0_EOF] = 44,
+	[CMDQ_EVENT_DISP_WDMA1_EOF] = 45,
+	/* Mutex end of frame(EOF) events */
+	[CMDQ_EVENT_MUTEX0_STREAM_EOF] = 53,
+	[CMDQ_EVENT_MUTEX1_STREAM_EOF] = 54,
+	[CMDQ_EVENT_MUTEX2_STREAM_EOF] = 55,
+	[CMDQ_EVENT_MUTEX3_STREAM_EOF] = 56,
+	[CMDQ_EVENT_MUTEX4_STREAM_EOF] = 57,
+	/* Display underrun events */
+	[CMDQ_EVENT_DISP_RDMA0_UNDERRUN] = 63,
+	[CMDQ_EVENT_DISP_RDMA1_UNDERRUN] = 64,
+	[CMDQ_EVENT_DISP_RDMA2_UNDERRUN] = 65,
+};
+
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, enum cmdq_event event)
+{
+	u32 arg_b;
+
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	/*
+	 * WFE arg_b
+	 * bit 0-11: wait value
+	 * bit 15: 1 - wait, 0 - no wait
+	 * bit 16-27: update value
+	 * bit 31: 1 - update, 0 - no update
+	 */
+	arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+	return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE,
+			cmdq_event_value[event], arg_b);
+}
+EXPORT_SYMBOL(cmdq_pkt_wfe);
+
+int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, enum cmdq_event event)
+{
+	if (event >= CMDQ_MAX_EVENT || event < 0)
+		return -EINVAL;
+
+	return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE,
+			cmdq_event_value[event], CMDQ_WFE_UPDATE);
+}
+EXPORT_SYMBOL(cmdq_pkt_clear_event);
+
+static int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
+{
+	int err;
+
+	if (cmdq_pkt_is_finalized(pkt))
+		return 0;
+
+	/* insert EOC and generate IRQ for each command iteration */
+	err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
+	if (err < 0)
+		return err;
+
+	/* JUMP to end */
+	err = cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+int cmdq_pkt_flush_async(struct cmdq_client *client, struct cmdq_pkt *pkt,
+			 cmdq_async_flush_cb cb, void *data)
+{
+	int err;
+
+	err = cmdq_pkt_finalize(pkt);
+	if (err < 0)
+		return err;
+
+	pkt->cb.cb = cb;
+	pkt->cb.data = data;
+
+	mbox_send_message(client->chan, pkt);
+	/* We can send next packet immediately, so just call txdone. */
+	mbox_client_txdone(client->chan, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(cmdq_pkt_flush_async);
+
+struct cmdq_flush_completion {
+	struct completion cmplt;
+	bool err;
+};
+
+static void cmdq_pkt_flush_cb(struct cmdq_cb_data data)
+{
+	struct cmdq_flush_completion *cmplt = data.data;
+
+	cmplt->err = data.err;
+	complete(&cmplt->cmplt);
+}
+
+int cmdq_pkt_flush(struct cmdq_client *client, struct cmdq_pkt *pkt)
+{
+	struct cmdq_flush_completion cmplt;
+	int err;
+
+	init_completion(&cmplt.cmplt);
+	err = cmdq_pkt_flush_async(client, pkt, cmdq_pkt_flush_cb, &cmplt);
+	if (err < 0)
+		return err;
+	wait_for_completion(&cmplt.cmplt);
+	return cmplt.err ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(cmdq_pkt_flush);
diff --git a/include/linux/mailbox/mtk-cmdq-mailbox.h b/include/linux/mailbox/mtk-cmdq-mailbox.h
new file mode 100644
index 0000000..131b8b3
--- /dev/null
+++ b/include/linux/mailbox/mtk-cmdq-mailbox.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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 __MTK_CMDQ_MAILBOX_H__
+#define __MTK_CMDQ_MAILBOX_H__
+
+#include <linux/slab.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#define CMDQ_INST_SIZE			8 /* instruction is 64-bit */
+#define CMDQ_OP_CODE_SHIFT		24
+#define CMDQ_JUMP_PASS			CMDQ_INST_SIZE
+
+#define CMDQ_WFE_UPDATE			BIT(31)
+#define CMDQ_WFE_WAIT			BIT(15)
+#define CMDQ_WFE_WAIT_VALUE		0x1
+
+/*
+ * CMDQ_CODE_MASK:
+ *   set write mask
+ *   format: op mask
+ * CMDQ_CODE_WRITE:
+ *   write value into target register
+ *   format: op subsys address value
+ * CMDQ_CODE_JUMP:
+ *   jump by offset
+ *   format: op offset
+ * CMDQ_CODE_WFE:
+ *   wait for event and clear
+ *   it is just clear if no wait
+ *   format: [wait]  op event update:1 to_wait:1 wait:1
+ *           [clear] op event update:1 to_wait:0 wait:0
+ * CMDQ_CODE_EOC:
+ *   end of command
+ *   format: op irq_flag
+ */
+enum cmdq_code {
+	CMDQ_CODE_MASK = 0x02,
+	CMDQ_CODE_WRITE = 0x04,
+	CMDQ_CODE_JUMP = 0x10,
+	CMDQ_CODE_WFE = 0x20,
+	CMDQ_CODE_EOC = 0x40,
+};
+
+struct cmdq_task_cb {
+	cmdq_async_flush_cb	cb;
+	void			*data;
+};
+
+struct cmdq_pkt {
+	void			*va_base;
+	size_t			cmd_buf_size; /* command occupied size */
+	size_t			buf_size; /* real buffer size */
+	struct cmdq_task_cb	cb;
+};
+
+#endif /* __MTK_CMDQ_MAILBOX_H__ */
diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h
new file mode 100644
index 0000000..7320837
--- /dev/null
+++ b/include/linux/soc/mediatek/mtk-cmdq.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * 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 __MTK_CMDQ_H__
+#define __MTK_CMDQ_H__
+
+#include <linux/mailbox_client.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* display events in command queue(CMDQ) */
+enum cmdq_event {
+	/* Display start of frame(SOF) events */
+	CMDQ_EVENT_DISP_OVL0_SOF,
+	CMDQ_EVENT_DISP_OVL1_SOF,
+	CMDQ_EVENT_DISP_RDMA0_SOF,
+	CMDQ_EVENT_DISP_RDMA1_SOF,
+	CMDQ_EVENT_DISP_RDMA2_SOF,
+	CMDQ_EVENT_DISP_WDMA0_SOF,
+	CMDQ_EVENT_DISP_WDMA1_SOF,
+	/* Display end of frame(EOF) events */
+	CMDQ_EVENT_DISP_OVL0_EOF,
+	CMDQ_EVENT_DISP_OVL1_EOF,
+	CMDQ_EVENT_DISP_RDMA0_EOF,
+	CMDQ_EVENT_DISP_RDMA1_EOF,
+	CMDQ_EVENT_DISP_RDMA2_EOF,
+	CMDQ_EVENT_DISP_WDMA0_EOF,
+	CMDQ_EVENT_DISP_WDMA1_EOF,
+	/* Mutex end of frame(EOF) events */
+	CMDQ_EVENT_MUTEX0_STREAM_EOF,
+	CMDQ_EVENT_MUTEX1_STREAM_EOF,
+	CMDQ_EVENT_MUTEX2_STREAM_EOF,
+	CMDQ_EVENT_MUTEX3_STREAM_EOF,
+	CMDQ_EVENT_MUTEX4_STREAM_EOF,
+	/* Display underrun events */
+	CMDQ_EVENT_DISP_RDMA0_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA1_UNDERRUN,
+	CMDQ_EVENT_DISP_RDMA2_UNDERRUN,
+	/* Keep this at the end */
+	CMDQ_MAX_EVENT,
+};
+
+struct cmdq_cb_data {
+	bool	err;
+	void	*data;
+};
+
+typedef void (*cmdq_async_flush_cb)(struct cmdq_cb_data data);
+
+struct cmdq_pkt;
+
+struct cmdq_base {
+	int	subsys;
+	u32	base;
+};
+
+struct cmdq_client {
+	struct mbox_client client;
+	struct mbox_chan *chan;
+};
+
+/**
+ * cmdq_register_device() - register device which needs CMDQ
+ * @dev:	device for CMDQ to access its registers
+ *
+ * Return: cmdq_base pointer or NULL for failed
+ */
+struct cmdq_base *cmdq_register_device(struct device *dev);
+
+/**
+ * cmdq_mbox_create() - create CMDQ mailbox client and channel
+ * @dev:	device of CMDQ mailbox client
+ * @index:	index of CMDQ mailbox channel
+ *
+ * Return: CMDQ mailbox client pointer
+ */
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index);
+
+/**
+ * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel
+ * @client:	the CMDQ mailbox client
+ */
+void cmdq_mbox_destroy(struct cmdq_client *client);
+
+/**
+ * cmdq_pkt_create() - create a CMDQ packet
+ * @pkt_ptr:	CMDQ packet pointer to retrieve cmdq_pkt
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_create(struct cmdq_pkt **pkt_ptr);
+
+/**
+ * cmdq_pkt_destroy() - destroy the CMDQ packet
+ * @pkt:	the CMDQ packet
+ */
+void cmdq_pkt_destroy(struct cmdq_pkt *pkt);
+
+/**
+ * cmdq_pkt_write() - append write command to the CMDQ packet
+ * @pkt:	the CMDQ packet
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value,
+		   struct cmdq_base *base, u32 offset);
+
+/**
+ * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet
+ * @pkt:	the CMDQ packet
+ * @value:	the specified target register value
+ * @base:	the CMDQ base
+ * @offset:	register offset from module base
+ * @mask:	the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
+			struct cmdq_base *base, u32 offset, u32 mask);
+
+/**
+ * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet
+ * @pkt:	the CMDQ packet
+ * @event:	the desired event type to "wait and CLEAR"
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, enum cmdq_event event);
+
+/**
+ * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet
+ * @pkt:	the CMDQ packet
+ * @event:	the desired event to be cleared
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, enum cmdq_event event);
+
+/**
+ * cmdq_pkt_flush() - trigger CMDQ to execute the CMDQ packet
+ * @client:	the CMDQ mailbox client
+ * @pkt:	the CMDQ packet
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to execute the CMDQ packet. Note that this is a
+ * synchronous flush function. When the function returned, the recorded
+ * commands have been done.
+ */
+int cmdq_pkt_flush(struct cmdq_client *client, struct cmdq_pkt *pkt);
+
+/**
+ * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ
+ *                          packet and call back at the end of done packet
+ * @client:	the CMDQ mailbox client
+ * @pkt:	the CMDQ packet
+ * @cb:		called at the end of done packet
+ * @data:	this data will pass back to cb
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to asynchronously execute the CMDQ packet and call back
+ * at the end of done packet. Note that this is an ASYNC function. When the
+ * function returned, it may or may not be finished.
+ */
+int cmdq_pkt_flush_async(struct cmdq_client *client, struct cmdq_pkt *pkt,
+			 cmdq_async_flush_cb cb, void *data);
+
+#endif	/* __MTK_CMDQ_H__ */
-- 
1.9.1

^ permalink raw reply related

* [PATCH v15 1/4] dt-bindings: soc: Add documentation for the MediaTek GCE unit
From: HS Liao @ 2016-10-17 10:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476699117-3001-1-git-send-email-hs.liao@mediatek.com>

This adds documentation for the MediaTek Global Command Engine (GCE) unit
found in MT8173 SoCs.

Signed-off-by: HS Liao <hs.liao@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/mailbox/mtk-gce.txt        | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/mtk-gce.txt

diff --git a/Documentation/devicetree/bindings/mailbox/mtk-gce.txt b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt
new file mode 100644
index 0000000..d2d3ccb
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt
@@ -0,0 +1,43 @@
+MediaTek GCE
+===============
+
+The Global Command Engine (GCE) is used to help read/write registers with
+critical time limitation, such as updating display configuration during the
+vblank. The GCE can be used to implement the Command Queue (CMDQ) driver.
+
+CMDQ driver uses mailbox framework for communication. Please refer to
+mailbox.txt for generic information about mailbox device-tree bindings.
+
+Required properties:
+- compatible: Must be "mediatek,mt8173-gce"
+- reg: Address range of the GCE unit
+- interrupts: The interrupt signal from the GCE block
+- clock: Clocks according to the common clock binding
+- clock-names: Must be "gce" to stand for GCE clock
+- #mbox-cells: Should be 2
+
+Required properties for a client device:
+- mboxes: client use mailbox to communicate with GCE, it should have this
+  property and list of phandle, mailbox channel specifiers, and atomic
+  execution flag.
+
+Example:
+
+	gce: gce at 10212000 {
+		compatible = "mediatek,mt8173-gce";
+		reg = <0 0x10212000 0 0x1000>;
+		interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&infracfg CLK_INFRA_GCE>;
+		clock-names = "gce";
+
+		#mbox-cells = <2>;
+	};
+
+Example for a client device:
+
+	mmsys: clock-controller at 14000000 {
+		compatible = "mediatek,mt8173-mmsys";
+		mboxes = <&gce 0 1 /* main display with atomic execution */
+			  &gce 1 1>; /* sub display with atomic execution */
+		...
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v15 0/4] Mediatek MT8173 CMDQ support
From: HS Liao @ 2016-10-17 10:11 UTC (permalink / raw)
  To: linux-arm-kernel


Hi,

This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
to help write registers with critical time limitation, such as
updating display configuration during the vblank. It controls Global
Command Engine (GCE) hardware to achieve this requirement.

These patches have a build dependency on top of v4.9-rc1.

Changes since v14:
 - split driver into mtk-cmdq-mailbox and mtk-cmdq-helper
 - split cmdq_task into cmdq_pkt for client and cmdq_task for controller
 - remove mailbox_controller.h from mtk-cmdq.h
 - replace msleep() by schedule()
 - replace irq_of_parse_and_map() by platform_get_irq()
 - remove .owner = THIS_MODULE
 - rebase to Linux v4.9-rc1

Best regards,
HS Liao

HS Liao (4):
  dt-bindings: soc: Add documentation for the MediaTek GCE unit
  CMDQ: Mediatek CMDQ driver
  arm64: dts: mt8173: Add GCE node
  CMDQ: save energy

 .../devicetree/bindings/mailbox/mtk-gce.txt        |  43 ++
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |  10 +
 drivers/mailbox/Kconfig                            |  10 +
 drivers/mailbox/Makefile                           |   2 +
 drivers/mailbox/mtk-cmdq-mailbox.c                 | 634 +++++++++++++++++++++
 drivers/soc/mediatek/Kconfig                       |  11 +
 drivers/soc/mediatek/Makefile                      |   1 +
 drivers/soc/mediatek/mtk-cmdq-helper.c             | 310 ++++++++++
 include/linux/mailbox/mtk-cmdq-mailbox.h           |  67 +++
 include/linux/soc/mediatek/mtk-cmdq.h              | 182 ++++++
 10 files changed, 1270 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/mtk-gce.txt
 create mode 100644 drivers/mailbox/mtk-cmdq-mailbox.c
 create mode 100644 drivers/soc/mediatek/mtk-cmdq-helper.c
 create mode 100644 include/linux/mailbox/mtk-cmdq-mailbox.h
 create mode 100644 include/linux/soc/mediatek/mtk-cmdq.h

-- 
1.9.1

^ permalink raw reply

* PROBLEM: DWC3 USB 3.0 not working on Odroid-XU4 with Exynos 5422
From: Vivek Gautam @ 2016-10-17  9:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <874m4btn2m.fsf@linux.intel.com>



On 10/17/2016 01:38 PM, Felipe Balbi wrote:
> Hi,
>
> Michael Niew?hner <linux@mniewoehner.de> writes:
>> Hi Felipe,
>> On Fri, 2016-10-07 at 22:26 +0200, Michael Niew?hner wrote:
>>> Hi Felipe,
>>>
>>> On Fr, 2016-10-07 at 10:42 +0300, Felipe Balbi wrote:
>>>> Hi,
>>>>
>>>> Michael Niew?hner <linux@mniewoehner.de> writes:
>>>>>> The clocks are same across working/non-working.
>>>>>> Is it possible to bisect the commit that's causing hang for 4.8x ?
>>>>>
>>>>> [c499ff71ff2a281366c6ec7a904c547d806cbcd1] usb: dwc3: core: re-factor init and exit paths
>>>>> This patch causes both the hang on reboot and the lsusb hang.
>>>> How to reproduce? Why don't we see this on x86 and TI boards? I'm
>>>> guessing this is failed bisection, as I can't see anything in that
>>>> commit that would cause reboot hang. Also, that code path is *NOT*
>>>> executed when you run lsusb.
>>>>
>>> I've tested this procedure multiple times to be sure:
>>>
>>> - checkout c499ff71, compile, boot the odroid
>>> - run lsusb -v => lsusb hangs, can't terminate with ctrl-c
>>> - hard reset, after boot run poweroff or reboot => board does not completely power off / reboot (see log below)
>>> - revert c499ff71, mrproper, compile, boot the odroid
>>> - run lsusb -v => shows full output, not hanging
>>> - run reboot or poweroff => board powers off / reboots just fine
>>>
>>>
>>> dmesg poweroff not working:
>>> ...
>>> [  120.733519] systemd-journald[144]: systemd-journald stopped as pid 144
>>> [  120.742663] systemd-shutdown[1]: Sending SIGKILL to remaining processes...
>>> [  120.769212] systemd-shutdown[1]: Unmounting file systems.
>>> [  120.773713] systemd-shutdown[1]: Unmounting /sys/kernel/debug.
>>> [  120.827211] systemd-shutdown[1]: Unmounting /dev/mqueue.
>>> [  121.081672] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.091687] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.095608] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.101014] systemd-shutdown[1]: All filesystems unmounted.
>>> [  121.106523] systemd-shutdown[1]: Deactivating swaps.
>>> [  121.111585] systemd-shutdown[1]: All swaps deactivated.
>>> [  121.116661] systemd-shutdown[1]: Detaching loop devices.
>>> [  121.126395] systemd-shutdown[1]: All loop devices detached.
>>> [  121.130525] systemd-shutdown[1]: Detaching DM devices.
>>> [  121.135824] systemd-shutdown[1]: All DM devices detached.
>>> [  121.166327] systemd-shutdown[1]: /lib/systemd/system-shutdown succeeded.
>>> [  121.171739] systemd-shutdown[1]: Powering off.
>>>
>>> => at this point removing the sd card would show a message
>>> "removed mmc0" (not sure what the real message was...) so the board is not completely off.
>>>
>>>
>>> dmesg poweroff working:
>>> ...
>>> [  120.733519] systemd-journald[144]: systemd-journald stopped as pid 144
>>> [  120.742663] systemd-shutdown[1]: Sending SIGKILL to remaining processes...
>>> [  120.769212] systemd-shutdown[1]: Unmounting file systems.
>>> [  120.773713] systemd-shutdown[1]: Unmounting /sys/kernel/debug.
>>> [  120.827211] systemd-shutdown[1]: Unmounting /dev/mqueue.
>>> [  121.081672] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.091687] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.095608] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)
>>> [  121.101014] systemd-shutdown[1]: All filesystems unmounted.
>>> [  121.106523] systemd-shutdown[1]: Deactivating swaps.
>>> [  121.111585] systemd-shutdown[1]: All swaps deactivated.
>>> [  121.116661] systemd-shutdown[1]: Detaching loop devices.
>>> [  121.126395] systemd-shutdown[1]: All loop devices detached.
>>> [  121.130525] systemd-shutdown[1]: Detaching DM devices.
>>> [  121.135824] systemd-shutdown[1]: All DM devices detached.
>>> [  121.166327] systemd-shutdown[1]: /lib/systemd/system-shutdown succeeded.
>>> [  121.171739] systemd-shutdown[1]: Powering off.
>>> [  121.182331] rebo?
>>>
>>>
>>>
>>> Best regards
>>> Michael Niew?hner
>>
>> I did some more tests with next-20161016. Reverting / commenting out
>> one part of your patch "solves" the lsusb hang, the reboot problem
>> and also the "debounce failed" message. [1]
>> Another "solution" is to call phy_power_off before phy_power_on. [2]
>>
>> Disclaimer: I have no idea what I was doing ;-) These were just some
>> simple trial-and-error attempts that maybe help to find the real
>> cause of the problems.
>>
>> [1]
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index 7287a76..5ef589d 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -724,6 +724,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
>>   	/* Adjust Frame Length */
>>   	dwc3_frame_length_adjustment(dwc);
>>   
>> +/*
>>   	usb_phy_set_suspend(dwc->usb2_phy, 0);
>>   	usb_phy_set_suspend(dwc->usb3_phy, 0);
>>   	ret = phy_power_on(dwc->usb2_generic_phy);
>> @@ -733,6 +734,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
>>   	ret = phy_power_on(dwc->usb3_generic_phy);
>>   	if (ret < 0)
>>   		goto err3;
>> +*/
>>   
>>   	ret = dwc3_event_buffers_setup(dwc);
>>   	if (ret) {
>>
>> [2]
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index 7287a76..f6c8e13 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -726,6 +726,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
>>   
>>          usb_phy_set_suspend(dwc->usb2_phy, 0);
>>          usb_phy_set_suspend(dwc->usb3_phy, 0);
>> +       phy_power_off(dwc->usb2_generic_phy);
>> +       phy_power_off(dwc->usb3_generic_phy);
> This looks like a PHY driver bug to me. Which PHY driver are you using?
>

The exynos5-usbdrd phy driver is used for exynos platforms.
Looks like something is not right with the phy driver even
after applying the phy_calibrate patches.

Michael, are you using the last set of patches for phy calibration [1]?
[1] https://lkml.org/lkml/2015/2/2/257.


Thanks
Vivek

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH] ARM64-cpuinfo: Combine six calls for sequence output into one seq_printf() call in c_show()
From: Matthias Brugger @ 2016-10-17  9:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <83d98772-8872-1b75-a9a5-5f08b8462e18@users.sourceforge.net>



On 16/10/16 21:03, SF Markus Elfring wrote:
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Sun, 16 Oct 2016 20:48:28 +0200
>
> Some data were printed into a sequence by six separate function calls.
> Print the same data by a single function call instead.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
> ---

Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>

>  arch/arm64/kernel/cpuinfo.c | 19 +++++++++++--------
>  1 file changed, 11 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
> index b3d5b3e..f22687d 100644
> --- a/arch/arm64/kernel/cpuinfo.c
> +++ b/arch/arm64/kernel/cpuinfo.c
> @@ -148,14 +148,17 @@ static int c_show(struct seq_file *m, void *v)
>  				if (elf_hwcap & (1 << j))
>  					seq_printf(m, " %s", hwcap_str[j]);
>  		}
> -		seq_puts(m, "\n");
> -
> -		seq_printf(m, "CPU implementer\t: 0x%02x\n",
> -			   MIDR_IMPLEMENTOR(midr));
> -		seq_printf(m, "CPU architecture: 8\n");
> -		seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
> -		seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
> -		seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
> +		seq_printf(m,
> +			   "\n"
> +			   "CPU implementer\t: 0x%02x\n"
> +			   "CPU architecture: 8\n"
> +			   "CPU variant\t: 0x%x\n"
> +			   "CPU part\t: 0x%03x\n"
> +			   "CPU revision\t: %d\n\n",
> +			   MIDR_IMPLEMENTOR(midr),
> +			   MIDR_VARIANT(midr),
> +			   MIDR_PARTNUM(midr),
> +			   MIDR_REVISION(midr));
>  	}
>
>  	return 0;
>

^ permalink raw reply

* [PATCH 1/2] ARM: oxnas: Add OX820 SMP support
From: Neil Armstrong @ 2016-10-17  9:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <14513531.isB50DxNJf@wuerfel>

On 10/17/2016 11:06 AM, Arnd Bergmann wrote:
> On Monday, October 17, 2016 10:43:02 AM CEST Neil Armstrong wrote:
>> +
>> +       /*
>> +        * This is really belt and braces; we hold unintended secondary
>> +        * CPUs in the holding pen until we're ready for them.  However,
>> +        * since we haven't sent them a soft interrupt, they shouldn't
>> +        * be there.
>> +        */
>> +       write_pen_release(cpu);
>> +
>> +       /*
>> +        * Enable GIC cpu interface in CPU Interface Control Register
>> +        */
>> +       writel(GIC_CPU_CTRL_ENABLE,
>> +               gic_cpu_ctrl + GIC_NCPU_OFFSET(cpu) + GIC_CPU_CTRL);
>> +
>> +       /*
>> +        * Send the secondary CPU a soft interrupt, thereby causing
>> +        * the boot monitor to read the system wide flags register,
>> +        * and branch to the address found there.
>> +        */
>> +
>> +       arch_send_wakeup_ipi_mask(cpumask_of(cpu));
>> +       timeout = jiffies + (1 * HZ);
>> +       while (time_before(jiffies, timeout)) {
>> +               smp_rmb();
>> +               if (read_pen_release() == -1)
>> +                       break;
>> +
>> +               udelay(10);
>> +       }
>>
> 
> This seems to have been copied from plat-versatile, but is really
> not needed here since you apparently have proper hardware support for
> starting up the CPUs.
Yes it seems.

> 
> Any reason you can't just write to the cpu_ctrl register
> once and keep going without that whole holding_pen loop
> and spinlock?
I suppose but I did not find any good examples except the plat-versatile code.
I will try some simpler code.

> 
> 	Arnd
> 

Neil

^ permalink raw reply

* [PATCH 10/10] mm: replace access_process_vm() write parameter with gup_flags
From: Jesper Nilsson @ 2016-10-17  9:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-11-lstoakes@gmail.com>

On Thu, Oct 13, 2016 at 01:20:20AM +0100, Lorenzo Stoakes wrote:
> This patch removes the write parameter from access_process_vm() and replaces it
> with a gup_flags parameter as use of this function previously _implied_
> FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> 
> We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> (and hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
> ---
>  arch/cris/arch-v32/kernel/ptrace.c |  4 ++--

For the CRIS part:

Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>

/^JN - Jesper Nilsson
-- 
               Jesper Nilsson -- jesper.nilsson at axis.com

^ permalink raw reply

* [PATCH] ARM: defconfig: update U8500 defconfig
From: Linus Walleij @ 2016-10-17  9:23 UTC (permalink / raw)
  To: linux-arm-kernel

Some config options like perf events and PM are now implicit,
we have an upstream driver for the AK8974, and we really
want the HRTIMER software triggers from configfs with some
of the sensors.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ARM SoC folks: please apply this wherever your usual batch of
defconfig changes go.
---
 arch/arm/configs/u8500_defconfig | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index b7b09189f1c5..e2151a7aaf49 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -4,7 +4,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_PERF_EVENTS=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -26,7 +25,6 @@ CONFIG_CPU_IDLE=y
 CONFIG_ARM_U8500_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -108,18 +106,19 @@ CONFIG_DMADEVICES=y
 CONFIG_STE_DMA40=y
 CONFIG_HSEM_U8500=y
 CONFIG_IIO=y
-CONFIG_IIO_BUFFER=y
+CONFIG_IIO_SW_TRIGGER=y
 CONFIG_IIO_ST_ACCEL_3AXIS=y
 CONFIG_IIO_ST_GYRO_3AXIS=y
 CONFIG_BH1780=y
+CONFIG_AK8974=y
 CONFIG_IIO_ST_MAGN_3AXIS=y
+CONFIG_IIO_HRTIMER_TRIGGER=y
 CONFIG_IIO_ST_PRESS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
-- 
2.7.4

^ permalink raw reply related

* [PATCH 06/10] mm: replace get_user_pages() write/force parameters with gup_flags
From: Jesper Nilsson @ 2016-10-17  9:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161013002020.3062-7-lstoakes@gmail.com>

On Thu, Oct 13, 2016 at 01:20:16AM +0100, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
> ---
>  arch/cris/arch-v32/drivers/cryptocop.c                 |  4 +---

For the CRIS part:

Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>

/^JN - Jesper Nilsson
-- 
               Jesper Nilsson -- jesper.nilsson at axis.com

^ permalink raw reply

* [PATCH] atags_proc: add missing \n when no ATAGs
From: Kefeng Wang @ 2016-10-17  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

No ATAGs message is missing a \n, add it.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 arch/arm/kernel/atags_proc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/kernel/atags_proc.c b/arch/arm/kernel/atags_proc.c
index 5a33790..d7af7b8 100644
--- a/arch/arm/kernel/atags_proc.c
+++ b/arch/arm/kernel/atags_proc.c
@@ -41,7 +41,7 @@ static int __init init_atags_procfs(void)
 	size_t size;
 
 	if (tag->hdr.tag != ATAG_CORE) {
-		pr_info("No ATAGs?");
+		pr_info("No ATAGs?\n");
 		return -EINVAL;
 	}
 
-- 
1.7.12.4

^ permalink raw reply related

* [PATCH 1/2] ARM: oxnas: Add OX820 SMP support
From: Arnd Bergmann @ 2016-10-17  9:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017084303.20078-2-narmstrong@baylibre.com>

On Monday, October 17, 2016 10:43:02 AM CEST Neil Armstrong wrote:
> +
> +       /*
> +        * This is really belt and braces; we hold unintended secondary
> +        * CPUs in the holding pen until we're ready for them.  However,
> +        * since we haven't sent them a soft interrupt, they shouldn't
> +        * be there.
> +        */
> +       write_pen_release(cpu);
> +
> +       /*
> +        * Enable GIC cpu interface in CPU Interface Control Register
> +        */
> +       writel(GIC_CPU_CTRL_ENABLE,
> +               gic_cpu_ctrl + GIC_NCPU_OFFSET(cpu) + GIC_CPU_CTRL);
> +
> +       /*
> +        * Send the secondary CPU a soft interrupt, thereby causing
> +        * the boot monitor to read the system wide flags register,
> +        * and branch to the address found there.
> +        */
> +
> +       arch_send_wakeup_ipi_mask(cpumask_of(cpu));
> +       timeout = jiffies + (1 * HZ);
> +       while (time_before(jiffies, timeout)) {
> +               smp_rmb();
> +               if (read_pen_release() == -1)
> +                       break;
> +
> +               udelay(10);
> +       }
> 

This seems to have been copied from plat-versatile, but is really
not needed here since you apparently have proper hardware support for
starting up the CPUs.

Any reason you can't just write to the cpu_ctrl register
once and keep going without that whole holding_pen loop
and spinlock?

	Arnd

^ permalink raw reply

* [PATCH 2/2] ARM: oxnas: Add OX820 config and makefile entry
From: Neil Armstrong @ 2016-10-17  8:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017084303.20078-1-narmstrong@baylibre.com>

Refactor the oxnas Kconfig entries among the OX810SE and OX820 configs,
and add the files to support the OX820 SMP feature.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm/Makefile           |  1 +
 arch/arm/mach-oxnas/Kconfig | 30 +++++++++++++++++++++---------
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 6be9ee1..68312a9 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -191,6 +191,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
 machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
+machine-$(CONFIG_ARCH_OXNAS)		+= oxnas
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
diff --git a/arch/arm/mach-oxnas/Kconfig b/arch/arm/mach-oxnas/Kconfig
index 29100be..8fa4557 100644
--- a/arch/arm/mach-oxnas/Kconfig
+++ b/arch/arm/mach-oxnas/Kconfig
@@ -1,9 +1,16 @@
 menuconfig ARCH_OXNAS
 	bool "Oxford Semiconductor OXNAS Family SoCs"
 	select ARCH_HAS_RESET_CONTROLLER
+	select COMMON_CLK_OXNAS
 	select GPIOLIB
+	select MFD_SYSCON
+	select OXNAS_RPS_TIMER
+	select PINCTRL_OXNAS
+	select RESET_CONTROLLER
+	select RESET_OXNAS
+	select VERSATILE_FPGA_IRQ
 	select PINCTRL
-	depends on ARCH_MULTI_V5
+	depends on ARCH_MULTI_V5 || ARCH_MULTI_V6
 	help
 	  Support for OxNas SoC family developed by Oxford Semiconductor.
 
@@ -11,16 +18,21 @@ if ARCH_OXNAS
 
 config MACH_OX810SE
 	bool "Support OX810SE Based Products"
-	select ARCH_HAS_RESET_CONTROLLER
-	select COMMON_CLK_OXNAS
+	depends on ARCH_MULTI_V5
 	select CPU_ARM926T
-	select MFD_SYSCON
-	select OXNAS_RPS_TIMER
-	select PINCTRL_OXNAS
-	select RESET_CONTROLLER
-	select RESET_OXNAS
-	select VERSATILE_FPGA_IRQ
 	help
 	  Include Support for the Oxford Semiconductor OX810SE SoC Based Products.
 
+config MACH_OX820
+	bool "Support OX820 Based Products"
+	depends on ARCH_MULTI_V6
+	select ARM_GIC
+	select DMA_CACHE_RWFO if SMP
+	select CPU_V6K
+	select HAVE_SMP
+	select HAVE_ARM_SCU if SMP
+	select HAVE_ARM_TWD if SMP
+	help
+	  Include Support for the Oxford Semiconductor OX820 SoC Based Products.
+
 endif
-- 
2.7.0

^ permalink raw reply related

* [PATCH 1/2] ARM: oxnas: Add OX820 SMP support
From: Neil Armstrong @ 2016-10-17  8:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017084303.20078-1-narmstrong@baylibre.com>

The Oxford Semiconductor OX820 is a ARM11MPcore based SoC sharing some
features with the OX810 earlier SoC.
This patch adds the core to wake up the second core.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm/mach-oxnas/Makefile  |   2 +
 arch/arm/mach-oxnas/headsmp.S |  28 ++++++++
 arch/arm/mach-oxnas/hotplug.c | 111 +++++++++++++++++++++++++++++
 arch/arm/mach-oxnas/platsmp.c | 161 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 arch/arm/mach-oxnas/Makefile
 create mode 100644 arch/arm/mach-oxnas/headsmp.S
 create mode 100644 arch/arm/mach-oxnas/hotplug.c
 create mode 100644 arch/arm/mach-oxnas/platsmp.c

diff --git a/arch/arm/mach-oxnas/Makefile b/arch/arm/mach-oxnas/Makefile
new file mode 100644
index 0000000..b625906
--- /dev/null
+++ b/arch/arm/mach-oxnas/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) 	+= hotplug.o
diff --git a/arch/arm/mach-oxnas/headsmp.S b/arch/arm/mach-oxnas/headsmp.S
new file mode 100644
index 0000000..2a94dcb
--- /dev/null
+++ b/arch/arm/mach-oxnas/headsmp.S
@@ -0,0 +1,28 @@
+/*
+ * linux/arch/arm/mach-oxnas/headsmp.S
+ *
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * 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.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+	__INIT
+
+/*
+ * OX820 specific entry point for secondary CPUs.
+ */
+ENTRY(ox820_secondary_startup)
+	mov r4, #0
+	/* invalidate both caches and branch target cache */
+	mcr p15, 0, r4, c7, c7, 0
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
diff --git a/arch/arm/mach-oxnas/hotplug.c b/arch/arm/mach-oxnas/hotplug.c
new file mode 100644
index 0000000..18fa814
--- /dev/null
+++ b/arch/arm/mach-oxnas/hotplug.c
@@ -0,0 +1,111 @@
+/*
+ *  linux/arch/arm/mach-oxnas/hotplug.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+
+#include <asm/cp15.h>
+#include <asm/smp_plat.h>
+
+static inline void cpu_enter_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(
+	"	mcr	p15, 0, %1, c7, c5, 0\n"
+	"	mcr	p15, 0, %1, c7, c10, 4\n"
+	/*
+	 * Turn off coherency
+	 */
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	bic	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	"	mrc	p15, 0, %0, c1, c0, 0\n"
+	"	bic	%0, %0, %2\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	  : "=&r" (v)
+	  : "r" (0), "Ir" (CR_C)
+	  : "cc");
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(	"mrc	p15, 0, %0, c1, c0, 0\n"
+	"	orr	%0, %0, %1\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	orr	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	  : "=&r" (v)
+	  : "Ir" (CR_C)
+	  : "cc");
+}
+
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
+{
+	/*
+	 * there is no power-control hardware on this platform, so all
+	 * we can do is put the core into WFI; this is safe as the calling
+	 * code will have already disabled interrupts
+	 */
+	for (;;) {
+		/*
+		 * here's the WFI
+		 */
+		asm(".word	0xe320f003\n"
+		    :
+		    :
+		    : "memory", "cc");
+
+		if (pen_release == cpu_logical_map(cpu)) {
+			/*
+			 * OK, proper wakeup, we're done
+			 */
+			break;
+		}
+
+		/*
+		 * Getting here, means that we have come out of WFI without
+		 * having been woken up - this shouldn't happen
+		 *
+		 * Just note it happening - when we're woken, we can report
+		 * its occurrence.
+		 */
+		(*spurious)++;
+	}
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void ox820_cpu_die(unsigned int cpu)
+{
+	int spurious = 0;
+
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	cpu_enter_lowpower();
+	platform_do_lowpower(cpu, &spurious);
+
+	/*
+	 * bring this CPU back into the world of cache
+	 * coherency, and then restore interrupts
+	 */
+	cpu_leave_lowpower();
+
+	if (spurious)
+		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+}
diff --git a/arch/arm/mach-oxnas/platsmp.c b/arch/arm/mach-oxnas/platsmp.c
new file mode 100644
index 0000000..d2ff2c4
--- /dev/null
+++ b/arch/arm/mach-oxnas/platsmp.c
@@ -0,0 +1,161 @@
+/*
+ * arch/arm/mach-oxnas/platsmp.c
+ *
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2002 ARM Ltd.
+ * All Rights Reserved
+ *
+ * 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.
+ */
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+extern void ox820_secondary_startup(void);
+extern void ox820_cpu_die(unsigned int cpu);
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __iomem *cpu_ctrl;
+static void __iomem *gic_cpu_ctrl;
+
+#define HOLDINGPEN_CPU_OFFSET		0xc8
+#define HOLDINGPEN_LOCATION_OFFSET	0xc4
+
+#define GIC_NCPU_OFFSET(cpu)		(0x100 + (cpu)*0x100)
+#define GIC_CPU_CTRL			0x00
+#define GIC_CPU_CTRL_ENABLE		1
+
+static inline void write_pen_release(int val)
+{
+	writel(val, cpu_ctrl + HOLDINGPEN_CPU_OFFSET);
+}
+
+static inline int read_pen_release(void)
+{
+	return readl(cpu_ctrl + HOLDINGPEN_CPU_OFFSET);
+}
+
+void ox820_secondary_init(unsigned int cpu)
+{
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+int ox820_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * This is really belt and braces; we hold unintended secondary
+	 * CPUs in the holding pen until we're ready for them.  However,
+	 * since we haven't sent them a soft interrupt, they shouldn't
+	 * be there.
+	 */
+	write_pen_release(cpu);
+
+	/*
+	 * Enable GIC cpu interface in CPU Interface Control Register
+	 */
+	writel(GIC_CPU_CTRL_ENABLE,
+		gic_cpu_ctrl + GIC_NCPU_OFFSET(cpu) + GIC_CPU_CTRL);
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (read_pen_release() == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return read_pen_release() != -1 ? -ENOSYS : 0;
+}
+
+static void __init ox820_smp_prepare_cpus(unsigned int max_cpus)
+{
+	struct device_node *np;
+	void __iomem *scu_base;
+
+	np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-scu");
+	scu_base = of_iomap(np, 0);
+	of_node_put(np);
+	if (!scu_base)
+		return;
+
+	/* Remap CPU Interrupt Interface Registers */
+	np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-gic");
+	gic_cpu_ctrl = of_iomap(np, 1);
+	of_node_put(np);
+	if (!gic_cpu_ctrl)
+		goto unmap_scu;
+
+	np = of_find_compatible_node(NULL, NULL, "oxsemi,ox820-sys-ctrl");
+	cpu_ctrl = of_iomap(np, 0);
+	of_node_put(np);
+	if (!cpu_ctrl)
+		goto unmap_scu;
+
+	scu_enable(scu_base);
+	flush_cache_all();
+
+	/*
+	 * Write the address of secondary startup into the
+	 * system-wide flags register. The BootMonitor waits
+	 * until it receives a soft interrupt, and then the
+	 * secondary CPU branches to this address.
+	 */
+	writel(virt_to_phys(ox820_secondary_startup),
+			cpu_ctrl + HOLDINGPEN_LOCATION_OFFSET);
+
+unmap_scu:
+	iounmap(scu_base);
+}
+
+static const struct smp_operations ox820_smp_ops __initconst = {
+	.smp_prepare_cpus	= ox820_smp_prepare_cpus,
+	.smp_secondary_init	= ox820_secondary_init,
+	.smp_boot_secondary	= ox820_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_die		= ox820_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(ox820_smp, "oxsemi,ox820-smp", &ox820_smp_ops);
-- 
2.7.0

^ permalink raw reply related

* [PATCH 0/2] ARM: oxnas: Add SMP support for OX820
From: Neil Armstrong @ 2016-10-17  8:43 UTC (permalink / raw)
  To: linux-arm-kernel

In order to support the SMP feature of the Oxford Semiconductor OX820 SoC,
   add the necessary code to handle the wake-up, hotplug and cpu entry.

Neil Armstrong (2):
  ARM: oxnas: Add OX820 SMP support
  ARM: oxnas: Add OX820 config and makefile entry

 arch/arm/Makefile             |   1 +
 arch/arm/mach-oxnas/Kconfig   |  30 +++++---
 arch/arm/mach-oxnas/Makefile  |   2 +
 arch/arm/mach-oxnas/headsmp.S |  28 ++++++++
 arch/arm/mach-oxnas/hotplug.c | 111 +++++++++++++++++++++++++++++
 arch/arm/mach-oxnas/platsmp.c | 161 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 324 insertions(+), 9 deletions(-)
 create mode 100644 arch/arm/mach-oxnas/Makefile
 create mode 100644 arch/arm/mach-oxnas/headsmp.S
 create mode 100644 arch/arm/mach-oxnas/hotplug.c
 create mode 100644 arch/arm/mach-oxnas/platsmp.c

-- 
2.7.0

^ permalink raw reply

* [PATCH] RFC: ARM: fix the uaccess crash on PB11MPCore
From: Neil Armstrong @ 2016-10-17  8:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdYJjxVsUsFUHxhy5dgjkCvYRHFRfqJwyireysMRbrLwRg@mail.gmail.com>

On 09/12/2016 03:36 PM, Linus Walleij wrote:
> On Fri, Sep 9, 2016 at 9:57 AM, Neil Armstrong <narmstrong@baylibre.com> wrote:
>> On 07/11/2016 07:08 PM, Linus Walleij wrote:
> 
>>> The following patch was sketched by Russell in response to my
>>> crashes on the PB11MPCore after the patch for software-based
>>> priviledged no access support for ARMv8.1. See this thread:
>>> http://marc.info/?l=linux-arm-kernel&m=144051749807214&w=2
>>>
>>> I am unsure what is going on, I suspect everyone involved in
>>> the discussion is. I just want to repost this to get the
>>> discussion restarted, as I still have to apply this patch
>>> with every kernel iteration to get my PB11MPCore Realview
>>> running.
>>>
>>> I also know that Oxnas has actual, mass-deployed NAS (PogoPlug
>>> Pro variants) using PB11MPCore, and that they may or may not
>>> be seeing the same issue so I want their feedback on this: do
>>> you or do you not see this with mainline, or have you not even
>>> tested?
>>>
>>> Cc: Russell King <linux@armlinux.org.uk>
>>> Cc: Will Deacon <will.deacon@arm.com>
>>> Cc: Neil Armstrong <narmstrong@baylibre.com>
>>> Fixes: a5e090acbf54 ("ARM: software-based priviledged-no-access support")
>>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>>> ---
>>>  arch/arm/kernel/smp_tlb.c | 7 +++++++
>>>  1 file changed, 7 insertions(+)
>>
>> Hi Linus, Russell, Arnd,
>>
>> I made a quick port ox OX820 over v4.8-rc4 and when enabling CONFIG_CPU_SW_DOMAIN_PAN
>> I get the following trace at boot time :
>> [    1.690000] Unable to handle kernel paging request at virtual address b6f23684
>> [    1.690000] Unable to handle kernel paging request at virtual address b6f95ef4
>> [    1.690000] pgd = c281c000
>> [    1.690000] [b6f95ef4] *pgd=62821831, *pte=00000000, *ppte=00000000
>> [    1.690000] Internal error: Oops: 81f [#1] SMP ARM
>> [    1.690000] Modules linked in:
>> [    1.690000] CPU: 1 PID: 65 Comm: mount Not tainted 4.8.0-rc4-00001-g0e9c45d-dirty #22
>> [    1.690000] Hardware name: Generic DT based system
>> [    1.690000] task: c2aad860 task.stack: c2814000
>> [    1.690000] PC is at ipi_flush_tlb_page+0x34/0x44
>> [    1.690000] LR is at on_each_cpu_mask+0x58/0x60
>> [    1.690000] pc : [<c010d3dc>]    lr : [<c017d584>]    psr: 20000193
>> [    1.690000] sp : c2815da0  ip : 00000002  fp : 00067c40
>> [    1.690000] r10: c0702744  r9 : 67c4079f  r8 : 67c9e75f
>> [    1.690000] r7 : c2815dbc  r6 : c010d3a8  r5 : c2816164  r4 : 20000113
>> [    1.690000] r3 : 00000000  r2 : b6f95003  r1 : 00000003  r0 : 00000003
>> [    1.690000] Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment none
>> [    1.690000] Control: 00c5787d  Table: 6281c00a  DAC: 00000051
>> [    1.690000] Process mount (pid: 65, stack limit = 0xc2814190)
>> [    1.690000] Stack: (0xc2815da0 to 0xc2816000)
>> [...]
>> [    1.690000] ---[ end trace 8f1207a6d611da09 ]---
>>
>> When applying this patch, it solved the issue.
>>
>> Tested-by: Neil Armstrong <narmstrong@baylibre.com>
> 
> So this problem appears on all ARM11MPcore, not just the RealView.
> 
> Yours,
> Linus Walleij
> 

Hi Russell,

Is there a plan to push this fix as it appears to break the Realview platform and the OX820 I am currently pushing ?

Thanks,
Neil

^ permalink raw reply

* [PATCH v4 2/8] scpi: Add alternative legacy structures, functions and macros
From: Neil Armstrong @ 2016-10-17  8:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <7bf3b68c-19aa-85c3-8b20-66b7380eaf3f@arm.com>

On 10/10/2016 04:36 PM, Sudeep Holla wrote:
> Hi Neil,
> 
> Sorry, I could not reply to your response on v3. Anyways I will review v4.
> 
> On 05/10/16 08:33, Neil Armstrong wrote:
>> This patch adds support for the Legacy SCPI protocol in early JUNO versions and
>> shipped Amlogic ARMv8 based SoCs. Some Rockchip SoC are also known to use this
>> version of protocol with extended vendor commands
>> .
>> In order to support the legacy SCPI protocol variant, add back the structures
>> and macros that varies against the final specification.
>> Then add indirection table for legacy commands.
>> Finally Add bitmap field for channel selection since the Legacy protocol mandates to
>> send a selected subset of the commands on the high priority channel instead of the
>> low priority channel.
>>
>> The message sending path differs from the final SCPI procotocol because the
>> Amlogic SCP firmware always reply 1 instead of a special value containing the command
>> byte and replied rx data length.
>> For this reason commands queuing cannot be used and we assume the reply command is
>> the head of the rx_pending list since we ensure sequential command sending with a
>> separate dedicated mutex.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/firmware/arm_scpi.c | 221 +++++++++++++++++++++++++++++++++++++++-----
>>  1 file changed, 199 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
>> index 498afa0..6244eb1 100644
>> --- a/drivers/firmware/arm_scpi.c
>> +++ b/drivers/firmware/arm_scpi.c
> 
> [...]
> 
>> @@ -307,21 +398,46 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
>>          return;
>>      }
>>
>> -    list_for_each_entry(t, &ch->rx_pending, node)
>> -        if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
>> -            list_del(&t->node);
>> -            match = t;
>> -            break;
>> -        }
>> +    /* Command type is not replied by the SCP Firmware in legacy Mode
>> +     * We should consider that command is the head of pending RX commands
>> +     * if the list is not empty. In TX only mode, the list would be empty.
>> +     */
>> +    if (scpi_info->is_legacy) {
>> +        match = list_first_entry(&ch->rx_pending, struct scpi_xfer,
>> +                     node);
>> +        list_del(&match->node);
>> +    } else {
>> +        list_for_each_entry(t, &ch->rx_pending, node)
>> +            if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
>> +                list_del(&t->node);
>> +                match = t;
>> +                break;
>> +            }
>> +    }
>>      /* check if wait_for_completion is in progress or timed-out */
>>      if (match && !completion_done(&match->done)) {
>> -        struct scpi_shared_mem *mem = ch->rx_payload;
>> -        unsigned int len = min(match->rx_len, CMD_SIZE(cmd));
>> +        unsigned int len;
>> +
>> +        if (scpi_info->is_legacy) {
>> +            struct legacy_scpi_shared_mem *mem = ch->rx_payload;
>> +
>> +            /* RX Length is not replied by the lagcy Firmware */
>> +            len = match->rx_len;
>> +
>> +            match->status = le32_to_cpu(mem->status);
>> +            memcpy_fromio(match->rx_buf, mem->payload, len);
> 
> The above 2 seems common to both, no ?

No, the shared_mem structure differs.

> 
>> +        } else {
>> +            struct scpi_shared_mem *mem = ch->rx_payload;
>> +
>> +            len = min(match->rx_len, CMD_SIZE(cmd));
>> +
>> +            match->status = le32_to_cpu(mem->status);
>> +            memcpy_fromio(match->rx_buf, mem->payload, len);
>> +        }
>>
>> -        match->status = le32_to_cpu(mem->status);
>> -        memcpy_fromio(match->rx_buf, mem->payload, len);
>>          if (match->rx_len > len)
>>              memset(match->rx_buf + len, 0, match->rx_len - len);
>> +
> 
> Spurious ?

Yep

> 
>>          complete(&match->done);
>>      }
>>      spin_unlock_irqrestore(&ch->rx_lock, flags);
>> @@ -331,7 +447,12 @@ static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
>>  {
>>      struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
>>      struct scpi_shared_mem *mem = ch->rx_payload;
>> -    u32 cmd = le32_to_cpu(mem->command);
>> +    u32 cmd;
>> +
>> +    if (scpi_info->is_legacy)
>> +        cmd = *(u32 *)msg;
> 
> Do we need do this if it doesn't contain command ?

No, will remove.

> 
>> +    else
>> +        cmd = le32_to_cpu(mem->command);
>>
>>      scpi_process_cmd(ch, cmd);
>>  }
>> @@ -343,17 +464,26 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
>>      struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
>>      struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
>>
>> -    if (t->tx_buf)
>> -        memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
>> +    if (t->tx_buf) {
>> +        if (scpi_info->is_legacy)
>> +            memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len);
>> +        else
>> +            memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
>> +    }
>> +
>>      if (t->rx_buf) {
>>          if (!(++ch->token))
>>              ++ch->token;
>>          ADD_SCPI_TOKEN(t->cmd, ch->token);
>> +        if (scpi_info->is_legacy)
>> +            t->slot = t->cmd;
> 
> I thought passing token was not an issue from your previous response,
> but you are overriding it here, why ?

Indeed, I can leave it, but it's useless since it won't serve to distinguish multiple similar commands.

> 
>>          spin_lock_irqsave(&ch->rx_lock, flags);
>>          list_add_tail(&t->node, &ch->rx_pending);
>>          spin_unlock_irqrestore(&ch->rx_lock, flags);
>>      }
>> -    mem->command = cpu_to_le32(t->cmd);
>> +
>> +    if (!scpi_info->is_legacy)
>> +        mem->command = cpu_to_le32(t->cmd);
>>  }
>>
>>  static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch)
>> @@ -396,21 +526,37 @@ static int scpi_send_message(unsigned int offset, void *tx_buf,
>>
>>      cmd = scpi_info->scpi_cmds[offset];
>>
>> -    chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans;
>> +    if (scpi_info->is_legacy)
>> +        chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0;
>> +    else
>> +        chan = atomic_inc_return(&scpi_info->next_chan) %
>> +            scpi_info->num_chans;
>>      scpi_chan = scpi_info->channels + chan;
>>
>>      msg = get_scpi_xfer(scpi_chan);
>>      if (!msg)
>>          return -ENOMEM;
>>
>> -    msg->slot = BIT(SCPI_SLOT);
>> -    msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
>> +    if (scpi_info->is_legacy) {
>> +        msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len);
>> +        msg->slot = msg->cmd;
>> +    } else {
>> +        msg->slot = BIT(SCPI_SLOT);
>> +        msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
>> +    }
>>      msg->tx_buf = tx_buf;
>>      msg->tx_len = tx_len;
>>      msg->rx_buf = rx_buf;
>>      msg->rx_len = rx_len;
>>      init_completion(&msg->done);
>>
>> +    /* Since we cannot distinguish the original command in the
>> +     * MHU reply stat value from a Legacy SCP firmware, ensure
>> +     * sequential command sending to the firmware.
>> +     */
> 
> OK this comment now questions the existence of this extra lock.
> The mailbox will always send the commands in the sequential order.
> It's only firmware that can re-order the response. Since that can't
> happen in you case, I really don't see the need for this.
> 
> Please explain the race you would see without this locking. Yes I
> understand that only one command is supposed to be sent to firmware at a
> time. Suppose you allow more callers here, all will wait on the
> completion flags and the first in the list gets unblocked right ?
> I am just trying to understand if there's real need for this extra
> lock when we already have that from the list.

In my current tests I have huge kernel hang when having multiple callers,
I must find out where this issue comes from...
In any case, we have an issue about the command sequencing.
If we push a tx-only command and then right after a tx-rx command, the
mailbox callback from the first command won't be able to distinguish which
command is handled !
In this case, the rx_pending list will not be empty, some garbage will be returned
to the second command handler and the real data from the second command handling
will be lost thinking it's a tx-only command.


We have two choices here :
 - Also push the tx-only commands to the rx_pending list, and also wait for their completion
 - Add an extra lock

What is your preferred scheme ?

>> +    if (scpi_info->is_legacy)
>> +        mutex_lock(&scpi_chan->legacy_lock);
>> +
>>      ret = mbox_send_message(scpi_chan->chan, msg);
>>      if (ret < 0 || !rx_buf)
>>          goto out;
>> @@ -421,9 +567,13 @@ static int scpi_send_message(unsigned int offset, void *tx_buf,
>>          /* first status word */
>>          ret = msg->status;
>>  out:
>> -    if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
>> +    if (ret < 0 && rx_buf)
>> +        /* remove entry from the list if timed-out */
>>          scpi_process_cmd(scpi_chan, msg->cmd);
>>
>> +    if (scpi_info->is_legacy)
>> +        mutex_unlock(&scpi_chan->legacy_lock);
>> +
>>      put_scpi_xfer(msg, scpi_chan);
>>      /* SCPI error codes > 0, translate them to Linux scale*/
>>      return ret > 0 ? scpi_to_linux_errno(ret) : ret;
> 
> [...]
> 
>> @@ -525,7 +687,6 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
>>
>>      info->count = DVFS_OPP_COUNT(buf.header);
>>      info->latency = DVFS_LATENCY(buf.header) * 1000; /* uS to nS */
>> -
> 
> Spurious ?

Indeed.

> 
>>      info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL);
>>      if (!info->opps) {
>>          kfree(info);
>> @@ -580,9 +741,13 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val)
>>
>>      ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id),
>>                  &buf, sizeof(buf));
>> -    if (!ret)
>> -        *val = (u64)le32_to_cpu(buf.hi_val) << 32 |
>> -            le32_to_cpu(buf.lo_val);
>> +    if (!ret) {
>> +        if (scpi_info->is_legacy)
>> +            *val = (u64)le32_to_cpu(buf.lo_val);
>> +        else
>> +            *val = (u64)le32_to_cpu(buf.hi_val) << 32 |
>> +                le32_to_cpu(buf.lo_val);
>> +    }
> 
> Not required as I have mentioned couple of times in previous versions,
> it's zero filled by the driver.
> 

OK

I will fix the issues, but I need your advice for the locking scheme. I really want this
to be merged and be able to go forward !

Thanks,
Neil

^ permalink raw reply

* [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Adrian Hunter @ 2016-10-17  8:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6bed26dc-f4c1-7f0d-36b6-d7d5fcbf0da9@marvell.com>

On 13/10/16 08:38, Ziji Hu wrote:
> Hi Adrian,
> 
> On 2016/10/12 21:07, Adrian Hunter wrote:
>> On 12/10/16 14:58, Ziji Hu wrote:
>>> Hi Adrian,
>>>
>>> 	Thank you very much for your review.
>>> 	I will firstly fix the typo.
>>>
>>> On 2016/10/11 20:37, Adrian Hunter wrote:
> <snip>
>>>>> +
>>>>> +static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
>>>>> +					     struct mmc_ios *ios)
>>>>> +{
>>>>> +	struct sdhci_host *host = mmc_priv(mmc);
>>>>> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>>> +	struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
>>>>> +
>>>>> +	/*
>>>>> +	 * Before SD/SDIO set signal voltage, SD bus clock should be
>>>>> +	 * disabled. However, sdhci_set_clock will also disable the Internal
>>>>> +	 * clock in mmc_set_signal_voltage().
>>>>> +	 * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated.
>>>>> +	 * Thus here manually enable internal clock.
>>>>> +	 *
>>>>> +	 * After switch completes, it is unnecessary to disable internal clock,
>>>>> +	 * since keeping internal clock active obeys SD spec.
>>>>> +	 */
>>>>> +	enable_xenon_internal_clk(host);
>>>>> +
>>>>> +	if (priv->card_candidate) {
>>>>
>>>> mmc_power_up() calls __mmc_set_signal_voltage() calls
>>>> host->ops->start_signal_voltage_switch so priv->card_candidate could be an
>>>> invalid reference to an old card.
>>>>
>>>> So that's not going to work if the card changes - not only for removable
>>>> cards but even for eMMC if init fails and retries.
>>>>
>>> 	As you point out, this piece of code have defects, even though it actually works on Marvell multiple platforms, unless eMMC card is removable.
>>>
>>> 	I can add a property to explicitly indicate eMMC type in DTS.
>>> 	Then card_candidate access can be removed here.
>>> 	Does it sounds more reasonable to you?
>>
>> Sure
>>
>>>
>>>>> +		if (mmc_card_mmc(priv->card_candidate))
>>>>> +			return xenon_emmc_signal_voltage_switch(mmc, ios);
>>>>
>>>> So if all you need to know is whether it is a eMMC, why can't DT tell you?
>>>>
>>> 	I can add an eMMC type property in DTS, to remove the card_candidate access here.
>>>
>>>>> +	}
>>>>> +
>>>>> +	return sdhci_start_signal_voltage_switch(mmc, ios);
>>>>> +}
>>>>> +
>>>>> +/*
>>>>> + * After determining which slot is used for SDIO,
>>>>> + * some additional task is required.
>>>>> + */
>>>>> +static void xenon_init_card(struct mmc_host *mmc, struct mmc_card *card)
>>>>> +{
>>>>> +	struct sdhci_host *host = mmc_priv(mmc);
>>>>> +	u32 reg;
>>>>> +	u8 slot_idx;
>>>>> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>>> +	struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
>>>>> +
>>>>> +	/* Link the card for delay adjustment */
>>>>> +	priv->card_candidate = card;
>>>>
>>>> You really need a better way to get the card.  I suggest you take up the
>>>> issue with Ulf.  One possibility is to have mmc core set host->card = card
>>>> much earlier.
>>>>
>>> 	Could you please tell me if any issue related to card_candidate still exists, after the card_candidate is removed from xenon_start_signal_voltage_switch() in above?
>>> 	It seems that when init_card is called, the structure card has already been updated and stable in MMC/SD/SDIO initialization sequence.
>>> 	May I keep it here?
>>
>> It works by accident rather than by design.  We can do better.
>>
> 	Could you please tell me some details which are satisfied about card_candidate?
> 
> 	I must admit that card_candidate in xenon_start_signal_voltage_switch() is imperfect.
> 	But card_candidate in init_card() and later in set_ios() work by design, rather than by accident. We did a lot of tests on several platforms.
> 	
> 	The structure mmc_card passed in here is a stable one. Thus in my very own opinion, it is safe and stable to use mmc_card here.
> 	card_candidate is used only in card initialization. It is not active in later transfers after initialization is done.
> 	It will always updated with mmc_card in next card initialization.

Ok, so maybe just add some comments and more explanation of how it works.


> 
>>>
>>>>> +	/* Set tuning functionality of this slot */
>>>>> +	xenon_slot_tuning_setup(host);
>>>>> +
>>>>> +	slot_idx = priv->slot_idx;
>>>>> +	if (!mmc_card_sdio(card)) {
>>>>> +		/* Re-enable the Auto-CMD12 cap flag. */
>>>>> +		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
>>>>> +		host->flags |= SDHCI_AUTO_CMD12;
>>>>> +
>>>>> +		/* Clear SDIO Card Inserted indication */
>>>>> +		reg = sdhci_readl(host, SDHC_SYS_CFG_INFO);
>>>>> +		reg &= ~(1 << (slot_idx + SLOT_TYPE_SDIO_SHIFT));
>>>>> +		sdhci_writel(host, reg, SDHC_SYS_CFG_INFO);
>>>>> +
>>>>> +		if (mmc_card_mmc(card)) {
>>>>> +			mmc->caps |= MMC_CAP_NONREMOVABLE;
>>>>> +			if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V))
>>>>> +				mmc->caps |= MMC_CAP_1_8V_DDR;
>>>>> +			/*
>>>>> +			 * Force to clear BUS_TEST to
>>>>> +			 * skip bus_test_pre and bus_test_post
>>>>> +			 */
>>>>> +			mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST;
>>>>> +			mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ |
>>>>> +				      MMC_CAP2_PACKED_CMD;
>>>>> +			if (mmc->caps & MMC_CAP_8_BIT_DATA)
>>>>> +				mmc->caps2 |= MMC_CAP2_HS400_1_8V;
>>>>> +		}
>>>>> +	} else {
>>>>> +		/*
>>>>> +		 * Delete the Auto-CMD12 cap flag.
>>>>> +		 * Otherwise, when sending multi-block CMD53,
>>>>> +		 * Driver will set Transfer Mode Register to enable Auto CMD12.
>>>>> +		 * However, SDIO device cannot recognize CMD12.
>>>>> +		 * Thus SDHC will time-out for waiting for CMD12 response.
>>>>> +		 */
>>>>> +		host->quirks &= ~SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
>>>>> +		host->flags &= ~SDHCI_AUTO_CMD12;
>>>>
>>>> sdhci_set_transfer_mode() won't enable auto-CMD12 for CMD53 anyway, so is
>>>> this needed?
>>>>
>>> 	In Xenon driver, Auto-CMD12 flag is set to enable full support to Auto-CMD feature, both Auto-CMD12 and Auto-CMD23.
>>> 	As a result, when Xenon SDHC slot can both support SD and SDIO, Auto-CMD12 is disabled when SDIO card is inserted, and renabled when SD is inserted.
>>>
>>> 	I recheck the sdhci code to set Auto-CMD bit in Transfer Mode register, in sdhci_set_transfer_mode():
>>> 	if (mmc_op_multi(cmd->opcode) || data->blocks > 1)
>>> 	As you can see, as long as it is CMD18/CMD25 OR there are multiple data blocks, Auto-CMD field will be set.
>>> 	CMD53 doesn't have CMD23. Thus Auto-CMD12 is selected since Auto-CMD12 flag is set.
>>> 	Thus I have to clear Auto-CMD12 to avoid issuing Auto-CMD12 in SDIO transfer.
>>
>>
>> The code is:
>>
>> 	if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
>> 		mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
>> 		/*
>> 		 * If we are sending CMD23, CMD12 never gets sent
>> 		 * on successful completion (so no Auto-CMD12).
>> 		 */
>> 		if (sdhci_auto_cmd12(host, cmd->mrq) &&
>> 		    (cmd->opcode != SD_IO_RW_EXTENDED))
>> 			mode |= SDHCI_TRNS_AUTO_CMD12;
>> 		else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
>> 			mode |= SDHCI_TRNS_AUTO_CMD23;
>> 			sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
>> 		}
>> 	}
>>
>> You can see the check for SD_IO_RW_EXTENDED which is CMD53.
>>
> 	Sorry. I didn't notice CMD53 check was added.
> 	I introduced this Auto-CMD12 hack since kernel 3.8. It seems that this check is not added in kernel 3.8.
> 	Thanks for the information. I will remove the Auto-CMD12 hack.
> 
>>>
>>> 	I just meet a similar issue in RPMB.
>>> 	When Auto-CMD12 flag is set, eMMC RPMB access will trigger Auto-CMD12, since CMD25 is in use.
>>> 	It will cause RPMB access failed.
>>
>> Can you explain more about the RPMB issue.  Doesn't it use CMD23, so CMD12
>> wouldn't be used - auto or manually.
>>
> 	RPMB go through the MMC ioctl routine.
> 	Unlike normal data transfer, MMC ioctl for RPMB explicitly issues CMD23. When CMD25 is issued, there is neither data->sbc nor Auto-CMD23.
> 	As a result, sdhci driver will automatically enable Auto-CMD12 for RPMB CMD25 if Auto-CMD12 flag is set.

OK, so SDHCI should also not allow auto-cmd12 if there is no stop command
i.e. data->stop is null.

> 
>>>
>>> 	One possible solution is to drop Auto-CMD12 support and use Auto-CMD23 only, in Xenon driver.
>>> 	May I know you opinion, please?
>>
>> I don't use auto-CMD12 because I don't know if it provides any benefit and
>> sdhci does not seem to have implemented Auto CMD12 Error Recovery, although
>> I have never looked at it closely.
>>
> 	Actually, Auto-CMD23 is always used on our Xenon. Auto-CMD12 is not used at all.
> 	But since this driver is a general one for all Marvell products, Auto-CMD12 is also supported in case that Auto-CMD23 is not available.
>  
> 

^ permalink raw reply

* PROBLEM: DWC3 USB 3.0 not working on Odroid-XU4 with Exynos 5422
From: Felipe Balbi @ 2016-10-17  8:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476627597.1752.3.camel@mniewoehner.de>


Hi,

Michael Niew?hner <linux@mniewoehner.de> writes:
> Hi Felipe,
> On Fri, 2016-10-07 at 22:26 +0200, Michael Niew?hner wrote:
>> Hi Felipe,
>> 
>> On Fr, 2016-10-07 at 10:42 +0300, Felipe Balbi wrote:
>> > Hi,
>> > 
>> > Michael Niew?hner <linux@mniewoehner.de> writes:
>> > > 
>> > > > 
>> > > > The clocks are same across working/non-working.
>> > > > Is it possible to bisect the commit that's causing hang for 4.8x ?
>> > > 
>> > > 
>> > > [c499ff71ff2a281366c6ec7a904c547d806cbcd1] usb: dwc3: core: re-factor init and exit paths
>> > > This patch causes both the hang on reboot and the lsusb hang.
>> > 
>> > How to reproduce? Why don't we see this on x86 and TI boards? I'm
>> > guessing this is failed bisection, as I can't see anything in that
>> > commit that would cause reboot hang. Also, that code path is *NOT*
>> > executed when you run lsusb.
>> > 
>> 
>> I've tested this procedure multiple times to be sure:
>> 
>> - checkout?c499ff71, compile, boot the odroid
>> - run lsusb -v => lsusb hangs, can't terminate with ctrl-c
>> - hard reset, after boot run poweroff or reboot => board does not completely power off / reboot (see log below)
>> - revert c499ff71, mrproper, compile, boot the odroid
>> - run lsusb -v => shows full output, not hanging
>> - run reboot or poweroff => board powers off / reboots just fine
>> 
>> 
>> dmesg poweroff not working:
>> ...
>> [??120.733519] systemd-journald[144]: systemd-journald stopped as pid 144???????
>> [??120.742663] systemd-shutdown[1]: Sending SIGKILL to remaining processes...???
>> [??120.769212] systemd-shutdown[1]: Unmounting file systems.????????????????????
>> [??120.773713] systemd-shutdown[1]: Unmounting /sys/kernel/debug.???????????????
>> [??120.827211] systemd-shutdown[1]: Unmounting /dev/mqueue.?????????????????????
>> [??121.081672] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.091687] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.095608] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.101014] systemd-shutdown[1]: All filesystems unmounted.??????????????????
>> [??121.106523] systemd-shutdown[1]: Deactivating swaps.?????????????????????????
>> [??121.111585] systemd-shutdown[1]: All swaps deactivated.??????????????????????
>> [??121.116661] systemd-shutdown[1]: Detaching loop devices.?????????????????????
>> [??121.126395] systemd-shutdown[1]: All loop devices detached.??????????????????
>> [??121.130525] systemd-shutdown[1]: Detaching DM devices.???????????????????????
>> [??121.135824] systemd-shutdown[1]: All DM devices detached.????????????????????
>> [??121.166327] systemd-shutdown[1]: /lib/systemd/system-shutdown succeeded.?????
>> [??121.171739] systemd-shutdown[1]: Powering off.
>> 
>> => at this point removing the sd card would show a message?
>> "removed mmc0" (not sure what the real message was...) so the board is not completely off.
>> 
>> 
>> dmesg poweroff working:
>> ...
>> [??120.733519] systemd-journald[144]: systemd-journald stopped as pid 144???????
>> [??120.742663] systemd-shutdown[1]: Sending SIGKILL to remaining processes...???
>> [??120.769212] systemd-shutdown[1]: Unmounting file systems.????????????????????
>> [??120.773713] systemd-shutdown[1]: Unmounting /sys/kernel/debug.???????????????
>> [??120.827211] systemd-shutdown[1]: Unmounting /dev/mqueue.?????????????????????
>> [??121.081672] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.091687] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.095608] EXT4-fs (mmcblk1p2): re-mounted. Opts: (null)????????????????????
>> [??121.101014] systemd-shutdown[1]: All filesystems unmounted.??????????????????
>> [??121.106523] systemd-shutdown[1]: Deactivating swaps.?????????????????????????
>> [??121.111585] systemd-shutdown[1]: All swaps deactivated.??????????????????????
>> [??121.116661] systemd-shutdown[1]: Detaching loop devices.?????????????????????
>> [??121.126395] systemd-shutdown[1]: All loop devices detached.??????????????????
>> [??121.130525] systemd-shutdown[1]: Detaching DM devices.???????????????????????
>> [??121.135824] systemd-shutdown[1]: All DM devices detached.????????????????????
>> [??121.166327] systemd-shutdown[1]: /lib/systemd/system-shutdown succeeded.?????
>> [??121.171739] systemd-shutdown[1]: Powering off.
>> [??121.182331] rebo?
>> 
>> 
>> 
>> Best regards
>> Michael Niew?hner
>
>
> I did some more tests with next-20161016. Reverting / commenting out
> one part of your patch "solves" the lsusb hang, the reboot problem
> and also the "debounce failed" message. [1]
> Another "solution" is to call phy_power_off before phy_power_on. [2]
>
> Disclaimer: I have no idea what I was doing ;-) These were just some
> simple trial-and-error attempts that maybe help to find the real
> cause of the problems.
>
> [1]
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 7287a76..5ef589d 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -724,6 +724,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
> ?	/* Adjust Frame Length */
> ?	dwc3_frame_length_adjustment(dwc);
> ?
> +/*
> ?	usb_phy_set_suspend(dwc->usb2_phy, 0);
> ?	usb_phy_set_suspend(dwc->usb3_phy, 0);
> ?	ret = phy_power_on(dwc->usb2_generic_phy);
> @@ -733,6 +734,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
> ?	ret = phy_power_on(dwc->usb3_generic_phy);
> ?	if (ret < 0)
> ?		goto err3;
> +*/
> ?
> ?	ret = dwc3_event_buffers_setup(dwc);
> ?	if (ret) {
>
> [2]
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 7287a76..f6c8e13 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -726,6 +726,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
> ?
> ????????usb_phy_set_suspend(dwc->usb2_phy, 0);
> ????????usb_phy_set_suspend(dwc->usb3_phy, 0);
> +???????phy_power_off(dwc->usb2_generic_phy);
> +???????phy_power_off(dwc->usb3_generic_phy);

This looks like a PHY driver bug to me. Which PHY driver are you using?

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161017/a826b912/attachment-0001.sig>

^ permalink raw reply

* aarch64 ACPI boot regressed by commit 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must bind to node0")
From: Leizhen (ThunderTown) @ 2016-10-17  8:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c8b9f6fc-3a4b-f74a-c930-f500bcc00a1d@redhat.com>



>> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
>> index d3f151cfd4a1..8507703dabe4 100644
>> --- a/arch/arm64/kernel/smp.c
>> +++ b/arch/arm64/kernel/smp.c
>> @@ -544,6 +544,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
>>  			return;
>>  		}
>>  		bootcpu_valid = true;
>> +		early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid));
>>  		return;
>>  	}
>>
> 
> Anyway, your patch works with both the two-node NUMA configuration Drew suggested for testing, and with the single-node config that I originally used for the bisection. Therefore:
> 
> Tested-by: Laszlo Ersek <lersek@redhat.com>
> Reported-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thank you very much for the quick bugfix! And, I think your patch (when you send it for real) should carry
I'm so sorry about this. My patch series prepared before ACPI NUMA upstreamed, and forgot considering it in later.

> 
> Fixes: 7ba5f605f3a0d9495aad539eeb8346d726dfc183
> 
> too, because it supplies the cpu#0<->node#xxx association that 7ba5f605f3a0 removed not just for DT, but also for ACPI.
> 
> Cheers!
> Laszlo
> 
> .
> 

^ permalink raw reply

* [PATCH 7/10] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC
From: Adrian Hunter @ 2016-10-17  7:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <bcf4abca-9f2e-6d1b-6690-d672766e18cb@marvell.com>

On 12/10/16 15:17, Ziji Hu wrote:
> Hi Adrian,
> 
> On 2016/10/11 20:39, Adrian Hunter wrote:
>> On 07/10/16 18:22, Gregory CLEMENT wrote:
>>> From: Ziji Hu <huziji@marvell.com>
>>>
>>> Marvell Xenon eMMC/SD/SDIO Host Controller contains PHY.
>>> Three types of PHYs are supported.
>>>
>>> Add support to multiple types of PHYs init and configuration.
>>> Add register definitions of PHYs.
>>>
>>> Signed-off-by: Hu Ziji <huziji@marvell.com>
>>> Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>>> ---
>>>  MAINTAINERS                        |    1 +-
>>>  drivers/mmc/host/Makefile          |    2 +-
>>>  drivers/mmc/host/sdhci-xenon-phy.c | 1141 +++++++++++++++++++++++++++++-
>>>  drivers/mmc/host/sdhci-xenon-phy.h |  157 ++++-
>>>  drivers/mmc/host/sdhci-xenon.c     |    4 +-
>>>  drivers/mmc/host/sdhci-xenon.h     |   17 +-
>>>  6 files changed, 1321 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/mmc/host/sdhci-xenon-phy.c
>>>  create mode 100644 drivers/mmc/host/sdhci-xenon-phy.h
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 859420e5dfd3..b5673c2ee5f2 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -7583,6 +7583,7 @@ M:	Ziji Hu <huziji@marvell.com>
>>>  L:	linux-mmc at vger.kernel.org
>>>  S:	Supported
>>>  F:	drivers/mmc/host/sdhci-xenon.*
>>> +F:	drivers/mmc/host/sdhci-xenon-phy.*
>>>  F:	Documentation/devicetree/bindings/mmc/marvell,sdhci-xenon.txt
>>>  
>>>  MATROX FRAMEBUFFER DRIVER
>>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>>> index 75eaf743486c..4f2854556ff7 100644
>>> --- a/drivers/mmc/host/Makefile
>>> +++ b/drivers/mmc/host/Makefile
>>> @@ -82,4 +82,4 @@ ifeq ($(CONFIG_CB710_DEBUG),y)
>>>  endif
>>>  
>>>  obj-$(CONFIG_MMC_SDHCI_XENON)	+= sdhci-xenon-driver.o
>>> -sdhci-xenon-driver-y		+= sdhci-xenon.o
>>> +sdhci-xenon-driver-y		+= sdhci-xenon.o sdhci-xenon-phy.o
>>> diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
>>> new file mode 100644
>>> index 000000000000..4eb8fea1bec9
>>> --- /dev/null
>>> +++ b/drivers/mmc/host/sdhci-xenon-phy.c
>>
>> <SNIP>
>>
>>> +static int __xenon_emmc_delay_adj_test(struct mmc_card *card)
>>> +{
>>> +	int err;
>>> +	u8 *ext_csd = NULL;
>>> +
>>> +	err = mmc_get_ext_csd(card, &ext_csd);
>>> +	kfree(ext_csd);
>>> +
>>> +	return err;
>>> +}
>>> +
>>> +static int __xenon_sdio_delay_adj_test(struct mmc_card *card)
>>> +{
>>> +	struct mmc_command cmd = {0};
>>> +	int err;
>>> +
>>> +	cmd.opcode = SD_IO_RW_DIRECT;
>>> +	cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
>>> +
>>> +	err = mmc_wait_for_cmd(card->host, &cmd, 0);
>>> +	if (err)
>>> +		return err;
>>> +
>>> +	if (cmd.resp[0] & R5_ERROR)
>>> +		return -EIO;
>>> +	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
>>> +		return -EINVAL;
>>> +	if (cmd.resp[0] & R5_OUT_OF_RANGE)
>>> +		return -ERANGE;
>>> +	return 0;
>>> +}
>>> +
>>> +static int __xenon_sd_delay_adj_test(struct mmc_card *card)
>>> +{
>>> +	struct mmc_command cmd = {0};
>>> +	int err;
>>> +
>>> +	cmd.opcode = MMC_SEND_STATUS;
>>> +	cmd.arg = card->rca << 16;
>>> +	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
>>> +
>>> +	err = mmc_wait_for_cmd(card->host, &cmd, 0);
>>> +	return err;
>>> +}
>>> +
>>> +static int xenon_delay_adj_test(struct mmc_card *card)
>>> +{
>>> +	WARN_ON(!card);
>>> +	WARN_ON(!card->host);
>>> +
>>> +	if (mmc_card_mmc(card))
>>> +		return __xenon_emmc_delay_adj_test(card);
>>> +	else if (mmc_card_sd(card))
>>> +		return __xenon_sd_delay_adj_test(card);
>>> +	else if (mmc_card_sdio(card))
>>> +		return __xenon_sdio_delay_adj_test(card);
>>> +	else
>>> +		return -EINVAL;
>>> +}
>>
>> So you are issuing commands from the ->set_ios() callback.  I would want to
>> get Ulf's OK for that before going further.
>>
> 	Yes, you are correct.
> 	In some speed mode, Xenon SDHC has to send a series of transfers to search for a perfect sampling point in PHY delay line.
> 	It is like tuning process.
> 
>> One thing: you will need to ensure you don't trigger get HS400 re-tuning
>> because it will call back into ->set_ios().
>>
> 	Could you please make the term "HS400 re-tuning" more detailed?
> 	In current MMC driver, "HS400 re-tuning" will go back to HS200, execute HS200 tuning and come back to HS400.
> 	I'm sure our Xenon SDHC will not execute it.

Currently, re-tuning is automatically enabled whenever tuning is executed,
and then re-tuning will be done periodically or after CRC errors.  The
function to disable re-tuning mmc_retune_disable() is not exported, however
if you have you are determining the sampling point your own way, you could
simply not implement ->execute_tuning() and then there would be no tuning
and no re-tuning.

> 
> 	However, in coming eMMC 5.2, there is a real HS400 re-tuning, in which tuning can be directly executed in HS400 mode.
> 	Our Xenon SDHC will neither trigger this HS400 re-tuning.
> 	But since so far there is no such feature in MMC driver, I cannot give you a 100% guarantee now.
> 
>> And you have the problem that you need to get a reference to the card before
>> the card device has been added.  As I wrote in response to the previous
>> patch, you should get Ulf's help with that too.
>>
> 	Sure.
> 	I will get card_candidate solved at first.
> 	Thank you again for your review and help.
> 
> 	Thank you.
> 
> Best regards,
> Hu Ziji
>>
> 

^ permalink raw reply

* [PATCH 2/2] ARM: dts: da850: add a node for the LCD controller
From: Tomi Valkeinen @ 2016-10-17  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <65fde145-0820-794d-d345-621f66cdacc0@ti.com>

On 17/10/16 10:12, Sekhar Nori wrote:
> On Monday 17 October 2016 11:26 AM, Tomi Valkeinen wrote:
>> On 15/10/16 20:42, Sekhar Nori wrote:
>>
>>>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>>>> index f79e1b9..32908ae 100644
>>>> --- a/arch/arm/boot/dts/da850.dtsi
>>>> +++ b/arch/arm/boot/dts/da850.dtsi
>>>
>>>> @@ -399,6 +420,14 @@
>>>>  				<&edma0 0 1>;
>>>>  			dma-names = "tx", "rx";
>>>>  		};
>>>> +
>>>> +		display: display at 213000 {
>>>> +			compatible = "ti,am33xx-tilcdc", "ti,da850-tilcdc";
>>>
>>> This should instead be:
>>>
>>> compatible = "ti,da850-tilcdc", "ti,am33xx-tilcdc";
>>>
>>> as the closest match should appear first in the list.
>>
>> Actually I don't think that's correct. The LCDC on da850 is not
>> compatible with the LCDC on AM335x. I think it should be just
>> "ti,da850-tilcdc".
> 
> So if "ti,am33xx-tilcdc" is used, the display wont work at all? If thats
> the case, I wonder how the patch passed testing. Bartosz?

AM3 has "version 2" of LCDC, whereas DA850 is v1. They are quite
similar, but different.

The driver gets the version number from LCDC's register, and acts based
on that, so afaik the compatible string doesn't really affect the
functionality (as long as it matches).

But even if it works with the current driver, I don't think
"ti,am33xx-tilcdc" and "ti,da850-tilcdc" are compatible in the HW level.

 Tomi

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161017/b6ff5ea1/attachment.sig>

^ permalink raw reply

* [PATCH v3 0/8] PM / Domains: DT support for domain idle states & atomic PM domains
From: Ulf Hansson @ 2016-10-17  7:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476467276-75094-1-git-send-email-lina.iyer@linaro.org>

On 14 October 2016 at 19:47, Lina Iyer <lina.iyer@linaro.org> wrote:
> Hi all,
>
> Changes since v2 [3] -
> - Addressed review comments from v2.
>         - domain-idle-states documentation updated
>         - fixed compiler issues with imx driver
>         - minor code change in pm_domains.c
> - The series is available at [4].
>
> Changes since v1 [2] -
> - Addressed review comments from v1.
>         - Fixes around dynamic allocation of genpd states
>         - Used OF method for iterating phandles
>         - Updated documentation, examples
>         - Rename state variable (provider -> fwnode)
> - The series is available at [3].
>
> The changes from [1] are -
> - Allocating memory for domain idle states dynamically
> - Conform to naming conventions for internal and exported genpd functions
> - DT binding example for domain-idle-state
> - Use fwnode instead of of_node
> - Handle atomic case for removal of PM Domain
> - Rebase on top of Rafael's pm/genpd tree
>
> Thanks,
> Lina
>
> Lina Iyer (8):
>   PM / Domains: Make genpd state allocation dynamic
>   PM / Domain: Add residency property to genpd states
>   PM / Domains: Allow domain power states to be read from DT
>   PM / Domains: Save the fwnode in genpd_power_state
>   dt/bindings: Update binding for PM domain idle states
>   PM / Domains: Abstract genpd locking
>   PM / Domains: Support IRQ safe PM domains
>   PM / doc: Update device documentation for devices in IRQ safe PM
>     domains
>
>  .../devicetree/bindings/power/power_domain.txt     |  43 +++
>  Documentation/power/devices.txt                    |   9 +-
>  arch/arm/mach-imx/gpc.c                            |  17 +-
>  drivers/base/power/domain.c                        | 358 +++++++++++++++++----
>  include/linux/pm_domain.h                          |  28 +-
>  5 files changed, 383 insertions(+), 72 deletions(-)
>

Rafael, Lina,

This looks good to me! Unless any other objections, I suggest to apply
this to get it tested in linux-next.

Kind regards
Uffe

> --
> 2.7.4
>
> [1]. https://www.spinics.net/lists/arm-kernel/msg526814.html
> [2]. http://www.spinics.net/lists/arm-kernel/msg535106.html
> [3]. https://git.linaro.org/people/lina.iyer/linux-next.git/shortlog/refs/heads/genpd-v2
> [4]. https://git.linaro.org/people/lina.iyer/linux-next.git/shortlog/refs/heads/genpd-v3

^ permalink raw reply

* [PATCH 2/2] ARM: dts: da850: add a node for the LCD controller
From: Bartosz Golaszewski @ 2016-10-17  7:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <65fde145-0820-794d-d345-621f66cdacc0@ti.com>

2016-10-17 9:12 GMT+02:00 Sekhar Nori <nsekhar@ti.com>:
> On Monday 17 October 2016 11:26 AM, Tomi Valkeinen wrote:
>> On 15/10/16 20:42, Sekhar Nori wrote:
>>
>>>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>>>> index f79e1b9..32908ae 100644
>>>> --- a/arch/arm/boot/dts/da850.dtsi
>>>> +++ b/arch/arm/boot/dts/da850.dtsi
>>>
>>>> @@ -399,6 +420,14 @@
>>>>                             <&edma0 0 1>;
>>>>                     dma-names = "tx", "rx";
>>>>             };
>>>> +
>>>> +           display: display at 213000 {
>>>> +                   compatible = "ti,am33xx-tilcdc", "ti,da850-tilcdc";
>>>
>>> This should instead be:
>>>
>>> compatible = "ti,da850-tilcdc", "ti,am33xx-tilcdc";
>>>
>>> as the closest match should appear first in the list.
>>
>> Actually I don't think that's correct. The LCDC on da850 is not
>> compatible with the LCDC on AM335x. I think it should be just
>> "ti,da850-tilcdc".
>
> So if "ti,am33xx-tilcdc" is used, the display wont work at all? If thats
> the case, I wonder how the patch passed testing. Bartosz?
>

DA850 uses revision 1 of the IP while am33xx is equipped with rev 2.
The driver reads the appropriate register, detects the revision and
sets the corresponding field in struct tilcdc_drm_private in
tilcdc_load().

Thanks,
Bartosz

^ permalink raw reply

* [PATCH 2/2] ARM: dts: da850: add a node for the LCD controller
From: Sekhar Nori @ 2016-10-17  7:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1e23c3e9-d34b-1d8f-8565-c9932a60fd32@ti.com>

On Monday 17 October 2016 11:26 AM, Tomi Valkeinen wrote:
> On 15/10/16 20:42, Sekhar Nori wrote:
> 
>>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>>> index f79e1b9..32908ae 100644
>>> --- a/arch/arm/boot/dts/da850.dtsi
>>> +++ b/arch/arm/boot/dts/da850.dtsi
>>
>>> @@ -399,6 +420,14 @@
>>>  				<&edma0 0 1>;
>>>  			dma-names = "tx", "rx";
>>>  		};
>>> +
>>> +		display: display at 213000 {
>>> +			compatible = "ti,am33xx-tilcdc", "ti,da850-tilcdc";
>>
>> This should instead be:
>>
>> compatible = "ti,da850-tilcdc", "ti,am33xx-tilcdc";
>>
>> as the closest match should appear first in the list.
> 
> Actually I don't think that's correct. The LCDC on da850 is not
> compatible with the LCDC on AM335x. I think it should be just
> "ti,da850-tilcdc".

So if "ti,am33xx-tilcdc" is used, the display wont work at all? If thats
the case, I wonder how the patch passed testing. Bartosz?

Thanks,
Sekhar

^ permalink raw reply

* [PATCH V3 0/8] IOMMU probe deferral support
From: Sricharan @ 2016-10-17  7:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <12cfb59f-f7ca-d4df-eb7f-42348e357979@samsung.com>

Resending, missed out on the link last time.

>-----Original Message-----
From: linux-arm-msm-owner@vger.kernel.org [mailto:linux-arm-msm-owner at vger.kernel.org] On Behalf Of Marek Szyprowski
>Sent: Monday, October 10, 2016 6:07 PM
>To: Sricharan R <sricharan@codeaurora.org>; will.deacon at arm.com; robin.murphy at arm.com; joro at 8bytes.org; iommu at lists.linux-
>foundation.org; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; laurent.pinchart at ideasonboard.com;
>tfiga at chromium.org; srinivas.kandagatla at linaro.org
>Subject: Re: [PATCH V3 0/8] IOMMU probe deferral support
>
>Hi Sricharan,
>
>
>On 2016-10-04 19:03, Sricharan R wrote:
>> Initial post from Laurent Pinchart[1]. This is
>> series calls the dma ops configuration for the devices
>> at a generic place so that it works for all busses.
>> The dma_configure_ops for a device is now called during
>> the device_attach callback just before the probe of the
>> bus/driver is called. Similarly dma_deconfigure is called during
>> device/driver_detach path.
>>
>>
>> pci_bus_add_devices    (platform/amba)(_device_create/driver_register)
>>         |                         |
>> pci_bus_add_device     (device_add/driver_register)
>>         |                         |
>> device_attach           device_initial_probe
>>         |                         |
>> __device_attach_driver    __device_attach_driver
>>         |
>> driver_probe_device
>>         |
>> really_probe
>>         |
>> dma_configure
>>
>>   Similarly on the device/driver_unregister path __device_release_driver
>> is
>>   called which inturn calls dma_deconfigure.
>>
>>   If the ACPI bus code follows the same, we can add acpi_dma_configure
>>   at the same place as of_dma_configure.
>>
>>   This series is based on the recently merged Generic DT bindings for
>>   PCI IOMMUs and ARM SMMU from Robin Murphy robin.murphy at arm.com [2]
>>
>>   This time tested this with platform and pci device for probe deferral
>>   and reprobe on arm64 based platform. There is an issue on the cleanup
>>   path for arm64 though, where there is WARN_ON if the dma_ops is reset
>> while
>>   device is attached to an domain in arch_teardown_dma_ops.
>>   But with iommu_groups created from the iommu driver, the device is
>> always
>>   attached to a domain/default_domain. So so the WARN has to be
>> removed/handled
>>   probably.
>
>Thanks for continuing work on this feature! Your can add my:
>
>Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>

Hi Will,Robin,Joerg,
       
       I have tested the probe deferral for platform/pcie bus devices based on latest Generic DT bindings
        series merged [1], for pci/arm-smmu.
       It will be good to know from you on whats the right way to take this forward ?

[1] http://www.spinics.net/lists/devicetree/msg142943.html

Regards,
 Sricharan

^ 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