aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-06 20:36:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-06 20:36:53 -0400
commitc6594fc6af1924b7fdce600088b10e3b3b159fb7 (patch)
tree9abf18bf70373623310aa6ea8e671d571e6236c1
parent553911c67eb701d46e2dcd073f603c6f6546c38b (diff)
parenta649244de727b87d38fe46d86ef98c8d1fc49551 (diff)
Merge branch 'mailbox-for-next' of git://git.linaro.org/landing-teams/working/fujitsu/integration
Pull mailbox updates from Jussi Brar: "New driver and DT bindings for MHU controller integrated on Amlogic Meson platform" * 'mailbox-for-next' of git://git.linaro.org/landing-teams/working/fujitsu/integration: dt-bindings: mailbox: Add Amlogic Meson MHU Bindings mailbox: Add Platform Message-Handling-Unit variant driver
-rw-r--r--Documentation/devicetree/bindings/mailbox/meson-mhu.txt34
-rw-r--r--drivers/mailbox/Kconfig10
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/platform_mhu.c205
4 files changed, 251 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/meson-mhu.txt b/Documentation/devicetree/bindings/mailbox/meson-mhu.txt
new file mode 100644
index 000000000000..a530310772b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/meson-mhu.txt
@@ -0,0 +1,34 @@
1Amlogic Meson MHU Mailbox Driver
2================================
3
4The Amlogic's Meson SoCs Message-Handling-Unit (MHU) is a mailbox controller
5that has 3 independent channels/links to communicate with remote processor(s).
6MHU links are hardwired on a platform. A link raises interrupt for any
7received data. However, there is no specified way of knowing if the sent
8data has been read by the remote. This driver assumes the sender polls
9STAT register and the remote clears it after having read the data.
10
11Mailbox Device Node:
12====================
13
14Required properties:
15--------------------
16- compatible: Shall be "amlogic,meson-gxbb-mhu"
17- reg: Contains the mailbox register address range (base
18 address and length)
19- #mbox-cells Shall be 1 - the index of the channel needed.
20- interrupts: Contains the interrupt information corresponding to
21 each of the 2 links of MHU.
22
23Example:
24--------
25
26 mailbox: mailbox@c883c404 {
27 #mbox-cells = <1>;
28 compatible = "amlogic,meson-gxbb-mhu";
29 reg = <0 0xc883c404 0 0x4c>;
30 interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
31 <0 209 IRQ_TYPE_EDGE_RISING>,
32 <0 210 IRQ_TYPE_EDGE_RISING>;
33 #mbox-cells = <1>;
34 };
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 7817d40d81e7..11eebfe8a4cb 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,16 @@ config ARM_MHU
15 The controller has 3 mailbox channels, the last of which can be 15 The controller has 3 mailbox channels, the last of which can be
16 used in Secure mode only. 16 used in Secure mode only.
17 17
18config PLATFORM_MHU
19 tristate "Platform MHU Mailbox"
20 depends on OF
21 depends on HAS_IOMEM
22 help
23 Say Y here if you want to build a platform specific variant MHU
24 controller driver.
25 The controller has a maximum of 3 mailbox channels, the last of
26 which can be used in Secure mode only.
27
18config PL320_MBOX 28config PL320_MBOX
19 bool "ARM PL320 Mailbox" 29 bool "ARM PL320 Mailbox"
20 depends on ARM_AMBA 30 depends on ARM_AMBA
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 66c38e300dfc..ace6fed8fea9 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o
6 6
7obj-$(CONFIG_ARM_MHU) += arm_mhu.o 7obj-$(CONFIG_ARM_MHU) += arm_mhu.o
8 8
9obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o
10
9obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o 11obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
10 12
11obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o 13obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
diff --git a/drivers/mailbox/platform_mhu.c b/drivers/mailbox/platform_mhu.c
new file mode 100644
index 000000000000..e13201a5cec6
--- /dev/null
+++ b/drivers/mailbox/platform_mhu.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (C) 2016 BayLibre SAS.
3 * Author: Neil Armstrong <narmstrong@baylibre.com>
4 * Synchronised with arm_mhu.c from :
5 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
6 * Copyright (C) 2015 Linaro Ltd.
7 * Author: Jassi Brar <jaswinder.singh@linaro.org>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/interrupt.h>
20#include <linux/spinlock.h>
21#include <linux/mutex.h>
22#include <linux/delay.h>
23#include <linux/slab.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/module.h>
27#include <linux/platform_device.h>
28#include <linux/mailbox_controller.h>
29
30#define INTR_SET_OFS 0x0
31#define INTR_STAT_OFS 0x4
32#define INTR_CLR_OFS 0x8
33
34#define MHU_SEC_OFFSET 0x0
35#define MHU_LP_OFFSET 0xc
36#define MHU_HP_OFFSET 0x18
37#define TX_REG_OFFSET 0x24
38
39#define MHU_CHANS 3
40
41struct platform_mhu_link {
42 int irq;
43 void __iomem *tx_reg;
44 void __iomem *rx_reg;
45};
46
47struct platform_mhu {
48 void __iomem *base;
49 struct platform_mhu_link mlink[MHU_CHANS];
50 struct mbox_chan chan[MHU_CHANS];
51 struct mbox_controller mbox;
52};
53
54static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)
55{
56 struct mbox_chan *chan = p;
57 struct platform_mhu_link *mlink = chan->con_priv;
58 u32 val;
59
60 val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
61 if (!val)
62 return IRQ_NONE;
63
64 mbox_chan_received_data(chan, (void *)&val);
65
66 writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
67
68 return IRQ_HANDLED;
69}
70
71static bool platform_mhu_last_tx_done(struct mbox_chan *chan)
72{
73 struct platform_mhu_link *mlink = chan->con_priv;
74 u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
75
76 return (val == 0);
77}
78
79static int platform_mhu_send_data(struct mbox_chan *chan, void *data)
80{
81 struct platform_mhu_link *mlink = chan->con_priv;
82 u32 *arg = data;
83
84 writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
85
86 return 0;
87}
88
89static int platform_mhu_startup(struct mbox_chan *chan)
90{
91 struct platform_mhu_link *mlink = chan->con_priv;
92 u32 val;
93 int ret;
94
95 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
96 writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
97
98 ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,
99 IRQF_SHARED, "platform_mhu_link", chan);
100 if (ret) {
101 dev_err(chan->mbox->dev,
102 "Unable to acquire IRQ %d\n", mlink->irq);
103 return ret;
104 }
105
106 return 0;
107}
108
109static void platform_mhu_shutdown(struct mbox_chan *chan)
110{
111 struct platform_mhu_link *mlink = chan->con_priv;
112
113 free_irq(mlink->irq, chan);
114}
115
116static const struct mbox_chan_ops platform_mhu_ops = {
117 .send_data = platform_mhu_send_data,
118 .startup = platform_mhu_startup,
119 .shutdown = platform_mhu_shutdown,
120 .last_tx_done = platform_mhu_last_tx_done,
121};
122
123static int platform_mhu_probe(struct platform_device *pdev)
124{
125 int i, err;
126 struct platform_mhu *mhu;
127 struct device *dev = &pdev->dev;
128 struct resource *res;
129 int platform_mhu_reg[MHU_CHANS] = {
130 MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET
131 };
132
133 /* Allocate memory for device */
134 mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
135 if (!mhu)
136 return -ENOMEM;
137
138 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
139 mhu->base = devm_ioremap_resource(dev, res);
140 if (IS_ERR(mhu->base)) {
141 dev_err(dev, "ioremap failed\n");
142 return PTR_ERR(mhu->base);
143 }
144
145 for (i = 0; i < MHU_CHANS; i++) {
146 mhu->chan[i].con_priv = &mhu->mlink[i];
147 mhu->mlink[i].irq = platform_get_irq(pdev, i);
148 if (mhu->mlink[i].irq < 0) {
149 dev_err(dev, "failed to get irq%d\n", i);
150 return mhu->mlink[i].irq;
151 }
152 mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];
153 mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
154 }
155
156 mhu->mbox.dev = dev;
157 mhu->mbox.chans = &mhu->chan[0];
158 mhu->mbox.num_chans = MHU_CHANS;
159 mhu->mbox.ops = &platform_mhu_ops;
160 mhu->mbox.txdone_irq = false;
161 mhu->mbox.txdone_poll = true;
162 mhu->mbox.txpoll_period = 1;
163
164 platform_set_drvdata(pdev, mhu);
165
166 err = mbox_controller_register(&mhu->mbox);
167 if (err) {
168 dev_err(dev, "Failed to register mailboxes %d\n", err);
169 return err;
170 }
171
172 dev_info(dev, "Platform MHU Mailbox registered\n");
173 return 0;
174}
175
176static int platform_mhu_remove(struct platform_device *pdev)
177{
178 struct platform_mhu *mhu = platform_get_drvdata(pdev);
179
180 mbox_controller_unregister(&mhu->mbox);
181
182 return 0;
183}
184
185static const struct of_device_id platform_mhu_dt_ids[] = {
186 { .compatible = "amlogic,meson-gxbb-mhu", },
187 { /* sentinel */ },
188};
189MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);
190
191static struct platform_driver platform_mhu_driver = {
192 .probe = platform_mhu_probe,
193 .remove = platform_mhu_remove,
194 .driver = {
195 .name = "platform-mhu",
196 .of_match_table = platform_mhu_dt_ids,
197 },
198};
199
200module_platform_driver(platform_mhu_driver);
201
202MODULE_LICENSE("GPL v2");
203MODULE_ALIAS("platform:platform-mhu");
204MODULE_DESCRIPTION("Platform MHU Driver");
205MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");