/* * If the read pointer is equal with write pointer, which means the fifo * is full or empty.
*/ if (wr_pos == rd_pos) { if (fifo_sts & SPRD_OUTBOX_FIFO_FULL)
fifo_len = priv->outbox_fifo_depth; else
fifo_len = 0;
} elseif (wr_pos > rd_pos) {
fifo_len = wr_pos - rd_pos;
} else {
fifo_len = priv->outbox_fifo_depth - rd_pos + wr_pos;
}
return fifo_len;
}
static irqreturn_t do_outbox_isr(void __iomem *base, struct sprd_mbox_priv *priv)
{ struct mbox_chan *chan;
u32 fifo_sts, fifo_len, msg[2]; int i, id;
/* Get the inbox data delivery status */
send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >>
SPRD_INBOX_FIFO_DELIVER_SHIFT; if (!send_sts) {
dev_warn_ratelimited(priv->dev, "spurious inbox interrupt\n"); return IRQ_NONE;
}
while (send_sts) {
id = __ffs(send_sts);
send_sts &= (send_sts - 1);
chan = &priv->chan[id];
/* * Check if the message was fetched by remote target, if yes, * that means the transmission has been completed.
*/
busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK; if (!(busy & BIT(id)))
mbox_chan_txdone(chan, 0);
}
/* Clear FIFO delivery and overflow status */
writel(fifo_sts &
(SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
priv->inbox_base + SPRD_MBOX_FIFO_RST);
/* Clear irq status */
writel(SPRD_MBOX_IRQ_CLR, priv->inbox_base + SPRD_MBOX_IRQ_STS);
/* Write data into inbox FIFO, and only support 8 bytes every time */
writel(data[0], priv->inbox_base + SPRD_MBOX_MSG_LOW);
writel(data[1], priv->inbox_base + SPRD_MBOX_MSG_HIGH);
/* Set target core id */
writel(id, priv->inbox_base + SPRD_MBOX_ID);
mutex_lock(&priv->lock); if (priv->refcnt++ == 0) { /* Select outbox FIFO mode and reset the outbox FIFO status */
writel(0x0, priv->outbox_base + SPRD_MBOX_FIFO_RST);
/* Enable inbox FIFO overflow and delivery interrupt */
val = readl(priv->inbox_base + SPRD_MBOX_IRQ_MSK);
val &= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ | SPRD_INBOX_FIFO_DELIVER_IRQ);
writel(val, priv->inbox_base + SPRD_MBOX_IRQ_MSK);
/* Enable outbox FIFO not empty interrupt */
val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK);
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
writel(val, priv->outbox_base + SPRD_MBOX_IRQ_MSK);
/* Enable supplementary outbox as the fundamental one */ if (priv->supp_base) {
writel(0x0, priv->supp_base + SPRD_MBOX_FIFO_RST);
val = readl(priv->supp_base + SPRD_MBOX_IRQ_MSK);
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
writel(val, priv->supp_base + SPRD_MBOX_IRQ_MSK);
}
}
mutex_unlock(&priv->lock);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->dev = dev;
mutex_init(&priv->lock);
/* * Unisoc mailbox uses an inbox to send messages to the target * core, and uses (an) outbox(es) to receive messages from other * cores. * * Thus in general the mailbox controller supplies 2 different * register addresses and IRQ numbers for inbox and outbox. * * If necessary, a supplementary inbox could be enabled optionally * with an independent FIFO and an extra interrupt.
*/
priv->inbox_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->inbox_base)) return PTR_ERR(priv->inbox_base);
priv->outbox_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(priv->outbox_base)) return PTR_ERR(priv->outbox_base);
clk = devm_clk_get_enabled(dev, "enable"); if (IS_ERR(clk)) {
dev_err(dev, "failed to get mailbox clock\n"); return PTR_ERR(clk);
}
inbox_irq = platform_get_irq_byname(pdev, "inbox"); if (inbox_irq < 0) return inbox_irq;
ret = devm_request_irq(dev, inbox_irq, sprd_mbox_inbox_isr,
IRQF_NO_SUSPEND, dev_name(dev), priv); if (ret) {
dev_err(dev, "failed to request inbox IRQ: %d\n", ret); return ret;
}
outbox_irq = platform_get_irq_byname(pdev, "outbox"); if (outbox_irq < 0) return outbox_irq;
ret = devm_request_irq(dev, outbox_irq, sprd_mbox_outbox_isr,
IRQF_NO_SUSPEND, dev_name(dev), priv); if (ret) {
dev_err(dev, "failed to request outbox IRQ: %d\n", ret); return ret;
}
/* Supplementary outbox IRQ is optional */
supp_irq = platform_get_irq_byname(pdev, "supp-outbox"); if (supp_irq > 0) {
ret = devm_request_irq(dev, supp_irq, sprd_mbox_supp_isr,
IRQF_NO_SUSPEND, dev_name(dev), priv); if (ret) {
dev_err(dev, "failed to request outbox IRQ: %d\n", ret); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.