summaryrefslogtreecommitdiff
path: root/drivers/mailbox
diff options
context:
space:
mode:
authorTeo Hall <teo.hall@nxp.com>2016-09-12 14:15:44 -0500
committerYe Li <ye.li@nxp.com>2018-04-27 02:32:30 -0700
commita360802ec1d1b52ea7d0c91e285ba355d0293140 (patch)
treeae9cd59cf62be1286b4075ded1307ac9e00e7e2c /drivers/mailbox
parentafcfb7e5105ef01ec46a6c896b20e210a07ee094 (diff)
MLK-14938-24 mailbox: add imx mu DM mailbox driver
implement i.MX Messaging Unit driver within the DM Mailbox uclass Signed-off-by: Teo Hall <teo.hall@nxp.com> Signed-off-by: Ye Li <ye.li@nxp.com> (cherry picked from commit 9caafe21ddf12c9ab994fe9e65dc7afe5e7bab3d)
Diffstat (limited to 'drivers/mailbox')
-rw-r--r--drivers/mailbox/Kconfig7
-rw-r--r--drivers/mailbox/Makefile1
-rw-r--r--drivers/mailbox/imx-mu.c191
3 files changed, 199 insertions, 0 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 9649b70589..14b5a03c9a 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -24,4 +24,11 @@ config TEGRA_HSP
This enables support for the NVIDIA Tegra HSP Hw module, which
implements doorbells, mailboxes, semaphores, and shared interrupts.
+config IMX_MU
+ bool "Enable i.MX MU support"
+ depends on DM_MAILBOX
+ help
+ Enable support for i.MX Messaging Unit for communication with other
+ processors on the SoC
+
endmenu
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 155dbeb099..75cd456678 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o
+obj-$(CONFIG_IMX_MU) += imx-mu.o
diff --git a/drivers/mailbox/imx-mu.c b/drivers/mailbox/imx-mu.c
new file mode 100644
index 0000000000..d08f9d1500
--- /dev/null
+++ b/drivers/mailbox/imx-mu.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <mailbox-uclass.h>
+
+#define NUM_MU_CHANNELS 4
+#define NUM_MU_FLAGS 4
+#define NUM_MU_GIP 4
+
+#define mu_rr(x) (0x10 + (x * 0x4))
+#define mu_tr(x) (x * 0x4)
+#define MU_SR_OFFSET 0x20
+#define MU_CR_OFFSET 0x24
+#define CHAN_TE_MASK(x) (0x00100000 << (x))
+#define CHAN_RF_MASK(x) (0x01000000 << (x))
+#define MU_CR_INT_MSK 0xFFF00000
+#define MU_FLGS_MSK 0x00000007
+#define MU_GIP_MSK 0xF0000000
+
+
+
+/* This driver only exposes the status bits to keep with the
+ * polling methodology of u-boot.
+ */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct imx_mu_mbox {
+ fdt_addr_t base;
+
+ /* use pointers to channel as a way to reserve channels */
+ void *channels[NUM_MU_CHANNELS];
+ bool flags[NUM_MU_FLAGS];
+
+ /* TODO add support for the reading/setting of flags to
+ * B side of MU
+ */
+};
+
+
+/* check that the channel is open or owned by caller */
+static int mu_check_channel(struct mbox_chan *chan)
+{
+ struct imx_mu_mbox *mailbox = dev_get_priv(chan->dev);
+
+ /* use id as number of channel within mbox only */
+ if ((chan->id < 0) || (chan->id >= NUM_MU_CHANNELS)) {
+ debug("nxp mu id out of range: %lu\n", chan->id);
+ return -EINVAL;
+ }
+ if (mailbox->channels[chan->id] != NULL) {
+ /* if reserved check that caller owns */
+ if (mailbox->channels[chan->id] == chan)
+ return 1; /* caller owns the channel */
+
+ return -EACCES;
+ }
+ return 0;/* channel empty */
+}
+
+static int mu_chan_request(struct mbox_chan *chan)
+{
+ struct imx_mu_mbox *mailbox = dev_get_priv(chan->dev);
+
+ debug("%s(chan=%p)\n", __func__, chan);
+
+ int status = mu_check_channel(chan);
+ if (status < 0) {
+ debug("channel not available :%d\n", status);
+ return -EPERM;
+ }
+ mailbox->channels[chan->id] = chan;
+
+ return 0;
+}
+/* currently not dynamically allocated
+ * only change pointer back to NULL */
+static int mu_chan_free(struct mbox_chan *chan)
+{
+ struct imx_mu_mbox *mailbox = dev_get_priv(chan->dev);
+ int status = mu_check_channel(chan);
+
+ debug("%s(chan=%p)\n", __func__, chan);
+ if (status <= 0) { /* check that the channel is also not empty */
+ debug("mu_chan_free() failed exit code: %d\n", status);
+ return status;
+ }
+ /*if you own channel and channel is NOT empty */
+ mailbox->channels[chan->id] = NULL;
+
+ return 0;
+}
+
+static int mu_send(struct mbox_chan *chan, const void *data)
+{
+ struct imx_mu_mbox *mbox = dev_get_priv(chan->dev);
+ int status = mu_check_channel(chan);
+ uint32_t val = *((uint32_t *)data);
+
+ debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
+ if (status < 1) {
+ debug("mu_send() failed. mu_chan_status is :%d\n", status);
+ return -EPERM;
+ }
+
+ /*check if transmit register is empty */
+ if (!(readl(mbox->base+MU_SR_OFFSET) & CHAN_TE_MASK(chan->id)))
+ return -EBUSY;
+
+ /* send out on transmit register*/
+ writel(val, mbox->base + mu_tr(chan->id));
+ return 0;
+}
+
+static int mu_recv(struct mbox_chan *chan, void *data)
+{
+ struct imx_mu_mbox *mbox = dev_get_priv(chan->dev);
+ int status = mu_check_channel(chan);
+ uint32_t *buffer = data;
+
+ debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
+
+ if (status < 1)
+ return -EPERM; /* return if channel isnt owned */
+
+ if (readl(mbox->base + MU_SR_OFFSET) & CHAN_RF_MASK(chan->id))
+ return -ENODATA;
+
+ *buffer = readl(mu_rr(chan->id));
+
+ return 0;
+}
+
+static int imx_mu_bind(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+static int imx_mu_probe(struct udevice *dev)
+{
+ struct imx_mu_mbox *mbox = dev_get_priv(dev);
+ uint32_t val;
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ /* get address from device tree */
+ mbox->base = dev_get_addr(dev);
+ if (mbox->base == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ val = readl(mbox->base + MU_CR_OFFSET);
+ val = val & ~MU_CR_INT_MSK;/* disable all interrupts */
+ val = val & ~MU_FLGS_MSK; /* clear all flags */
+
+ writel(val, mbox->base + MU_CR_OFFSET);
+
+ val = readl(mbox->base + MU_SR_OFFSET);
+ val = val | MU_GIP_MSK; /* clear any pending GIP */
+ writel(val, mbox->base + MU_SR_OFFSET);
+
+ return 0;
+}
+
+static const struct udevice_id imx_mu_ids[] = {
+ { .compatible = "nxp,imx-mu" },
+ { }
+};
+
+struct mbox_ops imx_mu_mbox_ops = {
+ .request = mu_chan_request,
+ .free = mu_chan_free,
+ .send = mu_send,
+ .recv = mu_recv,
+};
+
+U_BOOT_DRIVER(imx_mu) = {
+ .name = "imx-mu",
+ .id = UCLASS_MAILBOX,
+ .of_match = imx_mu_ids,
+ .bind = imx_mu_bind,
+ .probe = imx_mu_probe,
+ .priv_auto_alloc_size = sizeof(struct imx_mu_mbox),
+ .ops = &imx_mu_mbox_ops,
+};