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 <frank.wang@rock-chips.com>
Change-Id: Ie62d94c13f6d8081b08e8bf5c45b5f7de5204bbe
This commit is contained in:
Frank Wang
2024-06-25 09:59:55 +08:00
committed by Tao Huang
parent c09c257b5d
commit 8bc01b6dba
2 changed files with 80 additions and 28 deletions

View File

@@ -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:
--------

View File

@@ -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"))