diff options
author | Suman Anna <s-anna@ti.com> | 2014-06-25 04:43:43 +0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2014-07-29 12:57:25 +0400 |
commit | 72c1c8179cdc5ba7208d375bd3f104659fc50ad0 (patch) | |
tree | 6be3154385d5a638ad214313d1a7d6f4a656ad55 /drivers/mailbox | |
parent | be3322eb7038926ecd5fbd37b3aaa4aee76b78e0 (diff) | |
download | linux-72c1c8179cdc5ba7208d375bd3f104659fc50ad0.tar.xz |
mailbox/omap: add a parent structure for every IP instance
A new structure, omap_mbox_device, is added to contain
the global variables pertinent to a mailbox h/w IP block.
This enables the support for having multiple instances of
the same h/w IP block in the SoC. This is in preparation
to support the DRA7 SoC, which is the first SoC in the OMAP
family to have multiple mailbox IP instances.
The changes include enhancements to the sub-mailbox registration
logic and mbox startup sequencing, removing the usage of single
global configuration variables for all h/w instances, and storing
the registered sub-mailboxes with the parent mailbox device
structure.
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/omap-mailbox.c | 173 |
1 files changed, 115 insertions, 58 deletions
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index d9a503974d52..a27e00e63a8a 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -84,11 +84,22 @@ struct omap_mbox_queue { bool full; }; +struct omap_mbox_device { + struct device *dev; + struct mutex cfg_lock; + void __iomem *mbox_base; + u32 num_users; + u32 num_fifos; + struct omap_mbox **mboxes; + struct list_head elem; +}; + struct omap_mbox { const char *name; int irq; struct omap_mbox_queue *txq, *rxq; struct device *dev; + struct omap_mbox_device *parent; struct omap_mbox_fifo tx_fifo; struct omap_mbox_fifo rx_fifo; u32 ctx[OMAP4_MBOX_NR_REGS]; @@ -97,48 +108,49 @@ struct omap_mbox { struct blocking_notifier_head notifier; }; -static void __iomem *mbox_base; -static struct omap_mbox **mboxes; - -static DEFINE_MUTEX(mbox_configured_lock); +/* global variables for the mailbox devices */ +static DEFINE_MUTEX(omap_mbox_devices_lock); +static LIST_HEAD(omap_mbox_devices); static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; module_param(mbox_kfifo_size, uint, S_IRUGO); MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); -static inline unsigned int mbox_read_reg(size_t ofs) +static inline +unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs) { - return __raw_readl(mbox_base + ofs); + return __raw_readl(mdev->mbox_base + ofs); } -static inline void mbox_write_reg(u32 val, size_t ofs) +static inline +void mbox_write_reg(struct omap_mbox_device *mdev, u32 val, size_t ofs) { - __raw_writel(val, mbox_base + ofs); + __raw_writel(val, mdev->mbox_base + ofs); } /* Mailbox FIFO handle functions */ static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) { struct omap_mbox_fifo *fifo = &mbox->rx_fifo; - return (mbox_msg_t) mbox_read_reg(fifo->msg); + return (mbox_msg_t) mbox_read_reg(mbox->parent, fifo->msg); } static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) { struct omap_mbox_fifo *fifo = &mbox->tx_fifo; - mbox_write_reg(msg, fifo->msg); + mbox_write_reg(mbox->parent, msg, fifo->msg); } static int mbox_fifo_empty(struct omap_mbox *mbox) { struct omap_mbox_fifo *fifo = &mbox->rx_fifo; - return (mbox_read_reg(fifo->msg_stat) == 0); + return (mbox_read_reg(mbox->parent, fifo->msg_stat) == 0); } static int mbox_fifo_full(struct omap_mbox *mbox) { struct omap_mbox_fifo *fifo = &mbox->tx_fifo; - return mbox_read_reg(fifo->fifo_stat); + return mbox_read_reg(mbox->parent, fifo->fifo_stat); } /* Mailbox IRQ handle functions */ @@ -149,10 +161,10 @@ static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) u32 bit = fifo->intr_bit; u32 irqstatus = fifo->irqstatus; - mbox_write_reg(bit, irqstatus); + mbox_write_reg(mbox->parent, bit, irqstatus); /* Flush posted write for irq status to avoid spurious interrupts */ - mbox_read_reg(irqstatus); + mbox_read_reg(mbox->parent, irqstatus); } static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) @@ -163,8 +175,8 @@ static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) u32 irqenable = fifo->irqenable; u32 irqstatus = fifo->irqstatus; - u32 enable = mbox_read_reg(irqenable); - u32 status = mbox_read_reg(irqstatus); + u32 enable = mbox_read_reg(mbox->parent, irqenable); + u32 status = mbox_read_reg(mbox->parent, irqstatus); return (int)(enable & status & bit); } @@ -210,7 +222,7 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox) else nr_regs = MBOX_NR_REGS; for (i = 0; i < nr_regs; i++) { - mbox->ctx[i] = mbox_read_reg(i * sizeof(u32)); + mbox->ctx[i] = mbox_read_reg(mbox->parent, i * sizeof(u32)); dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, i, mbox->ctx[i]); @@ -228,7 +240,7 @@ void omap_mbox_restore_ctx(struct omap_mbox *mbox) else nr_regs = MBOX_NR_REGS; for (i = 0; i < nr_regs; i++) { - mbox_write_reg(mbox->ctx[i], i * sizeof(u32)); + mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32)); dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, i, mbox->ctx[i]); @@ -244,9 +256,9 @@ void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) u32 bit = fifo->intr_bit; u32 irqenable = fifo->irqenable; - l = mbox_read_reg(irqenable); + l = mbox_read_reg(mbox->parent, irqenable); l |= bit; - mbox_write_reg(l, irqenable); + mbox_write_reg(mbox->parent, l, irqenable); } EXPORT_SYMBOL(omap_mbox_enable_irq); @@ -262,9 +274,9 @@ void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) * OMAP4 and later SoCs have a dedicated interrupt disabling register. */ if (!mbox->intr_type) - bit = mbox_read_reg(irqdisable) & ~bit; + bit = mbox_read_reg(mbox->parent, irqdisable) & ~bit; - mbox_write_reg(bit, irqdisable); + mbox_write_reg(mbox->parent, bit, irqdisable); } EXPORT_SYMBOL(omap_mbox_disable_irq); @@ -398,9 +410,10 @@ static int omap_mbox_startup(struct omap_mbox *mbox) { int ret = 0; struct omap_mbox_queue *mq; + struct omap_mbox_device *mdev = mbox->parent; - mutex_lock(&mbox_configured_lock); - ret = pm_runtime_get_sync(mbox->dev->parent); + mutex_lock(&mdev->cfg_lock); + ret = pm_runtime_get_sync(mdev->dev); if (unlikely(ret < 0)) goto fail_startup; @@ -429,7 +442,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox) omap_mbox_enable_irq(mbox, IRQ_RX); } - mutex_unlock(&mbox_configured_lock); + mutex_unlock(&mdev->cfg_lock); return 0; fail_request_irq: @@ -437,16 +450,18 @@ fail_request_irq: fail_alloc_rxq: mbox_queue_free(mbox->txq); fail_alloc_txq: - pm_runtime_put_sync(mbox->dev->parent); + pm_runtime_put_sync(mdev->dev); mbox->use_count--; fail_startup: - mutex_unlock(&mbox_configured_lock); + mutex_unlock(&mdev->cfg_lock); return ret; } static void omap_mbox_fini(struct omap_mbox *mbox) { - mutex_lock(&mbox_configured_lock); + struct omap_mbox_device *mdev = mbox->parent; + + mutex_lock(&mdev->cfg_lock); if (!--mbox->use_count) { omap_mbox_disable_irq(mbox, IRQ_RX); @@ -457,25 +472,43 @@ static void omap_mbox_fini(struct omap_mbox *mbox) mbox_queue_free(mbox->rxq); } - pm_runtime_put_sync(mbox->dev->parent); + pm_runtime_put_sync(mdev->dev); - mutex_unlock(&mbox_configured_lock); + mutex_unlock(&mdev->cfg_lock); } -struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) +static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev, + const char *mbox_name) { struct omap_mbox *_mbox, *mbox = NULL; - int i, ret; + struct omap_mbox **mboxes = mdev->mboxes; + int i; if (!mboxes) - return ERR_PTR(-EINVAL); + return NULL; for (i = 0; (_mbox = mboxes[i]); i++) { - if (!strcmp(_mbox->name, name)) { + if (!strcmp(_mbox->name, mbox_name)) { mbox = _mbox; break; } } + return mbox; +} + +struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) +{ + struct omap_mbox *mbox = NULL; + struct omap_mbox_device *mdev; + int ret; + + mutex_lock(&omap_mbox_devices_lock); + list_for_each_entry(mdev, &omap_mbox_devices, elem) { + mbox = omap_mbox_device_find(mdev, name); + if (mbox) + break; + } + mutex_unlock(&omap_mbox_devices_lock); if (!mbox) return ERR_PTR(-ENOENT); @@ -502,19 +535,20 @@ EXPORT_SYMBOL(omap_mbox_put); static struct class omap_mbox_class = { .name = "mbox", }; -static int omap_mbox_register(struct device *parent, struct omap_mbox **list) +static int omap_mbox_register(struct omap_mbox_device *mdev) { int ret; int i; + struct omap_mbox **mboxes; - mboxes = list; - if (!mboxes) + if (!mdev || !mdev->mboxes) return -EINVAL; + mboxes = mdev->mboxes; for (i = 0; mboxes[i]; i++) { struct omap_mbox *mbox = mboxes[i]; mbox->dev = device_create(&omap_mbox_class, - parent, 0, mbox, "%s", mbox->name); + mdev->dev, 0, mbox, "%s", mbox->name); if (IS_ERR(mbox->dev)) { ret = PTR_ERR(mbox->dev); goto err_out; @@ -522,6 +556,11 @@ static int omap_mbox_register(struct device *parent, struct omap_mbox **list) BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); } + + mutex_lock(&omap_mbox_devices_lock); + list_add(&mdev->elem, &omap_mbox_devices); + mutex_unlock(&omap_mbox_devices_lock); + return 0; err_out: @@ -530,16 +569,21 @@ err_out: return ret; } -static int omap_mbox_unregister(void) +static int omap_mbox_unregister(struct omap_mbox_device *mdev) { int i; + struct omap_mbox **mboxes; - if (!mboxes) + if (!mdev || !mdev->mboxes) return -EINVAL; + mutex_lock(&omap_mbox_devices_lock); + list_del(&mdev->elem); + mutex_unlock(&omap_mbox_devices_lock); + + mboxes = mdev->mboxes; for (i = 0; mboxes[i]; i++) device_unregister(mboxes[i]->dev); - mboxes = NULL; return 0; } @@ -550,6 +594,7 @@ static int omap_mbox_probe(struct platform_device *pdev) struct omap_mbox **list, *mbox, *mboxblk; struct omap_mbox_pdata *pdata = pdev->dev.platform_data; struct omap_mbox_dev_info *info; + struct omap_mbox_device *mdev; struct omap_mbox_fifo *fifo; u32 intr_type; u32 l; @@ -560,6 +605,15 @@ static int omap_mbox_probe(struct platform_device *pdev) return -ENODEV; } + mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mdev->mbox_base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(mdev->mbox_base)) + return PTR_ERR(mdev->mbox_base); + /* allocate one extra for marking end of list */ list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); @@ -593,6 +647,7 @@ static int omap_mbox_probe(struct platform_device *pdev) mbox->intr_type = intr_type; + mbox->parent = mdev; mbox->name = info->name; mbox->irq = platform_get_irq(pdev, info->irq_id); if (mbox->irq < 0) @@ -600,21 +655,21 @@ static int omap_mbox_probe(struct platform_device *pdev) list[i] = mbox++; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mbox_base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(mbox_base)) - return PTR_ERR(mbox_base); - - ret = omap_mbox_register(&pdev->dev, list); + mutex_init(&mdev->cfg_lock); + mdev->dev = &pdev->dev; + mdev->num_users = pdata->num_users; + mdev->num_fifos = pdata->num_fifos; + mdev->mboxes = list; + ret = omap_mbox_register(mdev); if (ret) return ret; - platform_set_drvdata(pdev, list); - pm_runtime_enable(&pdev->dev); + platform_set_drvdata(pdev, mdev); + pm_runtime_enable(mdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_get_sync(mdev->dev); if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_put_noidle(mdev->dev); goto unregister; } @@ -622,25 +677,27 @@ static int omap_mbox_probe(struct platform_device *pdev) * just print the raw revision register, the format is not * uniform across all SoCs */ - l = mbox_read_reg(MAILBOX_REVISION); - dev_info(&pdev->dev, "omap mailbox rev 0x%x\n", l); + l = mbox_read_reg(mdev, MAILBOX_REVISION); + dev_info(mdev->dev, "omap mailbox rev 0x%x\n", l); - ret = pm_runtime_put_sync(&pdev->dev); + ret = pm_runtime_put_sync(mdev->dev); if (ret < 0) goto unregister; return 0; unregister: - pm_runtime_disable(&pdev->dev); - omap_mbox_unregister(); + pm_runtime_disable(mdev->dev); + omap_mbox_unregister(mdev); return ret; } static int omap_mbox_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); - omap_mbox_unregister(); + struct omap_mbox_device *mdev = platform_get_drvdata(pdev); + + pm_runtime_disable(mdev->dev); + omap_mbox_unregister(mdev); return 0; } |