From 8bc01b6dba82e120795504b4b4fde9eb4e79d998 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Tue, 25 Jun 2024 09:59:55 +0800 Subject: [PATCH] mailbox: rockchip: add more txdone methods support Configure "rockchip,txdone-irq" property in DT indicates that the controller can trigger the TX_DONE interrupt. This feature begin support from RV1103B and RK3506 SoCs with Rockchip mailbox v2 IP. If the mailbox client wants to use its own ACK to check TX_DONE, the "rockchip,txdone-ack" property also gets reday for it in this patch. Signed-off-by: Frank Wang Change-Id: Ie62d94c13f6d8081b08e8bf5c45b5f7de5204bbe --- .../bindings/mailbox/rockchip-mailbox.txt | 2 + drivers/mailbox/rockchip-mailbox.c | 106 +++++++++++++----- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt index c6f82d9bfaad..3d0747787577 100644 --- a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt @@ -26,6 +26,8 @@ Optional properties : - rockchip,txpoll-period-ms: TX Done polling interval in milliseconds. - rockchip,enable-cmd-trigger: Enable write cmd register to trigger interrupt. This is only support from rockchip,rk3576-mbox. + - rockchip,txdone-ack: Enable if the mailbox client use ACK to check TX_DONE. + - rockchip,txdone-irq: Enable if the controller can trigger TX_DONE interrupt. Example: -------- diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index 8eca72c781b3..40d142580a68 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -36,8 +36,14 @@ #define MAILBOX_V2_TRIGGER_SHIFT 8 #define MAILBOX_V2_TRIGGER_MASK BIT(8) -#define MAILBOX_V2_INT_MASK BIT(0) -#define MAILBOX_V2_INT_CLR BIT(0) + +#define MAILBOX_V2_INTEN_TX_DONE BIT(0) +#define MAILBOX_V2_INTEN_RX_DONE BIT(1) +#define MAILBOX_V2_INTEN_RX_DONE_SHIFT 1 + +#define MAILBOX_V2_STATUS_TX_DONE BIT(0) +#define MAILBOX_V2_STATUS_RX_DONE BIT(1) +#define MAILBOX_V2_STATUS_MASK GENMASK(1, 0) #define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */ #define BIT_WRITEABLE_SHIFT 16 @@ -171,7 +177,7 @@ static int rockchip_mbox_v2_send_data(struct mbox_chan *chan, void *data) return -EINVAL; status = readl_relaxed(mb->mbox_base + MAILBOX_V2_A2B_STATUS); - if (status & MAILBOX_V2_INT_MASK) { + if (status & MAILBOX_V2_STATUS_TX_DONE) { dev_err(mb->mbox.dev, "The mailbox is busy\n"); return -EBUSY; } @@ -197,10 +203,16 @@ static int rockchip_mbox_v2_startup(struct mbox_chan *chan) mb->trigger_method << MAILBOX_V2_TRIGGER_SHIFT), mb->mbox_base + MAILBOX_V2_A2B_INTEN); - /* Enable the B2A interrupt */ - writel_relaxed((1U << BIT_WRITEABLE_SHIFT | MAILBOX_V2_INT_MASK), + /* Enable the B2A TX_DONE interrupt */ + writel_relaxed((1U << BIT_WRITEABLE_SHIFT | MAILBOX_V2_INTEN_TX_DONE), mb->mbox_base + MAILBOX_V2_B2A_INTEN); + /* Enable the B2A RX_DONE interrupt */ + if (mb->mbox.txdone_irq) + writel_relaxed((1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT) | + MAILBOX_V2_INTEN_RX_DONE), + mb->mbox_base + MAILBOX_V2_B2A_INTEN); + return 0; } @@ -210,15 +222,20 @@ static bool rockchip_mbox_v2_last_tx_done(struct mbox_chan *chan) u32 status; status = readl_relaxed(mb->mbox_base + MAILBOX_V2_A2B_STATUS); - return !(status & MAILBOX_V2_INT_MASK); + return !(status & MAILBOX_V2_STATUS_TX_DONE); } static void rockchip_mbox_v2_shutdown(struct mbox_chan *chan) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); - /* Disable the B2A interrupt */ + /* Disable the B2A TX_DONE interrupt */ writel_relaxed(1U << BIT_WRITEABLE_SHIFT, mb->mbox_base + MAILBOX_V2_B2A_INTEN); + + /* Disable the B2A RX_DONE interrupt */ + if (mb->mbox.txdone_irq) + writel_relaxed(1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT), + mb->mbox_base + MAILBOX_V2_B2A_INTEN); } static irqreturn_t rockchip_mbox_v2_irq(int irq, void *dev_id) @@ -228,20 +245,33 @@ static irqreturn_t rockchip_mbox_v2_irq(int irq, void *dev_id) u32 status; status = readl_relaxed(mb->mbox_base + MAILBOX_V2_B2A_STATUS); - if (!(status & MAILBOX_V2_INT_MASK)) + if (!(status & MAILBOX_V2_STATUS_MASK)) return IRQ_NONE; - /* Get cmd/data from the channel of B2A */ - msg->cmd = readl_relaxed(mb->mbox_base + MAILBOX_V2_B2A_CMD); - msg->data = readl_relaxed(mb->mbox_base + MAILBOX_V2_B2A_DAT); + if (status & MAILBOX_V2_STATUS_TX_DONE) { + /* Get cmd/data from the channel of B2A */ + msg->cmd = readl_relaxed(mb->mbox_base + MAILBOX_V2_B2A_CMD); + msg->data = readl_relaxed(mb->mbox_base + MAILBOX_V2_B2A_DAT); - dev_dbg(mb->mbox.dev, "B2A message, cmd 0x%08x, data 0x%08x\n", msg->cmd, msg->data); + dev_dbg(mb->mbox.dev, "B2A message, cmd 0x%08x, data 0x%08x\n", + msg->cmd, msg->data); - if (mb->mbox.chans[0].cl) - mbox_chan_received_data(&mb->mbox.chans[0], msg); + /* Clear mbox's message B2A TX_DONE interrupt */ + writel_relaxed(MAILBOX_V2_STATUS_TX_DONE, + mb->mbox_base + MAILBOX_V2_B2A_STATUS); - /* Clear mbox's message interrupt */ - writel_relaxed(MAILBOX_V2_INT_CLR, mb->mbox_base + MAILBOX_V2_B2A_STATUS); + if (mb->mbox.chans[0].cl) + mbox_chan_received_data(&mb->mbox.chans[0], msg); + } + + if (status & MAILBOX_V2_STATUS_RX_DONE) { + if (mb->mbox.txdone_irq) + mbox_chan_txdone(&mb->mbox.chans[0], 0); + + /* Clear mbox's B2A RX_DONE interrupt */ + writel_relaxed(MAILBOX_V2_STATUS_RX_DONE, + mb->mbox_base + MAILBOX_V2_B2A_STATUS); + } return IRQ_HANDLED; } @@ -339,22 +369,42 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->mbox.ops = drv_data->ops; spin_lock_init(&mb->cfg_lock); - mb->mbox.txdone_poll = true; - if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { - ret = device_property_read_u32(&pdev->dev, "rockchip,txpoll-period-us", - &txpoll_period); - if (!ret) { - mb->mbox.txpoll_period = txpoll_period; + /* + * rockchip,txdone-ack: the mailbox client uses its own ACK to check + * TX_DONE, and call mbox_client_txdone() API to schedule tx_tick. + * rockchip,txdone-irq: the feature only support from RK3506, the ISR + * function call mbox_chan_txdone() API to schedule tx_tick. + * txdone_poll is default for all the platform, it cooperates with + * "rockchip,txpoll-period-ms" or "rockchip,txpoll-period-us" + * periodically call last_tx_done() to check TX_DONE by the hrtimer + * in mailbox framework. + */ + if (device_property_present(&pdev->dev, "rockchip,txdone-ack")) { + mb->mbox.txdone_irq = false; + mb->mbox.txdone_poll = false; + } else if (device_property_present(&pdev->dev, "rockchip,txdone-irq")) { + mb->mbox.txdone_irq = true; + } else { + mb->mbox.txdone_poll = true; + if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { + ret = device_property_read_u32(&pdev->dev, + "rockchip,txpoll-period-us", + &txpoll_period); + if (!ret) { + mb->mbox.txpoll_period = txpoll_period; + } else { + ret = device_property_read_u32(&pdev->dev, + "rockchip,txpoll-period-ms", + &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + mb->mbox.txpoll_period *= 1000U; /* Convert to us */ + } } else { - ret = device_property_read_u32(&pdev->dev, "rockchip,txpoll-period-ms", + ret = device_property_read_u32(&pdev->dev, + "rockchip,txpoll-period-ms", &txpoll_period); mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; - mb->mbox.txpoll_period *= 1000U; /* Convert to us */ } - } else { - ret = device_property_read_u32(&pdev->dev, "rockchip,txpoll-period-ms", - &txpoll_period); - mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; } if (device_property_present(&pdev->dev, "rockchip,enable-cmd-trigger"))