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

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
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>;
};
};
......@@ -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),
},
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment