]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
firmware: scmi: smccc transport: implement multi-channel
authorEtienne Carriere <etienne.carriere@linaro.org>
Tue, 31 May 2022 16:09:23 +0000 (18:09 +0200)
committerTom Rini <trini@konsulko.com>
Thu, 23 Jun 2022 17:12:55 +0000 (13:12 -0400)
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>
drivers/firmware/scmi/smccc_agent.c

index b7a930b24df11a99b6134c63c4f5729cb057a448..73a7e0a844aa07695ea09d8b877758dd1b4615a1 100644 (file)
@@ -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,
 };