aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorSuman Anna <s-anna@ti.com>2013-03-12 18:55:29 -0400
committerSuman Anna <s-anna@ti.com>2013-06-11 12:41:51 -0400
commitc869c75c16b3d1ffcf64fb2fd63ba0c4a369071c (patch)
tree02be072bd60241b604e2295addf78e817c47e3ca /arch/arm
parentfe32c1f6024e357f586b1d666237cab80a1215ce (diff)
mailbox/omap: move the OMAP mailbox framework to drivers
The mailbox hardware (in OMAP) uses a queued mailbox interrupt mechanism that provides a communication channel between processors through a set of registers and their associated interrupt signals by sending and receiving messages. The OMAP mailbox framework/driver code is moved to be under drivers/mailbox, in preparation for adapting to a common mailbox driver framework. This allows the build for OMAP mailbox to be enabled (it was disabled during the multi-platform support). As part of the migration from plat and mach code: - Kconfig symbols have been renamed to build OMAP1 or OMAP2+ drivers. - mailbox.h under plat-omap/plat/include has been split into a public and private header files. The public header has only the API related functions and types. - The module name mailbox.ko from plat-omap is changed to omap-mailbox.ko - The module name mailbox_mach.ko from mach-omapX is changed as mailbox_omap1.ko for OMAP1 mailbox_omap2.ko for OMAP2+ Cc: Tony Lindgren <tony@atomide.com> [gregkh@linuxfoundation.org: ack for staging part] Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Omar Ramirez Luna <omar.ramirez@copitl.com> Signed-off-by: Suman Anna <s-anna@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/configs/omap1_defconfig3
-rw-r--r--arch/arm/mach-omap1/Makefile4
-rw-r--r--arch/arm/mach-omap1/mailbox.c202
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/devices.c4
-rw-r--r--arch/arm/mach-omap2/mailbox.c358
-rw-r--r--arch/arm/plat-omap/Kconfig16
-rw-r--r--arch/arm/plat-omap/Makefile3
-rw-r--r--arch/arm/plat-omap/include/plat/mailbox.h105
-rw-r--r--arch/arm/plat-omap/mailbox.c435
10 files changed, 4 insertions, 1129 deletions
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index 9940f7b4e438..d74edbad18fc 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -26,7 +26,8 @@ CONFIG_ARCH_OMAP=y
26CONFIG_ARCH_OMAP1=y 26CONFIG_ARCH_OMAP1=y
27CONFIG_OMAP_RESET_CLOCKS=y 27CONFIG_OMAP_RESET_CLOCKS=y
28# CONFIG_OMAP_MUX is not set 28# CONFIG_OMAP_MUX is not set
29CONFIG_OMAP_MBOX_FWK=y 29CONFIG_MAILBOX=y
30CONFIG_OMAP1_MBOX=y
30CONFIG_OMAP_32K_TIMER=y 31CONFIG_OMAP_32K_TIMER=y
31CONFIG_OMAP_DM_TIMER=y 32CONFIG_OMAP_DM_TIMER=y
32CONFIG_ARCH_OMAP730=y 33CONFIG_ARCH_OMAP730=y
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 222d58c0ae76..3889b6cd211e 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -19,10 +19,6 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
19# Power Management 19# Power Management
20obj-$(CONFIG_PM) += pm.o sleep.o 20obj-$(CONFIG_PM) += pm.o sleep.o
21 21
22# DSP
23obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
24mailbox_mach-objs := mailbox.o
25
26i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o 22i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
27obj-y += $(i2c-omap-m) $(i2c-omap-y) 23obj-y += $(i2c-omap-m) $(i2c-omap-y)
28 24
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
deleted file mode 100644
index 7246a5258292..000000000000
--- a/arch/arm/mach-omap1/mailbox.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/*
2 * Mailbox reservation modules for OMAP1
3 *
4 * Copyright (C) 2006-2009 Nokia Corporation
5 * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11
12#include <linux/module.h>
13#include <linux/interrupt.h>
14#include <linux/platform_device.h>
15#include <linux/io.h>
16#include <plat/mailbox.h>
17
18#define MAILBOX_ARM2DSP1 0x00
19#define MAILBOX_ARM2DSP1b 0x04
20#define MAILBOX_DSP2ARM1 0x08
21#define MAILBOX_DSP2ARM1b 0x0c
22#define MAILBOX_DSP2ARM2 0x10
23#define MAILBOX_DSP2ARM2b 0x14
24#define MAILBOX_ARM2DSP1_Flag 0x18
25#define MAILBOX_DSP2ARM1_Flag 0x1c
26#define MAILBOX_DSP2ARM2_Flag 0x20
27
28static void __iomem *mbox_base;
29
30struct omap_mbox1_fifo {
31 unsigned long cmd;
32 unsigned long data;
33 unsigned long flag;
34};
35
36struct omap_mbox1_priv {
37 struct omap_mbox1_fifo tx_fifo;
38 struct omap_mbox1_fifo rx_fifo;
39};
40
41static inline int mbox_read_reg(size_t ofs)
42{
43 return __raw_readw(mbox_base + ofs);
44}
45
46static inline void mbox_write_reg(u32 val, size_t ofs)
47{
48 __raw_writew(val, mbox_base + ofs);
49}
50
51/* msg */
52static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox)
53{
54 struct omap_mbox1_fifo *fifo =
55 &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
56 mbox_msg_t msg;
57
58 msg = mbox_read_reg(fifo->data);
59 msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16;
60
61 return msg;
62}
63
64static void
65omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
66{
67 struct omap_mbox1_fifo *fifo =
68 &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo;
69
70 mbox_write_reg(msg & 0xffff, fifo->data);
71 mbox_write_reg(msg >> 16, fifo->cmd);
72}
73
74static int omap1_mbox_fifo_empty(struct omap_mbox *mbox)
75{
76 return 0;
77}
78
79static int omap1_mbox_fifo_full(struct omap_mbox *mbox)
80{
81 struct omap_mbox1_fifo *fifo =
82 &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
83
84 return mbox_read_reg(fifo->flag);
85}
86
87/* irq */
88static void
89omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
90{
91 if (irq == IRQ_RX)
92 enable_irq(mbox->irq);
93}
94
95static void
96omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
97{
98 if (irq == IRQ_RX)
99 disable_irq(mbox->irq);
100}
101
102static int
103omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
104{
105 if (irq == IRQ_TX)
106 return 0;
107 return 1;
108}
109
110static struct omap_mbox_ops omap1_mbox_ops = {
111 .type = OMAP_MBOX_TYPE1,
112 .fifo_read = omap1_mbox_fifo_read,
113 .fifo_write = omap1_mbox_fifo_write,
114 .fifo_empty = omap1_mbox_fifo_empty,
115 .fifo_full = omap1_mbox_fifo_full,
116 .enable_irq = omap1_mbox_enable_irq,
117 .disable_irq = omap1_mbox_disable_irq,
118 .is_irq = omap1_mbox_is_irq,
119};
120
121/* FIXME: the following struct should be created automatically by the user id */
122
123/* DSP */
124static struct omap_mbox1_priv omap1_mbox_dsp_priv = {
125 .tx_fifo = {
126 .cmd = MAILBOX_ARM2DSP1b,
127 .data = MAILBOX_ARM2DSP1,
128 .flag = MAILBOX_ARM2DSP1_Flag,
129 },
130 .rx_fifo = {
131 .cmd = MAILBOX_DSP2ARM1b,
132 .data = MAILBOX_DSP2ARM1,
133 .flag = MAILBOX_DSP2ARM1_Flag,
134 },
135};
136
137static struct omap_mbox mbox_dsp_info = {
138 .name = "dsp",
139 .ops = &omap1_mbox_ops,
140 .priv = &omap1_mbox_dsp_priv,
141};
142
143static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL };
144
145static int omap1_mbox_probe(struct platform_device *pdev)
146{
147 struct resource *mem;
148 int ret;
149 struct omap_mbox **list;
150
151 list = omap1_mboxes;
152 list[0]->irq = platform_get_irq_byname(pdev, "dsp");
153
154 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
155 if (!mem)
156 return -ENOENT;
157
158 mbox_base = ioremap(mem->start, resource_size(mem));
159 if (!mbox_base)
160 return -ENOMEM;
161
162 ret = omap_mbox_register(&pdev->dev, list);
163 if (ret) {
164 iounmap(mbox_base);
165 return ret;
166 }
167
168 return 0;
169}
170
171static int omap1_mbox_remove(struct platform_device *pdev)
172{
173 omap_mbox_unregister();
174 iounmap(mbox_base);
175 return 0;
176}
177
178static struct platform_driver omap1_mbox_driver = {
179 .probe = omap1_mbox_probe,
180 .remove = omap1_mbox_remove,
181 .driver = {
182 .name = "omap-mailbox",
183 },
184};
185
186static int __init omap1_mbox_init(void)
187{
188 return platform_driver_register(&omap1_mbox_driver);
189}
190
191static void __exit omap1_mbox_exit(void)
192{
193 platform_driver_unregister(&omap1_mbox_driver);
194}
195
196module_init(omap1_mbox_init);
197module_exit(omap1_mbox_exit);
198
199MODULE_LICENSE("GPL v2");
200MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions");
201MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
202MODULE_ALIAS("platform:omap1-mailbox");
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 55a9d6777683..f2d19af051eb 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -203,9 +203,6 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
203obj-$(CONFIG_OMAP3_EMU) += emu.o 203obj-$(CONFIG_OMAP3_EMU) += emu.o
204obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o 204obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
205 205
206obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
207mailbox_mach-objs := mailbox.o
208
209iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o 206iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o
210obj-y += $(iommu-m) $(iommu-y) 207obj-y += $(iommu-m) $(iommu-y)
211 208
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 4c97a86115e6..73762accd128 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -328,7 +328,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data
328 return 0; 328 return 0;
329} 329}
330 330
331#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE) 331#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
332static inline void __init omap_init_mbox(void) 332static inline void __init omap_init_mbox(void)
333{ 333{
334 struct omap_hwmod *oh; 334 struct omap_hwmod *oh;
@@ -352,7 +352,7 @@ static inline void __init omap_init_mbox(void)
352} 352}
353#else 353#else
354static inline void omap_init_mbox(void) { } 354static inline void omap_init_mbox(void) { }
355#endif /* CONFIG_OMAP_MBOX_FWK */ 355#endif /* CONFIG_OMAP2PLUS_MBOX */
356 356
357static inline void omap_init_sti(void) {} 357static inline void omap_init_sti(void) {}
358 358
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
deleted file mode 100644
index de21198d54ff..000000000000
--- a/arch/arm/mach-omap2/mailbox.c
+++ /dev/null
@@ -1,358 +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 <plat/mailbox.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#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
29#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
30
31#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
32#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
33#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
34
35#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
36#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
37
38#define MBOX_REG_SIZE 0x120
39
40#define OMAP4_MBOX_REG_SIZE 0x130
41
42#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
43#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
44
45static void __iomem *mbox_base;
46
47struct omap_mbox2_fifo {
48 unsigned long msg;
49 unsigned long fifo_stat;
50 unsigned long msg_stat;
51};
52
53struct omap_mbox2_priv {
54 struct omap_mbox2_fifo tx_fifo;
55 struct omap_mbox2_fifo rx_fifo;
56 unsigned long irqenable;
57 unsigned long irqstatus;
58 u32 newmsg_bit;
59 u32 notfull_bit;
60 u32 ctx[OMAP4_MBOX_NR_REGS];
61 unsigned long irqdisable;
62 u32 intr_type;
63};
64
65static inline unsigned int mbox_read_reg(size_t ofs)
66{
67 return __raw_readl(mbox_base + ofs);
68}
69
70static inline void mbox_write_reg(u32 val, size_t ofs)
71{
72 __raw_writel(val, mbox_base + ofs);
73}
74
75/* Mailbox H/W preparations */
76static int omap2_mbox_startup(struct omap_mbox *mbox)
77{
78 u32 l;
79
80 pm_runtime_enable(mbox->dev->parent);
81 pm_runtime_get_sync(mbox->dev->parent);
82
83 l = mbox_read_reg(MAILBOX_REVISION);
84 pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
85
86 return 0;
87}
88
89static void omap2_mbox_shutdown(struct omap_mbox *mbox)
90{
91 pm_runtime_put_sync(mbox->dev->parent);
92 pm_runtime_disable(mbox->dev->parent);
93}
94
95/* Mailbox FIFO handle functions */
96static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
97{
98 struct omap_mbox2_fifo *fifo =
99 &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
100 return (mbox_msg_t) mbox_read_reg(fifo->msg);
101}
102
103static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
104{
105 struct omap_mbox2_fifo *fifo =
106 &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
107 mbox_write_reg(msg, fifo->msg);
108}
109
110static int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
111{
112 struct omap_mbox2_fifo *fifo =
113 &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
114 return (mbox_read_reg(fifo->msg_stat) == 0);
115}
116
117static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
118{
119 struct omap_mbox2_fifo *fifo =
120 &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
121 return mbox_read_reg(fifo->fifo_stat);
122}
123
124/* Mailbox IRQ handle functions */
125static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
126{
127 struct omap_mbox2_priv *p = mbox->priv;
128 u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
129
130 l = mbox_read_reg(p->irqenable);
131 l |= bit;
132 mbox_write_reg(l, p->irqenable);
133}
134
135static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
136{
137 struct omap_mbox2_priv *p = mbox->priv;
138 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
139
140 /*
141 * Read and update the interrupt configuration register for pre-OMAP4.
142 * OMAP4 and later SoCs have a dedicated interrupt disabling register.
143 */
144 if (!p->intr_type)
145 bit = mbox_read_reg(p->irqdisable) & ~bit;
146
147 mbox_write_reg(bit, p->irqdisable);
148}
149
150static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
151{
152 struct omap_mbox2_priv *p = mbox->priv;
153 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
154
155 mbox_write_reg(bit, p->irqstatus);
156
157 /* Flush posted write for irq status to avoid spurious interrupts */
158 mbox_read_reg(p->irqstatus);
159}
160
161static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
162{
163 struct omap_mbox2_priv *p = mbox->priv;
164 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
165 u32 enable = mbox_read_reg(p->irqenable);
166 u32 status = mbox_read_reg(p->irqstatus);
167
168 return (int)(enable & status & bit);
169}
170
171static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
172{
173 int i;
174 struct omap_mbox2_priv *p = mbox->priv;
175 int nr_regs;
176
177 if (p->intr_type)
178 nr_regs = OMAP4_MBOX_NR_REGS;
179 else
180 nr_regs = MBOX_NR_REGS;
181 for (i = 0; i < nr_regs; i++) {
182 p->ctx[i] = mbox_read_reg(i * sizeof(u32));
183
184 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
185 i, p->ctx[i]);
186 }
187}
188
189static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
190{
191 int i;
192 struct omap_mbox2_priv *p = mbox->priv;
193 int nr_regs;
194
195 if (p->intr_type)
196 nr_regs = OMAP4_MBOX_NR_REGS;
197 else
198 nr_regs = MBOX_NR_REGS;
199 for (i = 0; i < nr_regs; i++) {
200 mbox_write_reg(p->ctx[i], i * sizeof(u32));
201
202 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
203 i, p->ctx[i]);
204 }
205}
206
207static struct omap_mbox_ops omap2_mbox_ops = {
208 .type = OMAP_MBOX_TYPE2,
209 .startup = omap2_mbox_startup,
210 .shutdown = omap2_mbox_shutdown,
211 .fifo_read = omap2_mbox_fifo_read,
212 .fifo_write = omap2_mbox_fifo_write,
213 .fifo_empty = omap2_mbox_fifo_empty,
214 .fifo_full = omap2_mbox_fifo_full,
215 .enable_irq = omap2_mbox_enable_irq,
216 .disable_irq = omap2_mbox_disable_irq,
217 .ack_irq = omap2_mbox_ack_irq,
218 .is_irq = omap2_mbox_is_irq,
219 .save_ctx = omap2_mbox_save_ctx,
220 .restore_ctx = omap2_mbox_restore_ctx,
221};
222
223static int omap2_mbox_probe(struct platform_device *pdev)
224{
225 struct resource *mem;
226 int ret;
227 struct omap_mbox **list, *mbox, *mboxblk;
228 struct omap_mbox2_priv *priv, *privblk;
229 struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
230 struct omap_mbox_dev_info *info;
231 int i;
232
233 if (!pdata || !pdata->info_cnt || !pdata->info) {
234 pr_err("%s: platform not supported\n", __func__);
235 return -ENODEV;
236 }
237
238 /* allocate one extra for marking end of list */
239 list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL);
240 if (!list)
241 return -ENOMEM;
242
243 mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL);
244 if (!mboxblk) {
245 ret = -ENOMEM;
246 goto free_list;
247 }
248
249 privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL);
250 if (!privblk) {
251 ret = -ENOMEM;
252 goto free_mboxblk;
253 }
254
255 info = pdata->info;
256 for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
257 priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
258 priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
259 priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
260 priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
261 priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
262 priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
263 if (pdata->intr_type) {
264 priv->irqenable = OMAP4_MAILBOX_IRQENABLE(info->usr_id);
265 priv->irqstatus = OMAP4_MAILBOX_IRQSTATUS(info->usr_id);
266 priv->irqdisable =
267 OMAP4_MAILBOX_IRQENABLE_CLR(info->usr_id);
268 } else {
269 priv->irqenable = MAILBOX_IRQENABLE(info->usr_id);
270 priv->irqstatus = MAILBOX_IRQSTATUS(info->usr_id);
271 priv->irqdisable = MAILBOX_IRQENABLE(info->usr_id);
272 }
273 priv->intr_type = pdata->intr_type;
274
275 mbox->priv = priv;
276 mbox->name = info->name;
277 mbox->ops = &omap2_mbox_ops;
278 mbox->irq = platform_get_irq(pdev, info->irq_id);
279 if (mbox->irq < 0) {
280 ret = mbox->irq;
281 goto free_privblk;
282 }
283 list[i] = mbox++;
284 }
285
286 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 if (!mem) {
288 ret = -ENOENT;
289 goto free_privblk;
290 }
291
292 mbox_base = ioremap(mem->start, resource_size(mem));
293 if (!mbox_base) {
294 ret = -ENOMEM;
295 goto free_privblk;
296 }
297
298 ret = omap_mbox_register(&pdev->dev, list);
299 if (ret)
300 goto unmap_mbox;
301 platform_set_drvdata(pdev, list);
302
303 return 0;
304
305unmap_mbox:
306 iounmap(mbox_base);
307free_privblk:
308 kfree(privblk);
309free_mboxblk:
310 kfree(mboxblk);
311free_list:
312 kfree(list);
313 return ret;
314}
315
316static int omap2_mbox_remove(struct platform_device *pdev)
317{
318 struct omap_mbox2_priv *privblk;
319 struct omap_mbox **list = platform_get_drvdata(pdev);
320 struct omap_mbox *mboxblk = list[0];
321
322 privblk = mboxblk->priv;
323 omap_mbox_unregister();
324 iounmap(mbox_base);
325 kfree(privblk);
326 kfree(mboxblk);
327 kfree(list);
328 platform_set_drvdata(pdev, NULL);
329
330 return 0;
331}
332
333static struct platform_driver omap2_mbox_driver = {
334 .probe = omap2_mbox_probe,
335 .remove = omap2_mbox_remove,
336 .driver = {
337 .name = "omap-mailbox",
338 },
339};
340
341static int __init omap2_mbox_init(void)
342{
343 return platform_driver_register(&omap2_mbox_driver);
344}
345
346static void __exit omap2_mbox_exit(void)
347{
348 platform_driver_unregister(&omap2_mbox_driver);
349}
350
351module_init(omap2_mbox_init);
352module_exit(omap2_mbox_exit);
353
354MODULE_LICENSE("GPL v2");
355MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
356MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
357MODULE_AUTHOR("Paul Mundt");
358MODULE_ALIAS("platform:omap2-mailbox");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index ce66eb9be481..f82bae2171eb 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -86,22 +86,6 @@ config OMAP_MUX_WARNINGS
86 to change the pin multiplexing setup. When there are no warnings 86 to change the pin multiplexing setup. When there are no warnings
87 printed, it's safe to deselect OMAP_MUX for your product. 87 printed, it's safe to deselect OMAP_MUX for your product.
88 88
89config OMAP_MBOX_FWK
90 tristate "Mailbox framework support"
91 depends on ARCH_OMAP && !ARCH_MULTIPLATFORM
92 help
93 Say Y here if you want to use OMAP Mailbox framework support for
94 DSP, IVA1.0 and IVA2 in OMAP1/2/3.
95
96config OMAP_MBOX_KFIFO_SIZE
97 int "Mailbox kfifo default buffer size (bytes)"
98 depends on OMAP_MBOX_FWK
99 default 256
100 help
101 Specify the default size of mailbox's kfifo buffers (bytes).
102 This can also be changed at runtime (via the mbox_kfifo_size
103 module parameter).
104
105config OMAP_IOMMU_IVA2 89config OMAP_IOMMU_IVA2
106 bool 90 bool
107 91
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 31199417b56a..0b01b68fd033 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -17,6 +17,3 @@ obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
17i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o 17i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
18obj-y += $(i2c-omap-m) $(i2c-omap-y) 18obj-y += $(i2c-omap-m) $(i2c-omap-y)
19 19
20# OMAP mailbox framework
21obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
22
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h
deleted file mode 100644
index e98f7e234686..000000000000
--- a/arch/arm/plat-omap/include/plat/mailbox.h
+++ /dev/null
@@ -1,105 +0,0 @@
1/* mailbox.h */
2
3#ifndef MAILBOX_H
4#define MAILBOX_H
5
6#include <linux/spinlock.h>
7#include <linux/workqueue.h>
8#include <linux/interrupt.h>
9#include <linux/device.h>
10#include <linux/kfifo.h>
11
12typedef u32 mbox_msg_t;
13struct omap_mbox;
14
15typedef int __bitwise omap_mbox_irq_t;
16#define IRQ_TX ((__force omap_mbox_irq_t) 1)
17#define IRQ_RX ((__force omap_mbox_irq_t) 2)
18
19typedef int __bitwise omap_mbox_type_t;
20#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1)
21#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2)
22
23struct omap_mbox_ops {
24 omap_mbox_type_t type;
25 int (*startup)(struct omap_mbox *mbox);
26 void (*shutdown)(struct omap_mbox *mbox);
27 /* fifo */
28 mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
29 void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
30 int (*fifo_empty)(struct omap_mbox *mbox);
31 int (*fifo_full)(struct omap_mbox *mbox);
32 /* irq */
33 void (*enable_irq)(struct omap_mbox *mbox,
34 omap_mbox_irq_t irq);
35 void (*disable_irq)(struct omap_mbox *mbox,
36 omap_mbox_irq_t irq);
37 void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
38 int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
39 /* ctx */
40 void (*save_ctx)(struct omap_mbox *mbox);
41 void (*restore_ctx)(struct omap_mbox *mbox);
42};
43
44struct omap_mbox_queue {
45 spinlock_t lock;
46 struct kfifo fifo;
47 struct work_struct work;
48 struct tasklet_struct tasklet;
49 struct omap_mbox *mbox;
50 bool full;
51};
52
53struct omap_mbox {
54 const char *name;
55 unsigned int irq;
56 struct omap_mbox_queue *txq, *rxq;
57 struct omap_mbox_ops *ops;
58 struct device *dev;
59 void *priv;
60 int use_count;
61 struct blocking_notifier_head notifier;
62};
63
64int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
65void omap_mbox_init_seq(struct omap_mbox *);
66
67struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb);
68void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb);
69
70int omap_mbox_register(struct device *parent, struct omap_mbox **);
71int omap_mbox_unregister(void);
72
73static inline void omap_mbox_save_ctx(struct omap_mbox *mbox)
74{
75 if (!mbox->ops->save_ctx) {
76 dev_err(mbox->dev, "%s:\tno save\n", __func__);
77 return;
78 }
79
80 mbox->ops->save_ctx(mbox);
81}
82
83static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox)
84{
85 if (!mbox->ops->restore_ctx) {
86 dev_err(mbox->dev, "%s:\tno restore\n", __func__);
87 return;
88 }
89
90 mbox->ops->restore_ctx(mbox);
91}
92
93static inline void omap_mbox_enable_irq(struct omap_mbox *mbox,
94 omap_mbox_irq_t irq)
95{
96 mbox->ops->enable_irq(mbox, irq);
97}
98
99static inline void omap_mbox_disable_irq(struct omap_mbox *mbox,
100 omap_mbox_irq_t irq)
101{
102 mbox->ops->disable_irq(mbox, irq);
103}
104
105#endif /* MAILBOX_H */
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
deleted file mode 100644
index f65eaf00fce6..000000000000
--- a/arch/arm/plat-omap/mailbox.c
+++ /dev/null
@@ -1,435 +0,0 @@
1/*
2 * OMAP mailbox driver
3 *
4 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
5 *
6 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/interrupt.h>
25#include <linux/spinlock.h>
26#include <linux/mutex.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/kfifo.h>
30#include <linux/err.h>
31#include <linux/notifier.h>
32#include <linux/module.h>
33
34#include <plat/mailbox.h>
35
36static struct omap_mbox **mboxes;
37
38static int mbox_configured;
39static DEFINE_MUTEX(mbox_configured_lock);
40
41static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
42module_param(mbox_kfifo_size, uint, S_IRUGO);
43MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
44
45/* Mailbox FIFO handle functions */
46static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
47{
48 return mbox->ops->fifo_read(mbox);
49}
50static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
51{
52 mbox->ops->fifo_write(mbox, msg);
53}
54static inline int mbox_fifo_empty(struct omap_mbox *mbox)
55{
56 return mbox->ops->fifo_empty(mbox);
57}
58static inline int mbox_fifo_full(struct omap_mbox *mbox)
59{
60 return mbox->ops->fifo_full(mbox);
61}
62
63/* Mailbox IRQ handle functions */
64static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
65{
66 if (mbox->ops->ack_irq)
67 mbox->ops->ack_irq(mbox, irq);
68}
69static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
70{
71 return mbox->ops->is_irq(mbox, irq);
72}
73
74/*
75 * message sender
76 */
77static int __mbox_poll_for_space(struct omap_mbox *mbox)
78{
79 int ret = 0, i = 1000;
80
81 while (mbox_fifo_full(mbox)) {
82 if (mbox->ops->type == OMAP_MBOX_TYPE2)
83 return -1;
84 if (--i == 0)
85 return -1;
86 udelay(1);
87 }
88 return ret;
89}
90
91int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
92{
93 struct omap_mbox_queue *mq = mbox->txq;
94 int ret = 0, len;
95
96 spin_lock_bh(&mq->lock);
97
98 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
99 ret = -ENOMEM;
100 goto out;
101 }
102
103 if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) {
104 mbox_fifo_write(mbox, msg);
105 goto out;
106 }
107
108 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
109 WARN_ON(len != sizeof(msg));
110
111 tasklet_schedule(&mbox->txq->tasklet);
112
113out:
114 spin_unlock_bh(&mq->lock);
115 return ret;
116}
117EXPORT_SYMBOL(omap_mbox_msg_send);
118
119static void mbox_tx_tasklet(unsigned long tx_data)
120{
121 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
122 struct omap_mbox_queue *mq = mbox->txq;
123 mbox_msg_t msg;
124 int ret;
125
126 while (kfifo_len(&mq->fifo)) {
127 if (__mbox_poll_for_space(mbox)) {
128 omap_mbox_enable_irq(mbox, IRQ_TX);
129 break;
130 }
131
132 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
133 sizeof(msg));
134 WARN_ON(ret != sizeof(msg));
135
136 mbox_fifo_write(mbox, msg);
137 }
138}
139
140/*
141 * Message receiver(workqueue)
142 */
143static void mbox_rx_work(struct work_struct *work)
144{
145 struct omap_mbox_queue *mq =
146 container_of(work, struct omap_mbox_queue, work);
147 mbox_msg_t msg;
148 int len;
149
150 while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
151 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
152 WARN_ON(len != sizeof(msg));
153
154 blocking_notifier_call_chain(&mq->mbox->notifier, len,
155 (void *)msg);
156 spin_lock_irq(&mq->lock);
157 if (mq->full) {
158 mq->full = false;
159 omap_mbox_enable_irq(mq->mbox, IRQ_RX);
160 }
161 spin_unlock_irq(&mq->lock);
162 }
163}
164
165/*
166 * Mailbox interrupt handler
167 */
168static void __mbox_tx_interrupt(struct omap_mbox *mbox)
169{
170 omap_mbox_disable_irq(mbox, IRQ_TX);
171 ack_mbox_irq(mbox, IRQ_TX);
172 tasklet_schedule(&mbox->txq->tasklet);
173}
174
175static void __mbox_rx_interrupt(struct omap_mbox *mbox)
176{
177 struct omap_mbox_queue *mq = mbox->rxq;
178 mbox_msg_t msg;
179 int len;
180
181 while (!mbox_fifo_empty(mbox)) {
182 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
183 omap_mbox_disable_irq(mbox, IRQ_RX);
184 mq->full = true;
185 goto nomem;
186 }
187
188 msg = mbox_fifo_read(mbox);
189
190 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
191 WARN_ON(len != sizeof(msg));
192
193 if (mbox->ops->type == OMAP_MBOX_TYPE1)
194 break;
195 }
196
197 /* no more messages in the fifo. clear IRQ source. */
198 ack_mbox_irq(mbox, IRQ_RX);
199nomem:
200 schedule_work(&mbox->rxq->work);
201}
202
203static irqreturn_t mbox_interrupt(int irq, void *p)
204{
205 struct omap_mbox *mbox = p;
206
207 if (is_mbox_irq(mbox, IRQ_TX))
208 __mbox_tx_interrupt(mbox);
209
210 if (is_mbox_irq(mbox, IRQ_RX))
211 __mbox_rx_interrupt(mbox);
212
213 return IRQ_HANDLED;
214}
215
216static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
217 void (*work) (struct work_struct *),
218 void (*tasklet)(unsigned long))
219{
220 struct omap_mbox_queue *mq;
221
222 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
223 if (!mq)
224 return NULL;
225
226 spin_lock_init(&mq->lock);
227
228 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
229 goto error;
230
231 if (work)
232 INIT_WORK(&mq->work, work);
233
234 if (tasklet)
235 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
236 return mq;
237error:
238 kfree(mq);
239 return NULL;
240}
241
242static void mbox_queue_free(struct omap_mbox_queue *q)
243{
244 kfifo_free(&q->fifo);
245 kfree(q);
246}
247
248static int omap_mbox_startup(struct omap_mbox *mbox)
249{
250 int ret = 0;
251 struct omap_mbox_queue *mq;
252
253 mutex_lock(&mbox_configured_lock);
254 if (!mbox_configured++) {
255 if (likely(mbox->ops->startup)) {
256 ret = mbox->ops->startup(mbox);
257 if (unlikely(ret))
258 goto fail_startup;
259 } else
260 goto fail_startup;
261 }
262
263 if (!mbox->use_count++) {
264 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
265 if (!mq) {
266 ret = -ENOMEM;
267 goto fail_alloc_txq;
268 }
269 mbox->txq = mq;
270
271 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
272 if (!mq) {
273 ret = -ENOMEM;
274 goto fail_alloc_rxq;
275 }
276 mbox->rxq = mq;
277 mq->mbox = mbox;
278 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
279 mbox->name, mbox);
280 if (unlikely(ret)) {
281 pr_err("failed to register mailbox interrupt:%d\n",
282 ret);
283 goto fail_request_irq;
284 }
285
286 omap_mbox_enable_irq(mbox, IRQ_RX);
287 }
288 mutex_unlock(&mbox_configured_lock);
289 return 0;
290
291fail_request_irq:
292 mbox_queue_free(mbox->rxq);
293fail_alloc_rxq:
294 mbox_queue_free(mbox->txq);
295fail_alloc_txq:
296 if (mbox->ops->shutdown)
297 mbox->ops->shutdown(mbox);
298 mbox->use_count--;
299fail_startup:
300 mbox_configured--;
301 mutex_unlock(&mbox_configured_lock);
302 return ret;
303}
304
305static void omap_mbox_fini(struct omap_mbox *mbox)
306{
307 mutex_lock(&mbox_configured_lock);
308
309 if (!--mbox->use_count) {
310 omap_mbox_disable_irq(mbox, IRQ_RX);
311 free_irq(mbox->irq, mbox);
312 tasklet_kill(&mbox->txq->tasklet);
313 flush_work(&mbox->rxq->work);
314 mbox_queue_free(mbox->txq);
315 mbox_queue_free(mbox->rxq);
316 }
317
318 if (likely(mbox->ops->shutdown)) {
319 if (!--mbox_configured)
320 mbox->ops->shutdown(mbox);
321 }
322
323 mutex_unlock(&mbox_configured_lock);
324}
325
326struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
327{
328 struct omap_mbox *_mbox, *mbox = NULL;
329 int i, ret;
330
331 if (!mboxes)
332 return ERR_PTR(-EINVAL);
333
334 for (i = 0; (_mbox = mboxes[i]); i++) {
335 if (!strcmp(_mbox->name, name)) {
336 mbox = _mbox;
337 break;
338 }
339 }
340
341 if (!mbox)
342 return ERR_PTR(-ENOENT);
343
344 if (nb)
345 blocking_notifier_chain_register(&mbox->notifier, nb);
346
347 ret = omap_mbox_startup(mbox);
348 if (ret) {
349 blocking_notifier_chain_unregister(&mbox->notifier, nb);
350 return ERR_PTR(-ENODEV);
351 }
352
353 return mbox;
354}
355EXPORT_SYMBOL(omap_mbox_get);
356
357void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
358{
359 blocking_notifier_chain_unregister(&mbox->notifier, nb);
360 omap_mbox_fini(mbox);
361}
362EXPORT_SYMBOL(omap_mbox_put);
363
364static struct class omap_mbox_class = { .name = "mbox", };
365
366int omap_mbox_register(struct device *parent, struct omap_mbox **list)
367{
368 int ret;
369 int i;
370
371 mboxes = list;
372 if (!mboxes)
373 return -EINVAL;
374
375 for (i = 0; mboxes[i]; i++) {
376 struct omap_mbox *mbox = mboxes[i];
377 mbox->dev = device_create(&omap_mbox_class,
378 parent, 0, mbox, "%s", mbox->name);
379 if (IS_ERR(mbox->dev)) {
380 ret = PTR_ERR(mbox->dev);
381 goto err_out;
382 }
383
384 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
385 }
386 return 0;
387
388err_out:
389 while (i--)
390 device_unregister(mboxes[i]->dev);
391 return ret;
392}
393EXPORT_SYMBOL(omap_mbox_register);
394
395int omap_mbox_unregister(void)
396{
397 int i;
398
399 if (!mboxes)
400 return -EINVAL;
401
402 for (i = 0; mboxes[i]; i++)
403 device_unregister(mboxes[i]->dev);
404 mboxes = NULL;
405 return 0;
406}
407EXPORT_SYMBOL(omap_mbox_unregister);
408
409static int __init omap_mbox_init(void)
410{
411 int err;
412
413 err = class_register(&omap_mbox_class);
414 if (err)
415 return err;
416
417 /* kfifo size sanity check: alignment and minimal size */
418 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
419 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
420 sizeof(mbox_msg_t));
421
422 return 0;
423}
424subsys_initcall(omap_mbox_init);
425
426static void __exit omap_mbox_exit(void)
427{
428 class_unregister(&omap_mbox_class);
429}
430module_exit(omap_mbox_exit);
431
432MODULE_LICENSE("GPL v2");
433MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
434MODULE_AUTHOR("Toshihiro Kobayashi");
435MODULE_AUTHOR("Hiroshi DOYU");