Commit c6ff9440 authored by Otto Pflüger's avatar Otto Pflüger Committed by Jassi Brar
Browse files

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: default avatarOtto Pflüger <otto.pflueger@abscue.de>
Signed-off-by: default avatarJassi Brar <jassisinghbrar@gmail.com>
parent c77661d6
Loading
Loading
Loading
Loading
+82 −21
Original line number Diff line number Diff line
@@ -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 */
	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),
	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.
		 */
		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);