diff mbox series

[v2,08/14] firmware: scmi: smccc transport: implement multi-channel

Message ID 20220531160929.931150-9-etienne.carriere@linaro.org
State New
Headers show
Series SCMI multi-channel and optee shm | expand

Commit Message

Etienne Carriere May 31, 2022, 4:09 p.m. UTC
Updates SCMI SMCCC transport driver to get SCMI channel reference
at initialization and use when posting SCMI messages.

Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
---
No change since v1.

---
 drivers/firmware/scmi/smccc_agent.c | 54 +++++++++++++++++++++++++++--
 1 file changed, 52 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
index b7a930b24df..73a7e0a844a 100644
--- a/drivers/firmware/scmi/smccc_agent.c
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -30,6 +30,14 @@  struct scmi_smccc_channel {
 	struct scmi_smt smt;
 };
 
+/**
+ * struct scmi_channel - Channel instance referenced in SCMI drivers
+ * @ref: Reference to local channel instance
+ **/
+struct scmi_channel {
+	struct scmi_smccc_channel ref;
+};
+
 static int scmi_smccc_process_msg(struct udevice *dev,
 				  struct scmi_channel *channel,
 				  struct scmi_msg *msg)
@@ -38,6 +46,10 @@  static int scmi_smccc_process_msg(struct udevice *dev,
 	struct arm_smccc_res res;
 	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;
@@ -53,9 +65,8 @@  static int scmi_smccc_process_msg(struct udevice *dev,
 	return ret;
 }
 
-static int scmi_smccc_of_to_plat(struct udevice *dev)
+static int setup_channel(struct udevice *dev, struct scmi_smccc_channel *chan)
 {
-	struct scmi_smccc_channel *chan = dev_get_plat(dev);
 	u32 func_id;
 	int ret;
 
@@ -73,12 +84,51 @@  static int scmi_smccc_of_to_plat(struct udevice *dev)
 	return ret;
 }
 
+static int scmi_smccc_get_channel(struct udevice *dev,
+				  struct scmi_channel **channel)
+{
+	struct scmi_smccc_channel *base_chan = dev_get_plat(dev->parent);
+	struct scmi_smccc_channel *chan;
+	u32 func_id;
+	int ret;
+
+	if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
+		/* Uses agent base channel */
+		*channel = container_of(base_chan, struct scmi_channel, ref);
+
+		return 0;
+	}
+
+	/* Setup a dedicated channel */
+	chan = calloc(1, sizeof(*chan));
+	if (!chan)
+		return -ENOMEM;
+
+	ret = setup_channel(dev, chan);
+	if (ret) {
+		free(chan);
+		return ret;
+	}
+
+	*channel = container_of(chan, struct scmi_channel, ref);
+
+	return 0;
+}
+
+static int scmi_smccc_of_to_plat(struct udevice *dev)
+{
+	struct scmi_smccc_channel *chan = dev_get_plat(dev);
+
+	return setup_channel(dev, chan);
+}
+
 static const struct udevice_id scmi_smccc_ids[] = {
 	{ .compatible = "arm,scmi-smc" },
 	{ }
 };
 
 static const struct scmi_agent_ops scmi_smccc_ops = {
+	.of_get_channel = scmi_smccc_get_channel,
 	.process_msg = scmi_smccc_process_msg,
 };