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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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