mcux: Add MCUX IPM driver for lpc and kinetis socs

Add driver for MCUX mailbox which can be used for lpcxpresso54114
and other lpc and kinetis socs.

Origin: Original

Signed-off-by: Stanislav Poboril <stanislav.poboril@nxp.com>
diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/dts.fixup b/arch/arm/soc/nxp_lpc/lpc54xxx/dts.fixup
index 4e3de15..f9903af 100644
--- a/arch/arm/soc/nxp_lpc/lpc54xxx/dts.fixup
+++ b/arch/arm/soc/nxp_lpc/lpc54xxx/dts.fixup
@@ -17,4 +17,9 @@
 #define CONFIG_USART_MCUX_LPC_0_IRQ_PRI	        NXP_LPC_USART_40086000_IRQ_0_PRIORITY
 #define CONFIG_USART_MCUX_LPC_0_NAME	        NXP_LPC_USART_40086000_LABEL
 
+#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ	NXP_LPC_MAILBOX_4008B000_IRQ_0
+#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI	NXP_LPC_MAILBOX_4008B000_IRQ_0_PRIORITY
+#define CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME	NXP_LPC_MAILBOX_4008B000_LABEL
+#define CONFIG_MAILBOX_MCUX_MAILBOX_0_BASE_ADDRESS	NXP_LPC_MAILBOX_4008B000_BASE_ADDRESS
+
 /* End of SoC Level DTS fixup file */
diff --git a/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts
index 33374d5..925fd43 100644
--- a/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts
+++ b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts
@@ -14,6 +14,7 @@
 
 	aliases {
 		usart-0 = &usart0;
+		mailbox-0 = &mailbox0;
 		led0 = &red_led;
 		led1 = &green_led;
 		led2 = &blue_led;
@@ -46,3 +47,7 @@
 	status = "disabled"; /* enable for console, if needed */
 	current-speed = <115200>;
 };
+
+&mailbox0 {
+	status = "ok";
+};
diff --git a/boards/arm/lpcxpresso54114_m4/lpcxpresso54114_m4.dts b/boards/arm/lpcxpresso54114_m4/lpcxpresso54114_m4.dts
index 4a2881d..7f5633c 100644
--- a/boards/arm/lpcxpresso54114_m4/lpcxpresso54114_m4.dts
+++ b/boards/arm/lpcxpresso54114_m4/lpcxpresso54114_m4.dts
@@ -14,6 +14,7 @@
 
 	aliases{
 		usart-0 = &usart0;
+		mailbox-0 = &mailbox0;
 		led0 = &red_led;
 		led1 = &green_led;
 		led2 = &blue_led;
@@ -46,3 +47,7 @@
 	status = "ok";
 	current-speed = <115200>;
 };
+
+&mailbox0 {
+	status = "ok";
+};
diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt
index bbff9cc..3121e87 100644
--- a/drivers/ipm/CMakeLists.txt
+++ b/drivers/ipm/CMakeLists.txt
@@ -1,5 +1,6 @@
 zephyr_library()
 
+zephyr_library_sources_ifdef(CONFIG_IPM_MCUX   ipm_mcux.c)
 zephyr_library_sources_ifdef(CONFIG_IPM_QUARK_SE ipm_quark_se.c)
 
 zephyr_library_sources_ifdef(CONFIG_USERSPACE   ipm_handlers.c)
diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig
index 9ff83ff..25d8214 100644
--- a/drivers/ipm/Kconfig
+++ b/drivers/ipm/Kconfig
@@ -22,3 +22,9 @@
 	  Sets up the initial interrupt mask and clears out all
 	  channels. Should be turned on for one CPU only.
 
+config IPM_MCUX
+	bool "MCUX IPM driver"
+	default n
+	depends on IPM && HAS_MCUX
+	help
+	  Driver for MCUX mailbox
diff --git a/drivers/ipm/ipm_mcux.c b/drivers/ipm/ipm_mcux.c
new file mode 100644
index 0000000..95aedee
--- /dev/null
+++ b/drivers/ipm/ipm_mcux.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017-2018, NXP
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <device.h>
+#include <ipm.h>
+#include <fsl_mailbox.h>
+#include <fsl_clock.h>
+#include <soc.h>
+
+#define MCUX_IPM_DATA_REGS 1
+#define MCUX_IPM_MAX_ID_VAL 0
+
+#if defined(__CM4_CMSIS_VERSION)
+#define MAILBOX_ID_THIS_CPU kMAILBOX_CM4
+#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM0Plus
+#else
+#define MAILBOX_ID_THIS_CPU kMAILBOX_CM0Plus
+#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM4
+#endif
+
+struct mcux_mailbox_config {
+	MAILBOX_Type *base;
+	void (*irq_config_func)(struct device *dev);
+};
+
+struct mcux_mailbox_data {
+	ipm_callback_t callback;
+	void *callback_ctx;
+};
+
+static void mcux_mailbox_isr(void *arg)
+{
+	struct device *dev = arg;
+	struct mcux_mailbox_data *data = dev->driver_data;
+	const struct mcux_mailbox_config *config = dev->config->config_info;
+	mailbox_cpu_id_t cpu_id;
+
+	cpu_id = MAILBOX_ID_THIS_CPU;
+
+	volatile u32_t value = MAILBOX_GetValue(config->base, cpu_id);
+
+	__ASSERT(value, "spurious MAILBOX interrupt");
+
+	/* Clear or the interrupt gets called intermittently */
+	MAILBOX_ClearValueBits(config->base, cpu_id, value);
+
+	if (data->callback) {
+		/* Only one MAILBOX, id is unused and set to 0 */
+		data->callback(data->callback_ctx, 0, &value);
+	}
+	/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F
+	 * Store immediate overlapping exception return operation
+	 * might vector to incorrect interrupt
+	 */
+#if defined __CORTEX_M && (__CORTEX_M == 4U)
+	__DSB();
+#endif
+}
+
+
+static int mcux_mailbox_ipm_send(struct device *d, int wait, u32_t id,
+			const void *data, int size)
+{
+	const struct mcux_mailbox_config *config = d->config->config_info;
+	MAILBOX_Type *base = config->base;
+	u32_t data32[MCUX_IPM_DATA_REGS]; /* Until we change API
+					   * to u32_t array
+					   */
+	int flags;
+	int i;
+
+	ARG_UNUSED(wait);
+
+	if (id > MCUX_IPM_MAX_ID_VAL) {
+		return -EINVAL;
+	}
+
+	if (size > MCUX_IPM_DATA_REGS * sizeof(u32_t)) {
+		return -EMSGSIZE;
+	}
+
+	flags = irq_lock();
+
+	/* Actual message is passing using 32 bits registers */
+	memcpy(data32, data, size);
+
+	for (i = 0; i < ARRAY_SIZE(data32); ++i) {
+		MAILBOX_SetValueBits(base, MAILBOX_ID_OTHER_CPU, data32[i]);
+	}
+
+	irq_unlock(flags);
+
+	return 0;
+}
+
+
+static int mcux_mailbox_ipm_max_data_size_get(struct device *d)
+{
+	ARG_UNUSED(d);
+	/* Only a single 32-bit register available */
+	return MCUX_IPM_DATA_REGS*sizeof(u32_t);
+}
+
+
+static u32_t mcux_mailbox_ipm_max_id_val_get(struct device *d)
+{
+	ARG_UNUSED(d);
+	/* Only a single instance of MAILBOX available for this platform */
+	return MCUX_IPM_MAX_ID_VAL;
+}
+
+static void mcux_mailbox_ipm_register_callback(struct device *d,
+					       ipm_callback_t cb,
+					       void *context)
+{
+	struct mcux_mailbox_data *driver_data = d->driver_data;
+
+	driver_data->callback = cb;
+	driver_data->callback_ctx = context;
+}
+
+
+static int mcux_mailbox_ipm_set_enabled(struct device *d, int enable)
+{
+	/* For now: nothing to be done */
+	return 0;
+}
+
+
+static int mcux_mailbox_init(struct device *dev)
+{
+	const struct mcux_mailbox_config *config = dev->config->config_info;
+
+	MAILBOX_Init(config->base);
+	config->irq_config_func(dev);
+	return 0;
+}
+
+static const struct ipm_driver_api mcux_mailbox_driver_api = {
+	.send = mcux_mailbox_ipm_send,
+	.register_callback = mcux_mailbox_ipm_register_callback,
+	.max_data_size_get = mcux_mailbox_ipm_max_data_size_get,
+	.max_id_val_get = mcux_mailbox_ipm_max_id_val_get,
+	.set_enabled = mcux_mailbox_ipm_set_enabled
+};
+
+
+/* Config MAILBOX 0 */
+
+static void mcux_mailbox_config_func_0(struct device *dev);
+
+static const struct mcux_mailbox_config mcux_mailbox_0_config = {
+	.base = (MAILBOX_Type *)CONFIG_MAILBOX_MCUX_MAILBOX_0_BASE_ADDRESS,
+	.irq_config_func = mcux_mailbox_config_func_0,
+};
+
+static struct mcux_mailbox_data mcux_mailbox_0_data;
+
+DEVICE_AND_API_INIT(mailbox_0, CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME,
+		    &mcux_mailbox_init,
+		    &mcux_mailbox_0_data, &mcux_mailbox_0_config,
+		    PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
+		    &mcux_mailbox_driver_api);
+
+
+static void mcux_mailbox_config_func_0(struct device *dev)
+{
+	IRQ_CONNECT(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ,
+		    CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI,
+		    mcux_mailbox_isr, DEVICE_GET(mailbox_0), 0);
+
+	irq_enable(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ);
+}
diff --git a/dts/arm/nxp/nxp_lpc54xxx.dtsi b/dts/arm/nxp/nxp_lpc54xxx.dtsi
index 388083d..61d6115 100644
--- a/dts/arm/nxp/nxp_lpc54xxx.dtsi
+++ b/dts/arm/nxp/nxp_lpc54xxx.dtsi
@@ -67,6 +67,14 @@
 			gpio-controller;
 			#gpio-cells = <2>;
 		};
+
+		mailbox0:mailbox@4008B000 {
+			compatible = "nxp,lpc-mailbox";
+			reg = <0x4008B000 0xEC>;
+			interrupts = <31 0>;
+			label = "MAILBOX_0";
+			status = "disabled";
+		};
 	};
 };
 
diff --git a/dts/bindings/arm/nxp,lpc-mailbox.yaml b/dts/bindings/arm/nxp,lpc-mailbox.yaml
new file mode 100644
index 0000000..d2b9dca
--- /dev/null
+++ b/dts/bindings/arm/nxp,lpc-mailbox.yaml
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2017, NXP
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+---
+title: LPC MAILBOX
+id: nxp,lpc-mailbox
+version: 0.1
+
+description: >
+    This binding gives a base representation of the LPC MAILBOX
+
+properties:
+  compatible:
+      type: string
+      category: required
+      description: compatible strings
+      constraint: "nxp,lpc-mailbox"
+
+  reg:
+      type: array
+      description: mmio register space
+      generation: define
+      category: required
+
+  interrupts:
+      type: array
+      category: required
+      description: required interrupts
+      generation: define
+
+  label:
+      type: string
+      category: required
+      description: Human readable string describing the device (used by Zephyr for API name)
+      generation: define
+
+...