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> 20*38ed8c88SHector 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> 29f89f9c56SSven Peter #include <linux/types.h> 30f89f9c56SSven Peter 31f89f9c56SSven Peter #define APPLE_ASC_MBOX_CONTROL_FULL BIT(16) 32f89f9c56SSven Peter #define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17) 33f89f9c56SSven Peter 34f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_CONTROL 0x110 35f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_SEND0 0x800 36f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_SEND1 0x808 37f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_RECV0 0x810 38f89f9c56SSven Peter #define APPLE_ASC_MBOX_A2I_RECV1 0x818 39f89f9c56SSven Peter 40f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_CONTROL 0x114 41f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_SEND0 0x820 42f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_SEND1 0x828 43f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_RECV0 0x830 44f89f9c56SSven Peter #define APPLE_ASC_MBOX_I2A_RECV1 0x838 45f89f9c56SSven Peter 46f89f9c56SSven Peter #define APPLE_M3_MBOX_CONTROL_FULL BIT(16) 47f89f9c56SSven Peter #define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17) 48f89f9c56SSven Peter 49f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_CONTROL 0x50 50f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_SEND0 0x60 51f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_SEND1 0x68 52f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_RECV0 0x70 53f89f9c56SSven Peter #define APPLE_M3_MBOX_A2I_RECV1 0x78 54f89f9c56SSven Peter 55f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_CONTROL 0x80 56f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_SEND0 0x90 57f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_SEND1 0x98 58f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_RECV0 0xa0 59f89f9c56SSven Peter #define APPLE_M3_MBOX_I2A_RECV1 0xa8 60f89f9c56SSven Peter 61f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_ENABLE 0x48 62f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_ACK 0x4c 63f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0) 64f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1) 65f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2) 66f89f9c56SSven Peter #define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3) 67f89f9c56SSven Peter 68f89f9c56SSven Peter #define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52) 69f89f9c56SSven Peter #define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48) 70f89f9c56SSven Peter #define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44) 71f89f9c56SSven Peter #define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40) 72f89f9c56SSven Peter #define APPLE_MBOX_MSG1_MSG GENMASK(31, 0) 73f89f9c56SSven Peter 74f89f9c56SSven Peter struct apple_mbox_hw { 75f89f9c56SSven Peter unsigned int control_full; 76f89f9c56SSven Peter unsigned int control_empty; 77f89f9c56SSven Peter 78f89f9c56SSven Peter unsigned int a2i_control; 79f89f9c56SSven Peter unsigned int a2i_send0; 80f89f9c56SSven Peter unsigned int a2i_send1; 81f89f9c56SSven Peter 82f89f9c56SSven Peter unsigned int i2a_control; 83f89f9c56SSven Peter unsigned int i2a_recv0; 84f89f9c56SSven Peter unsigned int i2a_recv1; 85f89f9c56SSven Peter 86f89f9c56SSven Peter bool has_irq_controls; 87f89f9c56SSven Peter unsigned int irq_enable; 88f89f9c56SSven Peter unsigned int irq_ack; 89f89f9c56SSven Peter unsigned int irq_bit_recv_not_empty; 90f89f9c56SSven Peter unsigned int irq_bit_send_empty; 91f89f9c56SSven Peter }; 92f89f9c56SSven Peter 93f89f9c56SSven Peter struct apple_mbox { 94f89f9c56SSven Peter void __iomem *regs; 95f89f9c56SSven Peter const struct apple_mbox_hw *hw; 96f89f9c56SSven Peter 97f89f9c56SSven Peter int irq_recv_not_empty; 98f89f9c56SSven Peter int irq_send_empty; 99f89f9c56SSven Peter 100f89f9c56SSven Peter struct mbox_chan chan; 101f89f9c56SSven Peter 102f89f9c56SSven Peter struct device *dev; 103f89f9c56SSven Peter struct mbox_controller controller; 104f89f9c56SSven Peter }; 105f89f9c56SSven Peter 106f89f9c56SSven Peter static const struct of_device_id apple_mbox_of_match[]; 107f89f9c56SSven Peter 108f89f9c56SSven Peter static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox) 109f89f9c56SSven Peter { 110f89f9c56SSven Peter u32 mbox_ctrl = 111f89f9c56SSven Peter readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control); 112f89f9c56SSven Peter 113f89f9c56SSven Peter return !(mbox_ctrl & apple_mbox->hw->control_full); 114f89f9c56SSven Peter } 115f89f9c56SSven Peter 116*38ed8c88SHector Martin static bool apple_mbox_hw_send_empty(struct apple_mbox *apple_mbox) 117*38ed8c88SHector Martin { 118*38ed8c88SHector Martin u32 mbox_ctrl = 119*38ed8c88SHector Martin readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control); 120*38ed8c88SHector Martin 121*38ed8c88SHector Martin return mbox_ctrl & apple_mbox->hw->control_empty; 122*38ed8c88SHector Martin } 123*38ed8c88SHector Martin 124f89f9c56SSven Peter static int apple_mbox_hw_send(struct apple_mbox *apple_mbox, 125f89f9c56SSven Peter struct apple_mbox_msg *msg) 126f89f9c56SSven Peter { 127f89f9c56SSven Peter if (!apple_mbox_hw_can_send(apple_mbox)) 128f89f9c56SSven Peter return -EBUSY; 129f89f9c56SSven Peter 130f89f9c56SSven Peter dev_dbg(apple_mbox->dev, "> TX %016llx %08x\n", msg->msg0, msg->msg1); 131f89f9c56SSven Peter 132f89f9c56SSven Peter writeq_relaxed(msg->msg0, apple_mbox->regs + apple_mbox->hw->a2i_send0); 133f89f9c56SSven Peter writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg->msg1), 134f89f9c56SSven Peter apple_mbox->regs + apple_mbox->hw->a2i_send1); 135f89f9c56SSven Peter 136f89f9c56SSven Peter return 0; 137f89f9c56SSven Peter } 138f89f9c56SSven Peter 139f89f9c56SSven Peter static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox) 140f89f9c56SSven Peter { 141f89f9c56SSven Peter u32 mbox_ctrl = 142f89f9c56SSven Peter readl_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_control); 143f89f9c56SSven Peter 144f89f9c56SSven Peter return !(mbox_ctrl & apple_mbox->hw->control_empty); 145f89f9c56SSven Peter } 146f89f9c56SSven Peter 147f89f9c56SSven Peter static int apple_mbox_hw_recv(struct apple_mbox *apple_mbox, 148f89f9c56SSven Peter struct apple_mbox_msg *msg) 149f89f9c56SSven Peter { 150f89f9c56SSven Peter if (!apple_mbox_hw_can_recv(apple_mbox)) 151f89f9c56SSven Peter return -ENOMSG; 152f89f9c56SSven Peter 153f89f9c56SSven Peter msg->msg0 = readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv0); 154f89f9c56SSven Peter msg->msg1 = FIELD_GET( 155f89f9c56SSven Peter APPLE_MBOX_MSG1_MSG, 156f89f9c56SSven Peter readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv1)); 157f89f9c56SSven Peter 158f89f9c56SSven Peter dev_dbg(apple_mbox->dev, "< RX %016llx %08x\n", msg->msg0, msg->msg1); 159f89f9c56SSven Peter 160f89f9c56SSven Peter return 0; 161f89f9c56SSven Peter } 162f89f9c56SSven Peter 163f89f9c56SSven Peter static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data) 164f89f9c56SSven Peter { 165f89f9c56SSven Peter struct apple_mbox *apple_mbox = chan->con_priv; 166f89f9c56SSven Peter struct apple_mbox_msg *msg = data; 167f89f9c56SSven Peter int ret; 168f89f9c56SSven Peter 169f89f9c56SSven Peter ret = apple_mbox_hw_send(apple_mbox, msg); 170f89f9c56SSven Peter if (ret) 171f89f9c56SSven Peter return ret; 172f89f9c56SSven Peter 173f89f9c56SSven Peter /* 174f89f9c56SSven Peter * The interrupt is level triggered and will keep firing as long as the 175f89f9c56SSven Peter * FIFO is empty. It will also keep firing if the FIFO was empty 176f89f9c56SSven Peter * at any point in the past until it has been acknowledged at the 177f89f9c56SSven Peter * mailbox level. By acknowledging it here we can ensure that we will 178f89f9c56SSven Peter * only get the interrupt once the FIFO has been cleared again. 179f89f9c56SSven Peter * If the FIFO is already empty before the ack it will fire again 180f89f9c56SSven Peter * immediately after the ack. 181f89f9c56SSven Peter */ 182f89f9c56SSven Peter if (apple_mbox->hw->has_irq_controls) { 183f89f9c56SSven Peter writel_relaxed(apple_mbox->hw->irq_bit_send_empty, 184f89f9c56SSven Peter apple_mbox->regs + apple_mbox->hw->irq_ack); 185f89f9c56SSven Peter } 186f89f9c56SSven Peter enable_irq(apple_mbox->irq_send_empty); 187f89f9c56SSven Peter 188f89f9c56SSven Peter return 0; 189f89f9c56SSven Peter } 190f89f9c56SSven Peter 191f89f9c56SSven Peter static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) 192f89f9c56SSven Peter { 193f89f9c56SSven Peter struct apple_mbox *apple_mbox = data; 194f89f9c56SSven Peter 195f89f9c56SSven Peter /* 196f89f9c56SSven Peter * We don't need to acknowledge the interrupt at the mailbox level 197f89f9c56SSven Peter * here even if supported by the hardware. It will keep firing but that 198f89f9c56SSven Peter * doesn't matter since it's disabled at the main interrupt controller. 199f89f9c56SSven Peter * apple_mbox_chan_send_data will acknowledge it before enabling 200f89f9c56SSven Peter * it at the main controller again. 201f89f9c56SSven Peter */ 202f89f9c56SSven Peter disable_irq_nosync(apple_mbox->irq_send_empty); 203f89f9c56SSven Peter mbox_chan_txdone(&apple_mbox->chan, 0); 204f89f9c56SSven Peter return IRQ_HANDLED; 205f89f9c56SSven Peter } 206f89f9c56SSven Peter 207f89f9c56SSven Peter static irqreturn_t apple_mbox_recv_irq(int irq, void *data) 208f89f9c56SSven Peter { 209f89f9c56SSven Peter struct apple_mbox *apple_mbox = data; 210f89f9c56SSven Peter struct apple_mbox_msg msg; 211f89f9c56SSven Peter 212f89f9c56SSven Peter while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) 213f89f9c56SSven Peter mbox_chan_received_data(&apple_mbox->chan, (void *)&msg); 214f89f9c56SSven Peter 215f89f9c56SSven Peter /* 216f89f9c56SSven Peter * The interrupt will keep firing even if there are no more messages 217f89f9c56SSven Peter * unless we also acknowledge it at the mailbox level here. 218f89f9c56SSven Peter * There's no race if a message comes in between the check in the while 219f89f9c56SSven Peter * loop above and the ack below: If a new messages arrives inbetween 220f89f9c56SSven Peter * those two the interrupt will just fire again immediately after the 221f89f9c56SSven Peter * ack since it's level triggered. 222f89f9c56SSven Peter */ 223f89f9c56SSven Peter if (apple_mbox->hw->has_irq_controls) { 224f89f9c56SSven Peter writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty, 225f89f9c56SSven Peter apple_mbox->regs + apple_mbox->hw->irq_ack); 226f89f9c56SSven Peter } 227f89f9c56SSven Peter 228f89f9c56SSven Peter return IRQ_HANDLED; 229f89f9c56SSven Peter } 230f89f9c56SSven Peter 231*38ed8c88SHector Martin static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout) 232*38ed8c88SHector Martin { 233*38ed8c88SHector Martin struct apple_mbox *apple_mbox = chan->con_priv; 234*38ed8c88SHector Martin unsigned long deadline = jiffies + msecs_to_jiffies(timeout); 235*38ed8c88SHector Martin 236*38ed8c88SHector Martin while (time_before(jiffies, deadline)) { 237*38ed8c88SHector Martin if (apple_mbox_hw_send_empty(apple_mbox)) { 238*38ed8c88SHector Martin mbox_chan_txdone(&apple_mbox->chan, 0); 239*38ed8c88SHector Martin return 0; 240*38ed8c88SHector Martin } 241*38ed8c88SHector Martin 242*38ed8c88SHector Martin udelay(1); 243*38ed8c88SHector Martin } 244*38ed8c88SHector Martin 245*38ed8c88SHector Martin return -ETIME; 246*38ed8c88SHector Martin } 247*38ed8c88SHector Martin 248f89f9c56SSven Peter static int apple_mbox_chan_startup(struct mbox_chan *chan) 249f89f9c56SSven Peter { 250f89f9c56SSven Peter struct apple_mbox *apple_mbox = chan->con_priv; 251f89f9c56SSven Peter 252f89f9c56SSven Peter /* 253f89f9c56SSven Peter * Only some variants of this mailbox HW provide interrupt control 254f89f9c56SSven Peter * at the mailbox level. We therefore need to handle enabling/disabling 255f89f9c56SSven Peter * interrupts at the main interrupt controller anyway for hardware that 256f89f9c56SSven Peter * doesn't. Just always keep the interrupts we care about enabled at 257f89f9c56SSven Peter * the mailbox level so that both hardware revisions behave almost 258f89f9c56SSven Peter * the same. 259f89f9c56SSven Peter */ 260f89f9c56SSven Peter if (apple_mbox->hw->has_irq_controls) { 261f89f9c56SSven Peter writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty | 262f89f9c56SSven Peter apple_mbox->hw->irq_bit_send_empty, 263f89f9c56SSven Peter apple_mbox->regs + apple_mbox->hw->irq_enable); 264f89f9c56SSven Peter } 265f89f9c56SSven Peter 266f89f9c56SSven Peter enable_irq(apple_mbox->irq_recv_not_empty); 267f89f9c56SSven Peter return 0; 268f89f9c56SSven Peter } 269f89f9c56SSven Peter 270f89f9c56SSven Peter static void apple_mbox_chan_shutdown(struct mbox_chan *chan) 271f89f9c56SSven Peter { 272f89f9c56SSven Peter struct apple_mbox *apple_mbox = chan->con_priv; 273f89f9c56SSven Peter 274f89f9c56SSven Peter disable_irq(apple_mbox->irq_recv_not_empty); 275f89f9c56SSven Peter } 276f89f9c56SSven Peter 277f89f9c56SSven Peter static const struct mbox_chan_ops apple_mbox_ops = { 278f89f9c56SSven Peter .send_data = apple_mbox_chan_send_data, 279*38ed8c88SHector Martin .flush = apple_mbox_chan_flush, 280f89f9c56SSven Peter .startup = apple_mbox_chan_startup, 281f89f9c56SSven Peter .shutdown = apple_mbox_chan_shutdown, 282f89f9c56SSven Peter }; 283f89f9c56SSven Peter 284f89f9c56SSven Peter static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox, 285f89f9c56SSven Peter const struct of_phandle_args *args) 286f89f9c56SSven Peter { 287f89f9c56SSven Peter if (args->args_count != 0) 288f89f9c56SSven Peter return ERR_PTR(-EINVAL); 289f89f9c56SSven Peter 290f89f9c56SSven Peter return &mbox->chans[0]; 291f89f9c56SSven Peter } 292f89f9c56SSven Peter 293f89f9c56SSven Peter static int apple_mbox_probe(struct platform_device *pdev) 294f89f9c56SSven Peter { 295f89f9c56SSven Peter int ret; 296f89f9c56SSven Peter const struct of_device_id *match; 297f89f9c56SSven Peter char *irqname; 298f89f9c56SSven Peter struct apple_mbox *mbox; 299f89f9c56SSven Peter struct device *dev = &pdev->dev; 300f89f9c56SSven Peter 301f89f9c56SSven Peter match = of_match_node(apple_mbox_of_match, pdev->dev.of_node); 302f89f9c56SSven Peter if (!match) 303f89f9c56SSven Peter return -EINVAL; 304f89f9c56SSven Peter if (!match->data) 305f89f9c56SSven Peter return -EINVAL; 306f89f9c56SSven Peter 307f89f9c56SSven Peter mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 308f89f9c56SSven Peter if (!mbox) 309f89f9c56SSven Peter return -ENOMEM; 310f89f9c56SSven Peter platform_set_drvdata(pdev, mbox); 311f89f9c56SSven Peter 312f89f9c56SSven Peter mbox->dev = dev; 313f89f9c56SSven Peter mbox->regs = devm_platform_ioremap_resource(pdev, 0); 314f89f9c56SSven Peter if (IS_ERR(mbox->regs)) 315f89f9c56SSven Peter return PTR_ERR(mbox->regs); 316f89f9c56SSven Peter 317f89f9c56SSven Peter mbox->hw = match->data; 318f89f9c56SSven Peter mbox->irq_recv_not_empty = 319f89f9c56SSven Peter platform_get_irq_byname(pdev, "recv-not-empty"); 320f89f9c56SSven Peter if (mbox->irq_recv_not_empty < 0) 321f89f9c56SSven Peter return -ENODEV; 322f89f9c56SSven Peter 323f89f9c56SSven Peter mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty"); 324f89f9c56SSven Peter if (mbox->irq_send_empty < 0) 325f89f9c56SSven Peter return -ENODEV; 326f89f9c56SSven Peter 327f89f9c56SSven Peter mbox->controller.dev = mbox->dev; 328f89f9c56SSven Peter mbox->controller.num_chans = 1; 329f89f9c56SSven Peter mbox->controller.chans = &mbox->chan; 330f89f9c56SSven Peter mbox->controller.ops = &apple_mbox_ops; 331f89f9c56SSven Peter mbox->controller.txdone_irq = true; 332f89f9c56SSven Peter mbox->controller.of_xlate = apple_mbox_of_xlate; 333f89f9c56SSven Peter mbox->chan.con_priv = mbox; 334f89f9c56SSven Peter 335f89f9c56SSven Peter irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev)); 336f89f9c56SSven Peter if (!irqname) 337f89f9c56SSven Peter return -ENOMEM; 338f89f9c56SSven Peter 339f89f9c56SSven Peter ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL, 340f89f9c56SSven Peter apple_mbox_recv_irq, 341f89f9c56SSven Peter IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname, 342f89f9c56SSven Peter mbox); 343f89f9c56SSven Peter if (ret) 344f89f9c56SSven Peter return ret; 345f89f9c56SSven Peter 346f89f9c56SSven Peter irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev)); 347f89f9c56SSven Peter if (!irqname) 348f89f9c56SSven Peter return -ENOMEM; 349f89f9c56SSven Peter 350f89f9c56SSven Peter ret = devm_request_irq(dev, mbox->irq_send_empty, 351f89f9c56SSven Peter apple_mbox_send_empty_irq, IRQF_NO_AUTOEN, 352f89f9c56SSven Peter irqname, mbox); 353f89f9c56SSven Peter if (ret) 354f89f9c56SSven Peter return ret; 355f89f9c56SSven Peter 356f89f9c56SSven Peter return devm_mbox_controller_register(dev, &mbox->controller); 357f89f9c56SSven Peter } 358f89f9c56SSven Peter 359f89f9c56SSven Peter static const struct apple_mbox_hw apple_mbox_asc_hw = { 360f89f9c56SSven Peter .control_full = APPLE_ASC_MBOX_CONTROL_FULL, 361f89f9c56SSven Peter .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY, 362f89f9c56SSven Peter 363f89f9c56SSven Peter .a2i_control = APPLE_ASC_MBOX_A2I_CONTROL, 364f89f9c56SSven Peter .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0, 365f89f9c56SSven Peter .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1, 366f89f9c56SSven Peter 367f89f9c56SSven Peter .i2a_control = APPLE_ASC_MBOX_I2A_CONTROL, 368f89f9c56SSven Peter .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0, 369f89f9c56SSven Peter .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1, 370f89f9c56SSven Peter 371f89f9c56SSven Peter .has_irq_controls = false, 372f89f9c56SSven Peter }; 373f89f9c56SSven Peter 374f89f9c56SSven Peter static const struct apple_mbox_hw apple_mbox_m3_hw = { 375f89f9c56SSven Peter .control_full = APPLE_M3_MBOX_CONTROL_FULL, 376f89f9c56SSven Peter .control_empty = APPLE_M3_MBOX_CONTROL_EMPTY, 377f89f9c56SSven Peter 378f89f9c56SSven Peter .a2i_control = APPLE_M3_MBOX_A2I_CONTROL, 379f89f9c56SSven Peter .a2i_send0 = APPLE_M3_MBOX_A2I_SEND0, 380f89f9c56SSven Peter .a2i_send1 = APPLE_M3_MBOX_A2I_SEND1, 381f89f9c56SSven Peter 382f89f9c56SSven Peter .i2a_control = APPLE_M3_MBOX_I2A_CONTROL, 383f89f9c56SSven Peter .i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0, 384f89f9c56SSven Peter .i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1, 385f89f9c56SSven Peter 386f89f9c56SSven Peter .has_irq_controls = true, 387f89f9c56SSven Peter .irq_enable = APPLE_M3_MBOX_IRQ_ENABLE, 388f89f9c56SSven Peter .irq_ack = APPLE_M3_MBOX_IRQ_ACK, 389f89f9c56SSven Peter .irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY, 390f89f9c56SSven Peter .irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY, 391f89f9c56SSven Peter }; 392f89f9c56SSven Peter 393f89f9c56SSven Peter static const struct of_device_id apple_mbox_of_match[] = { 3941fa68a35SHector Martin { .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw }, 3951fa68a35SHector Martin { .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw }, 396f89f9c56SSven Peter {} 397f89f9c56SSven Peter }; 398f89f9c56SSven Peter MODULE_DEVICE_TABLE(of, apple_mbox_of_match); 399f89f9c56SSven Peter 400f89f9c56SSven Peter static struct platform_driver apple_mbox_driver = { 401f89f9c56SSven Peter .driver = { 402f89f9c56SSven Peter .name = "apple-mailbox", 403f89f9c56SSven Peter .of_match_table = apple_mbox_of_match, 404f89f9c56SSven Peter }, 405f89f9c56SSven Peter .probe = apple_mbox_probe, 406f89f9c56SSven Peter }; 407f89f9c56SSven Peter module_platform_driver(apple_mbox_driver); 408f89f9c56SSven Peter 409f89f9c56SSven Peter MODULE_LICENSE("Dual MIT/GPL"); 410f89f9c56SSven Peter MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); 411f89f9c56SSven Peter MODULE_DESCRIPTION("Apple Mailbox driver"); 412