diff options
author | Olof Johansson <olof@lixom.net> | 2014-09-24 01:10:18 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2014-09-24 01:10:27 -0400 |
commit | 791cc88c57b524b4267a9ea550b5306749fc7479 (patch) | |
tree | c7cd6c33f5c6a97e326e49fe1653df4774e23696 | |
parent | 9cdf6bd51030e8b80b752adc016719a5b5d75d50 (diff) | |
parent | 75288cc66dc478b32e43970dd6913396526504ae (diff) |
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: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/mailbox/omap-mailbox.txt | 108 | ||||
-rw-r--r-- | drivers/mailbox/omap-mailbox.c | 156 |
2 files changed, 240 insertions, 24 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt new file mode 100644 index 000000000000..48edc4b92afb --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt | |||
@@ -0,0 +1,108 @@ | |||
1 | OMAP2+ Mailbox Driver | ||
2 | ===================== | ||
3 | |||
4 | The OMAP mailbox hardware facilitates communication between different processors | ||
5 | using a queued mailbox interrupt mechanism. The IP block is external to the | ||
6 | various processor subsystems and is connected on an interconnect bus. The | ||
7 | communication is achieved through a set of registers for message storage and | ||
8 | interrupt configuration registers. | ||
9 | |||
10 | Each mailbox IP block has a certain number of h/w fifo queues and output | ||
11 | interrupt lines. An output interrupt line is routed to an interrupt controller | ||
12 | within a processor subsystem, and there can be more than one line going to a | ||
13 | specific processor's interrupt controller. The interrupt line connections are | ||
14 | fixed for an instance and are dictated by the IP integration into the SoC | ||
15 | (excluding the SoCs that have a Interrupt Crossbar IP). Each interrupt line is | ||
16 | programmable through a set of interrupt configuration registers, and have a rx | ||
17 | and tx interrupt source per h/w fifo. Communication between different processors | ||
18 | is achieved through the appropriate programming of the rx and tx interrupt | ||
19 | sources on the appropriate interrupt lines. | ||
20 | |||
21 | The number of h/w fifo queues and interrupt lines dictate the usable registers. | ||
22 | All the current OMAP SoCs except for the newest DRA7xx SoC has a single IP | ||
23 | instance. DRA7xx has multiple instances with different number of h/w fifo queues | ||
24 | and interrupt lines between different instances. The interrupt lines can also be | ||
25 | routed to different processor sub-systems on DRA7xx as they are routed through | ||
26 | the Crossbar, a kind of interrupt router/multiplexer. | ||
27 | |||
28 | Mailbox Device Node: | ||
29 | ==================== | ||
30 | A Mailbox device node is used to represent a Mailbox IP instance within a SoC. | ||
31 | The sub-mailboxes are represented as child nodes of this parent node. | ||
32 | |||
33 | Required properties: | ||
34 | -------------------- | ||
35 | - compatible: Should be one of the following, | ||
36 | "ti,omap2-mailbox" for OMAP2420, OMAP2430 SoCs | ||
37 | "ti,omap3-mailbox" for OMAP3430, OMAP3630 SoCs | ||
38 | "ti,omap4-mailbox" for OMAP44xx, OMAP54xx, AM33xx, | ||
39 | AM43xx and DRA7xx SoCs | ||
40 | - reg: Contains the mailbox register address range (base | ||
41 | address and length) | ||
42 | - interrupts: Contains the interrupt information for the mailbox | ||
43 | device. The format is dependent on which interrupt | ||
44 | controller the OMAP device uses | ||
45 | - ti,hwmods: Name of the hwmod associated with the mailbox | ||
46 | - ti,mbox-num-users: Number of targets (processor devices) that the mailbox | ||
47 | device can interrupt | ||
48 | - ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block | ||
49 | |||
50 | Child Nodes: | ||
51 | ============ | ||
52 | A child node is used for representing the actual sub-mailbox device that is | ||
53 | used for the communication between the host processor and a remote processor. | ||
54 | Each child node should have a unique node name across all the different | ||
55 | mailbox device nodes. | ||
56 | |||
57 | Required properties: | ||
58 | -------------------- | ||
59 | - ti,mbox-tx: sub-mailbox descriptor property defining a Tx fifo | ||
60 | - ti,mbox-rx: sub-mailbox descriptor property defining a Rx fifo | ||
61 | |||
62 | Sub-mailbox Descriptor Data | ||
63 | --------------------------- | ||
64 | Each of the above ti,mbox-tx and ti,mbox-rx properties should have 3 cells of | ||
65 | data that represent the following: | ||
66 | Cell #1 (fifo_id) - mailbox fifo id used either for transmitting | ||
67 | (ti,mbox-tx) or for receiving (ti,mbox-rx) | ||
68 | Cell #2 (irq_id) - irq identifier index number to use from the parent's | ||
69 | interrupts data. Should be 0 for most of the cases, a | ||
70 | positive index value is seen only on mailboxes that have | ||
71 | multiple interrupt lines connected to the MPU processor. | ||
72 | Cell #3 (usr_id) - mailbox user id for identifying the interrupt line | ||
73 | associated with generating a tx/rx fifo interrupt. | ||
74 | |||
75 | Example: | ||
76 | -------- | ||
77 | |||
78 | /* OMAP4 */ | ||
79 | mailbox: mailbox@4a0f4000 { | ||
80 | compatible = "ti,omap4-mailbox"; | ||
81 | reg = <0x4a0f4000 0x200>; | ||
82 | interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; | ||
83 | ti,hwmods = "mailbox"; | ||
84 | ti,mbox-num-users = <3>; | ||
85 | ti,mbox-num-fifos = <8>; | ||
86 | mbox_ipu: mbox_ipu { | ||
87 | ti,mbox-tx = <0 0 0>; | ||
88 | ti,mbox-rx = <1 0 0>; | ||
89 | }; | ||
90 | mbox_dsp: mbox_dsp { | ||
91 | ti,mbox-tx = <3 0 0>; | ||
92 | ti,mbox-rx = <2 0 0>; | ||
93 | }; | ||
94 | }; | ||
95 | |||
96 | /* AM33xx */ | ||
97 | mailbox: mailbox@480C8000 { | ||
98 | compatible = "ti,omap4-mailbox"; | ||
99 | reg = <0x480C8000 0x200>; | ||
100 | interrupts = <77>; | ||
101 | ti,hwmods = "mailbox"; | ||
102 | ti,mbox-num-users = <4>; | ||
103 | ti,mbox-num-fifos = <8>; | ||
104 | mbox_wkupm3: wkup_m3 { | ||
105 | ti,mbox-tx = <0 0 0>; | ||
106 | ti,mbox-rx = <0 0 3>; | ||
107 | }; | ||
108 | }; | ||
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index a27e00e63a8a..bcc7ee129276 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/err.h> | 31 | #include <linux/err.h> |
32 | #include <linux/notifier.h> | 32 | #include <linux/notifier.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/of_device.h> | ||
34 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
35 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
36 | #include <linux/platform_data/mailbox-omap.h> | 37 | #include <linux/platform_data/mailbox-omap.h> |
@@ -94,6 +95,18 @@ struct omap_mbox_device { | |||
94 | struct list_head elem; | 95 | struct list_head elem; |
95 | }; | 96 | }; |
96 | 97 | ||
98 | struct omap_mbox_fifo_info { | ||
99 | int tx_id; | ||
100 | int tx_usr; | ||
101 | int tx_irq; | ||
102 | |||
103 | int rx_id; | ||
104 | int rx_usr; | ||
105 | int rx_irq; | ||
106 | |||
107 | const char *name; | ||
108 | }; | ||
109 | |||
97 | struct omap_mbox { | 110 | struct omap_mbox { |
98 | const char *name; | 111 | const char *name; |
99 | int irq; | 112 | int irq; |
@@ -587,24 +600,118 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev) | |||
587 | return 0; | 600 | return 0; |
588 | } | 601 | } |
589 | 602 | ||
603 | static const struct of_device_id omap_mailbox_of_match[] = { | ||
604 | { | ||
605 | .compatible = "ti,omap2-mailbox", | ||
606 | .data = (void *)MBOX_INTR_CFG_TYPE1, | ||
607 | }, | ||
608 | { | ||
609 | .compatible = "ti,omap3-mailbox", | ||
610 | .data = (void *)MBOX_INTR_CFG_TYPE1, | ||
611 | }, | ||
612 | { | ||
613 | .compatible = "ti,omap4-mailbox", | ||
614 | .data = (void *)MBOX_INTR_CFG_TYPE2, | ||
615 | }, | ||
616 | { | ||
617 | /* end */ | ||
618 | }, | ||
619 | }; | ||
620 | MODULE_DEVICE_TABLE(of, omap_mailbox_of_match); | ||
621 | |||
590 | static int omap_mbox_probe(struct platform_device *pdev) | 622 | static int omap_mbox_probe(struct platform_device *pdev) |
591 | { | 623 | { |
592 | struct resource *mem; | 624 | struct resource *mem; |
593 | int ret; | 625 | int ret; |
594 | struct omap_mbox **list, *mbox, *mboxblk; | 626 | struct omap_mbox **list, *mbox, *mboxblk; |
595 | struct omap_mbox_pdata *pdata = pdev->dev.platform_data; | 627 | struct omap_mbox_pdata *pdata = pdev->dev.platform_data; |
596 | struct omap_mbox_dev_info *info; | 628 | struct omap_mbox_dev_info *info = NULL; |
629 | struct omap_mbox_fifo_info *finfo, *finfoblk; | ||
597 | struct omap_mbox_device *mdev; | 630 | struct omap_mbox_device *mdev; |
598 | struct omap_mbox_fifo *fifo; | 631 | struct omap_mbox_fifo *fifo; |
599 | u32 intr_type; | 632 | struct device_node *node = pdev->dev.of_node; |
633 | struct device_node *child; | ||
634 | const struct of_device_id *match; | ||
635 | u32 intr_type, info_count; | ||
636 | u32 num_users, num_fifos; | ||
637 | u32 tmp[3]; | ||
600 | u32 l; | 638 | u32 l; |
601 | int i; | 639 | int i; |
602 | 640 | ||
603 | if (!pdata || !pdata->info_cnt || !pdata->info) { | 641 | if (!node && (!pdata || !pdata->info_cnt || !pdata->info)) { |
604 | pr_err("%s: platform not supported\n", __func__); | 642 | pr_err("%s: platform not supported\n", __func__); |
605 | return -ENODEV; | 643 | return -ENODEV; |
606 | } | 644 | } |
607 | 645 | ||
646 | if (node) { | ||
647 | match = of_match_device(omap_mailbox_of_match, &pdev->dev); | ||
648 | if (!match) | ||
649 | return -ENODEV; | ||
650 | intr_type = (u32)match->data; | ||
651 | |||
652 | if (of_property_read_u32(node, "ti,mbox-num-users", | ||
653 | &num_users)) | ||
654 | return -ENODEV; | ||
655 | |||
656 | if (of_property_read_u32(node, "ti,mbox-num-fifos", | ||
657 | &num_fifos)) | ||
658 | return -ENODEV; | ||
659 | |||
660 | info_count = of_get_available_child_count(node); | ||
661 | if (!info_count) { | ||
662 | dev_err(&pdev->dev, "no available mbox devices found\n"); | ||
663 | return -ENODEV; | ||
664 | } | ||
665 | } else { /* non-DT device creation */ | ||
666 | info_count = pdata->info_cnt; | ||
667 | info = pdata->info; | ||
668 | intr_type = pdata->intr_type; | ||
669 | num_users = pdata->num_users; | ||
670 | num_fifos = pdata->num_fifos; | ||
671 | } | ||
672 | |||
673 | finfoblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*finfoblk), | ||
674 | GFP_KERNEL); | ||
675 | if (!finfoblk) | ||
676 | return -ENOMEM; | ||
677 | |||
678 | finfo = finfoblk; | ||
679 | child = NULL; | ||
680 | for (i = 0; i < info_count; i++, finfo++) { | ||
681 | if (node) { | ||
682 | child = of_get_next_available_child(node, child); | ||
683 | ret = of_property_read_u32_array(child, "ti,mbox-tx", | ||
684 | tmp, ARRAY_SIZE(tmp)); | ||
685 | if (ret) | ||
686 | return ret; | ||
687 | finfo->tx_id = tmp[0]; | ||
688 | finfo->tx_irq = tmp[1]; | ||
689 | finfo->tx_usr = tmp[2]; | ||
690 | |||
691 | ret = of_property_read_u32_array(child, "ti,mbox-rx", | ||
692 | tmp, ARRAY_SIZE(tmp)); | ||
693 | if (ret) | ||
694 | return ret; | ||
695 | finfo->rx_id = tmp[0]; | ||
696 | finfo->rx_irq = tmp[1]; | ||
697 | finfo->rx_usr = tmp[2]; | ||
698 | |||
699 | finfo->name = child->name; | ||
700 | } else { | ||
701 | finfo->tx_id = info->tx_id; | ||
702 | finfo->rx_id = info->rx_id; | ||
703 | finfo->tx_usr = info->usr_id; | ||
704 | finfo->tx_irq = info->irq_id; | ||
705 | finfo->rx_usr = info->usr_id; | ||
706 | finfo->rx_irq = info->irq_id; | ||
707 | finfo->name = info->name; | ||
708 | info++; | ||
709 | } | ||
710 | if (finfo->tx_id >= num_fifos || finfo->rx_id >= num_fifos || | ||
711 | finfo->tx_usr >= num_users || finfo->rx_usr >= num_users) | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | |||
608 | mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL); | 715 | mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL); |
609 | if (!mdev) | 716 | if (!mdev) |
610 | return -ENOMEM; | 717 | return -ENOMEM; |
@@ -615,41 +722,40 @@ static int omap_mbox_probe(struct platform_device *pdev) | |||
615 | return PTR_ERR(mdev->mbox_base); | 722 | return PTR_ERR(mdev->mbox_base); |
616 | 723 | ||
617 | /* allocate one extra for marking end of list */ | 724 | /* allocate one extra for marking end of list */ |
618 | list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list), | 725 | list = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*list), |
619 | GFP_KERNEL); | 726 | GFP_KERNEL); |
620 | if (!list) | 727 | if (!list) |
621 | return -ENOMEM; | 728 | return -ENOMEM; |
622 | 729 | ||
623 | mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox), | 730 | mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox), |
624 | GFP_KERNEL); | 731 | GFP_KERNEL); |
625 | if (!mboxblk) | 732 | if (!mboxblk) |
626 | return -ENOMEM; | 733 | return -ENOMEM; |
627 | 734 | ||
628 | info = pdata->info; | ||
629 | intr_type = pdata->intr_type; | ||
630 | mbox = mboxblk; | 735 | mbox = mboxblk; |
631 | for (i = 0; i < pdata->info_cnt; i++, info++) { | 736 | finfo = finfoblk; |
737 | for (i = 0; i < info_count; i++, finfo++) { | ||
632 | fifo = &mbox->tx_fifo; | 738 | fifo = &mbox->tx_fifo; |
633 | fifo->msg = MAILBOX_MESSAGE(info->tx_id); | 739 | fifo->msg = MAILBOX_MESSAGE(finfo->tx_id); |
634 | fifo->fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); | 740 | fifo->fifo_stat = MAILBOX_FIFOSTATUS(finfo->tx_id); |
635 | fifo->intr_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); | 741 | fifo->intr_bit = MAILBOX_IRQ_NOTFULL(finfo->tx_id); |
636 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id); | 742 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->tx_usr); |
637 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id); | 743 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->tx_usr); |
638 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id); | 744 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->tx_usr); |
639 | 745 | ||
640 | fifo = &mbox->rx_fifo; | 746 | fifo = &mbox->rx_fifo; |
641 | fifo->msg = MAILBOX_MESSAGE(info->rx_id); | 747 | fifo->msg = MAILBOX_MESSAGE(finfo->rx_id); |
642 | fifo->msg_stat = MAILBOX_MSGSTATUS(info->rx_id); | 748 | fifo->msg_stat = MAILBOX_MSGSTATUS(finfo->rx_id); |
643 | fifo->intr_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); | 749 | fifo->intr_bit = MAILBOX_IRQ_NEWMSG(finfo->rx_id); |
644 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id); | 750 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->rx_usr); |
645 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id); | 751 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->rx_usr); |
646 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id); | 752 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->rx_usr); |
647 | 753 | ||
648 | mbox->intr_type = intr_type; | 754 | mbox->intr_type = intr_type; |
649 | 755 | ||
650 | mbox->parent = mdev; | 756 | mbox->parent = mdev; |
651 | mbox->name = info->name; | 757 | mbox->name = finfo->name; |
652 | mbox->irq = platform_get_irq(pdev, info->irq_id); | 758 | mbox->irq = platform_get_irq(pdev, finfo->tx_irq); |
653 | if (mbox->irq < 0) | 759 | if (mbox->irq < 0) |
654 | return mbox->irq; | 760 | return mbox->irq; |
655 | list[i] = mbox++; | 761 | list[i] = mbox++; |
@@ -657,8 +763,8 @@ static int omap_mbox_probe(struct platform_device *pdev) | |||
657 | 763 | ||
658 | mutex_init(&mdev->cfg_lock); | 764 | mutex_init(&mdev->cfg_lock); |
659 | mdev->dev = &pdev->dev; | 765 | mdev->dev = &pdev->dev; |
660 | mdev->num_users = pdata->num_users; | 766 | mdev->num_users = num_users; |
661 | mdev->num_fifos = pdata->num_fifos; | 767 | mdev->num_fifos = num_fifos; |
662 | mdev->mboxes = list; | 768 | mdev->mboxes = list; |
663 | ret = omap_mbox_register(mdev); | 769 | ret = omap_mbox_register(mdev); |
664 | if (ret) | 770 | if (ret) |
@@ -684,6 +790,7 @@ static int omap_mbox_probe(struct platform_device *pdev) | |||
684 | if (ret < 0) | 790 | if (ret < 0) |
685 | goto unregister; | 791 | goto unregister; |
686 | 792 | ||
793 | devm_kfree(&pdev->dev, finfoblk); | ||
687 | return 0; | 794 | return 0; |
688 | 795 | ||
689 | unregister: | 796 | unregister: |
@@ -708,6 +815,7 @@ static struct platform_driver omap_mbox_driver = { | |||
708 | .driver = { | 815 | .driver = { |
709 | .name = "omap-mailbox", | 816 | .name = "omap-mailbox", |
710 | .owner = THIS_MODULE, | 817 | .owner = THIS_MODULE, |
818 | .of_match_table = of_match_ptr(omap_mailbox_of_match), | ||
711 | }, | 819 | }, |
712 | }; | 820 | }; |
713 | 821 | ||