| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-09-23 GuEe-GUI first version
- */
- #include <rtthread.h>
- #include <rtdevice.h>
- #define DBG_TAG "mailbox.rockchip"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #define MAILBOX_A2B_INTEN 0x00
- #define MAILBOX_A2B_STATUS 0x04
- #define MAILBOX_A2B_CMD(x) (0x08 + (x) * 8)
- #define MAILBOX_A2B_DAT(x) (0x0c + (x) * 8)
- #define MAILBOX_B2A_INTEN 0x28
- #define MAILBOX_B2A_STATUS 0x2C
- #define MAILBOX_B2A_CMD(x) (0x30 + (x) * 8)
- #define MAILBOX_B2A_DAT(x) (0x34 + (x) * 8)
- #define MAILBOX_V2_A2B_INTEN MAILBOX_A2B_INTEN
- #define MAILBOX_V2_A2B_STATUS MAILBOX_A2B_STATUS
- #define MAILBOX_V2_A2B_CMD 0x08
- #define MAILBOX_V2_A2B_DAT 0x0c
- #define MAILBOX_V2_B2A_INTEN 0x10
- #define MAILBOX_V2_B2A_STATUS 0x14
- #define MAILBOX_V2_B2A_CMD 0x18
- #define MAILBOX_V2_B2A_DAT 0x1c
- #define MAILBOX_V2_TRIGGER_SHIFT 8
- #define MAILBOX_V2_TRIGGER_MASK RT_BIT(8)
- #define MAILBOX_V2_INTEN_TX_DONE RT_BIT(0)
- #define MAILBOX_V2_INTEN_RX_DONE RT_BIT(1)
- #define MAILBOX_V2_INTEN_RX_DONE_SHIFT 1
- #define MAILBOX_V2_STATUS_TX_DONE RT_BIT(0)
- #define MAILBOX_V2_STATUS_RX_DONE RT_BIT(1)
- #define MAILBOX_V2_STATUS_MASK RT_GENMASK(1, 0)
- #define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */
- #define BIT_WRITEABLE_SHIFT 16
- struct rockchip_mbox;
- struct rockchip_mbox_reg
- {
- rt_uint32_t tx_int;
- rt_uint32_t tx_sts;
- rt_uint32_t tx_cmd;
- rt_uint32_t tx_dat;
- rt_uint32_t rx_int;
- rt_uint32_t rx_sts;
- rt_uint32_t rx_cmd;
- rt_uint32_t rx_dat;
- };
- struct rockchip_mbox_msg
- {
- rt_uint32_t cmd;
- rt_uint32_t data;
- };
- struct rockchip_mbox_soc_data
- {
- int num_chans;
- struct rockchip_mbox_reg reg_a2b;
- struct rockchip_mbox_reg reg_b2a;
- const struct rt_mbox_controller_ops *ops;
- void (*isr)(int irqno, void *param);
- void (*thread_isr)(void *param);
- };
- struct rockchip_mbox_chan
- {
- int idx;
- int irq;
- struct rockchip_mbox_msg *msg;
- struct rockchip_mbox *rk_mbox;
- };
- struct rockchip_mbox
- {
- struct rt_mbox_controller parent;
- void *regs;
- struct rt_clk *pclk;
- struct rt_thread *irq_thread;
- const struct rockchip_mbox_reg *reg;
- rt_uint32_t buf_size;
- rt_bool_t txdone_irq;
- rt_bool_t trigger_method;
- struct rockchip_mbox_chan chans[];
- };
- #define raw_to_rockchip_mbox(raw) rt_container_of(raw, struct rockchip_mbox, parent)
- rt_inline rt_uint32_t rockchip_mbox_readl(struct rockchip_mbox *rk_mbox, int offset)
- {
- return HWREG32(rk_mbox->regs + offset);
- }
- rt_inline void rockchip_mbox_writel(struct rockchip_mbox *rk_mbox, int offset,
- rt_uint32_t value)
- {
- HWREG32(rk_mbox->regs + offset) = value;
- }
- static rt_err_t rockchip_mbox_request(struct rt_mbox_chan *chan)
- {
- int idx;
- rt_uint32_t value;
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- idx = chan - rk_mbox->parent.chans;
- /* Enable the corresponding B2A interrupts */
- value = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_INTEN);
- value |= RT_BIT(idx);
- rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, value);
- return RT_EOK;
- }
- static void rockchip_mbox_release(struct rt_mbox_chan *chan)
- {
- int idx;
- rt_uint32_t value;
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- idx = chan - rk_mbox->parent.chans;
- /* Disable the corresponding B2A interrupts */
- value = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_INTEN);
- value &= ~RT_BIT(idx);
- rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, value);
- rk_mbox->chans[idx].msg = RT_NULL;
- }
- static rt_err_t rockchip_mbox_send(struct rt_mbox_chan *chan, const void *data)
- {
- int idx;
- struct rockchip_mbox_msg *msg = (void *)data;
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- idx = chan - rk_mbox->parent.chans;
- if (rockchip_mbox_readl(rk_mbox, MAILBOX_A2B_STATUS) & RT_BIT(idx))
- {
- LOG_E("The mailbox channel(%d) is busy", idx);
- return -RT_EBUSY;
- }
- rk_mbox->chans[idx].msg = msg;
- rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_CMD(idx), msg->cmd);
- rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_DAT(idx), msg->data);
- return RT_EOK;
- }
- static const struct rt_mbox_controller_ops rockchip_mbox_ops =
- {
- .request = rockchip_mbox_request,
- .release = rockchip_mbox_release,
- .send = rockchip_mbox_send,
- };
- static void rockchip_mbox_thread_isr(void *param)
- {
- struct rockchip_mbox_msg *msg;
- struct rockchip_mbox *rk_mbox = param;
- while (RT_TRUE)
- {
- rt_thread_suspend(rk_mbox->irq_thread);
- rt_schedule();
- for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx)
- {
- msg = rk_mbox->chans[idx].msg;
- if (!msg)
- {
- LOG_E("Chan[%d]: B2A message is NULL", idx);
- break;
- }
- rt_mbox_recv(&rk_mbox->parent.chans[idx], msg);
- rk_mbox->chans[idx].msg = RT_NULL;
- }
- }
- }
- static void rockchip_mbox_isr(int irqno, void *param)
- {
- rt_uint32_t status;
- struct rockchip_mbox_msg *msg;
- struct rockchip_mbox *rk_mbox = param;
- status = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_STATUS);
- for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx)
- {
- if ((status & RT_BIT(idx)) && (irqno == rk_mbox->chans[idx].irq))
- {
- msg = rk_mbox->chans[idx].msg;
- msg->cmd = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_CMD(idx));
- msg->data = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_DAT(idx));
- /* Clear mbox interrupt */
- rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_STATUS, RT_BIT(idx));
- rt_thread_resume(rk_mbox->irq_thread);
- break;
- }
- }
- }
- static rt_err_t rockchip_mbox_v2_request(struct rt_mbox_chan *chan)
- {
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- /* Set the TX interrupt trigger method */
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_int,
- (1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_TRIGGER_SHIFT) |
- rk_mbox->trigger_method << MAILBOX_V2_TRIGGER_SHIFT));
- /* Enable the tx_done interrupt */
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
- (1U << BIT_WRITEABLE_SHIFT | MAILBOX_V2_INTEN_TX_DONE));
- /* Enable the rx_done interrupt */
- if (rk_mbox->txdone_irq)
- {
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
- (1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT) |
- MAILBOX_V2_INTEN_RX_DONE));
- }
- return RT_EOK;
- }
- static void rockchip_mbox_v2_release(struct rt_mbox_chan *chan)
- {
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- /* Disable the tx_done interrupt */
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int, 1U << BIT_WRITEABLE_SHIFT);
- /* Disable the rx_done interrupt */
- if (rk_mbox->txdone_irq)
- {
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
- 1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT));
- }
- }
- static rt_err_t rockchip_mbox_v2_send(struct rt_mbox_chan *chan, const void *data)
- {
- struct rockchip_mbox_msg *msg = (void *)data;
- struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
- if (rockchip_mbox_readl(rk_mbox, rk_mbox->reg->tx_sts) & MAILBOX_V2_STATUS_TX_DONE)
- {
- LOG_E("The mailbox channel(%d) is busy", 0);
- return -RT_EBUSY;
- }
- rk_mbox->chans[0].msg = msg;
- if (rk_mbox->trigger_method)
- {
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_cmd, msg->cmd);
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_dat, msg->data);
- }
- else
- {
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_cmd, msg->cmd);
- }
- return RT_EOK;
- }
- static const struct rt_mbox_controller_ops rockchip_mbox_v2_ops =
- {
- .request = rockchip_mbox_v2_request,
- .release = rockchip_mbox_v2_release,
- .send = rockchip_mbox_v2_send,
- };
- static void rockchip_mbox_v2_thread_isr(void *param)
- {
- struct rockchip_mbox_msg *msg;
- struct rockchip_mbox *rk_mbox = param;
- while (RT_TRUE)
- {
- rt_thread_suspend(rk_mbox->irq_thread);
- rt_schedule();
- msg = rk_mbox->chans[0].msg;
- if (!msg)
- {
- LOG_E("Chan[%d]: B2A message is NULL", 0);
- continue;
- }
- rt_mbox_recv(&rk_mbox->parent.chans[0], msg);
- rk_mbox->chans[0].msg = RT_NULL;
- }
- }
- static void rockchip_mbox_v2_isr(int irqno, void *param)
- {
- rt_uint32_t status;
- struct rockchip_mbox_msg *msg;
- struct rockchip_mbox *rk_mbox = param;
- status = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_sts);
- if (!(status & MAILBOX_V2_STATUS_MASK))
- {
- return;
- }
- if (status & MAILBOX_V2_STATUS_TX_DONE)
- {
- msg = rk_mbox->chans[0].msg;
- /* Get cmd/data from the channel */
- msg->cmd = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_cmd);
- msg->data = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_dat);
- /* Clear the tx_done interrupt */
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_sts, MAILBOX_V2_STATUS_TX_DONE);
- rt_thread_resume(rk_mbox->irq_thread);
- }
- if (status & MAILBOX_V2_STATUS_RX_DONE)
- {
- if (rk_mbox->txdone_irq)
- {
- rt_mbox_send_done(&rk_mbox->parent.chans[0], 0);
- }
- /* Clear the rx_done interrupt */
- rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_sts, MAILBOX_V2_STATUS_RX_DONE);
- }
- }
- static void rockchip_mbox_free_resource(struct rockchip_mbox *rk_mbox)
- {
- if (rk_mbox->regs)
- {
- rt_iounmap(rk_mbox->regs);
- }
- if (!rt_is_err_or_null(rk_mbox->pclk))
- {
- rt_clk_disable_unprepare(rk_mbox->pclk);
- rt_clk_put(rk_mbox->pclk);
- }
- if (rk_mbox->irq_thread)
- {
- rt_thread_delete(rk_mbox->irq_thread);
- }
- rt_free(rk_mbox);
- }
- static rt_err_t rockchip_mbox_probe(struct rt_platform_device *pdev)
- {
- rt_err_t err;
- char chan_name[RT_NAME_MAX];
- rt_uint64_t io_addr, io_size;
- struct rockchip_mbox *rk_mbox;
- struct rockchip_mbox_chan *chan;
- struct rt_device *dev = &pdev->parent;
- const struct rockchip_mbox_soc_data *soc_data = pdev->id->data;
- rk_mbox = rt_calloc(1, sizeof(*rk_mbox) +
- soc_data->num_chans * sizeof(struct rockchip_mbox_chan));
- if (!rk_mbox)
- {
- return -RT_ENOMEM;
- }
- if (rt_dm_dev_prop_read_bool(dev, "rockchip,tx-direction-b2a"))
- {
- rk_mbox->reg = &soc_data->reg_b2a;
- }
- else
- {
- rk_mbox->reg = &soc_data->reg_a2b;
- }
- if (rt_dm_dev_prop_read_bool(dev, "rockchip,txdone-ack"))
- {
- rk_mbox->txdone_irq = RT_FALSE;
- }
- else if (rt_dm_dev_prop_read_bool(dev, "rockchip,txdone-irq"))
- {
- rk_mbox->txdone_irq = RT_TRUE;
- }
- rk_mbox->trigger_method = !rt_dm_dev_prop_read_bool(dev, "rockchip,enable-cmd-trigger");
- if ((err = rt_dm_dev_get_address(dev, 0, &io_addr, &io_size)))
- {
- goto _fail;
- }
- rk_mbox->regs = rt_ioremap((void *)io_addr, (size_t)io_size);
- if (!rk_mbox->regs)
- {
- err = -RT_EIO;
- goto _fail;
- }
- rk_mbox->pclk = rt_clk_get_by_name(dev, "pclk_mailbox");
- if (rt_is_err(rk_mbox->pclk))
- {
- err = rt_ptr_err(rk_mbox->pclk);
- goto _fail;
- }
- if ((err = rt_clk_prepare_enable(rk_mbox->pclk)))
- {
- goto _fail;
- }
- rk_mbox->irq_thread = rt_thread_create("rk_mbox", soc_data->thread_isr,
- rk_mbox, DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10);
- if (!rk_mbox->irq_thread)
- {
- LOG_E("Create Mailbox IRQ thread fail");
- goto _fail;
- }
- rt_thread_startup(rk_mbox->irq_thread);
- chan = &rk_mbox->chans[0];
- for (int i = 0; i < soc_data->num_chans; ++i, ++chan)
- {
- int irq = rt_dm_dev_get_irq(dev, i);
- if (irq < 0)
- {
- err = irq;
- goto _fail;
- }
- rt_snprintf(chan_name, sizeof(chan_name), "rk_mbox-%d", i);
- rt_hw_interrupt_install(irq, soc_data->isr, rk_mbox, chan_name);
- rt_hw_interrupt_umask(irq);
- chan->idx = i;
- chan->irq = irq;
- chan->rk_mbox = rk_mbox;
- }
- rk_mbox->buf_size = io_size / (soc_data->num_chans * 2);
- dev->user_data = rk_mbox;
- rk_mbox->parent.dev = dev;
- rk_mbox->parent.num_chans = soc_data->num_chans;
- rk_mbox->parent.ops = soc_data->ops;
- if ((err = rt_mbox_controller_register(&rk_mbox->parent)))
- {
- goto _fail;
- }
- return RT_EOK;
- _fail:
- rockchip_mbox_free_resource(rk_mbox);
- return err;
- }
- static rt_err_t rockchip_mbox_remove(struct rt_platform_device *pdev)
- {
- struct rockchip_mbox_chan *chan;
- struct rockchip_mbox *rk_mbox = pdev->parent.user_data;
- chan = &rk_mbox->chans[0];
- for (int i = 0; i < rk_mbox->parent.num_chans; ++i, ++chan)
- {
- rt_hw_interrupt_mask(chan->irq);
- rt_pic_detach_irq(chan->irq, rk_mbox);
- }
- rt_mbox_controller_unregister(&rk_mbox->parent);
- rockchip_mbox_free_resource(rk_mbox);
- return RT_EOK;
- }
- static const struct rockchip_mbox_soc_data rk3368_data =
- {
- .num_chans = 4,
- .ops = &rockchip_mbox_ops,
- .isr = rockchip_mbox_isr,
- .thread_isr = rockchip_mbox_thread_isr,
- };
- static const struct rockchip_mbox_soc_data rk3576_data =
- {
- .num_chans = 1,
- .reg_a2b =
- {
- MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS,
- MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT,
- MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS,
- MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT
- },
- .reg_b2a =
- {
- MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS,
- MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT,
- MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS,
- MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT
- },
- .ops = &rockchip_mbox_v2_ops,
- .isr = rockchip_mbox_v2_isr,
- .thread_isr = rockchip_mbox_v2_thread_isr,
- };
- static const struct rt_ofw_node_id rockchip_mbox_ofw_ids[] =
- {
- { .compatible = "rockchip,rk3368-mailbox", .data = &rk3368_data },
- { .compatible = "rockchip,rk3576-mailbox", .data = &rk3576_data },
- { /* sentinel */ }
- };
- static struct rt_platform_driver rockchip_mbox_driver =
- {
- .name = "mailbox-rockchip",
- .ids = rockchip_mbox_ofw_ids,
- .probe = rockchip_mbox_probe,
- .remove = rockchip_mbox_remove,
- };
- RT_PLATFORM_DRIVER_EXPORT(rockchip_mbox_driver);
|