1f89f9c56SSven Peter // SPDX-License-Identifier: GPL-2.0-only OR MIT
2f89f9c56SSven Peter /*
3f89f9c56SSven Peter  * Apple mailbox driver
4f89f9c56SSven Peter  *
5f89f9c56SSven Peter  * Copyright (C) 2021 The Asahi Linux Contributors
6f89f9c56SSven Peter  *
7f89f9c56SSven Peter  * This driver adds support for two mailbox variants (called ASC and M3 by
8f89f9c56SSven Peter  * Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to
9f89f9c56SSven Peter  * exchange 64+32 bit messages between the main CPU and a co-processor.
10f89f9c56SSven Peter  * Various coprocessors implement different IPC protocols based on these simple
11f89f9c56SSven Peter  * messages and shared memory buffers.
12f89f9c56SSven Peter  *
13f89f9c56SSven Peter  * Both the main CPU and the co-processor see the same set of registers but
14f89f9c56SSven Peter  * the first FIFO (A2I) is always used to transfer messages from the application
15f89f9c56SSven Peter  * processor (us) to the I/O processor and the second one (I2A) for the
16f89f9c56SSven Peter  * other direction.
17f89f9c56SSven Peter  */
18f89f9c56SSven Peter 
19f89f9c56SSven Peter #include <linux/apple-mailbox.h>
2038ed8c88SHector Martin #include <linux/delay.h>
21f89f9c56SSven Peter #include <linux/device.h>
22f89f9c56SSven Peter #include <linux/gfp.h>
23f89f9c56SSven Peter #include <linux/interrupt.h>
24f89f9c56SSven Peter #include <linux/io.h>
25f89f9c56SSven Peter #include <linux/mailbox_controller.h>
26f89f9c56SSven Peter #include <linux/module.h>
27f89f9c56SSven Peter #include <linux/of.h>
28f89f9c56SSven Peter #include <linux/platform_device.h>
29*68584e38SHector Martin #include <linux/spinlock.h>
30f89f9c56SSven Peter #include <linux/types.h>
31f89f9c56SSven Peter 
32f89f9c56SSven Peter #define APPLE_ASC_MBOX_CONTROL_FULL  BIT(16)
33f89f9c56SSven Peter #define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17)
34f89f9c56SSven Peter 
35f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_CONTROL 0x110
36f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_SEND0   0x800
37f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_SEND1   0x808
38f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_RECV0   0x810
39f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_RECV1   0x818
40f89f9c56SSven Peter 
41f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_CONTROL 0x114
42f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_SEND0   0x820
43f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_SEND1   0x828
44f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_RECV0   0x830
45f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_RECV1   0x838
46f89f9c56SSven Peter 
47f89f9c56SSven Peter #define APPLE_M3_MBOX_CONTROL_FULL  BIT(16)
48f89f9c56SSven Peter #define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17)
49f89f9c56SSven Peter 
50f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_CONTROL 0x50
51f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_SEND0	  0x60
52f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_SEND1	  0x68
53f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_RECV0	  0x70
54f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_RECV1	  0x78
55f89f9c56SSven Peter 
56f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_CONTROL 0x80
57f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_SEND0	  0x90
58f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_SEND1	  0x98
59f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_RECV0	  0xa0
60f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_RECV1	  0xa8
61f89f9c56SSven Peter 
62f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_ENABLE	0x48
63f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_ACK		0x4c
64f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_A2I_EMPTY	BIT(0)
65f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1)
66f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_I2A_EMPTY	BIT(2)
67f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3)
68f89f9c56SSven Peter 
69f89f9c56SSven Peter #define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52)
70f89f9c56SSven Peter #define APPLE_MBOX_MSG1_INCNT  GENMASK(51, 48)
71f89f9c56SSven Peter #define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44)
72f89f9c56SSven Peter #define APPLE_MBOX_MSG1_INPTR  GENMASK(43, 40)
73f89f9c56SSven Peter #define APPLE_MBOX_MSG1_MSG    GENMASK(31, 0)
74f89f9c56SSven Peter 
75f89f9c56SSven Peter struct apple_mbox_hw {
76f89f9c56SSven Peter 	unsigned int control_full;
77f89f9c56SSven Peter 	unsigned int control_empty;
78f89f9c56SSven Peter 
79f89f9c56SSven Peter 	unsigned int a2i_control;
80f89f9c56SSven Peter 	unsigned int a2i_send0;
81f89f9c56SSven Peter 	unsigned int a2i_send1;
82f89f9c56SSven Peter 
83f89f9c56SSven Peter 	unsigned int i2a_control;
84f89f9c56SSven Peter 	unsigned int i2a_recv0;
85f89f9c56SSven Peter 	unsigned int i2a_recv1;
86f89f9c56SSven Peter 
87f89f9c56SSven Peter 	bool has_irq_controls;
88f89f9c56SSven Peter 	unsigned int irq_enable;
89f89f9c56SSven Peter 	unsigned int irq_ack;
90f89f9c56SSven Peter 	unsigned int irq_bit_recv_not_empty;
91f89f9c56SSven Peter 	unsigned int irq_bit_send_empty;
92f89f9c56SSven Peter };
93f89f9c56SSven Peter 
94f89f9c56SSven Peter struct apple_mbox {
95f89f9c56SSven Peter 	void __iomem *regs;
96f89f9c56SSven Peter 	const struct apple_mbox_hw *hw;
97f89f9c56SSven Peter 
98f89f9c56SSven Peter 	int irq_recv_not_empty;
99f89f9c56SSven Peter 	int irq_send_empty;
100f89f9c56SSven Peter 
101f89f9c56SSven Peter 	struct mbox_chan chan;
102f89f9c56SSven Peter 
103f89f9c56SSven Peter 	struct device *dev;
104f89f9c56SSven Peter 	struct mbox_controller controller;
105*68584e38SHector Martin 	spinlock_t rx_lock;
106f89f9c56SSven Peter };
107f89f9c56SSven Peter 
108f89f9c56SSven Peter static const struct of_device_id apple_mbox_of_match[];
109f89f9c56SSven Peter 
apple_mbox_hw_can_send(struct apple_mbox * apple_mbox)110f89f9c56SSven Peter static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox)
111f89f9c56SSven Peter {
112f89f9c56SSven Peter 	u32 mbox_ctrl =
113f89f9c56SSven Peter 		readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control);
114f89f9c56SSven Peter 
115f89f9c56SSven Peter 	return !(mbox_ctrl & apple_mbox->hw->control_full);
116f89f9c56SSven Peter }
117f89f9c56SSven Peter 
apple_mbox_hw_send_empty(struct apple_mbox * apple_mbox)11838ed8c88SHector Martin static bool apple_mbox_hw_send_empty(struct apple_mbox *apple_mbox)
11938ed8c88SHector Martin {
12038ed8c88SHector Martin 	u32 mbox_ctrl =
12138ed8c88SHector Martin 		readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control);
12238ed8c88SHector Martin 
12338ed8c88SHector Martin 	return mbox_ctrl & apple_mbox->hw->control_empty;
12438ed8c88SHector Martin }
12538ed8c88SHector Martin 
apple_mbox_hw_send(struct apple_mbox * apple_mbox,struct apple_mbox_msg * msg)126f89f9c56SSven Peter static int apple_mbox_hw_send(struct apple_mbox *apple_mbox,
127f89f9c56SSven Peter 			      struct apple_mbox_msg *msg)
128f89f9c56SSven Peter {
129f89f9c56SSven Peter 	if (!apple_mbox_hw_can_send(apple_mbox))
130f89f9c56SSven Peter 		return -EBUSY;
131f89f9c56SSven Peter 
132f89f9c56SSven Peter 	dev_dbg(apple_mbox->dev, "> TX %016llx %08x\n", msg->msg0, msg->msg1);
133f89f9c56SSven Peter 
134f89f9c56SSven Peter 	writeq_relaxed(msg->msg0, apple_mbox->regs + apple_mbox->hw->a2i_send0);
135f89f9c56SSven Peter 	writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg->msg1),
136f89f9c56SSven Peter 		       apple_mbox->regs + apple_mbox->hw->a2i_send1);
137f89f9c56SSven Peter 
138f89f9c56SSven Peter 	return 0;
139f89f9c56SSven Peter }
140f89f9c56SSven Peter 
apple_mbox_hw_can_recv(struct apple_mbox * apple_mbox)141f89f9c56SSven Peter static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox)
142f89f9c56SSven Peter {
143f89f9c56SSven Peter 	u32 mbox_ctrl =
144f89f9c56SSven Peter 		readl_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_control);
145f89f9c56SSven Peter 
146f89f9c56SSven Peter 	return !(mbox_ctrl & apple_mbox->hw->control_empty);
147f89f9c56SSven Peter }
148f89f9c56SSven Peter 
apple_mbox_hw_recv(struct apple_mbox * apple_mbox,struct apple_mbox_msg * msg)149f89f9c56SSven Peter static int apple_mbox_hw_recv(struct apple_mbox *apple_mbox,
150f89f9c56SSven Peter 			      struct apple_mbox_msg *msg)
151f89f9c56SSven Peter {
152f89f9c56SSven Peter 	if (!apple_mbox_hw_can_recv(apple_mbox))
153f89f9c56SSven Peter 		return -ENOMSG;
154f89f9c56SSven Peter 
155f89f9c56SSven Peter 	msg->msg0 = readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv0);
156f89f9c56SSven Peter 	msg->msg1 = FIELD_GET(
157f89f9c56SSven Peter 		APPLE_MBOX_MSG1_MSG,
158f89f9c56SSven Peter 		readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv1));
159f89f9c56SSven Peter 
160f89f9c56SSven Peter 	dev_dbg(apple_mbox->dev, "< RX %016llx %08x\n", msg->msg0, msg->msg1);
161f89f9c56SSven Peter 
162f89f9c56SSven Peter 	return 0;
163f89f9c56SSven Peter }
164f89f9c56SSven Peter 
apple_mbox_chan_send_data(struct mbox_chan * chan,void * data)165f89f9c56SSven Peter static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data)
166f89f9c56SSven Peter {
167f89f9c56SSven Peter 	struct apple_mbox *apple_mbox = chan->con_priv;
168f89f9c56SSven Peter 	struct apple_mbox_msg *msg = data;
169f89f9c56SSven Peter 	int ret;
170f89f9c56SSven Peter 
171f89f9c56SSven Peter 	ret = apple_mbox_hw_send(apple_mbox, msg);
172f89f9c56SSven Peter 	if (ret)
173f89f9c56SSven Peter 		return ret;
174f89f9c56SSven Peter 
175f89f9c56SSven Peter 	/*
176f89f9c56SSven Peter 	 * The interrupt is level triggered and will keep firing as long as the
177f89f9c56SSven Peter 	 * FIFO is empty. It will also keep firing if the FIFO was empty
178f89f9c56SSven Peter 	 * at any point in the past until it has been acknowledged at the
179f89f9c56SSven Peter 	 * mailbox level. By acknowledging it here we can ensure that we will
180f89f9c56SSven Peter 	 * only get the interrupt once the FIFO has been cleared again.
181f89f9c56SSven Peter 	 * If the FIFO is already empty before the ack it will fire again
182f89f9c56SSven Peter 	 * immediately after the ack.
183f89f9c56SSven Peter 	 */
184f89f9c56SSven Peter 	if (apple_mbox->hw->has_irq_controls) {
185f89f9c56SSven Peter 		writel_relaxed(apple_mbox->hw->irq_bit_send_empty,
186f89f9c56SSven Peter 			       apple_mbox->regs + apple_mbox->hw->irq_ack);
187f89f9c56SSven Peter 	}
188f89f9c56SSven Peter 	enable_irq(apple_mbox->irq_send_empty);
189f89f9c56SSven Peter 
190f89f9c56SSven Peter 	return 0;
191f89f9c56SSven Peter }
192f89f9c56SSven Peter 
apple_mbox_send_empty_irq(int irq,void * data)193f89f9c56SSven Peter static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data)
194f89f9c56SSven Peter {
195f89f9c56SSven Peter 	struct apple_mbox *apple_mbox = data;
196f89f9c56SSven Peter 
197f89f9c56SSven Peter 	/*
198f89f9c56SSven Peter 	 * We don't need to acknowledge the interrupt at the mailbox level
199f89f9c56SSven Peter 	 * here even if supported by the hardware. It will keep firing but that
200f89f9c56SSven Peter 	 * doesn't matter since it's disabled at the main interrupt controller.
201f89f9c56SSven Peter 	 * apple_mbox_chan_send_data will acknowledge it before enabling
202f89f9c56SSven Peter 	 * it at the main controller again.
203f89f9c56SSven Peter 	 */
204f89f9c56SSven Peter 	disable_irq_nosync(apple_mbox->irq_send_empty);
205f89f9c56SSven Peter 	mbox_chan_txdone(&apple_mbox->chan, 0);
206f89f9c56SSven Peter 	return IRQ_HANDLED;
207f89f9c56SSven Peter }
208f89f9c56SSven Peter 
apple_mbox_poll(struct apple_mbox * apple_mbox)209*68584e38SHector Martin static int apple_mbox_poll(struct apple_mbox *apple_mbox)
210f89f9c56SSven Peter {
211f89f9c56SSven Peter 	struct apple_mbox_msg msg;
212*68584e38SHector Martin 	int ret = 0;
213f89f9c56SSven Peter 
214*68584e38SHector Martin 	while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) {
215f89f9c56SSven Peter 		mbox_chan_received_data(&apple_mbox->chan, (void *)&msg);
216*68584e38SHector Martin 		ret++;
217*68584e38SHector Martin 	}
218f89f9c56SSven Peter 
219f89f9c56SSven Peter 	/*
220f89f9c56SSven Peter 	 * The interrupt will keep firing even if there are no more messages
221f89f9c56SSven Peter 	 * unless we also acknowledge it at the mailbox level here.
222f89f9c56SSven Peter 	 * There's no race if a message comes in between the check in the while
223f89f9c56SSven Peter 	 * loop above and the ack below: If a new messages arrives inbetween
224f89f9c56SSven Peter 	 * those two the interrupt will just fire again immediately after the
225f89f9c56SSven Peter 	 * ack since it's level triggered.
226f89f9c56SSven Peter 	 */
227f89f9c56SSven Peter 	if (apple_mbox->hw->has_irq_controls) {
228f89f9c56SSven Peter 		writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty,
229f89f9c56SSven Peter 			       apple_mbox->regs + apple_mbox->hw->irq_ack);
230f89f9c56SSven Peter 	}
231f89f9c56SSven Peter 
232*68584e38SHector Martin 	return ret;
233*68584e38SHector Martin }
234*68584e38SHector Martin 
apple_mbox_recv_irq(int irq,void * data)235*68584e38SHector Martin static irqreturn_t apple_mbox_recv_irq(int irq, void *data)
236*68584e38SHector Martin {
237*68584e38SHector Martin 	struct apple_mbox *apple_mbox = data;
238*68584e38SHector Martin 
239*68584e38SHector Martin 	spin_lock(&apple_mbox->rx_lock);
240*68584e38SHector Martin 	apple_mbox_poll(apple_mbox);
241*68584e38SHector Martin 	spin_unlock(&apple_mbox->rx_lock);
242*68584e38SHector Martin 
243f89f9c56SSven Peter 	return IRQ_HANDLED;
244f89f9c56SSven Peter }
245f89f9c56SSven Peter 
apple_mbox_chan_peek_data(struct mbox_chan * chan)246*68584e38SHector Martin static bool apple_mbox_chan_peek_data(struct mbox_chan *chan)
247*68584e38SHector Martin {
248*68584e38SHector Martin 	struct apple_mbox *apple_mbox = chan->con_priv;
249*68584e38SHector Martin 	unsigned long flags;
250*68584e38SHector Martin 	int ret;
251*68584e38SHector Martin 
252*68584e38SHector Martin 	spin_lock_irqsave(&apple_mbox->rx_lock, flags);
253*68584e38SHector Martin 	ret = apple_mbox_poll(apple_mbox);
254*68584e38SHector Martin 	spin_unlock_irqrestore(&apple_mbox->rx_lock, flags);
255*68584e38SHector Martin 
256*68584e38SHector Martin 	return ret > 0;
257*68584e38SHector Martin }
258*68584e38SHector Martin 
apple_mbox_chan_flush(struct mbox_chan * chan,unsigned long timeout)25938ed8c88SHector Martin static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout)
26038ed8c88SHector Martin {
26138ed8c88SHector Martin 	struct apple_mbox *apple_mbox = chan->con_priv;
26238ed8c88SHector Martin 	unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
26338ed8c88SHector Martin 
26438ed8c88SHector Martin 	while (time_before(jiffies, deadline)) {
26538ed8c88SHector Martin 		if (apple_mbox_hw_send_empty(apple_mbox)) {
26638ed8c88SHector Martin 			mbox_chan_txdone(&apple_mbox->chan, 0);
26738ed8c88SHector Martin 			return 0;
26838ed8c88SHector Martin 		}
26938ed8c88SHector Martin 
27038ed8c88SHector Martin 		udelay(1);
27138ed8c88SHector Martin 	}
27238ed8c88SHector Martin 
27338ed8c88SHector Martin 	return -ETIME;
27438ed8c88SHector Martin }
27538ed8c88SHector Martin 
apple_mbox_chan_startup(struct mbox_chan * chan)276f89f9c56SSven Peter static int apple_mbox_chan_startup(struct mbox_chan *chan)
277f89f9c56SSven Peter {
278f89f9c56SSven Peter 	struct apple_mbox *apple_mbox = chan->con_priv;
279f89f9c56SSven Peter 
280f89f9c56SSven Peter 	/*
281f89f9c56SSven Peter 	 * Only some variants of this mailbox HW provide interrupt control
282f89f9c56SSven Peter 	 * at the mailbox level. We therefore need to handle enabling/disabling
283f89f9c56SSven Peter 	 * interrupts at the main interrupt controller anyway for hardware that
284f89f9c56SSven Peter 	 * doesn't. Just always keep the interrupts we care about enabled at
285f89f9c56SSven Peter 	 * the mailbox level so that both hardware revisions behave almost
286f89f9c56SSven Peter 	 * the same.
287f89f9c56SSven Peter 	 */
288f89f9c56SSven Peter 	if (apple_mbox->hw->has_irq_controls) {
289f89f9c56SSven Peter 		writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty |
290f89f9c56SSven Peter 				       apple_mbox->hw->irq_bit_send_empty,
291f89f9c56SSven Peter 			       apple_mbox->regs + apple_mbox->hw->irq_enable);
292f89f9c56SSven Peter 	}
293f89f9c56SSven Peter 
294f89f9c56SSven Peter 	enable_irq(apple_mbox->irq_recv_not_empty);
295f89f9c56SSven Peter 	return 0;
296f89f9c56SSven Peter }
297f89f9c56SSven Peter 
apple_mbox_chan_shutdown(struct mbox_chan * chan)298f89f9c56SSven Peter static void apple_mbox_chan_shutdown(struct mbox_chan *chan)
299f89f9c56SSven Peter {
300f89f9c56SSven Peter 	struct apple_mbox *apple_mbox = chan->con_priv;
301f89f9c56SSven Peter 
302f89f9c56SSven Peter 	disable_irq(apple_mbox->irq_recv_not_empty);
303f89f9c56SSven Peter }
304f89f9c56SSven Peter 
305f89f9c56SSven Peter static const struct mbox_chan_ops apple_mbox_ops = {
306f89f9c56SSven Peter 	.send_data = apple_mbox_chan_send_data,
307*68584e38SHector Martin 	.peek_data = apple_mbox_chan_peek_data,
30838ed8c88SHector Martin 	.flush = apple_mbox_chan_flush,
309f89f9c56SSven Peter 	.startup = apple_mbox_chan_startup,
310f89f9c56SSven Peter 	.shutdown = apple_mbox_chan_shutdown,
311f89f9c56SSven Peter };
312f89f9c56SSven Peter 
apple_mbox_of_xlate(struct mbox_controller * mbox,const struct of_phandle_args * args)313f89f9c56SSven Peter static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox,
314f89f9c56SSven Peter 					     const struct of_phandle_args *args)
315f89f9c56SSven Peter {
316f89f9c56SSven Peter 	if (args->args_count != 0)
317f89f9c56SSven Peter 		return ERR_PTR(-EINVAL);
318f89f9c56SSven Peter 
319f89f9c56SSven Peter 	return &mbox->chans[0];
320f89f9c56SSven Peter }
321f89f9c56SSven Peter 
apple_mbox_probe(struct platform_device * pdev)322f89f9c56SSven Peter static int apple_mbox_probe(struct platform_device *pdev)
323f89f9c56SSven Peter {
324f89f9c56SSven Peter 	int ret;
325f89f9c56SSven Peter 	const struct of_device_id *match;
326f89f9c56SSven Peter 	char *irqname;
327f89f9c56SSven Peter 	struct apple_mbox *mbox;
328f89f9c56SSven Peter 	struct device *dev = &pdev->dev;
329f89f9c56SSven Peter 
330f89f9c56SSven Peter 	match = of_match_node(apple_mbox_of_match, pdev->dev.of_node);
331f89f9c56SSven Peter 	if (!match)
332f89f9c56SSven Peter 		return -EINVAL;
333f89f9c56SSven Peter 	if (!match->data)
334f89f9c56SSven Peter 		return -EINVAL;
335f89f9c56SSven Peter 
336f89f9c56SSven Peter 	mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
337f89f9c56SSven Peter 	if (!mbox)
338f89f9c56SSven Peter 		return -ENOMEM;
339f89f9c56SSven Peter 	platform_set_drvdata(pdev, mbox);
340f89f9c56SSven Peter 
341f89f9c56SSven Peter 	mbox->dev = dev;
342f89f9c56SSven Peter 	mbox->regs = devm_platform_ioremap_resource(pdev, 0);
343f89f9c56SSven Peter 	if (IS_ERR(mbox->regs))
344f89f9c56SSven Peter 		return PTR_ERR(mbox->regs);
345f89f9c56SSven Peter 
346f89f9c56SSven Peter 	mbox->hw = match->data;
347f89f9c56SSven Peter 	mbox->irq_recv_not_empty =
348f89f9c56SSven Peter 		platform_get_irq_byname(pdev, "recv-not-empty");
349f89f9c56SSven Peter 	if (mbox->irq_recv_not_empty < 0)
350f89f9c56SSven Peter 		return -ENODEV;
351f89f9c56SSven Peter 
352f89f9c56SSven Peter 	mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty");
353f89f9c56SSven Peter 	if (mbox->irq_send_empty < 0)
354f89f9c56SSven Peter 		return -ENODEV;
355f89f9c56SSven Peter 
356f89f9c56SSven Peter 	mbox->controller.dev = mbox->dev;
357f89f9c56SSven Peter 	mbox->controller.num_chans = 1;
358f89f9c56SSven Peter 	mbox->controller.chans = &mbox->chan;
359f89f9c56SSven Peter 	mbox->controller.ops = &apple_mbox_ops;
360f89f9c56SSven Peter 	mbox->controller.txdone_irq = true;
361f89f9c56SSven Peter 	mbox->controller.of_xlate = apple_mbox_of_xlate;
362f89f9c56SSven Peter 	mbox->chan.con_priv = mbox;
363*68584e38SHector Martin 	spin_lock_init(&mbox->rx_lock);
364f89f9c56SSven Peter 
365f89f9c56SSven Peter 	irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev));
366f89f9c56SSven Peter 	if (!irqname)
367f89f9c56SSven Peter 		return -ENOMEM;
368f89f9c56SSven Peter 
369f89f9c56SSven Peter 	ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL,
370f89f9c56SSven Peter 					apple_mbox_recv_irq,
371f89f9c56SSven Peter 					IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname,
372f89f9c56SSven Peter 					mbox);
373f89f9c56SSven Peter 	if (ret)
374f89f9c56SSven Peter 		return ret;
375f89f9c56SSven Peter 
376f89f9c56SSven Peter 	irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev));
377f89f9c56SSven Peter 	if (!irqname)
378f89f9c56SSven Peter 		return -ENOMEM;
379f89f9c56SSven Peter 
380f89f9c56SSven Peter 	ret = devm_request_irq(dev, mbox->irq_send_empty,
381f89f9c56SSven Peter 			       apple_mbox_send_empty_irq, IRQF_NO_AUTOEN,
382f89f9c56SSven Peter 			       irqname, mbox);
383f89f9c56SSven Peter 	if (ret)
384f89f9c56SSven Peter 		return ret;
385f89f9c56SSven Peter 
386f89f9c56SSven Peter 	return devm_mbox_controller_register(dev, &mbox->controller);
387f89f9c56SSven Peter }
388f89f9c56SSven Peter 
389f89f9c56SSven Peter static const struct apple_mbox_hw apple_mbox_asc_hw = {
390f89f9c56SSven Peter 	.control_full = APPLE_ASC_MBOX_CONTROL_FULL,
391f89f9c56SSven Peter 	.control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
392f89f9c56SSven Peter 
393f89f9c56SSven Peter 	.a2i_control = APPLE_ASC_MBOX_A2I_CONTROL,
394f89f9c56SSven Peter 	.a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
395f89f9c56SSven Peter 	.a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
396f89f9c56SSven Peter 
397f89f9c56SSven Peter 	.i2a_control = APPLE_ASC_MBOX_I2A_CONTROL,
398f89f9c56SSven Peter 	.i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
399f89f9c56SSven Peter 	.i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
400f89f9c56SSven Peter 
401f89f9c56SSven Peter 	.has_irq_controls = false,
402f89f9c56SSven Peter };
403f89f9c56SSven Peter 
404f89f9c56SSven Peter static const struct apple_mbox_hw apple_mbox_m3_hw = {
405f89f9c56SSven Peter 	.control_full = APPLE_M3_MBOX_CONTROL_FULL,
406f89f9c56SSven Peter 	.control_empty = APPLE_M3_MBOX_CONTROL_EMPTY,
407f89f9c56SSven Peter 
408f89f9c56SSven Peter 	.a2i_control = APPLE_M3_MBOX_A2I_CONTROL,
409f89f9c56SSven Peter 	.a2i_send0 = APPLE_M3_MBOX_A2I_SEND0,
410f89f9c56SSven Peter 	.a2i_send1 = APPLE_M3_MBOX_A2I_SEND1,
411f89f9c56SSven Peter 
412f89f9c56SSven Peter 	.i2a_control = APPLE_M3_MBOX_I2A_CONTROL,
413f89f9c56SSven Peter 	.i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0,
414f89f9c56SSven Peter 	.i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1,
415f89f9c56SSven Peter 
416f89f9c56SSven Peter 	.has_irq_controls = true,
417f89f9c56SSven Peter 	.irq_enable = APPLE_M3_MBOX_IRQ_ENABLE,
418f89f9c56SSven Peter 	.irq_ack = APPLE_M3_MBOX_IRQ_ACK,
419f89f9c56SSven Peter 	.irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY,
420f89f9c56SSven Peter 	.irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY,
421f89f9c56SSven Peter };
422f89f9c56SSven Peter 
423f89f9c56SSven Peter static const struct of_device_id apple_mbox_of_match[] = {
4241fa68a35SHector Martin 	{ .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw },
4251fa68a35SHector Martin 	{ .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw },
426f89f9c56SSven Peter 	{}
427f89f9c56SSven Peter };
428f89f9c56SSven Peter MODULE_DEVICE_TABLE(of, apple_mbox_of_match);
429f89f9c56SSven Peter 
430f89f9c56SSven Peter static struct platform_driver apple_mbox_driver = {
431f89f9c56SSven Peter 	.driver = {
432f89f9c56SSven Peter 		.name = "apple-mailbox",
433f89f9c56SSven Peter 		.of_match_table = apple_mbox_of_match,
434f89f9c56SSven Peter 	},
435f89f9c56SSven Peter 	.probe = apple_mbox_probe,
436f89f9c56SSven Peter };
437f89f9c56SSven Peter module_platform_driver(apple_mbox_driver);
438f89f9c56SSven Peter 
439f89f9c56SSven Peter MODULE_LICENSE("Dual MIT/GPL");
440f89f9c56SSven Peter MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
441f89f9c56SSven Peter MODULE_DESCRIPTION("Apple Mailbox driver");
442