]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mailbox: Allow controller specific mapping using fwnode
authorAnup Patel <apatel@ventanamicro.com>
Mon, 18 Aug 2025 04:09:01 +0000 (09:39 +0530)
committerPaul Walmsley <pjw@kernel.org>
Thu, 25 Sep 2025 01:32:00 +0000 (19:32 -0600)
Introduce optional fw_node() callback which allows a mailbox controller
driver to provide controller specific mapping using fwnode.

The Linux OF framework already implements fwnode operations for the
Linux DD framework so the fw_xlate() callback works fine with device
tree as well.

Acked-by: Jassi Brar <jassisinghbrar@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Link: https://lore.kernel.org/r/20250818040920.272664-6-apatel@ventanamicro.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
drivers/mailbox/mailbox.c
include/linux/mailbox_controller.h

index 5cd8ae22207309fadbe8fe7f6fd8b4bc2c345cfd..2acc6ec229a4580b345ae4e2cc28bce3349c7db8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/property.h>
 #include <linux/spinlock.h>
 
 #include "mailbox.h"
@@ -383,34 +384,56 @@ EXPORT_SYMBOL_GPL(mbox_bind_client);
  */
 struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
 {
-       struct device *dev = cl->dev;
+       struct fwnode_reference_args fwspec;
+       struct fwnode_handle *fwnode;
        struct mbox_controller *mbox;
        struct of_phandle_args spec;
        struct mbox_chan *chan;
+       struct device *dev;
+       unsigned int i;
        int ret;
 
-       if (!dev || !dev->of_node) {
-               pr_debug("%s: No owner device node\n", __func__);
+       dev = cl->dev;
+       if (!dev) {
+               pr_debug("No owner device\n");
                return ERR_PTR(-ENODEV);
        }
 
-       ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
-                                        index, &spec);
+       fwnode = dev_fwnode(dev);
+       if (!fwnode) {
+               dev_dbg(dev, "No owner fwnode\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       ret = fwnode_property_get_reference_args(fwnode, "mboxes", "#mbox-cells",
+                                                0, index, &fwspec);
        if (ret) {
-               dev_err(dev, "%s: can't parse \"mboxes\" property\n", __func__);
+               dev_err(dev, "%s: can't parse \"%s\" property\n", __func__, "mboxes");
                return ERR_PTR(ret);
        }
 
+       spec.np = to_of_node(fwspec.fwnode);
+       spec.args_count = fwspec.nargs;
+       for (i = 0; i < spec.args_count; i++)
+               spec.args[i] = fwspec.args[i];
+
        scoped_guard(mutex, &con_mutex) {
                chan = ERR_PTR(-EPROBE_DEFER);
-               list_for_each_entry(mbox, &mbox_cons, node)
-                       if (mbox->dev->of_node == spec.np) {
-                               chan = mbox->of_xlate(mbox, &spec);
-                               if (!IS_ERR(chan))
-                                       break;
+               list_for_each_entry(mbox, &mbox_cons, node) {
+                       if (device_match_fwnode(mbox->dev, fwspec.fwnode)) {
+                               if (mbox->fw_xlate) {
+                                       chan = mbox->fw_xlate(mbox, &fwspec);
+                                       if (!IS_ERR(chan))
+                                               break;
+                               } else if (mbox->of_xlate) {
+                                       chan = mbox->of_xlate(mbox, &spec);
+                                       if (!IS_ERR(chan))
+                                               break;
+                               }
                        }
+               }
 
-               of_node_put(spec.np);
+               fwnode_handle_put(fwspec.fwnode);
 
                if (IS_ERR(chan))
                        return chan;
@@ -427,15 +450,8 @@ EXPORT_SYMBOL_GPL(mbox_request_channel);
 struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
                                              const char *name)
 {
-       struct device_node *np = cl->dev->of_node;
-       int index;
-
-       if (!np) {
-               dev_err(cl->dev, "%s() currently only supports DT\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       int index = device_property_match_string(cl->dev, "mbox-names", name);
 
-       index = of_property_match_string(np, "mbox-names", name);
        if (index < 0) {
                dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
                        __func__, name);
@@ -470,9 +486,8 @@ void mbox_free_channel(struct mbox_chan *chan)
 }
 EXPORT_SYMBOL_GPL(mbox_free_channel);
 
-static struct mbox_chan *
-of_mbox_index_xlate(struct mbox_controller *mbox,
-                   const struct of_phandle_args *sp)
+static struct mbox_chan *fw_mbox_index_xlate(struct mbox_controller *mbox,
+                                            const struct fwnode_reference_args *sp)
 {
        int ind = sp->args[0];
 
@@ -523,8 +538,8 @@ int mbox_controller_register(struct mbox_controller *mbox)
                spin_lock_init(&chan->lock);
        }
 
-       if (!mbox->of_xlate)
-               mbox->of_xlate = of_mbox_index_xlate;
+       if (!mbox->fw_xlate && !mbox->of_xlate)
+               mbox->fw_xlate = fw_mbox_index_xlate;
 
        scoped_guard(mutex, &con_mutex)
                list_add_tail(&mbox->node, &mbox_cons);
index ad01c4082358648c4ba51a7f73554bc1bbf80c78..80a427c7ca299f0addfcfdf9d2878cdd87cc404f 100644 (file)
@@ -66,6 +66,7 @@ struct mbox_chan_ops {
  *                     no interrupt rises. Ignored if 'txdone_irq' is set.
  * @txpoll_period:     If 'txdone_poll' is in effect, the API polls for
  *                     last TX's status after these many millisecs
+ * @fw_xlate:          Controller driver specific mapping of channel via fwnode
  * @of_xlate:          Controller driver specific mapping of channel via DT
  * @poll_hrt:          API private. hrtimer used to poll for TXDONE on all
  *                     channels.
@@ -79,6 +80,8 @@ struct mbox_controller {
        bool txdone_irq;
        bool txdone_poll;
        unsigned txpoll_period;
+       struct mbox_chan *(*fw_xlate)(struct mbox_controller *mbox,
+                                     const struct fwnode_reference_args *sp);
        struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
                                      const struct of_phandle_args *sp);
        /* Internal to API */