Lines Matching +full:bcm74110 +full:- +full:mbox
1 // SPDX-License-Identifier: GPL-2.0
3 * Broadcom BCM74110 Mailbox Driver
10 #include <linux/io-64-nonatomic-hi-lo.h>
94 struct bcm74110_mbox *mbox; member
115 static void bcm74110_##name##_writel(struct bcm74110_mbox *mbox,\
118 writel_relaxed(val, mbox->base + offset_base + off); \
120 BCM74110_OFFSET_IO_WRITEL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan));
121 BCM74110_OFFSET_IO_WRITEL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan));
124 static u32 bcm74110_##name##_readl(struct bcm74110_mbox *mbox, \
127 return readl_relaxed(mbox->base + offset_base + off); \
129 BCM74110_OFFSET_IO_READL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan));
130 BCM74110_OFFSET_IO_READL_MACRO(rx, BCM_MBOX_BASE(mbox->rx_chan));
131 BCM74110_OFFSET_IO_READL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan));
139 static void bcm74110_rx_push_init_msg(struct bcm74110_mbox *mbox, u32 val) in bcm74110_rx_push_init_msg() argument
147 INIT_LIST_HEAD(&msg->list_entry); in bcm74110_rx_push_init_msg()
148 msg->msg = val; in bcm74110_rx_push_init_msg()
150 spin_lock(&mbox->rx_svc_list_lock); in bcm74110_rx_push_init_msg()
151 list_add_tail(&msg->list_entry, &mbox->rx_svc_init_list); in bcm74110_rx_push_init_msg()
152 spin_unlock(&mbox->rx_svc_list_lock); in bcm74110_rx_push_init_msg()
155 static void bcm74110_rx_process_msg(struct bcm74110_mbox *mbox) in bcm74110_rx_process_msg() argument
157 struct device *dev = &mbox->pdev->dev; in bcm74110_rx_process_msg()
164 msg = bcm74110_rx_readl(mbox, BCM_MBOX_RDATA); in bcm74110_rx_process_msg()
165 status = bcm74110_rx_readl(mbox, BCM_MBOX_STATUS0); in bcm74110_rx_process_msg()
175 bcm74110_rx_push_init_msg(mbox, msg); in bcm74110_rx_process_msg()
180 chan = &mbox->controller.chans[type]; in bcm74110_rx_process_msg()
181 chan_priv = chan->con_priv; in bcm74110_rx_process_msg()
182 if (chan_priv->en) in bcm74110_rx_process_msg()
195 struct bcm74110_mbox *mbox = data; in bcm74110_mbox_isr() local
198 status = bcm74110_irq_readl(mbox, BCM_MBOX_IRQ_STATUS); in bcm74110_mbox_isr()
200 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR); in bcm74110_mbox_isr()
203 bcm74110_rx_process_msg(mbox); in bcm74110_mbox_isr()
205 dev_warn(&mbox->pdev->dev, "Spurious interrupt\n"); in bcm74110_mbox_isr()
210 static void bcm74110_mbox_mask_and_clear(struct bcm74110_mbox *mbox) in bcm74110_mbox_mask_and_clear() argument
212 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_MASK_SET); in bcm74110_mbox_mask_and_clear()
213 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR); in bcm74110_mbox_mask_and_clear()
216 static int bcm74110_rx_pop_init_msg(struct bcm74110_mbox *mbox, u32 func_type, in bcm74110_rx_pop_init_msg() argument
223 spin_lock_irqsave(&mbox->rx_svc_list_lock, flags); in bcm74110_rx_pop_init_msg()
224 list_for_each_entry_safe(msg, msg_tmp, &mbox->rx_svc_init_list, in bcm74110_rx_pop_init_msg()
226 if (BCM_MSG_GET_FIELD(msg->msg, FUNC) == func_type) { in bcm74110_rx_pop_init_msg()
227 list_del(&msg->list_entry); in bcm74110_rx_pop_init_msg()
232 spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags); in bcm74110_rx_pop_init_msg()
235 return -EINVAL; in bcm74110_rx_pop_init_msg()
237 *val = msg->msg; in bcm74110_rx_pop_init_msg()
243 static void bcm74110_rx_flush_msg(struct bcm74110_mbox *mbox) in bcm74110_rx_flush_msg() argument
249 spin_lock_irqsave(&mbox->rx_svc_list_lock, flags); in bcm74110_rx_flush_msg()
250 list_splice_init(&mbox->rx_svc_init_list, &list_temp); in bcm74110_rx_flush_msg()
251 spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags); in bcm74110_rx_flush_msg()
254 list_del(&msg->list_entry); in bcm74110_rx_flush_msg()
260 static int bcm74110_rx_pop_init_msg_block(struct bcm74110_mbox *mbox, u32 func_type, in bcm74110_rx_pop_init_msg_block() argument
266 ret = bcm74110_rx_pop_init_msg(mbox, func_type, val); in bcm74110_rx_pop_init_msg_block()
276 dev_warn(&mbox->pdev->dev, "Timeout waiting for service init response\n"); in bcm74110_rx_pop_init_msg_block()
277 return -ETIMEDOUT; in bcm74110_rx_pop_init_msg_block()
295 static int bcm74110_mbox_tx_msg(struct bcm74110_mbox *mbox, u32 msg) in bcm74110_mbox_tx_msg() argument
300 val = bcm74110_tx_readl(mbox, BCM_MBOX_STATUS0); in bcm74110_mbox_tx_msg()
302 dev_err(&mbox->pdev->dev, "Mailbox full\n"); in bcm74110_mbox_tx_msg()
303 return -EINVAL; in bcm74110_mbox_tx_msg()
306 dev_dbg(&mbox->pdev->dev, "tx: [{req=%lu|rply=%lu|srv=%lu|fn=%lu|length=%lu|slot=%lu]\n", in bcm74110_mbox_tx_msg()
311 bcm74110_tx_writel(mbox, msg, BCM_MBOX_WDATA); in bcm74110_mbox_tx_msg()
317 static int bcm74110_mbox_link_training(struct bcm74110_mbox *mbox) in bcm74110_mbox_link_training() argument
326 dev_warn(&mbox->pdev->dev, in bcm74110_mbox_link_training()
330 return -EINVAL; in bcm74110_mbox_link_training()
344 bcm74110_mbox_tx_msg(mbox, msg); in bcm74110_mbox_link_training()
352 ret = bcm74110_rx_pop_init_msg_block(mbox, in bcm74110_mbox_link_training()
378 return -EINVAL; in bcm74110_mbox_link_training()
381 static int bcm74110_mbox_tx_msg_and_wait_ack(struct bcm74110_mbox *mbox, u32 msg) in bcm74110_mbox_tx_msg_and_wait_ack() argument
386 ret = bcm74110_mbox_tx_msg(mbox, msg); in bcm74110_mbox_tx_msg_and_wait_ack()
390 ret = bcm74110_rx_pop_init_msg_block(mbox, BCM_MSG_GET_FIELD(msg, FUNC), in bcm74110_mbox_tx_msg_and_wait_ack()
405 dev_err(&mbox->pdev->dev, "Found ack, but ack is invalid\n"); in bcm74110_mbox_tx_msg_and_wait_ack()
406 return -EINVAL; in bcm74110_mbox_tx_msg_and_wait_ack()
415 static int bcm74110_mbox_shmem_init(struct bcm74110_mbox *mbox) in bcm74110_mbox_shmem_init() argument
423 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); in bcm74110_mbox_shmem_init()
425 return -EINVAL; in bcm74110_mbox_shmem_init()
431 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); in bcm74110_mbox_shmem_init()
433 return -EINVAL; in bcm74110_mbox_shmem_init()
439 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); in bcm74110_mbox_shmem_init()
441 return -EINVAL; in bcm74110_mbox_shmem_init()
446 static int bcm74110_mbox_init(struct bcm74110_mbox *mbox) in bcm74110_mbox_init() argument
451 bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL); in bcm74110_mbox_init()
454 bcm74110_tx_writel(mbox, BCM_MBOX_CTRL_EN | BCM_MBOX_CTRL_CLR, in bcm74110_mbox_init()
458 bcm74110_irq_writel(mbox, BCM_MBOX_IRQ_NOT_EMPTY, BCM_MBOX_IRQ_MASK_CLEAR); in bcm74110_mbox_init()
460 ret = bcm74110_mbox_link_training(mbox); in bcm74110_mbox_init()
462 dev_err(&mbox->pdev->dev, "Training failed\n"); in bcm74110_mbox_init()
466 return bcm74110_mbox_shmem_init(mbox); in bcm74110_mbox_init()
471 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; in bcm74110_mbox_send_data()
474 switch (chan_priv->type) { in bcm74110_mbox_send_data()
478 msg = bcm74110_mbox_create_msg(1, 0, chan_priv->type, 0, in bcm74110_mbox_send_data()
479 128 + 28, chan_priv->slot); in bcm74110_mbox_send_data()
482 return -EINVAL; in bcm74110_mbox_send_data()
485 return bcm74110_mbox_tx_msg(chan_priv->mbox, msg); in bcm74110_mbox_send_data()
490 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; in bcm74110_mbox_chan_startup()
492 chan_priv->en = true; in bcm74110_mbox_chan_startup()
499 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; in bcm74110_mbox_chan_shutdown()
501 chan_priv->en = false; in bcm74110_mbox_chan_shutdown()
512 struct bcm74110_mbox *mbox = dev_get_drvdata(&pdev->dev); in bcm74110_mbox_shutdown() local
519 bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); in bcm74110_mbox_shutdown()
523 bcm74110_mbox_mask_and_clear(mbox); in bcm74110_mbox_shutdown()
526 bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL); in bcm74110_mbox_shutdown()
529 bcm74110_rx_flush_msg(mbox); in bcm74110_mbox_shutdown()
535 struct bcm74110_mbox *mbox = bcm74110_mbox_from_cntrl(cntrl); in bcm74110_mbox_of_xlate() local
536 struct device *dev = &mbox->pdev->dev; in bcm74110_mbox_of_xlate()
540 if (p->args_count != 2) { in bcm74110_mbox_of_xlate()
542 return ERR_PTR(-EINVAL); in bcm74110_mbox_of_xlate()
545 type = p->args[0]; in bcm74110_mbox_of_xlate()
546 slot = p->args[1]; in bcm74110_mbox_of_xlate()
554 return ERR_PTR(-EINVAL); in bcm74110_mbox_of_xlate()
556 chan_priv = cntrl->chans[type].con_priv; in bcm74110_mbox_of_xlate()
557 chan_priv->slot = slot; in bcm74110_mbox_of_xlate()
558 chan_priv->type = type; in bcm74110_mbox_of_xlate()
562 return ERR_PTR(-EINVAL); in bcm74110_mbox_of_xlate()
565 return &cntrl->chans[type]; in bcm74110_mbox_of_xlate()
570 struct device *dev = &pdev->dev; in bcm74110_mbox_probe()
571 struct bcm74110_mbox *mbox; in bcm74110_mbox_probe() local
574 mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); in bcm74110_mbox_probe()
575 if (!mbox) in bcm74110_mbox_probe()
576 return -ENOMEM; in bcm74110_mbox_probe()
578 mbox->pdev = pdev; in bcm74110_mbox_probe()
579 platform_set_drvdata(pdev, mbox); in bcm74110_mbox_probe()
581 mbox->base = devm_platform_ioremap_resource(pdev, 0); in bcm74110_mbox_probe()
582 if (IS_ERR(mbox->base)) in bcm74110_mbox_probe()
583 return dev_err_probe(dev, PTR_ERR(mbox->base), "Failed to iomap\n"); in bcm74110_mbox_probe()
585 ret = of_property_read_u32(dev->of_node, "brcm,tx", &mbox->tx_chan); in bcm74110_mbox_probe()
589 ret = of_property_read_u32(dev->of_node, "brcm,rx", &mbox->rx_chan); in bcm74110_mbox_probe()
593 mbox->rx_irq = platform_get_irq(pdev, 0); in bcm74110_mbox_probe()
594 if (mbox->rx_irq < 0) in bcm74110_mbox_probe()
595 return mbox->rx_irq; in bcm74110_mbox_probe()
597 INIT_LIST_HEAD(&mbox->rx_svc_init_list); in bcm74110_mbox_probe()
598 spin_lock_init(&mbox->rx_svc_list_lock); in bcm74110_mbox_probe()
599 bcm74110_mbox_mask_and_clear(mbox); in bcm74110_mbox_probe()
601 ret = devm_request_irq(dev, mbox->rx_irq, bcm74110_mbox_isr, in bcm74110_mbox_probe()
602 IRQF_NO_SUSPEND, pdev->name, mbox); in bcm74110_mbox_probe()
606 mbox->controller.ops = &bcm74110_mbox_chan_ops; in bcm74110_mbox_probe()
607 mbox->controller.dev = dev; in bcm74110_mbox_probe()
608 mbox->controller.num_chans = BCM_MSG_SVC_MAX; in bcm74110_mbox_probe()
609 mbox->controller.of_xlate = &bcm74110_mbox_of_xlate; in bcm74110_mbox_probe()
610 mbox->controller.chans = devm_kcalloc(dev, BCM_MSG_SVC_MAX, in bcm74110_mbox_probe()
611 sizeof(*mbox->controller.chans), in bcm74110_mbox_probe()
613 if (!mbox->controller.chans) in bcm74110_mbox_probe()
614 return -ENOMEM; in bcm74110_mbox_probe()
616 mbox->mbox_chan = devm_kcalloc(dev, BCM_MSG_SVC_MAX, in bcm74110_mbox_probe()
617 sizeof(*mbox->mbox_chan), in bcm74110_mbox_probe()
619 if (!mbox->mbox_chan) in bcm74110_mbox_probe()
620 return -ENOMEM; in bcm74110_mbox_probe()
623 mbox->mbox_chan[i].mbox = mbox; in bcm74110_mbox_probe()
624 mbox->controller.chans[i].con_priv = &mbox->mbox_chan[i]; in bcm74110_mbox_probe()
627 ret = devm_mbox_controller_register(dev, &mbox->controller); in bcm74110_mbox_probe()
631 ret = bcm74110_mbox_init(mbox); in bcm74110_mbox_probe()
639 { .compatible = "brcm,bcm74110-mbox", },
646 .name = "bcm74110-mbox",
655 MODULE_DESCRIPTION("BCM74110 mailbox driver");