diff mbox series

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

Message ID 20200907145000.30587-2-etienne.carriere@linaro.org
State Superseded
Delegated to: Tom Rini
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

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 */