Commit ba879dfc authored by Anup Patel's avatar Anup Patel Committed by Paul Walmsley
Browse files

mailbox: Allow controller specific mapping using fwnode



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: default avatarJassi Brar <jassisinghbrar@gmail.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarAnup Patel <apatel@ventanamicro.com>
Link: https://lore.kernel.org/r/20250818040920.272664-6-apatel@ventanamicro.com


Signed-off-by: default avatarPaul Walmsley <pjw@kernel.org>
parent 340974c4
Loading
Loading
Loading
Loading
+40 −25
Original line number Diff line number Diff line
@@ -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);
	}

	fwnode = dev_fwnode(dev);
	if (!fwnode) {
		dev_dbg(dev, "No owner fwnode\n");
		return ERR_PTR(-ENODEV);
	}

	ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
					 index, &spec);
	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) {
		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);
+3 −0
Original line number Diff line number Diff line
@@ -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 */