From 606a91990b69a03a646ec4ba428f5f05e426824c Mon Sep 17 00:00:00 2001 From: Teo Hall Date: Mon, 12 Sep 2016 14:15:44 -0500 Subject: [PATCH] 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 Signed-off-by: Ye Li (cherry picked from commit 9caafe21ddf12c9ab994fe9e65dc7afe5e7bab3d) (cherry picked from commit a360802ec1d1b52ea7d0c91e285ba355d0293140) --- drivers/mailbox/Kconfig | 7 ++ drivers/mailbox/Makefile | 1 + drivers/mailbox/imx-mu.c | 191 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 drivers/mailbox/imx-mu.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 2836ee4a7b..bcd6785c6d 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -34,4 +34,11 @@ config K3_SEC_PROXY Select this driver if your platform has support for this hardware block. +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 cd237698ba..af162714e2 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.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 +#include +#include +#include + +#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, +}; -- 2.17.1