Merge tag 'dm-pull-13oct23' of https://source.denx.de/u-boot/custodians/u-boot-dm

improvements with dev_read_addr_..._ptr()
scan all entries in multi-device boot_targets
EFI empty-capsule support
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 6abce9e..c0ed2d8 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -732,13 +732,10 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			protocol@10 {
-				reg = <0x10>;
-			};
-
 			clk_scmi: protocol@14 {
 				reg = <0x14>;
 				#clock-cells = <1>;
+				linaro,sandbox-channel-id = <0x14>;
 			};
 
 			reset_scmi: protocol@16 {
diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h
index c72ec1e..ccb0df6 100644
--- a/arch/sandbox/include/asm/scmi_test.h
+++ b/arch/sandbox/include/asm/scmi_test.h
@@ -89,10 +89,20 @@
 
 #ifdef CONFIG_SCMI_FIRMWARE
 /**
+ * sandbox_scmi_channel_id - Get the channel id
+ * @dev:	Reference to the SCMI protocol device
+ *
+ * Return:	Channel id
+ */
+unsigned int sandbox_scmi_channel_id(struct udevice *dev);
+
+/**
  * sandbox_scmi_service_ctx - Get the simulated SCMI services context
+ * sandbox_scmi_agent_ctx - Get the simulated SCMI agent context
+ * @dev:	Reference to the test agent
  * @return:	Reference to backend simulated resources state
  */
-struct sandbox_scmi_service *sandbox_scmi_service_ctx(void);
+struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev);
 
 /**
  * sandbox_scmi_devices_ctx - Get references to devices accessed through SCMI
@@ -101,7 +111,12 @@
  */
 struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev);
 #else
-static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+inline unsigned int sandbox_scmi_channel_id(struct udevice *dev);
+{
+	return 0;
+}
+
+static struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
 {
 	return NULL;
 }
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index d172fed..34a4936 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -13,17 +13,8 @@
 #include <asm/types.h>
 #include <linux/clk-provider.h>
 
-/**
- * struct scmi_clk_priv - Private data for SCMI clocks
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_clk_priv {
-	struct scmi_channel *channel;
-};
-
 static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(dev);
 	struct scmi_clk_protocol_attr_out out;
 	struct scmi_msg msg = {
 		.protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@@ -33,7 +24,7 @@
 	};
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret)
 		return ret;
 
@@ -44,7 +35,6 @@
 
 static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(dev);
 	struct scmi_clk_attribute_in in = {
 		.clock_id = clkid,
 	};
@@ -59,7 +49,7 @@
 	};
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret)
 		return ret;
 
@@ -70,7 +60,6 @@
 
 static int scmi_clk_gate(struct clk *clk, int enable)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
 	struct scmi_clk_state_in in = {
 		.clock_id = clk->id,
 		.attributes = enable,
@@ -81,7 +70,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(clk->dev, &msg);
 	if (ret)
 		return ret;
 
@@ -100,7 +89,6 @@
 
 static ulong scmi_clk_get_rate(struct clk *clk)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
 	struct scmi_clk_rate_get_in in = {
 		.clock_id = clk->id,
 	};
@@ -110,7 +98,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(clk->dev, &msg);
 	if (ret < 0)
 		return ret;
 
@@ -123,7 +111,6 @@
 
 static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
 	struct scmi_clk_rate_set_in in = {
 		.clock_id = clk->id,
 		.flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@@ -136,7 +123,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(clk->dev, &msg);
 	if (ret < 0)
 		return ret;
 
@@ -149,12 +136,11 @@
 
 static int scmi_clk_probe(struct udevice *dev)
 {
-	struct scmi_clk_priv *priv = dev_get_priv(dev);
 	struct clk *clk;
 	size_t num_clocks, i;
 	int ret;
 
-	ret = devm_scmi_of_get_channel(dev, &priv->channel);
+	ret = devm_scmi_of_get_channel(dev);
 	if (ret)
 		return ret;
 
@@ -205,5 +191,4 @@
 	.id = UCLASS_CLK,
 	.ops = &scmi_clk_ops,
 	.probe = scmi_clk_probe,
-	.priv_auto = sizeof(struct scmi_clk_priv *),
 };
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index b2ff483..1a23d49 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -1,4 +1,5 @@
 obj-y	+= scmi_agent-uclass.o
+obj-y	+= base.o
 obj-y	+= smt.o
 obj-$(CONFIG_SCMI_AGENT_SMCCC)		+= smccc_agent.o
 obj-$(CONFIG_SCMI_AGENT_MAILBOX)	+= mailbox_agent.o
diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c
new file mode 100644
index 0000000..1d41a8a
--- /dev/null
+++ b/drivers/firmware/scmi/base.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SCMI Base protocol as U-Boot device
+ *
+ * Copyright (C) 2023 Linaro Limited
+ *		author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <stdlib.h>
+#include <string.h>
+#include <asm/types.h>
+#include <dm/device_compat.h>
+#include <linux/kernel.h>
+
+/**
+ * scmi_generic_protocol_version - get protocol version
+ * @dev:	SCMI device
+ * @id:		SCMI protocol ID
+ * @version:	Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_generic_protocol_version(struct udevice *dev,
+				  enum scmi_std_protocol id, u32 *version)
+{
+	struct scmi_protocol_version_out out;
+	struct scmi_msg msg = {
+		.protocol_id = id,
+		.message_id = SCMI_PROTOCOL_VERSION,
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*version = out.version;
+
+	return 0;
+}
+
+/**
+ * scmi_base_protocol_version_int - get Base protocol version
+ * @dev:	SCMI device
+ * @version:	Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version for Base protocol.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version)
+{
+	return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
+					     version);
+}
+
+/**
+ * scmi_protocol_attrs_int - get protocol attributes
+ * @dev:		SCMI device
+ * @num_agents:		Number of SCMI agents
+ * @num_protocols:	Number of SCMI protocols
+ *
+ * Obtain the protocol attributes, the number of agents and the number
+ * of protocols, in @num_agents and @num_protocols respectively, that
+ * the device provides.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
+				   u32 *num_protocols)
+{
+	struct scmi_protocol_attrs_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_PROTOCOL_ATTRIBUTES,
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
+	*num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
+
+	return 0;
+}
+
+/**
+ * scmi_protocol_message_attrs_int - get message-specific attributes
+ * @dev:		SCMI device
+ * @message_id:		SCMI message ID
+ * @attributes:		Message-specific attributes
+ *
+ * Obtain the message-specific attributes in @attributes.
+ * This command succeeds if the message is implemented and available.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
+					   u32 *attributes)
+{
+	struct scmi_protocol_msg_attrs_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
+		.in_msg = (u8 *)&message_id,
+		.in_msg_sz = sizeof(message_id),
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*attributes = out.attributes;
+
+	return 0;
+}
+
+/**
+ * scmi_base_discover_vendor_int - get vendor name
+ * @dev:	SCMI device
+ * @vendor:	Pointer to vendor name
+ *
+ * Obtain the vendor's name in @vendor.
+ * It is a caller's responsibility to free @vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_vendor_int(struct udevice *dev, u8 **vendor)
+{
+	struct scmi_base_discover_vendor_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_DISCOVER_VENDOR,
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	if (!vendor)
+		return -EINVAL;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*vendor = strdup(out.vendor_identifier);
+	if (!*vendor)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * scmi_base_discover_sub_vendor_int - get sub-vendor name
+ * @dev:	SCMI device
+ * @sub_vendor:	Pointer to sub-vendor name
+ *
+ * Obtain the sub-vendor's name in @sub_vendor.
+ * It is a caller's responsibility to free @sub_vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
+					     u8 **sub_vendor)
+{
+	struct scmi_base_discover_vendor_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	if (!sub_vendor)
+		return -EINVAL;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*sub_vendor = strdup(out.vendor_identifier);
+	if (!*sub_vendor)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * scmi_base_discover_impl_version_int - get implementation version
+ * @dev:		SCMI device
+ * @impl_version:	Pointer to implementation version
+ *
+ * Obtain the implementation version number in @impl_version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_impl_version_int(struct udevice *dev,
+					       u32 *impl_version)
+{
+	struct scmi_base_discover_impl_version_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	*impl_version = out.impl_version;
+
+	return 0;
+}
+
+/**
+ * scmi_base_discover_list_protocols_int - get list of protocols
+ * @dev:	SCMI device
+ * @protocols:	Pointer to array of SCMI protocols
+ *
+ * Obtain the list of protocols provided in @protocols.
+ * The number of elements in @protocols always match to the number of
+ * protocols returned by smci_protocol_attrs() when this function succeeds.
+ * It is a caller's responsibility to free @protocols.
+ *
+ * Return: the number of protocols in @protocols on success, error code on
+ * failure
+ */
+static int scmi_base_discover_list_protocols_int(struct udevice *dev,
+						 u8 **protocols)
+{
+	struct scmi_base_discover_list_protocols_out out;
+	int cur;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
+		.in_msg = (u8 *)&cur,
+		.in_msg_sz = sizeof(cur),
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	u32 num_agents, num_protocols;
+	u8 *buf;
+	int i, ret;
+
+	ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
+	if (ret)
+		return ret;
+
+	buf = calloc(sizeof(u8), num_protocols);
+	if (!buf)
+		return -ENOMEM;
+
+	cur = 0;
+	do {
+		ret = devm_scmi_process_msg(dev, &msg);
+		if (ret)
+			goto err;
+		if (out.status) {
+			ret = scmi_to_linux_errno(out.status);
+			goto err;
+		}
+
+		for (i = 0; i < out.num_protocols; i++, cur++)
+			buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
+	} while (cur < num_protocols);
+
+	*protocols = buf;
+
+	return num_protocols;
+err:
+	free(buf);
+
+	return ret;
+}
+
+/**
+ * scmi_base_discover_agent_int - identify agent
+ * @dev:		SCMI device
+ * @agent_id:		SCMI agent ID
+ * @ret_agent_id:	Pointer to SCMI agent ID
+ * @name:		Pointer to SCMI agent name
+ *
+ * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
+ * this function returns the caller's agent id in @ret_agent_id.
+ * It is a caller's responsibility to free @name.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
+					u32 *ret_agent_id, u8 **name)
+{
+	struct scmi_base_discover_agent_out out;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_DISCOVER_AGENT,
+		.in_msg = (u8 *)&agent_id,
+		.in_msg_sz = sizeof(agent_id),
+		.out_msg = (u8 *)&out,
+		.out_msg_sz = sizeof(out),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (out.status)
+		return scmi_to_linux_errno(out.status);
+
+	if (ret_agent_id)
+		*ret_agent_id = out.agent_id;
+	if (name) {
+		*name = strdup(out.name);
+		if (!*name)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * scmi_base_set_device_permissions_int - configure access permission to device
+ * @dev:	SCMI device
+ * @agent_id:	SCMI agent ID
+ * @device_id:	ID of device to access
+ * @flags:	A set of flags
+ *
+ * Ask for allowing or denying access permission to the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
+						u32 device_id, u32 flags)
+{
+	struct scmi_base_set_device_permissions_in in = {
+		.agent_id = agent_id,
+		.device_id = device_id,
+		.flags = flags,
+	};
+	s32 status;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
+		.in_msg = (u8 *)&in,
+		.in_msg_sz = sizeof(in),
+		.out_msg = (u8 *)&status,
+		.out_msg_sz = sizeof(status),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (status)
+		return scmi_to_linux_errno(status);
+
+	return 0;
+}
+
+/**
+ * scmi_base_set_protocol_permissions_int - configure access permission to
+ *					    protocol on device
+ * @dev:	SCMI device
+ * @agent_id:	SCMI agent ID
+ * @device_id:	ID of device to access
+ * @command_id:	SCMI command ID
+ * @flags:	A set of flags
+ *
+ * Ask for allowing or denying access permission to the protocol, @command_id,
+ * on the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
+						  u32 agent_id, u32 device_id,
+						  u32 command_id, u32 flags)
+{
+	struct scmi_base_set_protocol_permissions_in in = {
+		.agent_id = agent_id,
+		.device_id = device_id,
+		.command_id = command_id,
+		.flags = flags,
+	};
+	s32 status;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
+		.in_msg = (u8 *)&in,
+		.in_msg_sz = sizeof(in),
+		.out_msg = (u8 *)&status,
+		.out_msg_sz = sizeof(status),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (status)
+		return scmi_to_linux_errno(status);
+
+	return 0;
+}
+
+/**
+ * scmi_base_reset_agent_configuration_int - reset resource settings
+ * @dev:	SCMI device
+ * @agent_id:	SCMI agent ID
+ * @flags:	A set of flags
+ *
+ * Reset all the resource settings against @agent_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
+						   u32 agent_id, u32 flags)
+{
+	struct scmi_base_reset_agent_configuration_in in = {
+		.agent_id = agent_id,
+		.flags = flags,
+	};
+	s32 status;
+	struct scmi_msg msg = {
+		.protocol_id = SCMI_PROTOCOL_ID_BASE,
+		.message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
+		.in_msg = (u8 *)&in,
+		.in_msg_sz = sizeof(in),
+		.out_msg = (u8 *)&status,
+		.out_msg_sz = sizeof(status),
+	};
+	int ret;
+
+	ret = devm_scmi_process_msg(dev, &msg);
+	if (ret)
+		return ret;
+	if (status)
+		return scmi_to_linux_errno(status);
+
+	return 0;
+}
+
+/**
+ * scmi_base_probe - probe base protocol device
+ * @dev:	SCMI device
+ *
+ * Probe the device for SCMI base protocol and initialize the private data.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_probe(struct udevice *dev)
+{
+	u32 version;
+	int ret;
+
+	ret = devm_scmi_of_get_channel(dev);
+	if (ret) {
+		dev_err(dev, "get_channel failed\n");
+		return ret;
+	}
+	ret = scmi_base_protocol_version_int(dev, &version);
+	if (ret) {
+		dev_err(dev, "getting protocol version failed\n");
+		return ret;
+	}
+	if (version < SCMI_BASE_PROTOCOL_VERSION)
+		return -EINVAL;
+
+	return ret;
+}
+
+static struct scmi_base_ops scmi_base_ops = {
+	/* Commands */
+	.protocol_version = scmi_base_protocol_version_int,
+	.protocol_attrs = scmi_protocol_attrs_int,
+	.protocol_message_attrs = scmi_protocol_message_attrs_int,
+	.base_discover_vendor = scmi_base_discover_vendor_int,
+	.base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
+	.base_discover_impl_version = scmi_base_discover_impl_version_int,
+	.base_discover_list_protocols = scmi_base_discover_list_protocols_int,
+	.base_discover_agent = scmi_base_discover_agent_int,
+	.base_notify_errors = NULL,
+	.base_set_device_permissions = scmi_base_set_device_permissions_int,
+	.base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
+	.base_reset_agent_configuration =
+			scmi_base_reset_agent_configuration_int,
+};
+
+int scmi_base_protocol_version(struct udevice *dev, u32 *version)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->protocol_version)
+		return (*ops->protocol_version)(dev, version);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
+			     u32 *num_protocols)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->protocol_attrs)
+		return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
+				     u32 *attributes)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->protocol_message_attrs)
+		return (*ops->protocol_message_attrs)(dev, message_id,
+						      attributes);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_discover_vendor)
+		return (*ops->base_discover_vendor)(dev, vendor);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_discover_sub_vendor)
+		return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_discover_impl_version)
+		return (*ops->base_discover_impl_version)(dev, impl_version);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_discover_list_protocols)
+		return (*ops->base_discover_list_protocols)(dev, protocols);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
+			     u32 *ret_agent_id, u8 **name)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_discover_agent)
+		return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
+						   name);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_notify_errors(struct udevice *dev, u32 enable)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_notify_errors)
+		return (*ops->base_notify_errors)(dev, enable);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
+				     u32 device_id, u32 flags)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_set_device_permissions)
+		return (*ops->base_set_device_permissions)(dev, agent_id,
+							   device_id, flags);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_set_protocol_permissions(struct udevice *dev,
+				       u32 agent_id, u32 device_id,
+				       u32 command_id, u32 flags)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_set_protocol_permissions)
+		return (*ops->base_set_protocol_permissions)(dev, agent_id,
+							     device_id,
+							     command_id,
+							     flags);
+
+	return -EOPNOTSUPP;
+}
+
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
+					u32 flags)
+{
+	const struct scmi_base_ops *ops = device_get_ops(dev);
+
+	if (ops->base_reset_agent_configuration)
+		return (*ops->base_reset_agent_configuration)(dev, agent_id,
+							      flags);
+
+	return -EOPNOTSUPP;
+}
+
+U_BOOT_DRIVER(scmi_base_drv) = {
+	.id = UCLASS_SCMI_BASE,
+	.name = "scmi_base_drv",
+	.ops = &scmi_base_ops,
+	.probe = scmi_base_probe,
+};
+
+UCLASS_DRIVER(scmi_base) = {
+	.id		= UCLASS_SCMI_BASE,
+	.name		= "scmi_base",
+};
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
index 8277c18..7ad3e8d 100644
--- a/drivers/firmware/scmi/mailbox_agent.c
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -94,13 +94,14 @@
 }
 
 static int scmi_mbox_get_channel(struct udevice *dev,
+				 struct udevice *protocol,
 				 struct scmi_channel **channel)
 {
 	struct scmi_mbox_channel *base_chan = dev_get_plat(dev);
 	struct scmi_mbox_channel *chan;
 	int ret;
 
-	if (!dev_read_prop(dev, "shmem", NULL)) {
+	if (!dev_read_prop(protocol, "shmem", NULL)) {
 		/* Uses agent base channel */
 		*channel = container_of(base_chan, struct scmi_channel, ref);
 
@@ -112,7 +113,7 @@
 		return -ENOMEM;
 
 	/* Setup a dedicated channel for the protocol */
-	ret = setup_channel(dev, chan);
+	ret = setup_channel(protocol, chan);
 	if (ret) {
 		free(chan);
 		return ret;
diff --git a/drivers/firmware/scmi/optee_agent.c b/drivers/firmware/scmi/optee_agent.c
index db927fb..48dbb88 100644
--- a/drivers/firmware/scmi/optee_agent.c
+++ b/drivers/firmware/scmi/optee_agent.c
@@ -149,7 +149,7 @@
 	struct tee_param param[1] = { };
 	int ret;
 
-	memset(sess, 0, sizeof(sess));
+	memset(sess, 0, sizeof(*sess));
 
 	sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
 	if (!sess->tee)
@@ -324,6 +324,7 @@
 }
 
 static int scmi_optee_get_channel(struct udevice *dev,
+				  struct udevice *protocol,
 				  struct scmi_channel **channel)
 {
 	struct scmi_optee_channel *base_chan = dev_get_plat(dev);
@@ -331,7 +332,7 @@
 	u32 channel_id;
 	int ret;
 
-	if (dev_read_u32(dev, "linaro,optee-channel-id", &channel_id)) {
+	if (dev_read_u32(protocol, "linaro,optee-channel-id", &channel_id)) {
 		/* Uses agent base channel */
 		*channel = container_of(base_chan, struct scmi_channel, ref);
 
@@ -343,7 +344,7 @@
 	if (!chan)
 		return -ENOMEM;
 
-	ret = setup_channel(dev, chan);
+	ret = setup_channel(protocol, chan);
 	if (ret) {
 		free(chan);
 		return ret;
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 0318829..eb567dd 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -14,11 +14,14 @@
 #include <asm/io.h>
 #include <asm/scmi_test.h>
 #include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
 
 /*
  * The sandbox SCMI agent driver simulates to some extend a SCMI message
  * processing. It simulates few of the SCMI services for some of the
  * SCMI protocols embedded in U-Boot. Currently:
+ * - SCMI base protocol
  * - SCMI clock protocol emulates an agent exposing 2 clocks
  * - SCMI reset protocol emulates an agent exposing a reset controller
  * - SCMI voltage domain protocol emulates an agent exposing 2 regulators
@@ -33,6 +36,41 @@
  * various uclass devices, as clocks and reset controllers.
  */
 
+#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION
+#define SANDBOX_SCMI_VENDOR "U-Boot"
+#define SANDBOX_SCMI_SUB_VENDOR "Sandbox"
+#define SANDBOX_SCMI_IMPL_VERSION 0x1
+#define SANDBOX_SCMI_AGENT_NAME "OSPM"
+#define SANDBOX_SCMI_PLATFORM_NAME "platform"
+
+/**
+ * struct sandbox_channel - Description of sandbox transport
+ * @channel_id:		Channel identifier
+ *
+ * Dummy channel. This will be used to test if a protocol-specific
+ * channel is properly used.
+ * Id 0 means a channel for the sandbox agent.
+ */
+struct sandbox_channel {
+	unsigned int channel_id;
+};
+
+/**
+ * struct scmi_channel - Channel instance referenced in SCMI drivers
+ * @ref: Reference to local channel instance
+ **/
+struct scmi_channel {
+	struct sandbox_channel ref;
+};
+
+static u8 protocols[] = {
+	SCMI_PROTOCOL_ID_CLOCK,
+	SCMI_PROTOCOL_ID_RESET_DOMAIN,
+	SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+};
+
+#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
+
 static struct sandbox_scmi_clk scmi_clk[] = {
 	{ .rate = 333 },
 	{ .rate = 200 },
@@ -48,11 +86,9 @@
 	{ .id = 1, .voltage_uv = 1800000 },
 };
 
-static struct sandbox_scmi_service sandbox_scmi_service_state;
-
-struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
 {
-	return &sandbox_scmi_service_state;
+	return dev_get_priv(dev);
 }
 
 static void debug_print_agent_state(struct udevice *dev, char *str)
@@ -114,6 +150,316 @@
  * Sandbox SCMI agent ops
  */
 
+/* Base Protocol */
+
+/**
+ * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_VERSION command.
+ */
+static int sandbox_scmi_base_protocol_version(struct udevice *dev,
+					      struct scmi_msg *msg)
+{
+	struct scmi_protocol_version_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_protocol_version_out *)msg->out_msg;
+	out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
+ */
+static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
+					    struct scmi_msg *msg)
+{
+	struct scmi_protocol_attrs_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_protocol_attrs_out *)msg->out_msg;
+	out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_message_attrs - implement
+ *					SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
+ */
+static int sandbox_scmi_base_message_attrs(struct udevice *dev,
+					   struct scmi_msg *msg)
+{
+	u32 message_id;
+	struct scmi_protocol_msg_attrs_out *out = NULL;
+
+	if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
+	    !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	message_id = *(u32 *)msg->in_msg;
+	out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
+
+	if (message_id >= SCMI_PROTOCOL_VERSION &&
+	    message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
+	    message_id != SCMI_BASE_NOTIFY_ERRORS) {
+		out->attributes = 0;
+		out->status = SCMI_SUCCESS;
+	} else {
+		out->status = SCMI_NOT_FOUND;
+	}
+
+		return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_VENDOR command
+ */
+static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
+					     struct scmi_msg *msg)
+{
+	struct scmi_base_discover_vendor_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
+	strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_sub_vendor - implement
+ *						SCMI_BASE_DISCOVER_SUB_VENDOR
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
+ */
+static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
+						 struct scmi_msg *msg)
+{
+	struct scmi_base_discover_vendor_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
+	strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_impl_version - implement
+ *				SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
+ */
+static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
+						   struct scmi_msg *msg)
+{
+	struct scmi_base_discover_impl_version_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
+	out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_list_protocols - implement
+ *					SCMI_BASE_DISCOVER_LIST_PROTOCOLS
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
+ */
+static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
+						     struct scmi_msg *msg)
+{
+	struct scmi_base_discover_list_protocols_out *out = NULL;
+
+	if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
+	memcpy(out->protocols, protocols, sizeof(protocols));
+	out->num_protocols = NUM_PROTOCOLS;
+	out->status = SCMI_SUCCESS;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_AGENT command
+ */
+static int sandbox_scmi_base_discover_agent(struct udevice *dev,
+					    struct scmi_msg *msg)
+{
+	u32 agent_id;
+	struct scmi_base_discover_agent_out *out = NULL;
+
+	if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
+	    !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+		return -EINVAL;
+
+	agent_id = *(u32 *)msg->in_msg;
+	out = (struct scmi_base_discover_agent_out *)msg->out_msg;
+	out->status = SCMI_SUCCESS;
+	if (agent_id == 0xffffffff || agent_id == 1) {
+		out->agent_id = 1;
+		strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
+	} else if (!agent_id) {
+		out->agent_id = agent_id;
+		strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
+	} else {
+		out->status = SCMI_NOT_FOUND;
+	}
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_set_device_permissions - implement
+ *						SCMI_BASE_SET_DEVICE_PERMISSIONS
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
+ */
+static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
+						    struct scmi_msg *msg)
+{
+	struct scmi_base_set_device_permissions_in *in = NULL;
+	u32 *status;
+
+	if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+	    !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+		return -EINVAL;
+
+	in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
+	status = (u32 *)msg->out_msg;
+
+	if (in->agent_id != 1 || in->device_id != 0)
+		*status = SCMI_NOT_FOUND;
+	else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
+		*status = SCMI_INVALID_PARAMETERS;
+	else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
+		*status = SCMI_SUCCESS;
+	else
+		/* unset not allowed */
+		*status = SCMI_DENIED;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_set_protocol_permissions - implement
+ *					SCMI_BASE_SET_PROTOCOL_PERMISSIONS
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
+ */
+static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
+						      struct scmi_msg *msg)
+{
+	struct scmi_base_set_protocol_permissions_in *in = NULL;
+	u32 *status;
+	int i;
+
+	if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+	    !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+		return -EINVAL;
+
+	in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
+	status = (u32 *)msg->out_msg;
+
+	for (i = 0; i < ARRAY_SIZE(protocols); i++)
+		if (protocols[i] == in->command_id)
+			break;
+	if (in->agent_id != 1 || in->device_id != 0 ||
+	    i == ARRAY_SIZE(protocols))
+		*status = SCMI_NOT_FOUND;
+	else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
+		*status = SCMI_INVALID_PARAMETERS;
+	else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
+		*status = SCMI_SUCCESS;
+	else
+		/* unset not allowed */
+		*status = SCMI_DENIED;
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_base_reset_agent_configuration - implement
+ *					SCMI_BASE_RESET_AGENT_CONFIGURATION
+ * @dev:	SCMI device
+ * @msg:	SCMI message
+ *
+ * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
+ */
+static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
+						       struct scmi_msg *msg)
+{
+	struct scmi_base_reset_agent_configuration_in *in = NULL;
+	u32 *status;
+
+	if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+	    !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+		return -EINVAL;
+
+	in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
+	status = (u32 *)msg->out_msg;
+
+	if (in->agent_id != 1)
+		*status = SCMI_NOT_FOUND;
+	else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
+		*status = SCMI_INVALID_PARAMETERS;
+	else
+		*status = SCMI_DENIED;
+
+	return 0;
+}
+
+/* Clock Protocol */
+
 static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
 					       struct scmi_msg *msg)
 {
@@ -470,11 +816,108 @@
 	return 0;
 }
 
+/**
+ * sandbox_scmi_of_get_channel - assigne a channel
+ * @dev:	SCMI agent device
+ * @protocol:	SCMI protocol device
+ * @channel:	Pointer to channel info
+ *
+ * Assign a channel for the protocol, @protocol, in @channel,
+ * based on a device tree's property.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_of_get_channel(struct udevice *dev,
+				       struct udevice *protocol,
+				       struct scmi_channel **channel)
+{
+	struct sandbox_channel *agent_chan = dev_get_plat(dev);
+	struct sandbox_channel *chan;
+	u32 channel_id;
+
+	if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
+		/* Uses agent channel */
+		*channel = container_of(agent_chan, struct scmi_channel, ref);
+
+		return 0;
+	}
+
+	/* Setup a dedicated channel */
+	chan = calloc(1, sizeof(*chan));
+	if (!chan)
+		return -ENOMEM;
+
+	chan->channel_id = channel_id;
+
+	*channel = container_of(chan, struct scmi_channel, ref);
+
+	return 0;
+}
+
+/**
+ * sandbox_scmi_of_to_plat - assigne a channel to agent
+ * @dev:	SCMI agent device
+ *
+ * Assign a channel for the agent, @protocol.
+ *
+ * Return: always 0
+ */
+static int sandbox_scmi_of_to_plat(struct udevice *dev)
+{
+	struct sandbox_channel *chan = dev_get_plat(dev);
+
+	/* The channel for agent is always 0 */
+	chan->channel_id = 0;
+
+	return 0;
+}
+
+unsigned int sandbox_scmi_channel_id(struct udevice *dev)
+{
+	struct scmi_agent_proto_priv *priv;
+	struct sandbox_channel *chan;
+
+	priv = dev_get_parent_priv(dev);
+	chan = (struct sandbox_channel *)&priv->channel->ref;
+
+	return chan->channel_id;
+}
+
 static int sandbox_scmi_test_process_msg(struct udevice *dev,
 					 struct scmi_channel *channel,
 					 struct scmi_msg *msg)
 {
 	switch (msg->protocol_id) {
+	case SCMI_PROTOCOL_ID_BASE:
+		switch (msg->message_id) {
+		case SCMI_PROTOCOL_VERSION:
+			return sandbox_scmi_base_protocol_version(dev, msg);
+		case SCMI_PROTOCOL_ATTRIBUTES:
+			return sandbox_scmi_base_protocol_attrs(dev, msg);
+		case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
+			return sandbox_scmi_base_message_attrs(dev, msg);
+		case SCMI_BASE_DISCOVER_VENDOR:
+			return sandbox_scmi_base_discover_vendor(dev, msg);
+		case SCMI_BASE_DISCOVER_SUB_VENDOR:
+			return sandbox_scmi_base_discover_sub_vendor(dev, msg);
+		case SCMI_BASE_DISCOVER_IMPL_VERSION:
+			return sandbox_scmi_base_discover_impl_version(dev, msg);
+		case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
+			return sandbox_scmi_base_discover_list_protocols(dev, msg);
+		case SCMI_BASE_DISCOVER_AGENT:
+			return sandbox_scmi_base_discover_agent(dev, msg);
+		case SCMI_BASE_NOTIFY_ERRORS:
+			break;
+		case SCMI_BASE_SET_DEVICE_PERMISSIONS:
+			return sandbox_scmi_base_set_device_permissions(dev, msg);
+		case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
+			return sandbox_scmi_base_set_protocol_permissions(dev, msg);
+		case SCMI_BASE_RESET_AGENT_CONFIGURATION:
+			return sandbox_scmi_base_reset_agent_configuration(dev, msg);
+		default:
+			break;
+		}
+		break;
 	case SCMI_PROTOCOL_ID_CLOCK:
 		switch (msg->message_id) {
 		case SCMI_PROTOCOL_ATTRIBUTES:
@@ -517,7 +960,6 @@
 			break;
 		}
 		break;
-	case SCMI_PROTOCOL_ID_BASE:
 	case SCMI_PROTOCOL_ID_POWER_DOMAIN:
 	case SCMI_PROTOCOL_ID_SYSTEM:
 	case SCMI_PROTOCOL_ID_PERF:
@@ -541,16 +983,8 @@
 
 static int sandbox_scmi_test_remove(struct udevice *dev)
 {
-	struct sandbox_scmi_agent *agent = dev_get_priv(dev);
-
-	if (agent != sandbox_scmi_service_ctx()->agent)
-		return -EINVAL;
-
 	debug_print_agent_state(dev, "removed");
 
-	/* We only need to dereference the agent in the context */
-	sandbox_scmi_service_ctx()->agent = NULL;
-
 	return 0;
 }
 
@@ -558,9 +992,6 @@
 {
 	struct sandbox_scmi_agent *agent = dev_get_priv(dev);
 
-	if (sandbox_scmi_service_ctx()->agent)
-		return -EINVAL;
-
 	*agent = (struct sandbox_scmi_agent){
 		.clk = scmi_clk,
 		.clk_count = ARRAY_SIZE(scmi_clk),
@@ -572,9 +1003,6 @@
 
 	debug_print_agent_state(dev, "probed");
 
-	/* Save reference for tests purpose */
-	sandbox_scmi_service_ctx()->agent = agent;
-
 	return 0;
 };
 
@@ -584,6 +1012,7 @@
 };
 
 struct scmi_agent_ops sandbox_scmi_test_ops = {
+	.of_get_channel = sandbox_scmi_of_get_channel,
 	.process_msg = sandbox_scmi_test_process_msg,
 };
 
@@ -592,6 +1021,8 @@
 	.id = UCLASS_SCMI_AGENT,
 	.of_match = sandbox_scmi_test_ids,
 	.priv_auto	= sizeof(struct sandbox_scmi_agent),
+	.plat_auto	= sizeof(struct sandbox_channel),
+	.of_to_plat	= sandbox_scmi_of_to_plat,
 	.probe = sandbox_scmi_test_probe,
 	.remove = sandbox_scmi_test_remove,
 	.ops = &sandbox_scmi_test_ops,
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 02de692..6f585b9 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
+#include <scmi_agent.h>
 #include <scmi_agent-uclass.h>
 #include <scmi_protocols.h>
 #include <dm/device_compat.h>
@@ -37,6 +38,118 @@
 	{ .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
 };
 
+/**
+ * scmi_protocol_is_supported - check availability of protocol
+ * @dev:	SCMI agent device
+ * @proto_id:	Identifier of protocol
+ *
+ * check if the protocol, @proto_id, is provided by the SCMI agent,
+ * @dev.
+ *
+ * Return:	0 on success, error code otherwise
+ */
+static bool scmi_protocol_is_supported(struct udevice *dev,
+				       enum scmi_std_protocol proto_id)
+{
+	struct scmi_agent_priv *priv;
+	int i;
+
+	if (proto_id == SCMI_PROTOCOL_ID_BASE)
+		return true;
+
+	priv = dev_get_uclass_plat(dev);
+	if (!priv) {
+		dev_err(dev, "No priv data found\n");
+		return false;
+	}
+
+	for (i = 0; i < priv->num_protocols; i++)
+		if (priv->protocols[i] == proto_id)
+			return true;
+
+	return false;
+}
+
+struct udevice *scmi_get_protocol(struct udevice *dev,
+				  enum scmi_std_protocol id)
+{
+	struct scmi_agent_priv *priv;
+	struct udevice *proto;
+
+	priv = dev_get_uclass_plat(dev);
+	if (!priv) {
+		dev_err(dev, "No priv data found\n");
+		return NULL;
+	}
+
+	switch (id) {
+	case SCMI_PROTOCOL_ID_BASE:
+		proto = priv->base_dev;
+		break;
+	case SCMI_PROTOCOL_ID_CLOCK:
+		proto = priv->clock_dev;
+		break;
+	case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+		proto = priv->resetdom_dev;
+		break;
+	case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+		proto = priv->voltagedom_dev;
+		break;
+	default:
+		dev_err(dev, "Protocol not supported\n");
+		proto = NULL;
+		break;
+	}
+	if (proto && device_probe(proto))
+		dev_err(dev, "Probe failed\n");
+
+	return proto;
+}
+
+/**
+ * scmi_add_protocol - add protocol to agent
+ * @dev:	SCMI agent device
+ * @proto_id:	SCMI protocol ID
+ * @proto:	SCMI protocol device
+ *
+ * Associate the protocol instance, @proto, to the agent, @dev,
+ * for later use.
+ *
+ * Return:	0 on success, error code on failure
+ */
+static int scmi_add_protocol(struct udevice *dev,
+			     enum scmi_std_protocol proto_id,
+			     struct udevice *proto)
+{
+	struct scmi_agent_priv *priv;
+
+	priv = dev_get_uclass_plat(dev);
+	if (!priv) {
+		dev_err(dev, "No priv data found\n");
+		return -ENODEV;
+	}
+
+	switch (proto_id) {
+	case SCMI_PROTOCOL_ID_BASE:
+		priv->base_dev = proto;
+		break;
+	case SCMI_PROTOCOL_ID_CLOCK:
+		priv->clock_dev = proto;
+		break;
+	case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+		priv->resetdom_dev = proto;
+		break;
+	case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+		priv->voltagedom_dev = proto;
+		break;
+	default:
+		dev_err(dev, "Protocol not supported\n");
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
 int scmi_to_linux_errno(s32 scmi_code)
 {
 	int n;
@@ -51,8 +164,191 @@
 	return -EPROTO;
 }
 
+static struct udevice *find_scmi_protocol_device(struct udevice *dev)
+{
+	struct udevice *parent = NULL, *protocol;
+
+	for (protocol = dev; protocol; protocol = parent) {
+		parent = dev_get_parent(protocol);
+		if (!parent ||
+		    device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
+			break;
+	}
+
+	if (!parent) {
+		dev_err(dev, "Invalid SCMI device, agent not found\n");
+		return NULL;
+	}
+
+	return protocol;
+}
+
+static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
+{
+	return (const struct scmi_agent_ops *)dev->driver->ops;
+}
+
+/**
+ * scmi_of_get_channel() - Get SCMI channel handle
+ *
+ * @dev:	SCMI agent device
+ * @channel:	Output reference to the SCMI channel upon success
+ *
+ * On return, @channel will be set.
+ * Return	0 on success and a negative errno on failure
+ */
+static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
+			       struct scmi_channel **channel)
+{
+	const struct scmi_agent_ops *ops;
+
+	ops = transport_dev_ops(dev);
+	if (ops->of_get_channel)
+		return ops->of_get_channel(dev, protocol, channel);
+	else
+		return -EPROTONOSUPPORT;
+}
+
+int devm_scmi_of_get_channel(struct udevice *dev)
+{
+	struct udevice *protocol;
+	struct scmi_agent_proto_priv *priv;
+	int ret;
+
+	protocol = find_scmi_protocol_device(dev);
+	if (!protocol)
+		return -ENODEV;
+
+	priv = dev_get_parent_priv(protocol);
+	ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
+	if (ret == -EPROTONOSUPPORT) {
+		/* Drivers without a get_channel operator don't need a channel ref */
+		priv->channel = NULL;
+
+		return 0;
+	}
+
+	return ret;
+}
+
+/**
+ * scmi_process_msg() - Send and process an SCMI message
+ *
+ * Send a message to an SCMI server.
+ * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
+ *
+ * @dev:	SCMI agent device
+ * @channel:	Communication channel for the device
+ * @msg:	Message structure reference
+ *
+ * On return, scmi_msg::out_msg_sz stores the response payload size.
+ * Return:	0 on success and a negative errno on failure
+ */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
+			    struct scmi_msg *msg)
+{
+	const struct scmi_agent_ops *ops;
+
+	ops = transport_dev_ops(dev);
+	if (ops->process_msg)
+		return ops->process_msg(dev, channel, msg);
+	else
+		return -EPROTONOSUPPORT;
+}
+
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+	struct udevice *protocol;
+	struct scmi_agent_proto_priv *priv;
+
+	protocol = find_scmi_protocol_device(dev);
+	if (!protocol)
+		return -ENODEV;
+
+	priv = dev_get_parent_priv(protocol);
+
+	return scmi_process_msg(protocol->parent, priv->channel, msg);
+}
+
+/**
+ * scmi_fill_base_info - get base information about SCMI server
+ * @agent:	SCMI agent device
+ * @dev:	SCMI protocol device
+ *
+ * By using Base protocol commands, collect the base information
+ * about SCMI server.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
+{
+	struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
+	int ret;
+
+	ret = scmi_base_protocol_version(dev, &priv->version);
+	if (ret) {
+		dev_err(dev, "protocol_version() failed (%d)\n", ret);
+		return ret;
+	}
+	/* check for required version */
+	if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
+		dev_err(dev, "base protocol version (%d) lower than expected\n",
+			priv->version);
+		return -EPROTO;
+	}
+
+	ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
+				       &priv->num_protocols);
+	if (ret) {
+		dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
+		return ret;
+	}
+	ret = scmi_base_discover_vendor(dev, &priv->vendor);
+	if (ret) {
+		dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
+		return ret;
+	}
+	ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
+	if (ret) {
+		if (ret != -EOPNOTSUPP) {
+			dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
+				ret);
+			return ret;
+		}
+		priv->sub_vendor = "NA";
+	}
+	ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
+	if (ret) {
+		dev_err(dev, "base_discover_impl_version() failed (%d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = scmi_base_discover_agent(dev, 0xffffffff,
+				       &priv->agent_id, &priv->agent_name);
+	if (ret) {
+		if (ret != -EOPNOTSUPP) {
+			dev_err(dev,
+				"base_discover_agent() failed for myself (%d)\n",
+				ret);
+			return ret;
+		}
+		priv->agent_id = 0xffffffff;
+		priv->agent_name = "NA";
+	}
+
+	ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
+	if (ret != priv->num_protocols) {
+		dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
+			ret);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
 /*
- * SCMI agent devices binds devices of various uclasses depeding on
+ * SCMI agent devices binds devices of various uclasses depending on
  * the FDT description. scmi_bind_protocol() is a generic bind sequence
  * called by the uclass at bind stage, that is uclass post_bind.
  */
@@ -61,9 +357,43 @@
 	int ret = 0;
 	ofnode node;
 	const char *name;
+	struct driver *drv;
+	struct udevice *agent, *proto;
+
+	if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
+		/* This is a second SCMI agent */
+		dev_err(dev, "Cannot have more than one SCMI agent\n");
+		return -EEXIST;
+	}
+
+	/* initialize the device from device tree */
+	drv = DM_DRIVER_GET(scmi_base_drv);
+	name = "scmi-base.0";
+	ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
+	if (ret) {
+		dev_err(dev, "failed to bind base protocol\n");
+		return ret;
+	}
+	ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
+	if (ret) {
+		dev_err(dev, "failed to add protocol: %s, ret: %d\n",
+			proto->name, ret);
+		return ret;
+	}
+
+	ret = device_probe(proto);
+	if (ret) {
+		dev_err(dev, "failed to probe base protocol\n");
+		return ret;
+	}
+
+	ret = scmi_fill_base_info(dev, proto);
+	if (ret) {
+		dev_err(dev, "failed to get base information\n");
+		return ret;
+	}
 
 	dev_for_each_subnode(node, dev) {
-		struct driver *drv = NULL;
 		u32 protocol_id;
 
 		if (!ofnode_is_enabled(node))
@@ -72,18 +402,22 @@
 		if (ofnode_read_u32(node, "reg", &protocol_id))
 			continue;
 
+		drv = NULL;
 		name = ofnode_get_name(node);
 		switch (protocol_id) {
 		case SCMI_PROTOCOL_ID_CLOCK:
-			if (CONFIG_IS_ENABLED(CLK_SCMI))
+			if (CONFIG_IS_ENABLED(CLK_SCMI) &&
+			    scmi_protocol_is_supported(dev, protocol_id))
 				drv = DM_DRIVER_GET(scmi_clock);
 			break;
 		case SCMI_PROTOCOL_ID_RESET_DOMAIN:
-			if (IS_ENABLED(CONFIG_RESET_SCMI))
+			if (IS_ENABLED(CONFIG_RESET_SCMI) &&
+			    scmi_protocol_is_supported(dev, protocol_id))
 				drv = DM_DRIVER_GET(scmi_reset_domain);
 			break;
 		case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
-			if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
+			if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
+			    scmi_protocol_is_supported(dev, protocol_id)) {
 				node = ofnode_find_subnode(node, "regulators");
 				if (!ofnode_valid(node)) {
 					dev_err(dev, "no regulators node\n");
@@ -102,70 +436,26 @@
 			continue;
 		}
 
-		ret = device_bind(dev, drv, name, NULL, node, NULL);
-		if (ret)
+		ret = device_bind(dev, drv, name, NULL, node, &proto);
+		if (ret) {
+			dev_err(dev, "failed to bind %s protocol\n", drv->name);
 			break;
+		}
+		ret = scmi_add_protocol(dev, protocol_id, proto);
+		if (ret) {
+			dev_err(dev, "failed to add protocol: %s, ret: %d\n",
+				proto->name, ret);
+			break;
+		}
 	}
 
 	return ret;
 }
 
-static struct udevice *find_scmi_transport_device(struct udevice *dev)
-{
-	struct udevice *parent = dev;
-
-	do {
-		parent = dev_get_parent(parent);
-	} while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
-
-	if (!parent)
-		dev_err(dev, "Invalid SCMI device, agent not found\n");
-
-	return parent;
-}
-
-static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
-{
-	return (const struct scmi_agent_ops *)dev->driver->ops;
-}
-
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
-{
-	struct udevice *parent;
-
-	parent = find_scmi_transport_device(dev);
-	if (!parent)
-		return -ENODEV;
-
-	if (transport_dev_ops(parent)->of_get_channel)
-		return transport_dev_ops(parent)->of_get_channel(parent, channel);
-
-	/* Drivers without a get_channel operator don't need a channel ref */
-	*channel = NULL;
-
-	return 0;
-}
-
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
-			  struct scmi_msg *msg)
-{
-	const struct scmi_agent_ops *ops;
-	struct udevice *parent;
-
-	parent = find_scmi_transport_device(dev);
-	if (!parent)
-		return -ENODEV;
-
-	ops = transport_dev_ops(parent);
-
-	if (ops->process_msg)
-		return ops->process_msg(parent, channel, msg);
-
-	return -EPROTONOSUPPORT;
-}
-
 UCLASS_DRIVER(scmi_agent) = {
 	.id		= UCLASS_SCMI_AGENT,
 	.name		= "scmi_agent",
 	.post_bind	= scmi_bind_protocols,
+	.per_device_plat_auto = sizeof(struct scmi_agent_priv),
+	.per_child_auto	= sizeof(struct scmi_agent_proto_priv),
 };
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
index 6a52cd7..972c6ad 100644
--- a/drivers/firmware/scmi/smccc_agent.c
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -81,6 +81,7 @@
 }
 
 static int scmi_smccc_get_channel(struct udevice *dev,
+				  struct udevice *protocol,
 				  struct scmi_channel **channel)
 {
 	struct scmi_smccc_channel *base_chan = dev_get_plat(dev);
@@ -88,7 +89,7 @@
 	u32 func_id;
 	int ret;
 
-	if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
+	if (dev_read_u32(protocol, "arm,smc-id", &func_id)) {
 		/* Uses agent base channel */
 		*channel = container_of(base_chan, struct scmi_channel, ref);
 
@@ -100,7 +101,7 @@
 	if (!chan)
 		return -ENOMEM;
 
-	ret = setup_channel(dev, chan);
+	ret = setup_channel(protocol, chan);
 	if (ret) {
 		free(chan);
 		return ret;
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
index 8011480..9c72c35 100644
--- a/drivers/power/regulator/scmi_regulator.c
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -25,18 +25,9 @@
 	u32 domain_id;
 };
 
-/**
- * struct scmi_regulator_priv - Private data for SCMI voltage regulator
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_regulator_priv {
-	struct scmi_channel *channel;
-};
-
 static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
 {
 	struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
-	struct scmi_regulator_priv *priv = dev_get_priv(dev);
 	struct scmi_voltd_config_set_in in = {
 		.domain_id = pdata->domain_id,
 		.config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@@ -47,7 +38,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret)
 		return ret;
 
@@ -57,7 +48,6 @@
 static int scmi_voltd_get_enable(struct udevice *dev)
 {
 	struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
-	struct scmi_regulator_priv *priv = dev_get_priv(dev);
 	struct scmi_voltd_config_get_in in = {
 		.domain_id = pdata->domain_id,
 	};
@@ -67,7 +57,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret < 0)
 		return ret;
 
@@ -80,7 +70,6 @@
 
 static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
 {
-	struct scmi_regulator_priv *priv = dev_get_priv(dev);
 	struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
 	struct scmi_voltd_level_set_in in = {
 		.domain_id = pdata->domain_id,
@@ -92,7 +81,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret < 0)
 		return ret;
 
@@ -101,7 +90,6 @@
 
 static int scmi_voltd_get_voltage_level(struct udevice *dev)
 {
-	struct scmi_regulator_priv *priv = dev_get_priv(dev);
 	struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
 	struct scmi_voltd_level_get_in in = {
 		.domain_id = pdata->domain_id,
@@ -112,7 +100,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(dev, &msg);
 	if (ret < 0)
 		return ret;
 
@@ -140,7 +128,6 @@
 static int scmi_regulator_probe(struct udevice *dev)
 {
 	struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
-	struct scmi_regulator_priv *priv = dev_get_priv(dev);
 	struct scmi_voltd_attr_in in = { 0 };
 	struct scmi_voltd_attr_out out = { 0 };
 	struct scmi_msg scmi_msg = {
@@ -153,14 +140,14 @@
 	};
 	int ret;
 
-	ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
+	ret = devm_scmi_of_get_channel(dev);
 	if (ret)
 		return ret;
 
 	/* Check voltage domain is known from SCMI server */
 	in.domain_id = pdata->domain_id;
 
-	ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
+	ret = devm_scmi_process_msg(dev, &scmi_msg);
 	if (ret) {
 		dev_err(dev, "Failed to query voltage domain %u: %d\n",
 			pdata->domain_id, ret);
@@ -184,7 +171,6 @@
 	.probe = scmi_regulator_probe,
 	.of_to_plat = scmi_regulator_of_to_plat,
 	.plat_auto = sizeof(struct scmi_regulator_platdata),
-	.priv_auto = sizeof(struct scmi_regulator_priv *),
 };
 
 static int scmi_regulator_bind(struct udevice *dev)
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
index 1225561..b76711f 100644
--- a/drivers/reset/reset-scmi.c
+++ b/drivers/reset/reset-scmi.c
@@ -13,17 +13,8 @@
 #include <scmi_protocols.h>
 #include <asm/types.h>
 
-/**
- * struct scmi_reset_priv - Private data for SCMI reset controller
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_reset_priv {
-	struct scmi_channel *channel;
-};
-
 static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
 {
-	struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
 	struct scmi_rd_reset_in in = {
 		.domain_id = rst->id,
 		.flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0,
@@ -35,7 +26,7 @@
 					  in, out);
 	int ret;
 
-	ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(rst->dev, &msg);
 	if (ret)
 		return ret;
 
@@ -54,7 +45,6 @@
 
 static int scmi_reset_request(struct reset_ctl *rst)
 {
-	struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
 	struct scmi_rd_attr_in in = {
 		.domain_id = rst->id,
 	};
@@ -68,7 +58,7 @@
 	 * We don't really care about the attribute, just check
 	 * the reset domain exists.
 	 */
-	ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
+	ret = devm_scmi_process_msg(rst->dev, &msg);
 	if (ret)
 		return ret;
 
@@ -83,9 +73,7 @@
 
 static int scmi_reset_probe(struct udevice *dev)
 {
-	struct scmi_reset_priv *priv = dev_get_priv(dev);
-
-	return devm_scmi_of_get_channel(dev, &priv->channel);
+	return devm_scmi_of_get_channel(dev);
 }
 
 U_BOOT_DRIVER(scmi_reset_domain) = {
@@ -93,5 +81,4 @@
 	.id = UCLASS_RESET,
 	.ops = &scmi_reset_domain_ops,
 	.probe = scmi_reset_probe,
-	.priv_auto = sizeof(struct scmi_reset_priv *),
 };
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index f16731c..4c42074 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -58,13 +58,9 @@
 	req->submitted = 1;
 
 	next_fifo_transaction(ep, req);
-	if (req->last_transaction) {
-		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
-		usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
-	} else {
+	if (ep_is_control(ep))
 		usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
-		usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
-	}
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
 }
 
 static void submit_next_request(struct usba_ep *ep)
@@ -890,7 +886,6 @@
 			if (req) {
 				list_del_init(&req->queue);
 				request_complete(ep, req, 0);
-				submit_next_request(ep);
 			}
 			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
 			ep->state = WAIT_FOR_SETUP;
@@ -1037,7 +1032,6 @@
 		DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
 
 		if (list_empty(&ep->queue)) {
-			DBG(DBG_INT, "ep_irq: queue empty\n");
 			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
 			return;
 		}
@@ -1051,7 +1045,6 @@
 
 		if (req->last_transaction) {
 			list_del_init(&req->queue);
-			submit_next_request(ep);
 			request_complete(ep, req, 0);
 		}
 
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0432c95..ab31580 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -123,6 +123,7 @@
 	UCLASS_RNG,		/* Random Number Generator */
 	UCLASS_RTC,		/* Real time clock device */
 	UCLASS_SCMI_AGENT,	/* Interface with an SCMI server */
+	UCLASS_SCMI_BASE,	/* Interface for SCMI Base protocol */
 	UCLASS_SCSI,		/* SCSI device */
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SIMPLE_BUS,	/* Bus with child devices */
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h
index b1c9353..35d9606 100644
--- a/include/scmi_agent-uclass.h
+++ b/include/scmi_agent-uclass.h
@@ -5,27 +5,108 @@
 #ifndef _SCMI_AGENT_UCLASS_H
 #define _SCMI_AGENT_UCLASS_H
 
-struct udevice;
+#include <scmi_protocols.h>
+#include <dm/device.h>
+
 struct scmi_msg;
 struct scmi_channel;
 
 /**
+ * struct scmi_agent_priv - private data maintained by agent instance
+ * @version:		Version
+ * @num_agents:		Number of agents
+ * @num_protocols:	Number of protocols
+ * @impl_version:	Implementation version
+ * @protocols:		Array of protocol IDs
+ * @vendor:		Vendor name
+ * @sub_vendor:		Sub-vendor name
+ * @agent_name:		Agent name
+ * @agent_id:		Identifier of agent
+ * @base_dev:		SCMI base protocol device
+ * @clock_dev:		SCMI clock protocol device
+ * @resetdom_dev:	SCMI reset domain protocol device
+ * @voltagedom_dev:	SCMI voltage domain protocol device
+ */
+struct scmi_agent_priv {
+	u32 version;
+	u32 num_agents;
+	u32 num_protocols;
+	u32 impl_version;
+	u8 *protocols;
+	u8 *vendor;
+	u8 *sub_vendor;
+	u8 *agent_name;
+	u32 agent_id;
+	struct udevice *base_dev;
+	struct udevice *clock_dev;
+	struct udevice *resetdom_dev;
+	struct udevice *voltagedom_dev;
+};
+
+static inline u32 scmi_version(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version;
+}
+
+static inline u32 scmi_num_agents(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents;
+}
+
+static inline u32 scmi_num_protocols(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols;
+}
+
+static inline u32 scmi_impl_version(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version;
+}
+
+static inline u8 *scmi_protocols(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols;
+}
+
+static inline u8 *scmi_vendor(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor;
+}
+
+static inline u8 *scmi_sub_vendor(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor;
+}
+
+static inline u8 *scmi_agent_name(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name;
+}
+
+static inline u32 scmi_agent_id(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
+}
+
+/**
  * struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
  */
 struct scmi_agent_ops {
 	/*
 	 * of_get_channel - Get SCMI channel from SCMI agent device tree node
 	 *
-	 * @dev:		SCMI protocol device using the transport
+	 * @dev:		SCMI agent device using the transport
+	 * @protocol:		SCMI protocol device using the transport
 	 * @channel:		Output reference to SCMI channel upon success
 	 * Return 0 upon success and a negative errno on failure
 	 */
-	int (*of_get_channel)(struct udevice *dev, struct scmi_channel **channel);
+	int (*of_get_channel)(struct udevice *dev, struct udevice *protocol,
+			      struct scmi_channel **channel);
 
 	/*
 	 * process_msg - Request transport to get the SCMI message processed
 	 *
-	 * @dev:		SCMI protocol device using the transport
+	 * @dev:		SCMI agent device using the transport
 	 * @msg:		SCMI message to be transmitted
 	 */
 	int (*process_msg)(struct udevice *dev, struct scmi_channel *channel,
diff --git a/include/scmi_agent.h b/include/scmi_agent.h
index ee62863..755986d 100644
--- a/include/scmi_agent.h
+++ b/include/scmi_agent.h
@@ -10,11 +10,20 @@
 #ifndef SCMI_AGENT_H
 #define SCMI_AGENT_H
 
+#include <scmi_protocols.h>
 #include <asm/types.h>
 
 struct udevice;
 struct scmi_channel;
 
+/**
+ * struct scmi_agent_proto_priv - Private data in device for SCMI agent
+ * @channel: Reference to the SCMI channel to use
+ */
+struct scmi_agent_proto_priv {
+	struct scmi_channel *channel;
+};
+
 /*
  * struct scmi_msg - Context of a SCMI message sent and the response received
  *
@@ -49,10 +58,9 @@
  * devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node
  *
  * @dev:	Device requesting a channel
- * @channel:	Output reference to the SCMI channel upon success
  * @return 0 on success and a negative errno on failure
  */
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel);
+int devm_scmi_of_get_channel(struct udevice *dev);
 
 /**
  * devm_scmi_process_msg() - Send and process an SCMI message
@@ -62,12 +70,23 @@
  * On return, scmi_msg::out_msg_sz stores the response payload size.
  *
  * @dev:	SCMI device
- * @channel:	Communication channel for the device
  * @msg:	Message structure reference
  * Return: 0 on success and a negative errno on failure
  */
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
-			  struct scmi_msg *msg);
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
+
+/**
+ * scmi_get_protocol() - get protocol instance
+ *
+ * @dev:	SCMI agent device
+ * @id:		SCMI protocol ID
+ *
+ * Obtain the device instance for given protocol ID, @id.
+ *
+ * Return:	Pointer to the device if found, null otherwise
+ */
+struct udevice *scmi_get_protocol(struct udevice *dev,
+				  enum scmi_std_protocol id);
 
 /**
  * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h
index a220cb2..163647a 100644
--- a/include/scmi_protocols.h
+++ b/include/scmi_protocols.h
@@ -50,6 +50,501 @@
 };
 
 /*
+ * SCMI Base Protocol
+ */
+#define SCMI_BASE_PROTOCOL_VERSION 0x20000
+
+enum scmi_base_message_id {
+	SCMI_BASE_DISCOVER_VENDOR = 0x3,
+	SCMI_BASE_DISCOVER_SUB_VENDOR = 0x4,
+	SCMI_BASE_DISCOVER_IMPL_VERSION = 0x5,
+	SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
+	SCMI_BASE_DISCOVER_AGENT = 0x7,
+	SCMI_BASE_NOTIFY_ERRORS = 0x8,
+	SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x9,
+	SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
+	SCMI_BASE_RESET_AGENT_CONFIGURATION = 0xb,
+};
+
+#define SCMI_BASE_NAME_LENGTH_MAX 16
+
+/**
+ * struct scmi_protocol_version_out - Response for SCMI_PROTOCOL_VERSION
+ *					command
+ * @status:	SCMI command status
+ * @version:	Protocol version
+ */
+struct scmi_protocol_version_out {
+	s32 status;
+	u32 version;
+};
+
+/**
+ * struct scmi_protocol_attrs_out - Response for SCMI_PROTOCOL_ATTRIBUTES
+ *					command
+ * @status:	SCMI command status
+ * @attributes:	Protocol attributes or implementation details
+ */
+struct scmi_protocol_attrs_out {
+	s32 status;
+	u32 attributes;
+};
+
+#define SCMI_PROTOCOL_ATTRS_NUM_AGENTS(attributes) \
+				(((attributes) & GENMASK(15, 8)) >> 8)
+#define SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(attributes) \
+				((attributes) & GENMASK(7, 0))
+
+/**
+ * struct scmi_protocol_msg_attrs_out - Response for
+ *					SCMI_PROTOCOL_MESSAGE_ATTRIBUTES command
+ * @status:	SCMI command status
+ * @attributes:	Message-specific attributes
+ */
+struct scmi_protocol_msg_attrs_out {
+	s32 status;
+	u32 attributes;
+};
+
+/**
+ * struct scmi_base_discover_vendor_out - Response for
+ *					  SCMI_BASE_DISCOVER_VENDOR or
+ *					  SCMI_BASE_DISCOVER_SUB_VENDOR command
+ * @status:		SCMI command status
+ * @vendor_identifier:	Name of vendor or sub-vendor in string
+ */
+struct scmi_base_discover_vendor_out {
+	s32 status;
+	u8 vendor_identifier[SCMI_BASE_NAME_LENGTH_MAX];
+};
+
+/**
+ * struct scmi_base_discover_impl_version_out - Response for
+ *					SCMI_BASE_DISCOVER_IMPL_VERSION command
+ * @status:		SCMI command status
+ * @impl_version:	Vendor-specific implementation version
+ */
+struct scmi_base_discover_impl_version_out {
+	s32 status;
+	u32 impl_version;
+};
+
+/**
+ * struct scmi_base_discover_list_protocols_out - Response for
+ *				SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
+ * @status:		SCMI command status
+ * @num_protocols:	Number of SCMI protocols in @protocol
+ * @protocols:		Array of packed SCMI protocol ID's
+ */
+struct scmi_base_discover_list_protocols_out {
+	s32 status;
+	u32 num_protocols;
+	u32 protocols[3];
+};
+
+/**
+ * struct scmi_base_discover_agent_out - Response for
+ *					 SCMI_BASE_DISCOVER_AGENT command
+ * @status:	SCMI command status
+ * @agent_id:	SCMI agent ID
+ * @name:	Name of agent in string
+ */
+struct scmi_base_discover_agent_out {
+	s32 status;
+	u32 agent_id;
+	u8 name[SCMI_BASE_NAME_LENGTH_MAX];
+};
+
+#define SCMI_BASE_NOTIFY_ERRORS_ENABLE BIT(0)
+
+/**
+ * struct scmi_base_set_device_permissions_in - Parameters for
+ *					SCMI_BASE_SET_DEVICE_PERMISSIONS command
+ * @agent_id:	SCMI agent ID
+ * @device_id:	device ID
+ * @flags:	A set of flags
+ */
+struct scmi_base_set_device_permissions_in {
+	u32 agent_id;
+	u32 device_id;
+	u32 flags;
+};
+
+#define SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS BIT(0)
+
+/**
+ * struct scmi_base_set_protocol_permissions_in - Parameters for
+ *				SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
+ * @agent_id:		SCMI agent ID
+ * @device_id:		device ID
+ * @command_id:		command ID
+ * @flags:		A set of flags
+ */
+struct scmi_base_set_protocol_permissions_in {
+	u32 agent_id;
+	u32 device_id;
+	u32 command_id;
+	u32 flags;
+};
+
+#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_COMMAND GENMASK(7, 0)
+#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS BIT(0)
+
+/**
+ * struct scmi_base_reset_agent_configuration_in - Parameters for
+ *				SCMI_BASE_RESET_AGENT_CONFIGURATION command
+ * @agent_id:	SCMI agent ID
+ * @flags:	A set of flags
+ */
+struct scmi_base_reset_agent_configuration_in {
+	u32 agent_id;
+	u32 flags;
+};
+
+#define SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS BIT(0)
+
+/**
+ * struct scmi_base_ops - SCMI base protocol interfaces
+ */
+struct scmi_base_ops {
+	/**
+	 * protocol_version - get Base protocol version
+	 * @dev:	SCMI protocol device
+	 * @version:	Pointer to SCMI protocol version
+	 *
+	 * Obtain the protocol version number in @version for Base protocol.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*protocol_version)(struct udevice *dev, u32 *version);
+	/**
+	 * protocol_attrs - get protocol attributes
+	 * @dev:		SCMI protocol device
+	 * @num_agents:		Number of SCMI agents
+	 * @num_protocols:	Number of SCMI protocols
+	 *
+	 * Obtain the protocol attributes, the number of agents and the number
+	 * of protocols, in @num_agents and @num_protocols respectively, that
+	 * the device provides.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*protocol_attrs)(struct udevice *dev, u32 *num_agents,
+			      u32 *num_protocols);
+	/**
+	 * protocol_message_attrs - get message-specific attributes
+	 * @dev:		SCMI protocol device
+	 * @message_id:		SCMI message ID
+	 * @attributes:		Message-specific attributes
+	 *
+	 * Obtain the message-specific attributes in @attributes.
+	 * This command succeeds if the message is implemented and available.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*protocol_message_attrs)(struct udevice *dev, u32 message_id,
+				      u32 *attributes);
+	/**
+	 * base_discover_vendor - get vendor name
+	 * @dev:	SCMI protocol device
+	 * @vendor:	Pointer to vendor name
+	 *
+	 * Obtain the vendor's name in @vendor.
+	 * It is a caller's responsibility to free @vendor.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_discover_vendor)(struct udevice *dev, u8 **vendor);
+	/**
+	 * base_discover_sub_vendor - get sub-vendor name
+	 * @dev:	SCMI protocol device
+	 * @sub_vendor:	Pointer to sub-vendor name
+	 *
+	 * Obtain the sub-vendor's name in @sub_vendor.
+	 * It is a caller's responsibility to free @sub_vendor.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_discover_sub_vendor)(struct udevice *dev, u8 **sub_vendor);
+	/**
+	 * base_discover_impl_version - get implementation version
+	 * @dev:		SCMI protocol device
+	 * @impl_version:	Pointer to implementation version
+	 *
+	 * Obtain the implementation version number in @impl_version.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_discover_impl_version)(struct udevice *dev,
+					  u32 *impl_version);
+	/**
+	 * base_discover_list_protocols - get list of protocols
+	 * @dev:	SCMI protocol device
+	 * @protocols:	Pointer to array of SCMI protocols
+	 *
+	 * Obtain the list of protocols provided in @protocols.
+	 * The number of elements in @protocols always match to the number of
+	 * protocols returned by smci_protocol_attrs() when this function
+	 * succeeds.
+	 * It is a caller's responsibility to free @protocols.
+	 *
+	 * Return: the number of protocols in @protocols on success,
+	 * error code on failure
+	 */
+	int (*base_discover_list_protocols)(struct udevice *dev,
+					    u8 **protocols);
+	/**
+	 * base_discover_agent - identify agent
+	 * @dev:		SCMI protocol device
+	 * @agent_id:		SCMI agent ID
+	 * @ret_agent_id:	Pointer to SCMI agent ID
+	 * @name:		Pointer to SCMI agent name
+	 *
+	 * Obtain the agent's name in @name. If @agent_id is equal to
+	 * 0xffffffff, * this function returns the caller's agent id in
+	 * @ret_agent_id.
+	 * It is a caller's responsibility to free @name.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_discover_agent)(struct udevice *dev, u32 agent_id,
+				   u32 *ret_agent_id, u8 **name);
+	/**
+	 * base_notify_errors - configure error notification
+	 * @dev:	SCMI protocol device
+	 * @enable:	Operation
+	 *
+	 * Enable or disable error notification from SCMI firmware.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_notify_errors)(struct udevice *dev, u32 enable);
+	/**
+	 * base_set_device_permissions - configure access permission to device
+	 * @dev:	SCMI protocol device
+	 * @agent_id:	SCMI agent ID
+	 * @device_id:	ID of device to access
+	 * @flags:	A set of flags
+	 *
+	 * Ask for allowing or denying access permission to the device,
+	 * @device_id. The meaning of @flags is defined in SCMI specification.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_set_device_permissions)(struct udevice *dev, u32 agent_id,
+					   u32 device_id, u32 flags);
+	/**
+	 * base_set_protocol_permissions - configure access permission to
+	 *				   protocol on device
+	 * @dev:	SCMI protocol device
+	 * @agent_id:	SCMI agent ID
+	 * @device_id:	ID of device to access
+	 * @command_id:	command ID
+	 * @flags:	A set of flags
+	 *
+	 * Ask for allowing or denying access permission to the protocol,
+	 * @command_id, on the device, @device_id.
+	 * The meaning of @flags is defined in SCMI specification.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_set_protocol_permissions)(struct udevice *dev, u32 agent_id,
+					     u32 device_id, u32 command_id,
+					     u32 flags);
+	/**
+	 * base_reset_agent_configuration - reset resource settings
+	 * @dev:	SCMI protocol device
+	 * @agent_id:	SCMI agent ID
+	 * @flags:	A set of flags
+	 *
+	 * Reset all the resource settings against @agent_id.
+	 * The meaning of @flags is defined in SCMI specification.
+	 *
+	 * Return: 0 on success, error code on failure
+	 */
+	int (*base_reset_agent_configuration)(struct udevice *dev, u32 agent_id,
+					      u32 flags);
+};
+
+/**
+ * scmi_generic_protocol_version - get protocol version
+ * @dev:	SCMI protocol device
+ * @id:		SCMI protocol ID
+ * @version:	Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_generic_protocol_version(struct udevice *dev,
+				  enum scmi_std_protocol id, u32 *version);
+
+/**
+ * scmi_base_protocol_version - get Base protocol version
+ * @dev:	SCMI protocol device
+ * @version:	Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version for Base protocol.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_protocol_version(struct udevice *dev, u32 *version);
+
+/**
+ * scmi_protocol_attrs - get protocol attributes
+ * @dev:		SCMI protocol device
+ * @num_agents:		Number of SCMI agents
+ * @num_protocols:	Number of SCMI protocols
+ *
+ * Obtain the protocol attributes, the number of agents and the number
+ * of protocols, in @num_agents and @num_protocols respectively, that
+ * the device provides.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
+			     u32 *num_protocols);
+
+/**
+ * scmi_protocol_message_attrs - get message-specific attributes
+ * @dev:		SCMI protocol device
+ * @message_id:		SCMI message ID
+ * @attributes:		Message-specific attributes
+ *
+ * Obtain the message-specific attributes in @attributes.
+ * This command succeeds if the message is implemented and available.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
+				     u32 *attributes);
+
+/**
+ * scmi_base_discover_vendor - get vendor name
+ * @dev:	SCMI protocol device
+ * @vendor:	Pointer to vendor name
+ *
+ * Obtain the vendor's name in @vendor.
+ * It is a caller's responsibility to free @vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor);
+
+/**
+ * scmi_base_discover_sub_vendor - get sub-vendor name
+ * @dev:	SCMI protocol device
+ * @sub_vendor:	Pointer to sub-vendor name
+ *
+ * Obtain the sub-vendor's name in @sub_vendor.
+ * It is a caller's responsibility to free @sub_vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor);
+
+/**
+ * scmi_base_discover_impl_version - get implementation version
+ * @dev:		SCMI protocol device
+ * @impl_version:	Pointer to implementation version
+ *
+ * Obtain the implementation version number in @impl_version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version);
+
+/**
+ * scmi_base_discover_list_protocols - get list of protocols
+ * @dev:	SCMI protocol device
+ * @protocols:	Pointer to array of SCMI protocols
+ *
+ * Obtain the list of protocols provided in @protocols.
+ * The number of elements in @protocols always match to the number of
+ * protocols returned by smci_protocol_attrs() when this function succeeds.
+ * It is a caller's responsibility to free @protocols.
+ *
+ * Return: the number of protocols in @protocols on success, error code on
+ * failure
+ */
+int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols);
+
+/**
+ * scmi_base_discover_agent - identify agent
+ * @dev:		SCMI protocol device
+ * @agent_id:		SCMI agent ID
+ * @ret_agent_id:	Pointer to SCMI agent ID
+ * @name:		Pointer to SCMI agent name
+ *
+ * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
+ * this function returns the caller's agent id in @ret_agent_id.
+ * It is a caller's responsibility to free @name.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
+			     u32 *ret_agent_id, u8 **name);
+
+/**
+ * scmi_base_notify_errors - configure error notification
+ * @dev:	SCMI protocol device
+ * @enable:	Operation
+ *
+ * Enable or disable error notification from SCMI firmware.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_notify_errors(struct udevice *dev, u32 enable);
+
+/**
+ * scmi_base_set_device_permissions - configure access permission to device
+ * @dev:	SCMI protocol device
+ * @agent_id:	SCMI agent ID
+ * @device_id:	ID of device to access
+ * @flags:	A set of flags
+ *
+ * Ask for allowing or denying access permission to the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
+				     u32 device_id, u32 flags);
+
+/**
+ * scmi_base_set_protocol_permissions - configure access permission to
+ *					protocol on device
+ * @dev:	SCMI protocol device
+ * @agent_id:	SCMI agent ID
+ * @device_id:	ID of device to access
+ * @command_id:	SCMI command ID
+ * @flags:	A set of flags
+ *
+ * Ask for allowing or denying access permission to the protocol, @command_id,
+ * on the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_set_protocol_permissions(struct udevice *dev,
+				       u32 agent_id, u32 device_id,
+				       u32 command_id, u32 flags);
+
+/**
+ * scmi_base_reset_agent_configuration - reset resource settings
+ * @dev:	SCMI protocol device
+ * @agent_id:	SCMI agent ID
+ * @flags:	A set of flags
+ *
+ * Reset all the resource settings against @agent_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
+					u32 flags);
+
+/*
  * SCMI Clock Protocol
  */
 
diff --git a/test/dm/scmi.c b/test/dm/scmi.c
index d87e273..d4ff60e 100644
--- a/test/dm/scmi.c
+++ b/test/dm/scmi.c
@@ -16,6 +16,9 @@
 #include <clk.h>
 #include <dm.h>
 #include <reset.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
 #include <asm/scmi_test.h>
 #include <dm/device-internal.h>
 #include <dm/test.h>
@@ -23,22 +26,11 @@
 #include <power/regulator.h>
 #include <test/ut.h>
 
-static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts)
-{
-	struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx();
-
-	ut_assertnonnull(scmi_ctx);
-	ut_assertnull(scmi_ctx->agent);
-
-	return 0;
-}
-
 static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts,
+					  struct sandbox_scmi_agent *agent,
 					  struct udevice *dev)
 {
 	struct sandbox_scmi_devices *scmi_devices;
-	struct sandbox_scmi_service *scmi_ctx;
-	struct sandbox_scmi_agent *agent;
 
 	/* Device references to check context against test sequence */
 	scmi_devices = sandbox_scmi_devices_ctx(dev);
@@ -48,10 +40,6 @@
 	ut_asserteq(2, scmi_devices->regul_count);
 
 	/* State of the simulated SCMI server exposed */
-	scmi_ctx = sandbox_scmi_service_ctx();
-	ut_assertnonnull(scmi_ctx);
-	agent = scmi_ctx->agent;
-	ut_assertnonnull(agent);
 	ut_asserteq(3, agent->clk_count);
 	ut_assertnonnull(agent->clk);
 	ut_asserteq(1, agent->reset_count);
@@ -63,27 +51,32 @@
 }
 
 static int load_sandbox_scmi_test_devices(struct unit_test_state *uts,
+					  struct sandbox_scmi_agent **ctx,
 					  struct udevice **dev)
 {
-	int ret;
+	struct udevice *agent_dev;
 
-	ret = ut_assert_scmi_state_preprobe(uts);
-	if (ret)
-		return ret;
+	ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
+					      &agent_dev));
+	ut_assertnonnull(agent_dev);
 
+	*ctx = sandbox_scmi_agent_ctx(agent_dev);
+	ut_assertnonnull(*ctx);
+
+	/* probe */
 	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi",
 					      dev));
 	ut_assertnonnull(*dev);
 
-	return ut_assert_scmi_state_postprobe(uts, *dev);
+	return ut_assert_scmi_state_postprobe(uts, *ctx, *dev);
 }
 
 static int release_sandbox_scmi_test_devices(struct unit_test_state *uts,
 					     struct udevice *dev)
 {
+	/* un-probe */
 	ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
 
-	/* Not sure test devices are fully removed, agent may not be visible */
 	return 0;
 }
 
@@ -93,10 +86,11 @@
  */
 static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts)
 {
+	struct sandbox_scmi_agent *ctx;
 	struct udevice *dev = NULL;
 	int ret;
 
-	ret = load_sandbox_scmi_test_devices(uts, &dev);
+	ret = load_sandbox_scmi_test_devices(uts, &ctx, &dev);
 	if (!ret)
 		ret = release_sandbox_scmi_test_devices(uts, dev);
 
@@ -104,25 +98,136 @@
 }
 DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);
 
+static int dm_test_scmi_base(struct unit_test_state *uts)
+{
+	struct udevice *agent_dev, *base;
+	struct scmi_agent_priv *priv;
+	u32 version, num_agents, num_protocols, impl_version;
+	u32 attributes, agent_id;
+	u8 *vendor, *agent_name, *protocols;
+	int ret;
+
+	/* preparation */
+	ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
+					      &agent_dev));
+	ut_assertnonnull(agent_dev);
+	ut_assertnonnull(priv = dev_get_uclass_plat(agent_dev));
+	ut_assertnonnull(base = scmi_get_protocol(agent_dev,
+						  SCMI_PROTOCOL_ID_BASE));
+
+	/* version */
+	ret = scmi_base_protocol_version(base, &version);
+	ut_assertok(ret);
+	ut_asserteq(priv->version, version);
+
+	/* protocol attributes */
+	ret = scmi_base_protocol_attrs(base, &num_agents, &num_protocols);
+	ut_assertok(ret);
+	ut_asserteq(priv->num_agents, num_agents);
+	ut_asserteq(priv->num_protocols, num_protocols);
+
+	/* discover vendor */
+	ret = scmi_base_discover_vendor(base, &vendor);
+	ut_assertok(ret);
+	ut_asserteq_str(priv->vendor, vendor);
+	free(vendor);
+
+	/* message attributes */
+	ret = scmi_base_protocol_message_attrs(base,
+					       SCMI_BASE_DISCOVER_SUB_VENDOR,
+					       &attributes);
+	ut_assertok(ret);
+	ut_assertok(attributes);
+
+	/* discover sub vendor */
+	ret = scmi_base_discover_sub_vendor(base, &vendor);
+	ut_assertok(ret);
+	ut_asserteq_str(priv->sub_vendor, vendor);
+	free(vendor);
+
+	/* impl version */
+	ret = scmi_base_discover_impl_version(base, &impl_version);
+	ut_assertok(ret);
+	ut_asserteq(priv->impl_version, impl_version);
+
+	/* discover agent (my self) */
+	ret = scmi_base_discover_agent(base, 0xffffffff, &agent_id,
+				       &agent_name);
+	ut_assertok(ret);
+	ut_asserteq(priv->agent_id, agent_id);
+	ut_asserteq_str(priv->agent_name, agent_name);
+	free(agent_name);
+
+	/* discover protocols */
+	ret = scmi_base_discover_list_protocols(base, &protocols);
+	ut_asserteq(num_protocols, ret);
+	ut_asserteq_mem(priv->protocols, protocols, sizeof(u8) * num_protocols);
+	free(protocols);
+
+	/*
+	 * NOTE: Sandbox SCMI driver handles device-0 only. It supports setting
+	 * access and protocol permissions, but doesn't allow unsetting them nor
+	 * resetting the configurations.
+	 */
+	/* set device permissions */
+	ret = scmi_base_set_device_permissions(base, agent_id, 0,
+					       SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
+	ut_assertok(ret); /* SCMI_SUCCESS */
+	ret = scmi_base_set_device_permissions(base, agent_id, 1,
+					       SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
+	ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
+	ret = scmi_base_set_device_permissions(base, agent_id, 0, 0);
+	ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
+
+	/* set protocol permissions */
+	ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
+						 SCMI_PROTOCOL_ID_CLOCK,
+						 SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
+	ut_assertok(ret); /* SCMI_SUCCESS */
+	ret = scmi_base_set_protocol_permissions(base, agent_id, 1,
+						 SCMI_PROTOCOL_ID_CLOCK,
+						 SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
+	ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
+	ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
+						 SCMI_PROTOCOL_ID_CLOCK, 0);
+	ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
+
+	/* reset agent configuration */
+	ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
+	ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
+	ret = scmi_base_reset_agent_configuration(base, agent_id,
+						  SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS);
+	ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
+	ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
+	ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
+
+	return 0;
+}
+
+DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT);
+
 static int dm_test_scmi_clocks(struct unit_test_state *uts)
 {
-	struct sandbox_scmi_devices *scmi_devices;
-	struct sandbox_scmi_service *scmi_ctx;
 	struct sandbox_scmi_agent *agent;
-	struct udevice *dev;
+	struct sandbox_scmi_devices *scmi_devices;
+	struct udevice *agent_dev, *clock_dev, *dev;
 	int ret_dev;
 	int ret;
 
-	ret = load_sandbox_scmi_test_devices(uts, &dev);
+	ret = load_sandbox_scmi_test_devices(uts, &agent, &dev);
 	if (ret)
 		return ret;
 
 	scmi_devices = sandbox_scmi_devices_ctx(dev);
 	ut_assertnonnull(scmi_devices);
-	scmi_ctx = sandbox_scmi_service_ctx();
-	ut_assertnonnull(scmi_ctx);
-	agent = scmi_ctx->agent;
-	ut_assertnonnull(agent);
+
+	/* Sandbox SCMI clock protocol has its own channel */
+	ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
+					      &agent_dev));
+	ut_assertnonnull(agent_dev);
+	clock_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_CLOCK);
+	ut_assertnonnull(clock_dev);
+	ut_asserteq(0x14, sandbox_scmi_channel_id(clock_dev));
 
 	/* Test SCMI clocks rate manipulation */
 	ut_asserteq(333, agent->clk[0].rate);
@@ -169,22 +274,25 @@
 
 static int dm_test_scmi_resets(struct unit_test_state *uts)
 {
-	struct sandbox_scmi_devices *scmi_devices;
-	struct sandbox_scmi_service *scmi_ctx;
 	struct sandbox_scmi_agent *agent;
-	struct udevice *dev = NULL;
+	struct sandbox_scmi_devices *scmi_devices;
+	struct udevice *agent_dev, *reset_dev, *dev = NULL;
 	int ret;
 
-	ret = load_sandbox_scmi_test_devices(uts, &dev);
+	ret = load_sandbox_scmi_test_devices(uts, &agent, &dev);
 	if (ret)
 		return ret;
 
 	scmi_devices = sandbox_scmi_devices_ctx(dev);
 	ut_assertnonnull(scmi_devices);
-	scmi_ctx = sandbox_scmi_service_ctx();
-	ut_assertnonnull(scmi_ctx);
-	agent = scmi_ctx->agent;
-	ut_assertnonnull(agent);
+
+	/* Sandbox SCMI reset protocol doesn't have its own channel */
+	ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
+					      &agent_dev));
+	ut_assertnonnull(agent_dev);
+	reset_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_RESET_DOMAIN);
+	ut_assertnonnull(reset_dev);
+	ut_asserteq(0x0, sandbox_scmi_channel_id(reset_dev));
 
 	/* Test SCMI resect controller manipulation */
 	ut_assert(!agent->reset[0].asserted);
@@ -201,21 +309,16 @@
 
 static int dm_test_scmi_voltage_domains(struct unit_test_state *uts)
 {
-	struct sandbox_scmi_devices *scmi_devices;
-	struct sandbox_scmi_service *scmi_ctx;
 	struct sandbox_scmi_agent *agent;
+	struct sandbox_scmi_devices *scmi_devices;
 	struct dm_regulator_uclass_plat *uc_pdata;
 	struct udevice *dev;
 	struct udevice *regul0_dev;
 
-	ut_assertok(load_sandbox_scmi_test_devices(uts, &dev));
+	ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev));
 
 	scmi_devices = sandbox_scmi_devices_ctx(dev);
 	ut_assertnonnull(scmi_devices);
-	scmi_ctx = sandbox_scmi_service_ctx();
-	ut_assertnonnull(scmi_ctx);
-	agent = scmi_ctx->agent;
-	ut_assertnonnull(agent);
 
 	/* Set/Get an SCMI voltage domain level */
 	regul0_dev = scmi_devices->regul[0];