LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] mailbox: arm_mhu: add support for mhuv2
@ 2018-05-02  7:14 Samarth Parikh
  2018-05-02 12:04 ` Jassi Brar
  0 siblings, 1 reply; 5+ messages in thread
From: Samarth Parikh @ 2018-05-02  7:14 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: linux-kernel, Sudipto.Paul, Arvind.Chauhan, samarthp,
	Deepak.Pandey, Sudeep.Holla, Samarth Parikh

Hi Jassi,

I am resending the patch for review, in case you have missed my previous
patch. Can you please go through it and let me know your thoughts on
the same?

ARM has launched a next version of MHU i.e. MHUv2 with its latest
subsystems. The main change is that the MHUv2 is now a distributed IP
with different peripheral views (registers) for the sender and receiver.

Another main difference is that MHUv1 duplex channels are now split into
simplex/half duplex in MHUv2. MHUv2 has a configurable number of
communication channels. There is a capability register (MSG_NO_CAP) to
find out how many channels are available in a system.

The register offsets have also changed for STAT, SET & CLEAR registers
from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.

0x0    0x4  0x8  0xC             0x1F
------------------------....-----
| STAT |    |    | SET |    |   |
------------------------....-----
      Transmit Channel

0x0    0x4  0x8   0xC            0x1F
------------------------....-----
| STAT |    | CLR |    |    |   |
------------------------....-----
        Receive Channel

The MHU controller can request the receiver to wake-up and once the
request is removed, the receiver may go back to sleep, but the MHU
itself does not actively puts a receiver to sleep.

So, in order to wake-up the receiver when the sender wants to send data,
the sender has to set ACCESS_REQUEST register first in order to wake-up
receiver, state of which can be detected using ACCESS_READY register.
ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
of 0xF8C and are accessible only on any sender channel.

This patch adds necessary changes required to support the older
version of MHU & the latest MHUv2 controller. This patch also need an
update in DT binding for ARM MHU as we need a second register base
(tx base) which would be used as the send channel base.

Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
---
 drivers/mailbox/arm_mhu.c | 163 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 151 insertions(+), 12 deletions(-)

diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c
index 99befa7..d8825c5 100644
--- a/drivers/mailbox/arm_mhu.c
+++ b/drivers/mailbox/arm_mhu.c
@@ -23,6 +23,8 @@
 #include <linux/module.h>
 #include <linux/amba/bus.h>
 #include <linux/mailbox_controller.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>

 #define INTR_STAT_OFS  0x0
 #define INTR_SET_OFS   0x8
@@ -33,12 +35,69 @@
 #define MHU_SEC_OFFSET 0x200
 #define TX_REG_OFFSET  0x100

+#define MHU_V2_REG_STAT_OFS    0x0
+#define MHU_V2_REG_CLR_OFS     0x8
+#define MHU_V2_REG_SET_OFS     0xC
+#define MHU_V2_REG_MSG_NO_CAP  0xF80
+#define MHU_V2_REG_ACC_REQ_OFS 0xF88
+#define MHU_V2_REG_ACC_RDY_OFS 0xF8C
+
+#define MHU_V2_LP_OFFSET  0x20
+#define MHU_V2_HP_OFFSET  0x0
+
 #define MHU_CHANS      3

+enum mhu_ver {
+       MHU_V1 = 1,
+       MHU_V2,
+       MHU_VER_END
+};
+
+enum mhu_regs {
+       MHU_REG_STAT,
+       MHU_REG_SET,
+       MHU_REG_CLR,
+       MHU_REG_END
+};
+
+enum mhu_access_regs {
+       MHU_REG_MSG_NO_CAP,
+       MHU_REG_ACC_REQ,
+       MHU_REG_ACC_RDY,
+       MHU_REG_ACC_END
+};
+
+enum mhu_channels {
+       MHU_CHAN_LOW,
+       MHU_CHAN_HIGH,
+       MHU_CHAN_SEC,
+       MHU_CHAN_END
+};
+
+/**
+ * ARM MHU Mailbox device specific data
+ *
+ * @regs: MHU version specific array of register offset for STAT,
+ *        SET & CLEAR registers.
+ * @chans: MHU version specific array of channel offset for Low
+ *         Priority, High Priority & Secure channels.
+ * @acc_regs: An array of access register offsets.
+ * @tx_reg_off: Offset for TX register.
+ * @version: Version of MHU controller available in the system.
+ */
+struct mhu_data {
+       int regs[MHU_REG_END]; /* STAT, SET, CLEAR */
+       int chans[MHU_CHAN_END]; /* LP, HP, Sec */
+       int acc_regs[MHU_REG_ACC_END];
+       long int tx_reg_off;
+       uint8_t version;
+};
+
 struct mhu_link {
        unsigned irq;
        void __iomem *tx_reg;
        void __iomem *rx_reg;
+       unsigned int pchan;
 };

 struct arm_mhu {
@@ -46,21 +105,24 @@ struct arm_mhu {
        struct mhu_link mlink[MHU_CHANS];
        struct mbox_chan chan[MHU_CHANS];
        struct mbox_controller mbox;
+       struct mhu_data *drvdata;
 };

 static irqreturn_t mhu_rx_interrupt(int irq, void *p)
 {
        struct mbox_chan *chan = p;
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 val;

-       val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
+       val = readl_relaxed(mlink->rx_reg + mdata->regs[MHU_REG_STAT]);
        if (!val)
                return IRQ_NONE;

        mbox_chan_received_data(chan, (void *)&val);

-       writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
+       writel_relaxed(val, mlink->rx_reg + mdata->regs[MHU_REG_CLR]);

        return IRQ_HANDLED;
 }
@@ -68,7 +130,9 @@ static irqreturn_t mhu_rx_interrupt(int irq, void *p)
 static bool mhu_last_tx_done(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
-       u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
+       u32 val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_REG_STAT]);

        return (val == 0);
 }
@@ -76,9 +140,11 @@ static bool mhu_last_tx_done(struct mbox_chan *chan)
 static int mhu_send_data(struct mbox_chan *chan, void *data)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 *arg = data;

-       writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
+       writel_relaxed(*arg, mlink->tx_reg + mdata->regs[MHU_REG_SET]);

        return 0;
 }
@@ -86,11 +152,18 @@ static int mhu_send_data(struct mbox_chan *chan, void *data)
 static int mhu_startup(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 val;
        int ret;

-       val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
-       writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
+       if (mdata->version == MHU_V2)
+               writel_relaxed(0x1, mlink->tx_reg
+                       + (mdata->acc_regs[MHU_REG_ACC_REQ]
+                       - (mdata->chans[mlink->pchan])));
+
+       val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_REG_STAT]);
+       writel_relaxed(val, mlink->tx_reg + mdata->regs[MHU_REG_CLR]);

        ret = request_irq(mlink->irq, mhu_rx_interrupt,
                          IRQF_SHARED, "mhu_link", chan);
@@ -106,6 +179,13 @@ static int mhu_startup(struct mbox_chan *chan)
 static void mhu_shutdown(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
+
+       if (mdata->version == MHU_V2)
+               writel_relaxed(0x0, mlink->tx_reg
+                       + (mdata->acc_regs[MHU_REG_ACC_REQ]
+                       - (mdata->chans[mlink->pchan])));

        free_irq(mlink->irq, chan);
 }
@@ -122,7 +202,15 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id)
        int i, err;
        struct arm_mhu *mhu;
        struct device *dev = &adev->dev;
-       int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET};
+       void __iomem *tx_base;
+       struct device_node *np = dev->of_node;
+       struct mhu_data *mdata = id->data;
+       unsigned int pchans = MHU_CHANS;
+
+       if (!mdata) {
+               dev_err(dev, "device data not found\n");
+               return -EINVAL;
+       }

        /* Allocate memory for device */
        mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
@@ -135,20 +223,45 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id)
                return PTR_ERR(mhu->base);
        }

-       for (i = 0; i < MHU_CHANS; i++) {
+       if (mdata->version == MHU_V2) {
+               tx_base = of_iomap(np, 1);
+               if (!tx_base) {
+                       dev_err(dev, "failed to map tx registers\n");
+                       return -ENOMEM;
+               }
+
+               mdata->tx_reg_off = tx_base - mhu->base;
+               pchans = readl_relaxed(tx_base
+                               + mdata->acc_regs[MHU_REG_MSG_NO_CAP]);
+               if (pchans == 0 || pchans > MHU_CHANS) {
+                       dev_err(dev, "invalid number of channels\n");
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < pchans; i++) {
                mhu->chan[i].con_priv = &mhu->mlink[i];
-               mhu->mlink[i].irq = adev->irq[i];
-               mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i];
-               mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
+               mhu->mlink[i].pchan = i;
+               int irq = mhu->mlink[i].irq = adev->irq[i];
+
+               if (irq <= 0) {
+                       dev_dbg(dev, "No IRQ found for Channel %d\n", i);
+                       continue;
+               }
+
+               mhu->mlink[i].rx_reg = mhu->base + mdata->chans[i];
+               mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg
+                       + mdata->tx_reg_off;
        }

        mhu->mbox.dev = dev;
        mhu->mbox.chans = &mhu->chan[0];
-       mhu->mbox.num_chans = MHU_CHANS;
+       mhu->mbox.num_chans = pchans;
        mhu->mbox.ops = &mhu_ops;
        mhu->mbox.txdone_irq = false;
        mhu->mbox.txdone_poll = true;
        mhu->mbox.txpoll_period = 1;
+       mhu->drvdata = mdata;

        amba_set_drvdata(adev, mhu);

@@ -171,10 +284,36 @@ static int mhu_remove(struct amba_device *adev)
        return 0;
 }

+static struct mhu_data arm_mhuv2_data = {
+       .regs = { MHU_V2_REG_STAT_OFS, MHU_V2_REG_SET_OFS, MHU_V2_REG_CLR_OFS },
+       .chans = { MHU_V2_LP_OFFSET, MHU_V2_HP_OFFSET },
+       .acc_regs = { MHU_V2_REG_MSG_NO_CAP, MHU_V2_REG_ACC_REQ_OFS,
+               MHU_V2_REG_ACC_RDY_OFS },
+       .version = MHU_V2,
+};
+
+static struct mhu_data arm_mhuv1_data = {
+       .regs = { INTR_STAT_OFS, INTR_SET_OFS, INTR_CLR_OFS },
+       .chans = { MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET },
+       .tx_reg_off = TX_REG_OFFSET,
+       .version = MHU_V1,
+};
+
 static struct amba_id mhu_ids[] = {
        {
+               .id     = 0x4b0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       {
+               .id     = 0xbb0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       {
                .id     = 0x1bb098,
                .mask   = 0xffffff,
+               .data   = (void *)&arm_mhuv1_data,
        },
        { 0, 0 },
 };
--
2.7.4

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* Re: [PATCH] mailbox: arm_mhu: add support for mhuv2
  2018-05-02  7:14 [PATCH] mailbox: arm_mhu: add support for mhuv2 Samarth Parikh
@ 2018-05-02 12:04 ` Jassi Brar
  2018-05-14  8:07   ` Samarth Parikh
  0 siblings, 1 reply; 5+ messages in thread
From: Jassi Brar @ 2018-05-02 12:04 UTC (permalink / raw)
  To: Samarth Parikh
  Cc: Linux Kernel Mailing List, Sudipto.Paul, Arvind.Chauhan,
	samarthp, Deepak.Pandey, Sudeep Holla

On Wed, May 2, 2018 at 12:44 PM, Samarth Parikh <samarth.parikh@arm.com> wrote:
> Hi Jassi,
>
> I am resending the patch for review, in case you have missed my previous
> patch. Can you please go through it and let me know your thoughts on
> the same?
>
You don't want this to go into git log :)
If your patch isn't looked into for more than 2weeks (or longer if
merge window is not near), please just ping as a reply to original
submission.
Anyways....

> ARM has launched a next version of MHU i.e. MHUv2 with its latest
> subsystems. The main change is that the MHUv2 is now a distributed IP
> with different peripheral views (registers) for the sender and receiver.
>
> Another main difference is that MHUv1 duplex channels are now split into
> simplex/half duplex in MHUv2. MHUv2 has a configurable number of
> communication channels. There is a capability register (MSG_NO_CAP) to
> find out how many channels are available in a system.
>
> The register offsets have also changed for STAT, SET & CLEAR registers
> from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.
>
> 0x0    0x4  0x8  0xC             0x1F
> ------------------------....-----
> | STAT |    |    | SET |    |   |
> ------------------------....-----
>       Transmit Channel
>
> 0x0    0x4  0x8   0xC            0x1F
> ------------------------....-----
> | STAT |    | CLR |    |    |   |
> ------------------------....-----
>         Receive Channel
>
> The MHU controller can request the receiver to wake-up and once the
> request is removed, the receiver may go back to sleep, but the MHU
> itself does not actively puts a receiver to sleep.
>
> So, in order to wake-up the receiver when the sender wants to send data,
> the sender has to set ACCESS_REQUEST register first in order to wake-up
> receiver, state of which can be detected using ACCESS_READY register.
> ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
> of 0xF8C and are accessible only on any sender channel.
>
> This patch adds necessary changes required to support the older
> version of MHU & the latest MHUv2 controller. This patch also need an
> update in DT binding for ARM MHU as we need a second register base
> (tx base) which would be used as the send channel base.
>
> Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
> ---
>  drivers/mailbox/arm_mhu.c | 163 ++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 151 insertions(+), 12 deletions(-)
>
The original driver is 195 loc, this patch makes it almost double the size.
Also there have been controllers (resembling closer to MHU than this
one) with separate drivers. So I think we should simply create another
arm_mhu_v2.c ?

Cheers!

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

* Re: [PATCH] mailbox: arm_mhu: add support for mhuv2
  2018-05-02 12:04 ` Jassi Brar
@ 2018-05-14  8:07   ` Samarth Parikh
  0 siblings, 0 replies; 5+ messages in thread
From: Samarth Parikh @ 2018-05-14  8:07 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Linux Kernel Mailing List, Sudipto Paul, Arvind Chauhan,
	samarthp, Deepak Pandey, Sudeep Holla

Hi Jassi,

As suggested by you, I have moved the MHUv2 related changes to a new file arm_mhu_v2.c. I have sent an updated patch, can you please review it?

Regards,
Samarth

On 02/05/18, 5:34 PM, "Jassi Brar" <jassisinghbrar@gmail.com> wrote:

    On Wed, May 2, 2018 at 12:44 PM, Samarth Parikh <samarth.parikh@arm.com> wrote:
    > Hi Jassi,
    >
    > I am resending the patch for review, in case you have missed my previous
    > patch. Can you please go through it and let me know your thoughts on
    > the same?
    >
    You don't want this to go into git log :)
    If your patch isn't looked into for more than 2weeks (or longer if
    merge window is not near), please just ping as a reply to original
    submission.
    Anyways....

    > ARM has launched a next version of MHU i.e. MHUv2 with its latest
    > subsystems. The main change is that the MHUv2 is now a distributed IP
    > with different peripheral views (registers) for the sender and receiver.
    >
    > Another main difference is that MHUv1 duplex channels are now split into
    > simplex/half duplex in MHUv2. MHUv2 has a configurable number of
    > communication channels. There is a capability register (MSG_NO_CAP) to
    > find out how many channels are available in a system.
    >
    > The register offsets have also changed for STAT, SET & CLEAR registers
    > from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.
    >
    > 0x0    0x4  0x8  0xC             0x1F
    > ------------------------....-----
    > | STAT |    |    | SET |    |   |
    > ------------------------....-----
    >       Transmit Channel
    >
    > 0x0    0x4  0x8   0xC            0x1F
    > ------------------------....-----
    > | STAT |    | CLR |    |    |   |
    > ------------------------....-----
    >         Receive Channel
    >
    > The MHU controller can request the receiver to wake-up and once the
    > request is removed, the receiver may go back to sleep, but the MHU
    > itself does not actively puts a receiver to sleep.
    >
    > So, in order to wake-up the receiver when the sender wants to send data,
    > the sender has to set ACCESS_REQUEST register first in order to wake-up
    > receiver, state of which can be detected using ACCESS_READY register.
    > ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
    > of 0xF8C and are accessible only on any sender channel.
    >
    > This patch adds necessary changes required to support the older
    > version of MHU & the latest MHUv2 controller. This patch also need an
    > update in DT binding for ARM MHU as we need a second register base
    > (tx base) which would be used as the send channel base.
    >
    > Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
    > ---
    >  drivers/mailbox/arm_mhu.c | 163 ++++++++++++++++++++++++++++++++++++++++++----
    >  1 file changed, 151 insertions(+), 12 deletions(-)
    >
    The original driver is 195 loc, this patch makes it almost double the size.
    Also there have been controllers (resembling closer to MHU than this
    one) with separate drivers. So I think we should simply create another
    arm_mhu_v2.c ?

    Cheers!


IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* [PATCH] mailbox: arm_mhu: add support for mhuv2
@ 2018-05-14  8:02 Samarth Parikh
  0 siblings, 0 replies; 5+ messages in thread
From: Samarth Parikh @ 2018-05-14  8:02 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: linux-kernel, Sudipto.Paul, Arvind.Chauhan, Deepak.Pandey,
	samarthp, Sudeep.Holla, Samarth Parikh

ARM has launched a next version of MHU i.e. MHUv2 with its latest
subsystems. The main change is that the MHUv2 is now a distributed IP
with different peripheral views (registers) for the sender and receiver.

Another main difference is that MHUv1 duplex channels are now split into
simplex/half duplex in MHUv2. MHUv2 has a configurable number of
communication channels. There is a capability register (MSG_NO_CAP) to
find out how many channels are available in a system.

The register offsets have also changed for STAT, SET & CLEAR registers
from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.

0x0    0x4  0x8  0xC             0x1F
------------------------....-----
| STAT |    |    | SET |    |   |
------------------------....-----
      Transmit Channel

0x0    0x4  0x8   0xC            0x1F
------------------------....-----
| STAT |    | CLR |    |    |   |
------------------------....-----
        Receive Channel

The MHU controller can request the receiver to wake-up and once the
request is removed, the receiver may go back to sleep, but the MHU
itself does not actively puts a receiver to sleep.

So, in order to wake-up the receiver when the sender wants to send data,
the sender has to set ACCESS_REQUEST register first in order to wake-up
receiver, state of which can be detected using ACCESS_READY register.
ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
of 0xF8C and are accessible only on any sender channel.

This patch adds necessary changes in a new file required to support the
latest MHUv2 controller. This patch also need an update in DT binding for
ARM MHUv2 as we need a second register base (tx base) which would be used
as the send channel base.

Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
---
 drivers/mailbox/Kconfig      |   9 ++
 drivers/mailbox/Makefile     |   2 +
 drivers/mailbox/arm_mhu_v2.c | 309 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 320 insertions(+)
 create mode 100644 drivers/mailbox/arm_mhu_v2.c

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index a2bb274..416bc78 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,15 @@ config ARM_MHU
          The controller has 3 mailbox channels, the last of which can be
          used in Secure mode only.

+config ARM_MHU_V2
+       tristate "ARM MHUv2 Mailbox"
+       depends on ARM_AMBA
+       help
+         Say Y here if you want to build the ARM MHUv2 controller driver.
+         The controller is a distributed IP with different peripheral
+         views (registers) for the sender and receiver & has 3 mailbox
+         channels, the last of which can be used in Secure mode only.
+
 config PLATFORM_MHU
        tristate "Platform MHU Mailbox"
        depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index cc23c3a..ae899a9 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_ARM_MHU_V2)       += arm_mhu_v2.o
+
 obj-$(CONFIG_PLATFORM_MHU)     += platform_mhu.o

 obj-$(CONFIG_PL320_MBOX)       += pl320-ipc.o
diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
new file mode 100644
index 0000000..259d4a9
--- /dev/null
+++ b/drivers/mailbox/arm_mhu_v2.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ * Author: Samarth Parikh <samarth.parikh@arm.com>
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/amba/bus.h>
+#include <linux/mailbox_controller.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#define MHU_V2_REG_STAT_OFS            0x0
+#define MHU_V2_REG_CLR_OFS             0x8
+#define MHU_V2_REG_SET_OFS             0xC
+#define MHU_V2_REG_MSG_NO_CAP_OFS      0xF80
+#define MHU_V2_REG_ACC_REQ_OFS         0xF88
+#define MHU_V2_REG_ACC_RDY_OFS         0xF8C
+
+#define MHU_V2_LP_OFFSET               0x20
+#define MHU_V2_HP_OFFSET               0x0
+
+#define MHU_V2_CHANS                   3
+
+#define mbox_to_arm_mhuv2(c) container_of(c, struct arm_mhuv2, mbox)
+
+enum mhuv2_regs {
+       MHU_V2_REG_STAT,
+       MHU_V2_REG_SET,
+       MHU_V2_REG_CLR,
+       MHU_V2_REG_END
+};
+
+enum mhuv2_access_regs {
+       MHU_V2_REG_MSG_NO_CAP,
+       MHU_V2_REG_ACC_REQ,
+       MHU_V2_REG_ACC_RDY,
+       MHU_V2_REG_ACC_END
+};
+
+enum mhuv2_channels {
+       MHU_V2_CHAN_LOW,
+       MHU_V2_CHAN_HIGH,
+       MHU_V2_CHAN_SEC,
+       MHU_V2_CHAN_END
+};
+
+/**
+ * ARM MHUv2 Mailbox device specific data
+ *
+ * @regs: MHUv2 specific array of register offset for STAT, SET & CLEAR
+ *        registers.
+ * @chans: MHUv2 specific array of channel offset for Low
+ *         Priority, High Priority & Secure channels.
+ * @acc_regs: An array of access register offsets.
+ */
+struct mhuv2_data {
+       int regs[MHU_V2_REG_END]; /* STAT, SET, CLEAR */
+       int chans[MHU_V2_CHAN_END]; /* LP, HP, Sec */
+       int acc_regs[MHU_V2_REG_ACC_END];
+};
+
+/**
+ * ARM MHUv2 link specific data
+ *
+ * @irq: MHUv2 receive channel IRQ number
+ * @tx_reg: Transmit channel register
+ * @rx_reg: Receive channel register
+ * @pchan: No. of physical channels
+ */
+struct mhuv2_link {
+       unsigned int irq;
+       void __iomem *tx_reg;
+       void __iomem *rx_reg;
+       unsigned int pchan;
+};
+
+/**
+ * ARM MHUv2 Mailbox driver specific data
+ *
+ * @mlink: MHUv2 link specific data
+ * @chan: Mbox specific data
+ * @mbox: Mbox controller specific data
+ * @drvdata: MHUv2 device specific data
+ */
+struct arm_mhuv2 {
+       struct mhuv2_link mlink[MHU_V2_CHANS];
+       struct mbox_chan chan[MHU_V2_CHANS];
+       struct mbox_controller mbox;
+       const struct mhuv2_data *drvdata;
+};
+
+static irqreturn_t mhuv2_rx_interrupt(int irq, void *p)
+{
+       struct mbox_chan *chan = p;
+       struct mhuv2_link *mlink = chan->con_priv;
+       struct arm_mhuv2 *mhu = mbox_to_arm_mhuv2(chan->mbox);
+       const struct mhuv2_data *mdata = mhu->drvdata;
+       u32 val;
+
+       val = readl_relaxed(mlink->rx_reg + mdata->regs[MHU_V2_REG_STAT]);
+       if (!val)
+               return IRQ_NONE;
+
+       mbox_chan_received_data(chan, (void *)&val);
+
+       writel_relaxed(val, mlink->rx_reg + mdata->regs[MHU_V2_REG_CLR]);
+
+       return IRQ_HANDLED;
+}
+
+static bool mhuv2_last_tx_done(struct mbox_chan *chan)
+{
+       struct mhuv2_link *mlink = chan->con_priv;
+       struct arm_mhuv2 *mhu = mbox_to_arm_mhuv2(chan->mbox);
+       const struct mhuv2_data *mdata = mhu->drvdata;
+       u32 val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_V2_REG_STAT]);
+
+       return (val == 0);
+}
+
+static int mhuv2_send_data(struct mbox_chan *chan, void *data)
+{
+       struct mhuv2_link *mlink = chan->con_priv;
+       struct arm_mhuv2 *mhu = mbox_to_arm_mhuv2(chan->mbox);
+       const struct mhuv2_data *mdata = mhu->drvdata;
+       u32 *arg = data;
+
+       writel_relaxed(*arg, mlink->tx_reg + mdata->regs[MHU_V2_REG_SET]);
+
+       return 0;
+}
+
+static int mhuv2_startup(struct mbox_chan *chan)
+{
+       struct mhuv2_link *mlink = chan->con_priv;
+       struct arm_mhuv2 *mhu = mbox_to_arm_mhuv2(chan->mbox);
+       const struct mhuv2_data *mdata = mhu->drvdata;
+       u32 val;
+       int ret;
+
+       writel_relaxed(0x1, mlink->tx_reg
+               + (mdata->acc_regs[MHU_V2_REG_ACC_REQ]
+               - (mdata->chans[mlink->pchan])));
+
+       val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_V2_REG_STAT]);
+       writel_relaxed(val, mlink->tx_reg + mdata->regs[MHU_V2_REG_CLR]);
+
+       ret = request_irq(mlink->irq, mhuv2_rx_interrupt,
+                         IRQF_SHARED, "mhuv2_link", chan);
+       if (ret) {
+               dev_err(chan->mbox->dev,
+                       "Unable to acquire IRQ %d\n", mlink->irq);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mhuv2_shutdown(struct mbox_chan *chan)
+{
+       struct mhuv2_link *mlink = chan->con_priv;
+       struct arm_mhuv2 *mhu = mbox_to_arm_mhuv2(chan->mbox);
+       const struct mhuv2_data *mdata = mhu->drvdata;
+
+       writel_relaxed(0x0, mlink->tx_reg
+               + (mdata->acc_regs[MHU_V2_REG_ACC_REQ]
+               - (mdata->chans[mlink->pchan])));
+
+       free_irq(mlink->irq, chan);
+}
+
+static const struct mbox_chan_ops mhuv2_ops = {
+       .send_data = mhuv2_send_data,
+       .startup = mhuv2_startup,
+       .shutdown = mhuv2_shutdown,
+       .last_tx_done = mhuv2_last_tx_done,
+};
+
+static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+{
+       int i, err, irq;
+       struct arm_mhuv2 *mhu;
+       struct device *dev = &adev->dev;
+       void __iomem *rx_base;
+       void __iomem *tx_base;
+       const struct device_node *np = dev->of_node;
+       const struct mhuv2_data *mdata = id->data;
+       unsigned int pchans;
+
+       if (!mdata) {
+               dev_err(dev, "device data not found\n");
+               return -EINVAL;
+       }
+
+       /* Allocate memory for device */
+       mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
+       if (!mhu)
+               return -ENOMEM;
+
+       rx_base = devm_ioremap_resource(dev, &adev->res);
+       if (IS_ERR(rx_base)) {
+               dev_err(dev, "ioremap failed\n");
+               return PTR_ERR(rx_base);
+       }
+
+       tx_base = of_iomap((struct device_node *)np, 1);
+       if (!tx_base) {
+               dev_err(dev, "failed to map tx registers\n");
+               return -ENOMEM;
+       }
+
+       pchans = readl_relaxed(tx_base
+                       + mdata->acc_regs[MHU_V2_REG_MSG_NO_CAP]);
+       if (pchans == 0 || pchans > MHU_V2_CHANS) {
+               dev_err(dev, "invalid number of channels %d\n", pchans);
+               iounmap(tx_base);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pchans; i++) {
+               mhu->chan[i].con_priv = &mhu->mlink[i];
+               mhu->mlink[i].pchan = i;
+               irq = mhu->mlink[i].irq = adev->irq[i];
+
+               if (irq <= 0) {
+                       dev_err(dev, "no IRQ found for channel %d\n", i);
+                       iounmap(tx_base);
+                       return -EINVAL;
+               }
+
+               mhu->mlink[i].rx_reg = rx_base + mdata->chans[i];
+               mhu->mlink[i].tx_reg = tx_base + mdata->chans[i];
+       }
+
+       mhu->mbox.dev = dev;
+       mhu->mbox.chans = &mhu->chan[0];
+       mhu->mbox.num_chans = pchans;
+       mhu->mbox.ops = &mhuv2_ops;
+       mhu->mbox.txdone_irq = false;
+       mhu->mbox.txdone_poll = true;
+       mhu->mbox.txpoll_period = 1;
+       mhu->drvdata = mdata;
+
+       amba_set_drvdata(adev, mhu);
+
+       err = mbox_controller_register(&mhu->mbox);
+       if (err) {
+               dev_err(dev, "failed to register mailboxes %d\n", err);
+               iounmap(tx_base);
+               return err;
+       }
+
+       dev_info(dev, "ARM MHUv2 Mailbox registered\n");
+       return 0;
+}
+
+static int mhuv2_remove(struct amba_device *adev)
+{
+       struct arm_mhuv2 *mhu = amba_get_drvdata(adev);
+
+       mbox_controller_unregister(&mhu->mbox);
+
+       return 0;
+}
+
+static struct mhuv2_data arm_mhuv2_data = {
+       .regs = { MHU_V2_REG_STAT_OFS, MHU_V2_REG_SET_OFS, MHU_V2_REG_CLR_OFS },
+       .chans = { MHU_V2_LP_OFFSET, MHU_V2_HP_OFFSET },
+       .acc_regs = { MHU_V2_REG_MSG_NO_CAP_OFS, MHU_V2_REG_ACC_REQ_OFS,
+               MHU_V2_REG_ACC_RDY_OFS },
+};
+
+static struct amba_id mhuv2_ids[] = {
+       {
+               .id     = 0x4b0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       {
+               .id     = 0xbb0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       { 0, 0 },
+};
+MODULE_DEVICE_TABLE(amba, mhuv2_ids);
+
+static struct amba_driver arm_mhuv2_driver = {
+       .drv = {
+               .name   = "mhuv2",
+       },
+       .id_table       = mhuv2_ids,
+       .probe          = mhuv2_probe,
+       .remove         = mhuv2_remove,
+};
+module_amba_driver(arm_mhuv2_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ARM MHUv2 Driver");
+MODULE_AUTHOR("Samarth Parikh <samarthp@ymail.com>");
--
2.7.4

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* [PATCH] mailbox: arm_mhu: add support for mhuv2
@ 2018-04-16  5:20 Samarth Parikh
  0 siblings, 0 replies; 5+ messages in thread
From: Samarth Parikh @ 2018-04-16  5:20 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: linux-kernel, Sudipto.Paul, Arvind.Chauhan, samarthp,
	Sudeep.Holla, Samarth Parikh

ARM has launched a next version of MHU i.e. MHUv2 with its latest
subsystems. The main change is that the MHUv2 is now a distributed IP
with different peripheral views (registers) for the sender and receiver.

Another main difference is that MHUv1 duplex channels are now split into
simplex/half duplex in MHUv2. MHUv2 has a configurable number of
communication channels. There is a capability register (MSG_NO_CAP) to
find out how many channels are available in a system.

The register offsets have also changed for STAT, SET & CLEAR registers
from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.

0x0    0x4  0x8  0xC             0x1F
------------------------....-----
| STAT |    |    | SET |    |   |
------------------------....-----
      Transmit Channel

0x0    0x4  0x8   0xC            0x1F
------------------------....-----
| STAT |    | CLR |    |    |   |
------------------------....-----
        Receive Channel

The MHU controller can request the receiver to wake-up and once the
request is removed, the receiver may go back to sleep, but the MHU
itself does not actively puts a receiver to sleep.

So, in order to wake-up the receiver when the sender wants to send data,
the sender has to set ACCESS_REQUEST register first in order to wake-up
receiver, state of which can be detected using ACCESS_READY register.
ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
of 0xF8C and are accessible only on any sender channel.

This patch adds necessary changes required to support the older
version of MHU & the latest MHUv2 controller. This patch also need an
update in DT binding for ARM MHU as we need a second register base
(tx base) which would be used as the send channel base.

Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
---
 drivers/mailbox/arm_mhu.c | 163 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 151 insertions(+), 12 deletions(-)

diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c
index 99befa7..d8825c5 100644
--- a/drivers/mailbox/arm_mhu.c
+++ b/drivers/mailbox/arm_mhu.c
@@ -23,6 +23,8 @@
 #include <linux/module.h>
 #include <linux/amba/bus.h>
 #include <linux/mailbox_controller.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>

 #define INTR_STAT_OFS  0x0
 #define INTR_SET_OFS   0x8
@@ -33,12 +35,69 @@
 #define MHU_SEC_OFFSET 0x200
 #define TX_REG_OFFSET  0x100

+#define MHU_V2_REG_STAT_OFS    0x0
+#define MHU_V2_REG_CLR_OFS     0x8
+#define MHU_V2_REG_SET_OFS     0xC
+#define MHU_V2_REG_MSG_NO_CAP  0xF80
+#define MHU_V2_REG_ACC_REQ_OFS 0xF88
+#define MHU_V2_REG_ACC_RDY_OFS 0xF8C
+
+#define MHU_V2_LP_OFFSET  0x20
+#define MHU_V2_HP_OFFSET  0x0
+
 #define MHU_CHANS      3

+enum mhu_ver {
+       MHU_V1 = 1,
+       MHU_V2,
+       MHU_VER_END
+};
+
+enum mhu_regs {
+       MHU_REG_STAT,
+       MHU_REG_SET,
+       MHU_REG_CLR,
+       MHU_REG_END
+};
+
+enum mhu_access_regs {
+       MHU_REG_MSG_NO_CAP,
+       MHU_REG_ACC_REQ,
+       MHU_REG_ACC_RDY,
+       MHU_REG_ACC_END
+};
+
+enum mhu_channels {
+       MHU_CHAN_LOW,
+       MHU_CHAN_HIGH,
+       MHU_CHAN_SEC,
+       MHU_CHAN_END
+};
+
+/**
+ * ARM MHU Mailbox device specific data
+ *
+ * @regs: MHU version specific array of register offset for STAT,
+ *        SET & CLEAR registers.
+ * @chans: MHU version specific array of channel offset for Low
+ *         Priority, High Priority & Secure channels.
+ * @acc_regs: An array of access register offsets.
+ * @tx_reg_off: Offset for TX register.
+ * @version: Version of MHU controller available in the system.
+ */
+struct mhu_data {
+       int regs[MHU_REG_END]; /* STAT, SET, CLEAR */
+       int chans[MHU_CHAN_END]; /* LP, HP, Sec */
+       int acc_regs[MHU_REG_ACC_END];
+       long int tx_reg_off;
+       uint8_t version;
+};
+
 struct mhu_link {
        unsigned irq;
        void __iomem *tx_reg;
        void __iomem *rx_reg;
+       unsigned int pchan;
 };

 struct arm_mhu {
@@ -46,21 +105,24 @@ struct arm_mhu {
        struct mhu_link mlink[MHU_CHANS];
        struct mbox_chan chan[MHU_CHANS];
        struct mbox_controller mbox;
+       struct mhu_data *drvdata;
 };

 static irqreturn_t mhu_rx_interrupt(int irq, void *p)
 {
        struct mbox_chan *chan = p;
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 val;

-       val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
+       val = readl_relaxed(mlink->rx_reg + mdata->regs[MHU_REG_STAT]);
        if (!val)
                return IRQ_NONE;

        mbox_chan_received_data(chan, (void *)&val);

-       writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
+       writel_relaxed(val, mlink->rx_reg + mdata->regs[MHU_REG_CLR]);

        return IRQ_HANDLED;
 }
@@ -68,7 +130,9 @@ static irqreturn_t mhu_rx_interrupt(int irq, void *p)
 static bool mhu_last_tx_done(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
-       u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
+       u32 val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_REG_STAT]);

        return (val == 0);
 }
@@ -76,9 +140,11 @@ static bool mhu_last_tx_done(struct mbox_chan *chan)
 static int mhu_send_data(struct mbox_chan *chan, void *data)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 *arg = data;

-       writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
+       writel_relaxed(*arg, mlink->tx_reg + mdata->regs[MHU_REG_SET]);

        return 0;
 }
@@ -86,11 +152,18 @@ static int mhu_send_data(struct mbox_chan *chan, void *data)
 static int mhu_startup(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
        u32 val;
        int ret;

-       val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
-       writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
+       if (mdata->version == MHU_V2)
+               writel_relaxed(0x1, mlink->tx_reg
+                       + (mdata->acc_regs[MHU_REG_ACC_REQ]
+                       - (mdata->chans[mlink->pchan])));
+
+       val = readl_relaxed(mlink->tx_reg + mdata->regs[MHU_REG_STAT]);
+       writel_relaxed(val, mlink->tx_reg + mdata->regs[MHU_REG_CLR]);

        ret = request_irq(mlink->irq, mhu_rx_interrupt,
                          IRQF_SHARED, "mhu_link", chan);
@@ -106,6 +179,13 @@ static int mhu_startup(struct mbox_chan *chan)
 static void mhu_shutdown(struct mbox_chan *chan)
 {
        struct mhu_link *mlink = chan->con_priv;
+       struct arm_mhu *mhu = container_of(chan->mbox, struct arm_mhu, mbox);
+       struct mhu_data *mdata = mhu->drvdata;
+
+       if (mdata->version == MHU_V2)
+               writel_relaxed(0x0, mlink->tx_reg
+                       + (mdata->acc_regs[MHU_REG_ACC_REQ]
+                       - (mdata->chans[mlink->pchan])));

        free_irq(mlink->irq, chan);
 }
@@ -122,7 +202,15 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id)
        int i, err;
        struct arm_mhu *mhu;
        struct device *dev = &adev->dev;
-       int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET};
+       void __iomem *tx_base;
+       struct device_node *np = dev->of_node;
+       struct mhu_data *mdata = id->data;
+       unsigned int pchans = MHU_CHANS;
+
+       if (!mdata) {
+               dev_err(dev, "device data not found\n");
+               return -EINVAL;
+       }

        /* Allocate memory for device */
        mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
@@ -135,20 +223,45 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id)
                return PTR_ERR(mhu->base);
        }

-       for (i = 0; i < MHU_CHANS; i++) {
+       if (mdata->version == MHU_V2) {
+               tx_base = of_iomap(np, 1);
+               if (!tx_base) {
+                       dev_err(dev, "failed to map tx registers\n");
+                       return -ENOMEM;
+               }
+
+               mdata->tx_reg_off = tx_base - mhu->base;
+               pchans = readl_relaxed(tx_base
+                               + mdata->acc_regs[MHU_REG_MSG_NO_CAP]);
+               if (pchans == 0 || pchans > MHU_CHANS) {
+                       dev_err(dev, "invalid number of channels\n");
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < pchans; i++) {
                mhu->chan[i].con_priv = &mhu->mlink[i];
-               mhu->mlink[i].irq = adev->irq[i];
-               mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i];
-               mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
+               mhu->mlink[i].pchan = i;
+               int irq = mhu->mlink[i].irq = adev->irq[i];
+
+               if (irq <= 0) {
+                       dev_dbg(dev, "No IRQ found for Channel %d\n", i);
+                       continue;
+               }
+
+               mhu->mlink[i].rx_reg = mhu->base + mdata->chans[i];
+               mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg
+                       + mdata->tx_reg_off;
        }

        mhu->mbox.dev = dev;
        mhu->mbox.chans = &mhu->chan[0];
-       mhu->mbox.num_chans = MHU_CHANS;
+       mhu->mbox.num_chans = pchans;
        mhu->mbox.ops = &mhu_ops;
        mhu->mbox.txdone_irq = false;
        mhu->mbox.txdone_poll = true;
        mhu->mbox.txpoll_period = 1;
+       mhu->drvdata = mdata;

        amba_set_drvdata(adev, mhu);

@@ -171,10 +284,36 @@ static int mhu_remove(struct amba_device *adev)
        return 0;
 }

+static struct mhu_data arm_mhuv2_data = {
+       .regs = { MHU_V2_REG_STAT_OFS, MHU_V2_REG_SET_OFS, MHU_V2_REG_CLR_OFS },
+       .chans = { MHU_V2_LP_OFFSET, MHU_V2_HP_OFFSET },
+       .acc_regs = { MHU_V2_REG_MSG_NO_CAP, MHU_V2_REG_ACC_REQ_OFS,
+               MHU_V2_REG_ACC_RDY_OFS },
+       .version = MHU_V2,
+};
+
+static struct mhu_data arm_mhuv1_data = {
+       .regs = { INTR_STAT_OFS, INTR_SET_OFS, INTR_CLR_OFS },
+       .chans = { MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET },
+       .tx_reg_off = TX_REG_OFFSET,
+       .version = MHU_V1,
+};
+
 static struct amba_id mhu_ids[] = {
        {
+               .id     = 0x4b0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       {
+               .id     = 0xbb0d1,
+               .mask   = 0xfffff,
+               .data   = (void *)&arm_mhuv2_data,
+       },
+       {
                .id     = 0x1bb098,
                .mask   = 0xffffff,
+               .data   = (void *)&arm_mhuv1_data,
        },
        { 0, 0 },
 };
--
2.7.4

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

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

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-02  7:14 [PATCH] mailbox: arm_mhu: add support for mhuv2 Samarth Parikh
2018-05-02 12:04 ` Jassi Brar
2018-05-14  8:07   ` Samarth Parikh
  -- strict thread matches above, loose matches on Subject: below --
2018-05-14  8:02 Samarth Parikh
2018-04-16  5:20 Samarth Parikh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).