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