drivers/mailbox/stm32-ipcc.c

Source file repositories/reference/linux-study-clean/drivers/mailbox/stm32-ipcc.c

File Facts

System
Linux kernel
Corpus path
drivers/mailbox/stm32-ipcc.c
Extension
.c
Size
9833 bytes
Lines
391
Domain
Driver Families
Bucket
drivers/mailbox
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct stm32_ipcc {
	struct mbox_controller controller;
	void __iomem *reg_base;
	void __iomem *reg_proc;
	struct clk *clk;
	spinlock_t lock; /* protect access to IPCC registers */
	int irqs[IPCC_IRQ_NUM];
	u32 proc_id;
	u32 n_chans;
	u32 xcr;
	u32 xmr;
};

static inline void stm32_ipcc_set_bits(spinlock_t *lock, void __iomem *reg,
				       u32 mask)
{
	unsigned long flags;

	spin_lock_irqsave(lock, flags);
	writel_relaxed(readl_relaxed(reg) | mask, reg);
	spin_unlock_irqrestore(lock, flags);
}

static inline void stm32_ipcc_clr_bits(spinlock_t *lock, void __iomem *reg,
				       u32 mask)
{
	unsigned long flags;

	spin_lock_irqsave(lock, flags);
	writel_relaxed(readl_relaxed(reg) & ~mask, reg);
	spin_unlock_irqrestore(lock, flags);
}

static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data)
{
	struct stm32_ipcc *ipcc = data;
	struct device *dev = ipcc->controller.dev;
	u32 status, mr, tosr, chan;
	irqreturn_t ret = IRQ_NONE;
	int proc_offset;

	/* read 'channel occupied' status from other proc */
	proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST;
	tosr = readl_relaxed(ipcc->reg_proc + proc_offset + IPCC_XTOYSR);
	mr = readl_relaxed(ipcc->reg_proc + IPCC_XMR);

	/* search for unmasked 'channel occupied' */
	status = tosr & FIELD_GET(RX_BIT_MASK, ~mr);

	for (chan = 0; chan < ipcc->n_chans; chan++) {
		if (!(status & (1 << chan)))
			continue;

		dev_dbg(dev, "%s: chan:%d rx\n", __func__, chan);

		mbox_chan_received_data(&ipcc->controller.chans[chan], NULL);

		stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XSCR,
				    RX_BIT_CHAN(chan));

		ret = IRQ_HANDLED;
	}

	return ret;
}

static irqreturn_t stm32_ipcc_tx_irq(int irq, void *data)
{
	struct stm32_ipcc *ipcc = data;
	struct device *dev = ipcc->controller.dev;
	u32 status, mr, tosr, chan;
	irqreturn_t ret = IRQ_NONE;

	tosr = readl_relaxed(ipcc->reg_proc + IPCC_XTOYSR);
	mr = readl_relaxed(ipcc->reg_proc + IPCC_XMR);

	/* search for unmasked 'channel free' */
	status = ~tosr & FIELD_GET(TX_BIT_MASK, ~mr);

	for (chan = 0; chan < ipcc->n_chans ; chan++) {
		if (!(status & (1 << chan)))
			continue;

		dev_dbg(dev, "%s: chan:%d tx\n", __func__, chan);

		/* mask 'tx channel free' interrupt */
		stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
				    TX_BIT_CHAN(chan));

		mbox_chan_txdone(&ipcc->controller.chans[chan], 0);

Annotation

Implementation Notes