Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2017-2019 Samuel Holland <samuel@sholland.org>
0004 
0005 #include <linux/bitops.h>
0006 #include <linux/clk.h>
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/interrupt.h>
0010 #include <linux/io.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mailbox_controller.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/of_irq.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/reset.h>
0018 #include <linux/spinlock.h>
0019 
0020 #define NUM_CHANS       8
0021 
0022 #define CTRL_REG(n)     (0x0000 + 0x4 * ((n) / 4))
0023 #define CTRL_RX(n)      BIT(0 + 8 * ((n) % 4))
0024 #define CTRL_TX(n)      BIT(4 + 8 * ((n) % 4))
0025 
0026 #define REMOTE_IRQ_EN_REG   0x0040
0027 #define REMOTE_IRQ_STAT_REG 0x0050
0028 #define LOCAL_IRQ_EN_REG    0x0060
0029 #define LOCAL_IRQ_STAT_REG  0x0070
0030 
0031 #define RX_IRQ(n)       BIT(0 + 2 * (n))
0032 #define RX_IRQ_MASK     0x5555
0033 #define TX_IRQ(n)       BIT(1 + 2 * (n))
0034 #define TX_IRQ_MASK     0xaaaa
0035 
0036 #define FIFO_STAT_REG(n)    (0x0100 + 0x4 * (n))
0037 #define FIFO_STAT_MASK      GENMASK(0, 0)
0038 
0039 #define MSG_STAT_REG(n)     (0x0140 + 0x4 * (n))
0040 #define MSG_STAT_MASK       GENMASK(2, 0)
0041 
0042 #define MSG_DATA_REG(n)     (0x0180 + 0x4 * (n))
0043 
0044 #define mbox_dbg(mbox, ...) dev_dbg((mbox)->controller.dev, __VA_ARGS__)
0045 
0046 struct sun6i_msgbox {
0047     struct mbox_controller controller;
0048     struct clk *clk;
0049     spinlock_t lock;
0050     void __iomem *regs;
0051 };
0052 
0053 static bool sun6i_msgbox_last_tx_done(struct mbox_chan *chan);
0054 static bool sun6i_msgbox_peek_data(struct mbox_chan *chan);
0055 
0056 static inline int channel_number(struct mbox_chan *chan)
0057 {
0058     return chan - chan->mbox->chans;
0059 }
0060 
0061 static inline struct sun6i_msgbox *to_sun6i_msgbox(struct mbox_chan *chan)
0062 {
0063     return chan->con_priv;
0064 }
0065 
0066 static irqreturn_t sun6i_msgbox_irq(int irq, void *dev_id)
0067 {
0068     struct sun6i_msgbox *mbox = dev_id;
0069     uint32_t status;
0070     int n;
0071 
0072     /* Only examine channels that are currently enabled. */
0073     status = readl(mbox->regs + LOCAL_IRQ_EN_REG) &
0074          readl(mbox->regs + LOCAL_IRQ_STAT_REG);
0075 
0076     if (!(status & RX_IRQ_MASK))
0077         return IRQ_NONE;
0078 
0079     for (n = 0; n < NUM_CHANS; ++n) {
0080         struct mbox_chan *chan = &mbox->controller.chans[n];
0081 
0082         if (!(status & RX_IRQ(n)))
0083             continue;
0084 
0085         while (sun6i_msgbox_peek_data(chan)) {
0086             uint32_t msg = readl(mbox->regs + MSG_DATA_REG(n));
0087 
0088             mbox_dbg(mbox, "Channel %d received 0x%08x\n", n, msg);
0089             mbox_chan_received_data(chan, &msg);
0090         }
0091 
0092         /* The IRQ can be cleared only once the FIFO is empty. */
0093         writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
0094     }
0095 
0096     return IRQ_HANDLED;
0097 }
0098 
0099 static int sun6i_msgbox_send_data(struct mbox_chan *chan, void *data)
0100 {
0101     struct sun6i_msgbox *mbox = to_sun6i_msgbox(chan);
0102     int n = channel_number(chan);
0103     uint32_t msg = *(uint32_t *)data;
0104 
0105     /* Using a channel backwards gets the hardware into a bad state. */
0106     if (WARN_ON_ONCE(!(readl(mbox->regs + CTRL_REG(n)) & CTRL_TX(n))))
0107         return 0;
0108 
0109     writel(msg, mbox->regs + MSG_DATA_REG(n));
0110     mbox_dbg(mbox, "Channel %d sent 0x%08x\n", n, msg);
0111 
0112     return 0;
0113 }
0114 
0115 static int sun6i_msgbox_startup(struct mbox_chan *chan)
0116 {
0117     struct sun6i_msgbox *mbox = to_sun6i_msgbox(chan);
0118     int n = channel_number(chan);
0119 
0120     /* The coprocessor is responsible for setting channel directions. */
0121     if (readl(mbox->regs + CTRL_REG(n)) & CTRL_RX(n)) {
0122         /* Flush the receive FIFO. */
0123         while (sun6i_msgbox_peek_data(chan))
0124             readl(mbox->regs + MSG_DATA_REG(n));
0125         writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
0126 
0127         /* Enable the receive IRQ. */
0128         spin_lock(&mbox->lock);
0129         writel(readl(mbox->regs + LOCAL_IRQ_EN_REG) | RX_IRQ(n),
0130                mbox->regs + LOCAL_IRQ_EN_REG);
0131         spin_unlock(&mbox->lock);
0132     }
0133 
0134     mbox_dbg(mbox, "Channel %d startup complete\n", n);
0135 
0136     return 0;
0137 }
0138 
0139 static void sun6i_msgbox_shutdown(struct mbox_chan *chan)
0140 {
0141     struct sun6i_msgbox *mbox = to_sun6i_msgbox(chan);
0142     int n = channel_number(chan);
0143 
0144     if (readl(mbox->regs + CTRL_REG(n)) & CTRL_RX(n)) {
0145         /* Disable the receive IRQ. */
0146         spin_lock(&mbox->lock);
0147         writel(readl(mbox->regs + LOCAL_IRQ_EN_REG) & ~RX_IRQ(n),
0148                mbox->regs + LOCAL_IRQ_EN_REG);
0149         spin_unlock(&mbox->lock);
0150 
0151         /* Attempt to flush the FIFO until the IRQ is cleared. */
0152         do {
0153             while (sun6i_msgbox_peek_data(chan))
0154                 readl(mbox->regs + MSG_DATA_REG(n));
0155             writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
0156         } while (readl(mbox->regs + LOCAL_IRQ_STAT_REG) & RX_IRQ(n));
0157     }
0158 
0159     mbox_dbg(mbox, "Channel %d shutdown complete\n", n);
0160 }
0161 
0162 static bool sun6i_msgbox_last_tx_done(struct mbox_chan *chan)
0163 {
0164     struct sun6i_msgbox *mbox = to_sun6i_msgbox(chan);
0165     int n = channel_number(chan);
0166 
0167     /*
0168      * The hardware allows snooping on the remote user's IRQ statuses.
0169      * We consider a message to be acknowledged only once the receive IRQ
0170      * for that channel is cleared. Since the receive IRQ for a channel
0171      * cannot be cleared until the FIFO for that channel is empty, this
0172      * ensures that the message has actually been read. It also gives the
0173      * recipient an opportunity to perform minimal processing before
0174      * acknowledging the message.
0175      */
0176     return !(readl(mbox->regs + REMOTE_IRQ_STAT_REG) & RX_IRQ(n));
0177 }
0178 
0179 static bool sun6i_msgbox_peek_data(struct mbox_chan *chan)
0180 {
0181     struct sun6i_msgbox *mbox = to_sun6i_msgbox(chan);
0182     int n = channel_number(chan);
0183 
0184     return readl(mbox->regs + MSG_STAT_REG(n)) & MSG_STAT_MASK;
0185 }
0186 
0187 static const struct mbox_chan_ops sun6i_msgbox_chan_ops = {
0188     .send_data    = sun6i_msgbox_send_data,
0189     .startup      = sun6i_msgbox_startup,
0190     .shutdown     = sun6i_msgbox_shutdown,
0191     .last_tx_done = sun6i_msgbox_last_tx_done,
0192     .peek_data    = sun6i_msgbox_peek_data,
0193 };
0194 
0195 static int sun6i_msgbox_probe(struct platform_device *pdev)
0196 {
0197     struct device *dev = &pdev->dev;
0198     struct mbox_chan *chans;
0199     struct reset_control *reset;
0200     struct sun6i_msgbox *mbox;
0201     int i, ret;
0202 
0203     mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
0204     if (!mbox)
0205         return -ENOMEM;
0206 
0207     chans = devm_kcalloc(dev, NUM_CHANS, sizeof(*chans), GFP_KERNEL);
0208     if (!chans)
0209         return -ENOMEM;
0210 
0211     for (i = 0; i < NUM_CHANS; ++i)
0212         chans[i].con_priv = mbox;
0213 
0214     mbox->clk = devm_clk_get(dev, NULL);
0215     if (IS_ERR(mbox->clk)) {
0216         ret = PTR_ERR(mbox->clk);
0217         dev_err(dev, "Failed to get clock: %d\n", ret);
0218         return ret;
0219     }
0220 
0221     ret = clk_prepare_enable(mbox->clk);
0222     if (ret) {
0223         dev_err(dev, "Failed to enable clock: %d\n", ret);
0224         return ret;
0225     }
0226 
0227     reset = devm_reset_control_get_exclusive(dev, NULL);
0228     if (IS_ERR(reset)) {
0229         ret = PTR_ERR(reset);
0230         dev_err(dev, "Failed to get reset control: %d\n", ret);
0231         goto err_disable_unprepare;
0232     }
0233 
0234     /*
0235      * NOTE: We rely on platform firmware to preconfigure the channel
0236      * directions, and we share this hardware block with other firmware
0237      * that runs concurrently with Linux (e.g. a trusted monitor).
0238      *
0239      * Therefore, we do *not* assert the reset line if probing fails or
0240      * when removing the device.
0241      */
0242     ret = reset_control_deassert(reset);
0243     if (ret) {
0244         dev_err(dev, "Failed to deassert reset: %d\n", ret);
0245         goto err_disable_unprepare;
0246     }
0247 
0248     mbox->regs = devm_platform_ioremap_resource(pdev, 0);
0249     if (IS_ERR(mbox->regs)) {
0250         ret = PTR_ERR(mbox->regs);
0251         dev_err(dev, "Failed to map MMIO resource: %d\n", ret);
0252         goto err_disable_unprepare;
0253     }
0254 
0255     /* Disable all IRQs for this end of the msgbox. */
0256     writel(0, mbox->regs + LOCAL_IRQ_EN_REG);
0257 
0258     ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
0259                    sun6i_msgbox_irq, 0, dev_name(dev), mbox);
0260     if (ret) {
0261         dev_err(dev, "Failed to register IRQ handler: %d\n", ret);
0262         goto err_disable_unprepare;
0263     }
0264 
0265     mbox->controller.dev           = dev;
0266     mbox->controller.ops           = &sun6i_msgbox_chan_ops;
0267     mbox->controller.chans         = chans;
0268     mbox->controller.num_chans     = NUM_CHANS;
0269     mbox->controller.txdone_irq    = false;
0270     mbox->controller.txdone_poll   = true;
0271     mbox->controller.txpoll_period = 5;
0272 
0273     spin_lock_init(&mbox->lock);
0274     platform_set_drvdata(pdev, mbox);
0275 
0276     ret = mbox_controller_register(&mbox->controller);
0277     if (ret) {
0278         dev_err(dev, "Failed to register controller: %d\n", ret);
0279         goto err_disable_unprepare;
0280     }
0281 
0282     return 0;
0283 
0284 err_disable_unprepare:
0285     clk_disable_unprepare(mbox->clk);
0286 
0287     return ret;
0288 }
0289 
0290 static int sun6i_msgbox_remove(struct platform_device *pdev)
0291 {
0292     struct sun6i_msgbox *mbox = platform_get_drvdata(pdev);
0293 
0294     mbox_controller_unregister(&mbox->controller);
0295     /* See the comment in sun6i_msgbox_probe about the reset line. */
0296     clk_disable_unprepare(mbox->clk);
0297 
0298     return 0;
0299 }
0300 
0301 static const struct of_device_id sun6i_msgbox_of_match[] = {
0302     { .compatible = "allwinner,sun6i-a31-msgbox", },
0303     {},
0304 };
0305 MODULE_DEVICE_TABLE(of, sun6i_msgbox_of_match);
0306 
0307 static struct platform_driver sun6i_msgbox_driver = {
0308     .driver = {
0309         .name = "sun6i-msgbox",
0310         .of_match_table = sun6i_msgbox_of_match,
0311     },
0312     .probe  = sun6i_msgbox_probe,
0313     .remove = sun6i_msgbox_remove,
0314 };
0315 module_platform_driver(sun6i_msgbox_driver);
0316 
0317 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
0318 MODULE_DESCRIPTION("Allwinner sun6i/sun8i/sun9i/sun50i Message Box");
0319 MODULE_LICENSE("GPL v2");