Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 791cc88c authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'mailbox-for-v3.18' of...

Merge tag 'mailbox-for-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers

Mailbox related changes for omaps to get it to work with
device tree.

* tag 'mailbox-for-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap

:
  mailbox/omap: add support for parsing dt devices
  Documentation: dt: add omap mailbox bindings

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 9cdf6bd5 75288cc6
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
OMAP2+ Mailbox Driver
=====================

The OMAP mailbox hardware facilitates communication between different processors
using a queued mailbox interrupt mechanism. The IP block is external to the
various processor subsystems and is connected on an interconnect bus. The
communication is achieved through a set of registers for message storage and
interrupt configuration registers.

Each mailbox IP block has a certain number of h/w fifo queues and output
interrupt lines. An output interrupt line is routed to an interrupt controller
within a processor subsystem, and there can be more than one line going to a
specific processor's interrupt controller. The interrupt line connections are
fixed for an instance and are dictated by the IP integration into the SoC
(excluding the SoCs that have a Interrupt Crossbar IP). Each interrupt line is
programmable through a set of interrupt configuration registers, and have a rx
and tx interrupt source per h/w fifo. Communication between different processors
is achieved through the appropriate programming of the rx and tx interrupt
sources on the appropriate interrupt lines.

The number of h/w fifo queues and interrupt lines dictate the usable registers.
All the current OMAP SoCs except for the newest DRA7xx SoC has a single IP
instance. DRA7xx has multiple instances with different number of h/w fifo queues
and interrupt lines between different instances. The interrupt lines can also be
routed to different processor sub-systems on DRA7xx as they are routed through
the Crossbar, a kind of interrupt router/multiplexer.

Mailbox Device Node:
====================
A Mailbox device node is used to represent a Mailbox IP instance within a SoC.
The sub-mailboxes are represented as child nodes of this parent node.

Required properties:
--------------------
- compatible:		Should be one of the following,
			    "ti,omap2-mailbox" for OMAP2420, OMAP2430 SoCs
			    "ti,omap3-mailbox" for OMAP3430, OMAP3630 SoCs
			    "ti,omap4-mailbox" for OMAP44xx, OMAP54xx, AM33xx,
						   AM43xx and DRA7xx SoCs
- reg:			Contains the mailbox register address range (base
			address and length)
- interrupts:		Contains the interrupt information for the mailbox
			device. The format is dependent on which interrupt
			controller the OMAP device uses
- ti,hwmods:		Name of the hwmod associated with the mailbox
- ti,mbox-num-users:	Number of targets (processor devices) that the mailbox
			device can interrupt
- ti,mbox-num-fifos:	Number of h/w fifo queues within the mailbox IP block

Child Nodes:
============
A child node is used for representing the actual sub-mailbox device that is
used for the communication between the host processor and a remote processor.
Each child node should have a unique node name across all the different
mailbox device nodes.

Required properties:
--------------------
- ti,mbox-tx:		sub-mailbox descriptor property defining a Tx fifo
- ti,mbox-rx:		sub-mailbox descriptor property defining a Rx fifo

Sub-mailbox Descriptor Data
---------------------------
Each of the above ti,mbox-tx and ti,mbox-rx properties should have 3 cells of
data that represent the following:
    Cell #1 (fifo_id) - mailbox fifo id used either for transmitting
                        (ti,mbox-tx) or for receiving (ti,mbox-rx)
    Cell #2 (irq_id)  - irq identifier index number to use from the parent's
                        interrupts data. Should be 0 for most of the cases, a
                        positive index value is seen only on mailboxes that have
                        multiple interrupt lines connected to the MPU processor.
    Cell #3 (usr_id)  - mailbox user id for identifying the interrupt line
                        associated with generating a tx/rx fifo interrupt.

Example:
--------

/* OMAP4 */
mailbox: mailbox@4a0f4000 {
	compatible = "ti,omap4-mailbox";
	reg = <0x4a0f4000 0x200>;
	interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
	ti,hwmods = "mailbox";
	ti,mbox-num-users = <3>;
	ti,mbox-num-fifos = <8>;
	mbox_ipu: mbox_ipu {
		ti,mbox-tx = <0 0 0>;
		ti,mbox-rx = <1 0 0>;
	};
	mbox_dsp: mbox_dsp {
		ti,mbox-tx = <3 0 0>;
		ti,mbox-rx = <2 0 0>;
	};
};

/* AM33xx */
mailbox: mailbox@480C8000 {
	compatible = "ti,omap4-mailbox";
	reg = <0x480C8000 0x200>;
	interrupts = <77>;
	ti,hwmods = "mailbox";
	ti,mbox-num-users = <4>;
	ti,mbox-num-fifos = <8>;
	mbox_wkupm3: wkup_m3 {
		ti,mbox-tx = <0 0 0>;
		ti,mbox-rx = <0 0 3>;
	};
};
+132 −24
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/notifier.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mailbox-omap.h>
@@ -94,6 +95,18 @@ struct omap_mbox_device {
	struct list_head elem;
};

struct omap_mbox_fifo_info {
	int tx_id;
	int tx_usr;
	int tx_irq;

	int rx_id;
	int rx_usr;
	int rx_irq;

	const char *name;
};

struct omap_mbox {
	const char		*name;
	int			irq;
@@ -587,24 +600,118 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev)
	return 0;
}

static const struct of_device_id omap_mailbox_of_match[] = {
	{
		.compatible	= "ti,omap2-mailbox",
		.data		= (void *)MBOX_INTR_CFG_TYPE1,
	},
	{
		.compatible	= "ti,omap3-mailbox",
		.data		= (void *)MBOX_INTR_CFG_TYPE1,
	},
	{
		.compatible	= "ti,omap4-mailbox",
		.data		= (void *)MBOX_INTR_CFG_TYPE2,
	},
	{
		/* end */
	},
};
MODULE_DEVICE_TABLE(of, omap_mailbox_of_match);

static int omap_mbox_probe(struct platform_device *pdev)
{
	struct resource *mem;
	int ret;
	struct omap_mbox **list, *mbox, *mboxblk;
	struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
	struct omap_mbox_dev_info *info;
	struct omap_mbox_dev_info *info = NULL;
	struct omap_mbox_fifo_info *finfo, *finfoblk;
	struct omap_mbox_device *mdev;
	struct omap_mbox_fifo *fifo;
	u32 intr_type;
	struct device_node *node = pdev->dev.of_node;
	struct device_node *child;
	const struct of_device_id *match;
	u32 intr_type, info_count;
	u32 num_users, num_fifos;
	u32 tmp[3];
	u32 l;
	int i;

	if (!pdata || !pdata->info_cnt || !pdata->info) {
	if (!node && (!pdata || !pdata->info_cnt || !pdata->info)) {
		pr_err("%s: platform not supported\n", __func__);
		return -ENODEV;
	}

	if (node) {
		match = of_match_device(omap_mailbox_of_match, &pdev->dev);
		if (!match)
			return -ENODEV;
		intr_type = (u32)match->data;

		if (of_property_read_u32(node, "ti,mbox-num-users",
					 &num_users))
			return -ENODEV;

		if (of_property_read_u32(node, "ti,mbox-num-fifos",
					 &num_fifos))
			return -ENODEV;

		info_count = of_get_available_child_count(node);
		if (!info_count) {
			dev_err(&pdev->dev, "no available mbox devices found\n");
			return -ENODEV;
		}
	} else { /* non-DT device creation */
		info_count = pdata->info_cnt;
		info = pdata->info;
		intr_type = pdata->intr_type;
		num_users = pdata->num_users;
		num_fifos = pdata->num_fifos;
	}

	finfoblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*finfoblk),
				GFP_KERNEL);
	if (!finfoblk)
		return -ENOMEM;

	finfo = finfoblk;
	child = NULL;
	for (i = 0; i < info_count; i++, finfo++) {
		if (node) {
			child = of_get_next_available_child(node, child);
			ret = of_property_read_u32_array(child, "ti,mbox-tx",
							 tmp, ARRAY_SIZE(tmp));
			if (ret)
				return ret;
			finfo->tx_id = tmp[0];
			finfo->tx_irq = tmp[1];
			finfo->tx_usr = tmp[2];

			ret = of_property_read_u32_array(child, "ti,mbox-rx",
							 tmp, ARRAY_SIZE(tmp));
			if (ret)
				return ret;
			finfo->rx_id = tmp[0];
			finfo->rx_irq = tmp[1];
			finfo->rx_usr = tmp[2];

			finfo->name = child->name;
		} else {
			finfo->tx_id = info->tx_id;
			finfo->rx_id = info->rx_id;
			finfo->tx_usr = info->usr_id;
			finfo->tx_irq = info->irq_id;
			finfo->rx_usr = info->usr_id;
			finfo->rx_irq = info->irq_id;
			finfo->name = info->name;
			info++;
		}
		if (finfo->tx_id >= num_fifos || finfo->rx_id >= num_fifos ||
		    finfo->tx_usr >= num_users || finfo->rx_usr >= num_users)
			return -EINVAL;
	}

	mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
	if (!mdev)
		return -ENOMEM;
@@ -615,41 +722,40 @@ static int omap_mbox_probe(struct platform_device *pdev)
		return PTR_ERR(mdev->mbox_base);

	/* allocate one extra for marking end of list */
	list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
	list = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*list),
			    GFP_KERNEL);
	if (!list)
		return -ENOMEM;

	mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
	mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox),
			       GFP_KERNEL);
	if (!mboxblk)
		return -ENOMEM;

	info = pdata->info;
	intr_type = pdata->intr_type;
	mbox = mboxblk;
	for (i = 0; i < pdata->info_cnt; i++, info++) {
	finfo = finfoblk;
	for (i = 0; i < info_count; i++, finfo++) {
		fifo = &mbox->tx_fifo;
		fifo->msg = MAILBOX_MESSAGE(info->tx_id);
		fifo->fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
		fifo->intr_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
		fifo->msg = MAILBOX_MESSAGE(finfo->tx_id);
		fifo->fifo_stat = MAILBOX_FIFOSTATUS(finfo->tx_id);
		fifo->intr_bit = MAILBOX_IRQ_NOTFULL(finfo->tx_id);
		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->tx_usr);
		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->tx_usr);
		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->tx_usr);

		fifo = &mbox->rx_fifo;
		fifo->msg =  MAILBOX_MESSAGE(info->rx_id);
		fifo->msg_stat =  MAILBOX_MSGSTATUS(info->rx_id);
		fifo->intr_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
		fifo->msg = MAILBOX_MESSAGE(finfo->rx_id);
		fifo->msg_stat =  MAILBOX_MSGSTATUS(finfo->rx_id);
		fifo->intr_bit = MAILBOX_IRQ_NEWMSG(finfo->rx_id);
		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->rx_usr);
		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->rx_usr);
		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->rx_usr);

		mbox->intr_type = intr_type;

		mbox->parent = mdev;
		mbox->name = info->name;
		mbox->irq = platform_get_irq(pdev, info->irq_id);
		mbox->name = finfo->name;
		mbox->irq = platform_get_irq(pdev, finfo->tx_irq);
		if (mbox->irq < 0)
			return mbox->irq;
		list[i] = mbox++;
@@ -657,8 +763,8 @@ static int omap_mbox_probe(struct platform_device *pdev)

	mutex_init(&mdev->cfg_lock);
	mdev->dev = &pdev->dev;
	mdev->num_users = pdata->num_users;
	mdev->num_fifos = pdata->num_fifos;
	mdev->num_users = num_users;
	mdev->num_fifos = num_fifos;
	mdev->mboxes = list;
	ret = omap_mbox_register(mdev);
	if (ret)
@@ -684,6 +790,7 @@ static int omap_mbox_probe(struct platform_device *pdev)
	if (ret < 0)
		goto unregister;

	devm_kfree(&pdev->dev, finfoblk);
	return 0;

unregister:
@@ -708,6 +815,7 @@ static struct platform_driver omap_mbox_driver = {
	.driver	= {
		.name = "omap-mailbox",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(omap_mailbox_of_match),
	},
};