diff mbox series

[v3,2/8] firmware: scmi: mailbox/smt agent device

Message ID 20200907145000.30587-2-etienne.carriere@linaro.org
State Superseded
Headers show
Series [v3,1/8] firmware: add SCMI agent uclass | expand

Commit Message

Etienne Carriere Sept. 7, 2020, 2:49 p.m. UTC
This change implements a mailbox transport using SMT format for SCMI
exchanges. This implementation follows the Linux kernel and
SCP-firmware [1] as references implementation for SCMI message
processing using SMT format for communication channel meta-data.

Use of mailboxes in SCMI FDT bindings are defined in the Linux kernel
DT bindings since v4.17.

Links: [1] https://github.com/ARM-software/SCP-firmware
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>

Cc: Simon Glass <sjg@chromium.org>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
---

Changes in v3:
- This is a followup of the SCMI agent patches posted in
  https://patchwork.ozlabs.org/project/uboot/list/?series=196253
  The v3 splits commits and introduces a new uclass as requested.
- This patch implements the same mailbox SCMI agent proposed in v2
  but split over few source files.
---
 drivers/firmware/scmi/Kconfig         |   6 +-
 drivers/firmware/scmi/Makefile        |   2 +
 drivers/firmware/scmi/mailbox_agent.c | 107 ++++++++++++++++++++
 drivers/firmware/scmi/smt.c           | 139 ++++++++++++++++++++++++++
 drivers/firmware/scmi/smt.h           |  86 ++++++++++++++++
 5 files changed, 338 insertions(+), 2 deletions(-)
 create mode 100644 drivers/firmware/scmi/mailbox_agent.c
 create mode 100644 drivers/firmware/scmi/smt.c
 create mode 100644 drivers/firmware/scmi/smt.h

-- 
2.17.1

Comments

Simon Glass Sept. 8, 2020, 3:20 p.m. UTC | #1
Hi Etienne,

On Mon, 7 Sep 2020 at 08:50, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>

> This change implements a mailbox transport using SMT format for SCMI

> exchanges. This implementation follows the Linux kernel and

> SCP-firmware [1] as references implementation for SCMI message

> processing using SMT format for communication channel meta-data.

>

> Use of mailboxes in SCMI FDT bindings are defined in the Linux kernel

> DT bindings since v4.17.

>

> Links: [1] https://github.com/ARM-software/SCP-firmware

> Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>

> Cc: Simon Glass <sjg@chromium.org>

> Cc: Peng Fan <peng.fan@nxp.com>

> Cc: Sudeep Holla <sudeep.holla@arm.com>

> ---

>

> Changes in v3:

> - This is a followup of the SCMI agent patches posted in

>   https://patchwork.ozlabs.org/project/uboot/list/?series=196253

>   The v3 splits commits and introduces a new uclass as requested.

> - This patch implements the same mailbox SCMI agent proposed in v2

>   but split over few source files.

> ---

>  drivers/firmware/scmi/Kconfig         |   6 +-

>  drivers/firmware/scmi/Makefile        |   2 +

>  drivers/firmware/scmi/mailbox_agent.c | 107 ++++++++++++++++++++

>  drivers/firmware/scmi/smt.c           | 139 ++++++++++++++++++++++++++

>  drivers/firmware/scmi/smt.h           |  86 ++++++++++++++++

>  5 files changed, 338 insertions(+), 2 deletions(-)

>  create mode 100644 drivers/firmware/scmi/mailbox_agent.c

>  create mode 100644 drivers/firmware/scmi/smt.c

>  create mode 100644 drivers/firmware/scmi/smt.h


Reviewed-by: Simon Glass <sjg@chromium.org>


>

> diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig

> index 57e2ebbe42..c501bf4943 100644

> --- a/drivers/firmware/scmi/Kconfig

> +++ b/drivers/firmware/scmi/Kconfig

> @@ -2,7 +2,7 @@ config SCMI_FIRMWARE

>         bool "Enable SCMI support"

>         select FIRMWARE

>         select OF_TRANSLATE

> -       depends on SANDBOX

> +       depends on SANDBOX || DM_MAILBOX

>         help

>           System Control and Management Interface (SCMI) is a communication

>           protocol that defines standard interfaces for power, performance

> @@ -14,4 +14,6 @@ config SCMI_FIRMWARE

>           or a companion host in the CPU system.

>

>           Communications between agent (client) and the SCMI server are

> -         based on message exchange.

> +         based on message exchange. Messages can be exchange over tranport

> +         channels as a mailbox device with some piece of identified shared

> +         memory.

> diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile

> index 336ea1f2a3..d22f53efe7 100644

> --- a/drivers/firmware/scmi/Makefile

> +++ b/drivers/firmware/scmi/Makefile

> @@ -1,2 +1,4 @@

>  obj-y  += scmi_agent-uclass.o

> +obj-y  += smt.o

> +obj-$(CONFIG_DM_MAILBOX)       += mailbox_agent.o

>  obj-$(CONFIG_SANDBOX)          += sandbox-scmi_agent.o

> diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c

> new file mode 100644

> index 0000000000..9a7b0a5858

> --- /dev/null

> +++ b/drivers/firmware/scmi/mailbox_agent.c

> @@ -0,0 +1,107 @@

> +// SPDX-License-Identifier: GPL-2.0+

> +/*

> + * Copyright (C) 2020 Linaro Limited.

> + */

> +

> +#include <common.h>

> +#include <dm.h>

> +#include <errno.h>

> +#include <mailbox.h>

> +#include <scmi_agent.h>

> +#include <scmi_agent-uclass.h>

> +#include <dm/devres.h>

> +#include <linux/compat.h>

> +

> +#include "smt.h"

> +

> +#define TIMEOUT_US_10MS                        10000

> +

> +/**

> + * struct scmi_mbox_channel - Description of an SCMI mailbox transport

> + * @smt:       Shared memory buffer

> + * @mbox:      Mailbox channel description

> + * @timeout_us:        Timeout in microseconds for the mailbox transfer

> + */

> +struct scmi_mbox_channel {

> +       struct scmi_smt smt;

> +       struct mbox_chan mbox;

> +       ulong timeout_us;

> +};

> +

> +static struct scmi_mbox_channel *scmi_mbox_get_priv(struct udevice *dev)

> +{

> +       return (struct scmi_mbox_channel *)dev_get_priv(dev);

> +}

> +

> +static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)

> +{

> +       struct scmi_mbox_channel *chan = scmi_mbox_get_priv(dev);

> +       int ret;

> +

> +       ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);

> +       if (ret)

> +               return ret;

> +

> +       /* Give shm addr to mbox in case it is meaningful */

> +       ret = mbox_send(&chan->mbox, chan->smt.buf);

> +       if (ret) {

> +               dev_err(dev, "Message send failed: %d\n", ret);

> +               goto out;

> +       }

> +

> +       /* Receive the response */

> +       ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);

> +       if (ret) {

> +               dev_err(dev, "Response failed: %d, abort\n", ret);

> +               goto out;

> +       }

> +

> +       ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);

> +

> +out:

> +       scmi_clear_smt_channel(&chan->smt);

> +

> +       return ret;

> +}

> +

> +int scmi_mbox_probe(struct udevice *dev)

> +{

> +       struct scmi_mbox_channel *chan = scmi_mbox_get_priv(dev);

> +       int ret;

> +

> +       chan->timeout_us = TIMEOUT_US_10MS;

> +

> +       ret = mbox_get_by_index(dev, 0, &chan->mbox);

> +       if (ret) {

> +               dev_err(dev, "Failed to find mailbox: %d\n", ret);

> +               goto out;

> +       }

> +

> +       ret = scmi_dt_get_smt_buffer(dev, &chan->smt);

> +       if (ret)

> +               dev_err(dev, "Failed to get shm resources: %d\n", ret);

> +

> +out:

> +       if (ret)

> +               devm_kfree(dev, chan);

> +

> +       return ret;

> +}

> +

> +static const struct udevice_id scmi_mbox_ids[] = {

> +       { .compatible = "arm,scmi" },

> +       { }

> +};

> +

> +static const struct scmi_agent_ops scmi_mbox_ops = {

> +       .process_msg = scmi_mbox_process_msg,

> +};

> +

> +U_BOOT_DRIVER(scmi_mbox) = {

> +       .name           = "scmi-over-mailbox",

> +       .id             = UCLASS_SCMI_AGENT,

> +       .of_match       = scmi_mbox_ids,

> +       .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel),

> +       .probe          = scmi_mbox_probe,

> +       .ops            = &scmi_mbox_ops,

> +};

> diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c

> new file mode 100644

> index 0000000000..afe95a4736

> --- /dev/null

> +++ b/drivers/firmware/scmi/smt.c

> @@ -0,0 +1,139 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.

> + * Copyright (C) 2019-2020 Linaro Limited.

> + */

> +

> +#include <common.h>

> +#include <cpu_func.h>

> +#include <dm.h>

> +#include <errno.h>

> +#include <scmi_agent.h>

> +#include <asm/cache.h>

> +#include <asm/system.h>

> +#include <dm/ofnode.h>

> +#include <linux/compat.h>

> +#include <linux/io.h>

> +#include <linux/ioport.h>

> +

> +#include "smt.h"

> +

> +/**

> + * Get shared memory configuration defined by the referred DT phandle

> + * Return with a errno compliant value.

> + */

> +int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)

> +{

> +       int ret;

> +       struct ofnode_phandle_args args;

> +       struct resource resource;

> +       fdt32_t faddr;

> +       phys_addr_t paddr;

> +

> +       ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);

> +       if (ret)

> +               return ret;

> +

> +       ret = ofnode_read_resource(args.node, 0, &resource);

> +       if (ret)

> +               return ret;

> +

> +       faddr = cpu_to_fdt32(resource.start);

> +       paddr = ofnode_translate_address(args.node, &faddr);

> +

> +       smt->size = resource_size(&resource);

> +       if (smt->size < sizeof(struct scmi_smt_header)) {

> +               dev_err(dev, "Shared memory buffer too small\n");

> +               return -EINVAL;

> +       }

> +

> +       smt->buf = devm_ioremap(dev, paddr, smt->size);

> +       if (!smt->buf)

> +               return -ENOMEM;

> +

> +#ifdef __arm__


Should that be CONFIG_ARM ?

> +       if (dcache_status())

> +               mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,

> +                                               smt->size, DCACHE_OFF);

> +#endif

> +

> +       return 0;

> +}

> +

[..]

Regards,
Simon
Etienne Carriere Sept. 9, 2020, 9:33 a.m. UTC | #2
On Tue, 8 Sep 2020 at 17:21, Simon Glass <sjg@chromium.org> wrote:
>

> Hi Etienne,

>

> On Mon, 7 Sep 2020 at 08:50, Etienne Carriere

> <etienne.carriere@linaro.org> wrote:

> >

> > This change implements a mailbox transport using SMT format for SCMI

> > exchanges. This implementation follows the Linux kernel and

> > SCP-firmware [1] as references implementation for SCMI message

> > processing using SMT format for communication channel meta-data.

> >

> > Use of mailboxes in SCMI FDT bindings are defined in the Linux kernel

> > DT bindings since v4.17.

> >

> > Links: [1] https://github.com/ARM-software/SCP-firmware

> > Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>

> > Cc: Simon Glass <sjg@chromium.org>

> > Cc: Peng Fan <peng.fan@nxp.com>

> > Cc: Sudeep Holla <sudeep.holla@arm.com>

> > ---

> >

> > Changes in v3:

> > - This is a followup of the SCMI agent patches posted in

> >   https://patchwork.ozlabs.org/project/uboot/list/?series=196253

> >   The v3 splits commits and introduces a new uclass as requested.

> > - This patch implements the same mailbox SCMI agent proposed in v2

> >   but split over few source files.

> > ---

> >  drivers/firmware/scmi/Kconfig         |   6 +-

> >  drivers/firmware/scmi/Makefile        |   2 +

> >  drivers/firmware/scmi/mailbox_agent.c | 107 ++++++++++++++++++++

> >  drivers/firmware/scmi/smt.c           | 139 ++++++++++++++++++++++++++

> >  drivers/firmware/scmi/smt.h           |  86 ++++++++++++++++

> >  5 files changed, 338 insertions(+), 2 deletions(-)

> >  create mode 100644 drivers/firmware/scmi/mailbox_agent.c

> >  create mode 100644 drivers/firmware/scmi/smt.c

> >  create mode 100644 drivers/firmware/scmi/smt.h

>

> Reviewed-by: Simon Glass <sjg@chromium.org>



Thanks for the reviews.


> > diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c

> > new file mode 100644

> > index 0000000000..afe95a4736

> > --- /dev/null

> > +++ b/drivers/firmware/scmi/smt.c

> > @@ -0,0 +1,139 @@

> > +// SPDX-License-Identifier: GPL-2.0

> > +/*

> > + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.

> > + * Copyright (C) 2019-2020 Linaro Limited.

> > + */

> > +

> > +#include <common.h>

> > +#include <cpu_func.h>

> > +#include <dm.h>

> > +#include <errno.h>

> > +#include <scmi_agent.h>

> > +#include <asm/cache.h>

> > +#include <asm/system.h>

> > +#include <dm/ofnode.h>

> > +#include <linux/compat.h>

> > +#include <linux/io.h>

> > +#include <linux/ioport.h>

> > +

> > +#include "smt.h"

> > +

> > +/**

> > + * Get shared memory configuration defined by the referred DT phandle

> > + * Return with a errno compliant value.

> > + */

> > +int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)

> > +{

> > +       int ret;

> > +       struct ofnode_phandle_args args;

> > +       struct resource resource;

> > +       fdt32_t faddr;

> > +       phys_addr_t paddr;

> > +

> > +       ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);

> > +       if (ret)

> > +               return ret;

> > +

> > +       ret = ofnode_read_resource(args.node, 0, &resource);

> > +       if (ret)

> > +               return ret;

> > +

> > +       faddr = cpu_to_fdt32(resource.start);

> > +       paddr = ofnode_translate_address(args.node, &faddr);

> > +

> > +       smt->size = resource_size(&resource);

> > +       if (smt->size < sizeof(struct scmi_smt_header)) {

> > +               dev_err(dev, "Shared memory buffer too small\n");

> > +               return -EINVAL;

> > +       }

> > +

> > +       smt->buf = devm_ioremap(dev, paddr, smt->size);

> > +       if (!smt->buf)

> > +               return -ENOMEM;

> > +

> > +#ifdef __arm__

>

> Should that be CONFIG_ARM ?


Would covers CONFIG_ARM and CONFIG_ARM64, so OK. I'll send a patch v4.

etienne

>

> > +       if (dcache_status())

> > +               mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,

> > +                                               smt->size, DCACHE_OFF);

> > +#endif

> > +

> > +       return 0;

> > +}

> > +

> [..]

>

> Regards,

> Simon
diff mbox series

Patch

diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
index 57e2ebbe42..c501bf4943 100644
--- a/drivers/firmware/scmi/Kconfig
+++ b/drivers/firmware/scmi/Kconfig
@@ -2,7 +2,7 @@  config SCMI_FIRMWARE
 	bool "Enable SCMI support"
 	select FIRMWARE
 	select OF_TRANSLATE
-	depends on SANDBOX
+	depends on SANDBOX || DM_MAILBOX
 	help
 	  System Control and Management Interface (SCMI) is a communication
 	  protocol that defines standard interfaces for power, performance
@@ -14,4 +14,6 @@  config SCMI_FIRMWARE
 	  or a companion host in the CPU system.
 
 	  Communications between agent (client) and the SCMI server are
-	  based on message exchange.
+	  based on message exchange. Messages can be exchange over tranport
+	  channels as a mailbox device with some piece of identified shared
+	  memory.
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index 336ea1f2a3..d22f53efe7 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -1,2 +1,4 @@ 
 obj-y	+= scmi_agent-uclass.o
+obj-y	+= smt.o
+obj-$(CONFIG_DM_MAILBOX)	+= mailbox_agent.o
 obj-$(CONFIG_SANDBOX)		+= sandbox-scmi_agent.o
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
new file mode 100644
index 0000000000..9a7b0a5858
--- /dev/null
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -0,0 +1,107 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mailbox.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <dm/devres.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define TIMEOUT_US_10MS			10000
+
+/**
+ * struct scmi_mbox_channel - Description of an SCMI mailbox transport
+ * @smt:	Shared memory buffer
+ * @mbox:	Mailbox channel description
+ * @timeout_us:	Timeout in microseconds for the mailbox transfer
+ */
+struct scmi_mbox_channel {
+	struct scmi_smt smt;
+	struct mbox_chan mbox;
+	ulong timeout_us;
+};
+
+static struct scmi_mbox_channel *scmi_mbox_get_priv(struct udevice *dev)
+{
+	return (struct scmi_mbox_channel *)dev_get_priv(dev);
+}
+
+static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+	struct scmi_mbox_channel *chan = scmi_mbox_get_priv(dev);
+	int ret;
+
+	ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
+	if (ret)
+		return ret;
+
+	/* Give shm addr to mbox in case it is meaningful */
+	ret = mbox_send(&chan->mbox, chan->smt.buf);
+	if (ret) {
+		dev_err(dev, "Message send failed: %d\n", ret);
+		goto out;
+	}
+
+	/* Receive the response */
+	ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);
+	if (ret) {
+		dev_err(dev, "Response failed: %d, abort\n", ret);
+		goto out;
+	}
+
+	ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+
+out:
+	scmi_clear_smt_channel(&chan->smt);
+
+	return ret;
+}
+
+int scmi_mbox_probe(struct udevice *dev)
+{
+	struct scmi_mbox_channel *chan = scmi_mbox_get_priv(dev);
+	int ret;
+
+	chan->timeout_us = TIMEOUT_US_10MS;
+
+	ret = mbox_get_by_index(dev, 0, &chan->mbox);
+	if (ret) {
+		dev_err(dev, "Failed to find mailbox: %d\n", ret);
+		goto out;
+	}
+
+	ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+	if (ret)
+		dev_err(dev, "Failed to get shm resources: %d\n", ret);
+
+out:
+	if (ret)
+		devm_kfree(dev, chan);
+
+	return ret;
+}
+
+static const struct udevice_id scmi_mbox_ids[] = {
+	{ .compatible = "arm,scmi" },
+	{ }
+};
+
+static const struct scmi_agent_ops scmi_mbox_ops = {
+	.process_msg = scmi_mbox_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_mbox) = {
+	.name		= "scmi-over-mailbox",
+	.id		= UCLASS_SCMI_AGENT,
+	.of_match	= scmi_mbox_ids,
+	.priv_auto_alloc_size = sizeof(struct scmi_mbox_channel),
+	.probe		= scmi_mbox_probe,
+	.ops		= &scmi_mbox_ops,
+};
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
new file mode 100644
index 0000000000..afe95a4736
--- /dev/null
+++ b/drivers/firmware/scmi/smt.c
@@ -0,0 +1,139 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <asm/cache.h>
+#include <asm/system.h>
+#include <dm/ofnode.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include "smt.h"
+
+/**
+ * Get shared memory configuration defined by the referred DT phandle
+ * Return with a errno compliant value.
+ */
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
+{
+	int ret;
+	struct ofnode_phandle_args args;
+	struct resource resource;
+	fdt32_t faddr;
+	phys_addr_t paddr;
+
+	ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
+	if (ret)
+		return ret;
+
+	ret = ofnode_read_resource(args.node, 0, &resource);
+	if (ret)
+		return ret;
+
+	faddr = cpu_to_fdt32(resource.start);
+	paddr = ofnode_translate_address(args.node, &faddr);
+
+	smt->size = resource_size(&resource);
+	if (smt->size < sizeof(struct scmi_smt_header)) {
+		dev_err(dev, "Shared memory buffer too small\n");
+		return -EINVAL;
+	}
+
+	smt->buf = devm_ioremap(dev, paddr, smt->size);
+	if (!smt->buf)
+		return -ENOMEM;
+
+#ifdef __arm__
+	if (dcache_status())
+		mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
+						smt->size, DCACHE_OFF);
+#endif
+
+	return 0;
+}
+
+/**
+ * Write SCMI message @msg into a SMT shared buffer @smt.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+			  struct scmi_msg *msg)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	if ((!msg->in_msg && msg->in_msg_sz) ||
+	    (!msg->out_msg && msg->out_msg_sz))
+		return -EINVAL;
+
+	if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+		dev_dbg(dev, "Channel busy\n");
+		return -EBUSY;
+	}
+
+	if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
+	    smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
+		dev_dbg(dev, "Buffer too small\n");
+		return -ETOOSMALL;
+	}
+
+	/* Load message in shared memory */
+	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+	hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
+	hdr->msg_header = SMT_HEADER_TOKEN(0) |
+			  SMT_HEADER_MESSAGE_TYPE(0) |
+			  SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
+			  SMT_HEADER_MESSAGE_ID(msg->message_id);
+
+	memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
+
+	return 0;
+}
+
+/**
+ * Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+			    struct scmi_msg *msg)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+		dev_err(dev, "Channel unexpectedly busy\n");
+		return -EBUSY;
+	}
+
+	if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
+		dev_err(dev, "Channel error reported, reset channel\n");
+		return -ECOMM;
+	}
+
+	if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
+		dev_err(dev, "Buffer to small\n");
+		return -ETOOSMALL;
+	}
+
+	/* Get the data */
+	msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header);
+	memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
+
+	return 0;
+}
+
+/**
+ * Clear SMT flags in shared buffer to allow further message exchange
+ */
+void scmi_clear_smt_channel(struct scmi_smt *smt)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
diff --git a/drivers/firmware/scmi/smt.h b/drivers/firmware/scmi/smt.h
new file mode 100644
index 0000000000..a8c0987bd3
--- /dev/null
+++ b/drivers/firmware/scmi/smt.h
@@ -0,0 +1,86 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+#ifndef SCMI_SMT_H
+#define SCMI_SMT_H
+
+#include <asm/types.h>
+
+/**
+ * struct scmi_smt_header - Description of the shared memory message buffer
+ *
+ * SMT stands for Shared Memory based Transport.
+ * SMT uses 28 byte header prior message payload to handle the state of
+ * the communication channel realized by the shared memory area and
+ * to define SCMI protocol information the payload relates to.
+ */
+struct scmi_smt_header {
+	__le32 reserved;
+	__le32 channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR	BIT(1)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE	BIT(0)
+	__le32 reserved1[2];
+	__le32 flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED		BIT(0)
+	__le32 length;
+	__le32 msg_header;
+	u8 msg_payload[0];
+};
+
+#define SMT_HEADER_TOKEN(token)		(((token) << 18) & GENMASK(31, 18))
+#define SMT_HEADER_PROTOCOL_ID(proto)	(((proto) << 10) & GENMASK(17, 10))
+#define SMT_HEADER_MESSAGE_TYPE(type)	(((type) << 18) & GENMASK(9, 8))
+#define SMT_HEADER_MESSAGE_ID(id)	((id) & GENMASK(7, 0))
+
+/**
+ * struct scmi_smt - Description of a SMT memory buffer
+ * @buf:	Shared memory base address
+ * @size:	Shared memory byte size
+ */
+struct scmi_smt {
+	u8 *buf;
+	size_t size;
+};
+
+static inline bool scmi_smt_channel_is_free(struct scmi_smt *smt)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline bool scmi_smt_channel_reports_error(struct scmi_smt *smt)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+static inline void scmi_smt_get_channel(struct scmi_smt *smt)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline void scmi_smt_put_channel(struct scmi_smt *smt)
+{
+	struct scmi_smt_header *hdr = (void *)smt->buf;
+
+	hdr->channel_status |= SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+	hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt);
+
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+			  struct scmi_msg *msg);
+
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+			    struct scmi_msg *msg);
+
+void scmi_clear_smt_channel(struct scmi_smt *smt);
+
+#endif /* SCMI_SMT_H */