Commit ab460a2e authored by Bjorn Andersson's avatar Bjorn Andersson
Browse files

rpmsg: qcom_smd: Access APCS through mailbox framework



Attempt to acquire the APCS IPC through the mailbox framework and fall
back to the old syscon based approach, to allow us to move away from
using the syscon.

Reviewed-by: default avatarArun Kumar Neelakantam <aneela@codeaurora.org>
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent 39e47767
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -22,9 +22,15 @@ The edge is described by the following properties:
	Definition: should specify the IRQ used by the remote processor to
	Definition: should specify the IRQ used by the remote processor to
		    signal this processor about communication related updates
		    signal this processor about communication related updates


- qcom,ipc:
- mboxes:
	Usage: required
	Usage: required
	Value type: <prop-encoded-array>
	Value type: <prop-encoded-array>
	Definition: reference to the associated doorbell in APCS, as described
		    in mailbox/mailbox.txt

- qcom,ipc:
	Usage: required, unless mboxes is specified
	Value type: <prop-encoded-array>
	Definition: three entries specifying the outgoing ipc bit used for
	Definition: three entries specifying the outgoing ipc bit used for
		    signaling the remote processor:
		    signaling the remote processor:
		    - phandle to a syscon node representing the apcs registers
		    - phandle to a syscon node representing the apcs registers
+1 −0
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@ config RPMSG_QCOM_GLINK_SMEM


config RPMSG_QCOM_SMD
config RPMSG_QCOM_SMD
	tristate "Qualcomm Shared Memory Driver (SMD)"
	tristate "Qualcomm Shared Memory Driver (SMD)"
	depends on MAILBOX
	depends on QCOM_SMEM
	depends on QCOM_SMEM
	select RPMSG
	select RPMSG
	help
	help
+49 −19
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@


#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/mailbox_client.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_irq.h>
@@ -107,6 +108,8 @@ static const struct {
 * @ipc_regmap:		regmap handle holding the outgoing ipc register
 * @ipc_regmap:		regmap handle holding the outgoing ipc register
 * @ipc_offset:		offset within @ipc_regmap of the register for ipc
 * @ipc_offset:		offset within @ipc_regmap of the register for ipc
 * @ipc_bit:		bit in the register at @ipc_offset of @ipc_regmap
 * @ipc_bit:		bit in the register at @ipc_offset of @ipc_regmap
 * @mbox_client:	mailbox client handle
 * @mbox_chan:		apcs ipc mailbox channel handle
 * @channels:		list of all channels detected on this edge
 * @channels:		list of all channels detected on this edge
 * @channels_lock:	guard for modifications of @channels
 * @channels_lock:	guard for modifications of @channels
 * @allocated:		array of bitmaps representing already allocated channels
 * @allocated:		array of bitmaps representing already allocated channels
@@ -129,6 +132,9 @@ struct qcom_smd_edge {
	int ipc_offset;
	int ipc_offset;
	int ipc_bit;
	int ipc_bit;


	struct mbox_client mbox_client;
	struct mbox_chan *mbox_chan;

	struct list_head channels;
	struct list_head channels;
	spinlock_t channels_lock;
	spinlock_t channels_lock;


@@ -366,8 +372,18 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel)
{
{
	struct qcom_smd_edge *edge = channel->edge;
	struct qcom_smd_edge *edge = channel->edge;


	if (edge->mbox_chan) {
		/*
		 * We can ignore a failing mbox_send_message() as the only
		 * possible cause is that the FIFO in the framework is full of
		 * other writes to the same bit.
		 */
		mbox_send_message(edge->mbox_chan, NULL);
		mbox_client_txdone(edge->mbox_chan, 0);
	} else {
		regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
		regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
	}
	}
}


/*
/*
 * Initialize the tx channel info
 * Initialize the tx channel info
@@ -1326,6 +1342,15 @@ static int qcom_smd_parse_edge(struct device *dev,
	key = "qcom,remote-pid";
	key = "qcom,remote-pid";
	of_property_read_u32(node, key, &edge->remote_pid);
	of_property_read_u32(node, key, &edge->remote_pid);


	edge->mbox_client.dev = dev;
	edge->mbox_client.knows_txdone = true;
	edge->mbox_chan = mbox_request_channel(&edge->mbox_client, 0);
	if (IS_ERR(edge->mbox_chan)) {
		if (PTR_ERR(edge->mbox_chan) != -ENODEV)
			return PTR_ERR(edge->mbox_chan);

		edge->mbox_chan = NULL;

		syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
		syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
		if (!syscon_np) {
		if (!syscon_np) {
			dev_err(dev, "no qcom,ipc node\n");
			dev_err(dev, "no qcom,ipc node\n");
@@ -1348,6 +1373,7 @@ static int qcom_smd_parse_edge(struct device *dev,
			dev_err(dev, "no bit in %s\n", key);
			dev_err(dev, "no bit in %s\n", key);
			return -EINVAL;
			return -EINVAL;
		}
		}
	}


	ret = of_property_read_string(node, "label", &edge->name);
	ret = of_property_read_string(node, "label", &edge->name);
	if (ret < 0)
	if (ret < 0)
@@ -1453,6 +1479,9 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
	return edge;
	return edge;


unregister_dev:
unregister_dev:
	if (!IS_ERR_OR_NULL(edge->mbox_chan))
		mbox_free_channel(edge->mbox_chan);

	device_unregister(&edge->dev);
	device_unregister(&edge->dev);
	return ERR_PTR(ret);
	return ERR_PTR(ret);
}
}
@@ -1481,6 +1510,7 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
	if (ret)
	if (ret)
		dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
		dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);


	mbox_free_channel(edge->mbox_chan);
	device_unregister(&edge->dev);
	device_unregister(&edge->dev);


	return 0;
	return 0;