mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
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:
@@ -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:
|
||||
--------
|
||||
|
||||
@@ -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"))
|
||||
|
||||
Reference in New Issue
Block a user