firmware: scmi: mailbox transport: implement multi-channel

Updates SCMI mailbox transport driver to get SCMI channel reference
at initialization and use when posting SCMI messages.

Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
index aa4929a..e63b67c 100644
--- a/drivers/firmware/scmi/mailbox_agent.c
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -31,6 +31,14 @@
 	ulong timeout_us;
 };
 
+/**
+ * struct scmi_channel - Channel instance referenced in SCMI drivers
+ * @ref: Reference to local channel instance
+ **/
+struct scmi_channel {
+	struct scmi_mbox_channel ref;
+};
+
 static int scmi_mbox_process_msg(struct udevice *dev,
 				 struct scmi_channel *channel,
 				 struct scmi_msg *msg)
@@ -38,6 +46,10 @@
 	struct scmi_mbox_channel *chan = dev_get_plat(dev);
 	int ret;
 
+	/* Support SCMI drivers upgraded to of_get_channel operator */
+	if (channel)
+		chan = &channel->ref;
+
 	ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
 	if (ret)
 		return ret;
@@ -64,13 +76,10 @@
 	return ret;
 }
 
-int scmi_mbox_of_to_plat(struct udevice *dev)
+static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
 {
-	struct scmi_mbox_channel *chan = dev_get_plat(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);
@@ -78,10 +87,51 @@
 	}
 
 	ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
-	if (ret)
+	if (ret) {
 		dev_err(dev, "Failed to get shm resources: %d\n", ret);
+		return ret;
+	}
 
-	return ret;
+	chan->timeout_us = TIMEOUT_US_10MS;
+
+	return 0;
+}
+
+static int scmi_mbox_get_channel(struct udevice *dev,
+				 struct scmi_channel **channel)
+{
+	struct scmi_mbox_channel *base_chan = dev_get_plat(dev->parent);
+	struct scmi_mbox_channel *chan;
+	int ret;
+
+	if (!dev_read_prop(dev, "shmem", NULL)) {
+		/* Uses agent base channel */
+		*channel = container_of(base_chan, struct scmi_channel, ref);
+
+		return 0;
+	}
+
+	chan = calloc(1, sizeof(*chan));
+	if (!chan)
+		return -ENOMEM;
+
+	/* Setup a dedicated channel for the protocol */
+	ret = setup_channel(dev, chan);
+	if (ret) {
+		free(chan);
+		return ret;
+	}
+
+	*channel = (void *)chan;
+
+	return 0;
+}
+
+int scmi_mbox_of_to_plat(struct udevice *dev)
+{
+	struct scmi_mbox_channel *chan = dev_get_plat(dev);
+
+	return setup_channel(dev, chan);
 }
 
 static const struct udevice_id scmi_mbox_ids[] = {
@@ -90,6 +140,7 @@
 };
 
 static const struct scmi_agent_ops scmi_mbox_ops = {
+	.of_get_channel = scmi_mbox_get_channel,
 	.process_msg = scmi_mbox_process_msg,
 };