summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOtto Pflüger <otto.pflueger@abscue.de>2026-01-10 16:43:37 +0100
committerJassi Brar <jassisinghbrar@gmail.com>2026-02-01 18:59:49 -0600
commitc6ff944003cf1b7be9ef5c9d868a42114bc6e867 (patch)
tree39ce742593834c89c2d429220ec1701919d0a9f5
parentc77661d60d4223bf2ff10d409beb0c3b2021183b (diff)
mailbox: sprd: add support for mailbox revision 2
Newer Unisoc SoCs such as UMS9230 include a new revision of the mailbox IP with support for up to 16 channels. Since the new revision has a similar register layout and many parts have remained unchanged, make the driver support both revisions. Signed-off-by: Otto Pflüger <otto.pflueger@abscue.de> Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
-rw-r--r--drivers/mailbox/sprd-mailbox.c103
1 files changed, 82 insertions, 21 deletions
diff --git a/drivers/mailbox/sprd-mailbox.c b/drivers/mailbox/sprd-mailbox.c
index 9a3d388f76b7..26256581a76a 100644
--- a/drivers/mailbox/sprd-mailbox.c
+++ b/drivers/mailbox/sprd-mailbox.c
@@ -24,7 +24,8 @@
#define SPRD_MBOX_IRQ_STS 0x18
#define SPRD_MBOX_IRQ_MSK 0x1c
#define SPRD_MBOX_LOCK 0x20
-#define SPRD_MBOX_FIFO_DEPTH 0x24
+#define SPRD_MBOX_FIFO_DEPTH 0x24 /* outbox only */
+#define SPRD_MBOX_IN_FIFO_STS2 0x24 /* inbox only, revision 2 */
/* Bit and mask definition for inbox's SPRD_MBOX_FIFO_STS register */
#define SPRD_INBOX_FIFO_DELIVER_MASK GENMASK(23, 16)
@@ -32,8 +33,18 @@
#define SPRD_INBOX_FIFO_DELIVER_SHIFT 16
#define SPRD_INBOX_FIFO_BUSY_MASK GENMASK(7, 0)
+/* Bit and mask definition for R2 inbox's SPRD_MBOX_FIFO_RST register */
+#define SPRD_INBOX_R2_FIFO_OVERFLOW_DELIVER_RST GENMASK(31, 0)
+
+/* Bit and mask definition for R2 inbox's SPRD_MBOX_FIFO_STS register */
+#define SPRD_INBOX_R2_FIFO_DELIVER_MASK GENMASK(15, 0)
+
+/* Bit and mask definition for SPRD_MBOX_IN_FIFO_STS2 register */
+#define SPRD_INBOX_R2_FIFO_OVERFLOW_MASK GENMASK(31, 16)
+#define SPRD_INBOX_R2_FIFO_BUSY_MASK GENMASK(15, 0)
+
/* Bit and mask definition for SPRD_MBOX_IRQ_STS register */
-#define SPRD_MBOX_IRQ_CLR BIT(0)
+#define SPRD_MBOX_IRQ_CLR GENMASK(31, 0)
/* Bit and mask definition for outbox's SPRD_MBOX_FIFO_STS register */
#define SPRD_OUTBOX_FIFO_FULL BIT(2)
@@ -52,8 +63,18 @@
#define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0)
#define SPRD_OUTBOX_BASE_SPAN 0x1000
-#define SPRD_MBOX_CHAN_MAX 8
-#define SPRD_SUPP_INBOX_ID_SC9863A 7
+#define SPRD_MBOX_R1_CHAN_MAX 8
+#define SPRD_MBOX_R2_CHAN_MAX 16
+
+enum sprd_mbox_version {
+ SPRD_MBOX_R1,
+ SPRD_MBOX_R2,
+};
+
+struct sprd_mbox_info {
+ enum sprd_mbox_version version;
+ unsigned long supp_id;
+};
struct sprd_mbox_priv {
struct mbox_controller mbox;
@@ -64,9 +85,11 @@ struct sprd_mbox_priv {
void __iomem *supp_base;
u32 outbox_fifo_depth;
+ const struct sprd_mbox_info *info;
+
struct mutex lock;
u32 refcnt;
- struct mbox_chan chan[SPRD_MBOX_CHAN_MAX];
+ struct mbox_chan chan[SPRD_MBOX_R2_CHAN_MAX];
};
static struct sprd_mbox_priv *to_sprd_mbox_priv(struct mbox_controller *mbox)
@@ -154,22 +177,34 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
{
struct sprd_mbox_priv *priv = data;
struct mbox_chan *chan;
- u32 fifo_sts, send_sts, busy, id;
+ u32 fifo_sts, fifo_sts2, send_sts, busy, id;
fifo_sts = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS);
+ if (priv->info->version == SPRD_MBOX_R2)
+ fifo_sts2 = readl(priv->inbox_base + SPRD_MBOX_IN_FIFO_STS2);
+
/* Get the inbox data delivery status */
- send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >>
- SPRD_INBOX_FIFO_DELIVER_SHIFT;
+ if (priv->info->version == SPRD_MBOX_R2) {
+ send_sts = fifo_sts & SPRD_INBOX_R2_FIFO_DELIVER_MASK;
+ } else {
+ 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;
}
/* Clear FIFO delivery and overflow status first */
- writel(fifo_sts &
- (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
- priv->inbox_base + SPRD_MBOX_FIFO_RST);
+ if (priv->info->version == SPRD_MBOX_R2) {
+ writel(SPRD_INBOX_R2_FIFO_OVERFLOW_DELIVER_RST,
+ priv->inbox_base + SPRD_MBOX_FIFO_RST);
+ } else {
+ writel(fifo_sts & (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
+ priv->inbox_base + SPRD_MBOX_FIFO_RST);
+ }
while (send_sts) {
id = __ffs(send_sts);
@@ -181,7 +216,11 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
* 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 (priv->info->version == SPRD_MBOX_R2)
+ busy = fifo_sts2 & SPRD_INBOX_R2_FIFO_BUSY_MASK;
+ else
+ busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK;
+
if (!(busy & BIT(id)))
mbox_chan_txdone(chan, 0);
}
@@ -295,7 +334,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct sprd_mbox_priv *priv;
int ret, inbox_irq, outbox_irq, supp_irq;
- unsigned long id, supp;
+ unsigned long id;
struct clk *clk;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -305,6 +344,10 @@ static int sprd_mbox_probe(struct platform_device *pdev)
priv->dev = dev;
mutex_init(&priv->lock);
+ priv->info = of_device_get_match_data(dev);
+ if (!priv->info)
+ return -EINVAL;
+
/*
* Unisoc mailbox uses an inbox to send messages to the target
* core, and uses (an) outbox(es) to receive messages from other
@@ -362,12 +405,12 @@ static int sprd_mbox_probe(struct platform_device *pdev)
return ret;
}
- supp = (unsigned long) of_device_get_match_data(dev);
- if (!supp) {
+ if (!priv->info->supp_id) {
dev_err(dev, "no supplementary outbox specified\n");
return -ENODEV;
}
- priv->supp_base = priv->outbox_base + (SPRD_OUTBOX_BASE_SPAN * supp);
+ priv->supp_base = priv->outbox_base +
+ (SPRD_OUTBOX_BASE_SPAN * priv->info->supp_id);
}
/* Get the default outbox FIFO depth */
@@ -375,11 +418,15 @@ static int sprd_mbox_probe(struct platform_device *pdev)
readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1;
priv->mbox.dev = dev;
priv->mbox.chans = &priv->chan[0];
- priv->mbox.num_chans = SPRD_MBOX_CHAN_MAX;
priv->mbox.ops = &sprd_mbox_ops;
priv->mbox.txdone_irq = true;
- for (id = 0; id < SPRD_MBOX_CHAN_MAX; id++)
+ if (priv->info->version == SPRD_MBOX_R2)
+ priv->mbox.num_chans = SPRD_MBOX_R2_CHAN_MAX;
+ else
+ priv->mbox.num_chans = SPRD_MBOX_R1_CHAN_MAX;
+
+ for (id = 0; id < priv->mbox.num_chans; id++)
priv->chan[id].con_priv = (void *)id;
ret = devm_mbox_controller_register(dev, &priv->mbox);
@@ -391,10 +438,24 @@ static int sprd_mbox_probe(struct platform_device *pdev)
return 0;
}
+static const struct sprd_mbox_info sc9860_mbox_info = {
+ .version = SPRD_MBOX_R1,
+};
+
+static const struct sprd_mbox_info sc9863a_mbox_info = {
+ .version = SPRD_MBOX_R1,
+ .supp_id = 7,
+};
+
+static const struct sprd_mbox_info ums9230_mbox_info = {
+ .version = SPRD_MBOX_R2,
+ .supp_id = 6,
+};
+
static const struct of_device_id sprd_mbox_of_match[] = {
- { .compatible = "sprd,sc9860-mailbox" },
- { .compatible = "sprd,sc9863a-mailbox",
- .data = (void *)SPRD_SUPP_INBOX_ID_SC9863A },
+ { .compatible = "sprd,sc9860-mailbox", .data = &sc9860_mbox_info },
+ { .compatible = "sprd,sc9863a-mailbox", .data = &sc9863a_mbox_info },
+ { .compatible = "sprd,ums9230-mailbox", .data = &ums9230_mbox_info },
{ },
};
MODULE_DEVICE_TABLE(of, sprd_mbox_of_match);