aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuman Anna <s-anna@ti.com>2014-11-03 18:05:50 -0500
committerJassi Brar <jaswinder.singh@linaro.org>2014-11-27 02:21:04 -0500
commit8841a66aaa7c3b1dfeeb4192d05f2ca86df58f00 (patch)
treeed0b18adc3cba64eebcf57a194ed4689db12b43a
parent97b0c7bd2e86c6e1e00c6b7178cf953d5f70c71a (diff)
mailbox/omap: adapt to the new mailbox framework
The OMAP mailbox driver and its existing clients (remoteproc for OMAP4+) are adapted to use the generic mailbox framework. The main changes for the adaptation are: - The tasklet used for Tx is replaced with the state machine from the generic mailbox framework. The workqueue used for processing the received messages stays intact for minimizing the effects on the OMAP mailbox clients. - The existing exported client API, omap_mbox_get, omap_mbox_put and omap_mbox_send_msg are deleted, as the framework provides equivalent functionality. A OMAP-specific omap_mbox_request_channel is added though to support non-DT way of requesting mailboxes. - The OMAP mailbox driver is integrated with the mailbox framework through the proper implementations of mbox_chan_ops, except for .last_tx_done and .peek_data. The OMAP mailbox driver does not need these ops, as it is completely interrupt driven. - The OMAP mailbox driver uses a custom of_xlate controller ops that allows phandles for the pargs specifier instead of indexing to avoid any channel registration order dependencies. - The new framework does not support multiple clients operating on a single channel, so the reference counting logic is simplified. - The remoteproc driver (current client) is adapted to use the new API. The notifier callbacks used within this client is replaced with the regular callbacks from the newer framework. - The exported OMAP mailbox API are limited to omap_mbox_save_ctx, omap_mbox_restore_ctx, omap_mbox_enable_irq & omap_mbox_disable_irq, with the signature modified to take in the new mbox_chan handle instead of the OMAP specific omap_mbox handle. The first 2 will be removed when the OMAP mailbox driver is adapted to runtime_pm. The other exported API omap_mbox_request_channel will be removed once existing legacy users are converted to DT. Signed-off-by: Suman Anna <s-anna@ti.com> Cc: Ohad Ben-Cohen <ohad@wizery.com> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/mailbox/omap-mailbox.txt23
-rw-r--r--drivers/mailbox/omap-mailbox.c346
-rw-r--r--drivers/remoteproc/omap_remoteproc.c51
-rw-r--r--include/linux/omap-mailbox.h16
4 files changed, 256 insertions, 180 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
index 48edc4b92afb..d1a043339c11 100644
--- a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
+++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
@@ -43,6 +43,9 @@ Required properties:
43 device. The format is dependent on which interrupt 43 device. The format is dependent on which interrupt
44 controller the OMAP device uses 44 controller the OMAP device uses
45- ti,hwmods: Name of the hwmod associated with the mailbox 45- ti,hwmods: Name of the hwmod associated with the mailbox
46- #mbox-cells: Common mailbox binding property to identify the number
47 of cells required for the mailbox specifier. Should be
48 1
46- ti,mbox-num-users: Number of targets (processor devices) that the mailbox 49- ti,mbox-num-users: Number of targets (processor devices) that the mailbox
47 device can interrupt 50 device can interrupt
48- ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block 51- ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block
@@ -72,6 +75,18 @@ data that represent the following:
72 Cell #3 (usr_id) - mailbox user id for identifying the interrupt line 75 Cell #3 (usr_id) - mailbox user id for identifying the interrupt line
73 associated with generating a tx/rx fifo interrupt. 76 associated with generating a tx/rx fifo interrupt.
74 77
78Mailbox Users:
79==============
80A device needing to communicate with a target processor device should specify
81them using the common mailbox binding properties, "mboxes" and the optional
82"mbox-names" (please see Documentation/devicetree/bindings/mailbox/mailbox.txt
83for details). Each value of the mboxes property should contain a phandle to the
84mailbox controller device node and an args specifier that will be the phandle to
85the intended sub-mailbox child node to be used for communication. The equivalent
86"mbox-names" property value can be used to give a name to the communication channel
87to be used by the client user.
88
89
75Example: 90Example:
76-------- 91--------
77 92
@@ -81,6 +96,7 @@ mailbox: mailbox@4a0f4000 {
81 reg = <0x4a0f4000 0x200>; 96 reg = <0x4a0f4000 0x200>;
82 interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; 97 interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
83 ti,hwmods = "mailbox"; 98 ti,hwmods = "mailbox";
99 #mbox-cells = <1>;
84 ti,mbox-num-users = <3>; 100 ti,mbox-num-users = <3>;
85 ti,mbox-num-fifos = <8>; 101 ti,mbox-num-fifos = <8>;
86 mbox_ipu: mbox_ipu { 102 mbox_ipu: mbox_ipu {
@@ -93,12 +109,19 @@ mailbox: mailbox@4a0f4000 {
93 }; 109 };
94}; 110};
95 111
112dsp {
113 ...
114 mboxes = <&mailbox &mbox_dsp>;
115 ...
116};
117
96/* AM33xx */ 118/* AM33xx */
97mailbox: mailbox@480C8000 { 119mailbox: mailbox@480C8000 {
98 compatible = "ti,omap4-mailbox"; 120 compatible = "ti,omap4-mailbox";
99 reg = <0x480C8000 0x200>; 121 reg = <0x480C8000 0x200>;
100 interrupts = <77>; 122 interrupts = <77>;
101 ti,hwmods = "mailbox"; 123 ti,hwmods = "mailbox";
124 #mbox-cells = <1>;
102 ti,mbox-num-users = <4>; 125 ti,mbox-num-users = <4>;
103 ti,mbox-num-fifos = <8>; 126 ti,mbox-num-fifos = <8>;
104 mbox_wkupm3: wkup_m3 { 127 mbox_wkupm3: wkup_m3 {
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
index bcc7ee129276..66b83ca94dcf 100644
--- a/drivers/mailbox/omap-mailbox.c
+++ b/drivers/mailbox/omap-mailbox.c
@@ -29,13 +29,14 @@
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/kfifo.h> 30#include <linux/kfifo.h>
31#include <linux/err.h> 31#include <linux/err.h>
32#include <linux/notifier.h>
33#include <linux/module.h> 32#include <linux/module.h>
34#include <linux/of_device.h> 33#include <linux/of_device.h>
35#include <linux/platform_device.h> 34#include <linux/platform_device.h>
36#include <linux/pm_runtime.h> 35#include <linux/pm_runtime.h>
37#include <linux/platform_data/mailbox-omap.h> 36#include <linux/platform_data/mailbox-omap.h>
38#include <linux/omap-mailbox.h> 37#include <linux/omap-mailbox.h>
38#include <linux/mailbox_controller.h>
39#include <linux/mailbox_client.h>
39 40
40#define MAILBOX_REVISION 0x000 41#define MAILBOX_REVISION 0x000
41#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) 42#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
@@ -80,7 +81,6 @@ struct omap_mbox_queue {
80 spinlock_t lock; 81 spinlock_t lock;
81 struct kfifo fifo; 82 struct kfifo fifo;
82 struct work_struct work; 83 struct work_struct work;
83 struct tasklet_struct tasklet;
84 struct omap_mbox *mbox; 84 struct omap_mbox *mbox;
85 bool full; 85 bool full;
86}; 86};
@@ -92,6 +92,7 @@ struct omap_mbox_device {
92 u32 num_users; 92 u32 num_users;
93 u32 num_fifos; 93 u32 num_fifos;
94 struct omap_mbox **mboxes; 94 struct omap_mbox **mboxes;
95 struct mbox_controller controller;
95 struct list_head elem; 96 struct list_head elem;
96}; 97};
97 98
@@ -110,15 +111,14 @@ struct omap_mbox_fifo_info {
110struct omap_mbox { 111struct omap_mbox {
111 const char *name; 112 const char *name;
112 int irq; 113 int irq;
113 struct omap_mbox_queue *txq, *rxq; 114 struct omap_mbox_queue *rxq;
114 struct device *dev; 115 struct device *dev;
115 struct omap_mbox_device *parent; 116 struct omap_mbox_device *parent;
116 struct omap_mbox_fifo tx_fifo; 117 struct omap_mbox_fifo tx_fifo;
117 struct omap_mbox_fifo rx_fifo; 118 struct omap_mbox_fifo rx_fifo;
118 u32 ctx[OMAP4_MBOX_NR_REGS]; 119 u32 ctx[OMAP4_MBOX_NR_REGS];
119 u32 intr_type; 120 u32 intr_type;
120 int use_count; 121 struct mbox_chan *chan;
121 struct blocking_notifier_head notifier;
122}; 122};
123 123
124/* global variables for the mailbox devices */ 124/* global variables for the mailbox devices */
@@ -129,6 +129,14 @@ static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
129module_param(mbox_kfifo_size, uint, S_IRUGO); 129module_param(mbox_kfifo_size, uint, S_IRUGO);
130MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); 130MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
131 131
132static struct omap_mbox *mbox_chan_to_omap_mbox(struct mbox_chan *chan)
133{
134 if (!chan || !chan->con_priv)
135 return NULL;
136
137 return (struct omap_mbox *)chan->con_priv;
138}
139
132static inline 140static inline
133unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs) 141unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs)
134{ 142{
@@ -194,41 +202,14 @@ static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
194 return (int)(enable & status & bit); 202 return (int)(enable & status & bit);
195} 203}
196 204
197/* 205void omap_mbox_save_ctx(struct mbox_chan *chan)
198 * message sender
199 */
200int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
201{
202 struct omap_mbox_queue *mq = mbox->txq;
203 int ret = 0, len;
204
205 spin_lock_bh(&mq->lock);
206
207 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
208 ret = -ENOMEM;
209 goto out;
210 }
211
212 if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) {
213 mbox_fifo_write(mbox, msg);
214 goto out;
215 }
216
217 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
218 WARN_ON(len != sizeof(msg));
219
220 tasklet_schedule(&mbox->txq->tasklet);
221
222out:
223 spin_unlock_bh(&mq->lock);
224 return ret;
225}
226EXPORT_SYMBOL(omap_mbox_msg_send);
227
228void omap_mbox_save_ctx(struct omap_mbox *mbox)
229{ 206{
230 int i; 207 int i;
231 int nr_regs; 208 int nr_regs;
209 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
210
211 if (WARN_ON(!mbox))
212 return;
232 213
233 if (mbox->intr_type) 214 if (mbox->intr_type)
234 nr_regs = OMAP4_MBOX_NR_REGS; 215 nr_regs = OMAP4_MBOX_NR_REGS;
@@ -243,10 +224,14 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox)
243} 224}
244EXPORT_SYMBOL(omap_mbox_save_ctx); 225EXPORT_SYMBOL(omap_mbox_save_ctx);
245 226
246void omap_mbox_restore_ctx(struct omap_mbox *mbox) 227void omap_mbox_restore_ctx(struct mbox_chan *chan)
247{ 228{
248 int i; 229 int i;
249 int nr_regs; 230 int nr_regs;
231 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
232
233 if (WARN_ON(!mbox))
234 return;
250 235
251 if (mbox->intr_type) 236 if (mbox->intr_type)
252 nr_regs = OMAP4_MBOX_NR_REGS; 237 nr_regs = OMAP4_MBOX_NR_REGS;
@@ -254,14 +239,13 @@ void omap_mbox_restore_ctx(struct omap_mbox *mbox)
254 nr_regs = MBOX_NR_REGS; 239 nr_regs = MBOX_NR_REGS;
255 for (i = 0; i < nr_regs; i++) { 240 for (i = 0; i < nr_regs; i++) {
256 mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32)); 241 mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32));
257
258 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, 242 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
259 i, mbox->ctx[i]); 243 i, mbox->ctx[i]);
260 } 244 }
261} 245}
262EXPORT_SYMBOL(omap_mbox_restore_ctx); 246EXPORT_SYMBOL(omap_mbox_restore_ctx);
263 247
264void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 248static void _omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
265{ 249{
266 u32 l; 250 u32 l;
267 struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? 251 struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
@@ -273,9 +257,8 @@ void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
273 l |= bit; 257 l |= bit;
274 mbox_write_reg(mbox->parent, l, irqenable); 258 mbox_write_reg(mbox->parent, l, irqenable);
275} 259}
276EXPORT_SYMBOL(omap_mbox_enable_irq);
277 260
278void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 261static void _omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
279{ 262{
280 struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? 263 struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
281 &mbox->tx_fifo : &mbox->rx_fifo; 264 &mbox->tx_fifo : &mbox->rx_fifo;
@@ -291,28 +274,28 @@ void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
291 274
292 mbox_write_reg(mbox->parent, bit, irqdisable); 275 mbox_write_reg(mbox->parent, bit, irqdisable);
293} 276}
294EXPORT_SYMBOL(omap_mbox_disable_irq);
295 277
296static void mbox_tx_tasklet(unsigned long tx_data) 278void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
297{ 279{
298 struct omap_mbox *mbox = (struct omap_mbox *)tx_data; 280 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
299 struct omap_mbox_queue *mq = mbox->txq;
300 mbox_msg_t msg;
301 int ret;
302 281
303 while (kfifo_len(&mq->fifo)) { 282 if (WARN_ON(!mbox))
304 if (mbox_fifo_full(mbox)) { 283 return;
305 omap_mbox_enable_irq(mbox, IRQ_TX);
306 break;
307 }
308 284
309 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, 285 _omap_mbox_enable_irq(mbox, irq);
310 sizeof(msg)); 286}
311 WARN_ON(ret != sizeof(msg)); 287EXPORT_SYMBOL(omap_mbox_enable_irq);
312 288
313 mbox_fifo_write(mbox, msg); 289void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
314 } 290{
291 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
292
293 if (WARN_ON(!mbox))
294 return;
295
296 _omap_mbox_disable_irq(mbox, irq);
315} 297}
298EXPORT_SYMBOL(omap_mbox_disable_irq);
316 299
317/* 300/*
318 * Message receiver(workqueue) 301 * Message receiver(workqueue)
@@ -328,12 +311,11 @@ static void mbox_rx_work(struct work_struct *work)
328 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); 311 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
329 WARN_ON(len != sizeof(msg)); 312 WARN_ON(len != sizeof(msg));
330 313
331 blocking_notifier_call_chain(&mq->mbox->notifier, len, 314 mbox_chan_received_data(mq->mbox->chan, (void *)msg);
332 (void *)msg);
333 spin_lock_irq(&mq->lock); 315 spin_lock_irq(&mq->lock);
334 if (mq->full) { 316 if (mq->full) {
335 mq->full = false; 317 mq->full = false;
336 omap_mbox_enable_irq(mq->mbox, IRQ_RX); 318 _omap_mbox_enable_irq(mq->mbox, IRQ_RX);
337 } 319 }
338 spin_unlock_irq(&mq->lock); 320 spin_unlock_irq(&mq->lock);
339 } 321 }
@@ -344,9 +326,9 @@ static void mbox_rx_work(struct work_struct *work)
344 */ 326 */
345static void __mbox_tx_interrupt(struct omap_mbox *mbox) 327static void __mbox_tx_interrupt(struct omap_mbox *mbox)
346{ 328{
347 omap_mbox_disable_irq(mbox, IRQ_TX); 329 _omap_mbox_disable_irq(mbox, IRQ_TX);
348 ack_mbox_irq(mbox, IRQ_TX); 330 ack_mbox_irq(mbox, IRQ_TX);
349 tasklet_schedule(&mbox->txq->tasklet); 331 mbox_chan_txdone(mbox->chan, 0);
350} 332}
351 333
352static void __mbox_rx_interrupt(struct omap_mbox *mbox) 334static void __mbox_rx_interrupt(struct omap_mbox *mbox)
@@ -357,7 +339,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
357 339
358 while (!mbox_fifo_empty(mbox)) { 340 while (!mbox_fifo_empty(mbox)) {
359 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { 341 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
360 omap_mbox_disable_irq(mbox, IRQ_RX); 342 _omap_mbox_disable_irq(mbox, IRQ_RX);
361 mq->full = true; 343 mq->full = true;
362 goto nomem; 344 goto nomem;
363 } 345 }
@@ -388,11 +370,13 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
388} 370}
389 371
390static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, 372static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
391 void (*work) (struct work_struct *), 373 void (*work)(struct work_struct *))
392 void (*tasklet)(unsigned long))
393{ 374{
394 struct omap_mbox_queue *mq; 375 struct omap_mbox_queue *mq;
395 376
377 if (!work)
378 return NULL;
379
396 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); 380 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
397 if (!mq) 381 if (!mq)
398 return NULL; 382 return NULL;
@@ -402,12 +386,9 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
402 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) 386 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
403 goto error; 387 goto error;
404 388
405 if (work) 389 INIT_WORK(&mq->work, work);
406 INIT_WORK(&mq->work, work);
407
408 if (tasklet)
409 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
410 return mq; 390 return mq;
391
411error: 392error:
412 kfree(mq); 393 kfree(mq);
413 return NULL; 394 return NULL;
@@ -423,71 +404,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
423{ 404{
424 int ret = 0; 405 int ret = 0;
425 struct omap_mbox_queue *mq; 406 struct omap_mbox_queue *mq;
426 struct omap_mbox_device *mdev = mbox->parent;
427 407
428 mutex_lock(&mdev->cfg_lock); 408 mq = mbox_queue_alloc(mbox, mbox_rx_work);
429 ret = pm_runtime_get_sync(mdev->dev); 409 if (!mq)
430 if (unlikely(ret < 0)) 410 return -ENOMEM;
431 goto fail_startup; 411 mbox->rxq = mq;
432 412 mq->mbox = mbox;
433 if (!mbox->use_count++) { 413
434 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); 414 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
435 if (!mq) { 415 mbox->name, mbox);
436 ret = -ENOMEM; 416 if (unlikely(ret)) {
437 goto fail_alloc_txq; 417 pr_err("failed to register mailbox interrupt:%d\n", ret);
438 } 418 goto fail_request_irq;
439 mbox->txq = mq; 419 }
440 420
441 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); 421 _omap_mbox_enable_irq(mbox, IRQ_RX);
442 if (!mq) {
443 ret = -ENOMEM;
444 goto fail_alloc_rxq;
445 }
446 mbox->rxq = mq;
447 mq->mbox = mbox;
448 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
449 mbox->name, mbox);
450 if (unlikely(ret)) {
451 pr_err("failed to register mailbox interrupt:%d\n",
452 ret);
453 goto fail_request_irq;
454 }
455 422
456 omap_mbox_enable_irq(mbox, IRQ_RX);
457 }
458 mutex_unlock(&mdev->cfg_lock);
459 return 0; 423 return 0;
460 424
461fail_request_irq: 425fail_request_irq:
462 mbox_queue_free(mbox->rxq); 426 mbox_queue_free(mbox->rxq);
463fail_alloc_rxq:
464 mbox_queue_free(mbox->txq);
465fail_alloc_txq:
466 pm_runtime_put_sync(mdev->dev);
467 mbox->use_count--;
468fail_startup:
469 mutex_unlock(&mdev->cfg_lock);
470 return ret; 427 return ret;
471} 428}
472 429
473static void omap_mbox_fini(struct omap_mbox *mbox) 430static void omap_mbox_fini(struct omap_mbox *mbox)
474{ 431{
475 struct omap_mbox_device *mdev = mbox->parent; 432 _omap_mbox_disable_irq(mbox, IRQ_RX);
476 433 free_irq(mbox->irq, mbox);
477 mutex_lock(&mdev->cfg_lock); 434 flush_work(&mbox->rxq->work);
478 435 mbox_queue_free(mbox->rxq);
479 if (!--mbox->use_count) {
480 omap_mbox_disable_irq(mbox, IRQ_RX);
481 free_irq(mbox->irq, mbox);
482 tasklet_kill(&mbox->txq->tasklet);
483 flush_work(&mbox->rxq->work);
484 mbox_queue_free(mbox->txq);
485 mbox_queue_free(mbox->rxq);
486 }
487
488 pm_runtime_put_sync(mdev->dev);
489
490 mutex_unlock(&mdev->cfg_lock);
491} 436}
492 437
493static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev, 438static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
@@ -509,42 +454,55 @@ static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
509 return mbox; 454 return mbox;
510} 455}
511 456
512struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) 457struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl,
458 const char *chan_name)
513{ 459{
460 struct device *dev = cl->dev;
514 struct omap_mbox *mbox = NULL; 461 struct omap_mbox *mbox = NULL;
515 struct omap_mbox_device *mdev; 462 struct omap_mbox_device *mdev;
463 struct mbox_chan *chan;
464 unsigned long flags;
516 int ret; 465 int ret;
517 466
467 if (!dev)
468 return ERR_PTR(-ENODEV);
469
470 if (dev->of_node) {
471 pr_err("%s: please use mbox_request_channel(), this API is supported only for OMAP non-DT usage\n",
472 __func__);
473 return ERR_PTR(-ENODEV);
474 }
475
518 mutex_lock(&omap_mbox_devices_lock); 476 mutex_lock(&omap_mbox_devices_lock);
519 list_for_each_entry(mdev, &omap_mbox_devices, elem) { 477 list_for_each_entry(mdev, &omap_mbox_devices, elem) {
520 mbox = omap_mbox_device_find(mdev, name); 478 mbox = omap_mbox_device_find(mdev, chan_name);
521 if (mbox) 479 if (mbox)
522 break; 480 break;
523 } 481 }
524 mutex_unlock(&omap_mbox_devices_lock); 482 mutex_unlock(&omap_mbox_devices_lock);
525 483
526 if (!mbox) 484 if (!mbox || !mbox->chan)
527 return ERR_PTR(-ENOENT); 485 return ERR_PTR(-ENOENT);
528 486
529 if (nb) 487 chan = mbox->chan;
530 blocking_notifier_chain_register(&mbox->notifier, nb); 488 spin_lock_irqsave(&chan->lock, flags);
489 chan->msg_free = 0;
490 chan->msg_count = 0;
491 chan->active_req = NULL;
492 chan->cl = cl;
493 init_completion(&chan->tx_complete);
494 spin_unlock_irqrestore(&chan->lock, flags);
531 495
532 ret = omap_mbox_startup(mbox); 496 ret = chan->mbox->ops->startup(chan);
533 if (ret) { 497 if (ret) {
534 blocking_notifier_chain_unregister(&mbox->notifier, nb); 498 pr_err("Unable to startup the chan (%d)\n", ret);
535 return ERR_PTR(-ENODEV); 499 mbox_free_channel(chan);
500 chan = ERR_PTR(ret);
536 } 501 }
537 502
538 return mbox; 503 return chan;
539}
540EXPORT_SYMBOL(omap_mbox_get);
541
542void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
543{
544 blocking_notifier_chain_unregister(&mbox->notifier, nb);
545 omap_mbox_fini(mbox);
546} 504}
547EXPORT_SYMBOL(omap_mbox_put); 505EXPORT_SYMBOL(omap_mbox_request_channel);
548 506
549static struct class omap_mbox_class = { .name = "mbox", }; 507static struct class omap_mbox_class = { .name = "mbox", };
550 508
@@ -560,25 +518,25 @@ static int omap_mbox_register(struct omap_mbox_device *mdev)
560 mboxes = mdev->mboxes; 518 mboxes = mdev->mboxes;
561 for (i = 0; mboxes[i]; i++) { 519 for (i = 0; mboxes[i]; i++) {
562 struct omap_mbox *mbox = mboxes[i]; 520 struct omap_mbox *mbox = mboxes[i];
563 mbox->dev = device_create(&omap_mbox_class, 521 mbox->dev = device_create(&omap_mbox_class, mdev->dev,
564 mdev->dev, 0, mbox, "%s", mbox->name); 522 0, mbox, "%s", mbox->name);
565 if (IS_ERR(mbox->dev)) { 523 if (IS_ERR(mbox->dev)) {
566 ret = PTR_ERR(mbox->dev); 524 ret = PTR_ERR(mbox->dev);
567 goto err_out; 525 goto err_out;
568 } 526 }
569
570 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
571 } 527 }
572 528
573 mutex_lock(&omap_mbox_devices_lock); 529 mutex_lock(&omap_mbox_devices_lock);
574 list_add(&mdev->elem, &omap_mbox_devices); 530 list_add(&mdev->elem, &omap_mbox_devices);
575 mutex_unlock(&omap_mbox_devices_lock); 531 mutex_unlock(&omap_mbox_devices_lock);
576 532
577 return 0; 533 ret = mbox_controller_register(&mdev->controller);
578 534
579err_out: 535err_out:
580 while (i--) 536 if (ret) {
581 device_unregister(mboxes[i]->dev); 537 while (i--)
538 device_unregister(mboxes[i]->dev);
539 }
582 return ret; 540 return ret;
583} 541}
584 542
@@ -594,12 +552,64 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev)
594 list_del(&mdev->elem); 552 list_del(&mdev->elem);
595 mutex_unlock(&omap_mbox_devices_lock); 553 mutex_unlock(&omap_mbox_devices_lock);
596 554
555 mbox_controller_unregister(&mdev->controller);
556
597 mboxes = mdev->mboxes; 557 mboxes = mdev->mboxes;
598 for (i = 0; mboxes[i]; i++) 558 for (i = 0; mboxes[i]; i++)
599 device_unregister(mboxes[i]->dev); 559 device_unregister(mboxes[i]->dev);
600 return 0; 560 return 0;
601} 561}
602 562
563static int omap_mbox_chan_startup(struct mbox_chan *chan)
564{
565 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
566 struct omap_mbox_device *mdev = mbox->parent;
567 int ret = 0;
568
569 mutex_lock(&mdev->cfg_lock);
570 pm_runtime_get_sync(mdev->dev);
571 ret = omap_mbox_startup(mbox);
572 if (ret)
573 pm_runtime_put_sync(mdev->dev);
574 mutex_unlock(&mdev->cfg_lock);
575 return ret;
576}
577
578static void omap_mbox_chan_shutdown(struct mbox_chan *chan)
579{
580 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
581 struct omap_mbox_device *mdev = mbox->parent;
582
583 mutex_lock(&mdev->cfg_lock);
584 omap_mbox_fini(mbox);
585 pm_runtime_put_sync(mdev->dev);
586 mutex_unlock(&mdev->cfg_lock);
587}
588
589static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
590{
591 struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
592 int ret = -EBUSY;
593
594 if (!mbox)
595 return -EINVAL;
596
597 if (!mbox_fifo_full(mbox)) {
598 mbox_fifo_write(mbox, (mbox_msg_t)data);
599 ret = 0;
600 }
601
602 /* always enable the interrupt */
603 _omap_mbox_enable_irq(mbox, IRQ_TX);
604 return ret;
605}
606
607static struct mbox_chan_ops omap_mbox_chan_ops = {
608 .startup = omap_mbox_chan_startup,
609 .send_data = omap_mbox_chan_send_data,
610 .shutdown = omap_mbox_chan_shutdown,
611};
612
603static const struct of_device_id omap_mailbox_of_match[] = { 613static const struct of_device_id omap_mailbox_of_match[] = {
604 { 614 {
605 .compatible = "ti,omap2-mailbox", 615 .compatible = "ti,omap2-mailbox",
@@ -619,10 +629,35 @@ static const struct of_device_id omap_mailbox_of_match[] = {
619}; 629};
620MODULE_DEVICE_TABLE(of, omap_mailbox_of_match); 630MODULE_DEVICE_TABLE(of, omap_mailbox_of_match);
621 631
632static struct mbox_chan *omap_mbox_of_xlate(struct mbox_controller *controller,
633 const struct of_phandle_args *sp)
634{
635 phandle phandle = sp->args[0];
636 struct device_node *node;
637 struct omap_mbox_device *mdev;
638 struct omap_mbox *mbox;
639
640 mdev = container_of(controller, struct omap_mbox_device, controller);
641 if (WARN_ON(!mdev))
642 return NULL;
643
644 node = of_find_node_by_phandle(phandle);
645 if (!node) {
646 pr_err("%s: could not find node phandle 0x%x\n",
647 __func__, phandle);
648 return NULL;
649 }
650
651 mbox = omap_mbox_device_find(mdev, node->name);
652 of_node_put(node);
653 return mbox ? mbox->chan : NULL;
654}
655
622static int omap_mbox_probe(struct platform_device *pdev) 656static int omap_mbox_probe(struct platform_device *pdev)
623{ 657{
624 struct resource *mem; 658 struct resource *mem;
625 int ret; 659 int ret;
660 struct mbox_chan *chnls;
626 struct omap_mbox **list, *mbox, *mboxblk; 661 struct omap_mbox **list, *mbox, *mboxblk;
627 struct omap_mbox_pdata *pdata = pdev->dev.platform_data; 662 struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
628 struct omap_mbox_dev_info *info = NULL; 663 struct omap_mbox_dev_info *info = NULL;
@@ -727,6 +762,11 @@ static int omap_mbox_probe(struct platform_device *pdev)
727 if (!list) 762 if (!list)
728 return -ENOMEM; 763 return -ENOMEM;
729 764
765 chnls = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*chnls),
766 GFP_KERNEL);
767 if (!chnls)
768 return -ENOMEM;
769
730 mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox), 770 mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox),
731 GFP_KERNEL); 771 GFP_KERNEL);
732 if (!mboxblk) 772 if (!mboxblk)
@@ -758,6 +798,8 @@ static int omap_mbox_probe(struct platform_device *pdev)
758 mbox->irq = platform_get_irq(pdev, finfo->tx_irq); 798 mbox->irq = platform_get_irq(pdev, finfo->tx_irq);
759 if (mbox->irq < 0) 799 if (mbox->irq < 0)
760 return mbox->irq; 800 return mbox->irq;
801 mbox->chan = &chnls[i];
802 chnls[i].con_priv = mbox;
761 list[i] = mbox++; 803 list[i] = mbox++;
762 } 804 }
763 805
@@ -766,6 +808,14 @@ static int omap_mbox_probe(struct platform_device *pdev)
766 mdev->num_users = num_users; 808 mdev->num_users = num_users;
767 mdev->num_fifos = num_fifos; 809 mdev->num_fifos = num_fifos;
768 mdev->mboxes = list; 810 mdev->mboxes = list;
811
812 /* OMAP does not have a Tx-Done IRQ, but rather a Tx-Ready IRQ */
813 mdev->controller.txdone_irq = true;
814 mdev->controller.dev = mdev->dev;
815 mdev->controller.ops = &omap_mbox_chan_ops;
816 mdev->controller.chans = chnls;
817 mdev->controller.num_chans = info_count;
818 mdev->controller.of_xlate = omap_mbox_of_xlate;
769 ret = omap_mbox_register(mdev); 819 ret = omap_mbox_register(mdev);
770 if (ret) 820 if (ret)
771 return ret; 821 return ret;
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index 51689721ea7a..cf92f6e7c5dc 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -27,6 +27,7 @@
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/dma-mapping.h> 28#include <linux/dma-mapping.h>
29#include <linux/remoteproc.h> 29#include <linux/remoteproc.h>
30#include <linux/mailbox_client.h>
30#include <linux/omap-mailbox.h> 31#include <linux/omap-mailbox.h>
31 32
32#include <linux/platform_data/remoteproc-omap.h> 33#include <linux/platform_data/remoteproc-omap.h>
@@ -36,20 +37,19 @@
36 37
37/** 38/**
38 * struct omap_rproc - omap remote processor state 39 * struct omap_rproc - omap remote processor state
39 * @mbox: omap mailbox handle 40 * @mbox: mailbox channel handle
40 * @nb: notifier block that will be invoked on inbound mailbox messages 41 * @client: mailbox client to request the mailbox channel
41 * @rproc: rproc handle 42 * @rproc: rproc handle
42 */ 43 */
43struct omap_rproc { 44struct omap_rproc {
44 struct omap_mbox *mbox; 45 struct mbox_chan *mbox;
45 struct notifier_block nb; 46 struct mbox_client client;
46 struct rproc *rproc; 47 struct rproc *rproc;
47}; 48};
48 49
49/** 50/**
50 * omap_rproc_mbox_callback() - inbound mailbox message handler 51 * omap_rproc_mbox_callback() - inbound mailbox message handler
51 * @this: notifier block 52 * @client: mailbox client pointer used for requesting the mailbox channel
52 * @index: unused
53 * @data: mailbox payload 53 * @data: mailbox payload
54 * 54 *
55 * This handler is invoked by omap's mailbox driver whenever a mailbox 55 * This handler is invoked by omap's mailbox driver whenever a mailbox
@@ -61,13 +61,13 @@ struct omap_rproc {
61 * that indicates different events. Those values are deliberately very 61 * that indicates different events. Those values are deliberately very
62 * big so they don't coincide with virtqueue indices. 62 * big so they don't coincide with virtqueue indices.
63 */ 63 */
64static int omap_rproc_mbox_callback(struct notifier_block *this, 64static void omap_rproc_mbox_callback(struct mbox_client *client, void *data)
65 unsigned long index, void *data)
66{ 65{
67 mbox_msg_t msg = (mbox_msg_t) data; 66 struct omap_rproc *oproc = container_of(client, struct omap_rproc,
68 struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb); 67 client);
69 struct device *dev = oproc->rproc->dev.parent; 68 struct device *dev = oproc->rproc->dev.parent;
70 const char *name = oproc->rproc->name; 69 const char *name = oproc->rproc->name;
70 u32 msg = (u32)data;
71 71
72 dev_dbg(dev, "mbox msg: 0x%x\n", msg); 72 dev_dbg(dev, "mbox msg: 0x%x\n", msg);
73 73
@@ -84,8 +84,6 @@ static int omap_rproc_mbox_callback(struct notifier_block *this,
84 if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE) 84 if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE)
85 dev_dbg(dev, "no message was found in vqid %d\n", msg); 85 dev_dbg(dev, "no message was found in vqid %d\n", msg);
86 } 86 }
87
88 return NOTIFY_DONE;
89} 87}
90 88
91/* kick a virtqueue */ 89/* kick a virtqueue */
@@ -96,8 +94,8 @@ static void omap_rproc_kick(struct rproc *rproc, int vqid)
96 int ret; 94 int ret;
97 95
98 /* send the index of the triggered virtqueue in the mailbox payload */ 96 /* send the index of the triggered virtqueue in the mailbox payload */
99 ret = omap_mbox_msg_send(oproc->mbox, vqid); 97 ret = mbox_send_message(oproc->mbox, (void *)vqid);
100 if (ret) 98 if (ret < 0)
101 dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret); 99 dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret);
102} 100}
103 101
@@ -115,17 +113,22 @@ static int omap_rproc_start(struct rproc *rproc)
115 struct platform_device *pdev = to_platform_device(dev); 113 struct platform_device *pdev = to_platform_device(dev);
116 struct omap_rproc_pdata *pdata = pdev->dev.platform_data; 114 struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
117 int ret; 115 int ret;
116 struct mbox_client *client = &oproc->client;
118 117
119 if (pdata->set_bootaddr) 118 if (pdata->set_bootaddr)
120 pdata->set_bootaddr(rproc->bootaddr); 119 pdata->set_bootaddr(rproc->bootaddr);
121 120
122 oproc->nb.notifier_call = omap_rproc_mbox_callback; 121 client->dev = dev;
122 client->tx_done = NULL;
123 client->rx_callback = omap_rproc_mbox_callback;
124 client->tx_block = false;
125 client->knows_txdone = false;
123 126
124 /* every omap rproc is assigned a mailbox instance for messaging */ 127 oproc->mbox = omap_mbox_request_channel(client, pdata->mbox_name);
125 oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb);
126 if (IS_ERR(oproc->mbox)) { 128 if (IS_ERR(oproc->mbox)) {
127 ret = PTR_ERR(oproc->mbox); 129 ret = -EBUSY;
128 dev_err(dev, "omap_mbox_get failed: %d\n", ret); 130 dev_err(dev, "mbox_request_channel failed: %ld\n",
131 PTR_ERR(oproc->mbox));
129 return ret; 132 return ret;
130 } 133 }
131 134
@@ -136,9 +139,9 @@ static int omap_rproc_start(struct rproc *rproc)
136 * Note that the reply will _not_ arrive immediately: this message 139 * Note that the reply will _not_ arrive immediately: this message
137 * will wait in the mailbox fifo until the remote processor is booted. 140 * will wait in the mailbox fifo until the remote processor is booted.
138 */ 141 */
139 ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST); 142 ret = mbox_send_message(oproc->mbox, (void *)RP_MBOX_ECHO_REQUEST);
140 if (ret) { 143 if (ret < 0) {
141 dev_err(dev, "omap_mbox_get failed: %d\n", ret); 144 dev_err(dev, "mbox_send_message failed: %d\n", ret);
142 goto put_mbox; 145 goto put_mbox;
143 } 146 }
144 147
@@ -151,7 +154,7 @@ static int omap_rproc_start(struct rproc *rproc)
151 return 0; 154 return 0;
152 155
153put_mbox: 156put_mbox:
154 omap_mbox_put(oproc->mbox, &oproc->nb); 157 mbox_free_channel(oproc->mbox);
155 return ret; 158 return ret;
156} 159}
157 160
@@ -168,7 +171,7 @@ static int omap_rproc_stop(struct rproc *rproc)
168 if (ret) 171 if (ret)
169 return ret; 172 return ret;
170 173
171 omap_mbox_put(oproc->mbox, &oproc->nb); 174 mbox_free_channel(oproc->mbox);
172 175
173 return 0; 176 return 0;
174} 177}
diff --git a/include/linux/omap-mailbox.h b/include/linux/omap-mailbox.h
index f8322d9cd235..587bbdd31f5a 100644
--- a/include/linux/omap-mailbox.h
+++ b/include/linux/omap-mailbox.h
@@ -10,20 +10,20 @@
10#define OMAP_MAILBOX_H 10#define OMAP_MAILBOX_H
11 11
12typedef u32 mbox_msg_t; 12typedef u32 mbox_msg_t;
13struct omap_mbox;
14 13
15typedef int __bitwise omap_mbox_irq_t; 14typedef int __bitwise omap_mbox_irq_t;
16#define IRQ_TX ((__force omap_mbox_irq_t) 1) 15#define IRQ_TX ((__force omap_mbox_irq_t) 1)
17#define IRQ_RX ((__force omap_mbox_irq_t) 2) 16#define IRQ_RX ((__force omap_mbox_irq_t) 2)
18 17
19int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); 18struct mbox_chan;
19struct mbox_client;
20 20
21struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); 21struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl,
22void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); 22 const char *chan_name);
23 23
24void omap_mbox_save_ctx(struct omap_mbox *mbox); 24void omap_mbox_save_ctx(struct mbox_chan *chan);
25void omap_mbox_restore_ctx(struct omap_mbox *mbox); 25void omap_mbox_restore_ctx(struct mbox_chan *chan);
26void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); 26void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq);
27void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); 27void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq);
28 28
29#endif /* OMAP_MAILBOX_H */ 29#endif /* OMAP_MAILBOX_H */