aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mailbox
diff options
context:
space:
mode:
authorSuman Anna <s-anna@ti.com>2014-06-24 20:43:41 -0400
committerTony Lindgren <tony@atomide.com>2014-07-29 04:57:25 -0400
commit5040f534385a300dee4f05af2484cdbf9ecef8a6 (patch)
treec0b9e9a84e1700f951986ada8ad6014c74898a75 /drivers/mailbox
parentef45eae6e9f6af297c0cd0bfb98c85f3f51e96be (diff)
mailbox/omap: consolidate OMAP mailbox driver
There is no need for a separate common OMAP mailbox module now that the OMAP1 mailbox driver has been removed. So, consolidate the two individual OMAP mailbox modules into a single driver. This streamlines the driver for converting to mailbox framework. The following are the main changes: - collapse mailbox-omap2.c into omap-mailbox.c - remove omap_mbox_ops and replace the ops calls with the equivalent functionality. - simplify the sub-mailbox startup/shutdown functionality, the one-time operations are moved into probe, and the pm_runtime_get_sync and pm_runtime_put_sync can be invoked without using a configuration counter. - move all definitions from private omap_mbox.h into the source code, and eliminate this internal header. - rename some variables that used the omap2_mbox prefix with a generic omap_mbox prefix. Signed-off-by: Suman Anna <s-anna@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/mailbox')
-rw-r--r--drivers/mailbox/Kconfig8
-rw-r--r--drivers/mailbox/Makefile4
-rw-r--r--drivers/mailbox/mailbox-omap2.c333
-rw-r--r--drivers/mailbox/omap-mailbox.c331
-rw-r--r--drivers/mailbox/omap-mbox.h62
5 files changed, 283 insertions, 455 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 1ec8f4e1cf5a..9fd9c6717e0c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -16,17 +16,9 @@ config PL320_MBOX
16 Management Engine, primarily for cpufreq. Say Y here if you want 16 Management Engine, primarily for cpufreq. Say Y here if you want
17 to use the PL320 IPCM support. 17 to use the PL320 IPCM support.
18 18
19config OMAP_MBOX
20 tristate
21 help
22 This option is selected by any OMAP architecture specific mailbox
23 driver such as CONFIG_OMAP2PLUS_MBOX. This enables the common OMAP
24 mailbox framework code.
25
26config OMAP2PLUS_MBOX 19config OMAP2PLUS_MBOX
27 tristate "OMAP2+ Mailbox framework support" 20 tristate "OMAP2+ Mailbox framework support"
28 depends on ARCH_OMAP2PLUS 21 depends on ARCH_OMAP2PLUS
29 select OMAP_MBOX
30 help 22 help
31 Mailbox implementation for OMAP family chips with hardware for 23 Mailbox implementation for OMAP family chips with hardware for
32 interprocessor communication involving DSP, IVA1.0 and IVA2 in 24 interprocessor communication involving DSP, IVA1.0 and IVA2 in
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index d023feb57ba5..6d184dbcaca8 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -1,5 +1,3 @@
1obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o 1obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
2 2
3obj-$(CONFIG_OMAP_MBOX) += omap-mailbox.o 3obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
4obj-$(CONFIG_OMAP2PLUS_MBOX) += mailbox_omap2.o
5mailbox_omap2-objs := mailbox-omap2.o
diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c
deleted file mode 100644
index 2c463d6c8a8c..000000000000
--- a/drivers/mailbox/mailbox-omap2.c
+++ /dev/null
@@ -1,333 +0,0 @@
1/*
2 * Mailbox reservation modules for OMAP2/3
3 *
4 * Copyright (C) 2006-2009 Nokia Corporation
5 * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
6 * and Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/clk.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/io.h>
19#include <linux/pm_runtime.h>
20#include <linux/platform_data/mailbox-omap.h>
21
22#include "omap-mbox.h"
23
24#define MAILBOX_REVISION 0x000
25#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
26#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
27#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
28
29#define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
30#define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
31
32#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
33#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
34#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
35
36#define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \
37 OMAP2_MAILBOX_IRQSTATUS(u))
38#define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \
39 OMAP2_MAILBOX_IRQENABLE(u))
40#define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \
41 : OMAP2_MAILBOX_IRQENABLE(u))
42
43#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
44#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
45
46#define MBOX_REG_SIZE 0x120
47
48#define OMAP4_MBOX_REG_SIZE 0x130
49
50#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
51#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
52
53static void __iomem *mbox_base;
54
55struct omap_mbox2_fifo {
56 unsigned long msg;
57 unsigned long fifo_stat;
58 unsigned long msg_stat;
59};
60
61struct omap_mbox2_priv {
62 struct omap_mbox2_fifo tx_fifo;
63 struct omap_mbox2_fifo rx_fifo;
64 unsigned long irqenable;
65 unsigned long irqstatus;
66 u32 newmsg_bit;
67 u32 notfull_bit;
68 u32 ctx[OMAP4_MBOX_NR_REGS];
69 unsigned long irqdisable;
70 u32 intr_type;
71};
72
73static inline unsigned int mbox_read_reg(size_t ofs)
74{
75 return __raw_readl(mbox_base + ofs);
76}
77
78static inline void mbox_write_reg(u32 val, size_t ofs)
79{
80 __raw_writel(val, mbox_base + ofs);
81}
82
83/* Mailbox H/W preparations */
84static int omap2_mbox_startup(struct omap_mbox *mbox)
85{
86 u32 l;
87
88 pm_runtime_enable(mbox->dev->parent);
89 pm_runtime_get_sync(mbox->dev->parent);
90
91 l = mbox_read_reg(MAILBOX_REVISION);
92 pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
93
94 return 0;
95}
96
97static void omap2_mbox_shutdown(struct omap_mbox *mbox)
98{
99 pm_runtime_put_sync(mbox->dev->parent);
100 pm_runtime_disable(mbox->dev->parent);
101}
102
103/* Mailbox FIFO handle functions */
104static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
105{
106 struct omap_mbox2_fifo *fifo =
107 &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
108 return (mbox_msg_t) mbox_read_reg(fifo->msg);
109}
110
111static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
112{
113 struct omap_mbox2_fifo *fifo =
114 &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
115 mbox_write_reg(msg, fifo->msg);
116}
117
118static int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
119{
120 struct omap_mbox2_fifo *fifo =
121 &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
122 return (mbox_read_reg(fifo->msg_stat) == 0);
123}
124
125static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
126{
127 struct omap_mbox2_fifo *fifo =
128 &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
129 return mbox_read_reg(fifo->fifo_stat);
130}
131
132/* Mailbox IRQ handle functions */
133static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
134{
135 struct omap_mbox2_priv *p = mbox->priv;
136 u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
137
138 l = mbox_read_reg(p->irqenable);
139 l |= bit;
140 mbox_write_reg(l, p->irqenable);
141}
142
143static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
144{
145 struct omap_mbox2_priv *p = mbox->priv;
146 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
147
148 /*
149 * Read and update the interrupt configuration register for pre-OMAP4.
150 * OMAP4 and later SoCs have a dedicated interrupt disabling register.
151 */
152 if (!p->intr_type)
153 bit = mbox_read_reg(p->irqdisable) & ~bit;
154
155 mbox_write_reg(bit, p->irqdisable);
156}
157
158static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
159{
160 struct omap_mbox2_priv *p = mbox->priv;
161 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
162
163 mbox_write_reg(bit, p->irqstatus);
164
165 /* Flush posted write for irq status to avoid spurious interrupts */
166 mbox_read_reg(p->irqstatus);
167}
168
169static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
170{
171 struct omap_mbox2_priv *p = mbox->priv;
172 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
173 u32 enable = mbox_read_reg(p->irqenable);
174 u32 status = mbox_read_reg(p->irqstatus);
175
176 return (int)(enable & status & bit);
177}
178
179static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
180{
181 int i;
182 struct omap_mbox2_priv *p = mbox->priv;
183 int nr_regs;
184
185 if (p->intr_type)
186 nr_regs = OMAP4_MBOX_NR_REGS;
187 else
188 nr_regs = MBOX_NR_REGS;
189 for (i = 0; i < nr_regs; i++) {
190 p->ctx[i] = mbox_read_reg(i * sizeof(u32));
191
192 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
193 i, p->ctx[i]);
194 }
195}
196
197static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
198{
199 int i;
200 struct omap_mbox2_priv *p = mbox->priv;
201 int nr_regs;
202
203 if (p->intr_type)
204 nr_regs = OMAP4_MBOX_NR_REGS;
205 else
206 nr_regs = MBOX_NR_REGS;
207 for (i = 0; i < nr_regs; i++) {
208 mbox_write_reg(p->ctx[i], i * sizeof(u32));
209
210 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
211 i, p->ctx[i]);
212 }
213}
214
215static struct omap_mbox_ops omap2_mbox_ops = {
216 .startup = omap2_mbox_startup,
217 .shutdown = omap2_mbox_shutdown,
218 .fifo_read = omap2_mbox_fifo_read,
219 .fifo_write = omap2_mbox_fifo_write,
220 .fifo_empty = omap2_mbox_fifo_empty,
221 .fifo_full = omap2_mbox_fifo_full,
222 .enable_irq = omap2_mbox_enable_irq,
223 .disable_irq = omap2_mbox_disable_irq,
224 .ack_irq = omap2_mbox_ack_irq,
225 .is_irq = omap2_mbox_is_irq,
226 .save_ctx = omap2_mbox_save_ctx,
227 .restore_ctx = omap2_mbox_restore_ctx,
228};
229
230static int omap2_mbox_probe(struct platform_device *pdev)
231{
232 struct resource *mem;
233 int ret;
234 struct omap_mbox **list, *mbox, *mboxblk;
235 struct omap_mbox2_priv *priv, *privblk;
236 struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
237 struct omap_mbox_dev_info *info;
238 u32 intr_type;
239 int i;
240
241 if (!pdata || !pdata->info_cnt || !pdata->info) {
242 pr_err("%s: platform not supported\n", __func__);
243 return -ENODEV;
244 }
245
246 /* allocate one extra for marking end of list */
247 list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
248 GFP_KERNEL);
249 if (!list)
250 return -ENOMEM;
251
252 mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
253 GFP_KERNEL);
254 if (!mboxblk)
255 return -ENOMEM;
256
257 privblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*priv),
258 GFP_KERNEL);
259 if (!privblk)
260 return -ENOMEM;
261
262 info = pdata->info;
263 intr_type = pdata->intr_type;
264 mbox = mboxblk;
265 priv = privblk;
266 for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
267 priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
268 priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
269 priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
270 priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
271 priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
272 priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
273 priv->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
274 priv->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
275 priv->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
276 priv->intr_type = intr_type;
277
278 mbox->priv = priv;
279 mbox->name = info->name;
280 mbox->ops = &omap2_mbox_ops;
281 mbox->irq = platform_get_irq(pdev, info->irq_id);
282 if (mbox->irq < 0)
283 return mbox->irq;
284 list[i] = mbox++;
285 }
286
287 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
288 mbox_base = devm_ioremap_resource(&pdev->dev, mem);
289 if (IS_ERR(mbox_base))
290 return PTR_ERR(mbox_base);
291
292 ret = omap_mbox_register(&pdev->dev, list);
293 if (ret)
294 return ret;
295
296 platform_set_drvdata(pdev, list);
297
298 return 0;
299}
300
301static int omap2_mbox_remove(struct platform_device *pdev)
302{
303 omap_mbox_unregister();
304
305 return 0;
306}
307
308static struct platform_driver omap2_mbox_driver = {
309 .probe = omap2_mbox_probe,
310 .remove = omap2_mbox_remove,
311 .driver = {
312 .name = "omap-mailbox",
313 },
314};
315
316static int __init omap2_mbox_init(void)
317{
318 return platform_driver_register(&omap2_mbox_driver);
319}
320
321static void __exit omap2_mbox_exit(void)
322{
323 platform_driver_unregister(&omap2_mbox_driver);
324}
325
326module_init(omap2_mbox_init);
327module_exit(omap2_mbox_exit);
328
329MODULE_LICENSE("GPL v2");
330MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
331MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
332MODULE_AUTHOR("Paul Mundt");
333MODULE_ALIAS("platform:omap2-mailbox");
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
index eab72276ffab..66b02ab00b19 100644
--- a/drivers/mailbox/omap-mailbox.c
+++ b/drivers/mailbox/omap-mailbox.c
@@ -2,8 +2,10 @@
2 * OMAP mailbox driver 2 * OMAP mailbox driver
3 * 3 *
4 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. 4 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
5 * Copyright (C) 2013-2014 Texas Instruments Inc.
5 * 6 *
6 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> 7 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
8 * Suman Anna <s-anna@ti.com>
7 * 9 *
8 * This program is free software; you can redistribute it and/or 10 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License 11 * modify it under the terms of the GNU General Public License
@@ -29,45 +31,145 @@
29#include <linux/err.h> 31#include <linux/err.h>
30#include <linux/notifier.h> 32#include <linux/notifier.h>
31#include <linux/module.h> 33#include <linux/module.h>
32 34#include <linux/platform_device.h>
33#include "omap-mbox.h" 35#include <linux/pm_runtime.h>
34 36#include <linux/platform_data/mailbox-omap.h>
37#include <linux/omap-mailbox.h>
38
39#define MAILBOX_REVISION 0x000
40#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
41#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
42#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
43
44#define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
45#define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
46
47#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
48#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
49#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
50
51#define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \
52 OMAP2_MAILBOX_IRQSTATUS(u))
53#define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \
54 OMAP2_MAILBOX_IRQENABLE(u))
55#define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \
56 : OMAP2_MAILBOX_IRQENABLE(u))
57
58#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
59#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
60
61#define MBOX_REG_SIZE 0x120
62
63#define OMAP4_MBOX_REG_SIZE 0x130
64
65#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
66#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
67
68struct omap_mbox_fifo {
69 unsigned long msg;
70 unsigned long fifo_stat;
71 unsigned long msg_stat;
72};
73
74struct omap_mbox_priv {
75 struct omap_mbox_fifo tx_fifo;
76 struct omap_mbox_fifo rx_fifo;
77 unsigned long irqenable;
78 unsigned long irqstatus;
79 u32 newmsg_bit;
80 u32 notfull_bit;
81 u32 ctx[OMAP4_MBOX_NR_REGS];
82 unsigned long irqdisable;
83 u32 intr_type;
84};
85
86struct omap_mbox_queue {
87 spinlock_t lock;
88 struct kfifo fifo;
89 struct work_struct work;
90 struct tasklet_struct tasklet;
91 struct omap_mbox *mbox;
92 bool full;
93};
94
95struct omap_mbox {
96 const char *name;
97 int irq;
98 struct omap_mbox_queue *txq, *rxq;
99 struct device *dev;
100 void *priv;
101 int use_count;
102 struct blocking_notifier_head notifier;
103};
104
105static void __iomem *mbox_base;
35static struct omap_mbox **mboxes; 106static struct omap_mbox **mboxes;
36 107
37static int mbox_configured;
38static DEFINE_MUTEX(mbox_configured_lock); 108static DEFINE_MUTEX(mbox_configured_lock);
39 109
40static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; 110static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
41module_param(mbox_kfifo_size, uint, S_IRUGO); 111module_param(mbox_kfifo_size, uint, S_IRUGO);
42MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); 112MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
43 113
114static inline unsigned int mbox_read_reg(size_t ofs)
115{
116 return __raw_readl(mbox_base + ofs);
117}
118
119static inline void mbox_write_reg(u32 val, size_t ofs)
120{
121 __raw_writel(val, mbox_base + ofs);
122}
123
44/* Mailbox FIFO handle functions */ 124/* Mailbox FIFO handle functions */
45static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) 125static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
46{ 126{
47 return mbox->ops->fifo_read(mbox); 127 struct omap_mbox_fifo *fifo =
128 &((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
129 return (mbox_msg_t) mbox_read_reg(fifo->msg);
48} 130}
49static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) 131
132static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
50{ 133{
51 mbox->ops->fifo_write(mbox, msg); 134 struct omap_mbox_fifo *fifo =
135 &((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
136 mbox_write_reg(msg, fifo->msg);
52} 137}
53static inline int mbox_fifo_empty(struct omap_mbox *mbox) 138
139static int mbox_fifo_empty(struct omap_mbox *mbox)
54{ 140{
55 return mbox->ops->fifo_empty(mbox); 141 struct omap_mbox_fifo *fifo =
142 &((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
143 return (mbox_read_reg(fifo->msg_stat) == 0);
56} 144}
57static inline int mbox_fifo_full(struct omap_mbox *mbox) 145
146static int mbox_fifo_full(struct omap_mbox *mbox)
58{ 147{
59 return mbox->ops->fifo_full(mbox); 148 struct omap_mbox_fifo *fifo =
149 &((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
150 return mbox_read_reg(fifo->fifo_stat);
60} 151}
61 152
62/* Mailbox IRQ handle functions */ 153/* Mailbox IRQ handle functions */
63static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 154static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
64{ 155{
65 if (mbox->ops->ack_irq) 156 struct omap_mbox_priv *p = mbox->priv;
66 mbox->ops->ack_irq(mbox, irq); 157 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
158
159 mbox_write_reg(bit, p->irqstatus);
160
161 /* Flush posted write for irq status to avoid spurious interrupts */
162 mbox_read_reg(p->irqstatus);
67} 163}
68static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 164
165static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
69{ 166{
70 return mbox->ops->is_irq(mbox, irq); 167 struct omap_mbox_priv *p = mbox->priv;
168 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
169 u32 enable = mbox_read_reg(p->irqenable);
170 u32 status = mbox_read_reg(p->irqstatus);
171
172 return (int)(enable & status & bit);
71} 173}
72 174
73/* 175/*
@@ -103,35 +205,66 @@ EXPORT_SYMBOL(omap_mbox_msg_send);
103 205
104void omap_mbox_save_ctx(struct omap_mbox *mbox) 206void omap_mbox_save_ctx(struct omap_mbox *mbox)
105{ 207{
106 if (!mbox->ops->save_ctx) { 208 int i;
107 dev_err(mbox->dev, "%s:\tno save\n", __func__); 209 struct omap_mbox_priv *p = mbox->priv;
108 return; 210 int nr_regs;
211
212 if (p->intr_type)
213 nr_regs = OMAP4_MBOX_NR_REGS;
214 else
215 nr_regs = MBOX_NR_REGS;
216 for (i = 0; i < nr_regs; i++) {
217 p->ctx[i] = mbox_read_reg(i * sizeof(u32));
218
219 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
220 i, p->ctx[i]);
109 } 221 }
110
111 mbox->ops->save_ctx(mbox);
112} 222}
113EXPORT_SYMBOL(omap_mbox_save_ctx); 223EXPORT_SYMBOL(omap_mbox_save_ctx);
114 224
115void omap_mbox_restore_ctx(struct omap_mbox *mbox) 225void omap_mbox_restore_ctx(struct omap_mbox *mbox)
116{ 226{
117 if (!mbox->ops->restore_ctx) { 227 int i;
118 dev_err(mbox->dev, "%s:\tno restore\n", __func__); 228 struct omap_mbox_priv *p = mbox->priv;
119 return; 229 int nr_regs;
230
231 if (p->intr_type)
232 nr_regs = OMAP4_MBOX_NR_REGS;
233 else
234 nr_regs = MBOX_NR_REGS;
235 for (i = 0; i < nr_regs; i++) {
236 mbox_write_reg(p->ctx[i], i * sizeof(u32));
237
238 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
239 i, p->ctx[i]);
120 } 240 }
121
122 mbox->ops->restore_ctx(mbox);
123} 241}
124EXPORT_SYMBOL(omap_mbox_restore_ctx); 242EXPORT_SYMBOL(omap_mbox_restore_ctx);
125 243
126void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 244void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
127{ 245{
128 mbox->ops->enable_irq(mbox, irq); 246 struct omap_mbox_priv *p = mbox->priv;
247 u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
248
249 l = mbox_read_reg(p->irqenable);
250 l |= bit;
251 mbox_write_reg(l, p->irqenable);
129} 252}
130EXPORT_SYMBOL(omap_mbox_enable_irq); 253EXPORT_SYMBOL(omap_mbox_enable_irq);
131 254
132void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 255void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
133{ 256{
134 mbox->ops->disable_irq(mbox, irq); 257 struct omap_mbox_priv *p = mbox->priv;
258 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
259
260 /*
261 * Read and update the interrupt configuration register for pre-OMAP4.
262 * OMAP4 and later SoCs have a dedicated interrupt disabling register.
263 */
264 if (!p->intr_type)
265 bit = mbox_read_reg(p->irqdisable) & ~bit;
266
267 mbox_write_reg(bit, p->irqdisable);
135} 268}
136EXPORT_SYMBOL(omap_mbox_disable_irq); 269EXPORT_SYMBOL(omap_mbox_disable_irq);
137 270
@@ -267,14 +400,9 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
267 struct omap_mbox_queue *mq; 400 struct omap_mbox_queue *mq;
268 401
269 mutex_lock(&mbox_configured_lock); 402 mutex_lock(&mbox_configured_lock);
270 if (!mbox_configured++) { 403 ret = pm_runtime_get_sync(mbox->dev->parent);
271 if (likely(mbox->ops->startup)) { 404 if (unlikely(ret < 0))
272 ret = mbox->ops->startup(mbox); 405 goto fail_startup;
273 if (unlikely(ret))
274 goto fail_startup;
275 } else
276 goto fail_startup;
277 }
278 406
279 if (!mbox->use_count++) { 407 if (!mbox->use_count++) {
280 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); 408 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
@@ -309,11 +437,9 @@ fail_request_irq:
309fail_alloc_rxq: 437fail_alloc_rxq:
310 mbox_queue_free(mbox->txq); 438 mbox_queue_free(mbox->txq);
311fail_alloc_txq: 439fail_alloc_txq:
312 if (mbox->ops->shutdown) 440 pm_runtime_put_sync(mbox->dev->parent);
313 mbox->ops->shutdown(mbox);
314 mbox->use_count--; 441 mbox->use_count--;
315fail_startup: 442fail_startup:
316 mbox_configured--;
317 mutex_unlock(&mbox_configured_lock); 443 mutex_unlock(&mbox_configured_lock);
318 return ret; 444 return ret;
319} 445}
@@ -331,10 +457,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
331 mbox_queue_free(mbox->rxq); 457 mbox_queue_free(mbox->rxq);
332 } 458 }
333 459
334 if (likely(mbox->ops->shutdown)) { 460 pm_runtime_put_sync(mbox->dev->parent);
335 if (!--mbox_configured)
336 mbox->ops->shutdown(mbox);
337 }
338 461
339 mutex_unlock(&mbox_configured_lock); 462 mutex_unlock(&mbox_configured_lock);
340} 463}
@@ -379,7 +502,7 @@ EXPORT_SYMBOL(omap_mbox_put);
379 502
380static struct class omap_mbox_class = { .name = "mbox", }; 503static struct class omap_mbox_class = { .name = "mbox", };
381 504
382int omap_mbox_register(struct device *parent, struct omap_mbox **list) 505static int omap_mbox_register(struct device *parent, struct omap_mbox **list)
383{ 506{
384 int ret; 507 int ret;
385 int i; 508 int i;
@@ -406,9 +529,8 @@ err_out:
406 device_unregister(mboxes[i]->dev); 529 device_unregister(mboxes[i]->dev);
407 return ret; 530 return ret;
408} 531}
409EXPORT_SYMBOL(omap_mbox_register);
410 532
411int omap_mbox_unregister(void) 533static int omap_mbox_unregister(void)
412{ 534{
413 int i; 535 int i;
414 536
@@ -420,7 +542,117 @@ int omap_mbox_unregister(void)
420 mboxes = NULL; 542 mboxes = NULL;
421 return 0; 543 return 0;
422} 544}
423EXPORT_SYMBOL(omap_mbox_unregister); 545
546static int omap_mbox_probe(struct platform_device *pdev)
547{
548 struct resource *mem;
549 int ret;
550 struct omap_mbox **list, *mbox, *mboxblk;
551 struct omap_mbox_priv *priv, *privblk;
552 struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
553 struct omap_mbox_dev_info *info;
554 u32 intr_type;
555 u32 l;
556 int i;
557
558 if (!pdata || !pdata->info_cnt || !pdata->info) {
559 pr_err("%s: platform not supported\n", __func__);
560 return -ENODEV;
561 }
562
563 /* allocate one extra for marking end of list */
564 list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
565 GFP_KERNEL);
566 if (!list)
567 return -ENOMEM;
568
569 mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
570 GFP_KERNEL);
571 if (!mboxblk)
572 return -ENOMEM;
573
574 privblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*priv),
575 GFP_KERNEL);
576 if (!privblk)
577 return -ENOMEM;
578
579 info = pdata->info;
580 intr_type = pdata->intr_type;
581 mbox = mboxblk;
582 priv = privblk;
583 for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
584 priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
585 priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
586 priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
587 priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
588 priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
589 priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
590 priv->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
591 priv->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
592 priv->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
593 priv->intr_type = intr_type;
594
595 mbox->priv = priv;
596 mbox->name = info->name;
597 mbox->irq = platform_get_irq(pdev, info->irq_id);
598 if (mbox->irq < 0)
599 return mbox->irq;
600 list[i] = mbox++;
601 }
602
603 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
604 mbox_base = devm_ioremap_resource(&pdev->dev, mem);
605 if (IS_ERR(mbox_base))
606 return PTR_ERR(mbox_base);
607
608 ret = omap_mbox_register(&pdev->dev, list);
609 if (ret)
610 return ret;
611
612 platform_set_drvdata(pdev, list);
613 pm_runtime_enable(&pdev->dev);
614
615 ret = pm_runtime_get_sync(&pdev->dev);
616 if (ret < 0) {
617 pm_runtime_put_noidle(&pdev->dev);
618 goto unregister;
619 }
620
621 /*
622 * just print the raw revision register, the format is not
623 * uniform across all SoCs
624 */
625 l = mbox_read_reg(MAILBOX_REVISION);
626 dev_info(&pdev->dev, "omap mailbox rev 0x%x\n", l);
627
628 ret = pm_runtime_put_sync(&pdev->dev);
629 if (ret < 0)
630 goto unregister;
631
632 return 0;
633
634unregister:
635 pm_runtime_disable(&pdev->dev);
636 omap_mbox_unregister();
637 return ret;
638}
639
640static int omap_mbox_remove(struct platform_device *pdev)
641{
642 pm_runtime_disable(&pdev->dev);
643 omap_mbox_unregister();
644
645 return 0;
646}
647
648static struct platform_driver omap_mbox_driver = {
649 .probe = omap_mbox_probe,
650 .remove = omap_mbox_remove,
651 .driver = {
652 .name = "omap-mailbox",
653 .owner = THIS_MODULE,
654 },
655};
424 656
425static int __init omap_mbox_init(void) 657static int __init omap_mbox_init(void)
426{ 658{
@@ -435,12 +667,13 @@ static int __init omap_mbox_init(void)
435 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, 667 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
436 sizeof(mbox_msg_t)); 668 sizeof(mbox_msg_t));
437 669
438 return 0; 670 return platform_driver_register(&omap_mbox_driver);
439} 671}
440subsys_initcall(omap_mbox_init); 672subsys_initcall(omap_mbox_init);
441 673
442static void __exit omap_mbox_exit(void) 674static void __exit omap_mbox_exit(void)
443{ 675{
676 platform_driver_unregister(&omap_mbox_driver);
444 class_unregister(&omap_mbox_class); 677 class_unregister(&omap_mbox_class);
445} 678}
446module_exit(omap_mbox_exit); 679module_exit(omap_mbox_exit);
diff --git a/drivers/mailbox/omap-mbox.h b/drivers/mailbox/omap-mbox.h
deleted file mode 100644
index fae215195590..000000000000
--- a/drivers/mailbox/omap-mbox.h
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * omap-mbox.h: OMAP mailbox internal definitions
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef OMAP_MBOX_H
10#define OMAP_MBOX_H
11
12#include <linux/device.h>
13#include <linux/interrupt.h>
14#include <linux/kfifo.h>
15#include <linux/spinlock.h>
16#include <linux/workqueue.h>
17#include <linux/omap-mailbox.h>
18
19struct omap_mbox_ops {
20 int (*startup)(struct omap_mbox *mbox);
21 void (*shutdown)(struct omap_mbox *mbox);
22 /* fifo */
23 mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
24 void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
25 int (*fifo_empty)(struct omap_mbox *mbox);
26 int (*fifo_full)(struct omap_mbox *mbox);
27 /* irq */
28 void (*enable_irq)(struct omap_mbox *mbox,
29 omap_mbox_irq_t irq);
30 void (*disable_irq)(struct omap_mbox *mbox,
31 omap_mbox_irq_t irq);
32 void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
33 int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
34 /* ctx */
35 void (*save_ctx)(struct omap_mbox *mbox);
36 void (*restore_ctx)(struct omap_mbox *mbox);
37};
38
39struct omap_mbox_queue {
40 spinlock_t lock;
41 struct kfifo fifo;
42 struct work_struct work;
43 struct tasklet_struct tasklet;
44 struct omap_mbox *mbox;
45 bool full;
46};
47
48struct omap_mbox {
49 const char *name;
50 int irq;
51 struct omap_mbox_queue *txq, *rxq;
52 struct omap_mbox_ops *ops;
53 struct device *dev;
54 void *priv;
55 int use_count;
56 struct blocking_notifier_head notifier;
57};
58
59int omap_mbox_register(struct device *parent, struct omap_mbox **);
60int omap_mbox_unregister(void);
61
62#endif /* OMAP_MBOX_H */