All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/4]Enable rpmsg support on imx amp platforms
@ 2016-01-06  8:06 Richard Zhu
  2016-01-06  8:06 ` [RFC 1/4] ARM: imx: enable " Richard Zhu
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-06  8:06 UTC (permalink / raw)
  To: ohad, shawnguo; +Cc: linux-kernel

Implement the rpmsg on imx amp platforms, such as imx6sx and imx7d.
Create one imx pingpong sample that demonstrate the data
transactions on imx amp platforms over the rpmsg bus.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC 1/4] ARM: imx: enable rpmsg support on imx amp platforms
  2016-01-06  8:06 [RFC 0/4]Enable rpmsg support on imx amp platforms Richard Zhu
@ 2016-01-06  8:06 ` Richard Zhu
  2016-01-06  8:06 ` [RFC 2/4] clk: imx7d: enable the mu and m4 root clocks Richard Zhu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-06  8:06 UTC (permalink / raw)
  To: ohad, shawnguo; +Cc: linux-kernel

From: Richard Zhu <Richard.Zhu@freescale.com>

enable the rpmsg support on imx amp platforms.
such as imx6sx, and imx7d.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 arch/arm/boot/dts/Makefile          |  6 ++--
 arch/arm/boot/dts/imx6sx-sdb-m4.dts | 56 +++++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx6sx.dtsi       | 12 ++++++++
 arch/arm/boot/dts/imx7d-sdb-m4.dts  | 44 +++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx7d.dtsi        | 14 ++++++++++
 5 files changed, 130 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/boot/dts/imx6sx-sdb-m4.dts
 create mode 100644 arch/arm/boot/dts/imx7d-sdb-m4.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 30bbc37..5d40c1d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -346,11 +346,13 @@ dtb-$(CONFIG_SOC_IMX6SL) += \
 dtb-$(CONFIG_SOC_IMX6SX) += \
 	imx6sx-sabreauto.dtb \
 	imx6sx-sdb-reva.dtb \
-	imx6sx-sdb.dtb
+	imx6sx-sdb.dtb \
+	imx6sx-sdb-m4.dtb
 dtb-$(CONFIG_SOC_IMX6UL) += \
 	imx6ul-14x14-evk.dtb
 dtb-$(CONFIG_SOC_IMX7D) += \
-	imx7d-sdb.dtb
+	imx7d-sdb.dtb \
+	imx7d-sdb-m4.dtb
 dtb-$(CONFIG_SOC_LS1021A) += \
 	ls1021a-qds.dtb \
 	ls1021a-twr.dtb
diff --git a/arch/arm/boot/dts/imx6sx-sdb-m4.dts b/arch/arm/boot/dts/imx6sx-sdb-m4.dts
new file mode 100644
index 0000000..3a45301
--- /dev/null
+++ b/arch/arm/boot/dts/imx6sx-sdb-m4.dts
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, 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.
+ */
+
+#include "imx6sx-sdb.dts"
+
+/*
+ * The following modules are manupulated by M4, should be disabled
+ * at A7/Linux side
+ * ADC1/2, FLEXCAN1/2, I2C3, QSPI2, UART2, WDOG3
+ *
+ */
+
+&adc1 {
+	status = "disabled";
+};
+
+&adc2 {
+	status = "disabled";
+};
+
+&flexcan1 {
+	status = "disabled";
+};
+
+&flexcan2 {
+	status = "disabled";
+};
+
+&i2c3 {
+	status = "disabled";
+};
+
+&mu {
+	status = "okay";
+};
+
+&ocram {
+	reg = <0x00901000 0xf000>;
+};
+
+&qspi2 {
+	status = "disabled";
+};
+
+&rpmsg{
+	status = "okay";
+};
+
+&uart2 {
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 167f77b..47a7f03 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -1184,6 +1184,18 @@
 				status = "disabled";
 			};
 
+			mu: mu@02294000 { /* mu */
+				compatible = "fsl,imx6sx-mu";
+				reg = <0x02294000 0x4000>;
+				interrupts = <0 90 0x04>;
+				status = "disabled";
+			};
+
+			rpmsg: rpmsg{
+				compatible = "fsl,imx6sx-rpmsg";
+				status = "disabled";
+			};
+
 			uart6: serial@022a0000 {
 				compatible = "fsl,imx6sx-uart", "fsl,imx21-uart";
 				reg = <0x022a0000 0x4000>;
diff --git a/arch/arm/boot/dts/imx7d-sdb-m4.dts b/arch/arm/boot/dts/imx7d-sdb-m4.dts
new file mode 100644
index 0000000..c941c3e
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-sdb-m4.dts
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, 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.
+ */
+
+#include "imx7d-sdb.dts"
+
+/*
+ * The following modules are manupulated by M4, should be disabled
+ * at A7/Linux side
+ * ADC1/2, FLEXCAN, I2C2, GPT3/4, UART2, WDOG3
+ *
+ */
+
+&i2c2 {
+	status = "disabled";
+};
+
+&gpt3 {
+	status = "disabled";
+};
+
+&gpt4 {
+	status = "disabled";
+};
+
+&mu{
+	status = "okay";
+};
+
+&rpmsg{
+	status = "okay";
+};
+
+&uart2 {
+	status = "disabled";
+};
+
+&wdog3{
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index ebc053a..b60b125 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -752,6 +752,20 @@
 				status = "disabled";
 			};
 
+			mu: mu@30aa0000 {
+				compatible = "fsl,imx7d-mu", "fsl,imx6sx-mu";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				clock-names = "mu";
+				status = "disabled";
+			};
+
+			rpmsg: rpmsg{
+				compatible = "fsl,imx7d-rpmsg";
+				status = "disabled";
+			};
+
 			usbotg1: usb@30b10000 {
 				compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
 				reg = <0x30b10000 0x200>;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC 2/4] clk: imx7d: enable the mu and m4 root clocks
  2016-01-06  8:06 [RFC 0/4]Enable rpmsg support on imx amp platforms Richard Zhu
  2016-01-06  8:06 ` [RFC 1/4] ARM: imx: enable " Richard Zhu
@ 2016-01-06  8:06 ` Richard Zhu
  2016-01-06  8:06 ` [RFC 3/4] ARM: imx: add the platform related rpmsg implementation Richard Zhu
  2016-01-06  8:06 ` [RFC 4/4] samples/rpmsg: add the imx pingpong rpmsg sample Richard Zhu
  3 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-06  8:06 UTC (permalink / raw)
  To: ohad, shawnguo; +Cc: linux-kernel

From: Richard Zhu <Richard.Zhu@freescale.com>

enable the mu and m4 root clocks

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 drivers/clk/imx/clk-imx7d.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 448ef32..ac8288b 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -692,6 +692,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
 	clks[IMX7D_NAND_USDHC_BUS_ROOT_DIV] = imx_clk_divider("nand_usdhc_post_div", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
 	clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider("ahb_post_div", "ahb_pre_div", base + 0x9000, 0, 6);
+	clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2);
 	clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
 	clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
 	clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
@@ -769,6 +770,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
 	clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
 	clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
+	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate2("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
 	clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate2("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0);
 	clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate2("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
 	clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate2("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
@@ -870,5 +872,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 
 	imx_register_uart_clocks(uart_clks);
 
+	/* set the parent clock source of m4, then keep it enabled */
+	clk_set_parent(clks[IMX7D_ARM_M4_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_240M_CLK]);
+	clk_prepare_enable(clks[IMX7D_ARM_M4_ROOT_CLK]);
+
 }
 CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-06  8:06 [RFC 0/4]Enable rpmsg support on imx amp platforms Richard Zhu
  2016-01-06  8:06 ` [RFC 1/4] ARM: imx: enable " Richard Zhu
  2016-01-06  8:06 ` [RFC 2/4] clk: imx7d: enable the mu and m4 root clocks Richard Zhu
@ 2016-01-06  8:06 ` Richard Zhu
  2016-01-28  1:35   ` Shawn Guo
  2016-01-06  8:06 ` [RFC 4/4] samples/rpmsg: add the imx pingpong rpmsg sample Richard Zhu
  3 siblings, 1 reply; 13+ messages in thread
From: Richard Zhu @ 2016-01-06  8:06 UTC (permalink / raw)
  To: ohad, shawnguo; +Cc: linux-kernel

From: Richard Zhu <Richard.Zhu@freescale.com>

- add mu driver support, the irq and 4bytes msg of
the mu module are as the interaction channel
between A# core and the M4 core on imx amp platforms.
- register one notify in isr of the mu's irq used by
rpmsg.
- instance the virtual processor, and fill up the
virtio_config_ops in the platform related rpmsg
implementation codes.
- hard-code the vring storage shared by A# core and
M# core on AMP SOCs.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 arch/arm/mach-imx/Kconfig     |  12 ++
 arch/arm/mach-imx/Makefile    |   2 +
 arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
 include/linux/imx_rpmsg.h     |  27 ++++
 5 files changed, 622 insertions(+)
 create mode 100644 arch/arm/mach-imx/imx_rpmsg.c
 create mode 100644 arch/arm/mach-imx/mu.c
 create mode 100644 include/linux/imx_rpmsg.h

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 8ceda28..a7bc41c 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -56,6 +56,12 @@ config HAVE_IMX_GPC
 config HAVE_IMX_MMDC
 	bool
 
+config HAVE_IMX_MU
+	bool
+
+config HAVE_IMX_RPMSG
+	bool
+
 config HAVE_IMX_SRC
 	def_bool y if SMP
 	select ARCH_HAS_RESET_CONTROLLER
@@ -544,6 +550,9 @@ config SOC_IMX6SX
 	bool "i.MX6 SoloX support"
 	select PINCTRL_IMX6SX
 	select SOC_IMX6
+	select HAVE_IMX_MU
+	select HAVE_IMX_RPMSG
+	select RPMSG
 
 	help
 	  This enables support for Freescale i.MX6 SoloX processor.
@@ -562,6 +571,9 @@ config SOC_IMX7D
 	select ARM_GIC
 	select HAVE_IMX_ANATOP
 	select HAVE_IMX_MMDC
+	select HAVE_IMX_MU
+	select HAVE_IMX_RPMSG
+	select RPMSG
 	help
 		This enables support for Freescale i.MX7 Dual processor.
 
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index fb689d8..a3c1814 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -74,7 +74,9 @@ obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o
 obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
+obj-$(CONFIG_HAVE_IMX_MU) += mu.o
 obj-$(CONFIG_HAVE_IMX_SRC) += src.o
+obj-$(CONFIG_HAVE_IMX_RPMSG) += imx_rpmsg.o
 ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
 AFLAGS_headsmp.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-imx/imx_rpmsg.c b/arch/arm/mach-imx/imx_rpmsg.c
new file mode 100644
index 0000000..ab6ba7a
--- /dev/null
+++ b/arch/arm/mach-imx/imx_rpmsg.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * derived from the omap-rpmsg implementation.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <linux/imx_rpmsg.h>
+
+struct imx_rpmsg_vproc {
+	struct virtio_device vdev;
+	unsigned int vring[2];
+	char *rproc_name;
+	struct mutex lock;
+	struct notifier_block nb;
+	struct virtqueue *vq[2];
+	int base_vq_id;
+	int num_of_vqs;
+};
+
+/*
+ * For now, allocate 256 buffers of 512 bytes for each side. each buffer
+ * will then have 16B for the msg header and 496B for the payload.
+ * This will require a total space of 256KB for the buffers themselves, and
+ * 3 pages for every vring (the size of the vring depends on the number of
+ * buffers it supports).
+ */
+#define RPMSG_NUM_BUFS		(512)
+#define RPMSG_BUF_SIZE		(512)
+#define RPMSG_BUFS_SPACE	(RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/*
+ * The alignment between the consumer and producer parts of the vring.
+ * Note: this is part of the "wire" protocol. If you change this, you need
+ * to update your BIOS image as well
+ */
+#define RPMSG_VRING_ALIGN	(4096)
+
+/* With 256 buffers, our vring will occupy 3 pages */
+#define RPMSG_RING_SIZE	((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
+				RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
+
+#define to_imx_rpdev(vd) container_of(vd, struct imx_rpmsg_vproc, vdev)
+
+struct imx_rpmsg_vq_info {
+	__u16 num;	/* number of entries in the virtio_ring */
+	__u16 vq_id;	/* a globaly unique index of this virtqueue */
+	void *addr;	/* address where we mapped the virtio ring */
+	struct imx_rpmsg_vproc *rpdev;
+};
+
+static u64 imx_rpmsg_get_features(struct virtio_device *vdev)
+{
+	return 1 << VIRTIO_RPMSG_F_NS;
+}
+
+static int imx_rpmsg_finalize_features(struct virtio_device *vdev)
+{
+	/* Give virtio_ring a chance to accept features */
+	vring_transport_features(vdev);
+	return 0;
+}
+
+/* kick the remote processor, and let it know which virtqueue to poke at */
+static bool imx_rpmsg_notify(struct virtqueue *vq)
+{
+	int ret;
+	unsigned int mu_rpmsg = 0;
+	struct imx_rpmsg_vq_info *rpvq = vq->priv;
+
+	mu_rpmsg = rpvq->vq_id << 16;
+	mutex_lock(&rpvq->rpdev->lock);
+	/* send the index of the triggered virtqueue as the mu payload */
+	ret = imx_mu_rpmsg_send(mu_rpmsg);
+	mutex_unlock(&rpvq->rpdev->lock);
+	if (ret) {
+		pr_err("ugh, imx_mu_rpmsg_send() failed: %d\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+static int imx_mu_rpmsg_callback(struct notifier_block *this,
+					unsigned long index, void *data)
+{
+	u32 mu_msg = (u32) data;
+	struct imx_rpmsg_vproc *rpdev;
+
+	rpdev = container_of(this, struct imx_rpmsg_vproc, nb);
+
+	pr_debug("%s mu_msg: 0x%x\n", __func__, mu_msg);
+
+	/* ignore vq indices which are clearly not for us */
+	mu_msg = mu_msg >> 16;
+	if (mu_msg < rpdev->base_vq_id)
+		pr_err("mu_msg: 0x%x is invalid\n", mu_msg);
+
+	mu_msg -= rpdev->base_vq_id;
+
+	/*
+	 * Currently both PENDING_MSG and explicit-virtqueue-index
+	 * messaging are supported.
+	 * Whatever approach is taken, at this point 'mu_msg' contains
+	 * the index of the vring which was just triggered.
+	 */
+	if (mu_msg < rpdev->num_of_vqs)
+		vring_interrupt(mu_msg, rpdev->vq[mu_msg]);
+
+	return NOTIFY_DONE;
+}
+
+static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
+				    unsigned index,
+				    void (*callback)(struct virtqueue *vq),
+				    const char *name)
+{
+	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
+	struct imx_rpmsg_vq_info *rpvq;
+	struct virtqueue *vq;
+	int err;
+
+	rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
+	if (!rpvq)
+		return ERR_PTR(-ENOMEM);
+
+	/* ioremap'ing normal memory, so we cast away sparse's complaints */
+	rpvq->addr = (__force void *) ioremap_nocache(rpdev->vring[index],
+							RPMSG_RING_SIZE);
+	if (!rpvq->addr) {
+		err = -ENOMEM;
+		goto free_rpvq;
+	}
+
+	memset(rpvq->addr, 0, RPMSG_RING_SIZE);
+
+	pr_debug("vring%d: phys 0x%x, virt 0x%x\n", index, rpdev->vring[index],
+					(unsigned int) rpvq->addr);
+
+	vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN,
+			vdev, true, rpvq->addr, imx_rpmsg_notify, callback,
+			name);
+	if (!vq) {
+		pr_err("vring_new_virtqueue failed\n");
+		err = -ENOMEM;
+		goto unmap_vring;
+	}
+
+	rpdev->vq[index] = vq;
+	vq->priv = rpvq;
+	/* system-wide unique id for this virtqueue */
+	rpvq->vq_id = rpdev->base_vq_id + index;
+	rpvq->rpdev = rpdev;
+	mutex_init(&rpdev->lock);
+
+	return vq;
+
+unmap_vring:
+	/* iounmap normal memory, so make sparse happy */
+	iounmap((__force void __iomem *) rpvq->addr);
+free_rpvq:
+	kfree(rpvq);
+	return ERR_PTR(err);
+}
+
+static void imx_rpmsg_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+		struct imx_rpmsg_vq_info *rpvq = vq->priv;
+
+		iounmap(rpvq->addr);
+		vring_del_virtqueue(vq);
+		kfree(rpvq);
+	}
+
+	if (&rpdev->nb)
+		imx_mu_rpmsg_unregister_nb((const char *)rpdev->rproc_name,
+				&rpdev->nb);
+}
+
+static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+		       struct virtqueue *vqs[],
+		       vq_callback_t *callbacks[],
+		       const char *names[])
+{
+	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
+	int i, err;
+
+	/* we maintain two virtqueues per remote processor (for RX and TX) */
+	if (nvqs != 2)
+		return -EINVAL;
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i])) {
+			err = PTR_ERR(vqs[i]);
+			goto error;
+		}
+	}
+
+	rpdev->num_of_vqs = nvqs;
+
+	rpdev->nb.notifier_call = imx_mu_rpmsg_callback;
+	imx_mu_rpmsg_register_nb((const char *)rpdev->rproc_name, &rpdev->nb);
+
+	return 0;
+
+error:
+	imx_rpmsg_del_vqs(vdev);
+	return err;
+}
+
+static void imx_rpmsg_reset(struct virtio_device *vdev)
+{
+	dev_dbg(&vdev->dev, "reset !\n");
+}
+
+static u8 imx_rpmsg_get_status(struct virtio_device *vdev)
+{
+	return 0;
+}
+
+static void imx_rpmsg_set_status(struct virtio_device *vdev, u8 status)
+{
+	dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status);
+}
+
+static void imx_rpmsg_vproc_release(struct device *dev)
+{
+	/* this handler is provided so driver core doesn't yell at us */
+}
+
+static struct virtio_config_ops imx_rpmsg_config_ops = {
+	.get_features	= imx_rpmsg_get_features,
+	.finalize_features = imx_rpmsg_finalize_features,
+	.find_vqs	= imx_rpmsg_find_vqs,
+	.del_vqs	= imx_rpmsg_del_vqs,
+	.reset		= imx_rpmsg_reset,
+	.set_status	= imx_rpmsg_set_status,
+	.get_status	= imx_rpmsg_get_status,
+};
+
+static struct imx_rpmsg_vproc imx_rpmsg_vprocs[] = {
+	{
+		.vdev.id.device	= VIRTIO_ID_RPMSG,
+		.vdev.config	= &imx_rpmsg_config_ops,
+		.rproc_name	= "m4",
+		.base_vq_id	= 0,
+	},
+};
+
+static const struct of_device_id imx_rpmsg_dt_ids[] = {
+	{ .compatible = "fsl,imx6sx-rpmsg", },
+	{ .compatible = "fsl,imx7d-rpmsg", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_rpmsg_dt_ids);
+
+static int imx_rpmsg_probe(struct platform_device *pdev)
+{
+	int i, ret = 0;
+	struct device_node *np = pdev->dev.of_node;
+
+	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
+		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
+
+		if (!strcmp(rpdev->rproc_name, "m4")) {
+			ret = of_device_is_compatible(np, "fsl,imx7d-rpmsg");
+			ret |= of_device_is_compatible(np, "fsl,imx6sx-rpmsg");
+			if (ret) {
+				/* hardcodes here now. */
+				rpdev->vring[0] = 0xBFFF0000;
+				rpdev->vring[1] = 0xBFFF8000;
+			}
+		} else {
+			break;
+		}
+
+		pr_debug("%s rpdev%d: vring0 0x%x, vring1 0x%x\n", __func__,
+				i, rpdev->vring[0], rpdev->vring[1]);
+
+		rpdev->vdev.dev.parent = &pdev->dev;
+		rpdev->vdev.dev.release = imx_rpmsg_vproc_release;
+
+		ret = register_virtio_device(&rpdev->vdev);
+		if (ret) {
+			pr_err("%s failed to register rpdev: %d\n",
+					__func__, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int imx_rpmsg_remove(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
+		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
+
+		unregister_virtio_device(&rpdev->vdev);
+	}
+	return 0;
+}
+
+static struct platform_driver imx_rpmsg_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "imx-rpmsg",
+		   .of_match_table = imx_rpmsg_dt_ids,
+		   },
+	.probe = imx_rpmsg_probe,
+	.remove = imx_rpmsg_remove,
+};
+
+static int __init imx_rpmsg_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&imx_rpmsg_driver);
+	if (ret)
+		pr_err("Unable to initialize rpmsg driver\n");
+	else
+		pr_info("imx rpmsg driver is registered.\n");
+
+	return ret;
+}
+
+static void __exit imx_rpmsg_exit(void)
+{
+	pr_info("imx rpmsg driver is unregistered.\n");
+	platform_driver_unregister(&imx_rpmsg_driver);
+}
+
+module_exit(imx_rpmsg_exit);
+module_init(imx_rpmsg_init);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("iMX remote processor messaging virtio device");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-imx/mu.c b/arch/arm/mach-imx/mu.c
new file mode 100644
index 0000000..7b07f48
--- /dev/null
+++ b/arch/arm/mach-imx/mu.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include "common.h"
+#include "hardware.h"
+
+#define MU_ATR0_OFFSET	0x0
+#define MU_ARR0_OFFSET	0x10
+#define MU_ARR1_OFFSET	0x14
+#define MU_ASR		0x20
+#define MU_ACR		0x24
+
+#define MU_RPMSG_HANDSHAKE_INDEX	1
+
+struct imx_mu_rpmsg_box {
+	const char *name;
+	struct blocking_notifier_head notifier;
+};
+
+static struct imx_mu_rpmsg_box mu_rpmsg_box = {
+	.name	= "m4",
+};
+
+static void __iomem *mu_base;
+static u32 m4_message;
+static struct delayed_work rpmsg_work;
+
+static int imx_mu_send_message(unsigned int index, unsigned int data)
+{
+	u32 val, ep;
+	int i, te_flag = 0;
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+	/* wait for transfer buffer empty, and no event pending */
+	do {
+		val = readl_relaxed(mu_base + MU_ASR);
+		ep = val & BIT(4);
+		if (time_after(jiffies, timeout)) {
+			pr_err("Waiting MU transmit buffer empty timeout!\n");
+			return -EIO;
+		}
+	} while (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4)));
+
+	writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET);
+
+	/*
+	 * make a double check that TEn is not empty after write
+	 */
+	val = readl_relaxed(mu_base + MU_ASR);
+	ep = val & BIT(4);
+	if (((val & (1 << (20 + (3 - index)))) == 0) || (ep == BIT(4)))
+		return 0;
+
+	/*
+	 * Make sure that TEn flag is changed, after the ATRn is filled up.
+	 */
+	for (i = 0; i < 100; i++) {
+		val = readl_relaxed(mu_base + MU_ASR);
+		ep = val & BIT(4);
+		if (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))) {
+			te_flag = 0;
+			break;
+		} else if (time_after(jiffies, timeout)) {
+			/* Can't see TEn 1->0, maybe already handled! */
+			te_flag = 1;
+			break;
+		}
+	}
+	if (te_flag == 0)
+		pr_info("TEn isn't changed when ATRn is filled up.\n");
+
+	return 0;
+}
+
+int imx_mu_rpmsg_send(unsigned int rpmsg)
+{
+	return imx_mu_send_message(MU_RPMSG_HANDSHAKE_INDEX, rpmsg);
+}
+
+int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb)
+{
+	if ((name == NULL) || (nb == NULL))
+		return -EINVAL;
+
+	if (!strcmp(mu_rpmsg_box.name, name))
+		blocking_notifier_chain_register(&(mu_rpmsg_box.notifier), nb);
+	else
+		return -ENOENT;
+
+	return 0;
+}
+
+int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb)
+{
+	if ((name == NULL) || (nb == NULL))
+		return -EINVAL;
+
+	if (!strcmp(mu_rpmsg_box.name, name))
+		blocking_notifier_chain_unregister(&(mu_rpmsg_box.notifier),
+				nb);
+	else
+		return -ENOENT;
+
+	return 0;
+}
+
+static void rpmsg_work_handler(struct work_struct *work)
+{
+
+	blocking_notifier_call_chain(&(mu_rpmsg_box.notifier), 4,
+						(void *)m4_message);
+	m4_message = 0;
+}
+
+static irqreturn_t imx_mu_isr(int irq, void *param)
+{
+	u32 irqs;
+
+	irqs = readl_relaxed(mu_base + MU_ASR);
+
+	/* RPMSG */
+	if (irqs & (1 << 26)) {
+		/* get message from receive buffer */
+		m4_message = readl_relaxed(mu_base + MU_ARR1_OFFSET);
+		schedule_delayed_work(&rpmsg_work, 0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int imx_mu_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 irq;
+	struct device_node *np;
+	struct clk *clk;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
+	mu_base = of_iomap(np, 0);
+	WARN_ON(!mu_base);
+
+	irq = platform_get_irq(pdev, 0);
+	ret = request_irq(irq, imx_mu_isr,
+		IRQF_EARLY_RESUME, "imx-mu", &mu_rpmsg_box);
+	if (ret) {
+		pr_err("%s: register interrupt %d failed, rc %d\n",
+			__func__, irq, ret);
+		return ret;
+	}
+
+	ret = of_device_is_compatible(np, "fsl,imx7d-mu");
+	if (ret) {
+		clk = devm_clk_get(&pdev->dev, "mu");
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev,
+				"mu clock source missing or invalid\n");
+			return PTR_ERR(clk);
+		}
+
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"unable to enable mu clock\n");
+			return ret;
+		}
+	}
+
+	INIT_DELAYED_WORK(&rpmsg_work, rpmsg_work_handler);
+	/* enable the bit26(RIE1) of MU_ACR */
+	writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(26),
+			mu_base + MU_ACR);
+	BLOCKING_INIT_NOTIFIER_HEAD(&(mu_rpmsg_box.notifier));
+
+	pr_info("MU is ready for cross core communication!\n");
+
+	return 0;
+}
+
+static const struct of_device_id imx_mu_ids[] = {
+	{ .compatible = "fsl,imx6sx-mu" },
+	{ .compatible = "fsl,imx7d-mu" },
+	{ }
+};
+
+static struct platform_driver imx_mu_driver = {
+	.driver = {
+		.name   = "imx-mu",
+		.owner  = THIS_MODULE,
+		.of_match_table = imx_mu_ids,
+	},
+	.probe = imx_mu_probe,
+};
+
+static int __init imx_mu_init(void)
+{
+	return platform_driver_register(&imx_mu_driver);
+}
+subsys_initcall(imx_mu_init);
diff --git a/include/linux/imx_rpmsg.h b/include/linux/imx_rpmsg.h
new file mode 100644
index 0000000..2b0dca5
--- /dev/null
+++ b/include/linux/imx_rpmsg.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*
+ * @file linux/imx_rpmsg.h
+ *
+ * @brief Global header file for imx RPMSG
+ *
+ * @ingroup RPMSG
+ */
+#ifndef __LINUX_IMX_RPMSG_H__
+#define __LINUX_IMX_RPMSG_H__
+
+int imx_mu_rpmsg_send(unsigned int vq_id);
+int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb);
+int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb);
+#endif /* __LINUX_IMX_RPMSG_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC 4/4] samples/rpmsg: add the imx pingpong rpmsg sample
  2016-01-06  8:06 [RFC 0/4]Enable rpmsg support on imx amp platforms Richard Zhu
                   ` (2 preceding siblings ...)
  2016-01-06  8:06 ` [RFC 3/4] ARM: imx: add the platform related rpmsg implementation Richard Zhu
@ 2016-01-06  8:06 ` Richard Zhu
  3 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-06  8:06 UTC (permalink / raw)
  To: ohad, shawnguo; +Cc: linux-kernel

From: Richard Zhu <Richard.Zhu@freescale.com>

Add one pingpong rpmsg sample, that demostrate the
how to communicate with an AMP-configured remote
processor over rpmsg bus.

In this sample, A# core of imx AMP SOC would
send out one unsigned int data "rpmsg_pingpong",
the initialized value is "0",
to the remote M# core when this driver is loaded.

The "rpmsg_pingpong" would be plus one at M# core side,
then sent back to A# core.
A# would do the same operations, after receive the
"rpmsg_pingpong" sent out by M# core, then send it
back to M#.

The demonstration would be stopped after 10000 times

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 samples/Kconfig                    |  8 +++
 samples/rpmsg/Makefile             |  1 +
 samples/rpmsg/imx_rpmsg_pingpong.c | 99 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 samples/rpmsg/imx_rpmsg_pingpong.c

diff --git a/samples/Kconfig b/samples/Kconfig
index d54f28c..49e0b62 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -63,6 +63,14 @@ config SAMPLE_RPMSG_CLIENT
 	  to communicate with an AMP-configured remote processor over
 	  the rpmsg bus.
 
+config IMX_RPMSG_PINGPONG
+	tristate "Build imx rpmsg pingpong sample -- loadable modules only"
+	depends on RPMSG && m
+	help
+	  Build an imx rpmsg pingpong sample driver, which demonstrates
+	  the data transactions on the AMP-configured imx processor over
+	  the rpmsg bus.
+
 config SAMPLE_LIVEPATCH
 	tristate "Build live patching sample -- loadable modules only"
 	depends on LIVEPATCH && m
diff --git a/samples/rpmsg/Makefile b/samples/rpmsg/Makefile
index 2d4973c..c01daae 100644
--- a/samples/rpmsg/Makefile
+++ b/samples/rpmsg/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_SAMPLE_RPMSG_CLIENT) += rpmsg_client_sample.o
+obj-$(CONFIG_IMX_RPMSG_PINGPONG)	+= imx_rpmsg_pingpong.o
diff --git a/samples/rpmsg/imx_rpmsg_pingpong.c b/samples/rpmsg/imx_rpmsg_pingpong.c
new file mode 100644
index 0000000..f46ebe1
--- /dev/null
+++ b/samples/rpmsg/imx_rpmsg_pingpong.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * derived from the omap-rpmsg implementation.
+ * Remote processor messaging transport - pingpong driver
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/rpmsg.h>
+
+#define MSG_LIMIT	100000
+static unsigned int rpmsg_pingpong;
+static int rx_count;
+
+static void rpmsg_pingpong_cb(struct rpmsg_channel *rpdev, void *data, int len,
+						void *priv, u32 src)
+{
+	int err;
+
+	/* reply */
+	rpmsg_pingpong = *(unsigned int *)data;
+	pr_info("get %d (src: 0x%x)\n",
+			rpmsg_pingpong, src);
+	rx_count++;
+
+	/* pingpongs should not live forever */
+	if (rx_count >= MSG_LIMIT) {
+		dev_info(&rpdev->dev, "goodbye!\n");
+		return;
+	}
+	rpmsg_pingpong++;
+	err = rpmsg_sendto(rpdev, (void *)(&rpmsg_pingpong), 4, src);
+
+	if (err)
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
+}
+
+static int rpmsg_pingpong_probe(struct rpmsg_channel *rpdev)
+{
+	int err;
+
+	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+			rpdev->src, rpdev->dst);
+
+	rpmsg_pingpong = 0;
+	rx_count = 0;
+	err = rpmsg_sendto(rpdev, (void *)(&rpmsg_pingpong), 4, rpdev->dst);
+	if (err) {
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void rpmsg_pingpong_remove(struct rpmsg_channel *rpdev)
+{
+	dev_info(&rpdev->dev, "rpmsg pingpong driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_pingpong_id_table[] = {
+	{ .name	= "rpmsg-openamp-demo-channel" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pingpong_id_table);
+
+static struct rpmsg_driver rpmsg_pingpong_driver = {
+	.drv.name	= KBUILD_MODNAME,
+	.drv.owner	= THIS_MODULE,
+	.id_table	= rpmsg_driver_pingpong_id_table,
+	.probe		= rpmsg_pingpong_probe,
+	.callback	= rpmsg_pingpong_cb,
+	.remove		= rpmsg_pingpong_remove,
+};
+
+static int __init init(void)
+{
+	return register_rpmsg_driver(&rpmsg_pingpong_driver);
+}
+
+static void __exit fini(void)
+{
+	unregister_rpmsg_driver(&rpmsg_pingpong_driver);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("iMX virtio remote processor messaging pingpong driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-06  8:06 ` [RFC 3/4] ARM: imx: add the platform related rpmsg implementation Richard Zhu
@ 2016-01-28  1:35   ` Shawn Guo
  2016-01-28  2:17     ` Richard Zhu
  0 siblings, 1 reply; 13+ messages in thread
From: Shawn Guo @ 2016-01-28  1:35 UTC (permalink / raw)
  To: Richard Zhu; +Cc: ohad, Stefan Agner, linux-kernel

On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> From: Richard Zhu <Richard.Zhu@freescale.com>
> 
> - add mu driver support, the irq and 4bytes msg of
> the mu module are as the interaction channel
> between A# core and the M4 core on imx amp platforms.
> - register one notify in isr of the mu's irq used by
> rpmsg.
> - instance the virtual processor, and fill up the
> virtio_config_ops in the platform related rpmsg
> implementation codes.
> - hard-code the vring storage shared by A# core and
> M# core on AMP SOCs.
> 
> Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> ---
>  arch/arm/mach-imx/Kconfig     |  12 ++
>  arch/arm/mach-imx/Makefile    |   2 +
>  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++

I'm not rpmsg expert, but it seems to me that the driver should be
put into drivers/rpmsg/ rather than mach-imx.

Also, when you repost, you may want to copy
Stefan Agner <stefan@agner.ch>, who is helping maintain Vybrid platform
and might be interested in your patches.

Shawn

>  include/linux/imx_rpmsg.h     |  27 ++++
>  5 files changed, 622 insertions(+)
>  create mode 100644 arch/arm/mach-imx/imx_rpmsg.c
>  create mode 100644 arch/arm/mach-imx/mu.c
>  create mode 100644 include/linux/imx_rpmsg.h
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 8ceda28..a7bc41c 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -56,6 +56,12 @@ config HAVE_IMX_GPC
>  config HAVE_IMX_MMDC
>  	bool
>  
> +config HAVE_IMX_MU
> +	bool
> +
> +config HAVE_IMX_RPMSG
> +	bool
> +
>  config HAVE_IMX_SRC
>  	def_bool y if SMP
>  	select ARCH_HAS_RESET_CONTROLLER
> @@ -544,6 +550,9 @@ config SOC_IMX6SX
>  	bool "i.MX6 SoloX support"
>  	select PINCTRL_IMX6SX
>  	select SOC_IMX6
> +	select HAVE_IMX_MU
> +	select HAVE_IMX_RPMSG
> +	select RPMSG
>  
>  	help
>  	  This enables support for Freescale i.MX6 SoloX processor.
> @@ -562,6 +571,9 @@ config SOC_IMX7D
>  	select ARM_GIC
>  	select HAVE_IMX_ANATOP
>  	select HAVE_IMX_MMDC
> +	select HAVE_IMX_MU
> +	select HAVE_IMX_RPMSG
> +	select RPMSG
>  	help
>  		This enables support for Freescale i.MX7 Dual processor.
>  
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index fb689d8..a3c1814 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -74,7 +74,9 @@ obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o
>  obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
>  obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
>  obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
> +obj-$(CONFIG_HAVE_IMX_MU) += mu.o
>  obj-$(CONFIG_HAVE_IMX_SRC) += src.o
> +obj-$(CONFIG_HAVE_IMX_RPMSG) += imx_rpmsg.o
>  ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
>  AFLAGS_headsmp.o :=-Wa,-march=armv7-a
>  obj-$(CONFIG_SMP) += headsmp.o platsmp.o
> diff --git a/arch/arm/mach-imx/imx_rpmsg.c b/arch/arm/mach-imx/imx_rpmsg.c
> new file mode 100644
> index 0000000..ab6ba7a
> --- /dev/null
> +++ b/arch/arm/mach-imx/imx_rpmsg.c
> @@ -0,0 +1,364 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + *
> + * derived from the omap-rpmsg implementation.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/notifier.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/rpmsg.h>
> +#include <linux/slab.h>
> +#include <linux/virtio.h>
> +#include <linux/virtio_config.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_ring.h>
> +#include <linux/imx_rpmsg.h>
> +
> +struct imx_rpmsg_vproc {
> +	struct virtio_device vdev;
> +	unsigned int vring[2];
> +	char *rproc_name;
> +	struct mutex lock;
> +	struct notifier_block nb;
> +	struct virtqueue *vq[2];
> +	int base_vq_id;
> +	int num_of_vqs;
> +};
> +
> +/*
> + * For now, allocate 256 buffers of 512 bytes for each side. each buffer
> + * will then have 16B for the msg header and 496B for the payload.
> + * This will require a total space of 256KB for the buffers themselves, and
> + * 3 pages for every vring (the size of the vring depends on the number of
> + * buffers it supports).
> + */
> +#define RPMSG_NUM_BUFS		(512)
> +#define RPMSG_BUF_SIZE		(512)
> +#define RPMSG_BUFS_SPACE	(RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
> +
> +/*
> + * The alignment between the consumer and producer parts of the vring.
> + * Note: this is part of the "wire" protocol. If you change this, you need
> + * to update your BIOS image as well
> + */
> +#define RPMSG_VRING_ALIGN	(4096)
> +
> +/* With 256 buffers, our vring will occupy 3 pages */
> +#define RPMSG_RING_SIZE	((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
> +				RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
> +
> +#define to_imx_rpdev(vd) container_of(vd, struct imx_rpmsg_vproc, vdev)
> +
> +struct imx_rpmsg_vq_info {
> +	__u16 num;	/* number of entries in the virtio_ring */
> +	__u16 vq_id;	/* a globaly unique index of this virtqueue */
> +	void *addr;	/* address where we mapped the virtio ring */
> +	struct imx_rpmsg_vproc *rpdev;
> +};
> +
> +static u64 imx_rpmsg_get_features(struct virtio_device *vdev)
> +{
> +	return 1 << VIRTIO_RPMSG_F_NS;
> +}
> +
> +static int imx_rpmsg_finalize_features(struct virtio_device *vdev)
> +{
> +	/* Give virtio_ring a chance to accept features */
> +	vring_transport_features(vdev);
> +	return 0;
> +}
> +
> +/* kick the remote processor, and let it know which virtqueue to poke at */
> +static bool imx_rpmsg_notify(struct virtqueue *vq)
> +{
> +	int ret;
> +	unsigned int mu_rpmsg = 0;
> +	struct imx_rpmsg_vq_info *rpvq = vq->priv;
> +
> +	mu_rpmsg = rpvq->vq_id << 16;
> +	mutex_lock(&rpvq->rpdev->lock);
> +	/* send the index of the triggered virtqueue as the mu payload */
> +	ret = imx_mu_rpmsg_send(mu_rpmsg);
> +	mutex_unlock(&rpvq->rpdev->lock);
> +	if (ret) {
> +		pr_err("ugh, imx_mu_rpmsg_send() failed: %d\n", ret);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static int imx_mu_rpmsg_callback(struct notifier_block *this,
> +					unsigned long index, void *data)
> +{
> +	u32 mu_msg = (u32) data;
> +	struct imx_rpmsg_vproc *rpdev;
> +
> +	rpdev = container_of(this, struct imx_rpmsg_vproc, nb);
> +
> +	pr_debug("%s mu_msg: 0x%x\n", __func__, mu_msg);
> +
> +	/* ignore vq indices which are clearly not for us */
> +	mu_msg = mu_msg >> 16;
> +	if (mu_msg < rpdev->base_vq_id)
> +		pr_err("mu_msg: 0x%x is invalid\n", mu_msg);
> +
> +	mu_msg -= rpdev->base_vq_id;
> +
> +	/*
> +	 * Currently both PENDING_MSG and explicit-virtqueue-index
> +	 * messaging are supported.
> +	 * Whatever approach is taken, at this point 'mu_msg' contains
> +	 * the index of the vring which was just triggered.
> +	 */
> +	if (mu_msg < rpdev->num_of_vqs)
> +		vring_interrupt(mu_msg, rpdev->vq[mu_msg]);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
> +				    unsigned index,
> +				    void (*callback)(struct virtqueue *vq),
> +				    const char *name)
> +{
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +	struct imx_rpmsg_vq_info *rpvq;
> +	struct virtqueue *vq;
> +	int err;
> +
> +	rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
> +	if (!rpvq)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* ioremap'ing normal memory, so we cast away sparse's complaints */
> +	rpvq->addr = (__force void *) ioremap_nocache(rpdev->vring[index],
> +							RPMSG_RING_SIZE);
> +	if (!rpvq->addr) {
> +		err = -ENOMEM;
> +		goto free_rpvq;
> +	}
> +
> +	memset(rpvq->addr, 0, RPMSG_RING_SIZE);
> +
> +	pr_debug("vring%d: phys 0x%x, virt 0x%x\n", index, rpdev->vring[index],
> +					(unsigned int) rpvq->addr);
> +
> +	vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN,
> +			vdev, true, rpvq->addr, imx_rpmsg_notify, callback,
> +			name);
> +	if (!vq) {
> +		pr_err("vring_new_virtqueue failed\n");
> +		err = -ENOMEM;
> +		goto unmap_vring;
> +	}
> +
> +	rpdev->vq[index] = vq;
> +	vq->priv = rpvq;
> +	/* system-wide unique id for this virtqueue */
> +	rpvq->vq_id = rpdev->base_vq_id + index;
> +	rpvq->rpdev = rpdev;
> +	mutex_init(&rpdev->lock);
> +
> +	return vq;
> +
> +unmap_vring:
> +	/* iounmap normal memory, so make sparse happy */
> +	iounmap((__force void __iomem *) rpvq->addr);
> +free_rpvq:
> +	kfree(rpvq);
> +	return ERR_PTR(err);
> +}
> +
> +static void imx_rpmsg_del_vqs(struct virtio_device *vdev)
> +{
> +	struct virtqueue *vq, *n;
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +
> +	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
> +		struct imx_rpmsg_vq_info *rpvq = vq->priv;
> +
> +		iounmap(rpvq->addr);
> +		vring_del_virtqueue(vq);
> +		kfree(rpvq);
> +	}
> +
> +	if (&rpdev->nb)
> +		imx_mu_rpmsg_unregister_nb((const char *)rpdev->rproc_name,
> +				&rpdev->nb);
> +}
> +
> +static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> +		       struct virtqueue *vqs[],
> +		       vq_callback_t *callbacks[],
> +		       const char *names[])
> +{
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +	int i, err;
> +
> +	/* we maintain two virtqueues per remote processor (for RX and TX) */
> +	if (nvqs != 2)
> +		return -EINVAL;
> +
> +	for (i = 0; i < nvqs; ++i) {
> +		vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
> +		if (IS_ERR(vqs[i])) {
> +			err = PTR_ERR(vqs[i]);
> +			goto error;
> +		}
> +	}
> +
> +	rpdev->num_of_vqs = nvqs;
> +
> +	rpdev->nb.notifier_call = imx_mu_rpmsg_callback;
> +	imx_mu_rpmsg_register_nb((const char *)rpdev->rproc_name, &rpdev->nb);
> +
> +	return 0;
> +
> +error:
> +	imx_rpmsg_del_vqs(vdev);
> +	return err;
> +}
> +
> +static void imx_rpmsg_reset(struct virtio_device *vdev)
> +{
> +	dev_dbg(&vdev->dev, "reset !\n");
> +}
> +
> +static u8 imx_rpmsg_get_status(struct virtio_device *vdev)
> +{
> +	return 0;
> +}
> +
> +static void imx_rpmsg_set_status(struct virtio_device *vdev, u8 status)
> +{
> +	dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status);
> +}
> +
> +static void imx_rpmsg_vproc_release(struct device *dev)
> +{
> +	/* this handler is provided so driver core doesn't yell at us */
> +}
> +
> +static struct virtio_config_ops imx_rpmsg_config_ops = {
> +	.get_features	= imx_rpmsg_get_features,
> +	.finalize_features = imx_rpmsg_finalize_features,
> +	.find_vqs	= imx_rpmsg_find_vqs,
> +	.del_vqs	= imx_rpmsg_del_vqs,
> +	.reset		= imx_rpmsg_reset,
> +	.set_status	= imx_rpmsg_set_status,
> +	.get_status	= imx_rpmsg_get_status,
> +};
> +
> +static struct imx_rpmsg_vproc imx_rpmsg_vprocs[] = {
> +	{
> +		.vdev.id.device	= VIRTIO_ID_RPMSG,
> +		.vdev.config	= &imx_rpmsg_config_ops,
> +		.rproc_name	= "m4",
> +		.base_vq_id	= 0,
> +	},
> +};
> +
> +static const struct of_device_id imx_rpmsg_dt_ids[] = {
> +	{ .compatible = "fsl,imx6sx-rpmsg", },
> +	{ .compatible = "fsl,imx7d-rpmsg", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx_rpmsg_dt_ids);
> +
> +static int imx_rpmsg_probe(struct platform_device *pdev)
> +{
> +	int i, ret = 0;
> +	struct device_node *np = pdev->dev.of_node;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
> +		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
> +
> +		if (!strcmp(rpdev->rproc_name, "m4")) {
> +			ret = of_device_is_compatible(np, "fsl,imx7d-rpmsg");
> +			ret |= of_device_is_compatible(np, "fsl,imx6sx-rpmsg");
> +			if (ret) {
> +				/* hardcodes here now. */
> +				rpdev->vring[0] = 0xBFFF0000;
> +				rpdev->vring[1] = 0xBFFF8000;
> +			}
> +		} else {
> +			break;
> +		}
> +
> +		pr_debug("%s rpdev%d: vring0 0x%x, vring1 0x%x\n", __func__,
> +				i, rpdev->vring[0], rpdev->vring[1]);
> +
> +		rpdev->vdev.dev.parent = &pdev->dev;
> +		rpdev->vdev.dev.release = imx_rpmsg_vproc_release;
> +
> +		ret = register_virtio_device(&rpdev->vdev);
> +		if (ret) {
> +			pr_err("%s failed to register rpdev: %d\n",
> +					__func__, ret);
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int imx_rpmsg_remove(struct platform_device *pdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
> +		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
> +
> +		unregister_virtio_device(&rpdev->vdev);
> +	}
> +	return 0;
> +}
> +
> +static struct platform_driver imx_rpmsg_driver = {
> +	.driver = {
> +		   .owner = THIS_MODULE,
> +		   .name = "imx-rpmsg",
> +		   .of_match_table = imx_rpmsg_dt_ids,
> +		   },
> +	.probe = imx_rpmsg_probe,
> +	.remove = imx_rpmsg_remove,
> +};
> +
> +static int __init imx_rpmsg_init(void)
> +{
> +	int ret;
> +
> +	ret = platform_driver_register(&imx_rpmsg_driver);
> +	if (ret)
> +		pr_err("Unable to initialize rpmsg driver\n");
> +	else
> +		pr_info("imx rpmsg driver is registered.\n");
> +
> +	return ret;
> +}
> +
> +static void __exit imx_rpmsg_exit(void)
> +{
> +	pr_info("imx rpmsg driver is unregistered.\n");
> +	platform_driver_unregister(&imx_rpmsg_driver);
> +}
> +
> +module_exit(imx_rpmsg_exit);
> +module_init(imx_rpmsg_init);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("iMX remote processor messaging virtio device");
> +MODULE_LICENSE("GPL v2");
> diff --git a/arch/arm/mach-imx/mu.c b/arch/arm/mach-imx/mu.c
> new file mode 100644
> index 0000000..7b07f48
> --- /dev/null
> +++ b/arch/arm/mach-imx/mu.c
> @@ -0,0 +1,217 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/notifier.h>
> +#include <linux/platform_device.h>
> +#include "common.h"
> +#include "hardware.h"
> +
> +#define MU_ATR0_OFFSET	0x0
> +#define MU_ARR0_OFFSET	0x10
> +#define MU_ARR1_OFFSET	0x14
> +#define MU_ASR		0x20
> +#define MU_ACR		0x24
> +
> +#define MU_RPMSG_HANDSHAKE_INDEX	1
> +
> +struct imx_mu_rpmsg_box {
> +	const char *name;
> +	struct blocking_notifier_head notifier;
> +};
> +
> +static struct imx_mu_rpmsg_box mu_rpmsg_box = {
> +	.name	= "m4",
> +};
> +
> +static void __iomem *mu_base;
> +static u32 m4_message;
> +static struct delayed_work rpmsg_work;
> +
> +static int imx_mu_send_message(unsigned int index, unsigned int data)
> +{
> +	u32 val, ep;
> +	int i, te_flag = 0;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(500);
> +
> +	/* wait for transfer buffer empty, and no event pending */
> +	do {
> +		val = readl_relaxed(mu_base + MU_ASR);
> +		ep = val & BIT(4);
> +		if (time_after(jiffies, timeout)) {
> +			pr_err("Waiting MU transmit buffer empty timeout!\n");
> +			return -EIO;
> +		}
> +	} while (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4)));
> +
> +	writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET);
> +
> +	/*
> +	 * make a double check that TEn is not empty after write
> +	 */
> +	val = readl_relaxed(mu_base + MU_ASR);
> +	ep = val & BIT(4);
> +	if (((val & (1 << (20 + (3 - index)))) == 0) || (ep == BIT(4)))
> +		return 0;
> +
> +	/*
> +	 * Make sure that TEn flag is changed, after the ATRn is filled up.
> +	 */
> +	for (i = 0; i < 100; i++) {
> +		val = readl_relaxed(mu_base + MU_ASR);
> +		ep = val & BIT(4);
> +		if (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))) {
> +			te_flag = 0;
> +			break;
> +		} else if (time_after(jiffies, timeout)) {
> +			/* Can't see TEn 1->0, maybe already handled! */
> +			te_flag = 1;
> +			break;
> +		}
> +	}
> +	if (te_flag == 0)
> +		pr_info("TEn isn't changed when ATRn is filled up.\n");
> +
> +	return 0;
> +}
> +
> +int imx_mu_rpmsg_send(unsigned int rpmsg)
> +{
> +	return imx_mu_send_message(MU_RPMSG_HANDSHAKE_INDEX, rpmsg);
> +}
> +
> +int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb)
> +{
> +	if ((name == NULL) || (nb == NULL))
> +		return -EINVAL;
> +
> +	if (!strcmp(mu_rpmsg_box.name, name))
> +		blocking_notifier_chain_register(&(mu_rpmsg_box.notifier), nb);
> +	else
> +		return -ENOENT;
> +
> +	return 0;
> +}
> +
> +int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb)
> +{
> +	if ((name == NULL) || (nb == NULL))
> +		return -EINVAL;
> +
> +	if (!strcmp(mu_rpmsg_box.name, name))
> +		blocking_notifier_chain_unregister(&(mu_rpmsg_box.notifier),
> +				nb);
> +	else
> +		return -ENOENT;
> +
> +	return 0;
> +}
> +
> +static void rpmsg_work_handler(struct work_struct *work)
> +{
> +
> +	blocking_notifier_call_chain(&(mu_rpmsg_box.notifier), 4,
> +						(void *)m4_message);
> +	m4_message = 0;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *param)
> +{
> +	u32 irqs;
> +
> +	irqs = readl_relaxed(mu_base + MU_ASR);
> +
> +	/* RPMSG */
> +	if (irqs & (1 << 26)) {
> +		/* get message from receive buffer */
> +		m4_message = readl_relaxed(mu_base + MU_ARR1_OFFSET);
> +		schedule_delayed_work(&rpmsg_work, 0);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int imx_mu_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	u32 irq;
> +	struct device_node *np;
> +	struct clk *clk;
> +
> +	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
> +	mu_base = of_iomap(np, 0);
> +	WARN_ON(!mu_base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	ret = request_irq(irq, imx_mu_isr,
> +		IRQF_EARLY_RESUME, "imx-mu", &mu_rpmsg_box);
> +	if (ret) {
> +		pr_err("%s: register interrupt %d failed, rc %d\n",
> +			__func__, irq, ret);
> +		return ret;
> +	}
> +
> +	ret = of_device_is_compatible(np, "fsl,imx7d-mu");
> +	if (ret) {
> +		clk = devm_clk_get(&pdev->dev, "mu");
> +		if (IS_ERR(clk)) {
> +			dev_err(&pdev->dev,
> +				"mu clock source missing or invalid\n");
> +			return PTR_ERR(clk);
> +		}
> +
> +		ret = clk_prepare_enable(clk);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"unable to enable mu clock\n");
> +			return ret;
> +		}
> +	}
> +
> +	INIT_DELAYED_WORK(&rpmsg_work, rpmsg_work_handler);
> +	/* enable the bit26(RIE1) of MU_ACR */
> +	writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(26),
> +			mu_base + MU_ACR);
> +	BLOCKING_INIT_NOTIFIER_HEAD(&(mu_rpmsg_box.notifier));
> +
> +	pr_info("MU is ready for cross core communication!\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id imx_mu_ids[] = {
> +	{ .compatible = "fsl,imx6sx-mu" },
> +	{ .compatible = "fsl,imx7d-mu" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_mu_driver = {
> +	.driver = {
> +		.name   = "imx-mu",
> +		.owner  = THIS_MODULE,
> +		.of_match_table = imx_mu_ids,
> +	},
> +	.probe = imx_mu_probe,
> +};
> +
> +static int __init imx_mu_init(void)
> +{
> +	return platform_driver_register(&imx_mu_driver);
> +}
> +subsys_initcall(imx_mu_init);
> diff --git a/include/linux/imx_rpmsg.h b/include/linux/imx_rpmsg.h
> new file mode 100644
> index 0000000..2b0dca5
> --- /dev/null
> +++ b/include/linux/imx_rpmsg.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU Lesser General
> + * Public License.  You may obtain a copy of the GNU Lesser General
> + * Public License Version 2.1 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/lgpl-license.html
> + * http://www.gnu.org/copyleft/lgpl.html
> + */
> +
> +/*
> + * @file linux/imx_rpmsg.h
> + *
> + * @brief Global header file for imx RPMSG
> + *
> + * @ingroup RPMSG
> + */
> +#ifndef __LINUX_IMX_RPMSG_H__
> +#define __LINUX_IMX_RPMSG_H__
> +
> +int imx_mu_rpmsg_send(unsigned int vq_id);
> +int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block *nb);
> +int imx_mu_rpmsg_unregister_nb(const char *name, struct notifier_block *nb);
> +#endif /* __LINUX_IMX_RPMSG_H__ */
> -- 
> 1.9.1
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-28  1:35   ` Shawn Guo
@ 2016-01-28  2:17     ` Richard Zhu
  2016-01-28  5:50       ` Shawn Guo
  2016-02-15  6:10         ` Shawn Guo
  0 siblings, 2 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-28  2:17 UTC (permalink / raw)
  To: Shawn Guo; +Cc: ohad, Stefan Agner, linux-kernel

Hi Shawn:
Thanks for your comments.
Further review would copied to Stefan Agner.

Best Regards
hongxing zhu
Linux BSP team
Office: 86-21-28937189
Email: hongxing.zhu@nxp.com


-----Original Message-----
From: Shawn Guo [mailto:shawnguo@kernel.org] 
Sent: Thursday, January 28, 2016 9:35 AM
To: Richard Zhu
Cc: ohad@wizery.com; Stefan Agner; linux-kernel@vger.kernel.org
Subject: Re: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation

On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> From: Richard Zhu <Richard.Zhu@freescale.com>
> 
> - add mu driver support, the irq and 4bytes msg of the mu module are 
> as the interaction channel between A# core and the M4 core on imx amp 
> platforms.
> - register one notify in isr of the mu's irq used by rpmsg.
> - instance the virtual processor, and fill up the virtio_config_ops in 
> the platform related rpmsg implementation codes.
> - hard-code the vring storage shared by A# core and M# core on AMP 
> SOCs.
> 
> Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> ---
>  arch/arm/mach-imx/Kconfig     |  12 ++
>  arch/arm/mach-imx/Makefile    |   2 +
>  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++

I'm not rpmsg expert, but it seems to me that the driver should be put into drivers/rpmsg/ rather than mach-imx.
[Richard] This part rpmsg codes are closed related to the platform. For example, kinds of ops callback functions.
Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does to omap rpmsg implementation.
http://omappedia.org/wiki/RPMsg_Kernel_Sources

Also, when you repost, you may want to copy Stefan Agner <stefan@agner.ch>, who is helping maintain Vybrid platform and might be interested in your patches.

Shawn

>  include/linux/imx_rpmsg.h     |  27 ++++
>  5 files changed, 622 insertions(+)
>  create mode 100644 arch/arm/mach-imx/imx_rpmsg.c  create mode 100644 
> arch/arm/mach-imx/mu.c  create mode 100644 include/linux/imx_rpmsg.h
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig 
> index 8ceda28..a7bc41c 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -56,6 +56,12 @@ config HAVE_IMX_GPC  config HAVE_IMX_MMDC
>  	bool
>  
> +config HAVE_IMX_MU
> +	bool
> +
> +config HAVE_IMX_RPMSG
> +	bool
> +
>  config HAVE_IMX_SRC
>  	def_bool y if SMP
>  	select ARCH_HAS_RESET_CONTROLLER
> @@ -544,6 +550,9 @@ config SOC_IMX6SX
>  	bool "i.MX6 SoloX support"
>  	select PINCTRL_IMX6SX
>  	select SOC_IMX6
> +	select HAVE_IMX_MU
> +	select HAVE_IMX_RPMSG
> +	select RPMSG
>  
>  	help
>  	  This enables support for Freescale i.MX6 SoloX processor.
> @@ -562,6 +571,9 @@ config SOC_IMX7D
>  	select ARM_GIC
>  	select HAVE_IMX_ANATOP
>  	select HAVE_IMX_MMDC
> +	select HAVE_IMX_MU
> +	select HAVE_IMX_RPMSG
> +	select RPMSG
>  	help
>  		This enables support for Freescale i.MX7 Dual processor.
>  
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile 
> index fb689d8..a3c1814 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -74,7 +74,9 @@ obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o
>  obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
>  obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
>  obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
> +obj-$(CONFIG_HAVE_IMX_MU) += mu.o
>  obj-$(CONFIG_HAVE_IMX_SRC) += src.o
> +obj-$(CONFIG_HAVE_IMX_RPMSG) += imx_rpmsg.o
>  ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
>  AFLAGS_headsmp.o :=-Wa,-march=armv7-a
>  obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git 
> a/arch/arm/mach-imx/imx_rpmsg.c b/arch/arm/mach-imx/imx_rpmsg.c new 
> file mode 100644 index 0000000..ab6ba7a
> --- /dev/null
> +++ b/arch/arm/mach-imx/imx_rpmsg.c
> @@ -0,0 +1,364 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + *
> + * derived from the omap-rpmsg implementation.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/notifier.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/rpmsg.h>
> +#include <linux/slab.h>
> +#include <linux/virtio.h>
> +#include <linux/virtio_config.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_ring.h>
> +#include <linux/imx_rpmsg.h>
> +
> +struct imx_rpmsg_vproc {
> +	struct virtio_device vdev;
> +	unsigned int vring[2];
> +	char *rproc_name;
> +	struct mutex lock;
> +	struct notifier_block nb;
> +	struct virtqueue *vq[2];
> +	int base_vq_id;
> +	int num_of_vqs;
> +};
> +
> +/*
> + * For now, allocate 256 buffers of 512 bytes for each side. each 
> +buffer
> + * will then have 16B for the msg header and 496B for the payload.
> + * This will require a total space of 256KB for the buffers 
> +themselves, and
> + * 3 pages for every vring (the size of the vring depends on the 
> +number of
> + * buffers it supports).
> + */
> +#define RPMSG_NUM_BUFS		(512)
> +#define RPMSG_BUF_SIZE		(512)
> +#define RPMSG_BUFS_SPACE	(RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
> +
> +/*
> + * The alignment between the consumer and producer parts of the vring.
> + * Note: this is part of the "wire" protocol. If you change this, you 
> +need
> + * to update your BIOS image as well
> + */
> +#define RPMSG_VRING_ALIGN	(4096)
> +
> +/* With 256 buffers, our vring will occupy 3 pages */
> +#define RPMSG_RING_SIZE	((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
> +				RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
> +
> +#define to_imx_rpdev(vd) container_of(vd, struct imx_rpmsg_vproc, 
> +vdev)
> +
> +struct imx_rpmsg_vq_info {
> +	__u16 num;	/* number of entries in the virtio_ring */
> +	__u16 vq_id;	/* a globaly unique index of this virtqueue */
> +	void *addr;	/* address where we mapped the virtio ring */
> +	struct imx_rpmsg_vproc *rpdev;
> +};
> +
> +static u64 imx_rpmsg_get_features(struct virtio_device *vdev) {
> +	return 1 << VIRTIO_RPMSG_F_NS;
> +}
> +
> +static int imx_rpmsg_finalize_features(struct virtio_device *vdev) {
> +	/* Give virtio_ring a chance to accept features */
> +	vring_transport_features(vdev);
> +	return 0;
> +}
> +
> +/* kick the remote processor, and let it know which virtqueue to poke 
> +at */ static bool imx_rpmsg_notify(struct virtqueue *vq) {
> +	int ret;
> +	unsigned int mu_rpmsg = 0;
> +	struct imx_rpmsg_vq_info *rpvq = vq->priv;
> +
> +	mu_rpmsg = rpvq->vq_id << 16;
> +	mutex_lock(&rpvq->rpdev->lock);
> +	/* send the index of the triggered virtqueue as the mu payload */
> +	ret = imx_mu_rpmsg_send(mu_rpmsg);
> +	mutex_unlock(&rpvq->rpdev->lock);
> +	if (ret) {
> +		pr_err("ugh, imx_mu_rpmsg_send() failed: %d\n", ret);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static int imx_mu_rpmsg_callback(struct notifier_block *this,
> +					unsigned long index, void *data) {
> +	u32 mu_msg = (u32) data;
> +	struct imx_rpmsg_vproc *rpdev;
> +
> +	rpdev = container_of(this, struct imx_rpmsg_vproc, nb);
> +
> +	pr_debug("%s mu_msg: 0x%x\n", __func__, mu_msg);
> +
> +	/* ignore vq indices which are clearly not for us */
> +	mu_msg = mu_msg >> 16;
> +	if (mu_msg < rpdev->base_vq_id)
> +		pr_err("mu_msg: 0x%x is invalid\n", mu_msg);
> +
> +	mu_msg -= rpdev->base_vq_id;
> +
> +	/*
> +	 * Currently both PENDING_MSG and explicit-virtqueue-index
> +	 * messaging are supported.
> +	 * Whatever approach is taken, at this point 'mu_msg' contains
> +	 * the index of the vring which was just triggered.
> +	 */
> +	if (mu_msg < rpdev->num_of_vqs)
> +		vring_interrupt(mu_msg, rpdev->vq[mu_msg]);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
> +				    unsigned index,
> +				    void (*callback)(struct virtqueue *vq),
> +				    const char *name)
> +{
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +	struct imx_rpmsg_vq_info *rpvq;
> +	struct virtqueue *vq;
> +	int err;
> +
> +	rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
> +	if (!rpvq)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* ioremap'ing normal memory, so we cast away sparse's complaints */
> +	rpvq->addr = (__force void *) ioremap_nocache(rpdev->vring[index],
> +							RPMSG_RING_SIZE);
> +	if (!rpvq->addr) {
> +		err = -ENOMEM;
> +		goto free_rpvq;
> +	}
> +
> +	memset(rpvq->addr, 0, RPMSG_RING_SIZE);
> +
> +	pr_debug("vring%d: phys 0x%x, virt 0x%x\n", index, rpdev->vring[index],
> +					(unsigned int) rpvq->addr);
> +
> +	vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN,
> +			vdev, true, rpvq->addr, imx_rpmsg_notify, callback,
> +			name);
> +	if (!vq) {
> +		pr_err("vring_new_virtqueue failed\n");
> +		err = -ENOMEM;
> +		goto unmap_vring;
> +	}
> +
> +	rpdev->vq[index] = vq;
> +	vq->priv = rpvq;
> +	/* system-wide unique id for this virtqueue */
> +	rpvq->vq_id = rpdev->base_vq_id + index;
> +	rpvq->rpdev = rpdev;
> +	mutex_init(&rpdev->lock);
> +
> +	return vq;
> +
> +unmap_vring:
> +	/* iounmap normal memory, so make sparse happy */
> +	iounmap((__force void __iomem *) rpvq->addr);
> +free_rpvq:
> +	kfree(rpvq);
> +	return ERR_PTR(err);
> +}
> +
> +static void imx_rpmsg_del_vqs(struct virtio_device *vdev) {
> +	struct virtqueue *vq, *n;
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +
> +	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
> +		struct imx_rpmsg_vq_info *rpvq = vq->priv;
> +
> +		iounmap(rpvq->addr);
> +		vring_del_virtqueue(vq);
> +		kfree(rpvq);
> +	}
> +
> +	if (&rpdev->nb)
> +		imx_mu_rpmsg_unregister_nb((const char *)rpdev->rproc_name,
> +				&rpdev->nb);
> +}
> +
> +static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> +		       struct virtqueue *vqs[],
> +		       vq_callback_t *callbacks[],
> +		       const char *names[])
> +{
> +	struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(vdev);
> +	int i, err;
> +
> +	/* we maintain two virtqueues per remote processor (for RX and TX) */
> +	if (nvqs != 2)
> +		return -EINVAL;
> +
> +	for (i = 0; i < nvqs; ++i) {
> +		vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
> +		if (IS_ERR(vqs[i])) {
> +			err = PTR_ERR(vqs[i]);
> +			goto error;
> +		}
> +	}
> +
> +	rpdev->num_of_vqs = nvqs;
> +
> +	rpdev->nb.notifier_call = imx_mu_rpmsg_callback;
> +	imx_mu_rpmsg_register_nb((const char *)rpdev->rproc_name, 
> +&rpdev->nb);
> +
> +	return 0;
> +
> +error:
> +	imx_rpmsg_del_vqs(vdev);
> +	return err;
> +}
> +
> +static void imx_rpmsg_reset(struct virtio_device *vdev) {
> +	dev_dbg(&vdev->dev, "reset !\n");
> +}
> +
> +static u8 imx_rpmsg_get_status(struct virtio_device *vdev) {
> +	return 0;
> +}
> +
> +static void imx_rpmsg_set_status(struct virtio_device *vdev, u8 
> +status) {
> +	dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status); }
> +
> +static void imx_rpmsg_vproc_release(struct device *dev) {
> +	/* this handler is provided so driver core doesn't yell at us */ }
> +
> +static struct virtio_config_ops imx_rpmsg_config_ops = {
> +	.get_features	= imx_rpmsg_get_features,
> +	.finalize_features = imx_rpmsg_finalize_features,
> +	.find_vqs	= imx_rpmsg_find_vqs,
> +	.del_vqs	= imx_rpmsg_del_vqs,
> +	.reset		= imx_rpmsg_reset,
> +	.set_status	= imx_rpmsg_set_status,
> +	.get_status	= imx_rpmsg_get_status,
> +};
> +
> +static struct imx_rpmsg_vproc imx_rpmsg_vprocs[] = {
> +	{
> +		.vdev.id.device	= VIRTIO_ID_RPMSG,
> +		.vdev.config	= &imx_rpmsg_config_ops,
> +		.rproc_name	= "m4",
> +		.base_vq_id	= 0,
> +	},
> +};
> +
> +static const struct of_device_id imx_rpmsg_dt_ids[] = {
> +	{ .compatible = "fsl,imx6sx-rpmsg", },
> +	{ .compatible = "fsl,imx7d-rpmsg", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx_rpmsg_dt_ids);
> +
> +static int imx_rpmsg_probe(struct platform_device *pdev) {
> +	int i, ret = 0;
> +	struct device_node *np = pdev->dev.of_node;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
> +		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
> +
> +		if (!strcmp(rpdev->rproc_name, "m4")) {
> +			ret = of_device_is_compatible(np, "fsl,imx7d-rpmsg");
> +			ret |= of_device_is_compatible(np, "fsl,imx6sx-rpmsg");
> +			if (ret) {
> +				/* hardcodes here now. */
> +				rpdev->vring[0] = 0xBFFF0000;
> +				rpdev->vring[1] = 0xBFFF8000;
> +			}
> +		} else {
> +			break;
> +		}
> +
> +		pr_debug("%s rpdev%d: vring0 0x%x, vring1 0x%x\n", __func__,
> +				i, rpdev->vring[0], rpdev->vring[1]);
> +
> +		rpdev->vdev.dev.parent = &pdev->dev;
> +		rpdev->vdev.dev.release = imx_rpmsg_vproc_release;
> +
> +		ret = register_virtio_device(&rpdev->vdev);
> +		if (ret) {
> +			pr_err("%s failed to register rpdev: %d\n",
> +					__func__, ret);
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int imx_rpmsg_remove(struct platform_device *pdev) {
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx_rpmsg_vprocs); i++) {
> +		struct imx_rpmsg_vproc *rpdev = &imx_rpmsg_vprocs[i];
> +
> +		unregister_virtio_device(&rpdev->vdev);
> +	}
> +	return 0;
> +}
> +
> +static struct platform_driver imx_rpmsg_driver = {
> +	.driver = {
> +		   .owner = THIS_MODULE,
> +		   .name = "imx-rpmsg",
> +		   .of_match_table = imx_rpmsg_dt_ids,
> +		   },
> +	.probe = imx_rpmsg_probe,
> +	.remove = imx_rpmsg_remove,
> +};
> +
> +static int __init imx_rpmsg_init(void) {
> +	int ret;
> +
> +	ret = platform_driver_register(&imx_rpmsg_driver);
> +	if (ret)
> +		pr_err("Unable to initialize rpmsg driver\n");
> +	else
> +		pr_info("imx rpmsg driver is registered.\n");
> +
> +	return ret;
> +}
> +
> +static void __exit imx_rpmsg_exit(void) {
> +	pr_info("imx rpmsg driver is unregistered.\n");
> +	platform_driver_unregister(&imx_rpmsg_driver);
> +}
> +
> +module_exit(imx_rpmsg_exit);
> +module_init(imx_rpmsg_init);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc."); 
> +MODULE_DESCRIPTION("iMX remote processor messaging virtio device"); 
> +MODULE_LICENSE("GPL v2");
> diff --git a/arch/arm/mach-imx/mu.c b/arch/arm/mach-imx/mu.c new file 
> mode 100644 index 0000000..7b07f48
> --- /dev/null
> +++ b/arch/arm/mach-imx/mu.c
> @@ -0,0 +1,217 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/notifier.h>
> +#include <linux/platform_device.h>
> +#include "common.h"
> +#include "hardware.h"
> +
> +#define MU_ATR0_OFFSET	0x0
> +#define MU_ARR0_OFFSET	0x10
> +#define MU_ARR1_OFFSET	0x14
> +#define MU_ASR		0x20
> +#define MU_ACR		0x24
> +
> +#define MU_RPMSG_HANDSHAKE_INDEX	1
> +
> +struct imx_mu_rpmsg_box {
> +	const char *name;
> +	struct blocking_notifier_head notifier; };
> +
> +static struct imx_mu_rpmsg_box mu_rpmsg_box = {
> +	.name	= "m4",
> +};
> +
> +static void __iomem *mu_base;
> +static u32 m4_message;
> +static struct delayed_work rpmsg_work;
> +
> +static int imx_mu_send_message(unsigned int index, unsigned int data) 
> +{
> +	u32 val, ep;
> +	int i, te_flag = 0;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(500);
> +
> +	/* wait for transfer buffer empty, and no event pending */
> +	do {
> +		val = readl_relaxed(mu_base + MU_ASR);
> +		ep = val & BIT(4);
> +		if (time_after(jiffies, timeout)) {
> +			pr_err("Waiting MU transmit buffer empty timeout!\n");
> +			return -EIO;
> +		}
> +	} while (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4)));
> +
> +	writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET);
> +
> +	/*
> +	 * make a double check that TEn is not empty after write
> +	 */
> +	val = readl_relaxed(mu_base + MU_ASR);
> +	ep = val & BIT(4);
> +	if (((val & (1 << (20 + (3 - index)))) == 0) || (ep == BIT(4)))
> +		return 0;
> +
> +	/*
> +	 * Make sure that TEn flag is changed, after the ATRn is filled up.
> +	 */
> +	for (i = 0; i < 100; i++) {
> +		val = readl_relaxed(mu_base + MU_ASR);
> +		ep = val & BIT(4);
> +		if (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))) {
> +			te_flag = 0;
> +			break;
> +		} else if (time_after(jiffies, timeout)) {
> +			/* Can't see TEn 1->0, maybe already handled! */
> +			te_flag = 1;
> +			break;
> +		}
> +	}
> +	if (te_flag == 0)
> +		pr_info("TEn isn't changed when ATRn is filled up.\n");
> +
> +	return 0;
> +}
> +
> +int imx_mu_rpmsg_send(unsigned int rpmsg) {
> +	return imx_mu_send_message(MU_RPMSG_HANDSHAKE_INDEX, rpmsg); }
> +
> +int imx_mu_rpmsg_register_nb(const char *name, struct notifier_block 
> +*nb) {
> +	if ((name == NULL) || (nb == NULL))
> +		return -EINVAL;
> +
> +	if (!strcmp(mu_rpmsg_box.name, name))
> +		blocking_notifier_chain_register(&(mu_rpmsg_box.notifier), nb);
> +	else
> +		return -ENOENT;
> +
> +	return 0;
> +}
> +
> +int imx_mu_rpmsg_unregister_nb(const char *name, struct 
> +notifier_block *nb) {
> +	if ((name == NULL) || (nb == NULL))
> +		return -EINVAL;
> +
> +	if (!strcmp(mu_rpmsg_box.name, name))
> +		blocking_notifier_chain_unregister(&(mu_rpmsg_box.notifier),
> +				nb);
> +	else
> +		return -ENOENT;
> +
> +	return 0;
> +}
> +
> +static void rpmsg_work_handler(struct work_struct *work) {
> +
> +	blocking_notifier_call_chain(&(mu_rpmsg_box.notifier), 4,
> +						(void *)m4_message);
> +	m4_message = 0;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *param) {
> +	u32 irqs;
> +
> +	irqs = readl_relaxed(mu_base + MU_ASR);
> +
> +	/* RPMSG */
> +	if (irqs & (1 << 26)) {
> +		/* get message from receive buffer */
> +		m4_message = readl_relaxed(mu_base + MU_ARR1_OFFSET);
> +		schedule_delayed_work(&rpmsg_work, 0);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	int ret;
> +	u32 irq;
> +	struct device_node *np;
> +	struct clk *clk;
> +
> +	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
> +	mu_base = of_iomap(np, 0);
> +	WARN_ON(!mu_base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	ret = request_irq(irq, imx_mu_isr,
> +		IRQF_EARLY_RESUME, "imx-mu", &mu_rpmsg_box);
> +	if (ret) {
> +		pr_err("%s: register interrupt %d failed, rc %d\n",
> +			__func__, irq, ret);
> +		return ret;
> +	}
> +
> +	ret = of_device_is_compatible(np, "fsl,imx7d-mu");
> +	if (ret) {
> +		clk = devm_clk_get(&pdev->dev, "mu");
> +		if (IS_ERR(clk)) {
> +			dev_err(&pdev->dev,
> +				"mu clock source missing or invalid\n");
> +			return PTR_ERR(clk);
> +		}
> +
> +		ret = clk_prepare_enable(clk);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"unable to enable mu clock\n");
> +			return ret;
> +		}
> +	}
> +
> +	INIT_DELAYED_WORK(&rpmsg_work, rpmsg_work_handler);
> +	/* enable the bit26(RIE1) of MU_ACR */
> +	writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(26),
> +			mu_base + MU_ACR);
> +	BLOCKING_INIT_NOTIFIER_HEAD(&(mu_rpmsg_box.notifier));
> +
> +	pr_info("MU is ready for cross core communication!\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id imx_mu_ids[] = {
> +	{ .compatible = "fsl,imx6sx-mu" },
> +	{ .compatible = "fsl,imx7d-mu" },
> +	{ }
> +};
> +
> +static struct platform_driver imx_mu_driver = {
> +	.driver = {
> +		.name   = "imx-mu",
> +		.owner  = THIS_MODULE,
> +		.of_match_table = imx_mu_ids,
> +	},
> +	.probe = imx_mu_probe,
> +};
> +
> +static int __init imx_mu_init(void)
> +{
> +	return platform_driver_register(&imx_mu_driver);
> +}
> +subsys_initcall(imx_mu_init);
> diff --git a/include/linux/imx_rpmsg.h b/include/linux/imx_rpmsg.h new 
> file mode 100644 index 0000000..2b0dca5
> --- /dev/null
> +++ b/include/linux/imx_rpmsg.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU Lesser General
> + * Public License.  You may obtain a copy of the GNU Lesser General
> + * Public License Version 2.1 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/lgpl-license.html
> + * http://www.gnu.org/copyleft/lgpl.html
> + */
> +
> +/*
> + * @file linux/imx_rpmsg.h
> + *
> + * @brief Global header file for imx RPMSG
> + *
> + * @ingroup RPMSG
> + */
> +#ifndef __LINUX_IMX_RPMSG_H__
> +#define __LINUX_IMX_RPMSG_H__
> +
> +int imx_mu_rpmsg_send(unsigned int vq_id); int 
> +imx_mu_rpmsg_register_nb(const char *name, struct notifier_block 
> +*nb); int imx_mu_rpmsg_unregister_nb(const char *name, struct 
> +notifier_block *nb); #endif /* __LINUX_IMX_RPMSG_H__ */
> --
> 1.9.1
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-28  2:17     ` Richard Zhu
@ 2016-01-28  5:50       ` Shawn Guo
  2016-01-28  6:33         ` Richard Zhu
  2016-02-15  6:10         ` Shawn Guo
  1 sibling, 1 reply; 13+ messages in thread
From: Shawn Guo @ 2016-01-28  5:50 UTC (permalink / raw)
  To: Richard Zhu; +Cc: ohad, Stefan Agner, linux-kernel

On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> >  arch/arm/mach-imx/Kconfig     |  12 ++
> >  arch/arm/mach-imx/Makefile    |   2 +
> >  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
> >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> 
> I'm not rpmsg expert, but it seems to me that the driver should be put into drivers/rpmsg/ rather than mach-imx.
> [Richard] This part rpmsg codes are closed related to the platform. For example, kinds of ops callback functions.
> Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does to omap rpmsg implementation.
> http://omappedia.org/wiki/RPMsg_Kernel_Sources

Okay, I will find some time slot to get myself familiar with rpmsg
subsystem and then review the patch.

Shawn

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-28  5:50       ` Shawn Guo
@ 2016-01-28  6:33         ` Richard Zhu
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-01-28  6:33 UTC (permalink / raw)
  To: Shawn Guo; +Cc: ohad, Stefan Agner, linux-kernel

Thanks a lot.

Best Regards
hongxing zhu
Linux BSP team
Office: 86-21-28937189
Email: hongxing.zhu@nxp.com


-----Original Message-----
From: Shawn Guo [mailto:shawnguo@kernel.org] 
Sent: Thursday, January 28, 2016 1:50 PM
To: Richard Zhu
Cc: ohad@wizery.com; Stefan Agner; linux-kernel@vger.kernel.org
Subject: Re: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation

On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> >  arch/arm/mach-imx/Kconfig     |  12 ++
> >  arch/arm/mach-imx/Makefile    |   2 +
> >  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
> >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> 
> I'm not rpmsg expert, but it seems to me that the driver should be put into drivers/rpmsg/ rather than mach-imx.
> [Richard] This part rpmsg codes are closed related to the platform. For example, kinds of ops callback functions.
> Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does to omap rpmsg implementation.
> http://omappedia.org/wiki/RPMsg_Kernel_Sources

Okay, I will find some time slot to get myself familiar with rpmsg subsystem and then review the patch.

Shawn

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-01-28  2:17     ` Richard Zhu
@ 2016-02-15  6:10         ` Shawn Guo
  2016-02-15  6:10         ` Shawn Guo
  1 sibling, 0 replies; 13+ messages in thread
From: Shawn Guo @ 2016-02-15  6:10 UTC (permalink / raw)
  To: Richard Zhu; +Cc: ohad, Stefan Agner, linux-kernel, linux-arm-kernel

+LAKML

On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> Hi Shawn:
> Thanks for your comments.
> Further review would copied to Stefan Agner.

Please do not top-posting.

> On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> > From: Richard Zhu <Richard.Zhu@freescale.com>
> > 
> > - add mu driver support, the irq and 4bytes msg of the mu module are 
> > as the interaction channel between A# core and the M4 core on imx amp 
> > platforms.
> > - register one notify in isr of the mu's irq used by rpmsg.
> > - instance the virtual processor, and fill up the virtio_config_ops in 
> > the platform related rpmsg implementation codes.
> > - hard-code the vring storage shared by A# core and M# core on AMP 
> > SOCs.
> > 
> > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > ---
> >  arch/arm/mach-imx/Kconfig     |  12 ++
> >  arch/arm/mach-imx/Makefile    |   2 +
> >  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
> >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> 
> I'm not rpmsg expert, but it seems to me that the driver should be put into drivers/rpmsg/ rather than mach-imx.
> [Richard] This part rpmsg codes are closed related to the platform. For example, kinds of ops callback functions.
> Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does to omap rpmsg implementation.
> http://omappedia.org/wiki/RPMsg_Kernel_Sources

I just took a closer look at this.  What the omappedia page above
describes is an OMAP rpmsg implementation in a vendor tree which is
in turn based on a relatively old kernel version, i.e. v3.0.

I guess the implementation is a base of what mainline has today on
remoteproc/rpmsg support, but they are somehow different.  For example,
on mainline kernel today, there is no remoteproc/rpmsg code in
arch/arm/plat-omap.  And, instead of handling rpmsg with a platform
specific driver, remoteproc encapsulates the rpmsg support.  You can
find the details in commit ac8954a41393 (remoteproc: create rpmsg virtio
device).

I suggest you look at the mainline code today instead of any old
implementation for reference.  And in any case, with device tree
support to populate platform device as needed, it's a wrong to put
remoteproc/rpmsg related driver code into arch/arm/mach-imx.

Shawn

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
@ 2016-02-15  6:10         ` Shawn Guo
  0 siblings, 0 replies; 13+ messages in thread
From: Shawn Guo @ 2016-02-15  6:10 UTC (permalink / raw)
  To: linux-arm-kernel

+LAKML

On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> Hi Shawn:
> Thanks for your comments.
> Further review would copied to Stefan Agner.

Please do not top-posting.

> On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> > From: Richard Zhu <Richard.Zhu@freescale.com>
> > 
> > - add mu driver support, the irq and 4bytes msg of the mu module are 
> > as the interaction channel between A# core and the M4 core on imx amp 
> > platforms.
> > - register one notify in isr of the mu's irq used by rpmsg.
> > - instance the virtual processor, and fill up the virtio_config_ops in 
> > the platform related rpmsg implementation codes.
> > - hard-code the vring storage shared by A# core and M# core on AMP 
> > SOCs.
> > 
> > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > ---
> >  arch/arm/mach-imx/Kconfig     |  12 ++
> >  arch/arm/mach-imx/Makefile    |   2 +
> >  arch/arm/mach-imx/imx_rpmsg.c | 364 ++++++++++++++++++++++++++++++++++++++++++
> >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> 
> I'm not rpmsg expert, but it seems to me that the driver should be put into drivers/rpmsg/ rather than mach-imx.
> [Richard] This part rpmsg codes are closed related to the platform. For example, kinds of ops callback functions.
> Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does to omap rpmsg implementation.
> http://omappedia.org/wiki/RPMsg_Kernel_Sources

I just took a closer look at this.  What the omappedia page above
describes is an OMAP rpmsg implementation in a vendor tree which is
in turn based on a relatively old kernel version, i.e. v3.0.

I guess the implementation is a base of what mainline has today on
remoteproc/rpmsg support, but they are somehow different.  For example,
on mainline kernel today, there is no remoteproc/rpmsg code in
arch/arm/plat-omap.  And, instead of handling rpmsg with a platform
specific driver, remoteproc encapsulates the rpmsg support.  You can
find the details in commit ac8954a41393 (remoteproc: create rpmsg virtio
device).

I suggest you look at the mainline code today instead of any old
implementation for reference.  And in any case, with device tree
support to populate platform device as needed, it's a wrong to put
remoteproc/rpmsg related driver code into arch/arm/mach-imx.

Shawn

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
  2016-02-15  6:10         ` Shawn Guo
@ 2016-02-15  6:44           ` Richard Zhu
  -1 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-02-15  6:44 UTC (permalink / raw)
  To: Shawn Guo; +Cc: ohad, Stefan Agner, linux-kernel, linux-arm-kernel


> -----Original Message-----
> From: Shawn Guo [mailto:shawnguo@kernel.org]
> Sent: Monday, February 15, 2016 2:10 PM
> To: Richard Zhu
> Cc: ohad@wizery.com; Stefan Agner; linux-kernel@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [RFC 3/4] ARM: imx: add the platform related rpmsg
> implementation
> 
> +LAKML
> 
> On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> > Hi Shawn:
> > Thanks for your comments.
> > Further review would copied to Stefan Agner.
> 
> Please do not top-posting.
> 
> > On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> > > From: Richard Zhu <Richard.Zhu@freescale.com>
> > >
> > > - add mu driver support, the irq and 4bytes msg of the mu module are
> > > as the interaction channel between A# core and the M4 core on imx
> > > amp platforms.
> > > - register one notify in isr of the mu's irq used by rpmsg.
> > > - instance the virtual processor, and fill up the virtio_config_ops
> > > in the platform related rpmsg implementation codes.
> > > - hard-code the vring storage shared by A# core and M# core on AMP
> > > SOCs.
> > >
> > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > > ---
> > >  arch/arm/mach-imx/Kconfig     |  12 ++
> > >  arch/arm/mach-imx/Makefile    |   2 +
> > >  arch/arm/mach-imx/imx_rpmsg.c | 364
> ++++++++++++++++++++++++++++++++++++++++++
> > >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> >
> > I'm not rpmsg expert, but it seems to me that the driver should be put into
> drivers/rpmsg/ rather than mach-imx.
> > [Richard] This part rpmsg codes are closed related to the platform. For
> example, kinds of ops callback functions.
> > Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does
> to omap rpmsg implementation.
> > http://omappedia.org/wiki/RPMsg_Kernel_Sources
> 
> I just took a closer look at this.  What the omappedia page above describes is
> an OMAP rpmsg implementation in a vendor tree which is in turn based on a
> relatively old kernel version, i.e. v3.0.
> 
> I guess the implementation is a base of what mainline has today on
> remoteproc/rpmsg support, but they are somehow different.  For example, on
> mainline kernel today, there is no remoteproc/rpmsg code in arch/arm/plat-
> omap.  And, instead of handling rpmsg with a platform specific driver,
> remoteproc encapsulates the rpmsg support.  You can find the details in
> commit ac8954a41393 (remoteproc: create rpmsg virtio device).
> 
> I suggest you look at the mainline code today instead of any old
> implementation for reference.  And in any case, with device tree support to
> populate platform device as needed, it's a wrong to put remoteproc/rpmsg
> related driver code into arch/arm/mach-imx.
> 
> Shawn
[Zhu hongxing]  Thanks a lot for your advice. I would take look into it, and re-organize my
patch-set.

Best Regards
hongxing zhu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC 3/4] ARM: imx: add the platform related rpmsg implementation
@ 2016-02-15  6:44           ` Richard Zhu
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Zhu @ 2016-02-15  6:44 UTC (permalink / raw)
  To: linux-arm-kernel


> -----Original Message-----
> From: Shawn Guo [mailto:shawnguo at kernel.org]
> Sent: Monday, February 15, 2016 2:10 PM
> To: Richard Zhu
> Cc: ohad at wizery.com; Stefan Agner; linux-kernel at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org
> Subject: Re: [RFC 3/4] ARM: imx: add the platform related rpmsg
> implementation
> 
> +LAKML
> 
> On Thu, Jan 28, 2016 at 02:17:21AM +0000, Richard Zhu wrote:
> > Hi Shawn:
> > Thanks for your comments.
> > Further review would copied to Stefan Agner.
> 
> Please do not top-posting.
> 
> > On Wed, Jan 06, 2016 at 04:06:43PM +0800, Richard Zhu wrote:
> > > From: Richard Zhu <Richard.Zhu@freescale.com>
> > >
> > > - add mu driver support, the irq and 4bytes msg of the mu module are
> > > as the interaction channel between A# core and the M4 core on imx
> > > amp platforms.
> > > - register one notify in isr of the mu's irq used by rpmsg.
> > > - instance the virtual processor, and fill up the virtio_config_ops
> > > in the platform related rpmsg implementation codes.
> > > - hard-code the vring storage shared by A# core and M# core on AMP
> > > SOCs.
> > >
> > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > > ---
> > >  arch/arm/mach-imx/Kconfig     |  12 ++
> > >  arch/arm/mach-imx/Makefile    |   2 +
> > >  arch/arm/mach-imx/imx_rpmsg.c | 364
> ++++++++++++++++++++++++++++++++++++++++++
> > >  arch/arm/mach-imx/mu.c        | 217 +++++++++++++++++++++++++
> >
> > I'm not rpmsg expert, but it seems to me that the driver should be put into
> drivers/rpmsg/ rather than mach-imx.
> > [Richard] This part rpmsg codes are closed related to the platform. For
> example, kinds of ops callback functions.
> > Thus, these codes are placed into arch/arm/mach-imx/ folder. BTW,  so does
> to omap rpmsg implementation.
> > http://omappedia.org/wiki/RPMsg_Kernel_Sources
> 
> I just took a closer look at this.  What the omappedia page above describes is
> an OMAP rpmsg implementation in a vendor tree which is in turn based on a
> relatively old kernel version, i.e. v3.0.
> 
> I guess the implementation is a base of what mainline has today on
> remoteproc/rpmsg support, but they are somehow different.  For example, on
> mainline kernel today, there is no remoteproc/rpmsg code in arch/arm/plat-
> omap.  And, instead of handling rpmsg with a platform specific driver,
> remoteproc encapsulates the rpmsg support.  You can find the details in
> commit ac8954a41393 (remoteproc: create rpmsg virtio device).
> 
> I suggest you look at the mainline code today instead of any old
> implementation for reference.  And in any case, with device tree support to
> populate platform device as needed, it's a wrong to put remoteproc/rpmsg
> related driver code into arch/arm/mach-imx.
> 
> Shawn
[Zhu hongxing]  Thanks a lot for your advice. I would take look into it, and re-organize my
patch-set.

Best Regards
hongxing zhu

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-02-15  6:44 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-06  8:06 [RFC 0/4]Enable rpmsg support on imx amp platforms Richard Zhu
2016-01-06  8:06 ` [RFC 1/4] ARM: imx: enable " Richard Zhu
2016-01-06  8:06 ` [RFC 2/4] clk: imx7d: enable the mu and m4 root clocks Richard Zhu
2016-01-06  8:06 ` [RFC 3/4] ARM: imx: add the platform related rpmsg implementation Richard Zhu
2016-01-28  1:35   ` Shawn Guo
2016-01-28  2:17     ` Richard Zhu
2016-01-28  5:50       ` Shawn Guo
2016-01-28  6:33         ` Richard Zhu
2016-02-15  6:10       ` Shawn Guo
2016-02-15  6:10         ` Shawn Guo
2016-02-15  6:44         ` Richard Zhu
2016-02-15  6:44           ` Richard Zhu
2016-01-06  8:06 ` [RFC 4/4] samples/rpmsg: add the imx pingpong rpmsg sample Richard Zhu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.