All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] add mailbox support for i.MX7D
@ 2018-06-15  9:51 ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

20180615 changes v2:
- DT: use mailbox@ instead of mu@
- DT: change interrupts description
- clk: use imx_clk_gate4 instead of imx_clk_gate2
- imx-mailbox: remove last_tx_done support
- imx-mailbox: fix module description 

This patches are providing support for mailbox (Messaging Unit)
for i.MX7D.
Functionality was tested on PHYTEC phyBOARD-Zeta i.MX7D with
Linux running on all cores: ARM Cortex-A7 and ARM Cortex-M4.

Both parts of i.MX messaging Unit are visible for all CPUs available
on i.MX7D. Communication worked independent of MU side in combination
with CPU. For example MU-A used on ARM Cortex-A7 and MU-B used on ARM Cortex-M4
or other ways around.

The question to NXP developers: are there are limitations or
recommendations about MU vs CPU combination? The i.MX7D documentation
talks about "Processor A" and "Processor B". It is not quite clear what
processor it actually is (A7 or M4).

Oleksij Rempel (4):
  clk: imx7d: add IMX7D_MU_ROOT_CLK
  dt-bindings: mailbox: provide imx-mailbox documentation
  ARM: dts: imx7s: add i.MX7 messaging unit support
  mailbox: Add support for i.MX7D messaging unit

 .../bindings/mailbox/imx-mailbox.txt          |  35 +++
 arch/arm/boot/dts/imx7s.dtsi                  |  18 ++
 drivers/clk/imx/clk-imx7d.c                   |   1 +
 drivers/mailbox/Kconfig                       |   6 +
 drivers/mailbox/Makefile                      |   2 +
 drivers/mailbox/imx-mailbox.c                 | 288 ++++++++++++++++++
 6 files changed, 350 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
 create mode 100644 drivers/mailbox/imx-mailbox.c

-- 
2.17.1

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

* [PATCH v2 0/4] add mailbox support for i.MX7D
@ 2018-06-15  9:51 ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

20180615 changes v2:
- DT: use mailbox@ instead of mu@
- DT: change interrupts description
- clk: use imx_clk_gate4 instead of imx_clk_gate2
- imx-mailbox: remove last_tx_done support
- imx-mailbox: fix module description 

This patches are providing support for mailbox (Messaging Unit)
for i.MX7D.
Functionality was tested on PHYTEC phyBOARD-Zeta i.MX7D with
Linux running on all cores: ARM Cortex-A7 and ARM Cortex-M4.

Both parts of i.MX messaging Unit are visible for all CPUs available
on i.MX7D. Communication worked independent of MU side in combination
with CPU. For example MU-A used on ARM Cortex-A7 and MU-B used on ARM Cortex-M4
or other ways around.

The question to NXP developers: are there are limitations or
recommendations about MU vs CPU combination? The i.MX7D documentation
talks about "Processor A" and "Processor B". It is not quite clear what
processor it actually is (A7 or M4).

Oleksij Rempel (4):
  clk: imx7d: add IMX7D_MU_ROOT_CLK
  dt-bindings: mailbox: provide imx-mailbox documentation
  ARM: dts: imx7s: add i.MX7 messaging unit support
  mailbox: Add support for i.MX7D messaging unit

 .../bindings/mailbox/imx-mailbox.txt          |  35 +++
 arch/arm/boot/dts/imx7s.dtsi                  |  18 ++
 drivers/clk/imx/clk-imx7d.c                   |   1 +
 drivers/mailbox/Kconfig                       |   6 +
 drivers/mailbox/Makefile                      |   2 +
 drivers/mailbox/imx-mailbox.c                 | 288 ++++++++++++++++++
 6 files changed, 350 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
 create mode 100644 drivers/mailbox/imx-mailbox.c

-- 
2.17.1


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

* [PATCH v2 0/4] add mailbox support for i.MX7D
@ 2018-06-15  9:51 ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

20180615 changes v2:
- DT: use mailbox@ instead of mu@
- DT: change interrupts description
- clk: use imx_clk_gate4 instead of imx_clk_gate2
- imx-mailbox: remove last_tx_done support
- imx-mailbox: fix module description 

This patches are providing support for mailbox (Messaging Unit)
for i.MX7D.
Functionality was tested on PHYTEC phyBOARD-Zeta i.MX7D with
Linux running on all cores: ARM Cortex-A7 and ARM Cortex-M4.

Both parts of i.MX messaging Unit are visible for all CPUs available
on i.MX7D. Communication worked independent of MU side in combination
with CPU. For example MU-A used on ARM Cortex-A7 and MU-B used on ARM Cortex-M4
or other ways around.

The question to NXP developers: are there are limitations or
recommendations about MU vs CPU combination? The i.MX7D documentation
talks about "Processor A" and "Processor B". It is not quite clear what
processor it actually is (A7 or M4).

Oleksij Rempel (4):
  clk: imx7d: add IMX7D_MU_ROOT_CLK
  dt-bindings: mailbox: provide imx-mailbox documentation
  ARM: dts: imx7s: add i.MX7 messaging unit support
  mailbox: Add support for i.MX7D messaging unit

 .../bindings/mailbox/imx-mailbox.txt          |  35 +++
 arch/arm/boot/dts/imx7s.dtsi                  |  18 ++
 drivers/clk/imx/clk-imx7d.c                   |   1 +
 drivers/mailbox/Kconfig                       |   6 +
 drivers/mailbox/Makefile                      |   2 +
 drivers/mailbox/imx-mailbox.c                 | 288 ++++++++++++++++++
 6 files changed, 350 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
 create mode 100644 drivers/mailbox/imx-mailbox.c

-- 
2.17.1

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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-06-15  9:51 ` Oleksij Rempel
  (?)
@ 2018-06-15  9:51   ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

This clock is needed for iMX mailbox driver

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/clk/imx/clk-imx7d.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 975a20d3cc94..c7159bfac77a 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
 	clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
 	clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
 	clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
 	clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
 	clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
-- 
2.17.1

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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

This clock is needed for iMX mailbox driver

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/clk/imx/clk-imx7d.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 975a20d3cc94..c7159bfac77a 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
 	clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
 	clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
 	clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
 	clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
 	clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
-- 
2.17.1


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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

This clock is needed for iMX mailbox driver

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/clk/imx/clk-imx7d.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 975a20d3cc94..c7159bfac77a 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
 	clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
 	clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
 	clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
 	clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
 	clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
-- 
2.17.1

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

* [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
  2018-06-15  9:51 ` Oleksij Rempel
  (?)
@ 2018-06-15  9:51   ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
new file mode 100644
index 000000000000..1577b86f1206
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
@@ -0,0 +1,35 @@
+i.MX Messaging Unit
+===================
+
+The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
+cases they are accessible from all Processor Units. On one hand, at least for
+mailbox functionality, it makes no difference which application or processor is
+using which set of the MU. On other hand, the register sets for each of the MU
+parts are not identical.
+
+Required properties:
+- compatible :	Shell be one of:
+                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
+- reg :		physical base address of the mailbox and length of
+		memory mapped region.
+- #mbox-cells:	Common mailbox binding property to identify the number
+		of cells required for the mailbox specifier. Should be 1.
+- interrupts :	The interrupt number
+- clocks     :  phandle to the input clock.
+
+Example:
+	mu0a: mailbox@30aa0000 {
+		compatible = "fsl,imx7s-mu-a";
+		reg = <0x30aa0000 0x28>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
+
+	mu0b: mailbox@30ab0000 {
+		compatible = "fsl,imx7s-mu-b";
+		reg = <0x30ab0000 0x28>;
+		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
-- 
2.17.1

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

* [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
new file mode 100644
index 000000000000..1577b86f1206
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
@@ -0,0 +1,35 @@
+i.MX Messaging Unit
+===================
+
+The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
+cases they are accessible from all Processor Units. On one hand, at least for
+mailbox functionality, it makes no difference which application or processor is
+using which set of the MU. On other hand, the register sets for each of the MU
+parts are not identical.
+
+Required properties:
+- compatible :	Shell be one of:
+                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
+- reg :		physical base address of the mailbox and length of
+		memory mapped region.
+- #mbox-cells:	Common mailbox binding property to identify the number
+		of cells required for the mailbox specifier. Should be 1.
+- interrupts :	The interrupt number
+- clocks     :  phandle to the input clock.
+
+Example:
+	mu0a: mailbox@30aa0000 {
+		compatible = "fsl,imx7s-mu-a";
+		reg = <0x30aa0000 0x28>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
+
+	mu0b: mailbox@30ab0000 {
+		compatible = "fsl,imx7s-mu-b";
+		reg = <0x30ab0000 0x28>;
+		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
-- 
2.17.1


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

* [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
new file mode 100644
index 000000000000..1577b86f1206
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
@@ -0,0 +1,35 @@
+i.MX Messaging Unit
+===================
+
+The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
+cases they are accessible from all Processor Units. On one hand, at least for
+mailbox functionality, it makes no difference which application or processor is
+using which set of the MU. On other hand, the register sets for each of the MU
+parts are not identical.
+
+Required properties:
+- compatible :	Shell be one of:
+                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
+- reg :		physical base address of the mailbox and length of
+		memory mapped region.
+- #mbox-cells:	Common mailbox binding property to identify the number
+		of cells required for the mailbox specifier. Should be 1.
+- interrupts :	The interrupt number
+- clocks     :  phandle to the input clock.
+
+Example:
+	mu0a: mailbox at 30aa0000 {
+		compatible = "fsl,imx7s-mu-a";
+		reg = <0x30aa0000 0x28>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
+
+	mu0b: mailbox at 30ab0000 {
+		compatible = "fsl,imx7s-mu-b";
+		reg = <0x30ab0000 0x28>;
+		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		#mbox-cells = <1>;
+	};
-- 
2.17.1

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

* [PATCH v2 3/4] ARM: dts: imx7s: add i.MX7 messaging unit support
  2018-06-15  9:51 ` Oleksij Rempel
  (?)
@ 2018-06-15  9:51   ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

Define the Messaging Unit (MU) for i.MX7 in the processor's dtsi.
The respective driver is added in the next commit.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/boot/dts/imx7s.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index d9437e773b37..87a82c1f4dfd 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -1008,6 +1008,24 @@
 				status = "disabled";
 			};
 
+			mu0a: mailbox@30aa0000 {
+				compatible = "fsl,imx7s-mu-a";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
+			mu0b: mailbox@30ab0000 {
+				compatible = "fsl,imx7s-mu-b";
+				reg = <0x30ab0000 0x10000>;
+				interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
 			usbotg1: usb@30b10000 {
 				compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
 				reg = <0x30b10000 0x200>;
-- 
2.17.1

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

* [PATCH v2 3/4] ARM: dts: imx7s: add i.MX7 messaging unit support
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

Define the Messaging Unit (MU) for i.MX7 in the processor's dtsi.
The respective driver is added in the next commit.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/boot/dts/imx7s.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index d9437e773b37..87a82c1f4dfd 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -1008,6 +1008,24 @@
 				status = "disabled";
 			};
 
+			mu0a: mailbox@30aa0000 {
+				compatible = "fsl,imx7s-mu-a";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
+			mu0b: mailbox@30ab0000 {
+				compatible = "fsl,imx7s-mu-b";
+				reg = <0x30ab0000 0x10000>;
+				interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
 			usbotg1: usb@30b10000 {
 				compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
 				reg = <0x30b10000 0x200>;
-- 
2.17.1


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

* [PATCH v2 3/4] ARM: dts: imx7s: add i.MX7 messaging unit support
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

Define the Messaging Unit (MU) for i.MX7 in the processor's dtsi.
The respective driver is added in the next commit.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/boot/dts/imx7s.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index d9437e773b37..87a82c1f4dfd 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -1008,6 +1008,24 @@
 				status = "disabled";
 			};
 
+			mu0a: mailbox at 30aa0000 {
+				compatible = "fsl,imx7s-mu-a";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
+			mu0b: mailbox at 30ab0000 {
+				compatible = "fsl,imx7s-mu-b";
+				reg = <0x30ab0000 0x10000>;
+				interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX7D_MU_ROOT_CLK>;
+				#mbox-cells = <1>;
+				status = "disabled";
+			};
+
 			usbotg1: usb at 30b10000 {
 				compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
 				reg = <0x30b10000 0x200>;
-- 
2.17.1

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-15  9:51 ` Oleksij Rempel
  (?)
@ 2018-06-15  9:51   ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

The Mailbox controller is able to send messages (up to 4 32 bit words)
between the endpoints.

This driver was tested using the mailbox-test driver sending messages
between the Cortex-A7 and the Cortex-M4.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/mailbox/Kconfig       |   6 +
 drivers/mailbox/Makefile      |   2 +
 drivers/mailbox/imx-mailbox.c | 288 ++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/mailbox/imx-mailbox.c

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index a2bb27446dce..e1d2738a2e4c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,12 @@ config ARM_MHU
 	  The controller has 3 mailbox channels, the last of which can be
 	  used in Secure mode only.
 
+config IMX_MBOX
+	tristate "iMX Mailbox"
+	depends on SOC_IMX7D || COMPILE_TEST
+	help
+	  Mailbox implementation for iMX7D Messaging Unit (MU).
+
 config PLATFORM_MHU
 	tristate "Platform MHU Mailbox"
 	depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index cc23c3a43fcd..ba2fe1b6dd62 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
 
 obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
 
+obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
+
 obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
 
 obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
new file mode 100644
index 000000000000..e3f621cb1d30
--- /dev/null
+++ b/drivers/mailbox/imx-mailbox.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+/* Transmit Register */
+#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
+/* Receive Register */
+#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
+/* Status Register */
+#define IMX_MU_xSR		0x20
+#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
+#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
+#define IMX_MU_xSR_BRDIP	BIT(9)
+
+/* Control Register */
+#define IMX_MU_xCR		0x24
+/* Transmit Interrupt Enable */
+#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
+/* Receive Interrupt Enable */
+#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
+
+#define IMX_MU_MAX_CHANS	4u
+
+struct imx_mu_priv;
+
+struct imx_mu_cfg {
+	unsigned int		chans;
+	void (*init_hw)(struct imx_mu_priv *priv);
+};
+
+struct imx_mu_con_priv {
+	int			irq;
+	unsigned int		bidx;
+	unsigned int		idx;
+};
+
+struct imx_mu_priv {
+	struct device		*dev;
+	const struct imx_mu_cfg	*dcfg;
+	void __iomem		*base;
+
+	struct mbox_controller	mbox;
+	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
+
+	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
+	struct clk		*clk;
+};
+
+static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
+{
+	return container_of(mbox, struct imx_mu_priv, mbox);
+}
+
+static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
+{
+	iowrite32(val, priv->base + offs);
+}
+
+static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
+{
+	return ioread32(priv->base + offs);
+}
+
+static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32 clr)
+{
+	u32 val;
+
+	val = imx_mu_read(priv, offs);
+	val &= ~clr;
+	val |= set;
+	imx_mu_write(priv, val, offs);
+
+	return val;
+}
+
+static irqreturn_t imx_mu_isr(int irq, void *p)
+{
+	struct mbox_chan *chan = p;
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	u32 val, dat;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
+	if (!val)
+		return IRQ_NONE;
+
+	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
+		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp->bidx));
+		mbox_chan_txdone(chan, 0);
+	}
+
+	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
+		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
+		mbox_chan_received_data(chan, (void *)&dat);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static bool imx_mu_last_tx_done(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 val;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	/* test if transmit register is empty */
+	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
+}
+
+static int imx_mu_send_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 *arg = data;
+
+	if (!imx_mu_last_tx_done(chan))
+		return -EBUSY;
+
+	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static int imx_mu_startup(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	int ret;
+
+	ret = request_irq(cp->irq, imx_mu_isr,
+			  IRQF_SHARED, "imx_mu_chan", chan);
+	if (ret) {
+		dev_err(chan->mbox->dev,
+			"Unable to acquire IRQ %d\n", cp->irq);
+		return ret;
+	}
+
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static void imx_mu_shutdown(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	imx_mu_rmw(priv, IMX_MU_xCR, 0,
+		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp->bidx));
+
+	free_irq(cp->irq, chan);
+}
+
+static const struct mbox_chan_ops imx_mu_ops = {
+	.send_data = imx_mu_send_data,
+	.startup = imx_mu_startup,
+	.shutdown = imx_mu_shutdown,
+};
+
+static int imx_mu_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iomem;
+	struct imx_mu_priv *priv;
+	const struct imx_mu_cfg *dcfg;
+	unsigned int i, chans;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dcfg = of_device_get_match_data(dev);
+	if (!dcfg)
+		return -EINVAL;
+
+	priv->dcfg = dcfg;
+	priv->dev = dev;
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return irq < 0 ? irq : -EINVAL;
+
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		if (PTR_ERR(priv->clk) == -ENOENT) {
+			priv->clk = NULL;
+		} else {
+			dev_err(dev, "Failed to get clock\n");
+			return PTR_ERR(priv->clk);
+		}
+	}
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable clock\n");
+		return ret;
+	}
+
+	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
+	/* Initialize channel identifiers */
+	for (i = 0; i < chans; i++) {
+		struct imx_mu_con_priv *cp = &priv->con_priv[i];
+
+		cp->bidx = 3 - i;
+		cp->idx = i;
+		cp->irq = irq;
+		priv->mbox_chans[i].con_priv = cp;
+	}
+
+	priv->mbox.dev = dev;
+	priv->mbox.ops = &imx_mu_ops;
+	priv->mbox.chans = priv->mbox_chans;
+	priv->mbox.num_chans = chans;
+	priv->mbox.txdone_irq = true;
+
+	platform_set_drvdata(pdev, priv);
+
+	if (priv->dcfg->init_hw)
+		priv->dcfg->init_hw(priv);
+
+	return mbox_controller_register(&priv->mbox);
+}
+
+static int imx_mu_remove(struct platform_device *pdev)
+{
+	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&priv->mbox);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+
+static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv)
+{
+	/* Set default config */
+	imx_mu_write(priv, 0, IMX_MU_xCR);
+}
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
+	.chans = IMX_MU_MAX_CHANS,
+	.init_hw = imx_mu_init_imx7d_a,
+};
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
+	.chans = IMX_MU_MAX_CHANS,
+};
+
+static const struct of_device_id imx_mu_dt_ids[] = {
+	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
+	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
+
+static struct platform_driver imx_mu_driver = {
+	.probe		= imx_mu_probe,
+	.remove		= imx_mu_remove,
+	.driver = {
+		.name	= "imx_mu",
+		.of_match_table = imx_mu_dt_ids,
+	},
+};
+module_platform_driver(imx_mu_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
+MODULE_DESCRIPTION("Message Unit driver for i.MX");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

The Mailbox controller is able to send messages (up to 4 32 bit words)
between the endpoints.

This driver was tested using the mailbox-test driver sending messages
between the Cortex-A7 and the Cortex-M4.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/mailbox/Kconfig       |   6 +
 drivers/mailbox/Makefile      |   2 +
 drivers/mailbox/imx-mailbox.c | 288 ++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/mailbox/imx-mailbox.c

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index a2bb27446dce..e1d2738a2e4c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,12 @@ config ARM_MHU
 	  The controller has 3 mailbox channels, the last of which can be
 	  used in Secure mode only.
 
+config IMX_MBOX
+	tristate "iMX Mailbox"
+	depends on SOC_IMX7D || COMPILE_TEST
+	help
+	  Mailbox implementation for iMX7D Messaging Unit (MU).
+
 config PLATFORM_MHU
 	tristate "Platform MHU Mailbox"
 	depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index cc23c3a43fcd..ba2fe1b6dd62 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
 
 obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
 
+obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
+
 obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
 
 obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
new file mode 100644
index 000000000000..e3f621cb1d30
--- /dev/null
+++ b/drivers/mailbox/imx-mailbox.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+/* Transmit Register */
+#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
+/* Receive Register */
+#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
+/* Status Register */
+#define IMX_MU_xSR		0x20
+#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
+#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
+#define IMX_MU_xSR_BRDIP	BIT(9)
+
+/* Control Register */
+#define IMX_MU_xCR		0x24
+/* Transmit Interrupt Enable */
+#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
+/* Receive Interrupt Enable */
+#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
+
+#define IMX_MU_MAX_CHANS	4u
+
+struct imx_mu_priv;
+
+struct imx_mu_cfg {
+	unsigned int		chans;
+	void (*init_hw)(struct imx_mu_priv *priv);
+};
+
+struct imx_mu_con_priv {
+	int			irq;
+	unsigned int		bidx;
+	unsigned int		idx;
+};
+
+struct imx_mu_priv {
+	struct device		*dev;
+	const struct imx_mu_cfg	*dcfg;
+	void __iomem		*base;
+
+	struct mbox_controller	mbox;
+	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
+
+	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
+	struct clk		*clk;
+};
+
+static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
+{
+	return container_of(mbox, struct imx_mu_priv, mbox);
+}
+
+static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
+{
+	iowrite32(val, priv->base + offs);
+}
+
+static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
+{
+	return ioread32(priv->base + offs);
+}
+
+static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32 clr)
+{
+	u32 val;
+
+	val = imx_mu_read(priv, offs);
+	val &= ~clr;
+	val |= set;
+	imx_mu_write(priv, val, offs);
+
+	return val;
+}
+
+static irqreturn_t imx_mu_isr(int irq, void *p)
+{
+	struct mbox_chan *chan = p;
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	u32 val, dat;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
+	if (!val)
+		return IRQ_NONE;
+
+	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
+		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp->bidx));
+		mbox_chan_txdone(chan, 0);
+	}
+
+	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
+		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
+		mbox_chan_received_data(chan, (void *)&dat);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static bool imx_mu_last_tx_done(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 val;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	/* test if transmit register is empty */
+	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
+}
+
+static int imx_mu_send_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 *arg = data;
+
+	if (!imx_mu_last_tx_done(chan))
+		return -EBUSY;
+
+	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static int imx_mu_startup(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	int ret;
+
+	ret = request_irq(cp->irq, imx_mu_isr,
+			  IRQF_SHARED, "imx_mu_chan", chan);
+	if (ret) {
+		dev_err(chan->mbox->dev,
+			"Unable to acquire IRQ %d\n", cp->irq);
+		return ret;
+	}
+
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static void imx_mu_shutdown(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	imx_mu_rmw(priv, IMX_MU_xCR, 0,
+		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp->bidx));
+
+	free_irq(cp->irq, chan);
+}
+
+static const struct mbox_chan_ops imx_mu_ops = {
+	.send_data = imx_mu_send_data,
+	.startup = imx_mu_startup,
+	.shutdown = imx_mu_shutdown,
+};
+
+static int imx_mu_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iomem;
+	struct imx_mu_priv *priv;
+	const struct imx_mu_cfg *dcfg;
+	unsigned int i, chans;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dcfg = of_device_get_match_data(dev);
+	if (!dcfg)
+		return -EINVAL;
+
+	priv->dcfg = dcfg;
+	priv->dev = dev;
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return irq < 0 ? irq : -EINVAL;
+
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		if (PTR_ERR(priv->clk) == -ENOENT) {
+			priv->clk = NULL;
+		} else {
+			dev_err(dev, "Failed to get clock\n");
+			return PTR_ERR(priv->clk);
+		}
+	}
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable clock\n");
+		return ret;
+	}
+
+	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
+	/* Initialize channel identifiers */
+	for (i = 0; i < chans; i++) {
+		struct imx_mu_con_priv *cp = &priv->con_priv[i];
+
+		cp->bidx = 3 - i;
+		cp->idx = i;
+		cp->irq = irq;
+		priv->mbox_chans[i].con_priv = cp;
+	}
+
+	priv->mbox.dev = dev;
+	priv->mbox.ops = &imx_mu_ops;
+	priv->mbox.chans = priv->mbox_chans;
+	priv->mbox.num_chans = chans;
+	priv->mbox.txdone_irq = true;
+
+	platform_set_drvdata(pdev, priv);
+
+	if (priv->dcfg->init_hw)
+		priv->dcfg->init_hw(priv);
+
+	return mbox_controller_register(&priv->mbox);
+}
+
+static int imx_mu_remove(struct platform_device *pdev)
+{
+	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&priv->mbox);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+
+static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv)
+{
+	/* Set default config */
+	imx_mu_write(priv, 0, IMX_MU_xCR);
+}
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
+	.chans = IMX_MU_MAX_CHANS,
+	.init_hw = imx_mu_init_imx7d_a,
+};
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
+	.chans = IMX_MU_MAX_CHANS,
+};
+
+static const struct of_device_id imx_mu_dt_ids[] = {
+	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
+	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
+
+static struct platform_driver imx_mu_driver = {
+	.probe		= imx_mu_probe,
+	.remove		= imx_mu_remove,
+	.driver = {
+		.name	= "imx_mu",
+		.of_match_table = imx_mu_dt_ids,
+	},
+};
+module_platform_driver(imx_mu_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
+MODULE_DESCRIPTION("Message Unit driver for i.MX");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-15  9:51   ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-15  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

The Mailbox controller is able to send messages (up to 4 32 bit words)
between the endpoints.

This driver was tested using the mailbox-test driver sending messages
between the Cortex-A7 and the Cortex-M4.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/mailbox/Kconfig       |   6 +
 drivers/mailbox/Makefile      |   2 +
 drivers/mailbox/imx-mailbox.c | 288 ++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/mailbox/imx-mailbox.c

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index a2bb27446dce..e1d2738a2e4c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,12 @@ config ARM_MHU
 	  The controller has 3 mailbox channels, the last of which can be
 	  used in Secure mode only.
 
+config IMX_MBOX
+	tristate "iMX Mailbox"
+	depends on SOC_IMX7D || COMPILE_TEST
+	help
+	  Mailbox implementation for iMX7D Messaging Unit (MU).
+
 config PLATFORM_MHU
 	tristate "Platform MHU Mailbox"
 	depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index cc23c3a43fcd..ba2fe1b6dd62 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
 
 obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
 
+obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
+
 obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
 
 obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
new file mode 100644
index 000000000000..e3f621cb1d30
--- /dev/null
+++ b/drivers/mailbox/imx-mailbox.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+/* Transmit Register */
+#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
+/* Receive Register */
+#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
+/* Status Register */
+#define IMX_MU_xSR		0x20
+#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
+#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
+#define IMX_MU_xSR_BRDIP	BIT(9)
+
+/* Control Register */
+#define IMX_MU_xCR		0x24
+/* Transmit Interrupt Enable */
+#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
+/* Receive Interrupt Enable */
+#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
+
+#define IMX_MU_MAX_CHANS	4u
+
+struct imx_mu_priv;
+
+struct imx_mu_cfg {
+	unsigned int		chans;
+	void (*init_hw)(struct imx_mu_priv *priv);
+};
+
+struct imx_mu_con_priv {
+	int			irq;
+	unsigned int		bidx;
+	unsigned int		idx;
+};
+
+struct imx_mu_priv {
+	struct device		*dev;
+	const struct imx_mu_cfg	*dcfg;
+	void __iomem		*base;
+
+	struct mbox_controller	mbox;
+	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
+
+	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
+	struct clk		*clk;
+};
+
+static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
+{
+	return container_of(mbox, struct imx_mu_priv, mbox);
+}
+
+static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
+{
+	iowrite32(val, priv->base + offs);
+}
+
+static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
+{
+	return ioread32(priv->base + offs);
+}
+
+static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32 clr)
+{
+	u32 val;
+
+	val = imx_mu_read(priv, offs);
+	val &= ~clr;
+	val |= set;
+	imx_mu_write(priv, val, offs);
+
+	return val;
+}
+
+static irqreturn_t imx_mu_isr(int irq, void *p)
+{
+	struct mbox_chan *chan = p;
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	u32 val, dat;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
+	if (!val)
+		return IRQ_NONE;
+
+	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
+		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp->bidx));
+		mbox_chan_txdone(chan, 0);
+	}
+
+	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
+		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
+		mbox_chan_received_data(chan, (void *)&dat);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static bool imx_mu_last_tx_done(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 val;
+
+	val = imx_mu_read(priv, IMX_MU_xSR);
+	/* test if transmit register is empty */
+	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
+}
+
+static int imx_mu_send_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	u32 *arg = data;
+
+	if (!imx_mu_last_tx_done(chan))
+		return -EBUSY;
+
+	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static int imx_mu_startup(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+	int ret;
+
+	ret = request_irq(cp->irq, imx_mu_isr,
+			  IRQF_SHARED, "imx_mu_chan", chan);
+	if (ret) {
+		dev_err(chan->mbox->dev,
+			"Unable to acquire IRQ %d\n", cp->irq);
+		return ret;
+	}
+
+	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
+
+	return 0;
+}
+
+static void imx_mu_shutdown(struct mbox_chan *chan)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	imx_mu_rmw(priv, IMX_MU_xCR, 0,
+		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp->bidx));
+
+	free_irq(cp->irq, chan);
+}
+
+static const struct mbox_chan_ops imx_mu_ops = {
+	.send_data = imx_mu_send_data,
+	.startup = imx_mu_startup,
+	.shutdown = imx_mu_shutdown,
+};
+
+static int imx_mu_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iomem;
+	struct imx_mu_priv *priv;
+	const struct imx_mu_cfg *dcfg;
+	unsigned int i, chans;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dcfg = of_device_get_match_data(dev);
+	if (!dcfg)
+		return -EINVAL;
+
+	priv->dcfg = dcfg;
+	priv->dev = dev;
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return irq < 0 ? irq : -EINVAL;
+
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		if (PTR_ERR(priv->clk) == -ENOENT) {
+			priv->clk = NULL;
+		} else {
+			dev_err(dev, "Failed to get clock\n");
+			return PTR_ERR(priv->clk);
+		}
+	}
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable clock\n");
+		return ret;
+	}
+
+	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
+	/* Initialize channel identifiers */
+	for (i = 0; i < chans; i++) {
+		struct imx_mu_con_priv *cp = &priv->con_priv[i];
+
+		cp->bidx = 3 - i;
+		cp->idx = i;
+		cp->irq = irq;
+		priv->mbox_chans[i].con_priv = cp;
+	}
+
+	priv->mbox.dev = dev;
+	priv->mbox.ops = &imx_mu_ops;
+	priv->mbox.chans = priv->mbox_chans;
+	priv->mbox.num_chans = chans;
+	priv->mbox.txdone_irq = true;
+
+	platform_set_drvdata(pdev, priv);
+
+	if (priv->dcfg->init_hw)
+		priv->dcfg->init_hw(priv);
+
+	return mbox_controller_register(&priv->mbox);
+}
+
+static int imx_mu_remove(struct platform_device *pdev)
+{
+	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
+
+	mbox_controller_unregister(&priv->mbox);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+
+static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv)
+{
+	/* Set default config */
+	imx_mu_write(priv, 0, IMX_MU_xCR);
+}
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
+	.chans = IMX_MU_MAX_CHANS,
+	.init_hw = imx_mu_init_imx7d_a,
+};
+
+static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
+	.chans = IMX_MU_MAX_CHANS,
+};
+
+static const struct of_device_id imx_mu_dt_ids[] = {
+	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
+	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
+
+static struct platform_driver imx_mu_driver = {
+	.probe		= imx_mu_probe,
+	.remove		= imx_mu_remove,
+	.driver = {
+		.name	= "imx_mu",
+		.of_match_table = imx_mu_dt_ids,
+	},
+};
+module_platform_driver(imx_mu_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
+MODULE_DESCRIPTION("Message Unit driver for i.MX");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1

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

* Re: [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-06-18  8:53     ` Leonard Crestez
  -1 siblings, 0 replies; 69+ messages in thread
From: Leonard Crestez @ 2018-06-18  8:53 UTC (permalink / raw)
  To: o.rempel, mark.rutland, shawnguo, robh+dt, A.s. Dong
  Cc: devicetree, Richard Zhu, dl-linux-imx, kernel, Fabio Estevam,
	linux-clk, linux-arm-kernel

On Fri, 2018-06-15 at 11:51 +0200, Oleksij Rempel wrote:
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt

A recent patch was posted which adds a similar but different binding
for the MU on 8qm/8qxp SOCs:

https://patchwork.kernel.org/patch/10468885/

Looking at manuals side-by-side the hardware seems to be the same so
there should be a single binding. Right?

That series I pointed to uses the MU to implement a communication with
a special "SCU" core which runs NXP firmware for handling details like
power management. However imx8 socs also have other MUs and M4 cores
for customers to use pretty exactly like they would on 7d.

The hardware exposes a very generic interface and my impression is that
 drivers for the MU are actually highly specific to what is on the
other side of the MU. For example your driver code seems to be mapping
the 4 MU registers to separate "channels" but for SCU messages are
written in all registers in a round-robin way.

Shouldn't your MU-using driver be a separate node which references the
MU by phandle? Like in this patch:

https://patchwork.kernel.org/patch/10468887/

> diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> new file mode 100644
> index 000000000000..1577b86f1206
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> @@ -0,0 +1,35 @@
> +i.MX Messaging Unit
> +===================
> +
> +The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
> +cases they are accessible from all Processor Units. On one hand, at least for
> +mailbox functionality, it makes no difference which application or processor is
> +using which set of the MU. On other hand, the register sets for each of the MU
> +parts are not identical.
> +
> +Required properties:
> +- compatible :	Shell be one of:
> +                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
> +- reg :		physical base address of the mailbox and length of
> +		memory mapped region.
> +- #mbox-cells:	Common mailbox binding property to identify the number
> +		of cells required for the mailbox specifier. Should be 1.
> +- interrupts :	The interrupt number
> +- clocks     :  phandle to the input clock.
> +
> +Example:
> +	mu0a: mailbox@30aa0000 {
> +		compatible = "fsl,imx7s-mu-a";
> +		reg = <0x30aa0000 0x28>;
> +		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
> +		#mbox-cells = <1>;
> +	};
> +
> +	mu0b: mailbox@30ab0000 {
> +		compatible = "fsl,imx7s-mu-b";
> +		reg = <0x30ab0000 0x28>;
> +		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
> +		#mbox-cells = <1>;
> +	};

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

* Re: [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-18  8:53     ` Leonard Crestez
  0 siblings, 0 replies; 69+ messages in thread
From: Leonard Crestez @ 2018-06-18  8:53 UTC (permalink / raw)
  To: o.rempel, mark.rutland, shawnguo, robh+dt, A.s. Dong
  Cc: linux-arm-kernel, Richard Zhu, dl-linux-imx, kernel,
	Fabio Estevam, devicetree, linux-clk

T24gRnJpLCAyMDE4LTA2LTE1IGF0IDExOjUxICswMjAwLCBPbGVrc2lqIFJlbXBlbCB3cm90ZToN
Cj4gU2lnbmVkLW9mZi1ieTogT2xla3NpaiBSZW1wZWwgPG8ucmVtcGVsQHBlbmd1dHJvbml4LmRl
Pg0KPiAtLS0NCj4gIC4uLi9iaW5kaW5ncy9tYWlsYm94L2lteC1tYWlsYm94LnR4dCAgICAgICAg
ICB8IDM1ICsrKysrKysrKysrKysrKysrKysNCj4gIDEgZmlsZSBjaGFuZ2VkLCAzNSBpbnNlcnRp
b25zKCspDQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2Jp
bmRpbmdzL21haWxib3gvaW14LW1haWxib3gudHh0DQoNCkEgcmVjZW50IHBhdGNoIHdhcyBwb3N0
ZWQgd2hpY2ggYWRkcyBhIHNpbWlsYXIgYnV0IGRpZmZlcmVudCBiaW5kaW5nDQpmb3IgdGhlIE1V
IG9uIDhxbS84cXhwIFNPQ3M6DQoNCmh0dHBzOi8vcGF0Y2h3b3JrLmtlcm5lbC5vcmcvcGF0Y2gv
MTA0Njg4ODUvDQoNCkxvb2tpbmcgYXQgbWFudWFscyBzaWRlLWJ5LXNpZGUgdGhlIGhhcmR3YXJl
IHNlZW1zIHRvIGJlIHRoZSBzYW1lIHNvDQp0aGVyZSBzaG91bGQgYmUgYSBzaW5nbGUgYmluZGlu
Zy4gUmlnaHQ/DQoNClRoYXQgc2VyaWVzIEkgcG9pbnRlZCB0byB1c2VzIHRoZSBNVSB0byBpbXBs
ZW1lbnQgYSBjb21tdW5pY2F0aW9uIHdpdGgNCmEgc3BlY2lhbCAiU0NVIiBjb3JlIHdoaWNoIHJ1
bnMgTlhQIGZpcm13YXJlIGZvciBoYW5kbGluZyBkZXRhaWxzIGxpa2UNCnBvd2VyIG1hbmFnZW1l
bnQuIEhvd2V2ZXIgaW14OCBzb2NzIGFsc28gaGF2ZSBvdGhlciBNVXMgYW5kIE00IGNvcmVzDQpm
b3IgY3VzdG9tZXJzIHRvIHVzZSBwcmV0dHkgZXhhY3RseSBsaWtlIHRoZXkgd291bGQgb24gN2Qu
DQoNClRoZSBoYXJkd2FyZSBleHBvc2VzIGEgdmVyeSBnZW5lcmljIGludGVyZmFjZSBhbmQgbXkg
aW1wcmVzc2lvbiBpcyB0aGF0DQogZHJpdmVycyBmb3IgdGhlIE1VIGFyZSBhY3R1YWxseSBoaWdo
bHkgc3BlY2lmaWMgdG8gd2hhdCBpcyBvbiB0aGUNCm90aGVyIHNpZGUgb2YgdGhlIE1VLiBGb3Ig
ZXhhbXBsZSB5b3VyIGRyaXZlciBjb2RlIHNlZW1zIHRvIGJlIG1hcHBpbmcNCnRoZSA0IE1VIHJl
Z2lzdGVycyB0byBzZXBhcmF0ZSAiY2hhbm5lbHMiIGJ1dCBmb3IgU0NVIG1lc3NhZ2VzIGFyZQ0K
d3JpdHRlbiBpbiBhbGwgcmVnaXN0ZXJzIGluIGEgcm91bmQtcm9iaW4gd2F5Lg0KDQpTaG91bGRu
J3QgeW91ciBNVS11c2luZyBkcml2ZXIgYmUgYSBzZXBhcmF0ZSBub2RlIHdoaWNoIHJlZmVyZW5j
ZXMgdGhlDQpNVSBieSBwaGFuZGxlPyBMaWtlIGluIHRoaXMgcGF0Y2g6DQoNCmh0dHBzOi8vcGF0
Y2h3b3JrLmtlcm5lbC5vcmcvcGF0Y2gvMTA0Njg4ODcvDQoNCj4gZGlmZiAtLWdpdCBhL0RvY3Vt
ZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9tYWlsYm94L2lteC1tYWlsYm94LnR4dCBiL0Rv
Y3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9tYWlsYm94L2lteC1tYWlsYm94LnR4dA0K
PiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiBpbmRleCAwMDAwMDAwMDAwMDAuLjE1NzdiODZmMTIw
Ng0KPiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5k
aW5ncy9tYWlsYm94L2lteC1tYWlsYm94LnR4dA0KPiBAQCAtMCwwICsxLDM1IEBADQo+ICtpLk1Y
IE1lc3NhZ2luZyBVbml0DQo+ICs9PT09PT09PT09PT09PT09PT09DQo+ICsNCj4gK1RoZSBpLk1Y
IE1lc3NhZ2luZyBVbml0IChNVSkgY29udGFpbnMgdHdvIHJlZ2lzdGVyIHNldHM6ICJBIiBhbmQg
IkIiLiBJbiBtb3N0DQo+ICtjYXNlcyB0aGV5IGFyZSBhY2Nlc3NpYmxlIGZyb20gYWxsIFByb2Nl
c3NvciBVbml0cy4gT24gb25lIGhhbmQsIGF0IGxlYXN0IGZvcg0KPiArbWFpbGJveCBmdW5jdGlv
bmFsaXR5LCBpdCBtYWtlcyBubyBkaWZmZXJlbmNlIHdoaWNoIGFwcGxpY2F0aW9uIG9yIHByb2Nl
c3NvciBpcw0KPiArdXNpbmcgd2hpY2ggc2V0IG9mIHRoZSBNVS4gT24gb3RoZXIgaGFuZCwgdGhl
IHJlZ2lzdGVyIHNldHMgZm9yIGVhY2ggb2YgdGhlIE1VDQo+ICtwYXJ0cyBhcmUgbm90IGlkZW50
aWNhbC4NCj4gKw0KPiArUmVxdWlyZWQgcHJvcGVydGllczoNCj4gKy0gY29tcGF0aWJsZSA6CVNo
ZWxsIGJlIG9uZSBvZjoNCj4gKyAgICAgICAgICAgICAgICAgICAgImZzbCxpbXg3cy1tdS1hIiBh
bmQgImZzbCxpbXg3cy1tdS1iIiBmb3IgaS5NWDdTIG9yIGkuTVg3RA0KPiArLSByZWcgOgkJcGh5
c2ljYWwgYmFzZSBhZGRyZXNzIG9mIHRoZSBtYWlsYm94IGFuZCBsZW5ndGggb2YNCj4gKwkJbWVt
b3J5IG1hcHBlZCByZWdpb24uDQo+ICstICNtYm94LWNlbGxzOglDb21tb24gbWFpbGJveCBiaW5k
aW5nIHByb3BlcnR5IHRvIGlkZW50aWZ5IHRoZSBudW1iZXINCj4gKwkJb2YgY2VsbHMgcmVxdWly
ZWQgZm9yIHRoZSBtYWlsYm94IHNwZWNpZmllci4gU2hvdWxkIGJlIDEuDQo+ICstIGludGVycnVw
dHMgOglUaGUgaW50ZXJydXB0IG51bWJlcg0KPiArLSBjbG9ja3MgICAgIDogIHBoYW5kbGUgdG8g
dGhlIGlucHV0IGNsb2NrLg0KPiArDQo+ICtFeGFtcGxlOg0KPiArCW11MGE6IG1haWxib3hAMzBh
YTAwMDAgew0KPiArCQljb21wYXRpYmxlID0gImZzbCxpbXg3cy1tdS1hIjsNCj4gKwkJcmVnID0g
PDB4MzBhYTAwMDAgMHgyOD47DQo+ICsJCWludGVycnVwdHMgPSA8R0lDX1NQSSA4OCBJUlFfVFlQ
RV9MRVZFTF9ISUdIPjsNCj4gKwkJY2xvY2tzID0gPCZjbGtzIElNWDdEX01VX1JPT1RfQ0xLPjsN
Cj4gKwkJI21ib3gtY2VsbHMgPSA8MT47DQo+ICsJfTsNCj4gKw0KPiArCW11MGI6IG1haWxib3hA
MzBhYjAwMDAgew0KPiArCQljb21wYXRpYmxlID0gImZzbCxpbXg3cy1tdS1iIjsNCj4gKwkJcmVn
ID0gPDB4MzBhYjAwMDAgMHgyOD47DQo+ICsJCWludGVycnVwdHMgPSA8R0lDX1NQSSA5NyBJUlFf
VFlQRV9MRVZFTF9ISUdIPjsNCj4gKwkJY2xvY2tzID0gPCZjbGtzIElNWDdEX01VX1JPT1RfQ0xL
PjsNCj4gKwkJI21ib3gtY2VsbHMgPSA8MT47DQo+ICsJfTsNCg==

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

* [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-18  8:53     ` Leonard Crestez
  0 siblings, 0 replies; 69+ messages in thread
From: Leonard Crestez @ 2018-06-18  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2018-06-15 at 11:51 +0200, Oleksij Rempel wrote:
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt

A recent patch was posted which adds a similar but different binding
for the MU on 8qm/8qxp SOCs:

https://patchwork.kernel.org/patch/10468885/

Looking at manuals side-by-side the hardware seems to be the same so
there should be a single binding. Right?

That series I pointed to uses the MU to implement a communication with
a special "SCU" core which runs NXP firmware for handling details like
power management. However imx8 socs also have other MUs and M4 cores
for customers to use pretty exactly like they would on 7d.

The hardware exposes a very generic interface and my impression is that
 drivers for the MU are actually highly specific to what is on the
other side of the MU. For example your driver code seems to be mapping
the 4 MU registers to separate "channels" but for SCU messages are
written in all registers in a round-robin way.

Shouldn't your MU-using driver be a separate node which references the
MU by phandle? Like in this patch:

https://patchwork.kernel.org/patch/10468887/

> diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> new file mode 100644
> index 000000000000..1577b86f1206
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> @@ -0,0 +1,35 @@
> +i.MX Messaging Unit
> +===================
> +
> +The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
> +cases they are accessible from all Processor Units. On one hand, at least for
> +mailbox functionality, it makes no difference which application or processor is
> +using which set of the MU. On other hand, the register sets for each of the MU
> +parts are not identical.
> +
> +Required properties:
> +- compatible :	Shell be one of:
> +                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
> +- reg :		physical base address of the mailbox and length of
> +		memory mapped region.
> +- #mbox-cells:	Common mailbox binding property to identify the number
> +		of cells required for the mailbox specifier. Should be 1.
> +- interrupts :	The interrupt number
> +- clocks     :  phandle to the input clock.
> +
> +Example:
> +	mu0a: mailbox at 30aa0000 {
> +		compatible = "fsl,imx7s-mu-a";
> +		reg = <0x30aa0000 0x28>;
> +		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
> +		#mbox-cells = <1>;
> +	};
> +
> +	mu0b: mailbox at 30ab0000 {
> +		compatible = "fsl,imx7s-mu-b";
> +		reg = <0x30ab0000 0x28>;
> +		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
> +		#mbox-cells = <1>;
> +	};

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

* Re: [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
  2018-06-18  8:53     ` Leonard Crestez
  (?)
@ 2018-06-18 11:51       ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-18 11:51 UTC (permalink / raw)
  To: Leonard Crestez, mark.rutland, shawnguo, robh+dt, A.s. Dong
  Cc: devicetree, Richard Zhu, dl-linux-imx, kernel, Fabio Estevam,
	linux-clk, linux-arm-kernel


[-- Attachment #1.1.1: Type: text/plain, Size: 5711 bytes --]

Hi Leonard,

On 18.06.2018 10:53, Leonard Crestez wrote:
> On Fri, 2018-06-15 at 11:51 +0200, Oleksij Rempel wrote:
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
>>  1 file changed, 35 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> 
> A recent patch was posted which adds a similar but different binding
> for the MU on 8qm/8qxp SOCs:
> 
> https://patchwork.kernel.org/patch/10468885/
> 
> Looking at manuals side-by-side the hardware seems to be the same so
> there should be a single binding. Right?

yes. This is why it make no sense to create imx8 specific MU driver.

> That series I pointed to uses the MU to implement a communication with
> a special "SCU" core which runs NXP firmware for handling details like
> power management. However imx8 socs also have other MUs and M4 cores
> for customers to use pretty exactly like they would on 7d.
> 
> The hardware exposes a very generic interface and my impression is that
>  drivers for the MU are actually highly specific to what is on the
> other side of the MU. For example your driver code seems to be mapping
> the 4 MU registers to separate "channels" but for SCU messages are
> written in all registers in a round-robin way.

ok.. let's take some of IMX8 SCU driver code to see if there any difference:

-- this part of the code is blocking write procedure for one channeler
per write-- correct?
+void mu_send_msg(struct mu_priv *priv, uint32_t index, uint32_t msg)
+{
+	uint32_t mask = MU_SR_TE0_MASK >> index;
+
+	/* Wait TX register to be empty. */
+	while (!(readl_relaxed(priv->base + MU_ASR) & mask))
+		;
+	writel_relaxed(msg, priv->base + MU_ATR0  + (index * 4));
+}
+EXPORT_SYMBOL_GPL(mu_send_msg);

+static void sc_ipc_write(struct sc_ipc *sc_ipc, void *data)
+{
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+	uint8_t count = 0;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG)
+		return;
+
+	/* Write first word */
+	mu_send_msg(sc_ipc->mu_base, 0, *((uint32_t *) msg));
+	count++;

--- in this loop we are writing to one channel per loop and waiting
until the channel was done ----

+	/* Write remaining words */
+	while (count < msg->size) {
+		mu_send_msg(sc_ipc->mu_base, count % MU_TR_COUNT,
+			    msg->DATA.u32[count - 1]);
+		count++;
+	}
+}


... and here is a proof that sc_ipc_write will do in some cases 5 rounds
(5 * 4 bytes = 20 bytes single message) with probable busy waiting for
each channel, which make me think that shared memory would be a better deal.

+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, uint32_t addr_src,
+				 uint32_t addr_dst, uint32_t len, bool fw)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD;
+	RPC_U32(&msg, 0) = addr_src;
+	RPC_U32(&msg, 4) = addr_dst;
+	RPC_U32(&msg, 8) = len;
+	RPC_U8(&msg, 12) = (uint8_t)fw;
+	RPC_SIZE(&msg) = 5;
+
+	sc_call_rpc(ipc, &msg, false);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+

So, the same code with mailbox framework will be some thing like this:

	/* Write remaining words */
	while (count < msg->size) {
		mbox_send_message(sc_ipc->mbox_chan[count % MU_TR_COUNT],
msg->DATA.u32[count - 1]);
		count++;
	}

to provide identical behavior we should set mbox_client->tx_block = true
and implement polling mode in the mailbox driver.

Please note. I don't think sc_ipc_write() implementation is good. I just
don't expect it will be ever changed.

> Shouldn't your MU-using driver be a separate node which references the
> MU by phandle? Like in this patch:

sure. But it is generic, not mailbox controller specific and make no
sense to describe client binding again in the controller binding.

> https://patchwork.kernel.org/patch/10468887/
> 
>> diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> new file mode 100644
>> index 000000000000..1577b86f1206
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> @@ -0,0 +1,35 @@
>> +i.MX Messaging Unit
>> +===================
>> +
>> +The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
>> +cases they are accessible from all Processor Units. On one hand, at least for
>> +mailbox functionality, it makes no difference which application or processor is
>> +using which set of the MU. On other hand, the register sets for each of the MU
>> +parts are not identical.
>> +
>> +Required properties:
>> +- compatible :	Shell be one of:
>> +                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
>> +- reg :		physical base address of the mailbox and length of
>> +		memory mapped region.
>> +- #mbox-cells:	Common mailbox binding property to identify the number
>> +		of cells required for the mailbox specifier. Should be 1.
>> +- interrupts :	The interrupt number
>> +- clocks     :  phandle to the input clock.
>> +
>> +Example:
>> +	mu0a: mailbox@30aa0000 {
>> +		compatible = "fsl,imx7s-mu-a";
>> +		reg = <0x30aa0000 0x28>;
>> +		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};
>> +
>> +	mu0b: mailbox@30ab0000 {
>> +		compatible = "fsl,imx7s-mu-b";
>> +		reg = <0x30ab0000 0x28>;
>> +		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-18 11:51       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-18 11:51 UTC (permalink / raw)
  To: Leonard Crestez, mark.rutland, shawnguo, robh+dt, A.s. Dong
  Cc: linux-arm-kernel, Richard Zhu, dl-linux-imx, kernel,
	Fabio Estevam, devicetree, linux-clk


[-- Attachment #1.1: Type: text/plain, Size: 5711 bytes --]

Hi Leonard,

On 18.06.2018 10:53, Leonard Crestez wrote:
> On Fri, 2018-06-15 at 11:51 +0200, Oleksij Rempel wrote:
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
>>  1 file changed, 35 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> 
> A recent patch was posted which adds a similar but different binding
> for the MU on 8qm/8qxp SOCs:
> 
> https://patchwork.kernel.org/patch/10468885/
> 
> Looking at manuals side-by-side the hardware seems to be the same so
> there should be a single binding. Right?

yes. This is why it make no sense to create imx8 specific MU driver.

> That series I pointed to uses the MU to implement a communication with
> a special "SCU" core which runs NXP firmware for handling details like
> power management. However imx8 socs also have other MUs and M4 cores
> for customers to use pretty exactly like they would on 7d.
> 
> The hardware exposes a very generic interface and my impression is that
>  drivers for the MU are actually highly specific to what is on the
> other side of the MU. For example your driver code seems to be mapping
> the 4 MU registers to separate "channels" but for SCU messages are
> written in all registers in a round-robin way.

ok.. let's take some of IMX8 SCU driver code to see if there any difference:

-- this part of the code is blocking write procedure for one channeler
per write-- correct?
+void mu_send_msg(struct mu_priv *priv, uint32_t index, uint32_t msg)
+{
+	uint32_t mask = MU_SR_TE0_MASK >> index;
+
+	/* Wait TX register to be empty. */
+	while (!(readl_relaxed(priv->base + MU_ASR) & mask))
+		;
+	writel_relaxed(msg, priv->base + MU_ATR0  + (index * 4));
+}
+EXPORT_SYMBOL_GPL(mu_send_msg);

+static void sc_ipc_write(struct sc_ipc *sc_ipc, void *data)
+{
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+	uint8_t count = 0;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG)
+		return;
+
+	/* Write first word */
+	mu_send_msg(sc_ipc->mu_base, 0, *((uint32_t *) msg));
+	count++;

--- in this loop we are writing to one channel per loop and waiting
until the channel was done ----

+	/* Write remaining words */
+	while (count < msg->size) {
+		mu_send_msg(sc_ipc->mu_base, count % MU_TR_COUNT,
+			    msg->DATA.u32[count - 1]);
+		count++;
+	}
+}


... and here is a proof that sc_ipc_write will do in some cases 5 rounds
(5 * 4 bytes = 20 bytes single message) with probable busy waiting for
each channel, which make me think that shared memory would be a better deal.

+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, uint32_t addr_src,
+				 uint32_t addr_dst, uint32_t len, bool fw)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD;
+	RPC_U32(&msg, 0) = addr_src;
+	RPC_U32(&msg, 4) = addr_dst;
+	RPC_U32(&msg, 8) = len;
+	RPC_U8(&msg, 12) = (uint8_t)fw;
+	RPC_SIZE(&msg) = 5;
+
+	sc_call_rpc(ipc, &msg, false);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+

So, the same code with mailbox framework will be some thing like this:

	/* Write remaining words */
	while (count < msg->size) {
		mbox_send_message(sc_ipc->mbox_chan[count % MU_TR_COUNT],
msg->DATA.u32[count - 1]);
		count++;
	}

to provide identical behavior we should set mbox_client->tx_block = true
and implement polling mode in the mailbox driver.

Please note. I don't think sc_ipc_write() implementation is good. I just
don't expect it will be ever changed.

> Shouldn't your MU-using driver be a separate node which references the
> MU by phandle? Like in this patch:

sure. But it is generic, not mailbox controller specific and make no
sense to describe client binding again in the controller binding.

> https://patchwork.kernel.org/patch/10468887/
> 
>> diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> new file mode 100644
>> index 000000000000..1577b86f1206
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> @@ -0,0 +1,35 @@
>> +i.MX Messaging Unit
>> +===================
>> +
>> +The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
>> +cases they are accessible from all Processor Units. On one hand, at least for
>> +mailbox functionality, it makes no difference which application or processor is
>> +using which set of the MU. On other hand, the register sets for each of the MU
>> +parts are not identical.
>> +
>> +Required properties:
>> +- compatible :	Shell be one of:
>> +                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
>> +- reg :		physical base address of the mailbox and length of
>> +		memory mapped region.
>> +- #mbox-cells:	Common mailbox binding property to identify the number
>> +		of cells required for the mailbox specifier. Should be 1.
>> +- interrupts :	The interrupt number
>> +- clocks     :  phandle to the input clock.
>> +
>> +Example:
>> +	mu0a: mailbox@30aa0000 {
>> +		compatible = "fsl,imx7s-mu-a";
>> +		reg = <0x30aa0000 0x28>;
>> +		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};
>> +
>> +	mu0b: mailbox@30ab0000 {
>> +		compatible = "fsl,imx7s-mu-b";
>> +		reg = <0x30ab0000 0x28>;
>> +		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation
@ 2018-06-18 11:51       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-18 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Leonard,

On 18.06.2018 10:53, Leonard Crestez wrote:
> On Fri, 2018-06-15 at 11:51 +0200, Oleksij Rempel wrote:
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  .../bindings/mailbox/imx-mailbox.txt          | 35 +++++++++++++++++++
>>  1 file changed, 35 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
> 
> A recent patch was posted which adds a similar but different binding
> for the MU on 8qm/8qxp SOCs:
> 
> https://patchwork.kernel.org/patch/10468885/
> 
> Looking at manuals side-by-side the hardware seems to be the same so
> there should be a single binding. Right?

yes. This is why it make no sense to create imx8 specific MU driver.

> That series I pointed to uses the MU to implement a communication with
> a special "SCU" core which runs NXP firmware for handling details like
> power management. However imx8 socs also have other MUs and M4 cores
> for customers to use pretty exactly like they would on 7d.
> 
> The hardware exposes a very generic interface and my impression is that
>  drivers for the MU are actually highly specific to what is on the
> other side of the MU. For example your driver code seems to be mapping
> the 4 MU registers to separate "channels" but for SCU messages are
> written in all registers in a round-robin way.

ok.. let's take some of IMX8 SCU driver code to see if there any difference:

-- this part of the code is blocking write procedure for one channeler
per write-- correct?
+void mu_send_msg(struct mu_priv *priv, uint32_t index, uint32_t msg)
+{
+	uint32_t mask = MU_SR_TE0_MASK >> index;
+
+	/* Wait TX register to be empty. */
+	while (!(readl_relaxed(priv->base + MU_ASR) & mask))
+		;
+	writel_relaxed(msg, priv->base + MU_ATR0  + (index * 4));
+}
+EXPORT_SYMBOL_GPL(mu_send_msg);

+static void sc_ipc_write(struct sc_ipc *sc_ipc, void *data)
+{
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+	uint8_t count = 0;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG)
+		return;
+
+	/* Write first word */
+	mu_send_msg(sc_ipc->mu_base, 0, *((uint32_t *) msg));
+	count++;

--- in this loop we are writing to one channel per loop and waiting
until the channel was done ----

+	/* Write remaining words */
+	while (count < msg->size) {
+		mu_send_msg(sc_ipc->mu_base, count % MU_TR_COUNT,
+			    msg->DATA.u32[count - 1]);
+		count++;
+	}
+}


... and here is a proof that sc_ipc_write will do in some cases 5 rounds
(5 * 4 bytes = 20 bytes single message) with probable busy waiting for
each channel, which make me think that shared memory would be a better deal.

+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, uint32_t addr_src,
+				 uint32_t addr_dst, uint32_t len, bool fw)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD;
+	RPC_U32(&msg, 0) = addr_src;
+	RPC_U32(&msg, 4) = addr_dst;
+	RPC_U32(&msg, 8) = len;
+	RPC_U8(&msg, 12) = (uint8_t)fw;
+	RPC_SIZE(&msg) = 5;
+
+	sc_call_rpc(ipc, &msg, false);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+

So, the same code with mailbox framework will be some thing like this:

	/* Write remaining words */
	while (count < msg->size) {
		mbox_send_message(sc_ipc->mbox_chan[count % MU_TR_COUNT],
msg->DATA.u32[count - 1]);
		count++;
	}

to provide identical behavior we should set mbox_client->tx_block = true
and implement polling mode in the mailbox driver.

Please note. I don't think sc_ipc_write() implementation is good. I just
don't expect it will be ever changed.

> Shouldn't your MU-using driver be a separate node which references the
> MU by phandle? Like in this patch:

sure. But it is generic, not mailbox controller specific and make no
sense to describe client binding again in the controller binding.

> https://patchwork.kernel.org/patch/10468887/
> 
>> diff --git a/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> new file mode 100644
>> index 000000000000..1577b86f1206
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mailbox/imx-mailbox.txt
>> @@ -0,0 +1,35 @@
>> +i.MX Messaging Unit
>> +===================
>> +
>> +The i.MX Messaging Unit (MU) contains two register sets: "A" and "B". In most
>> +cases they are accessible from all Processor Units. On one hand, at least for
>> +mailbox functionality, it makes no difference which application or processor is
>> +using which set of the MU. On other hand, the register sets for each of the MU
>> +parts are not identical.
>> +
>> +Required properties:
>> +- compatible :	Shell be one of:
>> +                    "fsl,imx7s-mu-a" and "fsl,imx7s-mu-b" for i.MX7S or i.MX7D
>> +- reg :		physical base address of the mailbox and length of
>> +		memory mapped region.
>> +- #mbox-cells:	Common mailbox binding property to identify the number
>> +		of cells required for the mailbox specifier. Should be 1.
>> +- interrupts :	The interrupt number
>> +- clocks     :  phandle to the input clock.
>> +
>> +Example:
>> +	mu0a: mailbox at 30aa0000 {
>> +		compatible = "fsl,imx7s-mu-a";
>> +		reg = <0x30aa0000 0x28>;
>> +		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};
>> +
>> +	mu0b: mailbox at 30ab0000 {
>> +		compatible = "fsl,imx7s-mu-b";
>> +		reg = <0x30ab0000 0x28>;
>> +		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&clks IMX7D_MU_ROOT_CLK>;
>> +		#mbox-cells = <1>;
>> +	};

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

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-06-26 10:09     ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 10:09 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
> 
> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
> 
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
> 
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST
> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> 
>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> 
> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> 
>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val = imx_mu_read(priv, offs);
> +	val &= ~clr;
> +	val |= set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan = p;
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {

I'm wondering whether this can work properly for multi consumers
at the same time. 
Because xSR_TEn is 1 by default and four virtual channels actually
are using the same interrupt. That means channel 1 interrupt may
cause channel 2 believe it's txdone.
Have we tested such using?

> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 val;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 *arg = data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}

Since Sascha is requesting to write a generic MU mailbox driver for both
SCU MU and M4 case, the current way using virtual channels in this patch
only send one word a time obviously can't fit for SCU MU clients well.
Do you think if we can refer to TI case to design a generic data transfer
protocol to allow send multi words which is more close to SCU?
include/linux/soc/ti/ti-msgmgr.h
struct ti_msgmgr_message {
        size_t len;
        u8 *buf;
};  

Or we try to support both type transfer protocols in this driver?
That may introduce much complexities, personally I'm not quite
like that.

Regards
Dong Aisheng

> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	int ret;
> +
> +	ret = request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);
> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops = {
> +	.send_data = imx_mu_send_data,
> +	.startup = imx_mu_startup,
> +	.shutdown = imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg = of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg = dcfg;
> +	priv->dev = dev;
> +
> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> +			priv->clk = NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");
> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i = 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> +
> +		cp->bidx = 3 - i;
> +		cp->idx = i;
> +		cp->irq = irq;
> +		priv->mbox_chans[i].con_priv = cp;
> +	}
> +
> +	priv->mbox.dev = dev;
> +	priv->mbox.ops = &imx_mu_ops;
> +	priv->mbox.chans = priv->mbox_chans;
> +	priv->mbox.num_chans = chans;
> +	priv->mbox.txdone_irq = true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);
> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> +	.chans = IMX_MU_MAX_CHANS,
> +	.init_hw = imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> +	.chans = IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] = {
> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver = {
> +	.probe		= imx_mu_probe,
> +	.remove		= imx_mu_remove,
> +	.driver = {
> +		.name	= "imx_mu",
> +		.of_match_table = imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 10:09     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 10:09 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, linux-arm-kernel, devicetree, linux-clk, dl-linux-imx

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>=20
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
>=20
> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
>=20
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
>=20
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
>=20
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST
> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+=3D mailbox-test.o
>=20
>  obj-$(CONFIG_ARM_MHU)	+=3D arm_mhu.o
>=20
> +obj-$(CONFIG_IMX_MBOX)	+=3D imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+=3D platform_mhu.o
>=20
>  obj-$(CONFIG_PL320_MBOX)	+=3D pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.=
c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val =3D imx_mu_read(priv, offs);
> +	val &=3D ~clr;
> +	val |=3D set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan =3D p;
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> +	val &=3D IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {

I'm wondering whether this can work properly for multi consumers
at the same time.=20
Because xSR_TEn is 1 by default and four virtual channels actually
are using the same interrupt. That means channel 1 interrupt may
cause channel 2 believe it's txdone.
Have we tested such using?

> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat =3D imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	u32 val;
> +
> +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	u32 *arg =3D data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}

Since Sascha is requesting to write a generic MU mailbox driver for both
SCU MU and M4 case, the current way using virtual channels in this patch
only send one word a time obviously can't fit for SCU MU clients well.
Do you think if we can refer to TI case to design a generic data transfer
protocol to allow send multi words which is more close to SCU?
include/linux/soc/ti/ti-msgmgr.h
struct ti_msgmgr_message {
        size_t len;
        u8 *buf;
}; =20

Or we try to support both type transfer protocols in this driver?
That may introduce much complexities, personally I'm not quite
like that.

Regards
Dong Aisheng

> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	int ret;
> +
> +	ret =3D request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);
> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops =3D {
> +	.send_data =3D imx_mu_send_data,
> +	.startup =3D imx_mu_startup,
> +	.shutdown =3D imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev =3D &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg =3D of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg =3D dcfg;
> +	priv->dev =3D dev;
> +
> +	iomem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base =3D devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq =3D platform_get_irq(pdev, 0);
> +	if (irq <=3D 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk =3D devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) =3D=3D -ENOENT) {
> +			priv->clk =3D NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");
> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret =3D clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans =3D min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i =3D 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp =3D &priv->con_priv[i];
> +
> +		cp->bidx =3D 3 - i;
> +		cp->idx =3D i;
> +		cp->irq =3D irq;
> +		priv->mbox_chans[i].con_priv =3D cp;
> +	}
> +
> +	priv->mbox.dev =3D dev;
> +	priv->mbox.ops =3D &imx_mu_ops;
> +	priv->mbox.chans =3D priv->mbox_chans;
> +	priv->mbox.num_chans =3D chans;
> +	priv->mbox.txdone_irq =3D true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv =3D platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);
> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a =3D {
> +	.chans =3D IMX_MU_MAX_CHANS,
> +	.init_hw =3D imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b =3D {
> +	.chans =3D IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] =3D {
> +	{ .compatible =3D "fsl,imx7s-mu-a", .data =3D &imx_mu_cfg_imx7d_a },
> +	{ .compatible =3D "fsl,imx7s-mu-b", .data =3D &imx_mu_cfg_imx7d_b },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver =3D {
> +	.probe		=3D imx_mu_probe,
> +	.remove		=3D imx_mu_remove,
> +	.driver =3D {
> +		.name	=3D "imx_mu",
> +		.of_match_table =3D imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1


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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 10:09     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 10:09 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org; linux-
> clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
> 
> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
> 
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
> 
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST
> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> 
>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> 
> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> 
>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val = imx_mu_read(priv, offs);
> +	val &= ~clr;
> +	val |= set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan = p;
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {

I'm wondering whether this can work properly for multi consumers
at the same time. 
Because xSR_TEn is 1 by default and four virtual channels actually
are using the same interrupt. That means channel 1 interrupt may
cause channel 2 believe it's txdone.
Have we tested such using?

> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 val;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 *arg = data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}

Since Sascha is requesting to write a generic MU mailbox driver for both
SCU MU and M4 case, the current way using virtual channels in this patch
only send one word a time obviously can't fit for SCU MU clients well.
Do you think if we can refer to TI case to design a generic data transfer
protocol to allow send multi words which is more close to SCU?
include/linux/soc/ti/ti-msgmgr.h
struct ti_msgmgr_message {
        size_t len;
        u8 *buf;
};  

Or we try to support both type transfer protocols in this driver?
That may introduce much complexities, personally I'm not quite
like that.

Regards
Dong Aisheng

> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	int ret;
> +
> +	ret = request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);
> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops = {
> +	.send_data = imx_mu_send_data,
> +	.startup = imx_mu_startup,
> +	.shutdown = imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg = of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg = dcfg;
> +	priv->dev = dev;
> +
> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> +			priv->clk = NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");
> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i = 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> +
> +		cp->bidx = 3 - i;
> +		cp->idx = i;
> +		cp->irq = irq;
> +		priv->mbox_chans[i].con_priv = cp;
> +	}
> +
> +	priv->mbox.dev = dev;
> +	priv->mbox.ops = &imx_mu_ops;
> +	priv->mbox.chans = priv->mbox_chans;
> +	priv->mbox.num_chans = chans;
> +	priv->mbox.txdone_irq = true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);
> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> +	.chans = IMX_MU_MAX_CHANS,
> +	.init_hw = imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> +	.chans = IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] = {
> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver = {
> +	.probe		= imx_mu_probe,
> +	.remove		= imx_mu_remove,
> +	.driver = {
> +		.name	= "imx_mu",
> +		.of_match_table = imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-26 10:09     ` A.s. Dong
  (?)
@ 2018-06-26 10:56       ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-26 10:56 UTC (permalink / raw)
  To: A.s. Dong, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, devicetree, dl-linux-imx, linux-arm-kernel, linux-clk


[-- Attachment #1.1.1: Type: text/plain, Size: 12193 bytes --]



On 26.06.2018 12:09, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>> Sent: Friday, June 15, 2018 5:51 PM
>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
>> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>> The Mailbox controller is able to send messages (up to 4 32 bit words)
>> between the endpoints.
>>
>> This driver was tested using the mailbox-test driver sending messages
>> between the Cortex-A7 and the Cortex-M4.
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  drivers/mailbox/Kconfig       |   6 +
>>  drivers/mailbox/Makefile      |   2 +
>>  drivers/mailbox/imx-mailbox.c | 288
>> ++++++++++++++++++++++++++++++++++
>>  3 files changed, 296 insertions(+)
>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>
>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>> a2bb27446dce..e1d2738a2e4c 100644
>> --- a/drivers/mailbox/Kconfig
>> +++ b/drivers/mailbox/Kconfig
>> @@ -15,6 +15,12 @@ config ARM_MHU
>>  	  The controller has 3 mailbox channels, the last of which can be
>>  	  used in Secure mode only.
>>
>> +config IMX_MBOX
>> +	tristate "iMX Mailbox"
>> +	depends on SOC_IMX7D || COMPILE_TEST
>> +	help
>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>> +
>>  config PLATFORM_MHU
>>  	tristate "Platform MHU Mailbox"
>>  	depends on OF
>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
>> cc23c3a43fcd..ba2fe1b6dd62 100644
>> --- a/drivers/mailbox/Makefile
>> +++ b/drivers/mailbox/Makefile
>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>
>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>
>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>> +
>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>
>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
>> new file mode 100644 index 000000000000..e3f621cb1d30
>> --- /dev/null
>> +++ b/drivers/mailbox/imx-mailbox.c
>> @@ -0,0 +1,288 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>> +<o.rempel@pengutronix.de>  */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mailbox_controller.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +
>> +/* Transmit Register */
>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>> +/* Receive Register */
>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>> +/* Status Register */
>> +#define IMX_MU_xSR		0x20
>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>> +
>> +/* Control Register */
>> +#define IMX_MU_xCR		0x24
>> +/* Transmit Interrupt Enable */
>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>> +/* Receive Interrupt Enable */
>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>> +
>> +#define IMX_MU_MAX_CHANS	4u
>> +
>> +struct imx_mu_priv;
>> +
>> +struct imx_mu_cfg {
>> +	unsigned int		chans;
>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>> +
>> +struct imx_mu_con_priv {
>> +	int			irq;
>> +	unsigned int		bidx;
>> +	unsigned int		idx;
>> +};
>> +
>> +struct imx_mu_priv {
>> +	struct device		*dev;
>> +	const struct imx_mu_cfg	*dcfg;
>> +	void __iomem		*base;
>> +
>> +	struct mbox_controller	mbox;
>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>> +
>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>> +	struct clk		*clk;
>> +};
>> +
>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
>> +{
>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>> +
>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>> +	iowrite32(val, priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>> +	return ioread32(priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
>> +clr) {
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, offs);
>> +	val &= ~clr;
>> +	val |= set;
>> +	imx_mu_write(priv, val, offs);
>> +
>> +	return val;
>> +}
>> +
>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>> +	struct mbox_chan *chan = p;
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	u32 val, dat;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>> +	if (!val)
>> +		return IRQ_NONE;
>> +
>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> 
> I'm wondering whether this can work properly for multi consumers
> at the same time. 
> Because xSR_TEn is 1 by default and four virtual channels actually
> are using the same interrupt. That means channel 1 interrupt may
> cause channel 2 believe it's txdone.
> Have we tested such using?

see imx_mu_send_data()
..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);

> 
>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>> bidx));

and here ^^^
TX status is enabled only for send and disabled as soon at transfer is done.

>> +		mbox_chan_txdone(chan, 0);
>> +	}
>> +
>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>> +		mbox_chan_received_data(chan, (void *)&dat);
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	/* test if transmit register is empty */
>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>> +
>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 *arg = data;
>> +
>> +	if (!imx_mu_last_tx_done(chan))
>> +		return -EBUSY;
>> +
>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
> 
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?

According to your code, you are able to send 1 word message. It means,
your SCU is configured to trigger an interrupt or status update if REG0
was written. The same is true for 2, 3, 4 and 5 word messages.

If the MU configuration would look like you it described, you would be
forced to write always 4 words, even for 1 word message.

> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?

Sure. ti-msgmgr.c is a good example. You will probably need reduced
variant of it. It is generic enough to make it useful not only for SCU.

> That may introduce much complexities, personally I'm not quite
> like that.

I expect 50-150 lines of extra code.

> Regards
> Dong Aisheng
> 
>> +
>> +static int imx_mu_startup(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	int ret;
>> +
>> +	ret = request_irq(cp->irq, imx_mu_isr,
>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>> +	if (ret) {
>> +		dev_err(chan->mbox->dev,
>> +			"Unable to acquire IRQ %d\n", cp->irq);
>> +		return ret;
>> +	}
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>> bidx));
>> +
>> +	free_irq(cp->irq, chan);
>> +}
>> +
>> +static const struct mbox_chan_ops imx_mu_ops = {
>> +	.send_data = imx_mu_send_data,
>> +	.startup = imx_mu_startup,
>> +	.shutdown = imx_mu_shutdown,
>> +};
>> +
>> +static int imx_mu_probe(struct platform_device *pdev) {
>> +	struct device *dev = &pdev->dev;
>> +	struct resource *iomem;
>> +	struct imx_mu_priv *priv;
>> +	const struct imx_mu_cfg *dcfg;
>> +	unsigned int i, chans;
>> +	int irq, ret;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	dcfg = of_device_get_match_data(dev);
>> +	if (!dcfg)
>> +		return -EINVAL;
>> +
>> +	priv->dcfg = dcfg;
>> +	priv->dev = dev;
>> +
>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>> +	if (IS_ERR(priv->base))
>> +		return PTR_ERR(priv->base);
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq <= 0)
>> +		return irq < 0 ? irq : -EINVAL;
>> +
>> +	priv->clk = devm_clk_get(dev, NULL);
>> +	if (IS_ERR(priv->clk)) {
>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>> +			priv->clk = NULL;
>> +		} else {
>> +			dev_err(dev, "Failed to get clock\n");
>> +			return PTR_ERR(priv->clk);
>> +		}
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->clk);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to enable clock\n");
>> +		return ret;
>> +	}
>> +
>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>> +	/* Initialize channel identifiers */
>> +	for (i = 0; i < chans; i++) {
>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>> +
>> +		cp->bidx = 3 - i;
>> +		cp->idx = i;
>> +		cp->irq = irq;
>> +		priv->mbox_chans[i].con_priv = cp;
>> +	}
>> +
>> +	priv->mbox.dev = dev;
>> +	priv->mbox.ops = &imx_mu_ops;
>> +	priv->mbox.chans = priv->mbox_chans;
>> +	priv->mbox.num_chans = chans;
>> +	priv->mbox.txdone_irq = true;
>> +
>> +	platform_set_drvdata(pdev, priv);
>> +
>> +	if (priv->dcfg->init_hw)
>> +		priv->dcfg->init_hw(priv);
>> +
>> +	return mbox_controller_register(&priv->mbox);
>> +}
>> +
>> +static int imx_mu_remove(struct platform_device *pdev) {
>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>> +
>> +	mbox_controller_unregister(&priv->mbox);
>> +	clk_disable_unprepare(priv->clk);
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>> +	/* Set default config */
>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>> +}
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +	.init_hw = imx_mu_init_imx7d_a,
>> +};
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +};
>> +
>> +static const struct of_device_id imx_mu_dt_ids[] = {
>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>> +
>> +static struct platform_driver imx_mu_driver = {
>> +	.probe		= imx_mu_probe,
>> +	.remove		= imx_mu_remove,
>> +	.driver = {
>> +		.name	= "imx_mu",
>> +		.of_match_table = imx_mu_dt_ids,
>> +	},
>> +};
>> +module_platform_driver(imx_mu_driver);
>> +
>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>> MODULE_LICENSE("GPL
>> +v2");
>> --
>> 2.17.1
> 
> 
> 


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 10:56       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-26 10:56 UTC (permalink / raw)
  To: A.s. Dong, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk


[-- Attachment #1.1: Type: text/plain, Size: 12193 bytes --]



On 26.06.2018 12:09, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>> Sent: Friday, June 15, 2018 5:51 PM
>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
>> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>> The Mailbox controller is able to send messages (up to 4 32 bit words)
>> between the endpoints.
>>
>> This driver was tested using the mailbox-test driver sending messages
>> between the Cortex-A7 and the Cortex-M4.
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  drivers/mailbox/Kconfig       |   6 +
>>  drivers/mailbox/Makefile      |   2 +
>>  drivers/mailbox/imx-mailbox.c | 288
>> ++++++++++++++++++++++++++++++++++
>>  3 files changed, 296 insertions(+)
>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>
>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>> a2bb27446dce..e1d2738a2e4c 100644
>> --- a/drivers/mailbox/Kconfig
>> +++ b/drivers/mailbox/Kconfig
>> @@ -15,6 +15,12 @@ config ARM_MHU
>>  	  The controller has 3 mailbox channels, the last of which can be
>>  	  used in Secure mode only.
>>
>> +config IMX_MBOX
>> +	tristate "iMX Mailbox"
>> +	depends on SOC_IMX7D || COMPILE_TEST
>> +	help
>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>> +
>>  config PLATFORM_MHU
>>  	tristate "Platform MHU Mailbox"
>>  	depends on OF
>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
>> cc23c3a43fcd..ba2fe1b6dd62 100644
>> --- a/drivers/mailbox/Makefile
>> +++ b/drivers/mailbox/Makefile
>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>
>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>
>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>> +
>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>
>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
>> new file mode 100644 index 000000000000..e3f621cb1d30
>> --- /dev/null
>> +++ b/drivers/mailbox/imx-mailbox.c
>> @@ -0,0 +1,288 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>> +<o.rempel@pengutronix.de>  */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mailbox_controller.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +
>> +/* Transmit Register */
>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>> +/* Receive Register */
>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>> +/* Status Register */
>> +#define IMX_MU_xSR		0x20
>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>> +
>> +/* Control Register */
>> +#define IMX_MU_xCR		0x24
>> +/* Transmit Interrupt Enable */
>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>> +/* Receive Interrupt Enable */
>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>> +
>> +#define IMX_MU_MAX_CHANS	4u
>> +
>> +struct imx_mu_priv;
>> +
>> +struct imx_mu_cfg {
>> +	unsigned int		chans;
>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>> +
>> +struct imx_mu_con_priv {
>> +	int			irq;
>> +	unsigned int		bidx;
>> +	unsigned int		idx;
>> +};
>> +
>> +struct imx_mu_priv {
>> +	struct device		*dev;
>> +	const struct imx_mu_cfg	*dcfg;
>> +	void __iomem		*base;
>> +
>> +	struct mbox_controller	mbox;
>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>> +
>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>> +	struct clk		*clk;
>> +};
>> +
>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
>> +{
>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>> +
>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>> +	iowrite32(val, priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>> +	return ioread32(priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
>> +clr) {
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, offs);
>> +	val &= ~clr;
>> +	val |= set;
>> +	imx_mu_write(priv, val, offs);
>> +
>> +	return val;
>> +}
>> +
>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>> +	struct mbox_chan *chan = p;
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	u32 val, dat;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>> +	if (!val)
>> +		return IRQ_NONE;
>> +
>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> 
> I'm wondering whether this can work properly for multi consumers
> at the same time. 
> Because xSR_TEn is 1 by default and four virtual channels actually
> are using the same interrupt. That means channel 1 interrupt may
> cause channel 2 believe it's txdone.
> Have we tested such using?

see imx_mu_send_data()
..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);

> 
>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>> bidx));

and here ^^^
TX status is enabled only for send and disabled as soon at transfer is done.

>> +		mbox_chan_txdone(chan, 0);
>> +	}
>> +
>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>> +		mbox_chan_received_data(chan, (void *)&dat);
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	/* test if transmit register is empty */
>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>> +
>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 *arg = data;
>> +
>> +	if (!imx_mu_last_tx_done(chan))
>> +		return -EBUSY;
>> +
>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
> 
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?

According to your code, you are able to send 1 word message. It means,
your SCU is configured to trigger an interrupt or status update if REG0
was written. The same is true for 2, 3, 4 and 5 word messages.

If the MU configuration would look like you it described, you would be
forced to write always 4 words, even for 1 word message.

> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?

Sure. ti-msgmgr.c is a good example. You will probably need reduced
variant of it. It is generic enough to make it useful not only for SCU.

> That may introduce much complexities, personally I'm not quite
> like that.

I expect 50-150 lines of extra code.

> Regards
> Dong Aisheng
> 
>> +
>> +static int imx_mu_startup(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	int ret;
>> +
>> +	ret = request_irq(cp->irq, imx_mu_isr,
>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>> +	if (ret) {
>> +		dev_err(chan->mbox->dev,
>> +			"Unable to acquire IRQ %d\n", cp->irq);
>> +		return ret;
>> +	}
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>> bidx));
>> +
>> +	free_irq(cp->irq, chan);
>> +}
>> +
>> +static const struct mbox_chan_ops imx_mu_ops = {
>> +	.send_data = imx_mu_send_data,
>> +	.startup = imx_mu_startup,
>> +	.shutdown = imx_mu_shutdown,
>> +};
>> +
>> +static int imx_mu_probe(struct platform_device *pdev) {
>> +	struct device *dev = &pdev->dev;
>> +	struct resource *iomem;
>> +	struct imx_mu_priv *priv;
>> +	const struct imx_mu_cfg *dcfg;
>> +	unsigned int i, chans;
>> +	int irq, ret;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	dcfg = of_device_get_match_data(dev);
>> +	if (!dcfg)
>> +		return -EINVAL;
>> +
>> +	priv->dcfg = dcfg;
>> +	priv->dev = dev;
>> +
>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>> +	if (IS_ERR(priv->base))
>> +		return PTR_ERR(priv->base);
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq <= 0)
>> +		return irq < 0 ? irq : -EINVAL;
>> +
>> +	priv->clk = devm_clk_get(dev, NULL);
>> +	if (IS_ERR(priv->clk)) {
>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>> +			priv->clk = NULL;
>> +		} else {
>> +			dev_err(dev, "Failed to get clock\n");
>> +			return PTR_ERR(priv->clk);
>> +		}
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->clk);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to enable clock\n");
>> +		return ret;
>> +	}
>> +
>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>> +	/* Initialize channel identifiers */
>> +	for (i = 0; i < chans; i++) {
>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>> +
>> +		cp->bidx = 3 - i;
>> +		cp->idx = i;
>> +		cp->irq = irq;
>> +		priv->mbox_chans[i].con_priv = cp;
>> +	}
>> +
>> +	priv->mbox.dev = dev;
>> +	priv->mbox.ops = &imx_mu_ops;
>> +	priv->mbox.chans = priv->mbox_chans;
>> +	priv->mbox.num_chans = chans;
>> +	priv->mbox.txdone_irq = true;
>> +
>> +	platform_set_drvdata(pdev, priv);
>> +
>> +	if (priv->dcfg->init_hw)
>> +		priv->dcfg->init_hw(priv);
>> +
>> +	return mbox_controller_register(&priv->mbox);
>> +}
>> +
>> +static int imx_mu_remove(struct platform_device *pdev) {
>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>> +
>> +	mbox_controller_unregister(&priv->mbox);
>> +	clk_disable_unprepare(priv->clk);
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>> +	/* Set default config */
>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>> +}
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +	.init_hw = imx_mu_init_imx7d_a,
>> +};
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +};
>> +
>> +static const struct of_device_id imx_mu_dt_ids[] = {
>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>> +
>> +static struct platform_driver imx_mu_driver = {
>> +	.probe		= imx_mu_probe,
>> +	.remove		= imx_mu_remove,
>> +	.driver = {
>> +		.name	= "imx_mu",
>> +		.of_match_table = imx_mu_dt_ids,
>> +	},
>> +};
>> +module_platform_driver(imx_mu_driver);
>> +
>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>> MODULE_LICENSE("GPL
>> +v2");
>> --
>> 2.17.1
> 
> 
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 10:56       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-06-26 10:56 UTC (permalink / raw)
  To: linux-arm-kernel



On 26.06.2018 12:09, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
>> Sent: Friday, June 15, 2018 5:51 PM
>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
>> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org; linux-
>> clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>> The Mailbox controller is able to send messages (up to 4 32 bit words)
>> between the endpoints.
>>
>> This driver was tested using the mailbox-test driver sending messages
>> between the Cortex-A7 and the Cortex-M4.
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
>>  drivers/mailbox/Kconfig       |   6 +
>>  drivers/mailbox/Makefile      |   2 +
>>  drivers/mailbox/imx-mailbox.c | 288
>> ++++++++++++++++++++++++++++++++++
>>  3 files changed, 296 insertions(+)
>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>
>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>> a2bb27446dce..e1d2738a2e4c 100644
>> --- a/drivers/mailbox/Kconfig
>> +++ b/drivers/mailbox/Kconfig
>> @@ -15,6 +15,12 @@ config ARM_MHU
>>  	  The controller has 3 mailbox channels, the last of which can be
>>  	  used in Secure mode only.
>>
>> +config IMX_MBOX
>> +	tristate "iMX Mailbox"
>> +	depends on SOC_IMX7D || COMPILE_TEST
>> +	help
>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>> +
>>  config PLATFORM_MHU
>>  	tristate "Platform MHU Mailbox"
>>  	depends on OF
>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
>> cc23c3a43fcd..ba2fe1b6dd62 100644
>> --- a/drivers/mailbox/Makefile
>> +++ b/drivers/mailbox/Makefile
>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>
>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>
>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>> +
>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>
>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
>> new file mode 100644 index 000000000000..e3f621cb1d30
>> --- /dev/null
>> +++ b/drivers/mailbox/imx-mailbox.c
>> @@ -0,0 +1,288 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>> +<o.rempel@pengutronix.de>  */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mailbox_controller.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +
>> +/* Transmit Register */
>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>> +/* Receive Register */
>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>> +/* Status Register */
>> +#define IMX_MU_xSR		0x20
>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>> +
>> +/* Control Register */
>> +#define IMX_MU_xCR		0x24
>> +/* Transmit Interrupt Enable */
>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>> +/* Receive Interrupt Enable */
>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>> +
>> +#define IMX_MU_MAX_CHANS	4u
>> +
>> +struct imx_mu_priv;
>> +
>> +struct imx_mu_cfg {
>> +	unsigned int		chans;
>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>> +
>> +struct imx_mu_con_priv {
>> +	int			irq;
>> +	unsigned int		bidx;
>> +	unsigned int		idx;
>> +};
>> +
>> +struct imx_mu_priv {
>> +	struct device		*dev;
>> +	const struct imx_mu_cfg	*dcfg;
>> +	void __iomem		*base;
>> +
>> +	struct mbox_controller	mbox;
>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>> +
>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>> +	struct clk		*clk;
>> +};
>> +
>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
>> +{
>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>> +
>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>> +	iowrite32(val, priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>> +	return ioread32(priv->base + offs);
>> +}
>> +
>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
>> +clr) {
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, offs);
>> +	val &= ~clr;
>> +	val |= set;
>> +	imx_mu_write(priv, val, offs);
>> +
>> +	return val;
>> +}
>> +
>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>> +	struct mbox_chan *chan = p;
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	u32 val, dat;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>> +	if (!val)
>> +		return IRQ_NONE;
>> +
>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> 
> I'm wondering whether this can work properly for multi consumers
> at the same time. 
> Because xSR_TEn is 1 by default and four virtual channels actually
> are using the same interrupt. That means channel 1 interrupt may
> cause channel 2 believe it's txdone.
> Have we tested such using?

see imx_mu_send_data()
..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);

> 
>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>> bidx));

and here ^^^
TX status is enabled only for send and disabled as soon at transfer is done.

>> +		mbox_chan_txdone(chan, 0);
>> +	}
>> +
>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>> +		mbox_chan_received_data(chan, (void *)&dat);
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 val;
>> +
>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>> +	/* test if transmit register is empty */
>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>> +
>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	u32 *arg = data;
>> +
>> +	if (!imx_mu_last_tx_done(chan))
>> +		return -EBUSY;
>> +
>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
> 
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?

According to your code, you are able to send 1 word message. It means,
your SCU is configured to trigger an interrupt or status update if REG0
was written. The same is true for 2, 3, 4 and 5 word messages.

If the MU configuration would look like you it described, you would be
forced to write always 4 words, even for 1 word message.

> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?

Sure. ti-msgmgr.c is a good example. You will probably need reduced
variant of it. It is generic enough to make it useful not only for SCU.

> That may introduce much complexities, personally I'm not quite
> like that.

I expect 50-150 lines of extra code.

> Regards
> Dong Aisheng
> 
>> +
>> +static int imx_mu_startup(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +	int ret;
>> +
>> +	ret = request_irq(cp->irq, imx_mu_isr,
>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>> +	if (ret) {
>> +		dev_err(chan->mbox->dev,
>> +			"Unable to acquire IRQ %d\n", cp->irq);
>> +		return ret;
>> +	}
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>> +
>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>> bidx));
>> +
>> +	free_irq(cp->irq, chan);
>> +}
>> +
>> +static const struct mbox_chan_ops imx_mu_ops = {
>> +	.send_data = imx_mu_send_data,
>> +	.startup = imx_mu_startup,
>> +	.shutdown = imx_mu_shutdown,
>> +};
>> +
>> +static int imx_mu_probe(struct platform_device *pdev) {
>> +	struct device *dev = &pdev->dev;
>> +	struct resource *iomem;
>> +	struct imx_mu_priv *priv;
>> +	const struct imx_mu_cfg *dcfg;
>> +	unsigned int i, chans;
>> +	int irq, ret;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	dcfg = of_device_get_match_data(dev);
>> +	if (!dcfg)
>> +		return -EINVAL;
>> +
>> +	priv->dcfg = dcfg;
>> +	priv->dev = dev;
>> +
>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>> +	if (IS_ERR(priv->base))
>> +		return PTR_ERR(priv->base);
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq <= 0)
>> +		return irq < 0 ? irq : -EINVAL;
>> +
>> +	priv->clk = devm_clk_get(dev, NULL);
>> +	if (IS_ERR(priv->clk)) {
>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>> +			priv->clk = NULL;
>> +		} else {
>> +			dev_err(dev, "Failed to get clock\n");
>> +			return PTR_ERR(priv->clk);
>> +		}
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->clk);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to enable clock\n");
>> +		return ret;
>> +	}
>> +
>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>> +	/* Initialize channel identifiers */
>> +	for (i = 0; i < chans; i++) {
>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>> +
>> +		cp->bidx = 3 - i;
>> +		cp->idx = i;
>> +		cp->irq = irq;
>> +		priv->mbox_chans[i].con_priv = cp;
>> +	}
>> +
>> +	priv->mbox.dev = dev;
>> +	priv->mbox.ops = &imx_mu_ops;
>> +	priv->mbox.chans = priv->mbox_chans;
>> +	priv->mbox.num_chans = chans;
>> +	priv->mbox.txdone_irq = true;
>> +
>> +	platform_set_drvdata(pdev, priv);
>> +
>> +	if (priv->dcfg->init_hw)
>> +		priv->dcfg->init_hw(priv);
>> +
>> +	return mbox_controller_register(&priv->mbox);
>> +}
>> +
>> +static int imx_mu_remove(struct platform_device *pdev) {
>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>> +
>> +	mbox_controller_unregister(&priv->mbox);
>> +	clk_disable_unprepare(priv->clk);
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>> +	/* Set default config */
>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>> +}
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +	.init_hw = imx_mu_init_imx7d_a,
>> +};
>> +
>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>> +	.chans = IMX_MU_MAX_CHANS,
>> +};
>> +
>> +static const struct of_device_id imx_mu_dt_ids[] = {
>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>> +
>> +static struct platform_driver imx_mu_driver = {
>> +	.probe		= imx_mu_probe,
>> +	.remove		= imx_mu_remove,
>> +	.driver = {
>> +		.name	= "imx_mu",
>> +		.of_match_table = imx_mu_dt_ids,
>> +	},
>> +};
>> +module_platform_driver(imx_mu_driver);
>> +
>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>> MODULE_LICENSE("GPL
>> +v2");
>> --
>> 2.17.1
> 
> 
> 

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

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-26 10:56       ` Oleksij Rempel
  (?)
@ 2018-06-26 12:07         ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 12:07 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, devicetree, dl-linux-imx, linux-arm-kernel, linux-clk

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Tuesday, June 26, 2018 6:56 PM
> To: A.s. Dong <aisheng.dong@nxp.com>; Shawn Guo
> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>
> Cc: devicetree@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-
> arm-kernel@lists.infradead.org; kernel@pengutronix.de; linux-
> clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> 
> 
> On 26.06.2018 12:09, A.s. Dong wrote:
> >> -----Original Message-----
> >> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> >> Sent: Friday, June 15, 2018 5:51 PM
> >> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> >> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> >> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> >> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> >> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> >> linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> >> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> >> unit
> >>
> >> The Mailbox controller is able to send messages (up to 4 32 bit
> >> words) between the endpoints.
> >>
> >> This driver was tested using the mailbox-test driver sending messages
> >> between the Cortex-A7 and the Cortex-M4.
> >>
> >> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> >> ---
> >>  drivers/mailbox/Kconfig       |   6 +
> >>  drivers/mailbox/Makefile      |   2 +
> >>  drivers/mailbox/imx-mailbox.c | 288
> >> ++++++++++++++++++++++++++++++++++
> >>  3 files changed, 296 insertions(+)
> >>  create mode 100644 drivers/mailbox/imx-mailbox.c
> >>
> >> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> >> a2bb27446dce..e1d2738a2e4c 100644
> >> --- a/drivers/mailbox/Kconfig
> >> +++ b/drivers/mailbox/Kconfig
> >> @@ -15,6 +15,12 @@ config ARM_MHU
> >>  	  The controller has 3 mailbox channels, the last of which can be
> >>  	  used in Secure mode only.
> >>
> >> +config IMX_MBOX
> >> +	tristate "iMX Mailbox"
> >> +	depends on SOC_IMX7D || COMPILE_TEST
> >> +	help
> >> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> >> +
> >>  config PLATFORM_MHU
> >>  	tristate "Platform MHU Mailbox"
> >>  	depends on OF
> >> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> >> index
> >> cc23c3a43fcd..ba2fe1b6dd62 100644
> >> --- a/drivers/mailbox/Makefile
> >> +++ b/drivers/mailbox/Makefile
> >> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> >>
> >>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> >>
> >> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> >> +
> >>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> >>
> >>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> >> diff --git a/drivers/mailbox/imx-mailbox.c
> >> b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> >> 000000000000..e3f621cb1d30
> >> --- /dev/null
> >> +++ b/drivers/mailbox/imx-mailbox.c
> >> @@ -0,0 +1,288 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> >> +<o.rempel@pengutronix.de>  */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/mailbox_controller.h> #include <linux/module.h>
> >> +#include <linux/of_device.h>
> >> +
> >> +/* Transmit Register */
> >> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> >> +/* Receive Register */
> >> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> >> +/* Status Register */
> >> +#define IMX_MU_xSR		0x20
> >> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> >> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> >> +#define IMX_MU_xSR_BRDIP	BIT(9)
> >> +
> >> +/* Control Register */
> >> +#define IMX_MU_xCR		0x24
> >> +/* Transmit Interrupt Enable */
> >> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> >> +/* Receive Interrupt Enable */
> >> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> >> +
> >> +#define IMX_MU_MAX_CHANS	4u
> >> +
> >> +struct imx_mu_priv;
> >> +
> >> +struct imx_mu_cfg {
> >> +	unsigned int		chans;
> >> +	void (*init_hw)(struct imx_mu_priv *priv); };
> >> +
> >> +struct imx_mu_con_priv {
> >> +	int			irq;
> >> +	unsigned int		bidx;
> >> +	unsigned int		idx;
> >> +};
> >> +
> >> +struct imx_mu_priv {
> >> +	struct device		*dev;
> >> +	const struct imx_mu_cfg	*dcfg;
> >> +	void __iomem		*base;
> >> +
> >> +	struct mbox_controller	mbox;
> >> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> >> +
> >> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> >> +	struct clk		*clk;
> >> +};
> >> +
> >> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> >> +*mbox) {
> >> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> >> +
> >> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> >> +	iowrite32(val, priv->base + offs);
> >> +}
> >> +
> >> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> >> +	return ioread32(priv->base + offs); }
> >> +
> >> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> >> +u32
> >> +clr) {
> >> +	u32 val;
> >> +
> >> +	val = imx_mu_read(priv, offs);
> >> +	val &= ~clr;
> >> +	val |= set;
> >> +	imx_mu_write(priv, val, offs);
> >> +
> >> +	return val;
> >> +}
> >> +
> >> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> >> +	struct mbox_chan *chan = p;
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +
> >> +	u32 val, dat;
> >> +
> >> +	val = imx_mu_read(priv, IMX_MU_xSR);
> >> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> >> +	if (!val)
> >> +		return IRQ_NONE;
> >> +
> >> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> >
> > I'm wondering whether this can work properly for multi consumers at
> > the same time.
> > Because xSR_TEn is 1 by default and four virtual channels actually are
> > using the same interrupt. That means channel 1 interrupt may cause
> > channel 2 believe it's txdone.
> > Have we tested such using?
> 
> see imx_mu_send_data()
> ..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> 
> >
> >> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >>> bidx));
> 
> and here ^^^
> TX status is enabled only for send and disabled as soon at transfer is done.
> 

That controls the interrupt enable signal, I'm not sure if the status bit
Won't be set if not enable interrupt. I've not tested it.

Have you double checked it?

For n = {0, 1, 2, 3} Processor A Transmit Register n Empty. (Read-only)
• The TEn bit is set to “1” after the BRRn register is read on the Processor B-side.
• After the TEn bit is set to “1”, the TEn bit signals the Processor A-side that the ATRn register is
ready to be written on the Processor A-side, and a Transmit n interrupt is issued on the Processor
A-side (if the TEn bit in the ACR register is set to “1”).
...

> >> +		mbox_chan_txdone(chan, 0);
> >> +	}
> >> +
> >> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> >> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> >> +		mbox_chan_received_data(chan, (void *)&dat);
> >> +	}
> >> +
> >> +	return IRQ_HANDLED;
> >> +}
> >> +
> >> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	u32 val;
> >> +
> >> +	val = imx_mu_read(priv, IMX_MU_xSR);
> >> +	/* test if transmit register is empty */
> >> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> >> +
> >> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	u32 *arg = data;
> >> +
> >> +	if (!imx_mu_last_tx_done(chan))
> >> +		return -EBUSY;
> >> +
> >> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> >> +
> >> +	return 0;
> >> +}
> >
> > Since Sascha is requesting to write a generic MU mailbox driver for
> > both SCU MU and M4 case, the current way using virtual channels in
> > this patch only send one word a time obviously can't fit for SCU MU clients
> well.
> > Do you think if we can refer to TI case to design a generic data
> > transfer protocol to allow send multi words which is more close to SCU?
> 
> According to your code, you are able to send 1 word message. It means, your
> SCU is configured to trigger an interrupt or status update if REG0 was written.
> The same is true for 2, 3, 4 and 5 word messages.
> 

SCU is interrupt driven already for the first word.
We do can send word one by one but the performance would be terrible
comparing to write 4 a time.

> If the MU configuration would look like you it described, you would be forced
> to write always 4 words, even for 1 word message.
> 
> > include/linux/soc/ti/ti-msgmgr.h
> > struct ti_msgmgr_message {
> >         size_t len;
> >         u8 *buf;
> > };
> >
> > Or we try to support both type transfer protocols in this driver?
> 
> Sure. ti-msgmgr.c is a good example. You will probably need reduced variant
> of it. It is generic enough to make it useful not only for SCU.
> 

Sascha needs a common design for both M4 and SCU.If decide to do that,
you probably need update this patch as well.

But even doing like TI style, it still need hack for SCU as the data size offset
Is different. However, that would be a much smaller hack than doing based
On this driver.

> > That may introduce much complexities, personally I'm not quite like
> > that.
> 
> I expect 50-150 lines of extra code.
> 

Hope that could be true.
Do you have suggestion on how to keep two type protocol co-exist
If you thought that would work without two much extra complexity?
Have you tried it already based this driver?

Regards
Dong Aisheng

> > Regards
> > Dong Aisheng
> >
> >> +
> >> +static int imx_mu_startup(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	int ret;
> >> +
> >> +	ret = request_irq(cp->irq, imx_mu_isr,
> >> +			  IRQF_SHARED, "imx_mu_chan", chan);
> >> +	if (ret) {
> >> +		dev_err(chan->mbox->dev,
> >> +			"Unable to acquire IRQ %d\n", cp->irq);
> >> +		return ret;
> >> +	}
> >> +
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> >> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >>> bidx));
> >> +
> >> +	free_irq(cp->irq, chan);
> >> +}
> >> +
> >> +static const struct mbox_chan_ops imx_mu_ops = {
> >> +	.send_data = imx_mu_send_data,
> >> +	.startup = imx_mu_startup,
> >> +	.shutdown = imx_mu_shutdown,
> >> +};
> >> +
> >> +static int imx_mu_probe(struct platform_device *pdev) {
> >> +	struct device *dev = &pdev->dev;
> >> +	struct resource *iomem;
> >> +	struct imx_mu_priv *priv;
> >> +	const struct imx_mu_cfg *dcfg;
> >> +	unsigned int i, chans;
> >> +	int irq, ret;
> >> +
> >> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >> +	if (!priv)
> >> +		return -ENOMEM;
> >> +
> >> +	dcfg = of_device_get_match_data(dev);
> >> +	if (!dcfg)
> >> +		return -EINVAL;
> >> +
> >> +	priv->dcfg = dcfg;
> >> +	priv->dev = dev;
> >> +
> >> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> >> +	if (IS_ERR(priv->base))
> >> +		return PTR_ERR(priv->base);
> >> +
> >> +	irq = platform_get_irq(pdev, 0);
> >> +	if (irq <= 0)
> >> +		return irq < 0 ? irq : -EINVAL;
> >> +
> >> +	priv->clk = devm_clk_get(dev, NULL);
> >> +	if (IS_ERR(priv->clk)) {
> >> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> >> +			priv->clk = NULL;
> >> +		} else {
> >> +			dev_err(dev, "Failed to get clock\n");
> >> +			return PTR_ERR(priv->clk);
> >> +		}
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(priv->clk);
> >> +	if (ret) {
> >> +		dev_err(dev, "Failed to enable clock\n");
> >> +		return ret;
> >> +	}
> >> +
> >> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> >> +	/* Initialize channel identifiers */
> >> +	for (i = 0; i < chans; i++) {
> >> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> >> +
> >> +		cp->bidx = 3 - i;
> >> +		cp->idx = i;
> >> +		cp->irq = irq;
> >> +		priv->mbox_chans[i].con_priv = cp;
> >> +	}
> >> +
> >> +	priv->mbox.dev = dev;
> >> +	priv->mbox.ops = &imx_mu_ops;
> >> +	priv->mbox.chans = priv->mbox_chans;
> >> +	priv->mbox.num_chans = chans;
> >> +	priv->mbox.txdone_irq = true;
> >> +
> >> +	platform_set_drvdata(pdev, priv);
> >> +
> >> +	if (priv->dcfg->init_hw)
> >> +		priv->dcfg->init_hw(priv);
> >> +
> >> +	return mbox_controller_register(&priv->mbox);
> >> +}
> >> +
> >> +static int imx_mu_remove(struct platform_device *pdev) {
> >> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> >> +
> >> +	mbox_controller_unregister(&priv->mbox);
> >> +	clk_disable_unprepare(priv->clk);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +
> >> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> >> +	/* Set default config */
> >> +	imx_mu_write(priv, 0, IMX_MU_xCR);
> >> +}
> >> +
> >> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> >> +	.chans = IMX_MU_MAX_CHANS,
> >> +	.init_hw = imx_mu_init_imx7d_a,
> >> +};
> >> +
> >> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> >> +	.chans = IMX_MU_MAX_CHANS,
> >> +};
> >> +
> >> +static const struct of_device_id imx_mu_dt_ids[] = {
> >> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> >> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> >> +	{ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> >> +
> >> +static struct platform_driver imx_mu_driver = {
> >> +	.probe		= imx_mu_probe,
> >> +	.remove		= imx_mu_remove,
> >> +	.driver = {
> >> +		.name	= "imx_mu",
> >> +		.of_match_table = imx_mu_dt_ids,
> >> +	},
> >> +};
> >> +module_platform_driver(imx_mu_driver);
> >> +
> >> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> >> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> >> MODULE_LICENSE("GPL
> >> +v2");
> >> --
> >> 2.17.1
> >
> >
> >

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 12:07         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 12:07 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk

PiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiBPbGVrc2lqIFJlbXBlbCBbbWFp
bHRvOm8ucmVtcGVsQHBlbmd1dHJvbml4LmRlXQ0KPiBTZW50OiBUdWVzZGF5LCBKdW5lIDI2LCAy
MDE4IDY6NTYgUE0NCj4gVG86IEEucy4gRG9uZyA8YWlzaGVuZy5kb25nQG54cC5jb20+OyBTaGF3
biBHdW8NCj4gPHNoYXduZ3VvQGtlcm5lbC5vcmc+OyBGYWJpbyBFc3RldmFtIDxmYWJpby5lc3Rl
dmFtQG54cC5jb20+OyBSb2INCj4gSGVycmluZyA8cm9iaCtkdEBrZXJuZWwub3JnPjsgTWFyayBS
dXRsYW5kIDxtYXJrLnJ1dGxhbmRAYXJtLmNvbT4NCj4gQ2M6IGRldmljZXRyZWVAdmdlci5rZXJu
ZWwub3JnOyBkbC1saW51eC1pbXggPGxpbnV4LWlteEBueHAuY29tPjsgbGludXgtDQo+IGFybS1r
ZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZzsga2VybmVsQHBlbmd1dHJvbml4LmRlOyBsaW51eC0N
Cj4gY2xrQHZnZXIua2VybmVsLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIHYyIDQvNF0gbWFp
bGJveDogQWRkIHN1cHBvcnQgZm9yIGkuTVg3RCBtZXNzYWdpbmcgdW5pdA0KPiANCj4gDQo+IA0K
PiBPbiAyNi4wNi4yMDE4IDEyOjA5LCBBLnMuIERvbmcgd3JvdGU6DQo+ID4+IC0tLS0tT3JpZ2lu
YWwgTWVzc2FnZS0tLS0tDQo+ID4+IEZyb206IE9sZWtzaWogUmVtcGVsIFttYWlsdG86by5yZW1w
ZWxAcGVuZ3V0cm9uaXguZGVdDQo+ID4+IFNlbnQ6IEZyaWRheSwgSnVuZSAxNSwgMjAxOCA1OjUx
IFBNDQo+ID4+IFRvOiBTaGF3biBHdW8gPHNoYXduZ3VvQGtlcm5lbC5vcmc+OyBGYWJpbyBFc3Rl
dmFtDQo+ID4+IDxmYWJpby5lc3RldmFtQG54cC5jb20+OyBSb2IgSGVycmluZyA8cm9iaCtkdEBr
ZXJuZWwub3JnPjsgTWFyaw0KPiA+PiBSdXRsYW5kIDxtYXJrLnJ1dGxhbmRAYXJtLmNvbT47IEEu
cy4gRG9uZyA8YWlzaGVuZy5kb25nQG54cC5jb20+DQo+ID4+IENjOiBPbGVrc2lqIFJlbXBlbCA8
by5yZW1wZWxAcGVuZ3V0cm9uaXguZGU+OyBrZXJuZWxAcGVuZ3V0cm9uaXguZGU7DQo+ID4+IGxp
bnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZzsgZGV2aWNldHJlZUB2Z2VyLmtlcm5l
bC5vcmc7DQo+ID4+IGxpbnV4LSBjbGtAdmdlci5rZXJuZWwub3JnOyBkbC1saW51eC1pbXggPGxp
bnV4LWlteEBueHAuY29tPg0KPiA+PiBTdWJqZWN0OiBbUEFUQ0ggdjIgNC80XSBtYWlsYm94OiBB
ZGQgc3VwcG9ydCBmb3IgaS5NWDdEIG1lc3NhZ2luZw0KPiA+PiB1bml0DQo+ID4+DQo+ID4+IFRo
ZSBNYWlsYm94IGNvbnRyb2xsZXIgaXMgYWJsZSB0byBzZW5kIG1lc3NhZ2VzICh1cCB0byA0IDMy
IGJpdA0KPiA+PiB3b3JkcykgYmV0d2VlbiB0aGUgZW5kcG9pbnRzLg0KPiA+Pg0KPiA+PiBUaGlz
IGRyaXZlciB3YXMgdGVzdGVkIHVzaW5nIHRoZSBtYWlsYm94LXRlc3QgZHJpdmVyIHNlbmRpbmcg
bWVzc2FnZXMNCj4gPj4gYmV0d2VlbiB0aGUgQ29ydGV4LUE3IGFuZCB0aGUgQ29ydGV4LU00Lg0K
PiA+Pg0KPiA+PiBTaWduZWQtb2ZmLWJ5OiBPbGVrc2lqIFJlbXBlbCA8by5yZW1wZWxAcGVuZ3V0
cm9uaXguZGU+DQo+ID4+IC0tLQ0KPiA+PiAgZHJpdmVycy9tYWlsYm94L0tjb25maWcgICAgICAg
fCAgIDYgKw0KPiA+PiAgZHJpdmVycy9tYWlsYm94L01ha2VmaWxlICAgICAgfCAgIDIgKw0KPiA+
PiAgZHJpdmVycy9tYWlsYm94L2lteC1tYWlsYm94LmMgfCAyODgNCj4gPj4gKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKw0KPiA+PiAgMyBmaWxlcyBjaGFuZ2VkLCAyOTYgaW5zZXJ0
aW9ucygrKQ0KPiA+PiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvbWFpbGJveC9pbXgtbWFp
bGJveC5jDQo+ID4+DQo+ID4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL21haWxib3gvS2NvbmZpZyBi
L2RyaXZlcnMvbWFpbGJveC9LY29uZmlnIGluZGV4DQo+ID4+IGEyYmIyNzQ0NmRjZS4uZTFkMjcz
OGEyZTRjIDEwMDY0NA0KPiA+PiAtLS0gYS9kcml2ZXJzL21haWxib3gvS2NvbmZpZw0KPiA+PiAr
KysgYi9kcml2ZXJzL21haWxib3gvS2NvbmZpZw0KPiA+PiBAQCAtMTUsNiArMTUsMTIgQEAgY29u
ZmlnIEFSTV9NSFUNCj4gPj4gIAkgIFRoZSBjb250cm9sbGVyIGhhcyAzIG1haWxib3ggY2hhbm5l
bHMsIHRoZSBsYXN0IG9mIHdoaWNoIGNhbiBiZQ0KPiA+PiAgCSAgdXNlZCBpbiBTZWN1cmUgbW9k
ZSBvbmx5Lg0KPiA+Pg0KPiA+PiArY29uZmlnIElNWF9NQk9YDQo+ID4+ICsJdHJpc3RhdGUgImlN
WCBNYWlsYm94Ig0KPiA+PiArCWRlcGVuZHMgb24gU09DX0lNWDdEIHx8IENPTVBJTEVfVEVTVA0K
PiA+PiArCWhlbHANCj4gPj4gKwkgIE1haWxib3ggaW1wbGVtZW50YXRpb24gZm9yIGlNWDdEIE1l
c3NhZ2luZyBVbml0IChNVSkuDQo+ID4+ICsNCj4gPj4gIGNvbmZpZyBQTEFURk9STV9NSFUNCj4g
Pj4gIAl0cmlzdGF0ZSAiUGxhdGZvcm0gTUhVIE1haWxib3giDQo+ID4+ICAJZGVwZW5kcyBvbiBP
Rg0KPiA+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tYWlsYm94L01ha2VmaWxlIGIvZHJpdmVycy9t
YWlsYm94L01ha2VmaWxlDQo+ID4+IGluZGV4DQo+ID4+IGNjMjNjM2E0M2ZjZC4uYmEyZmUxYjZk
ZDYyIDEwMDY0NA0KPiA+PiAtLS0gYS9kcml2ZXJzL21haWxib3gvTWFrZWZpbGUNCj4gPj4gKysr
IGIvZHJpdmVycy9tYWlsYm94L01ha2VmaWxlDQo+ID4+IEBAIC03LDYgKzcsOCBAQCBvYmotJChD
T05GSUdfTUFJTEJPWF9URVNUKQkrPSBtYWlsYm94LXRlc3Qubw0KPiA+Pg0KPiA+PiAgb2JqLSQo
Q09ORklHX0FSTV9NSFUpCSs9IGFybV9taHUubw0KPiA+Pg0KPiA+PiArb2JqLSQoQ09ORklHX0lN
WF9NQk9YKQkrPSBpbXgtbWFpbGJveC5vDQo+ID4+ICsNCj4gPj4gIG9iai0kKENPTkZJR19QTEFU
Rk9STV9NSFUpCSs9IHBsYXRmb3JtX21odS5vDQo+ID4+DQo+ID4+ICBvYmotJChDT05GSUdfUEwz
MjBfTUJPWCkJKz0gcGwzMjAtaXBjLm8NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbWFpbGJv
eC9pbXgtbWFpbGJveC5jDQo+ID4+IGIvZHJpdmVycy9tYWlsYm94L2lteC1tYWlsYm94LmMgbmV3
IGZpbGUgbW9kZSAxMDA2NDQgaW5kZXgNCj4gPj4gMDAwMDAwMDAwMDAwLi5lM2Y2MjFjYjFkMzAN
Cj4gPj4gLS0tIC9kZXYvbnVsbA0KPiA+PiArKysgYi9kcml2ZXJzL21haWxib3gvaW14LW1haWxi
b3guYw0KPiA+PiBAQCAtMCwwICsxLDI4OCBAQA0KPiA+PiArLy8gU1BEWC1MaWNlbnNlLUlkZW50
aWZpZXI6IEdQTC0yLjANCj4gPj4gKy8qDQo+ID4+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMTggUGVu
Z3V0cm9uaXgsIE9sZWtzaWogUmVtcGVsDQo+ID4+ICs8by5yZW1wZWxAcGVuZ3V0cm9uaXguZGU+
ICAqLw0KPiA+PiArDQo+ID4+ICsjaW5jbHVkZSA8bGludXgvY2xrLmg+DQo+ID4+ICsjaW5jbHVk
ZSA8bGludXgvaW50ZXJydXB0Lmg+DQo+ID4+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4NCj4gPj4g
KyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4NCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9tYWlsYm94
X2NvbnRyb2xsZXIuaD4gI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiA+PiArI2luY2x1ZGUg
PGxpbnV4L29mX2RldmljZS5oPg0KPiA+PiArDQo+ID4+ICsvKiBUcmFuc21pdCBSZWdpc3RlciAq
Lw0KPiA+PiArI2RlZmluZSBJTVhfTVVfeFRSbih4KQkJKDB4MDAgKyA0ICogKHgpKQ0KPiA+PiAr
LyogUmVjZWl2ZSBSZWdpc3RlciAqLw0KPiA+PiArI2RlZmluZSBJTVhfTVVfeFJSbih4KQkJKDB4
MTAgKyA0ICogKHgpKQ0KPiA+PiArLyogU3RhdHVzIFJlZ2lzdGVyICovDQo+ID4+ICsjZGVmaW5l
IElNWF9NVV94U1IJCTB4MjANCj4gPj4gKyNkZWZpbmUgSU1YX01VX3hTUl9URW4oeCkJQklUKDIw
ICsgKHgpKQ0KPiA+PiArI2RlZmluZSBJTVhfTVVfeFNSX1JGbih4KQlCSVQoMjQgKyAoeCkpDQo+
ID4+ICsjZGVmaW5lIElNWF9NVV94U1JfQlJESVAJQklUKDkpDQo+ID4+ICsNCj4gPj4gKy8qIENv
bnRyb2wgUmVnaXN0ZXIgKi8NCj4gPj4gKyNkZWZpbmUgSU1YX01VX3hDUgkJMHgyNA0KPiA+PiAr
LyogVHJhbnNtaXQgSW50ZXJydXB0IEVuYWJsZSAqLw0KPiA+PiArI2RlZmluZSBJTVhfTVVfeENS
X1RJRW4oeCkJQklUKDIwICsgKHgpKQ0KPiA+PiArLyogUmVjZWl2ZSBJbnRlcnJ1cHQgRW5hYmxl
ICovDQo+ID4+ICsjZGVmaW5lIElNWF9NVV94Q1JfUklFbih4KQlCSVQoMjQgKyAoeCkpDQo+ID4+
ICsNCj4gPj4gKyNkZWZpbmUgSU1YX01VX01BWF9DSEFOUwk0dQ0KPiA+PiArDQo+ID4+ICtzdHJ1
Y3QgaW14X211X3ByaXY7DQo+ID4+ICsNCj4gPj4gK3N0cnVjdCBpbXhfbXVfY2ZnIHsNCj4gPj4g
Kwl1bnNpZ25lZCBpbnQJCWNoYW5zOw0KPiA+PiArCXZvaWQgKCppbml0X2h3KShzdHJ1Y3QgaW14
X211X3ByaXYgKnByaXYpOyB9Ow0KPiA+PiArDQo+ID4+ICtzdHJ1Y3QgaW14X211X2Nvbl9wcml2
IHsNCj4gPj4gKwlpbnQJCQlpcnE7DQo+ID4+ICsJdW5zaWduZWQgaW50CQliaWR4Ow0KPiA+PiAr
CXVuc2lnbmVkIGludAkJaWR4Ow0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IGlteF9t
dV9wcml2IHsNCj4gPj4gKwlzdHJ1Y3QgZGV2aWNlCQkqZGV2Ow0KPiA+PiArCWNvbnN0IHN0cnVj
dCBpbXhfbXVfY2ZnCSpkY2ZnOw0KPiA+PiArCXZvaWQgX19pb21lbQkJKmJhc2U7DQo+ID4+ICsN
Cj4gPj4gKwlzdHJ1Y3QgbWJveF9jb250cm9sbGVyCW1ib3g7DQo+ID4+ICsJc3RydWN0IG1ib3hf
Y2hhbgltYm94X2NoYW5zW0lNWF9NVV9NQVhfQ0hBTlNdOw0KPiA+PiArDQo+ID4+ICsJc3RydWN0
IGlteF9tdV9jb25fcHJpdiAgY29uX3ByaXZbSU1YX01VX01BWF9DSEFOU107DQo+ID4+ICsJc3Ry
dWN0IGNsawkJKmNsazsNCj4gPj4gK307DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyBzdHJ1Y3QgaW14
X211X3ByaXYgKnRvX2lteF9tdV9wcml2KHN0cnVjdCBtYm94X2NvbnRyb2xsZXINCj4gPj4gKypt
Ym94KSB7DQo+ID4+ICsJcmV0dXJuIGNvbnRhaW5lcl9vZihtYm94LCBzdHJ1Y3QgaW14X211X3By
aXYsIG1ib3gpOyB9DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyB2b2lkIGlteF9tdV93cml0ZShzdHJ1
Y3QgaW14X211X3ByaXYgKnByaXYsIHUzMiB2YWwsIHUzMiBvZmZzKSB7DQo+ID4+ICsJaW93cml0
ZTMyKHZhbCwgcHJpdi0+YmFzZSArIG9mZnMpOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdGF0
aWMgdTMyIGlteF9tdV9yZWFkKHN0cnVjdCBpbXhfbXVfcHJpdiAqcHJpdiwgdTMyIG9mZnMpIHsN
Cj4gPj4gKwlyZXR1cm4gaW9yZWFkMzIocHJpdi0+YmFzZSArIG9mZnMpOyB9DQo+ID4+ICsNCj4g
Pj4gK3N0YXRpYyB1MzIgaW14X211X3JtdyhzdHJ1Y3QgaW14X211X3ByaXYgKnByaXYsIHUzMiBv
ZmZzLCB1MzIgc2V0LA0KPiA+PiArdTMyDQo+ID4+ICtjbHIpIHsNCj4gPj4gKwl1MzIgdmFsOw0K
PiA+PiArDQo+ID4+ICsJdmFsID0gaW14X211X3JlYWQocHJpdiwgb2Zmcyk7DQo+ID4+ICsJdmFs
ICY9IH5jbHI7DQo+ID4+ICsJdmFsIHw9IHNldDsNCj4gPj4gKwlpbXhfbXVfd3JpdGUocHJpdiwg
dmFsLCBvZmZzKTsNCj4gPj4gKw0KPiA+PiArCXJldHVybiB2YWw7DQo+ID4+ICt9DQo+ID4+ICsN
Cj4gPj4gK3N0YXRpYyBpcnFyZXR1cm5fdCBpbXhfbXVfaXNyKGludCBpcnEsIHZvaWQgKnApIHsN
Cj4gPj4gKwlzdHJ1Y3QgbWJveF9jaGFuICpjaGFuID0gcDsNCj4gPj4gKwlzdHJ1Y3QgaW14X211
X3ByaXYgKnByaXYgPSB0b19pbXhfbXVfcHJpdihjaGFuLT5tYm94KTsNCj4gPj4gKwlzdHJ1Y3Qg
aW14X211X2Nvbl9wcml2ICpjcCA9IGNoYW4tPmNvbl9wcml2Ow0KPiA+PiArDQo+ID4+ICsJdTMy
IHZhbCwgZGF0Ow0KPiA+PiArDQo+ID4+ICsJdmFsID0gaW14X211X3JlYWQocHJpdiwgSU1YX01V
X3hTUik7DQo+ID4+ICsJdmFsICY9IElNWF9NVV94U1JfVEVuKGNwLT5iaWR4KSB8IElNWF9NVV94
U1JfUkZuKGNwLT5iaWR4KTsNCj4gPj4gKwlpZiAoIXZhbCkNCj4gPj4gKwkJcmV0dXJuIElSUV9O
T05FOw0KPiA+PiArDQo+ID4+ICsJaWYgKHZhbCAmIElNWF9NVV94U1JfVEVuKGNwLT5iaWR4KSkg
ew0KPiA+DQo+ID4gSSdtIHdvbmRlcmluZyB3aGV0aGVyIHRoaXMgY2FuIHdvcmsgcHJvcGVybHkg
Zm9yIG11bHRpIGNvbnN1bWVycyBhdA0KPiA+IHRoZSBzYW1lIHRpbWUuDQo+ID4gQmVjYXVzZSB4
U1JfVEVuIGlzIDEgYnkgZGVmYXVsdCBhbmQgZm91ciB2aXJ0dWFsIGNoYW5uZWxzIGFjdHVhbGx5
IGFyZQ0KPiA+IHVzaW5nIHRoZSBzYW1lIGludGVycnVwdC4gVGhhdCBtZWFucyBjaGFubmVsIDEg
aW50ZXJydXB0IG1heSBjYXVzZQ0KPiA+IGNoYW5uZWwgMiBiZWxpZXZlIGl0J3MgdHhkb25lLg0K
PiA+IEhhdmUgd2UgdGVzdGVkIHN1Y2ggdXNpbmc/DQo+IA0KPiBzZWUgaW14X211X3NlbmRfZGF0
YSgpDQo+IC4uLi4uIGlteF9tdV9ybXcocHJpdiwgSU1YX01VX3hDUiwgSU1YX01VX3hTUl9URW4o
Y3AtPmJpZHgpLCAwKTsNCj4gDQo+ID4NCj4gPj4gKwkJaW14X211X3Jtdyhwcml2LCBJTVhfTVVf
eENSLCAwLCBJTVhfTVVfeENSX1RJRW4oY3AtDQo+ID4+PiBiaWR4KSk7DQo+IA0KPiBhbmQgaGVy
ZSBeXl4NCj4gVFggc3RhdHVzIGlzIGVuYWJsZWQgb25seSBmb3Igc2VuZCBhbmQgZGlzYWJsZWQg
YXMgc29vbiBhdCB0cmFuc2ZlciBpcyBkb25lLg0KPiANCg0KVGhhdCBjb250cm9scyB0aGUgaW50
ZXJydXB0IGVuYWJsZSBzaWduYWwsIEknbSBub3Qgc3VyZSBpZiB0aGUgc3RhdHVzIGJpdA0KV29u
J3QgYmUgc2V0IGlmIG5vdCBlbmFibGUgaW50ZXJydXB0LiBJJ3ZlIG5vdCB0ZXN0ZWQgaXQuDQoN
CkhhdmUgeW91IGRvdWJsZSBjaGVja2VkIGl0Pw0KDQpGb3IgbiA9IHswLCAxLCAyLCAzfSBQcm9j
ZXNzb3IgQSBUcmFuc21pdCBSZWdpc3RlciBuIEVtcHR5LiAoUmVhZC1vbmx5KQ0K4oCiIFRoZSBU
RW4gYml0IGlzIHNldCB0byDigJwx4oCdIGFmdGVyIHRoZSBCUlJuIHJlZ2lzdGVyIGlzIHJlYWQg
b24gdGhlIFByb2Nlc3NvciBCLXNpZGUuDQrigKIgQWZ0ZXIgdGhlIFRFbiBiaXQgaXMgc2V0IHRv
IOKAnDHigJ0sIHRoZSBURW4gYml0IHNpZ25hbHMgdGhlIFByb2Nlc3NvciBBLXNpZGUgdGhhdCB0
aGUgQVRSbiByZWdpc3RlciBpcw0KcmVhZHkgdG8gYmUgd3JpdHRlbiBvbiB0aGUgUHJvY2Vzc29y
IEEtc2lkZSwgYW5kIGEgVHJhbnNtaXQgbiBpbnRlcnJ1cHQgaXMgaXNzdWVkIG9uIHRoZSBQcm9j
ZXNzb3INCkEtc2lkZSAoaWYgdGhlIFRFbiBiaXQgaW4gdGhlIEFDUiByZWdpc3RlciBpcyBzZXQg
dG8g4oCcMeKAnSkuDQouLi4NCg0KPiA+PiArCQltYm94X2NoYW5fdHhkb25lKGNoYW4sIDApOw0K
PiA+PiArCX0NCj4gPj4gKw0KPiA+PiArCWlmICh2YWwgJiBJTVhfTVVfeFNSX1JGbihjcC0+Ymlk
eCkpIHsNCj4gPj4gKwkJZGF0ID0gaW14X211X3JlYWQocHJpdiwgSU1YX01VX3hSUm4oY3AtPmlk
eCkpOw0KPiA+PiArCQltYm94X2NoYW5fcmVjZWl2ZWRfZGF0YShjaGFuLCAodm9pZCAqKSZkYXQp
Ow0KPiA+PiArCX0NCj4gPj4gKw0KPiA+PiArCXJldHVybiBJUlFfSEFORExFRDsNCj4gPj4gK30N
Cj4gPj4gKw0KPiA+PiArc3RhdGljIGJvb2wgaW14X211X2xhc3RfdHhfZG9uZShzdHJ1Y3QgbWJv
eF9jaGFuICpjaGFuKSB7DQo+ID4+ICsJc3RydWN0IGlteF9tdV9wcml2ICpwcml2ID0gdG9faW14
X211X3ByaXYoY2hhbi0+bWJveCk7DQo+ID4+ICsJc3RydWN0IGlteF9tdV9jb25fcHJpdiAqY3Ag
PSBjaGFuLT5jb25fcHJpdjsNCj4gPj4gKwl1MzIgdmFsOw0KPiA+PiArDQo+ID4+ICsJdmFsID0g
aW14X211X3JlYWQocHJpdiwgSU1YX01VX3hTUik7DQo+ID4+ICsJLyogdGVzdCBpZiB0cmFuc21p
dCByZWdpc3RlciBpcyBlbXB0eSAqLw0KPiA+PiArCXJldHVybiAoISEodmFsICYgSU1YX01VX3hT
Ul9URW4oY3AtPmJpZHgpKSk7IH0NCj4gPj4gKw0KPiA+PiArc3RhdGljIGludCBpbXhfbXVfc2Vu
ZF9kYXRhKHN0cnVjdCBtYm94X2NoYW4gKmNoYW4sIHZvaWQgKmRhdGEpIHsNCj4gPj4gKwlzdHJ1
Y3QgaW14X211X3ByaXYgKnByaXYgPSB0b19pbXhfbXVfcHJpdihjaGFuLT5tYm94KTsNCj4gPj4g
KwlzdHJ1Y3QgaW14X211X2Nvbl9wcml2ICpjcCA9IGNoYW4tPmNvbl9wcml2Ow0KPiA+PiArCXUz
MiAqYXJnID0gZGF0YTsNCj4gPj4gKw0KPiA+PiArCWlmICghaW14X211X2xhc3RfdHhfZG9uZShj
aGFuKSkNCj4gPj4gKwkJcmV0dXJuIC1FQlVTWTsNCj4gPj4gKw0KPiA+PiArCWlteF9tdV93cml0
ZShwcml2LCAqYXJnLCBJTVhfTVVfeFRSbihjcC0+aWR4KSk7DQo+ID4+ICsJaW14X211X3Jtdyhw
cml2LCBJTVhfTVVfeENSLCBJTVhfTVVfeFNSX1RFbihjcC0+YmlkeCksIDApOw0KPiA+PiArDQo+
ID4+ICsJcmV0dXJuIDA7DQo+ID4+ICt9DQo+ID4NCj4gPiBTaW5jZSBTYXNjaGEgaXMgcmVxdWVz
dGluZyB0byB3cml0ZSBhIGdlbmVyaWMgTVUgbWFpbGJveCBkcml2ZXIgZm9yDQo+ID4gYm90aCBT
Q1UgTVUgYW5kIE00IGNhc2UsIHRoZSBjdXJyZW50IHdheSB1c2luZyB2aXJ0dWFsIGNoYW5uZWxz
IGluDQo+ID4gdGhpcyBwYXRjaCBvbmx5IHNlbmQgb25lIHdvcmQgYSB0aW1lIG9idmlvdXNseSBj
YW4ndCBmaXQgZm9yIFNDVSBNVSBjbGllbnRzDQo+IHdlbGwuDQo+ID4gRG8geW91IHRoaW5rIGlm
IHdlIGNhbiByZWZlciB0byBUSSBjYXNlIHRvIGRlc2lnbiBhIGdlbmVyaWMgZGF0YQ0KPiA+IHRy
YW5zZmVyIHByb3RvY29sIHRvIGFsbG93IHNlbmQgbXVsdGkgd29yZHMgd2hpY2ggaXMgbW9yZSBj
bG9zZSB0byBTQ1U/DQo+IA0KPiBBY2NvcmRpbmcgdG8geW91ciBjb2RlLCB5b3UgYXJlIGFibGUg
dG8gc2VuZCAxIHdvcmQgbWVzc2FnZS4gSXQgbWVhbnMsIHlvdXINCj4gU0NVIGlzIGNvbmZpZ3Vy
ZWQgdG8gdHJpZ2dlciBhbiBpbnRlcnJ1cHQgb3Igc3RhdHVzIHVwZGF0ZSBpZiBSRUcwIHdhcyB3
cml0dGVuLg0KPiBUaGUgc2FtZSBpcyB0cnVlIGZvciAyLCAzLCA0IGFuZCA1IHdvcmQgbWVzc2Fn
ZXMuDQo+IA0KDQpTQ1UgaXMgaW50ZXJydXB0IGRyaXZlbiBhbHJlYWR5IGZvciB0aGUgZmlyc3Qg
d29yZC4NCldlIGRvIGNhbiBzZW5kIHdvcmQgb25lIGJ5IG9uZSBidXQgdGhlIHBlcmZvcm1hbmNl
IHdvdWxkIGJlIHRlcnJpYmxlDQpjb21wYXJpbmcgdG8gd3JpdGUgNCBhIHRpbWUuDQoNCj4gSWYg
dGhlIE1VIGNvbmZpZ3VyYXRpb24gd291bGQgbG9vayBsaWtlIHlvdSBpdCBkZXNjcmliZWQsIHlv
dSB3b3VsZCBiZSBmb3JjZWQNCj4gdG8gd3JpdGUgYWx3YXlzIDQgd29yZHMsIGV2ZW4gZm9yIDEg
d29yZCBtZXNzYWdlLg0KPiANCj4gPiBpbmNsdWRlL2xpbnV4L3NvYy90aS90aS1tc2dtZ3IuaA0K
PiA+IHN0cnVjdCB0aV9tc2dtZ3JfbWVzc2FnZSB7DQo+ID4gICAgICAgICBzaXplX3QgbGVuOw0K
PiA+ICAgICAgICAgdTggKmJ1ZjsNCj4gPiB9Ow0KPiA+DQo+ID4gT3Igd2UgdHJ5IHRvIHN1cHBv
cnQgYm90aCB0eXBlIHRyYW5zZmVyIHByb3RvY29scyBpbiB0aGlzIGRyaXZlcj8NCj4gDQo+IFN1
cmUuIHRpLW1zZ21nci5jIGlzIGEgZ29vZCBleGFtcGxlLiBZb3Ugd2lsbCBwcm9iYWJseSBuZWVk
IHJlZHVjZWQgdmFyaWFudA0KPiBvZiBpdC4gSXQgaXMgZ2VuZXJpYyBlbm91Z2ggdG8gbWFrZSBp
dCB1c2VmdWwgbm90IG9ubHkgZm9yIFNDVS4NCj4gDQoNClNhc2NoYSBuZWVkcyBhIGNvbW1vbiBk
ZXNpZ24gZm9yIGJvdGggTTQgYW5kIFNDVS5JZiBkZWNpZGUgdG8gZG8gdGhhdCwNCnlvdSBwcm9i
YWJseSBuZWVkIHVwZGF0ZSB0aGlzIHBhdGNoIGFzIHdlbGwuDQoNCkJ1dCBldmVuIGRvaW5nIGxp
a2UgVEkgc3R5bGUsIGl0IHN0aWxsIG5lZWQgaGFjayBmb3IgU0NVIGFzIHRoZSBkYXRhIHNpemUg
b2Zmc2V0DQpJcyBkaWZmZXJlbnQuIEhvd2V2ZXIsIHRoYXQgd291bGQgYmUgYSBtdWNoIHNtYWxs
ZXIgaGFjayB0aGFuIGRvaW5nIGJhc2VkDQpPbiB0aGlzIGRyaXZlci4NCg0KPiA+IFRoYXQgbWF5
IGludHJvZHVjZSBtdWNoIGNvbXBsZXhpdGllcywgcGVyc29uYWxseSBJJ20gbm90IHF1aXRlIGxp
a2UNCj4gPiB0aGF0Lg0KPiANCj4gSSBleHBlY3QgNTAtMTUwIGxpbmVzIG9mIGV4dHJhIGNvZGUu
DQo+IA0KDQpIb3BlIHRoYXQgY291bGQgYmUgdHJ1ZS4NCkRvIHlvdSBoYXZlIHN1Z2dlc3Rpb24g
b24gaG93IHRvIGtlZXAgdHdvIHR5cGUgcHJvdG9jb2wgY28tZXhpc3QNCklmIHlvdSB0aG91Z2h0
IHRoYXQgd291bGQgd29yayB3aXRob3V0IHR3byBtdWNoIGV4dHJhIGNvbXBsZXhpdHk/DQpIYXZl
IHlvdSB0cmllZCBpdCBhbHJlYWR5IGJhc2VkIHRoaXMgZHJpdmVyPw0KDQpSZWdhcmRzDQpEb25n
IEFpc2hlbmcNCg0KPiA+IFJlZ2FyZHMNCj4gPiBEb25nIEFpc2hlbmcNCj4gPg0KPiA+PiArDQo+
ID4+ICtzdGF0aWMgaW50IGlteF9tdV9zdGFydHVwKHN0cnVjdCBtYm94X2NoYW4gKmNoYW4pIHsN
Cj4gPj4gKwlzdHJ1Y3QgaW14X211X3ByaXYgKnByaXYgPSB0b19pbXhfbXVfcHJpdihjaGFuLT5t
Ym94KTsNCj4gPj4gKwlzdHJ1Y3QgaW14X211X2Nvbl9wcml2ICpjcCA9IGNoYW4tPmNvbl9wcml2
Ow0KPiA+PiArCWludCByZXQ7DQo+ID4+ICsNCj4gPj4gKwlyZXQgPSByZXF1ZXN0X2lycShjcC0+
aXJxLCBpbXhfbXVfaXNyLA0KPiA+PiArCQkJICBJUlFGX1NIQVJFRCwgImlteF9tdV9jaGFuIiwg
Y2hhbik7DQo+ID4+ICsJaWYgKHJldCkgew0KPiA+PiArCQlkZXZfZXJyKGNoYW4tPm1ib3gtPmRl
diwNCj4gPj4gKwkJCSJVbmFibGUgdG8gYWNxdWlyZSBJUlEgJWRcbiIsIGNwLT5pcnEpOw0KPiA+
PiArCQlyZXR1cm4gcmV0Ow0KPiA+PiArCX0NCj4gPj4gKw0KPiA+PiArCWlteF9tdV9ybXcocHJp
diwgSU1YX01VX3hDUiwgSU1YX01VX3hDUl9SSUVuKGNwLT5iaWR4KSwgMCk7DQo+ID4+ICsNCj4g
Pj4gKwlyZXR1cm4gMDsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIHZvaWQgaW14X211
X3NodXRkb3duKHN0cnVjdCBtYm94X2NoYW4gKmNoYW4pIHsNCj4gPj4gKwlzdHJ1Y3QgaW14X211
X3ByaXYgKnByaXYgPSB0b19pbXhfbXVfcHJpdihjaGFuLT5tYm94KTsNCj4gPj4gKwlzdHJ1Y3Qg
aW14X211X2Nvbl9wcml2ICpjcCA9IGNoYW4tPmNvbl9wcml2Ow0KPiA+PiArDQo+ID4+ICsJaW14
X211X3Jtdyhwcml2LCBJTVhfTVVfeENSLCAwLA0KPiA+PiArCQkgICBJTVhfTVVfeENSX1RJRW4o
Y3AtPmJpZHgpIHwgSU1YX01VX3hDUl9SSUVuKGNwLQ0KPiA+Pj4gYmlkeCkpOw0KPiA+PiArDQo+
ID4+ICsJZnJlZV9pcnEoY3AtPmlycSwgY2hhbik7DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3N0
YXRpYyBjb25zdCBzdHJ1Y3QgbWJveF9jaGFuX29wcyBpbXhfbXVfb3BzID0gew0KPiA+PiArCS5z
ZW5kX2RhdGEgPSBpbXhfbXVfc2VuZF9kYXRhLA0KPiA+PiArCS5zdGFydHVwID0gaW14X211X3N0
YXJ0dXAsDQo+ID4+ICsJLnNodXRkb3duID0gaW14X211X3NodXRkb3duLA0KPiA+PiArfTsNCj4g
Pj4gKw0KPiA+PiArc3RhdGljIGludCBpbXhfbXVfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2Rldmlj
ZSAqcGRldikgew0KPiA+PiArCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7DQo+ID4+
ICsJc3RydWN0IHJlc291cmNlICppb21lbTsNCj4gPj4gKwlzdHJ1Y3QgaW14X211X3ByaXYgKnBy
aXY7DQo+ID4+ICsJY29uc3Qgc3RydWN0IGlteF9tdV9jZmcgKmRjZmc7DQo+ID4+ICsJdW5zaWdu
ZWQgaW50IGksIGNoYW5zOw0KPiA+PiArCWludCBpcnEsIHJldDsNCj4gPj4gKw0KPiA+PiArCXBy
aXYgPSBkZXZtX2t6YWxsb2MoZGV2LCBzaXplb2YoKnByaXYpLCBHRlBfS0VSTkVMKTsNCj4gPj4g
KwlpZiAoIXByaXYpDQo+ID4+ICsJCXJldHVybiAtRU5PTUVNOw0KPiA+PiArDQo+ID4+ICsJZGNm
ZyA9IG9mX2RldmljZV9nZXRfbWF0Y2hfZGF0YShkZXYpOw0KPiA+PiArCWlmICghZGNmZykNCj4g
Pj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ID4+ICsNCj4gPj4gKwlwcml2LT5kY2ZnID0gZGNmZzsN
Cj4gPj4gKwlwcml2LT5kZXYgPSBkZXY7DQo+ID4+ICsNCj4gPj4gKwlpb21lbSA9IHBsYXRmb3Jt
X2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7DQo+ID4+ICsJcHJpdi0+YmFz
ZSA9IGRldm1faW9yZW1hcF9yZXNvdXJjZSgmcGRldi0+ZGV2LCBpb21lbSk7DQo+ID4+ICsJaWYg
KElTX0VSUihwcml2LT5iYXNlKSkNCj4gPj4gKwkJcmV0dXJuIFBUUl9FUlIocHJpdi0+YmFzZSk7
DQo+ID4+ICsNCj4gPj4gKwlpcnEgPSBwbGF0Zm9ybV9nZXRfaXJxKHBkZXYsIDApOw0KPiA+PiAr
CWlmIChpcnEgPD0gMCkNCj4gPj4gKwkJcmV0dXJuIGlycSA8IDAgPyBpcnEgOiAtRUlOVkFMOw0K
PiA+PiArDQo+ID4+ICsJcHJpdi0+Y2xrID0gZGV2bV9jbGtfZ2V0KGRldiwgTlVMTCk7DQo+ID4+
ICsJaWYgKElTX0VSUihwcml2LT5jbGspKSB7DQo+ID4+ICsJCWlmIChQVFJfRVJSKHByaXYtPmNs
aykgPT0gLUVOT0VOVCkgew0KPiA+PiArCQkJcHJpdi0+Y2xrID0gTlVMTDsNCj4gPj4gKwkJfSBl
bHNlIHsNCj4gPj4gKwkJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGdldCBjbG9ja1xuIik7DQo+
ID4+ICsJCQlyZXR1cm4gUFRSX0VSUihwcml2LT5jbGspOw0KPiA+PiArCQl9DQo+ID4+ICsJfQ0K
PiA+PiArDQo+ID4+ICsJcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKHByaXYtPmNsayk7DQo+ID4+
ICsJaWYgKHJldCkgew0KPiA+PiArCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byBlbmFibGUgY2xv
Y2tcbiIpOw0KPiA+PiArCQlyZXR1cm4gcmV0Ow0KPiA+PiArCX0NCj4gPj4gKw0KPiA+PiArCWNo
YW5zID0gbWluKGRjZmctPmNoYW5zLCBJTVhfTVVfTUFYX0NIQU5TKTsNCj4gPj4gKwkvKiBJbml0
aWFsaXplIGNoYW5uZWwgaWRlbnRpZmllcnMgKi8NCj4gPj4gKwlmb3IgKGkgPSAwOyBpIDwgY2hh
bnM7IGkrKykgew0KPiA+PiArCQlzdHJ1Y3QgaW14X211X2Nvbl9wcml2ICpjcCA9ICZwcml2LT5j
b25fcHJpdltpXTsNCj4gPj4gKw0KPiA+PiArCQljcC0+YmlkeCA9IDMgLSBpOw0KPiA+PiArCQlj
cC0+aWR4ID0gaTsNCj4gPj4gKwkJY3AtPmlycSA9IGlycTsNCj4gPj4gKwkJcHJpdi0+bWJveF9j
aGFuc1tpXS5jb25fcHJpdiA9IGNwOw0KPiA+PiArCX0NCj4gPj4gKw0KPiA+PiArCXByaXYtPm1i
b3guZGV2ID0gZGV2Ow0KPiA+PiArCXByaXYtPm1ib3gub3BzID0gJmlteF9tdV9vcHM7DQo+ID4+
ICsJcHJpdi0+bWJveC5jaGFucyA9IHByaXYtPm1ib3hfY2hhbnM7DQo+ID4+ICsJcHJpdi0+bWJv
eC5udW1fY2hhbnMgPSBjaGFuczsNCj4gPj4gKwlwcml2LT5tYm94LnR4ZG9uZV9pcnEgPSB0cnVl
Ow0KPiA+PiArDQo+ID4+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgcHJpdik7DQo+ID4+
ICsNCj4gPj4gKwlpZiAocHJpdi0+ZGNmZy0+aW5pdF9odykNCj4gPj4gKwkJcHJpdi0+ZGNmZy0+
aW5pdF9odyhwcml2KTsNCj4gPj4gKw0KPiA+PiArCXJldHVybiBtYm94X2NvbnRyb2xsZXJfcmVn
aXN0ZXIoJnByaXYtPm1ib3gpOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdGF0aWMgaW50IGlt
eF9tdV9yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikgew0KPiA+PiArCXN0cnVj
dCBpbXhfbXVfcHJpdiAqcHJpdiA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOw0KPiA+PiAr
DQo+ID4+ICsJbWJveF9jb250cm9sbGVyX3VucmVnaXN0ZXIoJnByaXYtPm1ib3gpOw0KPiA+PiAr
CWNsa19kaXNhYmxlX3VucHJlcGFyZShwcml2LT5jbGspOw0KPiA+PiArDQo+ID4+ICsJcmV0dXJu
IDA7DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gKw0KPiA+PiArc3RhdGljIHZvaWQgaW14X211X2lu
aXRfaW14N2RfYShzdHJ1Y3QgaW14X211X3ByaXYgKnByaXYpIHsNCj4gPj4gKwkvKiBTZXQgZGVm
YXVsdCBjb25maWcgKi8NCj4gPj4gKwlpbXhfbXVfd3JpdGUocHJpdiwgMCwgSU1YX01VX3hDUik7
DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaW14X211X2NmZyBp
bXhfbXVfY2ZnX2lteDdkX2EgPSB7DQo+ID4+ICsJLmNoYW5zID0gSU1YX01VX01BWF9DSEFOUywN
Cj4gPj4gKwkuaW5pdF9odyA9IGlteF9tdV9pbml0X2lteDdkX2EsDQo+ID4+ICt9Ow0KPiA+PiAr
DQo+ID4+ICtzdGF0aWMgY29uc3Qgc3RydWN0IGlteF9tdV9jZmcgaW14X211X2NmZ19pbXg3ZF9i
ID0gew0KPiA+PiArCS5jaGFucyA9IElNWF9NVV9NQVhfQ0hBTlMsDQo+ID4+ICt9Ow0KPiA+PiAr
DQo+ID4+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBpbXhfbXVfZHRfaWRzW10g
PSB7DQo+ID4+ICsJeyAuY29tcGF0aWJsZSA9ICJmc2wsaW14N3MtbXUtYSIsIC5kYXRhID0gJmlt
eF9tdV9jZmdfaW14N2RfYSB9LA0KPiA+PiArCXsgLmNvbXBhdGlibGUgPSAiZnNsLGlteDdzLW11
LWIiLCAuZGF0YSA9ICZpbXhfbXVfY2ZnX2lteDdkX2IgfSwNCj4gPj4gKwl7IH0sDQo+ID4+ICt9
Ow0KPiA+PiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgaW14X211X2R0X2lkcyk7DQo+ID4+ICsN
Cj4gPj4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGlteF9tdV9kcml2ZXIgPSB7DQo+
ID4+ICsJLnByb2JlCQk9IGlteF9tdV9wcm9iZSwNCj4gPj4gKwkucmVtb3ZlCQk9IGlteF9tdV9y
ZW1vdmUsDQo+ID4+ICsJLmRyaXZlciA9IHsNCj4gPj4gKwkJLm5hbWUJPSAiaW14X211IiwNCj4g
Pj4gKwkJLm9mX21hdGNoX3RhYmxlID0gaW14X211X2R0X2lkcywNCj4gPj4gKwl9LA0KPiA+PiAr
fTsNCj4gPj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIoaW14X211X2RyaXZlcik7DQo+ID4+ICsN
Cj4gPj4gK01PRFVMRV9BVVRIT1IoIk9sZWtzaWogUmVtcGVsIDxvLnJlbXBlbEBwZW5ndXRyb25p
eC5kZT4iKTsNCj4gPj4gK01PRFVMRV9ERVNDUklQVElPTigiTWVzc2FnZSBVbml0IGRyaXZlciBm
b3IgaS5NWCIpOw0KPiA+PiBNT0RVTEVfTElDRU5TRSgiR1BMDQo+ID4+ICt2MiIpOw0KPiA+PiAt
LQ0KPiA+PiAyLjE3LjENCj4gPg0KPiA+DQo+ID4NCg0K

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 12:07         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-26 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Tuesday, June 26, 2018 6:56 PM
> To: A.s. Dong <aisheng.dong@nxp.com>; Shawn Guo
> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>
> Cc: devicetree at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-
> arm-kernel at lists.infradead.org; kernel at pengutronix.de; linux-
> clk at vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> 
> 
> On 26.06.2018 12:09, A.s. Dong wrote:
> >> -----Original Message-----
> >> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> >> Sent: Friday, June 15, 2018 5:51 PM
> >> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> >> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> >> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> >> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
> >> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
> >> linux- clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> >> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> >> unit
> >>
> >> The Mailbox controller is able to send messages (up to 4 32 bit
> >> words) between the endpoints.
> >>
> >> This driver was tested using the mailbox-test driver sending messages
> >> between the Cortex-A7 and the Cortex-M4.
> >>
> >> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> >> ---
> >>  drivers/mailbox/Kconfig       |   6 +
> >>  drivers/mailbox/Makefile      |   2 +
> >>  drivers/mailbox/imx-mailbox.c | 288
> >> ++++++++++++++++++++++++++++++++++
> >>  3 files changed, 296 insertions(+)
> >>  create mode 100644 drivers/mailbox/imx-mailbox.c
> >>
> >> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> >> a2bb27446dce..e1d2738a2e4c 100644
> >> --- a/drivers/mailbox/Kconfig
> >> +++ b/drivers/mailbox/Kconfig
> >> @@ -15,6 +15,12 @@ config ARM_MHU
> >>  	  The controller has 3 mailbox channels, the last of which can be
> >>  	  used in Secure mode only.
> >>
> >> +config IMX_MBOX
> >> +	tristate "iMX Mailbox"
> >> +	depends on SOC_IMX7D || COMPILE_TEST
> >> +	help
> >> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> >> +
> >>  config PLATFORM_MHU
> >>  	tristate "Platform MHU Mailbox"
> >>  	depends on OF
> >> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> >> index
> >> cc23c3a43fcd..ba2fe1b6dd62 100644
> >> --- a/drivers/mailbox/Makefile
> >> +++ b/drivers/mailbox/Makefile
> >> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> >>
> >>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> >>
> >> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> >> +
> >>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> >>
> >>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> >> diff --git a/drivers/mailbox/imx-mailbox.c
> >> b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> >> 000000000000..e3f621cb1d30
> >> --- /dev/null
> >> +++ b/drivers/mailbox/imx-mailbox.c
> >> @@ -0,0 +1,288 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> >> +<o.rempel@pengutronix.de>  */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/mailbox_controller.h> #include <linux/module.h>
> >> +#include <linux/of_device.h>
> >> +
> >> +/* Transmit Register */
> >> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> >> +/* Receive Register */
> >> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> >> +/* Status Register */
> >> +#define IMX_MU_xSR		0x20
> >> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> >> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> >> +#define IMX_MU_xSR_BRDIP	BIT(9)
> >> +
> >> +/* Control Register */
> >> +#define IMX_MU_xCR		0x24
> >> +/* Transmit Interrupt Enable */
> >> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> >> +/* Receive Interrupt Enable */
> >> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> >> +
> >> +#define IMX_MU_MAX_CHANS	4u
> >> +
> >> +struct imx_mu_priv;
> >> +
> >> +struct imx_mu_cfg {
> >> +	unsigned int		chans;
> >> +	void (*init_hw)(struct imx_mu_priv *priv); };
> >> +
> >> +struct imx_mu_con_priv {
> >> +	int			irq;
> >> +	unsigned int		bidx;
> >> +	unsigned int		idx;
> >> +};
> >> +
> >> +struct imx_mu_priv {
> >> +	struct device		*dev;
> >> +	const struct imx_mu_cfg	*dcfg;
> >> +	void __iomem		*base;
> >> +
> >> +	struct mbox_controller	mbox;
> >> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> >> +
> >> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> >> +	struct clk		*clk;
> >> +};
> >> +
> >> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> >> +*mbox) {
> >> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> >> +
> >> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> >> +	iowrite32(val, priv->base + offs);
> >> +}
> >> +
> >> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> >> +	return ioread32(priv->base + offs); }
> >> +
> >> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> >> +u32
> >> +clr) {
> >> +	u32 val;
> >> +
> >> +	val = imx_mu_read(priv, offs);
> >> +	val &= ~clr;
> >> +	val |= set;
> >> +	imx_mu_write(priv, val, offs);
> >> +
> >> +	return val;
> >> +}
> >> +
> >> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> >> +	struct mbox_chan *chan = p;
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +
> >> +	u32 val, dat;
> >> +
> >> +	val = imx_mu_read(priv, IMX_MU_xSR);
> >> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> >> +	if (!val)
> >> +		return IRQ_NONE;
> >> +
> >> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> >
> > I'm wondering whether this can work properly for multi consumers at
> > the same time.
> > Because xSR_TEn is 1 by default and four virtual channels actually are
> > using the same interrupt. That means channel 1 interrupt may cause
> > channel 2 believe it's txdone.
> > Have we tested such using?
> 
> see imx_mu_send_data()
> ..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> 
> >
> >> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >>> bidx));
> 
> and here ^^^
> TX status is enabled only for send and disabled as soon at transfer is done.
> 

That controls the interrupt enable signal, I'm not sure if the status bit
Won't be set if not enable interrupt. I've not tested it.

Have you double checked it?

For n = {0, 1, 2, 3} Processor A Transmit Register n Empty. (Read-only)
? The TEn bit is set to ?1? after the BRRn register is read on the Processor B-side.
? After the TEn bit is set to ?1?, the TEn bit signals the Processor A-side that the ATRn register is
ready to be written on the Processor A-side, and a Transmit n interrupt is issued on the Processor
A-side (if the TEn bit in the ACR register is set to ?1?).
...

> >> +		mbox_chan_txdone(chan, 0);
> >> +	}
> >> +
> >> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> >> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> >> +		mbox_chan_received_data(chan, (void *)&dat);
> >> +	}
> >> +
> >> +	return IRQ_HANDLED;
> >> +}
> >> +
> >> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	u32 val;
> >> +
> >> +	val = imx_mu_read(priv, IMX_MU_xSR);
> >> +	/* test if transmit register is empty */
> >> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> >> +
> >> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	u32 *arg = data;
> >> +
> >> +	if (!imx_mu_last_tx_done(chan))
> >> +		return -EBUSY;
> >> +
> >> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> >> +
> >> +	return 0;
> >> +}
> >
> > Since Sascha is requesting to write a generic MU mailbox driver for
> > both SCU MU and M4 case, the current way using virtual channels in
> > this patch only send one word a time obviously can't fit for SCU MU clients
> well.
> > Do you think if we can refer to TI case to design a generic data
> > transfer protocol to allow send multi words which is more close to SCU?
> 
> According to your code, you are able to send 1 word message. It means, your
> SCU is configured to trigger an interrupt or status update if REG0 was written.
> The same is true for 2, 3, 4 and 5 word messages.
> 

SCU is interrupt driven already for the first word.
We do can send word one by one but the performance would be terrible
comparing to write 4 a time.

> If the MU configuration would look like you it described, you would be forced
> to write always 4 words, even for 1 word message.
> 
> > include/linux/soc/ti/ti-msgmgr.h
> > struct ti_msgmgr_message {
> >         size_t len;
> >         u8 *buf;
> > };
> >
> > Or we try to support both type transfer protocols in this driver?
> 
> Sure. ti-msgmgr.c is a good example. You will probably need reduced variant
> of it. It is generic enough to make it useful not only for SCU.
> 

Sascha needs a common design for both M4 and SCU.If decide to do that,
you probably need update this patch as well.

But even doing like TI style, it still need hack for SCU as the data size offset
Is different. However, that would be a much smaller hack than doing based
On this driver.

> > That may introduce much complexities, personally I'm not quite like
> > that.
> 
> I expect 50-150 lines of extra code.
> 

Hope that could be true.
Do you have suggestion on how to keep two type protocol co-exist
If you thought that would work without two much extra complexity?
Have you tried it already based this driver?

Regards
Dong Aisheng

> > Regards
> > Dong Aisheng
> >
> >> +
> >> +static int imx_mu_startup(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +	int ret;
> >> +
> >> +	ret = request_irq(cp->irq, imx_mu_isr,
> >> +			  IRQF_SHARED, "imx_mu_chan", chan);
> >> +	if (ret) {
> >> +		dev_err(chan->mbox->dev,
> >> +			"Unable to acquire IRQ %d\n", cp->irq);
> >> +		return ret;
> >> +	}
> >> +
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> >> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> >> +	struct imx_mu_con_priv *cp = chan->con_priv;
> >> +
> >> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> >> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >>> bidx));
> >> +
> >> +	free_irq(cp->irq, chan);
> >> +}
> >> +
> >> +static const struct mbox_chan_ops imx_mu_ops = {
> >> +	.send_data = imx_mu_send_data,
> >> +	.startup = imx_mu_startup,
> >> +	.shutdown = imx_mu_shutdown,
> >> +};
> >> +
> >> +static int imx_mu_probe(struct platform_device *pdev) {
> >> +	struct device *dev = &pdev->dev;
> >> +	struct resource *iomem;
> >> +	struct imx_mu_priv *priv;
> >> +	const struct imx_mu_cfg *dcfg;
> >> +	unsigned int i, chans;
> >> +	int irq, ret;
> >> +
> >> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >> +	if (!priv)
> >> +		return -ENOMEM;
> >> +
> >> +	dcfg = of_device_get_match_data(dev);
> >> +	if (!dcfg)
> >> +		return -EINVAL;
> >> +
> >> +	priv->dcfg = dcfg;
> >> +	priv->dev = dev;
> >> +
> >> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> >> +	if (IS_ERR(priv->base))
> >> +		return PTR_ERR(priv->base);
> >> +
> >> +	irq = platform_get_irq(pdev, 0);
> >> +	if (irq <= 0)
> >> +		return irq < 0 ? irq : -EINVAL;
> >> +
> >> +	priv->clk = devm_clk_get(dev, NULL);
> >> +	if (IS_ERR(priv->clk)) {
> >> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> >> +			priv->clk = NULL;
> >> +		} else {
> >> +			dev_err(dev, "Failed to get clock\n");
> >> +			return PTR_ERR(priv->clk);
> >> +		}
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(priv->clk);
> >> +	if (ret) {
> >> +		dev_err(dev, "Failed to enable clock\n");
> >> +		return ret;
> >> +	}
> >> +
> >> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> >> +	/* Initialize channel identifiers */
> >> +	for (i = 0; i < chans; i++) {
> >> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> >> +
> >> +		cp->bidx = 3 - i;
> >> +		cp->idx = i;
> >> +		cp->irq = irq;
> >> +		priv->mbox_chans[i].con_priv = cp;
> >> +	}
> >> +
> >> +	priv->mbox.dev = dev;
> >> +	priv->mbox.ops = &imx_mu_ops;
> >> +	priv->mbox.chans = priv->mbox_chans;
> >> +	priv->mbox.num_chans = chans;
> >> +	priv->mbox.txdone_irq = true;
> >> +
> >> +	platform_set_drvdata(pdev, priv);
> >> +
> >> +	if (priv->dcfg->init_hw)
> >> +		priv->dcfg->init_hw(priv);
> >> +
> >> +	return mbox_controller_register(&priv->mbox);
> >> +}
> >> +
> >> +static int imx_mu_remove(struct platform_device *pdev) {
> >> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> >> +
> >> +	mbox_controller_unregister(&priv->mbox);
> >> +	clk_disable_unprepare(priv->clk);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +
> >> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> >> +	/* Set default config */
> >> +	imx_mu_write(priv, 0, IMX_MU_xCR);
> >> +}
> >> +
> >> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> >> +	.chans = IMX_MU_MAX_CHANS,
> >> +	.init_hw = imx_mu_init_imx7d_a,
> >> +};
> >> +
> >> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> >> +	.chans = IMX_MU_MAX_CHANS,
> >> +};
> >> +
> >> +static const struct of_device_id imx_mu_dt_ids[] = {
> >> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> >> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> >> +	{ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> >> +
> >> +static struct platform_driver imx_mu_driver = {
> >> +	.probe		= imx_mu_probe,
> >> +	.remove		= imx_mu_remove,
> >> +	.driver = {
> >> +		.name	= "imx_mu",
> >> +		.of_match_table = imx_mu_dt_ids,
> >> +	},
> >> +};
> >> +module_platform_driver(imx_mu_driver);
> >> +
> >> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> >> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> >> MODULE_LICENSE("GPL
> >> +v2");
> >> --
> >> 2.17.1
> >
> >
> >

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-26 10:09     ` A.s. Dong
  (?)
@ 2018-06-26 13:23       ` Sascha Hauer
  -1 siblings, 0 replies; 69+ messages in thread
From: Sascha Hauer @ 2018-06-26 13:23 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Mark Rutland, devicetree, Oleksij Rempel, Rob Herring,
	dl-linux-imx, kernel, Fabio Estevam, Shawn Guo, linux-clk,
	linux-arm-kernel

On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?
> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?
> That may introduce much complexities, personally I'm not quite
> like that.

To give you an idea what I am suggesting see the following patch.
It implements SCU mode ontop of Oleksijs patch. Untested of course
and as said, the mailbox framework lacks some way of synchronous
receive, that would still have to be implemented and Jassi might
have his own ideas how this could be done, but it doesn't add much
complexity.

Sascha


------------------------------8<--------------------------------

>From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Tue, 26 Jun 2018 15:07:04 +0200
Subject: [PATCH] mailbox: imx-mu: Implement SCU mode

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
 include/dt-bindings/mailbox/imx-mu.h | 10 ++++
 2 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 include/dt-bindings/mailbox/imx-mu.h

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index e3f621cb1d30..a4803d1eae1d 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -10,6 +10,8 @@
 #include <linux/mailbox_controller.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/iopoll.h>
+#include <dt-bindings/mailbox/imx-mu.h>
 
 /* Transmit Register */
 #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
@@ -28,7 +30,7 @@
 /* Receive Interrupt Enable */
 #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
 
-#define IMX_MU_MAX_CHANS	4u
+#define IMX_MU_MAX_CHANS	5u
 
 struct imx_mu_priv;
 
@@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct mbox_chan *chan)
 	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
 }
 
+// Take from some include file
+struct sc_rpc_msg {
+	uint8_t version;
+	uint8_t size;
+	uint8_t svc;
+	uint8_t func;
+};
+
+#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
+
+static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret;
+
+	for (i = 0; i < msg->size + 1; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_TEn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			goto out;
+
+		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
+	}
+
+	ret = 0;
+out:
+	mbox_chan_txdone(chan, ret);
+	return ret;
+}
+
+static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret, size = 8;
+
+	for (i = 0; i < size; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_RFn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			return ret;
+
+		msg_raw[i] = readl(priv->base + IMX_MU_xRRn(4 - index));
+
+		if (i == 0) {
+			size = msg->size;
+			if (size > 7)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 	struct imx_mu_con_priv *cp = chan->con_priv;
 	u32 *arg = data;
 
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_send_data(priv, data);
+
 	if (!imx_mu_last_tx_done(chan))
 		return -EBUSY;
 
@@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 	return 0;
 }
 
+static int imx_mu_receive_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_receive_data(priv, data);
+
+	return -EINVAL;
+}
+
 static int imx_mu_startup(struct mbox_chan *chan)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
@@ -166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
 
 static const struct mbox_chan_ops imx_mu_ops = {
 	.send_data = imx_mu_send_data,
+	/*
+	 * FIXME: This has to be implemented in the mailbox framework.
+	 * Currently there is only support for asynchronous read using
+	 * callbacks which is not suitable for the SCU usecase.
+	 */
+//	.synchronous_read = imx_mu_receive_data,
 	.startup = imx_mu_startup,
 	.shutdown = imx_mu_shutdown,
 };
diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-bindings/mailbox/imx-mu.h
new file mode 100644
index 000000000000..4836266a7e57
--- /dev/null
+++ b/include/dt-bindings/mailbox/imx-mu.h
@@ -0,0 +1,10 @@
+#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
+#define __DT_BINDINGS_MAILBOX_IMX_MU_H
+
+#define IMX_MU_CHANNEL0		0
+#define IMX_MU_CHANNEL1		1
+#define IMX_MU_CHANNEL2		2
+#define IMX_MU_CHANNEL3		3
+#define IMX_MU_CHANNEL_IMX8_SCU 4
+
+#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
-- 
2.17.1

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 13:23       ` Sascha Hauer
  0 siblings, 0 replies; 69+ messages in thread
From: Sascha Hauer @ 2018-06-26 13:23 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring,
	Mark Rutland, devicetree, dl-linux-imx, linux-arm-kernel, kernel,
	linux-clk

On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?
> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?
> That may introduce much complexities, personally I'm not quite
> like that.

To give you an idea what I am suggesting see the following patch.
It implements SCU mode ontop of Oleksijs patch. Untested of course
and as said, the mailbox framework lacks some way of synchronous
receive, that would still have to be implemented and Jassi might
have his own ideas how this could be done, but it doesn't add much
complexity.

Sascha


------------------------------8<--------------------------------

>From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Tue, 26 Jun 2018 15:07:04 +0200
Subject: [PATCH] mailbox: imx-mu: Implement SCU mode

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
 include/dt-bindings/mailbox/imx-mu.h | 10 ++++
 2 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 include/dt-bindings/mailbox/imx-mu.h

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index e3f621cb1d30..a4803d1eae1d 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -10,6 +10,8 @@
 #include <linux/mailbox_controller.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/iopoll.h>
+#include <dt-bindings/mailbox/imx-mu.h>
 
 /* Transmit Register */
 #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
@@ -28,7 +30,7 @@
 /* Receive Interrupt Enable */
 #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
 
-#define IMX_MU_MAX_CHANS	4u
+#define IMX_MU_MAX_CHANS	5u
 
 struct imx_mu_priv;
 
@@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct mbox_chan *chan)
 	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
 }
 
+// Take from some include file
+struct sc_rpc_msg {
+	uint8_t version;
+	uint8_t size;
+	uint8_t svc;
+	uint8_t func;
+};
+
+#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
+
+static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret;
+
+	for (i = 0; i < msg->size + 1; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_TEn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			goto out;
+
+		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
+	}
+
+	ret = 0;
+out:
+	mbox_chan_txdone(chan, ret);
+	return ret;
+}
+
+static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret, size = 8;
+
+	for (i = 0; i < size; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_RFn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			return ret;
+
+		msg_raw[i] = readl(priv->base + IMX_MU_xRRn(4 - index));
+
+		if (i == 0) {
+			size = msg->size;
+			if (size > 7)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 	struct imx_mu_con_priv *cp = chan->con_priv;
 	u32 *arg = data;
 
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_send_data(priv, data);
+
 	if (!imx_mu_last_tx_done(chan))
 		return -EBUSY;
 
@@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 	return 0;
 }
 
+static int imx_mu_receive_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_receive_data(priv, data);
+
+	return -EINVAL;
+}
+
 static int imx_mu_startup(struct mbox_chan *chan)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
@@ -166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
 
 static const struct mbox_chan_ops imx_mu_ops = {
 	.send_data = imx_mu_send_data,
+	/*
+	 * FIXME: This has to be implemented in the mailbox framework.
+	 * Currently there is only support for asynchronous read using
+	 * callbacks which is not suitable for the SCU usecase.
+	 */
+//	.synchronous_read = imx_mu_receive_data,
 	.startup = imx_mu_startup,
 	.shutdown = imx_mu_shutdown,
 };
diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-bindings/mailbox/imx-mu.h
new file mode 100644
index 000000000000..4836266a7e57
--- /dev/null
+++ b/include/dt-bindings/mailbox/imx-mu.h
@@ -0,0 +1,10 @@
+#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
+#define __DT_BINDINGS_MAILBOX_IMX_MU_H
+
+#define IMX_MU_CHANNEL0		0
+#define IMX_MU_CHANNEL1		1
+#define IMX_MU_CHANNEL2		2
+#define IMX_MU_CHANNEL3		3
+#define IMX_MU_CHANNEL_IMX8_SCU 4
+
+#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
-- 
2.17.1

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-26 13:23       ` Sascha Hauer
  0 siblings, 0 replies; 69+ messages in thread
From: Sascha Hauer @ 2018-06-26 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> Since Sascha is requesting to write a generic MU mailbox driver for both
> SCU MU and M4 case, the current way using virtual channels in this patch
> only send one word a time obviously can't fit for SCU MU clients well.
> Do you think if we can refer to TI case to design a generic data transfer
> protocol to allow send multi words which is more close to SCU?
> include/linux/soc/ti/ti-msgmgr.h
> struct ti_msgmgr_message {
>         size_t len;
>         u8 *buf;
> };  
> 
> Or we try to support both type transfer protocols in this driver?
> That may introduce much complexities, personally I'm not quite
> like that.

To give you an idea what I am suggesting see the following patch.
It implements SCU mode ontop of Oleksijs patch. Untested of course
and as said, the mailbox framework lacks some way of synchronous
receive, that would still have to be implemented and Jassi might
have his own ideas how this could be done, but it doesn't add much
complexity.

Sascha


------------------------------8<--------------------------------

>From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Tue, 26 Jun 2018 15:07:04 +0200
Subject: [PATCH] mailbox: imx-mu: Implement SCU mode

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
 include/dt-bindings/mailbox/imx-mu.h | 10 ++++
 2 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 include/dt-bindings/mailbox/imx-mu.h

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index e3f621cb1d30..a4803d1eae1d 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -10,6 +10,8 @@
 #include <linux/mailbox_controller.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/iopoll.h>
+#include <dt-bindings/mailbox/imx-mu.h>
 
 /* Transmit Register */
 #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
@@ -28,7 +30,7 @@
 /* Receive Interrupt Enable */
 #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
 
-#define IMX_MU_MAX_CHANS	4u
+#define IMX_MU_MAX_CHANS	5u
 
 struct imx_mu_priv;
 
@@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct mbox_chan *chan)
 	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));
 }
 
+// Take from some include file
+struct sc_rpc_msg {
+	uint8_t version;
+	uint8_t size;
+	uint8_t svc;
+	uint8_t func;
+};
+
+#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
+
+static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret;
+
+	for (i = 0; i < msg->size + 1; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_TEn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			goto out;
+
+		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
+	}
+
+	ret = 0;
+out:
+	mbox_chan_txdone(chan, ret);
+	return ret;
+}
+
+static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void *data)
+{
+	struct sc_rpc_msg *msg = data;
+	uint32_t *msg_raw = data;
+	int i, ret, size = 8;
+
+	for (i = 0; i < size; i++) {
+		int index = i % 4;
+		uint32_t asr;
+
+		/* Wait TX register to be empty. */
+		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR, asr,
+						asr & IMX_MU_xSR_RFn(4 - index),
+						0, MU_DATA_TIME_OUT_US);
+		if (ret)
+			return ret;
+
+		msg_raw[i] = readl(priv->base + IMX_MU_xRRn(4 - index));
+
+		if (i == 0) {
+			size = msg->size;
+			if (size > 7)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 	struct imx_mu_con_priv *cp = chan->con_priv;
 	u32 *arg = data;
 
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_send_data(priv, data);
+
 	if (!imx_mu_last_tx_done(chan))
 		return -EBUSY;
 
@@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 	return 0;
 }
 
+static int imx_mu_receive_data(struct mbox_chan *chan, void *data)
+{
+	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+	struct imx_mu_con_priv *cp = chan->con_priv;
+
+	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
+		return imx_mu_scu_receive_data(priv, data);
+
+	return -EINVAL;
+}
+
 static int imx_mu_startup(struct mbox_chan *chan)
 {
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
@@ -166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
 
 static const struct mbox_chan_ops imx_mu_ops = {
 	.send_data = imx_mu_send_data,
+	/*
+	 * FIXME: This has to be implemented in the mailbox framework.
+	 * Currently there is only support for asynchronous read using
+	 * callbacks which is not suitable for the SCU usecase.
+	 */
+//	.synchronous_read = imx_mu_receive_data,
 	.startup = imx_mu_startup,
 	.shutdown = imx_mu_shutdown,
 };
diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-bindings/mailbox/imx-mu.h
new file mode 100644
index 000000000000..4836266a7e57
--- /dev/null
+++ b/include/dt-bindings/mailbox/imx-mu.h
@@ -0,0 +1,10 @@
+#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
+#define __DT_BINDINGS_MAILBOX_IMX_MU_H
+
+#define IMX_MU_CHANNEL0		0
+#define IMX_MU_CHANNEL1		1
+#define IMX_MU_CHANNEL2		2
+#define IMX_MU_CHANNEL3		3
+#define IMX_MU_CHANNEL_IMX8_SCU 4
+
+#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
-- 
2.17.1

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-26 13:23       ` Sascha Hauer
  (?)
@ 2018-06-27  3:18         ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-27  3:18 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Mark Rutland, devicetree, Oleksij Rempel, Rob Herring,
	dl-linux-imx, kernel, Fabio Estevam, Shawn Guo, linux-clk,
	linux-arm-kernel

> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> Sent: Tuesday, June 26, 2018 9:23 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; Shawn Guo
> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>;
> devicetree@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-arm-
> kernel@lists.infradead.org; kernel@pengutronix.de; linux-
> clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> > Since Sascha is requesting to write a generic MU mailbox driver for
> > both SCU MU and M4 case, the current way using virtual channels in
> > this patch only send one word a time obviously can't fit for SCU MU clients
> well.
> > Do you think if we can refer to TI case to design a generic data
> > transfer protocol to allow send multi words which is more close to SCU?
> > include/linux/soc/ti/ti-msgmgr.h
> > struct ti_msgmgr_message {
> >         size_t len;
> >         u8 *buf;
> > };
> >
> > Or we try to support both type transfer protocols in this driver?
> > That may introduce much complexities, personally I'm not quite like
> > that.
> 
> To give you an idea what I am suggesting see the following patch.
> It implements SCU mode ontop of Oleksijs patch. Untested of course and as
> said, the mailbox framework lacks some way of synchronous receive, that
> would still have to be implemented and Jassi might have his own ideas how
> this could be done, but it doesn't add much complexity.
> 

Thanks for this.
We did similar thing as I described in another mail.
The different is we use interrupt and hrtimer to polling for rx which is the most
complicated part (Tx is quite simple). Be noted that for this demo code, we do
not need enable RX interrupt if using synchronize polling.

If the mailbox framework can support synchronize polling, that would
be good and will be much the same as we did in library way. Then we
obviously can switch to mailbox way for SCU as well.

But as I repeat before, from your demo code, you can also see those bits are
much specific to SCU MU protocol which I don't think is quite suitable to be
merged into a generic MU driver, except we can find a much common way for
handling both SCU MU and M4 case (e.g. change to TI style data transfer protocol).

But anyway, I will try it as you guys insist. Then we do not need stop at this point
for the whole QXP upstream work.

Regards
Dong Aisheng

> Sascha
> 
> 
> ------------------------------8<--------------------------------
> 
> From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
> From: Sascha Hauer <s.hauer@pengutronix.de>
> Date: Tue, 26 Jun 2018 15:07:04 +0200
> Subject: [PATCH] mailbox: imx-mu: Implement SCU mode
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
>  include/dt-bindings/mailbox/imx-mu.h | 10 ++++
>  2 files changed, 98 insertions(+), 1 deletion(-)  create mode 100644
> include/dt-bindings/mailbox/imx-mu.h
> 
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> index e3f621cb1d30..a4803d1eae1d 100644
> --- a/drivers/mailbox/imx-mailbox.c
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -10,6 +10,8 @@
>  #include <linux/mailbox_controller.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
> +#include <linux/iopoll.h>
> +#include <dt-bindings/mailbox/imx-mu.h>
> 
>  /* Transmit Register */
>  #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> @@ -28,7 +30,7 @@
>  /* Receive Interrupt Enable */
>  #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> 
> -#define IMX_MU_MAX_CHANS	4u
> +#define IMX_MU_MAX_CHANS	5u
> 
>  struct imx_mu_priv;
> 
> @@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct
> mbox_chan *chan)
>  	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));  }
> 
> +// Take from some include file
> +struct sc_rpc_msg {
> +	uint8_t version;
> +	uint8_t size;
> +	uint8_t svc;
> +	uint8_t func;
> +};
> +
> +#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
> +
> +static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data) {
> +	struct sc_rpc_msg *msg = data;
> +	uint32_t *msg_raw = data;
> +	int i, ret;
> +
> +	for (i = 0; i < msg->size + 1; i++) {
> +		int index = i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_TEn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			goto out;
> +
> +		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
> +	}
> +
> +	ret = 0;
> +out:
> +	mbox_chan_txdone(chan, ret);
> +	return ret;
> +}
> +
> +static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void
> +*data) {
> +	struct sc_rpc_msg *msg = data;
> +	uint32_t *msg_raw = data;
> +	int i, ret, size = 8;
> +
> +	for (i = 0; i < size; i++) {
> +		int index = i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_RFn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			return ret;
> +
> +		msg_raw[i] = readl(priv->base + IMX_MU_xRRn(4 - index));
> +
> +		if (i == 0) {
> +			size = msg->size;
> +			if (size > 7)
> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_mu_send_data(struct mbox_chan *chan, void *data)  {
>  	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>  	struct imx_mu_con_priv *cp = chan->con_priv;
>  	u32 *arg = data;
> 
> +	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_send_data(priv, data);
> +
>  	if (!imx_mu_last_tx_done(chan))
>  		return -EBUSY;
> 
> @@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan
> *chan, void *data)
>  	return 0;
>  }
> 
> +static int imx_mu_receive_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_receive_data(priv, data);
> +
> +	return -EINVAL;
> +}
> +
>  static int imx_mu_startup(struct mbox_chan *chan)  {
>  	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); @@ -
> 166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
> 
>  static const struct mbox_chan_ops imx_mu_ops = {
>  	.send_data = imx_mu_send_data,
> +	/*
> +	 * FIXME: This has to be implemented in the mailbox framework.
> +	 * Currently there is only support for asynchronous read using
> +	 * callbacks which is not suitable for the SCU usecase.
> +	 */
> +//	.synchronous_read = imx_mu_receive_data,
>  	.startup = imx_mu_startup,
>  	.shutdown = imx_mu_shutdown,
>  };
> diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-
> bindings/mailbox/imx-mu.h
> new file mode 100644
> index 000000000000..4836266a7e57
> --- /dev/null
> +++ b/include/dt-bindings/mailbox/imx-mu.h
> @@ -0,0 +1,10 @@
> +#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
> +#define __DT_BINDINGS_MAILBOX_IMX_MU_H
> +
> +#define IMX_MU_CHANNEL0		0
> +#define IMX_MU_CHANNEL1		1
> +#define IMX_MU_CHANNEL2		2
> +#define IMX_MU_CHANNEL3		3
> +#define IMX_MU_CHANNEL_IMX8_SCU 4
> +
> +#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
> --
> 2.17.1
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 |
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fww
> w.pengutronix.de%2F&data=02%7C01%7Caisheng.dong%40nxp.com%7C80f
> 356f57b1546baa07c08d5db67fe40%7C686ea1d3bc2b4c6fa92cd99c5c301635%7
> C0%7C0%7C636656162050199526&sdata=D0CE9mVcj8CakYwAET0aVUpGMe
> Ulz8thqzRfDgGlzkA%3D&reserved=0  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-27  3:18         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-27  3:18 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring,
	Mark Rutland, devicetree, dl-linux-imx, linux-arm-kernel, kernel,
	linux-clk

> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> Sent: Tuesday, June 26, 2018 9:23 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; Shawn Guo
> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>;
> devicetree@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-arm-
> kernel@lists.infradead.org; kernel@pengutronix.de; linux-
> clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging uni=
t
>=20
> On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> > Since Sascha is requesting to write a generic MU mailbox driver for
> > both SCU MU and M4 case, the current way using virtual channels in
> > this patch only send one word a time obviously can't fit for SCU MU cli=
ents
> well.
> > Do you think if we can refer to TI case to design a generic data
> > transfer protocol to allow send multi words which is more close to SCU?
> > include/linux/soc/ti/ti-msgmgr.h
> > struct ti_msgmgr_message {
> >         size_t len;
> >         u8 *buf;
> > };
> >
> > Or we try to support both type transfer protocols in this driver?
> > That may introduce much complexities, personally I'm not quite like
> > that.
>=20
> To give you an idea what I am suggesting see the following patch.
> It implements SCU mode ontop of Oleksijs patch. Untested of course and as
> said, the mailbox framework lacks some way of synchronous receive, that
> would still have to be implemented and Jassi might have his own ideas how
> this could be done, but it doesn't add much complexity.
>=20

Thanks for this.
We did similar thing as I described in another mail.
The different is we use interrupt and hrtimer to polling for rx which is th=
e most
complicated part (Tx is quite simple). Be noted that for this demo code, we=
 do
not need enable RX interrupt if using synchronize polling.

If the mailbox framework can support synchronize polling, that would
be good and will be much the same as we did in library way. Then we
obviously can switch to mailbox way for SCU as well.

But as I repeat before, from your demo code, you can also see those bits ar=
e
much specific to SCU MU protocol which I don't think is quite suitable to b=
e
merged into a generic MU driver, except we can find a much common way for
handling both SCU MU and M4 case (e.g. change to TI style data transfer pro=
tocol).

But anyway, I will try it as you guys insist. Then we do not need stop at t=
his point
for the whole QXP upstream work.

Regards
Dong Aisheng

> Sascha
>=20
>=20
> ------------------------------8<--------------------------------
>=20
> From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
> From: Sascha Hauer <s.hauer@pengutronix.de>
> Date: Tue, 26 Jun 2018 15:07:04 +0200
> Subject: [PATCH] mailbox: imx-mu: Implement SCU mode
>=20
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
>  include/dt-bindings/mailbox/imx-mu.h | 10 ++++
>  2 files changed, 98 insertions(+), 1 deletion(-)  create mode 100644
> include/dt-bindings/mailbox/imx-mu.h
>=20
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.=
c
> index e3f621cb1d30..a4803d1eae1d 100644
> --- a/drivers/mailbox/imx-mailbox.c
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -10,6 +10,8 @@
>  #include <linux/mailbox_controller.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
> +#include <linux/iopoll.h>
> +#include <dt-bindings/mailbox/imx-mu.h>
>=20
>  /* Transmit Register */
>  #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> @@ -28,7 +30,7 @@
>  /* Receive Interrupt Enable */
>  #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>=20
> -#define IMX_MU_MAX_CHANS	4u
> +#define IMX_MU_MAX_CHANS	5u
>=20
>  struct imx_mu_priv;
>=20
> @@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct
> mbox_chan *chan)
>  	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));  }
>=20
> +// Take from some include file
> +struct sc_rpc_msg {
> +	uint8_t version;
> +	uint8_t size;
> +	uint8_t svc;
> +	uint8_t func;
> +};
> +
> +#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
> +
> +static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data) {
> +	struct sc_rpc_msg *msg =3D data;
> +	uint32_t *msg_raw =3D data;
> +	int i, ret;
> +
> +	for (i =3D 0; i < msg->size + 1; i++) {
> +		int index =3D i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret =3D readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_TEn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			goto out;
> +
> +		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
> +	}
> +
> +	ret =3D 0;
> +out:
> +	mbox_chan_txdone(chan, ret);
> +	return ret;
> +}
> +
> +static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void
> +*data) {
> +	struct sc_rpc_msg *msg =3D data;
> +	uint32_t *msg_raw =3D data;
> +	int i, ret, size =3D 8;
> +
> +	for (i =3D 0; i < size; i++) {
> +		int index =3D i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret =3D readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_RFn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			return ret;
> +
> +		msg_raw[i] =3D readl(priv->base + IMX_MU_xRRn(4 - index));
> +
> +		if (i =3D=3D 0) {
> +			size =3D msg->size;
> +			if (size > 7)
> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_mu_send_data(struct mbox_chan *chan, void *data)  {
>  	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
>  	struct imx_mu_con_priv *cp =3D chan->con_priv;
>  	u32 *arg =3D data;
>=20
> +	if (cp->idx =3D=3D IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_send_data(priv, data);
> +
>  	if (!imx_mu_last_tx_done(chan))
>  		return -EBUSY;
>=20
> @@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan
> *chan, void *data)
>  	return 0;
>  }
>=20
> +static int imx_mu_receive_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +
> +	if (cp->idx =3D=3D IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_receive_data(priv, data);
> +
> +	return -EINVAL;
> +}
> +
>  static int imx_mu_startup(struct mbox_chan *chan)  {
>  	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox); @@ -
> 166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
>=20
>  static const struct mbox_chan_ops imx_mu_ops =3D {
>  	.send_data =3D imx_mu_send_data,
> +	/*
> +	 * FIXME: This has to be implemented in the mailbox framework.
> +	 * Currently there is only support for asynchronous read using
> +	 * callbacks which is not suitable for the SCU usecase.
> +	 */
> +//	.synchronous_read =3D imx_mu_receive_data,
>  	.startup =3D imx_mu_startup,
>  	.shutdown =3D imx_mu_shutdown,
>  };
> diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-
> bindings/mailbox/imx-mu.h
> new file mode 100644
> index 000000000000..4836266a7e57
> --- /dev/null
> +++ b/include/dt-bindings/mailbox/imx-mu.h
> @@ -0,0 +1,10 @@
> +#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
> +#define __DT_BINDINGS_MAILBOX_IMX_MU_H
> +
> +#define IMX_MU_CHANNEL0		0
> +#define IMX_MU_CHANNEL1		1
> +#define IMX_MU_CHANNEL2		2
> +#define IMX_MU_CHANNEL3		3
> +#define IMX_MU_CHANNEL_IMX8_SCU 4
> +
> +#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
> --
> 2.17.1
>=20
> --
> Pengutronix e.K.                           |                             =
|
> Industrial Linux Solutions                 |
> https://emea01.safelinks.protection.outlook.com/?url=3Dhttp%3A%2F%2Fww
> w.pengutronix.de%2F&data=3D02%7C01%7Caisheng.dong%40nxp.com%7C80f
> 356f57b1546baa07c08d5db67fe40%7C686ea1d3bc2b4c6fa92cd99c5c301635%7
> C0%7C0%7C636656162050199526&sdata=3DD0CE9mVcj8CakYwAET0aVUpGMe
> Ulz8thqzRfDgGlzkA%3D&reserved=3D0  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    =
|
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 =
|

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-06-27  3:18         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-06-27  3:18 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> Sent: Tuesday, June 26, 2018 9:23 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; Shawn Guo
> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>;
> devicetree at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-arm-
> kernel at lists.infradead.org; kernel at pengutronix.de; linux-
> clk at vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> On Tue, Jun 26, 2018 at 10:09:14AM +0000, A.s. Dong wrote:
> > Since Sascha is requesting to write a generic MU mailbox driver for
> > both SCU MU and M4 case, the current way using virtual channels in
> > this patch only send one word a time obviously can't fit for SCU MU clients
> well.
> > Do you think if we can refer to TI case to design a generic data
> > transfer protocol to allow send multi words which is more close to SCU?
> > include/linux/soc/ti/ti-msgmgr.h
> > struct ti_msgmgr_message {
> >         size_t len;
> >         u8 *buf;
> > };
> >
> > Or we try to support both type transfer protocols in this driver?
> > That may introduce much complexities, personally I'm not quite like
> > that.
> 
> To give you an idea what I am suggesting see the following patch.
> It implements SCU mode ontop of Oleksijs patch. Untested of course and as
> said, the mailbox framework lacks some way of synchronous receive, that
> would still have to be implemented and Jassi might have his own ideas how
> this could be done, but it doesn't add much complexity.
> 

Thanks for this.
We did similar thing as I described in another mail.
The different is we use interrupt and hrtimer to polling for rx which is the most
complicated part (Tx is quite simple). Be noted that for this demo code, we do
not need enable RX interrupt if using synchronize polling.

If the mailbox framework can support synchronize polling, that would
be good and will be much the same as we did in library way. Then we
obviously can switch to mailbox way for SCU as well.

But as I repeat before, from your demo code, you can also see those bits are
much specific to SCU MU protocol which I don't think is quite suitable to be
merged into a generic MU driver, except we can find a much common way for
handling both SCU MU and M4 case (e.g. change to TI style data transfer protocol).

But anyway, I will try it as you guys insist. Then we do not need stop at this point
for the whole QXP upstream work.

Regards
Dong Aisheng

> Sascha
> 
> 
> ------------------------------8<--------------------------------
> 
> From fad77078a1f1b5719fcc3c1ab789ce9cca4c9212 Mon Sep 17 00:00:00 2001
> From: Sascha Hauer <s.hauer@pengutronix.de>
> Date: Tue, 26 Jun 2018 15:07:04 +0200
> Subject: [PATCH] mailbox: imx-mu: Implement SCU mode
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/mailbox/imx-mailbox.c        | 89 +++++++++++++++++++++++++++-
>  include/dt-bindings/mailbox/imx-mu.h | 10 ++++
>  2 files changed, 98 insertions(+), 1 deletion(-)  create mode 100644
> include/dt-bindings/mailbox/imx-mu.h
> 
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> index e3f621cb1d30..a4803d1eae1d 100644
> --- a/drivers/mailbox/imx-mailbox.c
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -10,6 +10,8 @@
>  #include <linux/mailbox_controller.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
> +#include <linux/iopoll.h>
> +#include <dt-bindings/mailbox/imx-mu.h>
> 
>  /* Transmit Register */
>  #define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> @@ -28,7 +30,7 @@
>  /* Receive Interrupt Enable */
>  #define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> 
> -#define IMX_MU_MAX_CHANS	4u
> +#define IMX_MU_MAX_CHANS	5u
> 
>  struct imx_mu_priv;
> 
> @@ -119,12 +121,80 @@ static bool imx_mu_last_tx_done(struct
> mbox_chan *chan)
>  	return (!!(val & IMX_MU_xSR_TEn(cp->bidx)));  }
> 
> +// Take from some include file
> +struct sc_rpc_msg {
> +	uint8_t version;
> +	uint8_t size;
> +	uint8_t svc;
> +	uint8_t func;
> +};
> +
> +#define MU_DATA_TIME_OUT_US    (100 * USEC_PER_MSEC)
> +
> +static int imx_mu_scu_send_data(struct imx_mu_priv *priv, void *data) {
> +	struct sc_rpc_msg *msg = data;
> +	uint32_t *msg_raw = data;
> +	int i, ret;
> +
> +	for (i = 0; i < msg->size + 1; i++) {
> +		int index = i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_TEn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			goto out;
> +
> +		writel(msg_raw[i], priv->base + IMX_MU_xTRn(4 - index));
> +	}
> +
> +	ret = 0;
> +out:
> +	mbox_chan_txdone(chan, ret);
> +	return ret;
> +}
> +
> +static int imx_mu_scu_receive_data(struct imx_mu_priv *priv, void
> +*data) {
> +	struct sc_rpc_msg *msg = data;
> +	uint32_t *msg_raw = data;
> +	int i, ret, size = 8;
> +
> +	for (i = 0; i < size; i++) {
> +		int index = i % 4;
> +		uint32_t asr;
> +
> +		/* Wait TX register to be empty. */
> +		ret = readl_poll_timeout_atomic(priv->base + IMX_MU_xSR,
> asr,
> +						asr & IMX_MU_xSR_RFn(4 -
> index),
> +						0,
> MU_DATA_TIME_OUT_US);
> +		if (ret)
> +			return ret;
> +
> +		msg_raw[i] = readl(priv->base + IMX_MU_xRRn(4 - index));
> +
> +		if (i == 0) {
> +			size = msg->size;
> +			if (size > 7)
> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_mu_send_data(struct mbox_chan *chan, void *data)  {
>  	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>  	struct imx_mu_con_priv *cp = chan->con_priv;
>  	u32 *arg = data;
> 
> +	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_send_data(priv, data);
> +
>  	if (!imx_mu_last_tx_done(chan))
>  		return -EBUSY;
> 
> @@ -134,6 +204,17 @@ static int imx_mu_send_data(struct mbox_chan
> *chan, void *data)
>  	return 0;
>  }
> 
> +static int imx_mu_receive_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	if (cp->idx == IMX_MU_CHANNEL_IMX8_SCU)
> +		return imx_mu_scu_receive_data(priv, data);
> +
> +	return -EINVAL;
> +}
> +
>  static int imx_mu_startup(struct mbox_chan *chan)  {
>  	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); @@ -
> 166,6 +247,12 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
> 
>  static const struct mbox_chan_ops imx_mu_ops = {
>  	.send_data = imx_mu_send_data,
> +	/*
> +	 * FIXME: This has to be implemented in the mailbox framework.
> +	 * Currently there is only support for asynchronous read using
> +	 * callbacks which is not suitable for the SCU usecase.
> +	 */
> +//	.synchronous_read = imx_mu_receive_data,
>  	.startup = imx_mu_startup,
>  	.shutdown = imx_mu_shutdown,
>  };
> diff --git a/include/dt-bindings/mailbox/imx-mu.h b/include/dt-
> bindings/mailbox/imx-mu.h
> new file mode 100644
> index 000000000000..4836266a7e57
> --- /dev/null
> +++ b/include/dt-bindings/mailbox/imx-mu.h
> @@ -0,0 +1,10 @@
> +#ifndef __DT_BINDINGS_MAILBOX_IMX_MU_H
> +#define __DT_BINDINGS_MAILBOX_IMX_MU_H
> +
> +#define IMX_MU_CHANNEL0		0
> +#define IMX_MU_CHANNEL1		1
> +#define IMX_MU_CHANNEL2		2
> +#define IMX_MU_CHANNEL3		3
> +#define IMX_MU_CHANNEL_IMX8_SCU 4
> +
> +#endif /* __DT_BINDINGS_MAILBOX_IMX_MU_H */
> --
> 2.17.1
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 |
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fww
> w.pengutronix.de%2F&data=02%7C01%7Caisheng.dong%40nxp.com%7C80f
> 356f57b1546baa07c08d5db67fe40%7C686ea1d3bc2b4c6fa92cd99c5c301635%7
> C0%7C0%7C636656162050199526&sdata=D0CE9mVcj8CakYwAET0aVUpGMe
> Ulz8thqzRfDgGlzkA%3D&reserved=0  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-26 12:07         ` A.s. Dong
  (?)
@ 2018-07-02  7:35           ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-02  7:35 UTC (permalink / raw)
  To: A.s. Dong, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, devicetree, dl-linux-imx, linux-arm-kernel, linux-clk


[-- Attachment #1.1.1: Type: text/plain, Size: 15295 bytes --]



On 26.06.2018 14:07, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>> Sent: Tuesday, June 26, 2018 6:56 PM
>> To: A.s. Dong <aisheng.dong@nxp.com>; Shawn Guo
>> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
>> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>
>> Cc: devicetree@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-
>> arm-kernel@lists.infradead.org; kernel@pengutronix.de; linux-
>> clk@vger.kernel.org
>> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>>
>>
>> On 26.06.2018 12:09, A.s. Dong wrote:
>>>> -----Original Message-----
>>>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>>>> Sent: Friday, June 15, 2018 5:51 PM
>>>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>>>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>>>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>>>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
>>>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
>>>> linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>>>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
>>>> unit
>>>>
>>>> The Mailbox controller is able to send messages (up to 4 32 bit
>>>> words) between the endpoints.
>>>>
>>>> This driver was tested using the mailbox-test driver sending messages
>>>> between the Cortex-A7 and the Cortex-M4.
>>>>
>>>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>>>> ---
>>>>  drivers/mailbox/Kconfig       |   6 +
>>>>  drivers/mailbox/Makefile      |   2 +
>>>>  drivers/mailbox/imx-mailbox.c | 288
>>>> ++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 296 insertions(+)
>>>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>>>
>>>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>>>> a2bb27446dce..e1d2738a2e4c 100644
>>>> --- a/drivers/mailbox/Kconfig
>>>> +++ b/drivers/mailbox/Kconfig
>>>> @@ -15,6 +15,12 @@ config ARM_MHU
>>>>  	  The controller has 3 mailbox channels, the last of which can be
>>>>  	  used in Secure mode only.
>>>>
>>>> +config IMX_MBOX
>>>> +	tristate "iMX Mailbox"
>>>> +	depends on SOC_IMX7D || COMPILE_TEST
>>>> +	help
>>>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>>>> +
>>>>  config PLATFORM_MHU
>>>>  	tristate "Platform MHU Mailbox"
>>>>  	depends on OF
>>>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
>>>> index
>>>> cc23c3a43fcd..ba2fe1b6dd62 100644
>>>> --- a/drivers/mailbox/Makefile
>>>> +++ b/drivers/mailbox/Makefile
>>>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>>>
>>>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>>>
>>>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>>>> +
>>>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>>>
>>>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>>>> diff --git a/drivers/mailbox/imx-mailbox.c
>>>> b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
>>>> 000000000000..e3f621cb1d30
>>>> --- /dev/null
>>>> +++ b/drivers/mailbox/imx-mailbox.c
>>>> @@ -0,0 +1,288 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>>>> +<o.rempel@pengutronix.de>  */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/mailbox_controller.h> #include <linux/module.h>
>>>> +#include <linux/of_device.h>
>>>> +
>>>> +/* Transmit Register */
>>>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>>>> +/* Receive Register */
>>>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>>>> +/* Status Register */
>>>> +#define IMX_MU_xSR		0x20
>>>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>>>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>>>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>>>> +
>>>> +/* Control Register */
>>>> +#define IMX_MU_xCR		0x24
>>>> +/* Transmit Interrupt Enable */
>>>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>>>> +/* Receive Interrupt Enable */
>>>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>>>> +
>>>> +#define IMX_MU_MAX_CHANS	4u
>>>> +
>>>> +struct imx_mu_priv;
>>>> +
>>>> +struct imx_mu_cfg {
>>>> +	unsigned int		chans;
>>>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>>>> +
>>>> +struct imx_mu_con_priv {
>>>> +	int			irq;
>>>> +	unsigned int		bidx;
>>>> +	unsigned int		idx;
>>>> +};
>>>> +
>>>> +struct imx_mu_priv {
>>>> +	struct device		*dev;
>>>> +	const struct imx_mu_cfg	*dcfg;
>>>> +	void __iomem		*base;
>>>> +
>>>> +	struct mbox_controller	mbox;
>>>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>>>> +
>>>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>>>> +	struct clk		*clk;
>>>> +};
>>>> +
>>>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
>>>> +*mbox) {
>>>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>>>> +
>>>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>>>> +	iowrite32(val, priv->base + offs);
>>>> +}
>>>> +
>>>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>>>> +	return ioread32(priv->base + offs); }
>>>> +
>>>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
>>>> +u32
>>>> +clr) {
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, offs);
>>>> +	val &= ~clr;
>>>> +	val |= set;
>>>> +	imx_mu_write(priv, val, offs);
>>>> +
>>>> +	return val;
>>>> +}
>>>> +
>>>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>>>> +	struct mbox_chan *chan = p;
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	u32 val, dat;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>>>> +	if (!val)
>>>> +		return IRQ_NONE;
>>>> +
>>>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
>>>
>>> I'm wondering whether this can work properly for multi consumers at
>>> the same time.
>>> Because xSR_TEn is 1 by default and four virtual channels actually are
>>> using the same interrupt. That means channel 1 interrupt may cause
>>> channel 2 believe it's txdone.
>>> Have we tested such using?
>>
>> see imx_mu_send_data()
>> ..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>
>>>
>>>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>>>> bidx));
>>
>> and here ^^^
>> TX status is enabled only for send and disabled as soon at transfer is done.
>>
> 
> That controls the interrupt enable signal, I'm not sure if the status bit
> Won't be set if not enable interrupt. I've not tested it.
> 
> Have you double checked it?
> 
> For n = {0, 1, 2, 3} Processor A Transmit Register n Empty. (Read-only)
> • The TEn bit is set to “1” after the BRRn register is read on the Processor B-side.
> • After the TEn bit is set to “1”, the TEn bit signals the Processor A-side that the ATRn register is
> ready to be written on the Processor A-side, and a Transmit n interrupt is issued on the Processor
> A-side (if the TEn bit in the ACR register is set to “1”).

You are right.
> mdw phys 0x30aa0024 # read control register
0x30aa0024: 08000000  # onyl RIE for channel 0 is enabled
> mdw phys 0x30aa0020 # read status register
0x30aa0020: 00f00200  # all TE are 1

So i need to compare Control with Status regs to see if we expect an
Interrupt on for the TX.

> 
>>>> +		mbox_chan_txdone(chan, 0);
>>>> +	}
>>>> +
>>>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>>>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>>>> +		mbox_chan_received_data(chan, (void *)&dat);
>>>> +	}
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	/* test if transmit register is empty */
>>>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>>>> +
>>>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 *arg = data;
>>>> +
>>>> +	if (!imx_mu_last_tx_done(chan))
>>>> +		return -EBUSY;
>>>> +
>>>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> Since Sascha is requesting to write a generic MU mailbox driver for
>>> both SCU MU and M4 case, the current way using virtual channels in
>>> this patch only send one word a time obviously can't fit for SCU MU clients
>> well.
>>> Do you think if we can refer to TI case to design a generic data
>>> transfer protocol to allow send multi words which is more close to SCU?
>>
>> According to your code, you are able to send 1 word message. It means, your
>> SCU is configured to trigger an interrupt or status update if REG0 was written.
>> The same is true for 2, 3, 4 and 5 word messages.
>>
> 
> SCU is interrupt driven already for the first word.
> We do can send word one by one but the performance would be terrible
> comparing to write 4 a time.
> 
>> If the MU configuration would look like you it described, you would be forced
>> to write always 4 words, even for 1 word message.
>>
>>> include/linux/soc/ti/ti-msgmgr.h
>>> struct ti_msgmgr_message {
>>>         size_t len;
>>>         u8 *buf;
>>> };
>>>
>>> Or we try to support both type transfer protocols in this driver?
>>
>> Sure. ti-msgmgr.c is a good example. You will probably need reduced variant
>> of it. It is generic enough to make it useful not only for SCU.
>>
> 
> Sascha needs a common design for both M4 and SCU.If decide to do that,
> you probably need update this patch as well.
> 
> But even doing like TI style, it still need hack for SCU as the data size offset
> Is different. However, that would be a much smaller hack than doing based
> On this driver.
> 
>>> That may introduce much complexities, personally I'm not quite like
>>> that.
>>
>> I expect 50-150 lines of extra code.
>>
> 
> Hope that could be true.
> Do you have suggestion on how to keep two type protocol co-exist
> If you thought that would work without two much extra complexity?
> Have you tried it already based this driver?
> 
> Regards
> Dong Aisheng
> 
>>> Regards
>>> Dong Aisheng
>>>
>>>> +
>>>> +static int imx_mu_startup(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	int ret;
>>>> +
>>>> +	ret = request_irq(cp->irq, imx_mu_isr,
>>>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>>>> +	if (ret) {
>>>> +		dev_err(chan->mbox->dev,
>>>> +			"Unable to acquire IRQ %d\n", cp->irq);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>>>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>>>> bidx));
>>>> +
>>>> +	free_irq(cp->irq, chan);
>>>> +}
>>>> +
>>>> +static const struct mbox_chan_ops imx_mu_ops = {
>>>> +	.send_data = imx_mu_send_data,
>>>> +	.startup = imx_mu_startup,
>>>> +	.shutdown = imx_mu_shutdown,
>>>> +};
>>>> +
>>>> +static int imx_mu_probe(struct platform_device *pdev) {
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct resource *iomem;
>>>> +	struct imx_mu_priv *priv;
>>>> +	const struct imx_mu_cfg *dcfg;
>>>> +	unsigned int i, chans;
>>>> +	int irq, ret;
>>>> +
>>>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>> +	if (!priv)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	dcfg = of_device_get_match_data(dev);
>>>> +	if (!dcfg)
>>>> +		return -EINVAL;
>>>> +
>>>> +	priv->dcfg = dcfg;
>>>> +	priv->dev = dev;
>>>> +
>>>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>>>> +	if (IS_ERR(priv->base))
>>>> +		return PTR_ERR(priv->base);
>>>> +
>>>> +	irq = platform_get_irq(pdev, 0);
>>>> +	if (irq <= 0)
>>>> +		return irq < 0 ? irq : -EINVAL;
>>>> +
>>>> +	priv->clk = devm_clk_get(dev, NULL);
>>>> +	if (IS_ERR(priv->clk)) {
>>>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>>>> +			priv->clk = NULL;
>>>> +		} else {
>>>> +			dev_err(dev, "Failed to get clock\n");
>>>> +			return PTR_ERR(priv->clk);
>>>> +		}
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(priv->clk);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Failed to enable clock\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>>>> +	/* Initialize channel identifiers */
>>>> +	for (i = 0; i < chans; i++) {
>>>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>>>> +
>>>> +		cp->bidx = 3 - i;
>>>> +		cp->idx = i;
>>>> +		cp->irq = irq;
>>>> +		priv->mbox_chans[i].con_priv = cp;
>>>> +	}
>>>> +
>>>> +	priv->mbox.dev = dev;
>>>> +	priv->mbox.ops = &imx_mu_ops;
>>>> +	priv->mbox.chans = priv->mbox_chans;
>>>> +	priv->mbox.num_chans = chans;
>>>> +	priv->mbox.txdone_irq = true;
>>>> +
>>>> +	platform_set_drvdata(pdev, priv);
>>>> +
>>>> +	if (priv->dcfg->init_hw)
>>>> +		priv->dcfg->init_hw(priv);
>>>> +
>>>> +	return mbox_controller_register(&priv->mbox);
>>>> +}
>>>> +
>>>> +static int imx_mu_remove(struct platform_device *pdev) {
>>>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>>>> +
>>>> +	mbox_controller_unregister(&priv->mbox);
>>>> +	clk_disable_unprepare(priv->clk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +
>>>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>>>> +	/* Set default config */
>>>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>>>> +}
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +	.init_hw = imx_mu_init_imx7d_a,
>>>> +};
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +};
>>>> +
>>>> +static const struct of_device_id imx_mu_dt_ids[] = {
>>>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>>>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>>>> +
>>>> +static struct platform_driver imx_mu_driver = {
>>>> +	.probe		= imx_mu_probe,
>>>> +	.remove		= imx_mu_remove,
>>>> +	.driver = {
>>>> +		.name	= "imx_mu",
>>>> +		.of_match_table = imx_mu_dt_ids,
>>>> +	},
>>>> +};
>>>> +module_platform_driver(imx_mu_driver);
>>>> +
>>>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>>>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>>>> MODULE_LICENSE("GPL
>>>> +v2");
>>>> --
>>>> 2.17.1
>>>
>>>
>>>
> 


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-02  7:35           ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-02  7:35 UTC (permalink / raw)
  To: A.s. Dong, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk


[-- Attachment #1.1: Type: text/plain, Size: 15295 bytes --]



On 26.06.2018 14:07, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>> Sent: Tuesday, June 26, 2018 6:56 PM
>> To: A.s. Dong <aisheng.dong@nxp.com>; Shawn Guo
>> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
>> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>
>> Cc: devicetree@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-
>> arm-kernel@lists.infradead.org; kernel@pengutronix.de; linux-
>> clk@vger.kernel.org
>> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>>
>>
>> On 26.06.2018 12:09, A.s. Dong wrote:
>>>> -----Original Message-----
>>>> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
>>>> Sent: Friday, June 15, 2018 5:51 PM
>>>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>>>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>>>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>>>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
>>>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
>>>> linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>>>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
>>>> unit
>>>>
>>>> The Mailbox controller is able to send messages (up to 4 32 bit
>>>> words) between the endpoints.
>>>>
>>>> This driver was tested using the mailbox-test driver sending messages
>>>> between the Cortex-A7 and the Cortex-M4.
>>>>
>>>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>>>> ---
>>>>  drivers/mailbox/Kconfig       |   6 +
>>>>  drivers/mailbox/Makefile      |   2 +
>>>>  drivers/mailbox/imx-mailbox.c | 288
>>>> ++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 296 insertions(+)
>>>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>>>
>>>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>>>> a2bb27446dce..e1d2738a2e4c 100644
>>>> --- a/drivers/mailbox/Kconfig
>>>> +++ b/drivers/mailbox/Kconfig
>>>> @@ -15,6 +15,12 @@ config ARM_MHU
>>>>  	  The controller has 3 mailbox channels, the last of which can be
>>>>  	  used in Secure mode only.
>>>>
>>>> +config IMX_MBOX
>>>> +	tristate "iMX Mailbox"
>>>> +	depends on SOC_IMX7D || COMPILE_TEST
>>>> +	help
>>>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>>>> +
>>>>  config PLATFORM_MHU
>>>>  	tristate "Platform MHU Mailbox"
>>>>  	depends on OF
>>>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
>>>> index
>>>> cc23c3a43fcd..ba2fe1b6dd62 100644
>>>> --- a/drivers/mailbox/Makefile
>>>> +++ b/drivers/mailbox/Makefile
>>>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>>>
>>>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>>>
>>>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>>>> +
>>>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>>>
>>>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>>>> diff --git a/drivers/mailbox/imx-mailbox.c
>>>> b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
>>>> 000000000000..e3f621cb1d30
>>>> --- /dev/null
>>>> +++ b/drivers/mailbox/imx-mailbox.c
>>>> @@ -0,0 +1,288 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>>>> +<o.rempel@pengutronix.de>  */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/mailbox_controller.h> #include <linux/module.h>
>>>> +#include <linux/of_device.h>
>>>> +
>>>> +/* Transmit Register */
>>>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>>>> +/* Receive Register */
>>>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>>>> +/* Status Register */
>>>> +#define IMX_MU_xSR		0x20
>>>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>>>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>>>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>>>> +
>>>> +/* Control Register */
>>>> +#define IMX_MU_xCR		0x24
>>>> +/* Transmit Interrupt Enable */
>>>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>>>> +/* Receive Interrupt Enable */
>>>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>>>> +
>>>> +#define IMX_MU_MAX_CHANS	4u
>>>> +
>>>> +struct imx_mu_priv;
>>>> +
>>>> +struct imx_mu_cfg {
>>>> +	unsigned int		chans;
>>>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>>>> +
>>>> +struct imx_mu_con_priv {
>>>> +	int			irq;
>>>> +	unsigned int		bidx;
>>>> +	unsigned int		idx;
>>>> +};
>>>> +
>>>> +struct imx_mu_priv {
>>>> +	struct device		*dev;
>>>> +	const struct imx_mu_cfg	*dcfg;
>>>> +	void __iomem		*base;
>>>> +
>>>> +	struct mbox_controller	mbox;
>>>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>>>> +
>>>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>>>> +	struct clk		*clk;
>>>> +};
>>>> +
>>>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
>>>> +*mbox) {
>>>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>>>> +
>>>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>>>> +	iowrite32(val, priv->base + offs);
>>>> +}
>>>> +
>>>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>>>> +	return ioread32(priv->base + offs); }
>>>> +
>>>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
>>>> +u32
>>>> +clr) {
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, offs);
>>>> +	val &= ~clr;
>>>> +	val |= set;
>>>> +	imx_mu_write(priv, val, offs);
>>>> +
>>>> +	return val;
>>>> +}
>>>> +
>>>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>>>> +	struct mbox_chan *chan = p;
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	u32 val, dat;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>>>> +	if (!val)
>>>> +		return IRQ_NONE;
>>>> +
>>>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
>>>
>>> I'm wondering whether this can work properly for multi consumers at
>>> the same time.
>>> Because xSR_TEn is 1 by default and four virtual channels actually are
>>> using the same interrupt. That means channel 1 interrupt may cause
>>> channel 2 believe it's txdone.
>>> Have we tested such using?
>>
>> see imx_mu_send_data()
>> ..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>
>>>
>>>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>>>> bidx));
>>
>> and here ^^^
>> TX status is enabled only for send and disabled as soon at transfer is done.
>>
> 
> That controls the interrupt enable signal, I'm not sure if the status bit
> Won't be set if not enable interrupt. I've not tested it.
> 
> Have you double checked it?
> 
> For n = {0, 1, 2, 3} Processor A Transmit Register n Empty. (Read-only)
> • The TEn bit is set to “1” after the BRRn register is read on the Processor B-side.
> • After the TEn bit is set to “1”, the TEn bit signals the Processor A-side that the ATRn register is
> ready to be written on the Processor A-side, and a Transmit n interrupt is issued on the Processor
> A-side (if the TEn bit in the ACR register is set to “1”).

You are right.
> mdw phys 0x30aa0024 # read control register
0x30aa0024: 08000000  # onyl RIE for channel 0 is enabled
> mdw phys 0x30aa0020 # read status register
0x30aa0020: 00f00200  # all TE are 1

So i need to compare Control with Status regs to see if we expect an
Interrupt on for the TX.

> 
>>>> +		mbox_chan_txdone(chan, 0);
>>>> +	}
>>>> +
>>>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>>>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>>>> +		mbox_chan_received_data(chan, (void *)&dat);
>>>> +	}
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	/* test if transmit register is empty */
>>>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>>>> +
>>>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 *arg = data;
>>>> +
>>>> +	if (!imx_mu_last_tx_done(chan))
>>>> +		return -EBUSY;
>>>> +
>>>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> Since Sascha is requesting to write a generic MU mailbox driver for
>>> both SCU MU and M4 case, the current way using virtual channels in
>>> this patch only send one word a time obviously can't fit for SCU MU clients
>> well.
>>> Do you think if we can refer to TI case to design a generic data
>>> transfer protocol to allow send multi words which is more close to SCU?
>>
>> According to your code, you are able to send 1 word message. It means, your
>> SCU is configured to trigger an interrupt or status update if REG0 was written.
>> The same is true for 2, 3, 4 and 5 word messages.
>>
> 
> SCU is interrupt driven already for the first word.
> We do can send word one by one but the performance would be terrible
> comparing to write 4 a time.
> 
>> If the MU configuration would look like you it described, you would be forced
>> to write always 4 words, even for 1 word message.
>>
>>> include/linux/soc/ti/ti-msgmgr.h
>>> struct ti_msgmgr_message {
>>>         size_t len;
>>>         u8 *buf;
>>> };
>>>
>>> Or we try to support both type transfer protocols in this driver?
>>
>> Sure. ti-msgmgr.c is a good example. You will probably need reduced variant
>> of it. It is generic enough to make it useful not only for SCU.
>>
> 
> Sascha needs a common design for both M4 and SCU.If decide to do that,
> you probably need update this patch as well.
> 
> But even doing like TI style, it still need hack for SCU as the data size offset
> Is different. However, that would be a much smaller hack than doing based
> On this driver.
> 
>>> That may introduce much complexities, personally I'm not quite like
>>> that.
>>
>> I expect 50-150 lines of extra code.
>>
> 
> Hope that could be true.
> Do you have suggestion on how to keep two type protocol co-exist
> If you thought that would work without two much extra complexity?
> Have you tried it already based this driver?
> 
> Regards
> Dong Aisheng
> 
>>> Regards
>>> Dong Aisheng
>>>
>>>> +
>>>> +static int imx_mu_startup(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	int ret;
>>>> +
>>>> +	ret = request_irq(cp->irq, imx_mu_isr,
>>>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>>>> +	if (ret) {
>>>> +		dev_err(chan->mbox->dev,
>>>> +			"Unable to acquire IRQ %d\n", cp->irq);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>>>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>>>> bidx));
>>>> +
>>>> +	free_irq(cp->irq, chan);
>>>> +}
>>>> +
>>>> +static const struct mbox_chan_ops imx_mu_ops = {
>>>> +	.send_data = imx_mu_send_data,
>>>> +	.startup = imx_mu_startup,
>>>> +	.shutdown = imx_mu_shutdown,
>>>> +};
>>>> +
>>>> +static int imx_mu_probe(struct platform_device *pdev) {
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct resource *iomem;
>>>> +	struct imx_mu_priv *priv;
>>>> +	const struct imx_mu_cfg *dcfg;
>>>> +	unsigned int i, chans;
>>>> +	int irq, ret;
>>>> +
>>>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>> +	if (!priv)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	dcfg = of_device_get_match_data(dev);
>>>> +	if (!dcfg)
>>>> +		return -EINVAL;
>>>> +
>>>> +	priv->dcfg = dcfg;
>>>> +	priv->dev = dev;
>>>> +
>>>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>>>> +	if (IS_ERR(priv->base))
>>>> +		return PTR_ERR(priv->base);
>>>> +
>>>> +	irq = platform_get_irq(pdev, 0);
>>>> +	if (irq <= 0)
>>>> +		return irq < 0 ? irq : -EINVAL;
>>>> +
>>>> +	priv->clk = devm_clk_get(dev, NULL);
>>>> +	if (IS_ERR(priv->clk)) {
>>>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>>>> +			priv->clk = NULL;
>>>> +		} else {
>>>> +			dev_err(dev, "Failed to get clock\n");
>>>> +			return PTR_ERR(priv->clk);
>>>> +		}
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(priv->clk);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Failed to enable clock\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>>>> +	/* Initialize channel identifiers */
>>>> +	for (i = 0; i < chans; i++) {
>>>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>>>> +
>>>> +		cp->bidx = 3 - i;
>>>> +		cp->idx = i;
>>>> +		cp->irq = irq;
>>>> +		priv->mbox_chans[i].con_priv = cp;
>>>> +	}
>>>> +
>>>> +	priv->mbox.dev = dev;
>>>> +	priv->mbox.ops = &imx_mu_ops;
>>>> +	priv->mbox.chans = priv->mbox_chans;
>>>> +	priv->mbox.num_chans = chans;
>>>> +	priv->mbox.txdone_irq = true;
>>>> +
>>>> +	platform_set_drvdata(pdev, priv);
>>>> +
>>>> +	if (priv->dcfg->init_hw)
>>>> +		priv->dcfg->init_hw(priv);
>>>> +
>>>> +	return mbox_controller_register(&priv->mbox);
>>>> +}
>>>> +
>>>> +static int imx_mu_remove(struct platform_device *pdev) {
>>>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>>>> +
>>>> +	mbox_controller_unregister(&priv->mbox);
>>>> +	clk_disable_unprepare(priv->clk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +
>>>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>>>> +	/* Set default config */
>>>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>>>> +}
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +	.init_hw = imx_mu_init_imx7d_a,
>>>> +};
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +};
>>>> +
>>>> +static const struct of_device_id imx_mu_dt_ids[] = {
>>>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>>>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>>>> +
>>>> +static struct platform_driver imx_mu_driver = {
>>>> +	.probe		= imx_mu_probe,
>>>> +	.remove		= imx_mu_remove,
>>>> +	.driver = {
>>>> +		.name	= "imx_mu",
>>>> +		.of_match_table = imx_mu_dt_ids,
>>>> +	},
>>>> +};
>>>> +module_platform_driver(imx_mu_driver);
>>>> +
>>>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>>>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>>>> MODULE_LICENSE("GPL
>>>> +v2");
>>>> --
>>>> 2.17.1
>>>
>>>
>>>
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-02  7:35           ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-02  7:35 UTC (permalink / raw)
  To: linux-arm-kernel



On 26.06.2018 14:07, A.s. Dong wrote:
>> -----Original Message-----
>> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
>> Sent: Tuesday, June 26, 2018 6:56 PM
>> To: A.s. Dong <aisheng.dong@nxp.com>; Shawn Guo
>> <shawnguo@kernel.org>; Fabio Estevam <fabio.estevam@nxp.com>; Rob
>> Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>
>> Cc: devicetree at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-
>> arm-kernel at lists.infradead.org; kernel at pengutronix.de; linux-
>> clk at vger.kernel.org
>> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>>
>>
>>
>> On 26.06.2018 12:09, A.s. Dong wrote:
>>>> -----Original Message-----
>>>> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
>>>> Sent: Friday, June 15, 2018 5:51 PM
>>>> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
>>>> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
>>>> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
>>>> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
>>>> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
>>>> linux- clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>>>> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
>>>> unit
>>>>
>>>> The Mailbox controller is able to send messages (up to 4 32 bit
>>>> words) between the endpoints.
>>>>
>>>> This driver was tested using the mailbox-test driver sending messages
>>>> between the Cortex-A7 and the Cortex-M4.
>>>>
>>>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>>>> ---
>>>>  drivers/mailbox/Kconfig       |   6 +
>>>>  drivers/mailbox/Makefile      |   2 +
>>>>  drivers/mailbox/imx-mailbox.c | 288
>>>> ++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 296 insertions(+)
>>>>  create mode 100644 drivers/mailbox/imx-mailbox.c
>>>>
>>>> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
>>>> a2bb27446dce..e1d2738a2e4c 100644
>>>> --- a/drivers/mailbox/Kconfig
>>>> +++ b/drivers/mailbox/Kconfig
>>>> @@ -15,6 +15,12 @@ config ARM_MHU
>>>>  	  The controller has 3 mailbox channels, the last of which can be
>>>>  	  used in Secure mode only.
>>>>
>>>> +config IMX_MBOX
>>>> +	tristate "iMX Mailbox"
>>>> +	depends on SOC_IMX7D || COMPILE_TEST
>>>> +	help
>>>> +	  Mailbox implementation for iMX7D Messaging Unit (MU).
>>>> +
>>>>  config PLATFORM_MHU
>>>>  	tristate "Platform MHU Mailbox"
>>>>  	depends on OF
>>>> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
>>>> index
>>>> cc23c3a43fcd..ba2fe1b6dd62 100644
>>>> --- a/drivers/mailbox/Makefile
>>>> +++ b/drivers/mailbox/Makefile
>>>> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
>>>>
>>>>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
>>>>
>>>> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
>>>> +
>>>>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
>>>>
>>>>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
>>>> diff --git a/drivers/mailbox/imx-mailbox.c
>>>> b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
>>>> 000000000000..e3f621cb1d30
>>>> --- /dev/null
>>>> +++ b/drivers/mailbox/imx-mailbox.c
>>>> @@ -0,0 +1,288 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
>>>> +<o.rempel@pengutronix.de>  */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/mailbox_controller.h> #include <linux/module.h>
>>>> +#include <linux/of_device.h>
>>>> +
>>>> +/* Transmit Register */
>>>> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
>>>> +/* Receive Register */
>>>> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
>>>> +/* Status Register */
>>>> +#define IMX_MU_xSR		0x20
>>>> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
>>>> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
>>>> +#define IMX_MU_xSR_BRDIP	BIT(9)
>>>> +
>>>> +/* Control Register */
>>>> +#define IMX_MU_xCR		0x24
>>>> +/* Transmit Interrupt Enable */
>>>> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
>>>> +/* Receive Interrupt Enable */
>>>> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
>>>> +
>>>> +#define IMX_MU_MAX_CHANS	4u
>>>> +
>>>> +struct imx_mu_priv;
>>>> +
>>>> +struct imx_mu_cfg {
>>>> +	unsigned int		chans;
>>>> +	void (*init_hw)(struct imx_mu_priv *priv); };
>>>> +
>>>> +struct imx_mu_con_priv {
>>>> +	int			irq;
>>>> +	unsigned int		bidx;
>>>> +	unsigned int		idx;
>>>> +};
>>>> +
>>>> +struct imx_mu_priv {
>>>> +	struct device		*dev;
>>>> +	const struct imx_mu_cfg	*dcfg;
>>>> +	void __iomem		*base;
>>>> +
>>>> +	struct mbox_controller	mbox;
>>>> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
>>>> +
>>>> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
>>>> +	struct clk		*clk;
>>>> +};
>>>> +
>>>> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
>>>> +*mbox) {
>>>> +	return container_of(mbox, struct imx_mu_priv, mbox); }
>>>> +
>>>> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
>>>> +	iowrite32(val, priv->base + offs);
>>>> +}
>>>> +
>>>> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
>>>> +	return ioread32(priv->base + offs); }
>>>> +
>>>> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
>>>> +u32
>>>> +clr) {
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, offs);
>>>> +	val &= ~clr;
>>>> +	val |= set;
>>>> +	imx_mu_write(priv, val, offs);
>>>> +
>>>> +	return val;
>>>> +}
>>>> +
>>>> +static irqreturn_t imx_mu_isr(int irq, void *p) {
>>>> +	struct mbox_chan *chan = p;
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	u32 val, dat;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
>>>> +	if (!val)
>>>> +		return IRQ_NONE;
>>>> +
>>>> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
>>>
>>> I'm wondering whether this can work properly for multi consumers at
>>> the same time.
>>> Because xSR_TEn is 1 by default and four virtual channels actually are
>>> using the same interrupt. That means channel 1 interrupt may cause
>>> channel 2 believe it's txdone.
>>> Have we tested such using?
>>
>> see imx_mu_send_data()
>> ..... imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>
>>>
>>>> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
>>>>> bidx));
>>
>> and here ^^^
>> TX status is enabled only for send and disabled as soon at transfer is done.
>>
> 
> That controls the interrupt enable signal, I'm not sure if the status bit
> Won't be set if not enable interrupt. I've not tested it.
> 
> Have you double checked it?
> 
> For n = {0, 1, 2, 3} Processor A Transmit Register n Empty. (Read-only)
> ? The TEn bit is set to ?1? after the BRRn register is read on the Processor B-side.
> ? After the TEn bit is set to ?1?, the TEn bit signals the Processor A-side that the ATRn register is
> ready to be written on the Processor A-side, and a Transmit n interrupt is issued on the Processor
> A-side (if the TEn bit in the ACR register is set to ?1?).

You are right.
> mdw phys 0x30aa0024 # read control register
0x30aa0024: 08000000  # onyl RIE for channel 0 is enabled
> mdw phys 0x30aa0020 # read status register
0x30aa0020: 00f00200  # all TE are 1

So i need to compare Control with Status regs to see if we expect an
Interrupt on for the TX.

> 
>>>> +		mbox_chan_txdone(chan, 0);
>>>> +	}
>>>> +
>>>> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
>>>> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
>>>> +		mbox_chan_received_data(chan, (void *)&dat);
>>>> +	}
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 val;
>>>> +
>>>> +	val = imx_mu_read(priv, IMX_MU_xSR);
>>>> +	/* test if transmit register is empty */
>>>> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
>>>> +
>>>> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	u32 *arg = data;
>>>> +
>>>> +	if (!imx_mu_last_tx_done(chan))
>>>> +		return -EBUSY;
>>>> +
>>>> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> Since Sascha is requesting to write a generic MU mailbox driver for
>>> both SCU MU and M4 case, the current way using virtual channels in
>>> this patch only send one word a time obviously can't fit for SCU MU clients
>> well.
>>> Do you think if we can refer to TI case to design a generic data
>>> transfer protocol to allow send multi words which is more close to SCU?
>>
>> According to your code, you are able to send 1 word message. It means, your
>> SCU is configured to trigger an interrupt or status update if REG0 was written.
>> The same is true for 2, 3, 4 and 5 word messages.
>>
> 
> SCU is interrupt driven already for the first word.
> We do can send word one by one but the performance would be terrible
> comparing to write 4 a time.
> 
>> If the MU configuration would look like you it described, you would be forced
>> to write always 4 words, even for 1 word message.
>>
>>> include/linux/soc/ti/ti-msgmgr.h
>>> struct ti_msgmgr_message {
>>>         size_t len;
>>>         u8 *buf;
>>> };
>>>
>>> Or we try to support both type transfer protocols in this driver?
>>
>> Sure. ti-msgmgr.c is a good example. You will probably need reduced variant
>> of it. It is generic enough to make it useful not only for SCU.
>>
> 
> Sascha needs a common design for both M4 and SCU.If decide to do that,
> you probably need update this patch as well.
> 
> But even doing like TI style, it still need hack for SCU as the data size offset
> Is different. However, that would be a much smaller hack than doing based
> On this driver.
> 
>>> That may introduce much complexities, personally I'm not quite like
>>> that.
>>
>> I expect 50-150 lines of extra code.
>>
> 
> Hope that could be true.
> Do you have suggestion on how to keep two type protocol co-exist
> If you thought that would work without two much extra complexity?
> Have you tried it already based this driver?
> 
> Regards
> Dong Aisheng
> 
>>> Regards
>>> Dong Aisheng
>>>
>>>> +
>>>> +static int imx_mu_startup(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +	int ret;
>>>> +
>>>> +	ret = request_irq(cp->irq, imx_mu_isr,
>>>> +			  IRQF_SHARED, "imx_mu_chan", chan);
>>>> +	if (ret) {
>>>> +		dev_err(chan->mbox->dev,
>>>> +			"Unable to acquire IRQ %d\n", cp->irq);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void imx_mu_shutdown(struct mbox_chan *chan) {
>>>> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
>>>> +	struct imx_mu_con_priv *cp = chan->con_priv;
>>>> +
>>>> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
>>>> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
>>>>> bidx));
>>>> +
>>>> +	free_irq(cp->irq, chan);
>>>> +}
>>>> +
>>>> +static const struct mbox_chan_ops imx_mu_ops = {
>>>> +	.send_data = imx_mu_send_data,
>>>> +	.startup = imx_mu_startup,
>>>> +	.shutdown = imx_mu_shutdown,
>>>> +};
>>>> +
>>>> +static int imx_mu_probe(struct platform_device *pdev) {
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct resource *iomem;
>>>> +	struct imx_mu_priv *priv;
>>>> +	const struct imx_mu_cfg *dcfg;
>>>> +	unsigned int i, chans;
>>>> +	int irq, ret;
>>>> +
>>>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>> +	if (!priv)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	dcfg = of_device_get_match_data(dev);
>>>> +	if (!dcfg)
>>>> +		return -EINVAL;
>>>> +
>>>> +	priv->dcfg = dcfg;
>>>> +	priv->dev = dev;
>>>> +
>>>> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
>>>> +	if (IS_ERR(priv->base))
>>>> +		return PTR_ERR(priv->base);
>>>> +
>>>> +	irq = platform_get_irq(pdev, 0);
>>>> +	if (irq <= 0)
>>>> +		return irq < 0 ? irq : -EINVAL;
>>>> +
>>>> +	priv->clk = devm_clk_get(dev, NULL);
>>>> +	if (IS_ERR(priv->clk)) {
>>>> +		if (PTR_ERR(priv->clk) == -ENOENT) {
>>>> +			priv->clk = NULL;
>>>> +		} else {
>>>> +			dev_err(dev, "Failed to get clock\n");
>>>> +			return PTR_ERR(priv->clk);
>>>> +		}
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(priv->clk);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Failed to enable clock\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
>>>> +	/* Initialize channel identifiers */
>>>> +	for (i = 0; i < chans; i++) {
>>>> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
>>>> +
>>>> +		cp->bidx = 3 - i;
>>>> +		cp->idx = i;
>>>> +		cp->irq = irq;
>>>> +		priv->mbox_chans[i].con_priv = cp;
>>>> +	}
>>>> +
>>>> +	priv->mbox.dev = dev;
>>>> +	priv->mbox.ops = &imx_mu_ops;
>>>> +	priv->mbox.chans = priv->mbox_chans;
>>>> +	priv->mbox.num_chans = chans;
>>>> +	priv->mbox.txdone_irq = true;
>>>> +
>>>> +	platform_set_drvdata(pdev, priv);
>>>> +
>>>> +	if (priv->dcfg->init_hw)
>>>> +		priv->dcfg->init_hw(priv);
>>>> +
>>>> +	return mbox_controller_register(&priv->mbox);
>>>> +}
>>>> +
>>>> +static int imx_mu_remove(struct platform_device *pdev) {
>>>> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
>>>> +
>>>> +	mbox_controller_unregister(&priv->mbox);
>>>> +	clk_disable_unprepare(priv->clk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +
>>>> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
>>>> +	/* Set default config */
>>>> +	imx_mu_write(priv, 0, IMX_MU_xCR);
>>>> +}
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +	.init_hw = imx_mu_init_imx7d_a,
>>>> +};
>>>> +
>>>> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
>>>> +	.chans = IMX_MU_MAX_CHANS,
>>>> +};
>>>> +
>>>> +static const struct of_device_id imx_mu_dt_ids[] = {
>>>> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
>>>> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
>>>> +
>>>> +static struct platform_driver imx_mu_driver = {
>>>> +	.probe		= imx_mu_probe,
>>>> +	.remove		= imx_mu_remove,
>>>> +	.driver = {
>>>> +		.name	= "imx_mu",
>>>> +		.of_match_table = imx_mu_dt_ids,
>>>> +	},
>>>> +};
>>>> +module_platform_driver(imx_mu_driver);
>>>> +
>>>> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
>>>> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
>>>> MODULE_LICENSE("GPL
>>>> +v2");
>>>> --
>>>> 2.17.1
>>>
>>>
>>>
> 

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

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-07-09  6:22     ` Stephen Boyd
  -1 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09  6:22 UTC (permalink / raw)
  To: A.s. Dong, Fabio Estevam, Mark Rutland, Rob Herring, Shawn Guo
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>

but I think you'll want some imx maintainer to review it still.

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  6:22     ` Stephen Boyd
  0 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09  6:22 UTC (permalink / raw)
  To: A.s. Dong, Fabio Estevam, Mark Rutland, Oleksij Rempel,
	Rob Herring, Shawn Guo
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> =

> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>

but I think you'll want some imx maintainer to review it still.

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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  6:22     ` Stephen Boyd
  0 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09  6:22 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>

but I think you'll want some imx maintainer to review it still.

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-07-09  6:22     ` Stephen Boyd
  (?)
@ 2018-07-09  6:28       ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-09  6:28 UTC (permalink / raw)
  To: Stephen Boyd, A.s. Dong, Fabio Estevam, Mark Rutland,
	Rob Herring, Shawn Guo
  Cc: linux-arm-kernel, devicetree, dl-linux-imx, kernel, linux-clk


[-- Attachment #1.1.1: Type: text/plain, Size: 385 bytes --]

Hallo Fabio,

can you please review it.

On 09.07.2018 08:22, Stephen Boyd wrote:
> Quoting Oleksij Rempel (2018-06-15 02:51:04)
>> This clock is needed for iMX mailbox driver
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
> 
> Acked-by: Stephen Boyd <sboyd@kernel.org>
> 
> but I think you'll want some imx maintainer to review it still.
> 
> 


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  6:28       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-09  6:28 UTC (permalink / raw)
  To: Stephen Boyd, A.s. Dong, Fabio Estevam, Mark Rutland,
	Rob Herring, Shawn Guo
  Cc: devicetree, dl-linux-imx, kernel, linux-clk, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 385 bytes --]

Hallo Fabio,

can you please review it.

On 09.07.2018 08:22, Stephen Boyd wrote:
> Quoting Oleksij Rempel (2018-06-15 02:51:04)
>> This clock is needed for iMX mailbox driver
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
> 
> Acked-by: Stephen Boyd <sboyd@kernel.org>
> 
> but I think you'll want some imx maintainer to review it still.
> 
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  6:28       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-09  6:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hallo Fabio,

can you please review it.

On 09.07.2018 08:22, Stephen Boyd wrote:
> Quoting Oleksij Rempel (2018-06-15 02:51:04)
>> This clock is needed for iMX mailbox driver
>>
>> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
>> ---
> 
> Acked-by: Stephen Boyd <sboyd@kernel.org>
> 
> but I think you'll want some imx maintainer to review it still.
> 
> 

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

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

* RE: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-07-09  8:18     ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-09  8:18 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
> 
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>

I think this can go separately through CLK tree.

Regards
Dong Aisheng

> ---
>  drivers/clk/imx/clk-imx7d.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index
> 975a20d3cc94..c7159bfac77a 100644
> --- a/drivers/clk/imx/clk-imx7d.c
> +++ b/drivers/clk/imx/clk-imx7d.c
> @@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct
> device_node *ccm_node)
>  	clks[IMX7D_DRAM_ALT_ROOT_CLK] =
> imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
>  	clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk",
> "ipg_root_clk", base + 0x4230, 0);
>  	clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk",
> base + 0x4250, 0);
> +	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk",
> "ipg_root_clk",
> +base + 0x4270, 0);
>  	clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk",
> base + 0x4240, 0);
>  	clks[IMX7D_USB_HSIC_ROOT_CLK] =
> imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
>  	clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk",
> "ahb_root_clk", base + 0x4480, 0);
> --
> 2.17.1

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

* RE: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  8:18     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-09  8:18 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, linux-arm-kernel, devicetree, linux-clk, dl-linux-imx

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
>=20
> This clock is needed for iMX mailbox driver
>=20
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>

I think this can go separately through CLK tree.

Regards
Dong Aisheng

> ---
>  drivers/clk/imx/clk-imx7d.c | 1 +
>  1 file changed, 1 insertion(+)
>=20
> diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c in=
dex
> 975a20d3cc94..c7159bfac77a 100644
> --- a/drivers/clk/imx/clk-imx7d.c
> +++ b/drivers/clk/imx/clk-imx7d.c
> @@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct
> device_node *ccm_node)
>  	clks[IMX7D_DRAM_ALT_ROOT_CLK] =3D
> imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0)=
;
>  	clks[IMX7D_OCOTP_CLK] =3D imx_clk_gate4("ocotp_clk",
> "ipg_root_clk", base + 0x4230, 0);
>  	clks[IMX7D_SNVS_CLK] =3D imx_clk_gate4("snvs_clk", "ipg_root_clk",
> base + 0x4250, 0);
> +	clks[IMX7D_MU_ROOT_CLK] =3D imx_clk_gate4("mu_root_clk",
> "ipg_root_clk",
> +base + 0x4270, 0);
>  	clks[IMX7D_CAAM_CLK] =3D imx_clk_gate4("caam_clk", "ipg_root_clk",
> base + 0x4240, 0);
>  	clks[IMX7D_USB_HSIC_ROOT_CLK] =3D
> imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0)=
;
>  	clks[IMX7D_SDMA_CORE_CLK] =3D imx_clk_gate4("sdma_root_clk",
> "ahb_root_clk", base + 0x4480, 0);
> --
> 2.17.1


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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09  8:18     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-09  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org; linux-
> clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
> 
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>

I think this can go separately through CLK tree.

Regards
Dong Aisheng

> ---
>  drivers/clk/imx/clk-imx7d.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index
> 975a20d3cc94..c7159bfac77a 100644
> --- a/drivers/clk/imx/clk-imx7d.c
> +++ b/drivers/clk/imx/clk-imx7d.c
> @@ -795,6 +795,7 @@ static void __init imx7d_clocks_init(struct
> device_node *ccm_node)
>  	clks[IMX7D_DRAM_ALT_ROOT_CLK] =
> imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
>  	clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk",
> "ipg_root_clk", base + 0x4230, 0);
>  	clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk",
> base + 0x4250, 0);
> +	clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk",
> "ipg_root_clk",
> +base + 0x4270, 0);
>  	clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk",
> base + 0x4240, 0);
>  	clks[IMX7D_USB_HSIC_ROOT_CLK] =
> imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
>  	clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk",
> "ahb_root_clk", base + 0x4480, 0);
> --
> 2.17.1

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-07-09 12:47     ` Fabio Estevam
  -1 siblings, 0 replies; 69+ messages in thread
From: Fabio Estevam @ 2018-07-09 12:47 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, A.s. Dong,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Rob Herring, dl-linux-imx, Sascha Hauer, Fabio Estevam,
	Shawn Guo, linux-clk,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Fri, Jun 15, 2018 at 6:51 AM, Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> This clock is needed for iMX mailbox driver
>
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09 12:47     ` Fabio Estevam
  0 siblings, 0 replies; 69+ messages in thread
From: Fabio Estevam @ 2018-07-09 12:47 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, A.s. Dong,
	Sascha Hauer,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-clk, dl-linux-imx

On Fri, Jun 15, 2018 at 6:51 AM, Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> This clock is needed for iMX mailbox driver
>
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09 12:47     ` Fabio Estevam
  0 siblings, 0 replies; 69+ messages in thread
From: Fabio Estevam @ 2018-07-09 12:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 15, 2018 at 6:51 AM, Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> This clock is needed for iMX mailbox driver
>
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-07-09 16:57     ` Stephen Boyd
  -1 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09 16:57 UTC (permalink / raw)
  To: A.s. Dong, Fabio Estevam, Mark Rutland, Rob Herring, Shawn Guo
  Cc: devicetree, Oleksij Rempel, dl-linux-imx, kernel, linux-clk,
	linux-arm-kernel

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Applied to clk-next

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

* Re: [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09 16:57     ` Stephen Boyd
  0 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09 16:57 UTC (permalink / raw)
  To: A.s. Dong, Fabio Estevam, Mark Rutland, Oleksij Rempel,
	Rob Herring, Shawn Guo
  Cc: Oleksij Rempel, kernel, linux-arm-kernel, devicetree, linux-clk,
	dl-linux-imx

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> =

> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Applied to clk-next


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

* [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK
@ 2018-07-09 16:57     ` Stephen Boyd
  0 siblings, 0 replies; 69+ messages in thread
From: Stephen Boyd @ 2018-07-09 16:57 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Oleksij Rempel (2018-06-15 02:51:04)
> This clock is needed for iMX mailbox driver
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

Applied to clk-next

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-06-15  9:51   ` Oleksij Rempel
  (?)
@ 2018-07-12 11:28     ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-12 11:28 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: devicetree, dl-linux-imx, linux-arm-kernel, kernel, linux-clk

Hi Oleksij,

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
> 

This is not correct according to current implementation as we abstract them
into 4 virtual channels while each 'channel' can send only one word one time.
We probably need explain such limitation in commit message as well.

I'm not strongly against this way. But it makes the controller lose the HW
capability to send up to 4 words. I'd just like to know a bit history or reason
why we decided to do that. Do we design it for specific users case for M4?
And are we assuming there will be no real users of multi words send requirement?

> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
> 
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
> 
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST

Better change to ARCH_MXC as other platform does.

> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).

Ditto

> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> 
>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> 
> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> 
>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val = imx_mu_read(priv, offs);
> +	val &= ~clr;
> +	val |= set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan = p;
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 val;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 *arg = data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	int ret;
> +
> +	ret = request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);

I guess no need to assign the irq for each cp as we have only one irq.

> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops = {
> +	.send_data = imx_mu_send_data,
> +	.startup = imx_mu_startup,
> +	.shutdown = imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg = of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg = dcfg;
> +	priv->dev = dev;
> +
> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> +			priv->clk = NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");

I guess we may not need print it for DEFER_PROBE error case.

> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i = 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> +
> +		cp->bidx = 3 - i;

We may not need it if we improve the macro to calculate bidx by idx?

> +		cp->idx = i;
> +		cp->irq = irq;
> +		priv->mbox_chans[i].con_priv = cp;
> +	}
> +
> +	priv->mbox.dev = dev;
> +	priv->mbox.ops = &imx_mu_ops;
> +	priv->mbox.chans = priv->mbox_chans;
> +	priv->mbox.num_chans = chans;
> +	priv->mbox.txdone_irq = true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);

This will reset both MU Side A and B.
So we may need make sure Side B is initialized after A?

> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> +	.chans = IMX_MU_MAX_CHANS,
> +	.init_hw = imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> +	.chans = IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] = {
> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },

I'm not sure whether we already have the decision to use fsl,<soc>-mu compatible
String and use property to specify the mu side.
Can you double check if we can switch to that way?

And would you update the binding doc for M4 support according to the qxp mu one
Which Is already signed by Rob's tag?

Regards
Dong Aisheng

> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver = {
> +	.probe		= imx_mu_probe,
> +	.remove		= imx_mu_remove,
> +	.driver = {
> +		.name	= "imx_mu",
> +		.of_match_table = imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-12 11:28     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-12 11:28 UTC (permalink / raw)
  To: Oleksij Rempel, Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland
  Cc: kernel, linux-arm-kernel, devicetree, linux-clk, dl-linux-imx

Hi Oleksij,

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
>=20
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
>=20

This is not correct according to current implementation as we abstract them
into 4 virtual channels while each 'channel' can send only one word one tim=
e.
We probably need explain such limitation in commit message as well.

I'm not strongly against this way. But it makes the controller lose the HW
capability to send up to 4 words. I'd just like to know a bit history or re=
ason
why we decided to do that. Do we design it for specific users case for M4?
And are we assuming there will be no real users of multi words send require=
ment?

> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
>=20
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
>=20
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
>=20
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST

Better change to ARCH_MXC as other platform does.

> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).

Ditto

> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+=3D mailbox-test.o
>=20
>  obj-$(CONFIG_ARM_MHU)	+=3D arm_mhu.o
>=20
> +obj-$(CONFIG_IMX_MBOX)	+=3D imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+=3D platform_mhu.o
>=20
>  obj-$(CONFIG_PL320_MBOX)	+=3D pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.=
c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val =3D imx_mu_read(priv, offs);
> +	val &=3D ~clr;
> +	val |=3D set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan =3D p;
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> +	val &=3D IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat =3D imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	u32 val;
> +
> +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	u32 *arg =3D data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +	int ret;
> +
> +	ret =3D request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);

I guess no need to assign the irq for each cp as we have only one irq.

> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops =3D {
> +	.send_data =3D imx_mu_send_data,
> +	.startup =3D imx_mu_startup,
> +	.shutdown =3D imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev =3D &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg =3D of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg =3D dcfg;
> +	priv->dev =3D dev;
> +
> +	iomem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base =3D devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq =3D platform_get_irq(pdev, 0);
> +	if (irq <=3D 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk =3D devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) =3D=3D -ENOENT) {
> +			priv->clk =3D NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");

I guess we may not need print it for DEFER_PROBE error case.

> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret =3D clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans =3D min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i =3D 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp =3D &priv->con_priv[i];
> +
> +		cp->bidx =3D 3 - i;

We may not need it if we improve the macro to calculate bidx by idx?

> +		cp->idx =3D i;
> +		cp->irq =3D irq;
> +		priv->mbox_chans[i].con_priv =3D cp;
> +	}
> +
> +	priv->mbox.dev =3D dev;
> +	priv->mbox.ops =3D &imx_mu_ops;
> +	priv->mbox.chans =3D priv->mbox_chans;
> +	priv->mbox.num_chans =3D chans;
> +	priv->mbox.txdone_irq =3D true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv =3D platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);

This will reset both MU Side A and B.
So we may need make sure Side B is initialized after A?

> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a =3D {
> +	.chans =3D IMX_MU_MAX_CHANS,
> +	.init_hw =3D imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b =3D {
> +	.chans =3D IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] =3D {
> +	{ .compatible =3D "fsl,imx7s-mu-a", .data =3D &imx_mu_cfg_imx7d_a },
> +	{ .compatible =3D "fsl,imx7s-mu-b", .data =3D &imx_mu_cfg_imx7d_b },

I'm not sure whether we already have the decision to use fsl,<soc>-mu compa=
tible
String and use property to specify the mu side.
Can you double check if we can switch to that way?

And would you update the binding doc for M4 support according to the qxp mu=
 one
Which Is already signed by Rob's tag?

Regards
Dong Aisheng

> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver =3D {
> +	.probe		=3D imx_mu_probe,
> +	.remove		=3D imx_mu_remove,
> +	.driver =3D {
> +		.name	=3D "imx_mu",
> +		.of_match_table =3D imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1


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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-12 11:28     ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-12 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Oleksij,

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Friday, June 15, 2018 5:51 PM
> To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
> linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org; linux-
> clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> The Mailbox controller is able to send messages (up to 4 32 bit words)
> between the endpoints.
> 

This is not correct according to current implementation as we abstract them
into 4 virtual channels while each 'channel' can send only one word one time.
We probably need explain such limitation in commit message as well.

I'm not strongly against this way. But it makes the controller lose the HW
capability to send up to 4 words. I'd just like to know a bit history or reason
why we decided to do that. Do we design it for specific users case for M4?
And are we assuming there will be no real users of multi words send requirement?

> This driver was tested using the mailbox-test driver sending messages
> between the Cortex-A7 and the Cortex-M4.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/mailbox/Kconfig       |   6 +
>  drivers/mailbox/Makefile      |   2 +
>  drivers/mailbox/imx-mailbox.c | 288
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 296 insertions(+)
>  create mode 100644 drivers/mailbox/imx-mailbox.c
> 
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> a2bb27446dce..e1d2738a2e4c 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -15,6 +15,12 @@ config ARM_MHU
>  	  The controller has 3 mailbox channels, the last of which can be
>  	  used in Secure mode only.
> 
> +config IMX_MBOX
> +	tristate "iMX Mailbox"
> +	depends on SOC_IMX7D || COMPILE_TEST

Better change to ARCH_MXC as other platform does.

> +	help
> +	  Mailbox implementation for iMX7D Messaging Unit (MU).

Ditto

> +
>  config PLATFORM_MHU
>  	tristate "Platform MHU Mailbox"
>  	depends on OF
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> cc23c3a43fcd..ba2fe1b6dd62 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> 
>  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> 
> +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> +
>  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> 
>  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> new file mode 100644 index 000000000000..e3f621cb1d30
> --- /dev/null
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> +<o.rempel@pengutronix.de>  */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +
> +/* Transmit Register */
> +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> +/* Receive Register */
> +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> +/* Status Register */
> +#define IMX_MU_xSR		0x20
> +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> +#define IMX_MU_xSR_BRDIP	BIT(9)
> +
> +/* Control Register */
> +#define IMX_MU_xCR		0x24
> +/* Transmit Interrupt Enable */
> +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> +/* Receive Interrupt Enable */
> +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> +
> +#define IMX_MU_MAX_CHANS	4u
> +
> +struct imx_mu_priv;
> +
> +struct imx_mu_cfg {
> +	unsigned int		chans;
> +	void (*init_hw)(struct imx_mu_priv *priv); };
> +
> +struct imx_mu_con_priv {
> +	int			irq;
> +	unsigned int		bidx;
> +	unsigned int		idx;
> +};
> +
> +struct imx_mu_priv {
> +	struct device		*dev;
> +	const struct imx_mu_cfg	*dcfg;
> +	void __iomem		*base;
> +
> +	struct mbox_controller	mbox;
> +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> +
> +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> +	struct clk		*clk;
> +};
> +
> +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> +{
> +	return container_of(mbox, struct imx_mu_priv, mbox); }
> +
> +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> +	iowrite32(val, priv->base + offs);
> +}
> +
> +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> +	return ioread32(priv->base + offs);
> +}
> +
> +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> +clr) {
> +	u32 val;
> +
> +	val = imx_mu_read(priv, offs);
> +	val &= ~clr;
> +	val |= set;
> +	imx_mu_write(priv, val, offs);
> +
> +	return val;
> +}
> +
> +static irqreturn_t imx_mu_isr(int irq, void *p) {
> +	struct mbox_chan *chan = p;
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	u32 val, dat;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> +	if (!val)
> +		return IRQ_NONE;
> +
> +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> >bidx));
> +		mbox_chan_txdone(chan, 0);
> +	}
> +
> +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> +		mbox_chan_received_data(chan, (void *)&dat);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 val;
> +
> +	val = imx_mu_read(priv, IMX_MU_xSR);
> +	/* test if transmit register is empty */
> +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> +
> +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	u32 *arg = data;
> +
> +	if (!imx_mu_last_tx_done(chan))
> +		return -EBUSY;
> +
> +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static int imx_mu_startup(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +	int ret;
> +
> +	ret = request_irq(cp->irq, imx_mu_isr,
> +			  IRQF_SHARED, "imx_mu_chan", chan);

I guess no need to assign the irq for each cp as we have only one irq.

> +	if (ret) {
> +		dev_err(chan->mbox->dev,
> +			"Unable to acquire IRQ %d\n", cp->irq);
> +		return ret;
> +	}
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> +
> +	return 0;
> +}
> +
> +static void imx_mu_shutdown(struct mbox_chan *chan) {
> +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> +	struct imx_mu_con_priv *cp = chan->con_priv;
> +
> +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> >bidx));
> +
> +	free_irq(cp->irq, chan);
> +}
> +
> +static const struct mbox_chan_ops imx_mu_ops = {
> +	.send_data = imx_mu_send_data,
> +	.startup = imx_mu_startup,
> +	.shutdown = imx_mu_shutdown,
> +};
> +
> +static int imx_mu_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct resource *iomem;
> +	struct imx_mu_priv *priv;
> +	const struct imx_mu_cfg *dcfg;
> +	unsigned int i, chans;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dcfg = of_device_get_match_data(dev);
> +	if (!dcfg)
> +		return -EINVAL;
> +
> +	priv->dcfg = dcfg;
> +	priv->dev = dev;
> +
> +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return irq < 0 ? irq : -EINVAL;
> +
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		if (PTR_ERR(priv->clk) == -ENOENT) {
> +			priv->clk = NULL;
> +		} else {
> +			dev_err(dev, "Failed to get clock\n");

I guess we may not need print it for DEFER_PROBE error case.

> +			return PTR_ERR(priv->clk);
> +		}
> +	}
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "Failed to enable clock\n");
> +		return ret;
> +	}
> +
> +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> +	/* Initialize channel identifiers */
> +	for (i = 0; i < chans; i++) {
> +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> +
> +		cp->bidx = 3 - i;

We may not need it if we improve the macro to calculate bidx by idx?

> +		cp->idx = i;
> +		cp->irq = irq;
> +		priv->mbox_chans[i].con_priv = cp;
> +	}
> +
> +	priv->mbox.dev = dev;
> +	priv->mbox.ops = &imx_mu_ops;
> +	priv->mbox.chans = priv->mbox_chans;
> +	priv->mbox.num_chans = chans;
> +	priv->mbox.txdone_irq = true;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	if (priv->dcfg->init_hw)
> +		priv->dcfg->init_hw(priv);
> +
> +	return mbox_controller_register(&priv->mbox);
> +}
> +
> +static int imx_mu_remove(struct platform_device *pdev) {
> +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> +
> +	mbox_controller_unregister(&priv->mbox);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +
> +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> +	/* Set default config */
> +	imx_mu_write(priv, 0, IMX_MU_xCR);

This will reset both MU Side A and B.
So we may need make sure Side B is initialized after A?

> +}
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> +	.chans = IMX_MU_MAX_CHANS,
> +	.init_hw = imx_mu_init_imx7d_a,
> +};
> +
> +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> +	.chans = IMX_MU_MAX_CHANS,
> +};
> +
> +static const struct of_device_id imx_mu_dt_ids[] = {
> +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },

I'm not sure whether we already have the decision to use fsl,<soc>-mu compatible
String and use property to specify the mu side.
Can you double check if we can switch to that way?

And would you update the binding doc for M4 support according to the qxp mu one
Which Is already signed by Rob's tag?

Regards
Dong Aisheng

> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
> +
> +static struct platform_driver imx_mu_driver = {
> +	.probe		= imx_mu_probe,
> +	.remove		= imx_mu_remove,
> +	.driver = {
> +		.name	= "imx_mu",
> +		.of_match_table = imx_mu_dt_ids,
> +	},
> +};
> +module_platform_driver(imx_mu_driver);
> +
> +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
> +MODULE_DESCRIPTION("Message Unit driver for i.MX");
> MODULE_LICENSE("GPL
> +v2");
> --
> 2.17.1

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-07-12 11:28     ` A.s. Dong
  (?)
@ 2018-07-14  7:02       ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  7:02 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Mark Rutland, devicetree, Rob Herring, dl-linux-imx, kernel,
	Fabio Estevam, Shawn Guo, linux-clk, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 13064 bytes --]

Hi,

Beside, what is equivalent of name and family name is in your name?
I know it is different in China, so I won't to avoid confusion with:
"Hi $name," format :)

On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> Hi Oleksij,
> 
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > Sent: Friday, June 15, 2018 5:51 PM
> > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> > clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > The Mailbox controller is able to send messages (up to 4 32 bit words)
> > between the endpoints.
> > 
> 
> This is not correct according to current implementation as we abstract them
> into 4 virtual channels while each 'channel' can send only one word one time.
> We probably need explain such limitation in commit message as well.
> 
> I'm not strongly against this way. But it makes the controller lose the HW
> capability to send up to 4 words. I'd just like to know a bit history or reason
> why we decided to do that. Do we design it for specific users case for M4?

no, it is R&D.

> And are we assuming there will be no real users of multi words send requirement?

no. In my experience, each imaginable Brainfuck configuration will
actually happen some day in some design for $reasons.
So, no assumptions, just currently working configuration of my R&D
project.

> > This driver was tested using the mailbox-test driver sending messages
> > between the Cortex-A7 and the Cortex-M4.
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > ---
> >  drivers/mailbox/Kconfig       |   6 +
> >  drivers/mailbox/Makefile      |   2 +
> >  drivers/mailbox/imx-mailbox.c | 288
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 296 insertions(+)
> >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > 
> > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > a2bb27446dce..e1d2738a2e4c 100644
> > --- a/drivers/mailbox/Kconfig
> > +++ b/drivers/mailbox/Kconfig
> > @@ -15,6 +15,12 @@ config ARM_MHU
> >  	  The controller has 3 mailbox channels, the last of which can be
> >  	  used in Secure mode only.
> > 
> > +config IMX_MBOX
> > +	tristate "iMX Mailbox"
> > +	depends on SOC_IMX7D || COMPILE_TEST
> 
> Better change to ARCH_MXC as other platform does.

ok

> > +	help
> > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> 
> Ditto

ok

> > +
> >  config PLATFORM_MHU
> >  	tristate "Platform MHU Mailbox"
> >  	depends on OF
> > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> > cc23c3a43fcd..ba2fe1b6dd62 100644
> > --- a/drivers/mailbox/Makefile
> > +++ b/drivers/mailbox/Makefile
> > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > 
> >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > 
> > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > +
> >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > 
> >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> > new file mode 100644 index 000000000000..e3f621cb1d30
> > --- /dev/null
> > +++ b/drivers/mailbox/imx-mailbox.c
> > @@ -0,0 +1,288 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > +<o.rempel@pengutronix.de>  */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mailbox_controller.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +
> > +/* Transmit Register */
> > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > +/* Receive Register */
> > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > +/* Status Register */
> > +#define IMX_MU_xSR		0x20
> > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > +
> > +/* Control Register */
> > +#define IMX_MU_xCR		0x24
> > +/* Transmit Interrupt Enable */
> > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > +/* Receive Interrupt Enable */
> > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > +
> > +#define IMX_MU_MAX_CHANS	4u
> > +
> > +struct imx_mu_priv;
> > +
> > +struct imx_mu_cfg {
> > +	unsigned int		chans;
> > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > +
> > +struct imx_mu_con_priv {
> > +	int			irq;
> > +	unsigned int		bidx;
> > +	unsigned int		idx;
> > +};
> > +
> > +struct imx_mu_priv {
> > +	struct device		*dev;
> > +	const struct imx_mu_cfg	*dcfg;
> > +	void __iomem		*base;
> > +
> > +	struct mbox_controller	mbox;
> > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > +
> > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > +	struct clk		*clk;
> > +};
> > +
> > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> > +{
> > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > +
> > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > +	iowrite32(val, priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > +	return ioread32(priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> > +clr) {
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, offs);
> > +	val &= ~clr;
> > +	val |= set;
> > +	imx_mu_write(priv, val, offs);
> > +
> > +	return val;
> > +}
> > +
> > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > +	struct mbox_chan *chan = p;
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	u32 val, dat;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > +	if (!val)
> > +		return IRQ_NONE;
> > +
> > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > >bidx));
> > +		mbox_chan_txdone(chan, 0);
> > +	}
> > +
> > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > +		mbox_chan_received_data(chan, (void *)&dat);
> > +	}
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	/* test if transmit register is empty */
> > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > +
> > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 *arg = data;
> > +
> > +	if (!imx_mu_last_tx_done(chan))
> > +		return -EBUSY;
> > +
> > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static int imx_mu_startup(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	int ret;
> > +
> > +	ret = request_irq(cp->irq, imx_mu_isr,
> > +			  IRQF_SHARED, "imx_mu_chan", chan);
> 
> I guess no need to assign the irq for each cp as we have only one irq.

all irq chip controller have one sink and number of source limited to
imagination or amount of bits in a register. May be we will need some day to
write a irqchip driver to make it work as chained irq controller.

So, I don't see any technical reason to not do it. Are you?

> > +	if (ret) {
> > +		dev_err(chan->mbox->dev,
> > +			"Unable to acquire IRQ %d\n", cp->irq);
> > +		return ret;
> > +	}
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > >bidx));
> > +
> > +	free_irq(cp->irq, chan);
> > +}
> > +
> > +static const struct mbox_chan_ops imx_mu_ops = {
> > +	.send_data = imx_mu_send_data,
> > +	.startup = imx_mu_startup,
> > +	.shutdown = imx_mu_shutdown,
> > +};
> > +
> > +static int imx_mu_probe(struct platform_device *pdev) {
> > +	struct device *dev = &pdev->dev;
> > +	struct resource *iomem;
> > +	struct imx_mu_priv *priv;
> > +	const struct imx_mu_cfg *dcfg;
> > +	unsigned int i, chans;
> > +	int irq, ret;
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	dcfg = of_device_get_match_data(dev);
> > +	if (!dcfg)
> > +		return -EINVAL;
> > +
> > +	priv->dcfg = dcfg;
> > +	priv->dev = dev;
> > +
> > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > +	if (IS_ERR(priv->base))
> > +		return PTR_ERR(priv->base);
> > +
> > +	irq = platform_get_irq(pdev, 0);
> > +	if (irq <= 0)
> > +		return irq < 0 ? irq : -EINVAL;
> > +
> > +	priv->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(priv->clk)) {
> > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > +			priv->clk = NULL;
> > +		} else {
> > +			dev_err(dev, "Failed to get clock\n");
> 
> I guess we may not need print it for DEFER_PROBE error case.

ok.

> > +			return PTR_ERR(priv->clk);
> > +		}
> > +	}
> > +
> > +	ret = clk_prepare_enable(priv->clk);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to enable clock\n");
> > +		return ret;
> > +	}
> > +
> > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > +	/* Initialize channel identifiers */
> > +	for (i = 0; i < chans; i++) {
> > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > +
> > +		cp->bidx = 3 - i;
> 
> We may not need it if we improve the macro to calculate bidx by idx?

Are all implementation of NXP MU have reversed bit order?
Will it fit good for one channel implementation?

> > +		cp->idx = i;
> > +		cp->irq = irq;
> > +		priv->mbox_chans[i].con_priv = cp;
> > +	}
> > +
> > +	priv->mbox.dev = dev;
> > +	priv->mbox.ops = &imx_mu_ops;
> > +	priv->mbox.chans = priv->mbox_chans;
> > +	priv->mbox.num_chans = chans;
> > +	priv->mbox.txdone_irq = true;
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +
> > +	if (priv->dcfg->init_hw)
> > +		priv->dcfg->init_hw(priv);
> > +
> > +	return mbox_controller_register(&priv->mbox);
> > +}
> > +
> > +static int imx_mu_remove(struct platform_device *pdev) {
> > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > +
> > +	mbox_controller_unregister(&priv->mbox);
> > +	clk_disable_unprepare(priv->clk);
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > +	/* Set default config */
> > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> 
> This will reset both MU Side A and B.
> So we may need make sure Side B is initialized after A?

I assume it is implementation specific, as soon as it will be needed,
we may introduce extra DT flag. No need to cover all possible cases if
we don't have to.

> > +}
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +	.init_hw = imx_mu_init_imx7d_a,
> > +};
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +};
> > +
> > +static const struct of_device_id imx_mu_dt_ids[] = {
> > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> 
> I'm not sure whether we already have the decision to use fsl,<soc>-mu compatible
> String and use property to specify the mu side.
> Can you double check if we can switch to that way?

ok.

> And would you update the binding doc for M4 support according to the qxp mu one
> Which Is already signed by Rob's tag?

ok.

So, should I update my patch set including DT binding documentation
prior to yours?

If yes, can you please contact Rob to avoid confusions.

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  7:02       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  7:02 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, devicetree,
	dl-linux-imx, linux-arm-kernel, kernel, linux-clk

[-- Attachment #1: Type: text/plain, Size: 13064 bytes --]

Hi,

Beside, what is equivalent of name and family name is in your name?
I know it is different in China, so I won't to avoid confusion with:
"Hi $name," format :)

On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> Hi Oleksij,
> 
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > Sent: Friday, June 15, 2018 5:51 PM
> > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel@pengutronix.de;
> > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-
> > clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > The Mailbox controller is able to send messages (up to 4 32 bit words)
> > between the endpoints.
> > 
> 
> This is not correct according to current implementation as we abstract them
> into 4 virtual channels while each 'channel' can send only one word one time.
> We probably need explain such limitation in commit message as well.
> 
> I'm not strongly against this way. But it makes the controller lose the HW
> capability to send up to 4 words. I'd just like to know a bit history or reason
> why we decided to do that. Do we design it for specific users case for M4?

no, it is R&D.

> And are we assuming there will be no real users of multi words send requirement?

no. In my experience, each imaginable Brainfuck configuration will
actually happen some day in some design for $reasons.
So, no assumptions, just currently working configuration of my R&D
project.

> > This driver was tested using the mailbox-test driver sending messages
> > between the Cortex-A7 and the Cortex-M4.
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > ---
> >  drivers/mailbox/Kconfig       |   6 +
> >  drivers/mailbox/Makefile      |   2 +
> >  drivers/mailbox/imx-mailbox.c | 288
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 296 insertions(+)
> >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > 
> > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > a2bb27446dce..e1d2738a2e4c 100644
> > --- a/drivers/mailbox/Kconfig
> > +++ b/drivers/mailbox/Kconfig
> > @@ -15,6 +15,12 @@ config ARM_MHU
> >  	  The controller has 3 mailbox channels, the last of which can be
> >  	  used in Secure mode only.
> > 
> > +config IMX_MBOX
> > +	tristate "iMX Mailbox"
> > +	depends on SOC_IMX7D || COMPILE_TEST
> 
> Better change to ARCH_MXC as other platform does.

ok

> > +	help
> > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> 
> Ditto

ok

> > +
> >  config PLATFORM_MHU
> >  	tristate "Platform MHU Mailbox"
> >  	depends on OF
> > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> > cc23c3a43fcd..ba2fe1b6dd62 100644
> > --- a/drivers/mailbox/Makefile
> > +++ b/drivers/mailbox/Makefile
> > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > 
> >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > 
> > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > +
> >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > 
> >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> > new file mode 100644 index 000000000000..e3f621cb1d30
> > --- /dev/null
> > +++ b/drivers/mailbox/imx-mailbox.c
> > @@ -0,0 +1,288 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > +<o.rempel@pengutronix.de>  */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mailbox_controller.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +
> > +/* Transmit Register */
> > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > +/* Receive Register */
> > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > +/* Status Register */
> > +#define IMX_MU_xSR		0x20
> > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > +
> > +/* Control Register */
> > +#define IMX_MU_xCR		0x24
> > +/* Transmit Interrupt Enable */
> > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > +/* Receive Interrupt Enable */
> > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > +
> > +#define IMX_MU_MAX_CHANS	4u
> > +
> > +struct imx_mu_priv;
> > +
> > +struct imx_mu_cfg {
> > +	unsigned int		chans;
> > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > +
> > +struct imx_mu_con_priv {
> > +	int			irq;
> > +	unsigned int		bidx;
> > +	unsigned int		idx;
> > +};
> > +
> > +struct imx_mu_priv {
> > +	struct device		*dev;
> > +	const struct imx_mu_cfg	*dcfg;
> > +	void __iomem		*base;
> > +
> > +	struct mbox_controller	mbox;
> > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > +
> > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > +	struct clk		*clk;
> > +};
> > +
> > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> > +{
> > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > +
> > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > +	iowrite32(val, priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > +	return ioread32(priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> > +clr) {
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, offs);
> > +	val &= ~clr;
> > +	val |= set;
> > +	imx_mu_write(priv, val, offs);
> > +
> > +	return val;
> > +}
> > +
> > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > +	struct mbox_chan *chan = p;
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	u32 val, dat;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > +	if (!val)
> > +		return IRQ_NONE;
> > +
> > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > >bidx));
> > +		mbox_chan_txdone(chan, 0);
> > +	}
> > +
> > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > +		mbox_chan_received_data(chan, (void *)&dat);
> > +	}
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	/* test if transmit register is empty */
> > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > +
> > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 *arg = data;
> > +
> > +	if (!imx_mu_last_tx_done(chan))
> > +		return -EBUSY;
> > +
> > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static int imx_mu_startup(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	int ret;
> > +
> > +	ret = request_irq(cp->irq, imx_mu_isr,
> > +			  IRQF_SHARED, "imx_mu_chan", chan);
> 
> I guess no need to assign the irq for each cp as we have only one irq.

all irq chip controller have one sink and number of source limited to
imagination or amount of bits in a register. May be we will need some day to
write a irqchip driver to make it work as chained irq controller.

So, I don't see any technical reason to not do it. Are you?

> > +	if (ret) {
> > +		dev_err(chan->mbox->dev,
> > +			"Unable to acquire IRQ %d\n", cp->irq);
> > +		return ret;
> > +	}
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > >bidx));
> > +
> > +	free_irq(cp->irq, chan);
> > +}
> > +
> > +static const struct mbox_chan_ops imx_mu_ops = {
> > +	.send_data = imx_mu_send_data,
> > +	.startup = imx_mu_startup,
> > +	.shutdown = imx_mu_shutdown,
> > +};
> > +
> > +static int imx_mu_probe(struct platform_device *pdev) {
> > +	struct device *dev = &pdev->dev;
> > +	struct resource *iomem;
> > +	struct imx_mu_priv *priv;
> > +	const struct imx_mu_cfg *dcfg;
> > +	unsigned int i, chans;
> > +	int irq, ret;
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	dcfg = of_device_get_match_data(dev);
> > +	if (!dcfg)
> > +		return -EINVAL;
> > +
> > +	priv->dcfg = dcfg;
> > +	priv->dev = dev;
> > +
> > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > +	if (IS_ERR(priv->base))
> > +		return PTR_ERR(priv->base);
> > +
> > +	irq = platform_get_irq(pdev, 0);
> > +	if (irq <= 0)
> > +		return irq < 0 ? irq : -EINVAL;
> > +
> > +	priv->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(priv->clk)) {
> > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > +			priv->clk = NULL;
> > +		} else {
> > +			dev_err(dev, "Failed to get clock\n");
> 
> I guess we may not need print it for DEFER_PROBE error case.

ok.

> > +			return PTR_ERR(priv->clk);
> > +		}
> > +	}
> > +
> > +	ret = clk_prepare_enable(priv->clk);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to enable clock\n");
> > +		return ret;
> > +	}
> > +
> > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > +	/* Initialize channel identifiers */
> > +	for (i = 0; i < chans; i++) {
> > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > +
> > +		cp->bidx = 3 - i;
> 
> We may not need it if we improve the macro to calculate bidx by idx?

Are all implementation of NXP MU have reversed bit order?
Will it fit good for one channel implementation?

> > +		cp->idx = i;
> > +		cp->irq = irq;
> > +		priv->mbox_chans[i].con_priv = cp;
> > +	}
> > +
> > +	priv->mbox.dev = dev;
> > +	priv->mbox.ops = &imx_mu_ops;
> > +	priv->mbox.chans = priv->mbox_chans;
> > +	priv->mbox.num_chans = chans;
> > +	priv->mbox.txdone_irq = true;
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +
> > +	if (priv->dcfg->init_hw)
> > +		priv->dcfg->init_hw(priv);
> > +
> > +	return mbox_controller_register(&priv->mbox);
> > +}
> > +
> > +static int imx_mu_remove(struct platform_device *pdev) {
> > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > +
> > +	mbox_controller_unregister(&priv->mbox);
> > +	clk_disable_unprepare(priv->clk);
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > +	/* Set default config */
> > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> 
> This will reset both MU Side A and B.
> So we may need make sure Side B is initialized after A?

I assume it is implementation specific, as soon as it will be needed,
we may introduce extra DT flag. No need to cover all possible cases if
we don't have to.

> > +}
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +	.init_hw = imx_mu_init_imx7d_a,
> > +};
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +};
> > +
> > +static const struct of_device_id imx_mu_dt_ids[] = {
> > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> 
> I'm not sure whether we already have the decision to use fsl,<soc>-mu compatible
> String and use property to specify the mu side.
> Can you double check if we can switch to that way?

ok.

> And would you update the binding doc for M4 support according to the qxp mu one
> Which Is already signed by Rob's tag?

ok.

So, should I update my patch set including DT binding documentation
prior to yours?

If yes, can you please contact Rob to avoid confusions.

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  7:02       ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  7:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Beside, what is equivalent of name and family name is in your name?
I know it is different in China, so I won't to avoid confusion with:
"Hi $name," format :)

On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> Hi Oleksij,
> 
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > Sent: Friday, June 15, 2018 5:51 PM
> > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Oleksij Rempel <o.rempel@pengutronix.de>; kernel at pengutronix.de;
> > linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org; linux-
> > clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > The Mailbox controller is able to send messages (up to 4 32 bit words)
> > between the endpoints.
> > 
> 
> This is not correct according to current implementation as we abstract them
> into 4 virtual channels while each 'channel' can send only one word one time.
> We probably need explain such limitation in commit message as well.
> 
> I'm not strongly against this way. But it makes the controller lose the HW
> capability to send up to 4 words. I'd just like to know a bit history or reason
> why we decided to do that. Do we design it for specific users case for M4?

no, it is R&D.

> And are we assuming there will be no real users of multi words send requirement?

no. In my experience, each imaginable Brainfuck configuration will
actually happen some day in some design for $reasons.
So, no assumptions, just currently working configuration of my R&D
project.

> > This driver was tested using the mailbox-test driver sending messages
> > between the Cortex-A7 and the Cortex-M4.
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > ---
> >  drivers/mailbox/Kconfig       |   6 +
> >  drivers/mailbox/Makefile      |   2 +
> >  drivers/mailbox/imx-mailbox.c | 288
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 296 insertions(+)
> >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > 
> > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > a2bb27446dce..e1d2738a2e4c 100644
> > --- a/drivers/mailbox/Kconfig
> > +++ b/drivers/mailbox/Kconfig
> > @@ -15,6 +15,12 @@ config ARM_MHU
> >  	  The controller has 3 mailbox channels, the last of which can be
> >  	  used in Secure mode only.
> > 
> > +config IMX_MBOX
> > +	tristate "iMX Mailbox"
> > +	depends on SOC_IMX7D || COMPILE_TEST
> 
> Better change to ARCH_MXC as other platform does.

ok

> > +	help
> > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> 
> Ditto

ok

> > +
> >  config PLATFORM_MHU
> >  	tristate "Platform MHU Mailbox"
> >  	depends on OF
> > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index
> > cc23c3a43fcd..ba2fe1b6dd62 100644
> > --- a/drivers/mailbox/Makefile
> > +++ b/drivers/mailbox/Makefile
> > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > 
> >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > 
> > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > +
> >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > 
> >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> > new file mode 100644 index 000000000000..e3f621cb1d30
> > --- /dev/null
> > +++ b/drivers/mailbox/imx-mailbox.c
> > @@ -0,0 +1,288 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > +<o.rempel@pengutronix.de>  */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mailbox_controller.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +
> > +/* Transmit Register */
> > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > +/* Receive Register */
> > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > +/* Status Register */
> > +#define IMX_MU_xSR		0x20
> > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > +
> > +/* Control Register */
> > +#define IMX_MU_xCR		0x24
> > +/* Transmit Interrupt Enable */
> > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > +/* Receive Interrupt Enable */
> > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > +
> > +#define IMX_MU_MAX_CHANS	4u
> > +
> > +struct imx_mu_priv;
> > +
> > +struct imx_mu_cfg {
> > +	unsigned int		chans;
> > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > +
> > +struct imx_mu_con_priv {
> > +	int			irq;
> > +	unsigned int		bidx;
> > +	unsigned int		idx;
> > +};
> > +
> > +struct imx_mu_priv {
> > +	struct device		*dev;
> > +	const struct imx_mu_cfg	*dcfg;
> > +	void __iomem		*base;
> > +
> > +	struct mbox_controller	mbox;
> > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > +
> > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > +	struct clk		*clk;
> > +};
> > +
> > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
> > +{
> > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > +
> > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > +	iowrite32(val, priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > +	return ioread32(priv->base + offs);
> > +}
> > +
> > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set, u32
> > +clr) {
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, offs);
> > +	val &= ~clr;
> > +	val |= set;
> > +	imx_mu_write(priv, val, offs);
> > +
> > +	return val;
> > +}
> > +
> > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > +	struct mbox_chan *chan = p;
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	u32 val, dat;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > +	if (!val)
> > +		return IRQ_NONE;
> > +
> > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > >bidx));
> > +		mbox_chan_txdone(chan, 0);
> > +	}
> > +
> > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > +		mbox_chan_received_data(chan, (void *)&dat);
> > +	}
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 val;
> > +
> > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > +	/* test if transmit register is empty */
> > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > +
> > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	u32 *arg = data;
> > +
> > +	if (!imx_mu_last_tx_done(chan))
> > +		return -EBUSY;
> > +
> > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static int imx_mu_startup(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +	int ret;
> > +
> > +	ret = request_irq(cp->irq, imx_mu_isr,
> > +			  IRQF_SHARED, "imx_mu_chan", chan);
> 
> I guess no need to assign the irq for each cp as we have only one irq.

all irq chip controller have one sink and number of source limited to
imagination or amount of bits in a register. May be we will need some day to
write a irqchip driver to make it work as chained irq controller.

So, I don't see any technical reason to not do it. Are you?

> > +	if (ret) {
> > +		dev_err(chan->mbox->dev,
> > +			"Unable to acquire IRQ %d\n", cp->irq);
> > +		return ret;
> > +	}
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > +
> > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > >bidx));
> > +
> > +	free_irq(cp->irq, chan);
> > +}
> > +
> > +static const struct mbox_chan_ops imx_mu_ops = {
> > +	.send_data = imx_mu_send_data,
> > +	.startup = imx_mu_startup,
> > +	.shutdown = imx_mu_shutdown,
> > +};
> > +
> > +static int imx_mu_probe(struct platform_device *pdev) {
> > +	struct device *dev = &pdev->dev;
> > +	struct resource *iomem;
> > +	struct imx_mu_priv *priv;
> > +	const struct imx_mu_cfg *dcfg;
> > +	unsigned int i, chans;
> > +	int irq, ret;
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	dcfg = of_device_get_match_data(dev);
> > +	if (!dcfg)
> > +		return -EINVAL;
> > +
> > +	priv->dcfg = dcfg;
> > +	priv->dev = dev;
> > +
> > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > +	if (IS_ERR(priv->base))
> > +		return PTR_ERR(priv->base);
> > +
> > +	irq = platform_get_irq(pdev, 0);
> > +	if (irq <= 0)
> > +		return irq < 0 ? irq : -EINVAL;
> > +
> > +	priv->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(priv->clk)) {
> > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > +			priv->clk = NULL;
> > +		} else {
> > +			dev_err(dev, "Failed to get clock\n");
> 
> I guess we may not need print it for DEFER_PROBE error case.

ok.

> > +			return PTR_ERR(priv->clk);
> > +		}
> > +	}
> > +
> > +	ret = clk_prepare_enable(priv->clk);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to enable clock\n");
> > +		return ret;
> > +	}
> > +
> > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > +	/* Initialize channel identifiers */
> > +	for (i = 0; i < chans; i++) {
> > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > +
> > +		cp->bidx = 3 - i;
> 
> We may not need it if we improve the macro to calculate bidx by idx?

Are all implementation of NXP MU have reversed bit order?
Will it fit good for one channel implementation?

> > +		cp->idx = i;
> > +		cp->irq = irq;
> > +		priv->mbox_chans[i].con_priv = cp;
> > +	}
> > +
> > +	priv->mbox.dev = dev;
> > +	priv->mbox.ops = &imx_mu_ops;
> > +	priv->mbox.chans = priv->mbox_chans;
> > +	priv->mbox.num_chans = chans;
> > +	priv->mbox.txdone_irq = true;
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +
> > +	if (priv->dcfg->init_hw)
> > +		priv->dcfg->init_hw(priv);
> > +
> > +	return mbox_controller_register(&priv->mbox);
> > +}
> > +
> > +static int imx_mu_remove(struct platform_device *pdev) {
> > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > +
> > +	mbox_controller_unregister(&priv->mbox);
> > +	clk_disable_unprepare(priv->clk);
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > +	/* Set default config */
> > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> 
> This will reset both MU Side A and B.
> So we may need make sure Side B is initialized after A?

I assume it is implementation specific, as soon as it will be needed,
we may introduce extra DT flag. No need to cover all possible cases if
we don't have to.

> > +}
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +	.init_hw = imx_mu_init_imx7d_a,
> > +};
> > +
> > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > +	.chans = IMX_MU_MAX_CHANS,
> > +};
> > +
> > +static const struct of_device_id imx_mu_dt_ids[] = {
> > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> 
> I'm not sure whether we already have the decision to use fsl,<soc>-mu compatible
> String and use property to specify the mu side.
> Can you double check if we can switch to that way?

ok.

> And would you update the binding doc for M4 support according to the qxp mu one
> Which Is already signed by Rob's tag?

ok.

So, should I update my patch set including DT binding documentation
prior to yours?

If yes, can you please contact Rob to avoid confusions.

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180714/3a574844/attachment.sig>

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-07-14  7:02       ` Oleksij Rempel
  (?)
@ 2018-07-14  8:49         ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14  8:49 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, devicetree, Rob Herring, dl-linux-imx, kernel,
	Fabio Estevam, Shawn Guo, linux-clk, linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Saturday, July 14, 2018 3:02 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> kernel@pengutronix.de; linux-clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> Hi,
> 
> Beside, what is equivalent of name and family name is in your name?
> I know it is different in China, so I won't to avoid confusion with:
> "Hi $name," format :)
> 

Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)

> On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > Hi Oleksij,
> >
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > Sent: Friday, June 15, 2018 5:51 PM
> > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> kernel@pengutronix.de;
> > > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > unit
> > >
> > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > words) between the endpoints.
> > >
> >
> > This is not correct according to current implementation as we abstract
> > them into 4 virtual channels while each 'channel' can send only one word
> one time.
> > We probably need explain such limitation in commit message as well.
> >
> > I'm not strongly against this way. But it makes the controller lose
> > the HW capability to send up to 4 words. I'd just like to know a bit
> > history or reason why we decided to do that. Do we design it for specific
> users case for M4?
> 
> no, it is R&D.
> 

Got it

> > And are we assuming there will be no real users of multi words send
> requirement?
> 
> no. In my experience, each imaginable Brainfuck configuration will actually
> happen some day in some design for $reasons.
> So, no assumptions, just currently working configuration of my R&D project.
> 

I'm fine with as it is currently. We don't have to address all possible
Issues in one time.

> > > This driver was tested using the mailbox-test driver sending
> > > messages between the Cortex-A7 and the Cortex-M4.
> > >
> > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > ---
> > >  drivers/mailbox/Kconfig       |   6 +
> > >  drivers/mailbox/Makefile      |   2 +
> > >  drivers/mailbox/imx-mailbox.c | 288
> > > ++++++++++++++++++++++++++++++++++
> > >  3 files changed, 296 insertions(+)
> > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > >
> > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > a2bb27446dce..e1d2738a2e4c 100644
> > > --- a/drivers/mailbox/Kconfig
> > > +++ b/drivers/mailbox/Kconfig
> > > @@ -15,6 +15,12 @@ config ARM_MHU
> > >  	  The controller has 3 mailbox channels, the last of which can be
> > >  	  used in Secure mode only.
> > >
> > > +config IMX_MBOX
> > > +	tristate "iMX Mailbox"
> > > +	depends on SOC_IMX7D || COMPILE_TEST
> >
> > Better change to ARCH_MXC as other platform does.
> 
> ok
> 
> > > +	help
> > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> >
> > Ditto
> 
> ok
> 
> > > +
> > >  config PLATFORM_MHU
> > >  	tristate "Platform MHU Mailbox"
> > >  	depends on OF
> > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > index
> > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > --- a/drivers/mailbox/Makefile
> > > +++ b/drivers/mailbox/Makefile
> > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > >
> > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > >
> > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > +
> > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > >
> > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > 000000000000..e3f621cb1d30
> > > --- /dev/null
> > > +++ b/drivers/mailbox/imx-mailbox.c
> > > @@ -0,0 +1,288 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > +<o.rempel@pengutronix.de>  */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +
> > > +/* Transmit Register */
> > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > +/* Receive Register */
> > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > +/* Status Register */
> > > +#define IMX_MU_xSR		0x20
> > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > +
> > > +/* Control Register */
> > > +#define IMX_MU_xCR		0x24
> > > +/* Transmit Interrupt Enable */
> > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > +/* Receive Interrupt Enable */
> > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > +
> > > +#define IMX_MU_MAX_CHANS	4u
> > > +
> > > +struct imx_mu_priv;
> > > +
> > > +struct imx_mu_cfg {
> > > +	unsigned int		chans;
> > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > +
> > > +struct imx_mu_con_priv {
> > > +	int			irq;
> > > +	unsigned int		bidx;
> > > +	unsigned int		idx;
> > > +};
> > > +
> > > +struct imx_mu_priv {
> > > +	struct device		*dev;
> > > +	const struct imx_mu_cfg	*dcfg;
> > > +	void __iomem		*base;
> > > +
> > > +	struct mbox_controller	mbox;
> > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > +
> > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > +	struct clk		*clk;
> > > +};
> > > +
> > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > +*mbox) {
> > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > +
> > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > > +	iowrite32(val, priv->base + offs); }
> > > +
> > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > +	return ioread32(priv->base + offs); }
> > > +
> > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > +u32
> > > +clr) {
> > > +	u32 val;
> > > +
> > > +	val = imx_mu_read(priv, offs);
> > > +	val &= ~clr;
> > > +	val |= set;
> > > +	imx_mu_write(priv, val, offs);
> > > +
> > > +	return val;
> > > +}
> > > +
> > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > +	struct mbox_chan *chan = p;
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +
> > > +	u32 val, dat;
> > > +
> > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > +	if (!val)
> > > +		return IRQ_NONE;
> > > +
> > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > >bidx));
> > > +		mbox_chan_txdone(chan, 0);
> > > +	}
> > > +
> > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > +	}
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	u32 val;
> > > +
> > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > +	/* test if transmit register is empty */
> > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > +
> > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	u32 *arg = data;
> > > +
> > > +	if (!imx_mu_last_tx_done(chan))
> > > +		return -EBUSY;
> > > +
> > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	int ret;
> > > +
> > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> >
> > I guess no need to assign the irq for each cp as we have only one irq.
> 
> all irq chip controller have one sink and number of source limited to
> imagination or amount of bits in a register. May be we will need some day to
> write a irqchip driver to make it work as chained irq controller.
> 

We do need write an irqchip driver later because MU still supports another
four general purpose interrupts which will be used by SCU firmware.
But I don't think it's necessary to abstract them for TX/RX interrutps.
This makes thing simple.

> So, I don't see any technical reason to not do it. Are you?
> 
> > > +	if (ret) {
> > > +		dev_err(chan->mbox->dev,
> > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > +		return ret;
> > > +	}
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > >bidx));
> > > +
> > > +	free_irq(cp->irq, chan);
> > > +}
> > > +
> > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > +	.send_data = imx_mu_send_data,
> > > +	.startup = imx_mu_startup,
> > > +	.shutdown = imx_mu_shutdown,
> > > +};
> > > +
> > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > +	struct device *dev = &pdev->dev;
> > > +	struct resource *iomem;
> > > +	struct imx_mu_priv *priv;
> > > +	const struct imx_mu_cfg *dcfg;
> > > +	unsigned int i, chans;
> > > +	int irq, ret;
> > > +
> > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > +	if (!priv)
> > > +		return -ENOMEM;
> > > +
> > > +	dcfg = of_device_get_match_data(dev);
> > > +	if (!dcfg)
> > > +		return -EINVAL;
> > > +
> > > +	priv->dcfg = dcfg;
> > > +	priv->dev = dev;
> > > +
> > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > +	if (IS_ERR(priv->base))
> > > +		return PTR_ERR(priv->base);
> > > +
> > > +	irq = platform_get_irq(pdev, 0);
> > > +	if (irq <= 0)
> > > +		return irq < 0 ? irq : -EINVAL;
> > > +
> > > +	priv->clk = devm_clk_get(dev, NULL);
> > > +	if (IS_ERR(priv->clk)) {
> > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > +			priv->clk = NULL;
> > > +		} else {
> > > +			dev_err(dev, "Failed to get clock\n");
> >
> > I guess we may not need print it for DEFER_PROBE error case.
> 
> ok.
> 
> > > +			return PTR_ERR(priv->clk);
> > > +		}
> > > +	}
> > > +
> > > +	ret = clk_prepare_enable(priv->clk);
> > > +	if (ret) {
> > > +		dev_err(dev, "Failed to enable clock\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > +	/* Initialize channel identifiers */
> > > +	for (i = 0; i < chans; i++) {
> > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > +
> > > +		cp->bidx = 3 - i;
> >
> > We may not need it if we improve the macro to calculate bidx by idx?
> 
> Are all implementation of NXP MU have reversed bit order?

AFAIK NXP MU library is used for all known platforms with MUs.
So I guess yes.

> Will it fit good for one channel implementation?

If you see the SCU MU patches I sent, you will see I also need
convert the channel index to channel mask. But here you're
using bidx where SCU MU does have. So have a common
channel index to mask macro may be good for both using.

> 
> > > +		cp->idx = i;
> > > +		cp->irq = irq;
> > > +		priv->mbox_chans[i].con_priv = cp;
> > > +	}
> > > +
> > > +	priv->mbox.dev = dev;
> > > +	priv->mbox.ops = &imx_mu_ops;
> > > +	priv->mbox.chans = priv->mbox_chans;
> > > +	priv->mbox.num_chans = chans;
> > > +	priv->mbox.txdone_irq = true;
> > > +
> > > +	platform_set_drvdata(pdev, priv);
> > > +
> > > +	if (priv->dcfg->init_hw)
> > > +		priv->dcfg->init_hw(priv);
> > > +
> > > +	return mbox_controller_register(&priv->mbox);
> > > +}
> > > +
> > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > +
> > > +	mbox_controller_unregister(&priv->mbox);
> > > +	clk_disable_unprepare(priv->clk);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +
> > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > +	/* Set default config */
> > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> >
> > This will reset both MU Side A and B.
> > So we may need make sure Side B is initialized after A?
> 
> I assume it is implementation specific, as soon as it will be needed, we may
> introduce extra DT flag. No need to cover all possible cases if we don't have
> to.
> 

We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
We just need to know the limitation later. Probably a note added here
is better.

> > > +}
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > +	.chans = IMX_MU_MAX_CHANS,
> > > +	.init_hw = imx_mu_init_imx7d_a,
> > > +};
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > +	.chans = IMX_MU_MAX_CHANS,
> > > +};
> > > +
> > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> >
> > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > compatible String and use property to specify the mu side.
> > Can you double check if we can switch to that way?
> 
> ok.
> 
> > And would you update the binding doc for M4 support according to the
> > qxp mu one Which Is already signed by Rob's tag?
> 
> ok.
> 
> So, should I update my patch set including DT binding documentation prior to
> yours?
> 

I guess you can pick that patch and send with yours. Once your part is
reviewed ok (should be quick) then I can send the SCU part based on your
Patch series.

Finally, I'm glad that we meet an agreement now. As we're trying to
Speed up the mx8qxp support and targets to hit v4.19 kernel.
So hopefully you could help send the updated patch series soon.
Then I can follow up with my work. :)

Regards
Dong Aisheng

> If yes, can you please contact Rob to avoid confusions.
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  8:49         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14  8:49 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, devicetree,
	dl-linux-imx, linux-arm-kernel, kernel, linux-clk

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Saturday, July 14, 2018 3:02 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> kernel@pengutronix.de; linux-clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging uni=
t
>=20
> Hi,
>=20
> Beside, what is equivalent of name and family name is in your name?
> I know it is different in China, so I won't to avoid confusion with:
> "Hi $name," format :)
>=20

Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)

> On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > Hi Oleksij,
> >
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > Sent: Friday, June 15, 2018 5:51 PM
> > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> kernel@pengutronix.de;
> > > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > unit
> > >
> > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > words) between the endpoints.
> > >
> >
> > This is not correct according to current implementation as we abstract
> > them into 4 virtual channels while each 'channel' can send only one wor=
d
> one time.
> > We probably need explain such limitation in commit message as well.
> >
> > I'm not strongly against this way. But it makes the controller lose
> > the HW capability to send up to 4 words. I'd just like to know a bit
> > history or reason why we decided to do that. Do we design it for specif=
ic
> users case for M4?
>=20
> no, it is R&D.
>=20

Got it

> > And are we assuming there will be no real users of multi words send
> requirement?
>=20
> no. In my experience, each imaginable Brainfuck configuration will actual=
ly
> happen some day in some design for $reasons.
> So, no assumptions, just currently working configuration of my R&D projec=
t.
>=20

I'm fine with as it is currently. We don't have to address all possible
Issues in one time.

> > > This driver was tested using the mailbox-test driver sending
> > > messages between the Cortex-A7 and the Cortex-M4.
> > >
> > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > ---
> > >  drivers/mailbox/Kconfig       |   6 +
> > >  drivers/mailbox/Makefile      |   2 +
> > >  drivers/mailbox/imx-mailbox.c | 288
> > > ++++++++++++++++++++++++++++++++++
> > >  3 files changed, 296 insertions(+)
> > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > >
> > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > a2bb27446dce..e1d2738a2e4c 100644
> > > --- a/drivers/mailbox/Kconfig
> > > +++ b/drivers/mailbox/Kconfig
> > > @@ -15,6 +15,12 @@ config ARM_MHU
> > >  	  The controller has 3 mailbox channels, the last of which can be
> > >  	  used in Secure mode only.
> > >
> > > +config IMX_MBOX
> > > +	tristate "iMX Mailbox"
> > > +	depends on SOC_IMX7D || COMPILE_TEST
> >
> > Better change to ARCH_MXC as other platform does.
>=20
> ok
>=20
> > > +	help
> > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> >
> > Ditto
>=20
> ok
>=20
> > > +
> > >  config PLATFORM_MHU
> > >  	tristate "Platform MHU Mailbox"
> > >  	depends on OF
> > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > index
> > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > --- a/drivers/mailbox/Makefile
> > > +++ b/drivers/mailbox/Makefile
> > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+=3D mailbox-test.o
> > >
> > >  obj-$(CONFIG_ARM_MHU)	+=3D arm_mhu.o
> > >
> > > +obj-$(CONFIG_IMX_MBOX)	+=3D imx-mailbox.o
> > > +
> > >  obj-$(CONFIG_PLATFORM_MHU)	+=3D platform_mhu.o
> > >
> > >  obj-$(CONFIG_PL320_MBOX)	+=3D pl320-ipc.o
> > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > 000000000000..e3f621cb1d30
> > > --- /dev/null
> > > +++ b/drivers/mailbox/imx-mailbox.c
> > > @@ -0,0 +1,288 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > +<o.rempel@pengutronix.de>  */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +
> > > +/* Transmit Register */
> > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > +/* Receive Register */
> > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > +/* Status Register */
> > > +#define IMX_MU_xSR		0x20
> > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > +
> > > +/* Control Register */
> > > +#define IMX_MU_xCR		0x24
> > > +/* Transmit Interrupt Enable */
> > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > +/* Receive Interrupt Enable */
> > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > +
> > > +#define IMX_MU_MAX_CHANS	4u
> > > +
> > > +struct imx_mu_priv;
> > > +
> > > +struct imx_mu_cfg {
> > > +	unsigned int		chans;
> > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > +
> > > +struct imx_mu_con_priv {
> > > +	int			irq;
> > > +	unsigned int		bidx;
> > > +	unsigned int		idx;
> > > +};
> > > +
> > > +struct imx_mu_priv {
> > > +	struct device		*dev;
> > > +	const struct imx_mu_cfg	*dcfg;
> > > +	void __iomem		*base;
> > > +
> > > +	struct mbox_controller	mbox;
> > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > +
> > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > +	struct clk		*clk;
> > > +};
> > > +
> > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > +*mbox) {
> > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > +
> > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs=
) {
> > > +	iowrite32(val, priv->base + offs); }
> > > +
> > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > +	return ioread32(priv->base + offs); }
> > > +
> > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > +u32
> > > +clr) {
> > > +	u32 val;
> > > +
> > > +	val =3D imx_mu_read(priv, offs);
> > > +	val &=3D ~clr;
> > > +	val |=3D set;
> > > +	imx_mu_write(priv, val, offs);
> > > +
> > > +	return val;
> > > +}
> > > +
> > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > +	struct mbox_chan *chan =3D p;
> > > +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> > > +
> > > +	u32 val, dat;
> > > +
> > > +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> > > +	val &=3D IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > +	if (!val)
> > > +		return IRQ_NONE;
> > > +
> > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > >bidx));
> > > +		mbox_chan_txdone(chan, 0);
> > > +	}
> > > +
> > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > +		dat =3D imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > +	}
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> > > +	u32 val;
> > > +
> > > +	val =3D imx_mu_read(priv, IMX_MU_xSR);
> > > +	/* test if transmit register is empty */
> > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > +
> > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> > > +	u32 *arg =3D data;
> > > +
> > > +	if (!imx_mu_last_tx_done(chan))
> > > +		return -EBUSY;
> > > +
> > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> > > +	int ret;
> > > +
> > > +	ret =3D request_irq(cp->irq, imx_mu_isr,
> > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> >
> > I guess no need to assign the irq for each cp as we have only one irq.
>=20
> all irq chip controller have one sink and number of source limited to
> imagination or amount of bits in a register. May be we will need some day=
 to
> write a irqchip driver to make it work as chained irq controller.
>=20

We do need write an irqchip driver later because MU still supports another
four general purpose interrupts which will be used by SCU firmware.
But I don't think it's necessary to abstract them for TX/RX interrutps.
This makes thing simple.

> So, I don't see any technical reason to not do it. Are you?
>=20
> > > +	if (ret) {
> > > +		dev_err(chan->mbox->dev,
> > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > +		return ret;
> > > +	}
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv =3D to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp =3D chan->con_priv;
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > >bidx));
> > > +
> > > +	free_irq(cp->irq, chan);
> > > +}
> > > +
> > > +static const struct mbox_chan_ops imx_mu_ops =3D {
> > > +	.send_data =3D imx_mu_send_data,
> > > +	.startup =3D imx_mu_startup,
> > > +	.shutdown =3D imx_mu_shutdown,
> > > +};
> > > +
> > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > +	struct device *dev =3D &pdev->dev;
> > > +	struct resource *iomem;
> > > +	struct imx_mu_priv *priv;
> > > +	const struct imx_mu_cfg *dcfg;
> > > +	unsigned int i, chans;
> > > +	int irq, ret;
> > > +
> > > +	priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > +	if (!priv)
> > > +		return -ENOMEM;
> > > +
> > > +	dcfg =3D of_device_get_match_data(dev);
> > > +	if (!dcfg)
> > > +		return -EINVAL;
> > > +
> > > +	priv->dcfg =3D dcfg;
> > > +	priv->dev =3D dev;
> > > +
> > > +	iomem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	priv->base =3D devm_ioremap_resource(&pdev->dev, iomem);
> > > +	if (IS_ERR(priv->base))
> > > +		return PTR_ERR(priv->base);
> > > +
> > > +	irq =3D platform_get_irq(pdev, 0);
> > > +	if (irq <=3D 0)
> > > +		return irq < 0 ? irq : -EINVAL;
> > > +
> > > +	priv->clk =3D devm_clk_get(dev, NULL);
> > > +	if (IS_ERR(priv->clk)) {
> > > +		if (PTR_ERR(priv->clk) =3D=3D -ENOENT) {
> > > +			priv->clk =3D NULL;
> > > +		} else {
> > > +			dev_err(dev, "Failed to get clock\n");
> >
> > I guess we may not need print it for DEFER_PROBE error case.
>=20
> ok.
>=20
> > > +			return PTR_ERR(priv->clk);
> > > +		}
> > > +	}
> > > +
> > > +	ret =3D clk_prepare_enable(priv->clk);
> > > +	if (ret) {
> > > +		dev_err(dev, "Failed to enable clock\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	chans =3D min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > +	/* Initialize channel identifiers */
> > > +	for (i =3D 0; i < chans; i++) {
> > > +		struct imx_mu_con_priv *cp =3D &priv->con_priv[i];
> > > +
> > > +		cp->bidx =3D 3 - i;
> >
> > We may not need it if we improve the macro to calculate bidx by idx?
>=20
> Are all implementation of NXP MU have reversed bit order?

AFAIK NXP MU library is used for all known platforms with MUs.
So I guess yes.

> Will it fit good for one channel implementation?

If you see the SCU MU patches I sent, you will see I also need
convert the channel index to channel mask. But here you're
using bidx where SCU MU does have. So have a common
channel index to mask macro may be good for both using.

>=20
> > > +		cp->idx =3D i;
> > > +		cp->irq =3D irq;
> > > +		priv->mbox_chans[i].con_priv =3D cp;
> > > +	}
> > > +
> > > +	priv->mbox.dev =3D dev;
> > > +	priv->mbox.ops =3D &imx_mu_ops;
> > > +	priv->mbox.chans =3D priv->mbox_chans;
> > > +	priv->mbox.num_chans =3D chans;
> > > +	priv->mbox.txdone_irq =3D true;
> > > +
> > > +	platform_set_drvdata(pdev, priv);
> > > +
> > > +	if (priv->dcfg->init_hw)
> > > +		priv->dcfg->init_hw(priv);
> > > +
> > > +	return mbox_controller_register(&priv->mbox);
> > > +}
> > > +
> > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > +	struct imx_mu_priv *priv =3D platform_get_drvdata(pdev);
> > > +
> > > +	mbox_controller_unregister(&priv->mbox);
> > > +	clk_disable_unprepare(priv->clk);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +
> > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > +	/* Set default config */
> > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> >
> > This will reset both MU Side A and B.
> > So we may need make sure Side B is initialized after A?
>=20
> I assume it is implementation specific, as soon as it will be needed, we =
may
> introduce extra DT flag. No need to cover all possible cases if we don't =
have
> to.
>=20

We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
We just need to know the limitation later. Probably a note added here
is better.

> > > +}
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a =3D {
> > > +	.chans =3D IMX_MU_MAX_CHANS,
> > > +	.init_hw =3D imx_mu_init_imx7d_a,
> > > +};
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b =3D {
> > > +	.chans =3D IMX_MU_MAX_CHANS,
> > > +};
> > > +
> > > +static const struct of_device_id imx_mu_dt_ids[] =3D {
> > > +	{ .compatible =3D "fsl,imx7s-mu-a", .data =3D &imx_mu_cfg_imx7d_a }=
,
> > > +	{ .compatible =3D "fsl,imx7s-mu-b", .data =3D &imx_mu_cfg_imx7d_b }=
,
> >
> > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > compatible String and use property to specify the mu side.
> > Can you double check if we can switch to that way?
>=20
> ok.
>=20
> > And would you update the binding doc for M4 support according to the
> > qxp mu one Which Is already signed by Rob's tag?
>=20
> ok.
>=20
> So, should I update my patch set including DT binding documentation prior=
 to
> yours?
>=20

I guess you can pick that patch and send with yours. Once your part is
reviewed ok (should be quick) then I can send the SCU part based on your
Patch series.

Finally, I'm glad that we meet an agreement now. As we're trying to
Speed up the mx8qxp support and targets to hit v4.19 kernel.
So hopefully you could help send the updated patch series soon.
Then I can follow up with my work. :)

Regards
Dong Aisheng

> If yes, can you please contact Rob to avoid confusions.
>=20
> --
> Pengutronix e.K.                           |                             =
|
> Industrial Linux Solutions                 | http://www.pengutronix.de/  =
|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    =
|
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 =
|

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  8:49         ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Saturday, July 14, 2018 3:02 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree at vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
> kernel at pengutronix.de; linux-clk at vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> Hi,
> 
> Beside, what is equivalent of name and family name is in your name?
> I know it is different in China, so I won't to avoid confusion with:
> "Hi $name," format :)
> 

Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)

> On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > Hi Oleksij,
> >
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > > Sent: Friday, June 15, 2018 5:51 PM
> > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> kernel at pengutronix.de;
> > > linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
> > > linux- clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > unit
> > >
> > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > words) between the endpoints.
> > >
> >
> > This is not correct according to current implementation as we abstract
> > them into 4 virtual channels while each 'channel' can send only one word
> one time.
> > We probably need explain such limitation in commit message as well.
> >
> > I'm not strongly against this way. But it makes the controller lose
> > the HW capability to send up to 4 words. I'd just like to know a bit
> > history or reason why we decided to do that. Do we design it for specific
> users case for M4?
> 
> no, it is R&D.
> 

Got it

> > And are we assuming there will be no real users of multi words send
> requirement?
> 
> no. In my experience, each imaginable Brainfuck configuration will actually
> happen some day in some design for $reasons.
> So, no assumptions, just currently working configuration of my R&D project.
> 

I'm fine with as it is currently. We don't have to address all possible
Issues in one time.

> > > This driver was tested using the mailbox-test driver sending
> > > messages between the Cortex-A7 and the Cortex-M4.
> > >
> > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > ---
> > >  drivers/mailbox/Kconfig       |   6 +
> > >  drivers/mailbox/Makefile      |   2 +
> > >  drivers/mailbox/imx-mailbox.c | 288
> > > ++++++++++++++++++++++++++++++++++
> > >  3 files changed, 296 insertions(+)
> > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > >
> > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > a2bb27446dce..e1d2738a2e4c 100644
> > > --- a/drivers/mailbox/Kconfig
> > > +++ b/drivers/mailbox/Kconfig
> > > @@ -15,6 +15,12 @@ config ARM_MHU
> > >  	  The controller has 3 mailbox channels, the last of which can be
> > >  	  used in Secure mode only.
> > >
> > > +config IMX_MBOX
> > > +	tristate "iMX Mailbox"
> > > +	depends on SOC_IMX7D || COMPILE_TEST
> >
> > Better change to ARCH_MXC as other platform does.
> 
> ok
> 
> > > +	help
> > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> >
> > Ditto
> 
> ok
> 
> > > +
> > >  config PLATFORM_MHU
> > >  	tristate "Platform MHU Mailbox"
> > >  	depends on OF
> > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > index
> > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > --- a/drivers/mailbox/Makefile
> > > +++ b/drivers/mailbox/Makefile
> > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > >
> > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > >
> > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > +
> > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > >
> > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > 000000000000..e3f621cb1d30
> > > --- /dev/null
> > > +++ b/drivers/mailbox/imx-mailbox.c
> > > @@ -0,0 +1,288 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > +<o.rempel@pengutronix.de>  */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +
> > > +/* Transmit Register */
> > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > +/* Receive Register */
> > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > +/* Status Register */
> > > +#define IMX_MU_xSR		0x20
> > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > +
> > > +/* Control Register */
> > > +#define IMX_MU_xCR		0x24
> > > +/* Transmit Interrupt Enable */
> > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > +/* Receive Interrupt Enable */
> > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > +
> > > +#define IMX_MU_MAX_CHANS	4u
> > > +
> > > +struct imx_mu_priv;
> > > +
> > > +struct imx_mu_cfg {
> > > +	unsigned int		chans;
> > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > +
> > > +struct imx_mu_con_priv {
> > > +	int			irq;
> > > +	unsigned int		bidx;
> > > +	unsigned int		idx;
> > > +};
> > > +
> > > +struct imx_mu_priv {
> > > +	struct device		*dev;
> > > +	const struct imx_mu_cfg	*dcfg;
> > > +	void __iomem		*base;
> > > +
> > > +	struct mbox_controller	mbox;
> > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > +
> > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > +	struct clk		*clk;
> > > +};
> > > +
> > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > +*mbox) {
> > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > +
> > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > > +	iowrite32(val, priv->base + offs); }
> > > +
> > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > +	return ioread32(priv->base + offs); }
> > > +
> > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > +u32
> > > +clr) {
> > > +	u32 val;
> > > +
> > > +	val = imx_mu_read(priv, offs);
> > > +	val &= ~clr;
> > > +	val |= set;
> > > +	imx_mu_write(priv, val, offs);
> > > +
> > > +	return val;
> > > +}
> > > +
> > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > +	struct mbox_chan *chan = p;
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +
> > > +	u32 val, dat;
> > > +
> > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > +	if (!val)
> > > +		return IRQ_NONE;
> > > +
> > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > >bidx));
> > > +		mbox_chan_txdone(chan, 0);
> > > +	}
> > > +
> > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > +	}
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	u32 val;
> > > +
> > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > +	/* test if transmit register is empty */
> > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > +
> > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	u32 *arg = data;
> > > +
> > > +	if (!imx_mu_last_tx_done(chan))
> > > +		return -EBUSY;
> > > +
> > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +	int ret;
> > > +
> > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> >
> > I guess no need to assign the irq for each cp as we have only one irq.
> 
> all irq chip controller have one sink and number of source limited to
> imagination or amount of bits in a register. May be we will need some day to
> write a irqchip driver to make it work as chained irq controller.
> 

We do need write an irqchip driver later because MU still supports another
four general purpose interrupts which will be used by SCU firmware.
But I don't think it's necessary to abstract them for TX/RX interrutps.
This makes thing simple.

> So, I don't see any technical reason to not do it. Are you?
> 
> > > +	if (ret) {
> > > +		dev_err(chan->mbox->dev,
> > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > +		return ret;
> > > +	}
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > +
> > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > >bidx));
> > > +
> > > +	free_irq(cp->irq, chan);
> > > +}
> > > +
> > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > +	.send_data = imx_mu_send_data,
> > > +	.startup = imx_mu_startup,
> > > +	.shutdown = imx_mu_shutdown,
> > > +};
> > > +
> > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > +	struct device *dev = &pdev->dev;
> > > +	struct resource *iomem;
> > > +	struct imx_mu_priv *priv;
> > > +	const struct imx_mu_cfg *dcfg;
> > > +	unsigned int i, chans;
> > > +	int irq, ret;
> > > +
> > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > +	if (!priv)
> > > +		return -ENOMEM;
> > > +
> > > +	dcfg = of_device_get_match_data(dev);
> > > +	if (!dcfg)
> > > +		return -EINVAL;
> > > +
> > > +	priv->dcfg = dcfg;
> > > +	priv->dev = dev;
> > > +
> > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > +	if (IS_ERR(priv->base))
> > > +		return PTR_ERR(priv->base);
> > > +
> > > +	irq = platform_get_irq(pdev, 0);
> > > +	if (irq <= 0)
> > > +		return irq < 0 ? irq : -EINVAL;
> > > +
> > > +	priv->clk = devm_clk_get(dev, NULL);
> > > +	if (IS_ERR(priv->clk)) {
> > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > +			priv->clk = NULL;
> > > +		} else {
> > > +			dev_err(dev, "Failed to get clock\n");
> >
> > I guess we may not need print it for DEFER_PROBE error case.
> 
> ok.
> 
> > > +			return PTR_ERR(priv->clk);
> > > +		}
> > > +	}
> > > +
> > > +	ret = clk_prepare_enable(priv->clk);
> > > +	if (ret) {
> > > +		dev_err(dev, "Failed to enable clock\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > +	/* Initialize channel identifiers */
> > > +	for (i = 0; i < chans; i++) {
> > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > +
> > > +		cp->bidx = 3 - i;
> >
> > We may not need it if we improve the macro to calculate bidx by idx?
> 
> Are all implementation of NXP MU have reversed bit order?

AFAIK NXP MU library is used for all known platforms with MUs.
So I guess yes.

> Will it fit good for one channel implementation?

If you see the SCU MU patches I sent, you will see I also need
convert the channel index to channel mask. But here you're
using bidx where SCU MU does have. So have a common
channel index to mask macro may be good for both using.

> 
> > > +		cp->idx = i;
> > > +		cp->irq = irq;
> > > +		priv->mbox_chans[i].con_priv = cp;
> > > +	}
> > > +
> > > +	priv->mbox.dev = dev;
> > > +	priv->mbox.ops = &imx_mu_ops;
> > > +	priv->mbox.chans = priv->mbox_chans;
> > > +	priv->mbox.num_chans = chans;
> > > +	priv->mbox.txdone_irq = true;
> > > +
> > > +	platform_set_drvdata(pdev, priv);
> > > +
> > > +	if (priv->dcfg->init_hw)
> > > +		priv->dcfg->init_hw(priv);
> > > +
> > > +	return mbox_controller_register(&priv->mbox);
> > > +}
> > > +
> > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > +
> > > +	mbox_controller_unregister(&priv->mbox);
> > > +	clk_disable_unprepare(priv->clk);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +
> > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > +	/* Set default config */
> > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> >
> > This will reset both MU Side A and B.
> > So we may need make sure Side B is initialized after A?
> 
> I assume it is implementation specific, as soon as it will be needed, we may
> introduce extra DT flag. No need to cover all possible cases if we don't have
> to.
> 

We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
We just need to know the limitation later. Probably a note added here
is better.

> > > +}
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > +	.chans = IMX_MU_MAX_CHANS,
> > > +	.init_hw = imx_mu_init_imx7d_a,
> > > +};
> > > +
> > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > +	.chans = IMX_MU_MAX_CHANS,
> > > +};
> > > +
> > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> >
> > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > compatible String and use property to specify the mu side.
> > Can you double check if we can switch to that way?
> 
> ok.
> 
> > And would you update the binding doc for M4 support according to the
> > qxp mu one Which Is already signed by Rob's tag?
> 
> ok.
> 
> So, should I update my patch set including DT binding documentation prior to
> yours?
> 

I guess you can pick that patch and send with yours. Once your part is
reviewed ok (should be quick) then I can send the SCU part based on your
Patch series.

Finally, I'm glad that we meet an agreement now. As we're trying to
Speed up the mx8qxp support and targets to hit v4.19 kernel.
So hopefully you could help send the updated patch series soon.
Then I can follow up with my work. :)

Regards
Dong Aisheng

> If yes, can you please contact Rob to avoid confusions.
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-07-14  8:49         ` A.s. Dong
  (?)
@ 2018-07-14  9:41           ` Oleksij Rempel
  -1 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  9:41 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Mark Rutland, devicetree, Rob Herring, dl-linux-imx, kernel,
	Fabio Estevam, Shawn Guo, linux-clk, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 17370 bytes --]

On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > Sent: Saturday, July 14, 2018 3:02 PM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> > imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> > kernel@pengutronix.de; linux-clk@vger.kernel.org
> > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > Hi,
> > 
> > Beside, what is equivalent of name and family name is in your name?
> > I know it is different in China, so I won't to avoid confusion with:
> > "Hi $name," format :)
> > 
> 
> Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> 
> > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > Hi Oleksij,
> > >
> > > > -----Original Message-----
> > > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > kernel@pengutronix.de;
> > > > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> > > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > > unit
> > > >
> > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > words) between the endpoints.
> > > >
> > >
> > > This is not correct according to current implementation as we abstract
> > > them into 4 virtual channels while each 'channel' can send only one word
> > one time.
> > > We probably need explain such limitation in commit message as well.
> > >
> > > I'm not strongly against this way. But it makes the controller lose
> > > the HW capability to send up to 4 words. I'd just like to know a bit
> > > history or reason why we decided to do that. Do we design it for specific
> > users case for M4?
> > 
> > no, it is R&D.
> > 
> 
> Got it
> 
> > > And are we assuming there will be no real users of multi words send
> > requirement?
> > 
> > no. In my experience, each imaginable Brainfuck configuration will actually
> > happen some day in some design for $reasons.
> > So, no assumptions, just currently working configuration of my R&D project.
> > 
> 
> I'm fine with as it is currently. We don't have to address all possible
> Issues in one time.
> 
> > > > This driver was tested using the mailbox-test driver sending
> > > > messages between the Cortex-A7 and the Cortex-M4.
> > > >
> > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > ---
> > > >  drivers/mailbox/Kconfig       |   6 +
> > > >  drivers/mailbox/Makefile      |   2 +
> > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > ++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 296 insertions(+)
> > > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > > >
> > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > > a2bb27446dce..e1d2738a2e4c 100644
> > > > --- a/drivers/mailbox/Kconfig
> > > > +++ b/drivers/mailbox/Kconfig
> > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > >  	  The controller has 3 mailbox channels, the last of which can be
> > > >  	  used in Secure mode only.
> > > >
> > > > +config IMX_MBOX
> > > > +	tristate "iMX Mailbox"
> > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > >
> > > Better change to ARCH_MXC as other platform does.
> > 
> > ok
> > 
> > > > +	help
> > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > >
> > > Ditto
> > 
> > ok
> > 
> > > > +
> > > >  config PLATFORM_MHU
> > > >  	tristate "Platform MHU Mailbox"
> > > >  	depends on OF
> > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > index
> > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > --- a/drivers/mailbox/Makefile
> > > > +++ b/drivers/mailbox/Makefile
> > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > > >
> > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > >
> > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > +
> > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > >
> > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > 000000000000..e3f621cb1d30
> > > > --- /dev/null
> > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > @@ -0,0 +1,288 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > +<o.rempel@pengutronix.de>  */
> > > > +
> > > > +#include <linux/clk.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/io.h>
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > +#include <linux/of_device.h>
> > > > +
> > > > +/* Transmit Register */
> > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > +/* Receive Register */
> > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > +/* Status Register */
> > > > +#define IMX_MU_xSR		0x20
> > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > +
> > > > +/* Control Register */
> > > > +#define IMX_MU_xCR		0x24
> > > > +/* Transmit Interrupt Enable */
> > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > +/* Receive Interrupt Enable */
> > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > +
> > > > +#define IMX_MU_MAX_CHANS	4u
> > > > +
> > > > +struct imx_mu_priv;
> > > > +
> > > > +struct imx_mu_cfg {
> > > > +	unsigned int		chans;
> > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > +
> > > > +struct imx_mu_con_priv {
> > > > +	int			irq;
> > > > +	unsigned int		bidx;
> > > > +	unsigned int		idx;
> > > > +};
> > > > +
> > > > +struct imx_mu_priv {
> > > > +	struct device		*dev;
> > > > +	const struct imx_mu_cfg	*dcfg;
> > > > +	void __iomem		*base;
> > > > +
> > > > +	struct mbox_controller	mbox;
> > > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > > +
> > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > +	struct clk		*clk;
> > > > +};
> > > > +
> > > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > > +*mbox) {
> > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > +
> > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > > > +	iowrite32(val, priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > +	return ioread32(priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > > +u32
> > > > +clr) {
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, offs);
> > > > +	val &= ~clr;
> > > > +	val |= set;
> > > > +	imx_mu_write(priv, val, offs);
> > > > +
> > > > +	return val;
> > > > +}
> > > > +
> > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > +	struct mbox_chan *chan = p;
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	u32 val, dat;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > > +	if (!val)
> > > > +		return IRQ_NONE;
> > > > +
> > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > > >bidx));
> > > > +		mbox_chan_txdone(chan, 0);
> > > > +	}
> > > > +
> > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > +	}
> > > > +
> > > > +	return IRQ_HANDLED;
> > > > +}
> > > > +
> > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	/* test if transmit register is empty */
> > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > +
> > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 *arg = data;
> > > > +
> > > > +	if (!imx_mu_last_tx_done(chan))
> > > > +		return -EBUSY;
> > > > +
> > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	int ret;
> > > > +
> > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > >
> > > I guess no need to assign the irq for each cp as we have only one irq.
> > 
> > all irq chip controller have one sink and number of source limited to
> > imagination or amount of bits in a register. May be we will need some day to
> > write a irqchip driver to make it work as chained irq controller.
> > 
> 
> We do need write an irqchip driver later because MU still supports another
> four general purpose interrupts which will be used by SCU firmware.
> But I don't think it's necessary to abstract them for TX/RX interrutps.
> This makes thing simple.

You just gave me one more reason to keep current version :)

> > So, I don't see any technical reason to not do it. Are you?
> > 
> > > > +	if (ret) {
> > > > +		dev_err(chan->mbox->dev,
> > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > > >bidx));
> > > > +
> > > > +	free_irq(cp->irq, chan);
> > > > +}
> > > > +
> > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > +	.send_data = imx_mu_send_data,
> > > > +	.startup = imx_mu_startup,
> > > > +	.shutdown = imx_mu_shutdown,
> > > > +};
> > > > +
> > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > +	struct device *dev = &pdev->dev;
> > > > +	struct resource *iomem;
> > > > +	struct imx_mu_priv *priv;
> > > > +	const struct imx_mu_cfg *dcfg;
> > > > +	unsigned int i, chans;
> > > > +	int irq, ret;
> > > > +
> > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > +	if (!priv)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dcfg = of_device_get_match_data(dev);
> > > > +	if (!dcfg)
> > > > +		return -EINVAL;
> > > > +
> > > > +	priv->dcfg = dcfg;
> > > > +	priv->dev = dev;
> > > > +
> > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > +	if (IS_ERR(priv->base))
> > > > +		return PTR_ERR(priv->base);
> > > > +
> > > > +	irq = platform_get_irq(pdev, 0);
> > > > +	if (irq <= 0)
> > > > +		return irq < 0 ? irq : -EINVAL;
> > > > +
> > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > +	if (IS_ERR(priv->clk)) {
> > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > +			priv->clk = NULL;
> > > > +		} else {
> > > > +			dev_err(dev, "Failed to get clock\n");
> > >
> > > I guess we may not need print it for DEFER_PROBE error case.
> > 
> > ok.
> > 
> > > > +			return PTR_ERR(priv->clk);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	ret = clk_prepare_enable(priv->clk);
> > > > +	if (ret) {
> > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > +	/* Initialize channel identifiers */
> > > > +	for (i = 0; i < chans; i++) {
> > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > +
> > > > +		cp->bidx = 3 - i;
> > >
> > > We may not need it if we improve the macro to calculate bidx by idx?
> > 
> > Are all implementation of NXP MU have reversed bit order?
> 
> AFAIK NXP MU library is used for all known platforms with MUs.
> So I guess yes.
> 
> > Will it fit good for one channel implementation?
> 
> If you see the SCU MU patches I sent, you will see I also need
> convert the channel index to channel mask. But here you're
> using bidx where SCU MU does have. So have a common
> channel index to mask macro may be good for both using.

ok

> > 
> > > > +		cp->idx = i;
> > > > +		cp->irq = irq;
> > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > +	}
> > > > +
> > > > +	priv->mbox.dev = dev;
> > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > +	priv->mbox.num_chans = chans;
> > > > +	priv->mbox.txdone_irq = true;
> > > > +
> > > > +	platform_set_drvdata(pdev, priv);
> > > > +
> > > > +	if (priv->dcfg->init_hw)
> > > > +		priv->dcfg->init_hw(priv);
> > > > +
> > > > +	return mbox_controller_register(&priv->mbox);
> > > > +}
> > > > +
> > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > +
> > > > +	mbox_controller_unregister(&priv->mbox);
> > > > +	clk_disable_unprepare(priv->clk);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +
> > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > +	/* Set default config */
> > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > >
> > > This will reset both MU Side A and B.
> > > So we may need make sure Side B is initialized after A?
> > 
> > I assume it is implementation specific, as soon as it will be needed, we may
> > introduce extra DT flag. No need to cover all possible cases if we don't have
> > to.
> > 
> 
> We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> We just need to know the limitation later. Probably a note added here
> is better.

ok

> > > > +}
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +	.init_hw = imx_mu_init_imx7d_a,
> > > > +};
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +};
> > > > +
> > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > > > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> > >
> > > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > > compatible String and use property to specify the mu side.
> > > Can you double check if we can switch to that way?
> > 
> > ok.
> > 
> > > And would you update the binding doc for M4 support according to the
> > > qxp mu one Which Is already signed by Rob's tag?
> > 
> > ok.
> > 
> > So, should I update my patch set including DT binding documentation prior to
> > yours?
> > 
> 
> I guess you can pick that patch and send with yours. Once your part is
> reviewed ok (should be quick) then I can send the SCU part based on your
> Patch series.

Normally it is preferred to squash all history for newly created files.
I'll take your patch as base with minimal changes and send some comments
to Rob.

> Finally, I'm glad that we meet an agreement now. As we're trying to
> Speed up the mx8qxp support and targets to hit v4.19 kernel.
> So hopefully you could help send the updated patch series soon.
> Then I can follow up with my work. :)

I'll try to finish it and resend new version at Monday. Ok?

> Regards
> Dong Aisheng
> 
> > If yes, can you please contact Rob to avoid confusions.
> > 
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  9:41           ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  9:41 UTC (permalink / raw)
  To: A.s. Dong
  Cc: Shawn Guo, Fabio Estevam, Rob Herring, Mark Rutland, devicetree,
	dl-linux-imx, linux-arm-kernel, kernel, linux-clk

[-- Attachment #1: Type: text/plain, Size: 17370 bytes --]

On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > Sent: Saturday, July 14, 2018 3:02 PM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> > imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> > kernel@pengutronix.de; linux-clk@vger.kernel.org
> > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > Hi,
> > 
> > Beside, what is equivalent of name and family name is in your name?
> > I know it is different in China, so I won't to avoid confusion with:
> > "Hi $name," format :)
> > 
> 
> Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> 
> > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > Hi Oleksij,
> > >
> > > > -----Original Message-----
> > > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > kernel@pengutronix.de;
> > > > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> > > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > > unit
> > > >
> > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > words) between the endpoints.
> > > >
> > >
> > > This is not correct according to current implementation as we abstract
> > > them into 4 virtual channels while each 'channel' can send only one word
> > one time.
> > > We probably need explain such limitation in commit message as well.
> > >
> > > I'm not strongly against this way. But it makes the controller lose
> > > the HW capability to send up to 4 words. I'd just like to know a bit
> > > history or reason why we decided to do that. Do we design it for specific
> > users case for M4?
> > 
> > no, it is R&D.
> > 
> 
> Got it
> 
> > > And are we assuming there will be no real users of multi words send
> > requirement?
> > 
> > no. In my experience, each imaginable Brainfuck configuration will actually
> > happen some day in some design for $reasons.
> > So, no assumptions, just currently working configuration of my R&D project.
> > 
> 
> I'm fine with as it is currently. We don't have to address all possible
> Issues in one time.
> 
> > > > This driver was tested using the mailbox-test driver sending
> > > > messages between the Cortex-A7 and the Cortex-M4.
> > > >
> > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > ---
> > > >  drivers/mailbox/Kconfig       |   6 +
> > > >  drivers/mailbox/Makefile      |   2 +
> > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > ++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 296 insertions(+)
> > > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > > >
> > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > > a2bb27446dce..e1d2738a2e4c 100644
> > > > --- a/drivers/mailbox/Kconfig
> > > > +++ b/drivers/mailbox/Kconfig
> > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > >  	  The controller has 3 mailbox channels, the last of which can be
> > > >  	  used in Secure mode only.
> > > >
> > > > +config IMX_MBOX
> > > > +	tristate "iMX Mailbox"
> > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > >
> > > Better change to ARCH_MXC as other platform does.
> > 
> > ok
> > 
> > > > +	help
> > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > >
> > > Ditto
> > 
> > ok
> > 
> > > > +
> > > >  config PLATFORM_MHU
> > > >  	tristate "Platform MHU Mailbox"
> > > >  	depends on OF
> > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > index
> > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > --- a/drivers/mailbox/Makefile
> > > > +++ b/drivers/mailbox/Makefile
> > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > > >
> > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > >
> > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > +
> > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > >
> > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > 000000000000..e3f621cb1d30
> > > > --- /dev/null
> > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > @@ -0,0 +1,288 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > +<o.rempel@pengutronix.de>  */
> > > > +
> > > > +#include <linux/clk.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/io.h>
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > +#include <linux/of_device.h>
> > > > +
> > > > +/* Transmit Register */
> > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > +/* Receive Register */
> > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > +/* Status Register */
> > > > +#define IMX_MU_xSR		0x20
> > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > +
> > > > +/* Control Register */
> > > > +#define IMX_MU_xCR		0x24
> > > > +/* Transmit Interrupt Enable */
> > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > +/* Receive Interrupt Enable */
> > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > +
> > > > +#define IMX_MU_MAX_CHANS	4u
> > > > +
> > > > +struct imx_mu_priv;
> > > > +
> > > > +struct imx_mu_cfg {
> > > > +	unsigned int		chans;
> > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > +
> > > > +struct imx_mu_con_priv {
> > > > +	int			irq;
> > > > +	unsigned int		bidx;
> > > > +	unsigned int		idx;
> > > > +};
> > > > +
> > > > +struct imx_mu_priv {
> > > > +	struct device		*dev;
> > > > +	const struct imx_mu_cfg	*dcfg;
> > > > +	void __iomem		*base;
> > > > +
> > > > +	struct mbox_controller	mbox;
> > > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > > +
> > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > +	struct clk		*clk;
> > > > +};
> > > > +
> > > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > > +*mbox) {
> > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > +
> > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > > > +	iowrite32(val, priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > +	return ioread32(priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > > +u32
> > > > +clr) {
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, offs);
> > > > +	val &= ~clr;
> > > > +	val |= set;
> > > > +	imx_mu_write(priv, val, offs);
> > > > +
> > > > +	return val;
> > > > +}
> > > > +
> > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > +	struct mbox_chan *chan = p;
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	u32 val, dat;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > > +	if (!val)
> > > > +		return IRQ_NONE;
> > > > +
> > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > > >bidx));
> > > > +		mbox_chan_txdone(chan, 0);
> > > > +	}
> > > > +
> > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > +	}
> > > > +
> > > > +	return IRQ_HANDLED;
> > > > +}
> > > > +
> > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	/* test if transmit register is empty */
> > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > +
> > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 *arg = data;
> > > > +
> > > > +	if (!imx_mu_last_tx_done(chan))
> > > > +		return -EBUSY;
> > > > +
> > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	int ret;
> > > > +
> > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > >
> > > I guess no need to assign the irq for each cp as we have only one irq.
> > 
> > all irq chip controller have one sink and number of source limited to
> > imagination or amount of bits in a register. May be we will need some day to
> > write a irqchip driver to make it work as chained irq controller.
> > 
> 
> We do need write an irqchip driver later because MU still supports another
> four general purpose interrupts which will be used by SCU firmware.
> But I don't think it's necessary to abstract them for TX/RX interrutps.
> This makes thing simple.

You just gave me one more reason to keep current version :)

> > So, I don't see any technical reason to not do it. Are you?
> > 
> > > > +	if (ret) {
> > > > +		dev_err(chan->mbox->dev,
> > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > > >bidx));
> > > > +
> > > > +	free_irq(cp->irq, chan);
> > > > +}
> > > > +
> > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > +	.send_data = imx_mu_send_data,
> > > > +	.startup = imx_mu_startup,
> > > > +	.shutdown = imx_mu_shutdown,
> > > > +};
> > > > +
> > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > +	struct device *dev = &pdev->dev;
> > > > +	struct resource *iomem;
> > > > +	struct imx_mu_priv *priv;
> > > > +	const struct imx_mu_cfg *dcfg;
> > > > +	unsigned int i, chans;
> > > > +	int irq, ret;
> > > > +
> > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > +	if (!priv)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dcfg = of_device_get_match_data(dev);
> > > > +	if (!dcfg)
> > > > +		return -EINVAL;
> > > > +
> > > > +	priv->dcfg = dcfg;
> > > > +	priv->dev = dev;
> > > > +
> > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > +	if (IS_ERR(priv->base))
> > > > +		return PTR_ERR(priv->base);
> > > > +
> > > > +	irq = platform_get_irq(pdev, 0);
> > > > +	if (irq <= 0)
> > > > +		return irq < 0 ? irq : -EINVAL;
> > > > +
> > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > +	if (IS_ERR(priv->clk)) {
> > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > +			priv->clk = NULL;
> > > > +		} else {
> > > > +			dev_err(dev, "Failed to get clock\n");
> > >
> > > I guess we may not need print it for DEFER_PROBE error case.
> > 
> > ok.
> > 
> > > > +			return PTR_ERR(priv->clk);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	ret = clk_prepare_enable(priv->clk);
> > > > +	if (ret) {
> > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > +	/* Initialize channel identifiers */
> > > > +	for (i = 0; i < chans; i++) {
> > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > +
> > > > +		cp->bidx = 3 - i;
> > >
> > > We may not need it if we improve the macro to calculate bidx by idx?
> > 
> > Are all implementation of NXP MU have reversed bit order?
> 
> AFAIK NXP MU library is used for all known platforms with MUs.
> So I guess yes.
> 
> > Will it fit good for one channel implementation?
> 
> If you see the SCU MU patches I sent, you will see I also need
> convert the channel index to channel mask. But here you're
> using bidx where SCU MU does have. So have a common
> channel index to mask macro may be good for both using.

ok

> > 
> > > > +		cp->idx = i;
> > > > +		cp->irq = irq;
> > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > +	}
> > > > +
> > > > +	priv->mbox.dev = dev;
> > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > +	priv->mbox.num_chans = chans;
> > > > +	priv->mbox.txdone_irq = true;
> > > > +
> > > > +	platform_set_drvdata(pdev, priv);
> > > > +
> > > > +	if (priv->dcfg->init_hw)
> > > > +		priv->dcfg->init_hw(priv);
> > > > +
> > > > +	return mbox_controller_register(&priv->mbox);
> > > > +}
> > > > +
> > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > +
> > > > +	mbox_controller_unregister(&priv->mbox);
> > > > +	clk_disable_unprepare(priv->clk);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +
> > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > +	/* Set default config */
> > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > >
> > > This will reset both MU Side A and B.
> > > So we may need make sure Side B is initialized after A?
> > 
> > I assume it is implementation specific, as soon as it will be needed, we may
> > introduce extra DT flag. No need to cover all possible cases if we don't have
> > to.
> > 
> 
> We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> We just need to know the limitation later. Probably a note added here
> is better.

ok

> > > > +}
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +	.init_hw = imx_mu_init_imx7d_a,
> > > > +};
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +};
> > > > +
> > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > > > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> > >
> > > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > > compatible String and use property to specify the mu side.
> > > Can you double check if we can switch to that way?
> > 
> > ok.
> > 
> > > And would you update the binding doc for M4 support according to the
> > > qxp mu one Which Is already signed by Rob's tag?
> > 
> > ok.
> > 
> > So, should I update my patch set including DT binding documentation prior to
> > yours?
> > 
> 
> I guess you can pick that patch and send with yours. Once your part is
> reviewed ok (should be quick) then I can send the SCU part based on your
> Patch series.

Normally it is preferred to squash all history for newly created files.
I'll take your patch as base with minimal changes and send some comments
to Rob.

> Finally, I'm glad that we meet an agreement now. As we're trying to
> Speed up the mx8qxp support and targets to hit v4.19 kernel.
> So hopefully you could help send the updated patch series soon.
> Then I can follow up with my work. :)

I'll try to finish it and resend new version at Monday. Ok?

> Regards
> Dong Aisheng
> 
> > If yes, can you please contact Rob to avoid confusions.
> > 
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14  9:41           ` Oleksij Rempel
  0 siblings, 0 replies; 69+ messages in thread
From: Oleksij Rempel @ 2018-07-14  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > -----Original Message-----
> > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > Sent: Saturday, July 14, 2018 3:02 PM
> > To: A.s. Dong <aisheng.dong@nxp.com>
> > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > Rutland <mark.rutland@arm.com>; devicetree at vger.kernel.org; dl-linux-
> > imx <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
> > kernel at pengutronix.de; linux-clk at vger.kernel.org
> > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> > 
> > Hi,
> > 
> > Beside, what is equivalent of name and family name is in your name?
> > I know it is different in China, so I won't to avoid confusion with:
> > "Hi $name," format :)
> > 
> 
> Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> 
> > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > Hi Oleksij,
> > >
> > > > -----Original Message-----
> > > > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > > Rutland <mark.rutland@arm.com>; A.s. Dong <aisheng.dong@nxp.com>
> > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > kernel at pengutronix.de;
> > > > linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
> > > > linux- clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging
> > > > unit
> > > >
> > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > words) between the endpoints.
> > > >
> > >
> > > This is not correct according to current implementation as we abstract
> > > them into 4 virtual channels while each 'channel' can send only one word
> > one time.
> > > We probably need explain such limitation in commit message as well.
> > >
> > > I'm not strongly against this way. But it makes the controller lose
> > > the HW capability to send up to 4 words. I'd just like to know a bit
> > > history or reason why we decided to do that. Do we design it for specific
> > users case for M4?
> > 
> > no, it is R&D.
> > 
> 
> Got it
> 
> > > And are we assuming there will be no real users of multi words send
> > requirement?
> > 
> > no. In my experience, each imaginable Brainfuck configuration will actually
> > happen some day in some design for $reasons.
> > So, no assumptions, just currently working configuration of my R&D project.
> > 
> 
> I'm fine with as it is currently. We don't have to address all possible
> Issues in one time.
> 
> > > > This driver was tested using the mailbox-test driver sending
> > > > messages between the Cortex-A7 and the Cortex-M4.
> > > >
> > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > ---
> > > >  drivers/mailbox/Kconfig       |   6 +
> > > >  drivers/mailbox/Makefile      |   2 +
> > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > ++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 296 insertions(+)
> > > >  create mode 100644 drivers/mailbox/imx-mailbox.c
> > > >
> > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index
> > > > a2bb27446dce..e1d2738a2e4c 100644
> > > > --- a/drivers/mailbox/Kconfig
> > > > +++ b/drivers/mailbox/Kconfig
> > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > >  	  The controller has 3 mailbox channels, the last of which can be
> > > >  	  used in Secure mode only.
> > > >
> > > > +config IMX_MBOX
> > > > +	tristate "iMX Mailbox"
> > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > >
> > > Better change to ARCH_MXC as other platform does.
> > 
> > ok
> > 
> > > > +	help
> > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > >
> > > Ditto
> > 
> > ok
> > 
> > > > +
> > > >  config PLATFORM_MHU
> > > >  	tristate "Platform MHU Mailbox"
> > > >  	depends on OF
> > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > index
> > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > --- a/drivers/mailbox/Makefile
> > > > +++ b/drivers/mailbox/Makefile
> > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-test.o
> > > >
> > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > >
> > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > +
> > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > >
> > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > 000000000000..e3f621cb1d30
> > > > --- /dev/null
> > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > @@ -0,0 +1,288 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > +<o.rempel@pengutronix.de>  */
> > > > +
> > > > +#include <linux/clk.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/io.h>
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > +#include <linux/of_device.h>
> > > > +
> > > > +/* Transmit Register */
> > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > +/* Receive Register */
> > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > +/* Status Register */
> > > > +#define IMX_MU_xSR		0x20
> > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > +
> > > > +/* Control Register */
> > > > +#define IMX_MU_xCR		0x24
> > > > +/* Transmit Interrupt Enable */
> > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > +/* Receive Interrupt Enable */
> > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > +
> > > > +#define IMX_MU_MAX_CHANS	4u
> > > > +
> > > > +struct imx_mu_priv;
> > > > +
> > > > +struct imx_mu_cfg {
> > > > +	unsigned int		chans;
> > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > +
> > > > +struct imx_mu_con_priv {
> > > > +	int			irq;
> > > > +	unsigned int		bidx;
> > > > +	unsigned int		idx;
> > > > +};
> > > > +
> > > > +struct imx_mu_priv {
> > > > +	struct device		*dev;
> > > > +	const struct imx_mu_cfg	*dcfg;
> > > > +	void __iomem		*base;
> > > > +
> > > > +	struct mbox_controller	mbox;
> > > > +	struct mbox_chan	mbox_chans[IMX_MU_MAX_CHANS];
> > > > +
> > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > +	struct clk		*clk;
> > > > +};
> > > > +
> > > > +static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller
> > > > +*mbox) {
> > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > +
> > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) {
> > > > +	iowrite32(val, priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > +	return ioread32(priv->base + offs); }
> > > > +
> > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32 set,
> > > > +u32
> > > > +clr) {
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, offs);
> > > > +	val &= ~clr;
> > > > +	val |= set;
> > > > +	imx_mu_write(priv, val, offs);
> > > > +
> > > > +	return val;
> > > > +}
> > > > +
> > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > +	struct mbox_chan *chan = p;
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	u32 val, dat;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp->bidx);
> > > > +	if (!val)
> > > > +		return IRQ_NONE;
> > > > +
> > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0, IMX_MU_xCR_TIEn(cp-
> > > > >bidx));
> > > > +		mbox_chan_txdone(chan, 0);
> > > > +	}
> > > > +
> > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > +	}
> > > > +
> > > > +	return IRQ_HANDLED;
> > > > +}
> > > > +
> > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 val;
> > > > +
> > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > +	/* test if transmit register is empty */
> > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > +
> > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	u32 *arg = data;
> > > > +
> > > > +	if (!imx_mu_last_tx_done(chan))
> > > > +		return -EBUSY;
> > > > +
> > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +	int ret;
> > > > +
> > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > >
> > > I guess no need to assign the irq for each cp as we have only one irq.
> > 
> > all irq chip controller have one sink and number of source limited to
> > imagination or amount of bits in a register. May be we will need some day to
> > write a irqchip driver to make it work as chained irq controller.
> > 
> 
> We do need write an irqchip driver later because MU still supports another
> four general purpose interrupts which will be used by SCU firmware.
> But I don't think it's necessary to abstract them for TX/RX interrutps.
> This makes thing simple.

You just gave me one more reason to keep current version :)

> > So, I don't see any technical reason to not do it. Are you?
> > 
> > > > +	if (ret) {
> > > > +		dev_err(chan->mbox->dev,
> > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp->bidx), 0);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > +
> > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > +		   IMX_MU_xCR_TIEn(cp->bidx) | IMX_MU_xCR_RIEn(cp-
> > > > >bidx));
> > > > +
> > > > +	free_irq(cp->irq, chan);
> > > > +}
> > > > +
> > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > +	.send_data = imx_mu_send_data,
> > > > +	.startup = imx_mu_startup,
> > > > +	.shutdown = imx_mu_shutdown,
> > > > +};
> > > > +
> > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > +	struct device *dev = &pdev->dev;
> > > > +	struct resource *iomem;
> > > > +	struct imx_mu_priv *priv;
> > > > +	const struct imx_mu_cfg *dcfg;
> > > > +	unsigned int i, chans;
> > > > +	int irq, ret;
> > > > +
> > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > +	if (!priv)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dcfg = of_device_get_match_data(dev);
> > > > +	if (!dcfg)
> > > > +		return -EINVAL;
> > > > +
> > > > +	priv->dcfg = dcfg;
> > > > +	priv->dev = dev;
> > > > +
> > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > +	if (IS_ERR(priv->base))
> > > > +		return PTR_ERR(priv->base);
> > > > +
> > > > +	irq = platform_get_irq(pdev, 0);
> > > > +	if (irq <= 0)
> > > > +		return irq < 0 ? irq : -EINVAL;
> > > > +
> > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > +	if (IS_ERR(priv->clk)) {
> > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > +			priv->clk = NULL;
> > > > +		} else {
> > > > +			dev_err(dev, "Failed to get clock\n");
> > >
> > > I guess we may not need print it for DEFER_PROBE error case.
> > 
> > ok.
> > 
> > > > +			return PTR_ERR(priv->clk);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	ret = clk_prepare_enable(priv->clk);
> > > > +	if (ret) {
> > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > +	/* Initialize channel identifiers */
> > > > +	for (i = 0; i < chans; i++) {
> > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > +
> > > > +		cp->bidx = 3 - i;
> > >
> > > We may not need it if we improve the macro to calculate bidx by idx?
> > 
> > Are all implementation of NXP MU have reversed bit order?
> 
> AFAIK NXP MU library is used for all known platforms with MUs.
> So I guess yes.
> 
> > Will it fit good for one channel implementation?
> 
> If you see the SCU MU patches I sent, you will see I also need
> convert the channel index to channel mask. But here you're
> using bidx where SCU MU does have. So have a common
> channel index to mask macro may be good for both using.

ok

> > 
> > > > +		cp->idx = i;
> > > > +		cp->irq = irq;
> > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > +	}
> > > > +
> > > > +	priv->mbox.dev = dev;
> > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > +	priv->mbox.num_chans = chans;
> > > > +	priv->mbox.txdone_irq = true;
> > > > +
> > > > +	platform_set_drvdata(pdev, priv);
> > > > +
> > > > +	if (priv->dcfg->init_hw)
> > > > +		priv->dcfg->init_hw(priv);
> > > > +
> > > > +	return mbox_controller_register(&priv->mbox);
> > > > +}
> > > > +
> > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > +
> > > > +	mbox_controller_unregister(&priv->mbox);
> > > > +	clk_disable_unprepare(priv->clk);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +
> > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > +	/* Set default config */
> > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > >
> > > This will reset both MU Side A and B.
> > > So we may need make sure Side B is initialized after A?
> > 
> > I assume it is implementation specific, as soon as it will be needed, we may
> > introduce extra DT flag. No need to cover all possible cases if we don't have
> > to.
> > 
> 
> We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> We just need to know the limitation later. Probably a note added here
> is better.

ok

> > > > +}
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +	.init_hw = imx_mu_init_imx7d_a,
> > > > +};
> > > > +
> > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > +};
> > > > +
> > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > +	{ .compatible = "fsl,imx7s-mu-a", .data = &imx_mu_cfg_imx7d_a },
> > > > +	{ .compatible = "fsl,imx7s-mu-b", .data = &imx_mu_cfg_imx7d_b },
> > >
> > > I'm not sure whether we already have the decision to use fsl,<soc>-mu
> > > compatible String and use property to specify the mu side.
> > > Can you double check if we can switch to that way?
> > 
> > ok.
> > 
> > > And would you update the binding doc for M4 support according to the
> > > qxp mu one Which Is already signed by Rob's tag?
> > 
> > ok.
> > 
> > So, should I update my patch set including DT binding documentation prior to
> > yours?
> > 
> 
> I guess you can pick that patch and send with yours. Once your part is
> reviewed ok (should be quick) then I can send the SCU part based on your
> Patch series.

Normally it is preferred to squash all history for newly created files.
I'll take your patch as base with minimal changes and send some comments
to Rob.

> Finally, I'm glad that we meet an agreement now. As we're trying to
> Speed up the mx8qxp support and targets to hit v4.19 kernel.
> So hopefully you could help send the updated patch series soon.
> Then I can follow up with my work. :)

I'll try to finish it and resend new version at Monday. Ok?

> Regards
> Dong Aisheng
> 
> > If yes, can you please contact Rob to avoid confusions.
> > 
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180714/1e3d63e4/attachment.sig>

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
  2018-07-14  9:41           ` Oleksij Rempel
  (?)
@ 2018-07-14 11:41             ` A.s. Dong
  -1 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14 11:41 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, devicetree, Rob Herring, dl-linux-imx, kernel,
	Fabio Estevam, Shawn Guo, linux-clk, linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Saturday, July 14, 2018 5:42 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> kernel@pengutronix.de; linux-clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > Sent: Saturday, July 14, 2018 3:02 PM
> > > To: A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org;
> > > dl-linux- imx <linux-imx@nxp.com>;
> > > linux-arm-kernel@lists.infradead.org;
> > > kernel@pengutronix.de; linux-clk@vger.kernel.org
> > > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > messaging unit
> > >
> > > Hi,
> > >
> > > Beside, what is equivalent of name and family name is in your name?
> > > I know it is different in China, so I won't to avoid confusion with:
> > > "Hi $name," format :)
> > >
> >
> > Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> >
> > > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > > Hi Oleksij,
> > > >
> > > > > -----Original Message-----
> > > > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>;
> Mark
> > > > > Rutland <mark.rutland@arm.com>; A.s. Dong
> <aisheng.dong@nxp.com>
> > > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > > kernel@pengutronix.de;
> > > > > linux-arm-kernel@lists.infradead.org;
> > > > > devicetree@vger.kernel.org;
> > > > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > > > messaging unit
> > > > >
> > > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > > words) between the endpoints.
> > > > >
> > > >
> > > > This is not correct according to current implementation as we
> > > > abstract them into 4 virtual channels while each 'channel' can
> > > > send only one word
> > > one time.
> > > > We probably need explain such limitation in commit message as well.
> > > >
> > > > I'm not strongly against this way. But it makes the controller
> > > > lose the HW capability to send up to 4 words. I'd just like to
> > > > know a bit history or reason why we decided to do that. Do we
> > > > design it for specific
> > > users case for M4?
> > >
> > > no, it is R&D.
> > >
> >
> > Got it
> >
> > > > And are we assuming there will be no real users of multi words
> > > > send
> > > requirement?
> > >
> > > no. In my experience, each imaginable Brainfuck configuration will
> > > actually happen some day in some design for $reasons.
> > > So, no assumptions, just currently working configuration of my R&D
> project.
> > >
> >
> > I'm fine with as it is currently. We don't have to address all
> > possible Issues in one time.
> >
> > > > > This driver was tested using the mailbox-test driver sending
> > > > > messages between the Cortex-A7 and the Cortex-M4.
> > > > >
> > > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > > ---
> > > > >  drivers/mailbox/Kconfig       |   6 +
> > > > >  drivers/mailbox/Makefile      |   2 +
> > > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > > ++++++++++++++++++++++++++++++++++
> > > > >  3 files changed, 296 insertions(+)  create mode 100644
> > > > > drivers/mailbox/imx-mailbox.c
> > > > >
> > > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> > > > > index a2bb27446dce..e1d2738a2e4c 100644
> > > > > --- a/drivers/mailbox/Kconfig
> > > > > +++ b/drivers/mailbox/Kconfig
> > > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > > >  	  The controller has 3 mailbox channels, the last of which can
> be
> > > > >  	  used in Secure mode only.
> > > > >
> > > > > +config IMX_MBOX
> > > > > +	tristate "iMX Mailbox"
> > > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > > >
> > > > Better change to ARCH_MXC as other platform does.
> > >
> > > ok
> > >
> > > > > +	help
> > > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > > >
> > > > Ditto
> > >
> > > ok
> > >
> > > > > +
> > > > >  config PLATFORM_MHU
> > > > >  	tristate "Platform MHU Mailbox"
> > > > >  	depends on OF
> > > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > > index
> > > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > > --- a/drivers/mailbox/Makefile
> > > > > +++ b/drivers/mailbox/Makefile
> > > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-
> test.o
> > > > >
> > > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > > >
> > > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > > +
> > > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > > >
> > > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > > 000000000000..e3f621cb1d30
> > > > > --- /dev/null
> > > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > > @@ -0,0 +1,288 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0
> > > > > +/*
> > > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > > +<o.rempel@pengutronix.de>  */
> > > > > +
> > > > > +#include <linux/clk.h>
> > > > > +#include <linux/interrupt.h>
> > > > > +#include <linux/io.h>
> > > > > +#include <linux/kernel.h>
> > > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > > +#include <linux/of_device.h>
> > > > > +
> > > > > +/* Transmit Register */
> > > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > > +/* Receive Register */
> > > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > > +/* Status Register */
> > > > > +#define IMX_MU_xSR		0x20
> > > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > > +
> > > > > +/* Control Register */
> > > > > +#define IMX_MU_xCR		0x24
> > > > > +/* Transmit Interrupt Enable */
> > > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > > +/* Receive Interrupt Enable */
> > > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > > +
> > > > > +#define IMX_MU_MAX_CHANS	4u
> > > > > +
> > > > > +struct imx_mu_priv;
> > > > > +
> > > > > +struct imx_mu_cfg {
> > > > > +	unsigned int		chans;
> > > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > > +
> > > > > +struct imx_mu_con_priv {
> > > > > +	int			irq;
> > > > > +	unsigned int		bidx;
> > > > > +	unsigned int		idx;
> > > > > +};
> > > > > +
> > > > > +struct imx_mu_priv {
> > > > > +	struct device		*dev;
> > > > > +	const struct imx_mu_cfg	*dcfg;
> > > > > +	void __iomem		*base;
> > > > > +
> > > > > +	struct mbox_controller	mbox;
> > > > > +	struct mbox_chan
> 	mbox_chans[IMX_MU_MAX_CHANS];
> > > > > +
> > > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > > +	struct clk		*clk;
> > > > > +};
> > > > > +
> > > > > +static struct imx_mu_priv *to_imx_mu_priv(struct
> > > > > +mbox_controller
> > > > > +*mbox) {
> > > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > > +
> > > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
> {
> > > > > +	iowrite32(val, priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > > +	return ioread32(priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32
> > > > > +set,
> > > > > +u32
> > > > > +clr) {
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, offs);
> > > > > +	val &= ~clr;
> > > > > +	val |= set;
> > > > > +	imx_mu_write(priv, val, offs);
> > > > > +
> > > > > +	return val;
> > > > > +}
> > > > > +
> > > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > > +	struct mbox_chan *chan = p;
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	u32 val, dat;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp-
> >bidx);
> > > > > +	if (!val)
> > > > > +		return IRQ_NONE;
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0,
> IMX_MU_xCR_TIEn(cp-
> > > > > >bidx));
> > > > > +		mbox_chan_txdone(chan, 0);
> > > > > +	}
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > > +	}
> > > > > +
> > > > > +	return IRQ_HANDLED;
> > > > > +}
> > > > > +
> > > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	/* test if transmit register is empty */
> > > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > > +
> > > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 *arg = data;
> > > > > +
> > > > > +	if (!imx_mu_last_tx_done(chan))
> > > > > +		return -EBUSY;
> > > > > +
> > > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > > >
> > > > I guess no need to assign the irq for each cp as we have only one irq.
> > >
> > > all irq chip controller have one sink and number of source limited
> > > to imagination or amount of bits in a register. May be we will need
> > > some day to write a irqchip driver to make it work as chained irq
> controller.
> > >
> >
> > We do need write an irqchip driver later because MU still supports
> > another four general purpose interrupts which will be used by SCU
> firmware.
> > But I don't think it's necessary to abstract them for TX/RX interrutps.
> > This makes thing simple.
> 
> You just gave me one more reason to keep current version :)
> 

Anyway, I don't think it's a must change.
You can keep it.

> > > So, I don't see any technical reason to not do it. Are you?
> > >
> > > > > +	if (ret) {
> > > > > +		dev_err(chan->mbox->dev,
> > > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > > +		   IMX_MU_xCR_TIEn(cp->bidx) |
> IMX_MU_xCR_RIEn(cp-
> > > > > >bidx));
> > > > > +
> > > > > +	free_irq(cp->irq, chan);
> > > > > +}
> > > > > +
> > > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > > +	.send_data = imx_mu_send_data,
> > > > > +	.startup = imx_mu_startup,
> > > > > +	.shutdown = imx_mu_shutdown,
> > > > > +};
> > > > > +
> > > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > > +	struct device *dev = &pdev->dev;
> > > > > +	struct resource *iomem;
> > > > > +	struct imx_mu_priv *priv;
> > > > > +	const struct imx_mu_cfg *dcfg;
> > > > > +	unsigned int i, chans;
> > > > > +	int irq, ret;
> > > > > +
> > > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > > +	if (!priv)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	dcfg = of_device_get_match_data(dev);
> > > > > +	if (!dcfg)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	priv->dcfg = dcfg;
> > > > > +	priv->dev = dev;
> > > > > +
> > > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM,
> 0);
> > > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > > +	if (IS_ERR(priv->base))
> > > > > +		return PTR_ERR(priv->base);
> > > > > +
> > > > > +	irq = platform_get_irq(pdev, 0);
> > > > > +	if (irq <= 0)
> > > > > +		return irq < 0 ? irq : -EINVAL;
> > > > > +
> > > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > > +	if (IS_ERR(priv->clk)) {
> > > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > > +			priv->clk = NULL;
> > > > > +		} else {
> > > > > +			dev_err(dev, "Failed to get clock\n");
> > > >
> > > > I guess we may not need print it for DEFER_PROBE error case.
> > >
> > > ok.
> > >
> > > > > +			return PTR_ERR(priv->clk);
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	ret = clk_prepare_enable(priv->clk);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > > +	/* Initialize channel identifiers */
> > > > > +	for (i = 0; i < chans; i++) {
> > > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > > +
> > > > > +		cp->bidx = 3 - i;
> > > >
> > > > We may not need it if we improve the macro to calculate bidx by idx?
> > >
> > > Are all implementation of NXP MU have reversed bit order?
> >
> > AFAIK NXP MU library is used for all known platforms with MUs.
> > So I guess yes.
> >
> > > Will it fit good for one channel implementation?
> >
> > If you see the SCU MU patches I sent, you will see I also need convert
> > the channel index to channel mask. But here you're using bidx where
> > SCU MU does have. So have a common channel index to mask macro may
> be
> > good for both using.
> 
> ok
> 
> > >
> > > > > +		cp->idx = i;
> > > > > +		cp->irq = irq;
> > > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > > +	}
> > > > > +
> > > > > +	priv->mbox.dev = dev;
> > > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > > +	priv->mbox.num_chans = chans;
> > > > > +	priv->mbox.txdone_irq = true;
> > > > > +
> > > > > +	platform_set_drvdata(pdev, priv);
> > > > > +
> > > > > +	if (priv->dcfg->init_hw)
> > > > > +		priv->dcfg->init_hw(priv);
> > > > > +
> > > > > +	return mbox_controller_register(&priv->mbox);
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > > +
> > > > > +	mbox_controller_unregister(&priv->mbox);
> > > > > +	clk_disable_unprepare(priv->clk);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > > +	/* Set default config */
> > > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > > >
> > > > This will reset both MU Side A and B.
> > > > So we may need make sure Side B is initialized after A?
> > >
> > > I assume it is implementation specific, as soon as it will be
> > > needed, we may introduce extra DT flag. No need to cover all
> > > possible cases if we don't have to.
> > >
> >
> > We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> > We just need to know the limitation later. Probably a note added here
> > is better.
> 
> ok
> 
> > > > > +}
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +	.init_hw = imx_mu_init_imx7d_a, };
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +};
> > > > > +
> > > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > > +	{ .compatible = "fsl,imx7s-mu-a", .data =
> &imx_mu_cfg_imx7d_a },
> > > > > +	{ .compatible = "fsl,imx7s-mu-b", .data =
> &imx_mu_cfg_imx7d_b
> > > > > +},
> > > >
> > > > I'm not sure whether we already have the decision to use
> > > > fsl,<soc>-mu compatible String and use property to specify the mu side.
> > > > Can you double check if we can switch to that way?
> > >
> > > ok.
> > >
> > > > And would you update the binding doc for M4 support according to
> > > > the qxp mu one Which Is already signed by Rob's tag?
> > >
> > > ok.
> > >
> > > So, should I update my patch set including DT binding documentation
> > > prior to yours?
> > >
> >
> > I guess you can pick that patch and send with yours. Once your part is
> > reviewed ok (should be quick) then I can send the SCU part based on
> > your Patch series.
> 
> Normally it is preferred to squash all history for newly created files.
> I'll take your patch as base with minimal changes and send some comments
> to Rob.
> 
> > Finally, I'm glad that we meet an agreement now. As we're trying to
> > Speed up the mx8qxp support and targets to hit v4.19 kernel.
> > So hopefully you could help send the updated patch series soon.
> > Then I can follow up with my work. :)
> 
> I'll try to finish it and resend new version at Monday. Ok?
> 

Good to me.
Thanks

Regards
Dong Aisheng

> > Regards
> > Dong Aisheng
> >
> > > If yes, can you please contact Rob to avoid confusions.
> > >
> > > --
> > > Pengutronix e.K.                           |                             |
> > > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0
> |
> > > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> >
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* RE: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14 11:41             ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14 11:41 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, devicetree, Rob Herring, dl-linux-imx, kernel,
	Fabio Estevam, Shawn Guo, linux-clk, linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> Sent: Saturday, July 14, 2018 5:42 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel@lists.infradead.org;
> kernel@pengutronix.de; linux-clk@vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > Sent: Saturday, July 14, 2018 3:02 PM
> > > To: A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; devicetree@vger.kernel.org;
> > > dl-linux- imx <linux-imx@nxp.com>;
> > > linux-arm-kernel@lists.infradead.org;
> > > kernel@pengutronix.de; linux-clk@vger.kernel.org
> > > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > messaging unit
> > >
> > > Hi,
> > >
> > > Beside, what is equivalent of name and family name is in your name?
> > > I know it is different in China, so I won't to avoid confusion with:
> > > "Hi $name," format :)
> > >
> >
> > Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> >
> > > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > > Hi Oleksij,
> > > >
> > > > > -----Original Message-----
> > > > > From: Oleksij Rempel [mailto:o.rempel@pengutronix.de]
> > > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>;
> Mark
> > > > > Rutland <mark.rutland@arm.com>; A.s. Dong
> <aisheng.dong@nxp.com>
> > > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > > kernel@pengutronix.de;
> > > > > linux-arm-kernel@lists.infradead.org;
> > > > > devicetree@vger.kernel.org;
> > > > > linux- clk@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > > > messaging unit
> > > > >
> > > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > > words) between the endpoints.
> > > > >
> > > >
> > > > This is not correct according to current implementation as we
> > > > abstract them into 4 virtual channels while each 'channel' can
> > > > send only one word
> > > one time.
> > > > We probably need explain such limitation in commit message as well.
> > > >
> > > > I'm not strongly against this way. But it makes the controller
> > > > lose the HW capability to send up to 4 words. I'd just like to
> > > > know a bit history or reason why we decided to do that. Do we
> > > > design it for specific
> > > users case for M4?
> > >
> > > no, it is R&D.
> > >
> >
> > Got it
> >
> > > > And are we assuming there will be no real users of multi words
> > > > send
> > > requirement?
> > >
> > > no. In my experience, each imaginable Brainfuck configuration will
> > > actually happen some day in some design for $reasons.
> > > So, no assumptions, just currently working configuration of my R&D
> project.
> > >
> >
> > I'm fine with as it is currently. We don't have to address all
> > possible Issues in one time.
> >
> > > > > This driver was tested using the mailbox-test driver sending
> > > > > messages between the Cortex-A7 and the Cortex-M4.
> > > > >
> > > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > > ---
> > > > >  drivers/mailbox/Kconfig       |   6 +
> > > > >  drivers/mailbox/Makefile      |   2 +
> > > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > > ++++++++++++++++++++++++++++++++++
> > > > >  3 files changed, 296 insertions(+)  create mode 100644
> > > > > drivers/mailbox/imx-mailbox.c
> > > > >
> > > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> > > > > index a2bb27446dce..e1d2738a2e4c 100644
> > > > > --- a/drivers/mailbox/Kconfig
> > > > > +++ b/drivers/mailbox/Kconfig
> > > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > > >  	  The controller has 3 mailbox channels, the last of which can
> be
> > > > >  	  used in Secure mode only.
> > > > >
> > > > > +config IMX_MBOX
> > > > > +	tristate "iMX Mailbox"
> > > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > > >
> > > > Better change to ARCH_MXC as other platform does.
> > >
> > > ok
> > >
> > > > > +	help
> > > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > > >
> > > > Ditto
> > >
> > > ok
> > >
> > > > > +
> > > > >  config PLATFORM_MHU
> > > > >  	tristate "Platform MHU Mailbox"
> > > > >  	depends on OF
> > > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > > index
> > > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > > --- a/drivers/mailbox/Makefile
> > > > > +++ b/drivers/mailbox/Makefile
> > > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-
> test.o
> > > > >
> > > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > > >
> > > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > > +
> > > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > > >
> > > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > > 000000000000..e3f621cb1d30
> > > > > --- /dev/null
> > > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > > @@ -0,0 +1,288 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0
> > > > > +/*
> > > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > > +<o.rempel@pengutronix.de>  */
> > > > > +
> > > > > +#include <linux/clk.h>
> > > > > +#include <linux/interrupt.h>
> > > > > +#include <linux/io.h>
> > > > > +#include <linux/kernel.h>
> > > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > > +#include <linux/of_device.h>
> > > > > +
> > > > > +/* Transmit Register */
> > > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > > +/* Receive Register */
> > > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > > +/* Status Register */
> > > > > +#define IMX_MU_xSR		0x20
> > > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > > +
> > > > > +/* Control Register */
> > > > > +#define IMX_MU_xCR		0x24
> > > > > +/* Transmit Interrupt Enable */
> > > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > > +/* Receive Interrupt Enable */
> > > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > > +
> > > > > +#define IMX_MU_MAX_CHANS	4u
> > > > > +
> > > > > +struct imx_mu_priv;
> > > > > +
> > > > > +struct imx_mu_cfg {
> > > > > +	unsigned int		chans;
> > > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > > +
> > > > > +struct imx_mu_con_priv {
> > > > > +	int			irq;
> > > > > +	unsigned int		bidx;
> > > > > +	unsigned int		idx;
> > > > > +};
> > > > > +
> > > > > +struct imx_mu_priv {
> > > > > +	struct device		*dev;
> > > > > +	const struct imx_mu_cfg	*dcfg;
> > > > > +	void __iomem		*base;
> > > > > +
> > > > > +	struct mbox_controller	mbox;
> > > > > +	struct mbox_chan
> 	mbox_chans[IMX_MU_MAX_CHANS];
> > > > > +
> > > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > > +	struct clk		*clk;
> > > > > +};
> > > > > +
> > > > > +static struct imx_mu_priv *to_imx_mu_priv(struct
> > > > > +mbox_controller
> > > > > +*mbox) {
> > > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > > +
> > > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
> {
> > > > > +	iowrite32(val, priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > > +	return ioread32(priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32
> > > > > +set,
> > > > > +u32
> > > > > +clr) {
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, offs);
> > > > > +	val &= ~clr;
> > > > > +	val |= set;
> > > > > +	imx_mu_write(priv, val, offs);
> > > > > +
> > > > > +	return val;
> > > > > +}
> > > > > +
> > > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > > +	struct mbox_chan *chan = p;
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	u32 val, dat;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp-
> >bidx);
> > > > > +	if (!val)
> > > > > +		return IRQ_NONE;
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0,
> IMX_MU_xCR_TIEn(cp-
> > > > > >bidx));
> > > > > +		mbox_chan_txdone(chan, 0);
> > > > > +	}
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > > +	}
> > > > > +
> > > > > +	return IRQ_HANDLED;
> > > > > +}
> > > > > +
> > > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	/* test if transmit register is empty */
> > > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > > +
> > > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 *arg = data;
> > > > > +
> > > > > +	if (!imx_mu_last_tx_done(chan))
> > > > > +		return -EBUSY;
> > > > > +
> > > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > > >
> > > > I guess no need to assign the irq for each cp as we have only one irq.
> > >
> > > all irq chip controller have one sink and number of source limited
> > > to imagination or amount of bits in a register. May be we will need
> > > some day to write a irqchip driver to make it work as chained irq
> controller.
> > >
> >
> > We do need write an irqchip driver later because MU still supports
> > another four general purpose interrupts which will be used by SCU
> firmware.
> > But I don't think it's necessary to abstract them for TX/RX interrutps.
> > This makes thing simple.
> 
> You just gave me one more reason to keep current version :)
> 

Anyway, I don't think it's a must change.
You can keep it.

> > > So, I don't see any technical reason to not do it. Are you?
> > >
> > > > > +	if (ret) {
> > > > > +		dev_err(chan->mbox->dev,
> > > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > > +		   IMX_MU_xCR_TIEn(cp->bidx) |
> IMX_MU_xCR_RIEn(cp-
> > > > > >bidx));
> > > > > +
> > > > > +	free_irq(cp->irq, chan);
> > > > > +}
> > > > > +
> > > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > > +	.send_data = imx_mu_send_data,
> > > > > +	.startup = imx_mu_startup,
> > > > > +	.shutdown = imx_mu_shutdown,
> > > > > +};
> > > > > +
> > > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > > +	struct device *dev = &pdev->dev;
> > > > > +	struct resource *iomem;
> > > > > +	struct imx_mu_priv *priv;
> > > > > +	const struct imx_mu_cfg *dcfg;
> > > > > +	unsigned int i, chans;
> > > > > +	int irq, ret;
> > > > > +
> > > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > > +	if (!priv)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	dcfg = of_device_get_match_data(dev);
> > > > > +	if (!dcfg)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	priv->dcfg = dcfg;
> > > > > +	priv->dev = dev;
> > > > > +
> > > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM,
> 0);
> > > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > > +	if (IS_ERR(priv->base))
> > > > > +		return PTR_ERR(priv->base);
> > > > > +
> > > > > +	irq = platform_get_irq(pdev, 0);
> > > > > +	if (irq <= 0)
> > > > > +		return irq < 0 ? irq : -EINVAL;
> > > > > +
> > > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > > +	if (IS_ERR(priv->clk)) {
> > > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > > +			priv->clk = NULL;
> > > > > +		} else {
> > > > > +			dev_err(dev, "Failed to get clock\n");
> > > >
> > > > I guess we may not need print it for DEFER_PROBE error case.
> > >
> > > ok.
> > >
> > > > > +			return PTR_ERR(priv->clk);
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	ret = clk_prepare_enable(priv->clk);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > > +	/* Initialize channel identifiers */
> > > > > +	for (i = 0; i < chans; i++) {
> > > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > > +
> > > > > +		cp->bidx = 3 - i;
> > > >
> > > > We may not need it if we improve the macro to calculate bidx by idx?
> > >
> > > Are all implementation of NXP MU have reversed bit order?
> >
> > AFAIK NXP MU library is used for all known platforms with MUs.
> > So I guess yes.
> >
> > > Will it fit good for one channel implementation?
> >
> > If you see the SCU MU patches I sent, you will see I also need convert
> > the channel index to channel mask. But here you're using bidx where
> > SCU MU does have. So have a common channel index to mask macro may
> be
> > good for both using.
> 
> ok
> 
> > >
> > > > > +		cp->idx = i;
> > > > > +		cp->irq = irq;
> > > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > > +	}
> > > > > +
> > > > > +	priv->mbox.dev = dev;
> > > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > > +	priv->mbox.num_chans = chans;
> > > > > +	priv->mbox.txdone_irq = true;
> > > > > +
> > > > > +	platform_set_drvdata(pdev, priv);
> > > > > +
> > > > > +	if (priv->dcfg->init_hw)
> > > > > +		priv->dcfg->init_hw(priv);
> > > > > +
> > > > > +	return mbox_controller_register(&priv->mbox);
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > > +
> > > > > +	mbox_controller_unregister(&priv->mbox);
> > > > > +	clk_disable_unprepare(priv->clk);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > > +	/* Set default config */
> > > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > > >
> > > > This will reset both MU Side A and B.
> > > > So we may need make sure Side B is initialized after A?
> > >
> > > I assume it is implementation specific, as soon as it will be
> > > needed, we may introduce extra DT flag. No need to cover all
> > > possible cases if we don't have to.
> > >
> >
> > We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> > We just need to know the limitation later. Probably a note added here
> > is better.
> 
> ok
> 
> > > > > +}
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +	.init_hw = imx_mu_init_imx7d_a, };
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +};
> > > > > +
> > > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > > +	{ .compatible = "fsl,imx7s-mu-a", .data =
> &imx_mu_cfg_imx7d_a },
> > > > > +	{ .compatible = "fsl,imx7s-mu-b", .data =
> &imx_mu_cfg_imx7d_b
> > > > > +},
> > > >
> > > > I'm not sure whether we already have the decision to use
> > > > fsl,<soc>-mu compatible String and use property to specify the mu side.
> > > > Can you double check if we can switch to that way?
> > >
> > > ok.
> > >
> > > > And would you update the binding doc for M4 support according to
> > > > the qxp mu one Which Is already signed by Rob's tag?
> > >
> > > ok.
> > >
> > > So, should I update my patch set including DT binding documentation
> > > prior to yours?
> > >
> >
> > I guess you can pick that patch and send with yours. Once your part is
> > reviewed ok (should be quick) then I can send the SCU part based on
> > your Patch series.
> 
> Normally it is preferred to squash all history for newly created files.
> I'll take your patch as base with minimal changes and send some comments
> to Rob.
> 
> > Finally, I'm glad that we meet an agreement now. As we're trying to
> > Speed up the mx8qxp support and targets to hit v4.19 kernel.
> > So hopefully you could help send the updated patch series soon.
> > Then I can follow up with my work. :)
> 
> I'll try to finish it and resend new version at Monday. Ok?
> 

Good to me.
Thanks

Regards
Dong Aisheng

> > Regards
> > Dong Aisheng
> >
> > > If yes, can you please contact Rob to avoid confusions.
> > >
> > > --
> > > Pengutronix e.K.                           |                             |
> > > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0
> |
> > > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> >
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
@ 2018-07-14 11:41             ` A.s. Dong
  0 siblings, 0 replies; 69+ messages in thread
From: A.s. Dong @ 2018-07-14 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> Sent: Saturday, July 14, 2018 5:42 PM
> To: A.s. Dong <aisheng.dong@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; devicetree at vger.kernel.org; dl-linux-
> imx <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
> kernel at pengutronix.de; linux-clk at vger.kernel.org
> Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit
> 
> On Sat, Jul 14, 2018 at 08:49:28AM +0000, A.s. Dong wrote:
> > > -----Original Message-----
> > > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > > Sent: Saturday, July 14, 2018 3:02 PM
> > > To: A.s. Dong <aisheng.dong@nxp.com>
> > > Cc: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>; Mark
> > > Rutland <mark.rutland@arm.com>; devicetree at vger.kernel.org;
> > > dl-linux- imx <linux-imx@nxp.com>;
> > > linux-arm-kernel at lists.infradead.org;
> > > kernel at pengutronix.de; linux-clk at vger.kernel.org
> > > Subject: Re: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > messaging unit
> > >
> > > Hi,
> > >
> > > Beside, what is equivalent of name and family name is in your name?
> > > I know it is different in China, so I won't to avoid confusion with:
> > > "Hi $name," format :)
> > >
> >
> > Dong is my family name. Either Hi A.S or Hi Dong is fine to me. :)
> >
> > > On Thu, Jul 12, 2018 at 11:28:16AM +0000, A.s. Dong wrote:
> > > > Hi Oleksij,
> > > >
> > > > > -----Original Message-----
> > > > > From: Oleksij Rempel [mailto:o.rempel at pengutronix.de]
> > > > > Sent: Friday, June 15, 2018 5:51 PM
> > > > > To: Shawn Guo <shawnguo@kernel.org>; Fabio Estevam
> > > > > <fabio.estevam@nxp.com>; Rob Herring <robh+dt@kernel.org>;
> Mark
> > > > > Rutland <mark.rutland@arm.com>; A.s. Dong
> <aisheng.dong@nxp.com>
> > > > > Cc: Oleksij Rempel <o.rempel@pengutronix.de>;
> > > kernel at pengutronix.de;
> > > > > linux-arm-kernel at lists.infradead.org;
> > > > > devicetree at vger.kernel.org;
> > > > > linux- clk at vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > > > Subject: [PATCH v2 4/4] mailbox: Add support for i.MX7D
> > > > > messaging unit
> > > > >
> > > > > The Mailbox controller is able to send messages (up to 4 32 bit
> > > > > words) between the endpoints.
> > > > >
> > > >
> > > > This is not correct according to current implementation as we
> > > > abstract them into 4 virtual channels while each 'channel' can
> > > > send only one word
> > > one time.
> > > > We probably need explain such limitation in commit message as well.
> > > >
> > > > I'm not strongly against this way. But it makes the controller
> > > > lose the HW capability to send up to 4 words. I'd just like to
> > > > know a bit history or reason why we decided to do that. Do we
> > > > design it for specific
> > > users case for M4?
> > >
> > > no, it is R&D.
> > >
> >
> > Got it
> >
> > > > And are we assuming there will be no real users of multi words
> > > > send
> > > requirement?
> > >
> > > no. In my experience, each imaginable Brainfuck configuration will
> > > actually happen some day in some design for $reasons.
> > > So, no assumptions, just currently working configuration of my R&D
> project.
> > >
> >
> > I'm fine with as it is currently. We don't have to address all
> > possible Issues in one time.
> >
> > > > > This driver was tested using the mailbox-test driver sending
> > > > > messages between the Cortex-A7 and the Cortex-M4.
> > > > >
> > > > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > > > > ---
> > > > >  drivers/mailbox/Kconfig       |   6 +
> > > > >  drivers/mailbox/Makefile      |   2 +
> > > > >  drivers/mailbox/imx-mailbox.c | 288
> > > > > ++++++++++++++++++++++++++++++++++
> > > > >  3 files changed, 296 insertions(+)  create mode 100644
> > > > > drivers/mailbox/imx-mailbox.c
> > > > >
> > > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> > > > > index a2bb27446dce..e1d2738a2e4c 100644
> > > > > --- a/drivers/mailbox/Kconfig
> > > > > +++ b/drivers/mailbox/Kconfig
> > > > > @@ -15,6 +15,12 @@ config ARM_MHU
> > > > >  	  The controller has 3 mailbox channels, the last of which can
> be
> > > > >  	  used in Secure mode only.
> > > > >
> > > > > +config IMX_MBOX
> > > > > +	tristate "iMX Mailbox"
> > > > > +	depends on SOC_IMX7D || COMPILE_TEST
> > > >
> > > > Better change to ARCH_MXC as other platform does.
> > >
> > > ok
> > >
> > > > > +	help
> > > > > +	  Mailbox implementation for iMX7D Messaging Unit (MU).
> > > >
> > > > Ditto
> > >
> > > ok
> > >
> > > > > +
> > > > >  config PLATFORM_MHU
> > > > >  	tristate "Platform MHU Mailbox"
> > > > >  	depends on OF
> > > > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> > > > > index
> > > > > cc23c3a43fcd..ba2fe1b6dd62 100644
> > > > > --- a/drivers/mailbox/Makefile
> > > > > +++ b/drivers/mailbox/Makefile
> > > > > @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST)	+= mailbox-
> test.o
> > > > >
> > > > >  obj-$(CONFIG_ARM_MHU)	+= arm_mhu.o
> > > > >
> > > > > +obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
> > > > > +
> > > > >  obj-$(CONFIG_PLATFORM_MHU)	+= platform_mhu.o
> > > > >
> > > > >  obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> > > > > diff --git a/drivers/mailbox/imx-mailbox.c
> > > > > b/drivers/mailbox/imx-mailbox.c new file mode 100644 index
> > > > > 000000000000..e3f621cb1d30
> > > > > --- /dev/null
> > > > > +++ b/drivers/mailbox/imx-mailbox.c
> > > > > @@ -0,0 +1,288 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0
> > > > > +/*
> > > > > + * Copyright (c) 2018 Pengutronix, Oleksij Rempel
> > > > > +<o.rempel@pengutronix.de>  */
> > > > > +
> > > > > +#include <linux/clk.h>
> > > > > +#include <linux/interrupt.h>
> > > > > +#include <linux/io.h>
> > > > > +#include <linux/kernel.h>
> > > > > +#include <linux/mailbox_controller.h> #include <linux/module.h>
> > > > > +#include <linux/of_device.h>
> > > > > +
> > > > > +/* Transmit Register */
> > > > > +#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
> > > > > +/* Receive Register */
> > > > > +#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
> > > > > +/* Status Register */
> > > > > +#define IMX_MU_xSR		0x20
> > > > > +#define IMX_MU_xSR_TEn(x)	BIT(20 + (x))
> > > > > +#define IMX_MU_xSR_RFn(x)	BIT(24 + (x))
> > > > > +#define IMX_MU_xSR_BRDIP	BIT(9)
> > > > > +
> > > > > +/* Control Register */
> > > > > +#define IMX_MU_xCR		0x24
> > > > > +/* Transmit Interrupt Enable */
> > > > > +#define IMX_MU_xCR_TIEn(x)	BIT(20 + (x))
> > > > > +/* Receive Interrupt Enable */
> > > > > +#define IMX_MU_xCR_RIEn(x)	BIT(24 + (x))
> > > > > +
> > > > > +#define IMX_MU_MAX_CHANS	4u
> > > > > +
> > > > > +struct imx_mu_priv;
> > > > > +
> > > > > +struct imx_mu_cfg {
> > > > > +	unsigned int		chans;
> > > > > +	void (*init_hw)(struct imx_mu_priv *priv); };
> > > > > +
> > > > > +struct imx_mu_con_priv {
> > > > > +	int			irq;
> > > > > +	unsigned int		bidx;
> > > > > +	unsigned int		idx;
> > > > > +};
> > > > > +
> > > > > +struct imx_mu_priv {
> > > > > +	struct device		*dev;
> > > > > +	const struct imx_mu_cfg	*dcfg;
> > > > > +	void __iomem		*base;
> > > > > +
> > > > > +	struct mbox_controller	mbox;
> > > > > +	struct mbox_chan
> 	mbox_chans[IMX_MU_MAX_CHANS];
> > > > > +
> > > > > +	struct imx_mu_con_priv  con_priv[IMX_MU_MAX_CHANS];
> > > > > +	struct clk		*clk;
> > > > > +};
> > > > > +
> > > > > +static struct imx_mu_priv *to_imx_mu_priv(struct
> > > > > +mbox_controller
> > > > > +*mbox) {
> > > > > +	return container_of(mbox, struct imx_mu_priv, mbox); }
> > > > > +
> > > > > +static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
> {
> > > > > +	iowrite32(val, priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) {
> > > > > +	return ioread32(priv->base + offs); }
> > > > > +
> > > > > +static u32 imx_mu_rmw(struct imx_mu_priv *priv, u32 offs, u32
> > > > > +set,
> > > > > +u32
> > > > > +clr) {
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, offs);
> > > > > +	val &= ~clr;
> > > > > +	val |= set;
> > > > > +	imx_mu_write(priv, val, offs);
> > > > > +
> > > > > +	return val;
> > > > > +}
> > > > > +
> > > > > +static irqreturn_t imx_mu_isr(int irq, void *p) {
> > > > > +	struct mbox_chan *chan = p;
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	u32 val, dat;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	val &= IMX_MU_xSR_TEn(cp->bidx) | IMX_MU_xSR_RFn(cp-
> >bidx);
> > > > > +	if (!val)
> > > > > +		return IRQ_NONE;
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_TEn(cp->bidx)) {
> > > > > +		imx_mu_rmw(priv, IMX_MU_xCR, 0,
> IMX_MU_xCR_TIEn(cp-
> > > > > >bidx));
> > > > > +		mbox_chan_txdone(chan, 0);
> > > > > +	}
> > > > > +
> > > > > +	if (val & IMX_MU_xSR_RFn(cp->bidx)) {
> > > > > +		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
> > > > > +		mbox_chan_received_data(chan, (void *)&dat);
> > > > > +	}
> > > > > +
> > > > > +	return IRQ_HANDLED;
> > > > > +}
> > > > > +
> > > > > +static bool imx_mu_last_tx_done(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 val;
> > > > > +
> > > > > +	val = imx_mu_read(priv, IMX_MU_xSR);
> > > > > +	/* test if transmit register is empty */
> > > > > +	return (!!(val & IMX_MU_xSR_TEn(cp->bidx))); }
> > > > > +
> > > > > +static int imx_mu_send_data(struct mbox_chan *chan, void *data) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	u32 *arg = data;
> > > > > +
> > > > > +	if (!imx_mu_last_tx_done(chan))
> > > > > +		return -EBUSY;
> > > > > +
> > > > > +	imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xSR_TEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_startup(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = request_irq(cp->irq, imx_mu_isr,
> > > > > +			  IRQF_SHARED, "imx_mu_chan", chan);
> > > >
> > > > I guess no need to assign the irq for each cp as we have only one irq.
> > >
> > > all irq chip controller have one sink and number of source limited
> > > to imagination or amount of bits in a register. May be we will need
> > > some day to write a irqchip driver to make it work as chained irq
> controller.
> > >
> >
> > We do need write an irqchip driver later because MU still supports
> > another four general purpose interrupts which will be used by SCU
> firmware.
> > But I don't think it's necessary to abstract them for TX/RX interrutps.
> > This makes thing simple.
> 
> You just gave me one more reason to keep current version :)
> 

Anyway, I don't think it's a must change.
You can keep it.

> > > So, I don't see any technical reason to not do it. Are you?
> > >
> > > > > +	if (ret) {
> > > > > +		dev_err(chan->mbox->dev,
> > > > > +			"Unable to acquire IRQ %d\n", cp->irq);
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, IMX_MU_xCR_RIEn(cp-
> >bidx), 0);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static void imx_mu_shutdown(struct mbox_chan *chan) {
> > > > > +	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
> > > > > +	struct imx_mu_con_priv *cp = chan->con_priv;
> > > > > +
> > > > > +	imx_mu_rmw(priv, IMX_MU_xCR, 0,
> > > > > +		   IMX_MU_xCR_TIEn(cp->bidx) |
> IMX_MU_xCR_RIEn(cp-
> > > > > >bidx));
> > > > > +
> > > > > +	free_irq(cp->irq, chan);
> > > > > +}
> > > > > +
> > > > > +static const struct mbox_chan_ops imx_mu_ops = {
> > > > > +	.send_data = imx_mu_send_data,
> > > > > +	.startup = imx_mu_startup,
> > > > > +	.shutdown = imx_mu_shutdown,
> > > > > +};
> > > > > +
> > > > > +static int imx_mu_probe(struct platform_device *pdev) {
> > > > > +	struct device *dev = &pdev->dev;
> > > > > +	struct resource *iomem;
> > > > > +	struct imx_mu_priv *priv;
> > > > > +	const struct imx_mu_cfg *dcfg;
> > > > > +	unsigned int i, chans;
> > > > > +	int irq, ret;
> > > > > +
> > > > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > > > +	if (!priv)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	dcfg = of_device_get_match_data(dev);
> > > > > +	if (!dcfg)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	priv->dcfg = dcfg;
> > > > > +	priv->dev = dev;
> > > > > +
> > > > > +	iomem = platform_get_resource(pdev, IORESOURCE_MEM,
> 0);
> > > > > +	priv->base = devm_ioremap_resource(&pdev->dev, iomem);
> > > > > +	if (IS_ERR(priv->base))
> > > > > +		return PTR_ERR(priv->base);
> > > > > +
> > > > > +	irq = platform_get_irq(pdev, 0);
> > > > > +	if (irq <= 0)
> > > > > +		return irq < 0 ? irq : -EINVAL;
> > > > > +
> > > > > +	priv->clk = devm_clk_get(dev, NULL);
> > > > > +	if (IS_ERR(priv->clk)) {
> > > > > +		if (PTR_ERR(priv->clk) == -ENOENT) {
> > > > > +			priv->clk = NULL;
> > > > > +		} else {
> > > > > +			dev_err(dev, "Failed to get clock\n");
> > > >
> > > > I guess we may not need print it for DEFER_PROBE error case.
> > >
> > > ok.
> > >
> > > > > +			return PTR_ERR(priv->clk);
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	ret = clk_prepare_enable(priv->clk);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "Failed to enable clock\n");
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	chans = min(dcfg->chans, IMX_MU_MAX_CHANS);
> > > > > +	/* Initialize channel identifiers */
> > > > > +	for (i = 0; i < chans; i++) {
> > > > > +		struct imx_mu_con_priv *cp = &priv->con_priv[i];
> > > > > +
> > > > > +		cp->bidx = 3 - i;
> > > >
> > > > We may not need it if we improve the macro to calculate bidx by idx?
> > >
> > > Are all implementation of NXP MU have reversed bit order?
> >
> > AFAIK NXP MU library is used for all known platforms with MUs.
> > So I guess yes.
> >
> > > Will it fit good for one channel implementation?
> >
> > If you see the SCU MU patches I sent, you will see I also need convert
> > the channel index to channel mask. But here you're using bidx where
> > SCU MU does have. So have a common channel index to mask macro may
> be
> > good for both using.
> 
> ok
> 
> > >
> > > > > +		cp->idx = i;
> > > > > +		cp->irq = irq;
> > > > > +		priv->mbox_chans[i].con_priv = cp;
> > > > > +	}
> > > > > +
> > > > > +	priv->mbox.dev = dev;
> > > > > +	priv->mbox.ops = &imx_mu_ops;
> > > > > +	priv->mbox.chans = priv->mbox_chans;
> > > > > +	priv->mbox.num_chans = chans;
> > > > > +	priv->mbox.txdone_irq = true;
> > > > > +
> > > > > +	platform_set_drvdata(pdev, priv);
> > > > > +
> > > > > +	if (priv->dcfg->init_hw)
> > > > > +		priv->dcfg->init_hw(priv);
> > > > > +
> > > > > +	return mbox_controller_register(&priv->mbox);
> > > > > +}
> > > > > +
> > > > > +static int imx_mu_remove(struct platform_device *pdev) {
> > > > > +	struct imx_mu_priv *priv = platform_get_drvdata(pdev);
> > > > > +
> > > > > +	mbox_controller_unregister(&priv->mbox);
> > > > > +	clk_disable_unprepare(priv->clk);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +static void imx_mu_init_imx7d_a(struct imx_mu_priv *priv) {
> > > > > +	/* Set default config */
> > > > > +	imx_mu_write(priv, 0, IMX_MU_xCR);
> > > >
> > > > This will reset both MU Side A and B.
> > > > So we may need make sure Side B is initialized after A?
> > >
> > > I assume it is implementation specific, as soon as it will be
> > > needed, we may introduce extra DT flag. No need to cover all
> > > possible cases if we don't have to.
> > >
> >
> > We shouldn't reset SCU side, but SCU MU is not using it. So I'm okay.
> > We just need to know the limitation later. Probably a note added here
> > is better.
> 
> ok
> 
> > > > > +}
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_a = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +	.init_hw = imx_mu_init_imx7d_a, };
> > > > > +
> > > > > +static const struct imx_mu_cfg imx_mu_cfg_imx7d_b = {
> > > > > +	.chans = IMX_MU_MAX_CHANS,
> > > > > +};
> > > > > +
> > > > > +static const struct of_device_id imx_mu_dt_ids[] = {
> > > > > +	{ .compatible = "fsl,imx7s-mu-a", .data =
> &imx_mu_cfg_imx7d_a },
> > > > > +	{ .compatible = "fsl,imx7s-mu-b", .data =
> &imx_mu_cfg_imx7d_b
> > > > > +},
> > > >
> > > > I'm not sure whether we already have the decision to use
> > > > fsl,<soc>-mu compatible String and use property to specify the mu side.
> > > > Can you double check if we can switch to that way?
> > >
> > > ok.
> > >
> > > > And would you update the binding doc for M4 support according to
> > > > the qxp mu one Which Is already signed by Rob's tag?
> > >
> > > ok.
> > >
> > > So, should I update my patch set including DT binding documentation
> > > prior to yours?
> > >
> >
> > I guess you can pick that patch and send with yours. Once your part is
> > reviewed ok (should be quick) then I can send the SCU part based on
> > your Patch series.
> 
> Normally it is preferred to squash all history for newly created files.
> I'll take your patch as base with minimal changes and send some comments
> to Rob.
> 
> > Finally, I'm glad that we meet an agreement now. As we're trying to
> > Speed up the mx8qxp support and targets to hit v4.19 kernel.
> > So hopefully you could help send the updated patch series soon.
> > Then I can follow up with my work. :)
> 
> I'll try to finish it and resend new version at Monday. Ok?
> 

Good to me.
Thanks

Regards
Dong Aisheng

> > Regards
> > Dong Aisheng
> >
> > > If yes, can you please contact Rob to avoid confusions.
> > >
> > > --
> > > Pengutronix e.K.                           |                             |
> > > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0
> |
> > > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> >
> 
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

end of thread, other threads:[~2018-07-14 11:41 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-15  9:51 [PATCH v2 0/4] add mailbox support for i.MX7D Oleksij Rempel
2018-06-15  9:51 ` Oleksij Rempel
2018-06-15  9:51 ` Oleksij Rempel
2018-06-15  9:51 ` [PATCH v2 1/4] clk: imx7d: add IMX7D_MU_ROOT_CLK Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-07-09  6:22   ` Stephen Boyd
2018-07-09  6:22     ` Stephen Boyd
2018-07-09  6:22     ` Stephen Boyd
2018-07-09  6:28     ` Oleksij Rempel
2018-07-09  6:28       ` Oleksij Rempel
2018-07-09  6:28       ` Oleksij Rempel
2018-07-09  8:18   ` A.s. Dong
2018-07-09  8:18     ` A.s. Dong
2018-07-09  8:18     ` A.s. Dong
2018-07-09 12:47   ` Fabio Estevam
2018-07-09 12:47     ` Fabio Estevam
2018-07-09 12:47     ` Fabio Estevam
2018-07-09 16:57   ` Stephen Boyd
2018-07-09 16:57     ` Stephen Boyd
2018-07-09 16:57     ` Stephen Boyd
2018-06-15  9:51 ` [PATCH v2 2/4] dt-bindings: mailbox: provide imx-mailbox documentation Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-18  8:53   ` Leonard Crestez
2018-06-18  8:53     ` Leonard Crestez
2018-06-18  8:53     ` Leonard Crestez
2018-06-18 11:51     ` Oleksij Rempel
2018-06-18 11:51       ` Oleksij Rempel
2018-06-18 11:51       ` Oleksij Rempel
2018-06-15  9:51 ` [PATCH v2 3/4] ARM: dts: imx7s: add i.MX7 messaging unit support Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-15  9:51 ` [PATCH v2 4/4] mailbox: Add support for i.MX7D messaging unit Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-15  9:51   ` Oleksij Rempel
2018-06-26 10:09   ` A.s. Dong
2018-06-26 10:09     ` A.s. Dong
2018-06-26 10:09     ` A.s. Dong
2018-06-26 10:56     ` Oleksij Rempel
2018-06-26 10:56       ` Oleksij Rempel
2018-06-26 10:56       ` Oleksij Rempel
2018-06-26 12:07       ` A.s. Dong
2018-06-26 12:07         ` A.s. Dong
2018-06-26 12:07         ` A.s. Dong
2018-07-02  7:35         ` Oleksij Rempel
2018-07-02  7:35           ` Oleksij Rempel
2018-07-02  7:35           ` Oleksij Rempel
2018-06-26 13:23     ` Sascha Hauer
2018-06-26 13:23       ` Sascha Hauer
2018-06-26 13:23       ` Sascha Hauer
2018-06-27  3:18       ` A.s. Dong
2018-06-27  3:18         ` A.s. Dong
2018-06-27  3:18         ` A.s. Dong
2018-07-12 11:28   ` A.s. Dong
2018-07-12 11:28     ` A.s. Dong
2018-07-12 11:28     ` A.s. Dong
2018-07-14  7:02     ` Oleksij Rempel
2018-07-14  7:02       ` Oleksij Rempel
2018-07-14  7:02       ` Oleksij Rempel
2018-07-14  8:49       ` A.s. Dong
2018-07-14  8:49         ` A.s. Dong
2018-07-14  8:49         ` A.s. Dong
2018-07-14  9:41         ` Oleksij Rempel
2018-07-14  9:41           ` Oleksij Rempel
2018-07-14  9:41           ` Oleksij Rempel
2018-07-14 11:41           ` A.s. Dong
2018-07-14 11:41             ` A.s. Dong
2018-07-14 11:41             ` A.s. Dong

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.