Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only OR MIT
0002 /*
0003  * Apple mailbox driver
0004  *
0005  * Copyright (C) 2021 The Asahi Linux Contributors
0006  *
0007  * This driver adds support for two mailbox variants (called ASC and M3 by
0008  * Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to
0009  * exchange 64+32 bit messages between the main CPU and a co-processor.
0010  * Various coprocessors implement different IPC protocols based on these simple
0011  * messages and shared memory buffers.
0012  *
0013  * Both the main CPU and the co-processor see the same set of registers but
0014  * the first FIFO (A2I) is always used to transfer messages from the application
0015  * processor (us) to the I/O processor and the second one (I2A) for the
0016  * other direction.
0017  */
0018 
0019 #include <linux/apple-mailbox.h>
0020 #include <linux/device.h>
0021 #include <linux/gfp.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/io.h>
0024 #include <linux/mailbox_controller.h>
0025 #include <linux/module.h>
0026 #include <linux/of.h>
0027 #include <linux/platform_device.h>
0028 #include <linux/types.h>
0029 
0030 #define APPLE_ASC_MBOX_CONTROL_FULL  BIT(16)
0031 #define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17)
0032 
0033 #define APPLE_ASC_MBOX_A2I_CONTROL 0x110
0034 #define APPLE_ASC_MBOX_A2I_SEND0   0x800
0035 #define APPLE_ASC_MBOX_A2I_SEND1   0x808
0036 #define APPLE_ASC_MBOX_A2I_RECV0   0x810
0037 #define APPLE_ASC_MBOX_A2I_RECV1   0x818
0038 
0039 #define APPLE_ASC_MBOX_I2A_CONTROL 0x114
0040 #define APPLE_ASC_MBOX_I2A_SEND0   0x820
0041 #define APPLE_ASC_MBOX_I2A_SEND1   0x828
0042 #define APPLE_ASC_MBOX_I2A_RECV0   0x830
0043 #define APPLE_ASC_MBOX_I2A_RECV1   0x838
0044 
0045 #define APPLE_M3_MBOX_CONTROL_FULL  BIT(16)
0046 #define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17)
0047 
0048 #define APPLE_M3_MBOX_A2I_CONTROL 0x50
0049 #define APPLE_M3_MBOX_A2I_SEND0   0x60
0050 #define APPLE_M3_MBOX_A2I_SEND1   0x68
0051 #define APPLE_M3_MBOX_A2I_RECV0   0x70
0052 #define APPLE_M3_MBOX_A2I_RECV1   0x78
0053 
0054 #define APPLE_M3_MBOX_I2A_CONTROL 0x80
0055 #define APPLE_M3_MBOX_I2A_SEND0   0x90
0056 #define APPLE_M3_MBOX_I2A_SEND1   0x98
0057 #define APPLE_M3_MBOX_I2A_RECV0   0xa0
0058 #define APPLE_M3_MBOX_I2A_RECV1   0xa8
0059 
0060 #define APPLE_M3_MBOX_IRQ_ENABLE    0x48
0061 #define APPLE_M3_MBOX_IRQ_ACK       0x4c
0062 #define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0)
0063 #define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1)
0064 #define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2)
0065 #define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3)
0066 
0067 #define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52)
0068 #define APPLE_MBOX_MSG1_INCNT  GENMASK(51, 48)
0069 #define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44)
0070 #define APPLE_MBOX_MSG1_INPTR  GENMASK(43, 40)
0071 #define APPLE_MBOX_MSG1_MSG    GENMASK(31, 0)
0072 
0073 struct apple_mbox_hw {
0074     unsigned int control_full;
0075     unsigned int control_empty;
0076 
0077     unsigned int a2i_control;
0078     unsigned int a2i_send0;
0079     unsigned int a2i_send1;
0080 
0081     unsigned int i2a_control;
0082     unsigned int i2a_recv0;
0083     unsigned int i2a_recv1;
0084 
0085     bool has_irq_controls;
0086     unsigned int irq_enable;
0087     unsigned int irq_ack;
0088     unsigned int irq_bit_recv_not_empty;
0089     unsigned int irq_bit_send_empty;
0090 };
0091 
0092 struct apple_mbox {
0093     void __iomem *regs;
0094     const struct apple_mbox_hw *hw;
0095 
0096     int irq_recv_not_empty;
0097     int irq_send_empty;
0098 
0099     struct mbox_chan chan;
0100 
0101     struct device *dev;
0102     struct mbox_controller controller;
0103 };
0104 
0105 static const struct of_device_id apple_mbox_of_match[];
0106 
0107 static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox)
0108 {
0109     u32 mbox_ctrl =
0110         readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control);
0111 
0112     return !(mbox_ctrl & apple_mbox->hw->control_full);
0113 }
0114 
0115 static int apple_mbox_hw_send(struct apple_mbox *apple_mbox,
0116                   struct apple_mbox_msg *msg)
0117 {
0118     if (!apple_mbox_hw_can_send(apple_mbox))
0119         return -EBUSY;
0120 
0121     dev_dbg(apple_mbox->dev, "> TX %016llx %08x\n", msg->msg0, msg->msg1);
0122 
0123     writeq_relaxed(msg->msg0, apple_mbox->regs + apple_mbox->hw->a2i_send0);
0124     writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg->msg1),
0125                apple_mbox->regs + apple_mbox->hw->a2i_send1);
0126 
0127     return 0;
0128 }
0129 
0130 static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox)
0131 {
0132     u32 mbox_ctrl =
0133         readl_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_control);
0134 
0135     return !(mbox_ctrl & apple_mbox->hw->control_empty);
0136 }
0137 
0138 static int apple_mbox_hw_recv(struct apple_mbox *apple_mbox,
0139                   struct apple_mbox_msg *msg)
0140 {
0141     if (!apple_mbox_hw_can_recv(apple_mbox))
0142         return -ENOMSG;
0143 
0144     msg->msg0 = readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv0);
0145     msg->msg1 = FIELD_GET(
0146         APPLE_MBOX_MSG1_MSG,
0147         readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv1));
0148 
0149     dev_dbg(apple_mbox->dev, "< RX %016llx %08x\n", msg->msg0, msg->msg1);
0150 
0151     return 0;
0152 }
0153 
0154 static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data)
0155 {
0156     struct apple_mbox *apple_mbox = chan->con_priv;
0157     struct apple_mbox_msg *msg = data;
0158     int ret;
0159 
0160     ret = apple_mbox_hw_send(apple_mbox, msg);
0161     if (ret)
0162         return ret;
0163 
0164     /*
0165      * The interrupt is level triggered and will keep firing as long as the
0166      * FIFO is empty. It will also keep firing if the FIFO was empty
0167      * at any point in the past until it has been acknowledged at the
0168      * mailbox level. By acknowledging it here we can ensure that we will
0169      * only get the interrupt once the FIFO has been cleared again.
0170      * If the FIFO is already empty before the ack it will fire again
0171      * immediately after the ack.
0172      */
0173     if (apple_mbox->hw->has_irq_controls) {
0174         writel_relaxed(apple_mbox->hw->irq_bit_send_empty,
0175                    apple_mbox->regs + apple_mbox->hw->irq_ack);
0176     }
0177     enable_irq(apple_mbox->irq_send_empty);
0178 
0179     return 0;
0180 }
0181 
0182 static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data)
0183 {
0184     struct apple_mbox *apple_mbox = data;
0185 
0186     /*
0187      * We don't need to acknowledge the interrupt at the mailbox level
0188      * here even if supported by the hardware. It will keep firing but that
0189      * doesn't matter since it's disabled at the main interrupt controller.
0190      * apple_mbox_chan_send_data will acknowledge it before enabling
0191      * it at the main controller again.
0192      */
0193     disable_irq_nosync(apple_mbox->irq_send_empty);
0194     mbox_chan_txdone(&apple_mbox->chan, 0);
0195     return IRQ_HANDLED;
0196 }
0197 
0198 static irqreturn_t apple_mbox_recv_irq(int irq, void *data)
0199 {
0200     struct apple_mbox *apple_mbox = data;
0201     struct apple_mbox_msg msg;
0202 
0203     while (apple_mbox_hw_recv(apple_mbox, &msg) == 0)
0204         mbox_chan_received_data(&apple_mbox->chan, (void *)&msg);
0205 
0206     /*
0207      * The interrupt will keep firing even if there are no more messages
0208      * unless we also acknowledge it at the mailbox level here.
0209      * There's no race if a message comes in between the check in the while
0210      * loop above and the ack below: If a new messages arrives inbetween
0211      * those two the interrupt will just fire again immediately after the
0212      * ack since it's level triggered.
0213      */
0214     if (apple_mbox->hw->has_irq_controls) {
0215         writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty,
0216                    apple_mbox->regs + apple_mbox->hw->irq_ack);
0217     }
0218 
0219     return IRQ_HANDLED;
0220 }
0221 
0222 static int apple_mbox_chan_startup(struct mbox_chan *chan)
0223 {
0224     struct apple_mbox *apple_mbox = chan->con_priv;
0225 
0226     /*
0227      * Only some variants of this mailbox HW provide interrupt control
0228      * at the mailbox level. We therefore need to handle enabling/disabling
0229      * interrupts at the main interrupt controller anyway for hardware that
0230      * doesn't. Just always keep the interrupts we care about enabled at
0231      * the mailbox level so that both hardware revisions behave almost
0232      * the same.
0233      */
0234     if (apple_mbox->hw->has_irq_controls) {
0235         writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty |
0236                        apple_mbox->hw->irq_bit_send_empty,
0237                    apple_mbox->regs + apple_mbox->hw->irq_enable);
0238     }
0239 
0240     enable_irq(apple_mbox->irq_recv_not_empty);
0241     return 0;
0242 }
0243 
0244 static void apple_mbox_chan_shutdown(struct mbox_chan *chan)
0245 {
0246     struct apple_mbox *apple_mbox = chan->con_priv;
0247 
0248     disable_irq(apple_mbox->irq_recv_not_empty);
0249 }
0250 
0251 static const struct mbox_chan_ops apple_mbox_ops = {
0252     .send_data = apple_mbox_chan_send_data,
0253     .startup = apple_mbox_chan_startup,
0254     .shutdown = apple_mbox_chan_shutdown,
0255 };
0256 
0257 static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox,
0258                          const struct of_phandle_args *args)
0259 {
0260     if (args->args_count != 0)
0261         return ERR_PTR(-EINVAL);
0262 
0263     return &mbox->chans[0];
0264 }
0265 
0266 static int apple_mbox_probe(struct platform_device *pdev)
0267 {
0268     int ret;
0269     const struct of_device_id *match;
0270     char *irqname;
0271     struct apple_mbox *mbox;
0272     struct device *dev = &pdev->dev;
0273 
0274     match = of_match_node(apple_mbox_of_match, pdev->dev.of_node);
0275     if (!match)
0276         return -EINVAL;
0277     if (!match->data)
0278         return -EINVAL;
0279 
0280     mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
0281     if (!mbox)
0282         return -ENOMEM;
0283     platform_set_drvdata(pdev, mbox);
0284 
0285     mbox->dev = dev;
0286     mbox->regs = devm_platform_ioremap_resource(pdev, 0);
0287     if (IS_ERR(mbox->regs))
0288         return PTR_ERR(mbox->regs);
0289 
0290     mbox->hw = match->data;
0291     mbox->irq_recv_not_empty =
0292         platform_get_irq_byname(pdev, "recv-not-empty");
0293     if (mbox->irq_recv_not_empty < 0)
0294         return -ENODEV;
0295 
0296     mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty");
0297     if (mbox->irq_send_empty < 0)
0298         return -ENODEV;
0299 
0300     mbox->controller.dev = mbox->dev;
0301     mbox->controller.num_chans = 1;
0302     mbox->controller.chans = &mbox->chan;
0303     mbox->controller.ops = &apple_mbox_ops;
0304     mbox->controller.txdone_irq = true;
0305     mbox->controller.of_xlate = apple_mbox_of_xlate;
0306     mbox->chan.con_priv = mbox;
0307 
0308     irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev));
0309     if (!irqname)
0310         return -ENOMEM;
0311 
0312     ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL,
0313                     apple_mbox_recv_irq,
0314                     IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname,
0315                     mbox);
0316     if (ret)
0317         return ret;
0318 
0319     irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev));
0320     if (!irqname)
0321         return -ENOMEM;
0322 
0323     ret = devm_request_irq(dev, mbox->irq_send_empty,
0324                    apple_mbox_send_empty_irq, IRQF_NO_AUTOEN,
0325                    irqname, mbox);
0326     if (ret)
0327         return ret;
0328 
0329     return devm_mbox_controller_register(dev, &mbox->controller);
0330 }
0331 
0332 static const struct apple_mbox_hw apple_mbox_asc_hw = {
0333     .control_full = APPLE_ASC_MBOX_CONTROL_FULL,
0334     .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
0335 
0336     .a2i_control = APPLE_ASC_MBOX_A2I_CONTROL,
0337     .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
0338     .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
0339 
0340     .i2a_control = APPLE_ASC_MBOX_I2A_CONTROL,
0341     .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
0342     .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
0343 
0344     .has_irq_controls = false,
0345 };
0346 
0347 static const struct apple_mbox_hw apple_mbox_m3_hw = {
0348     .control_full = APPLE_M3_MBOX_CONTROL_FULL,
0349     .control_empty = APPLE_M3_MBOX_CONTROL_EMPTY,
0350 
0351     .a2i_control = APPLE_M3_MBOX_A2I_CONTROL,
0352     .a2i_send0 = APPLE_M3_MBOX_A2I_SEND0,
0353     .a2i_send1 = APPLE_M3_MBOX_A2I_SEND1,
0354 
0355     .i2a_control = APPLE_M3_MBOX_I2A_CONTROL,
0356     .i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0,
0357     .i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1,
0358 
0359     .has_irq_controls = true,
0360     .irq_enable = APPLE_M3_MBOX_IRQ_ENABLE,
0361     .irq_ack = APPLE_M3_MBOX_IRQ_ACK,
0362     .irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY,
0363     .irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY,
0364 };
0365 
0366 static const struct of_device_id apple_mbox_of_match[] = {
0367     { .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw },
0368     { .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw },
0369     {}
0370 };
0371 MODULE_DEVICE_TABLE(of, apple_mbox_of_match);
0372 
0373 static struct platform_driver apple_mbox_driver = {
0374     .driver = {
0375         .name = "apple-mailbox",
0376         .of_match_table = apple_mbox_of_match,
0377     },
0378     .probe = apple_mbox_probe,
0379 };
0380 module_platform_driver(apple_mbox_driver);
0381 
0382 MODULE_LICENSE("Dual MIT/GPL");
0383 MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
0384 MODULE_DESCRIPTION("Apple Mailbox driver");