0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/interrupt.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/mutex.h>
0014 #include <linux/delay.h>
0015 #include <linux/slab.h>
0016 #include <linux/err.h>
0017 #include <linux/io.h>
0018 #include <linux/module.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/mailbox_controller.h>
0021
0022 #define INTR_SET_OFS 0x0
0023 #define INTR_STAT_OFS 0x4
0024 #define INTR_CLR_OFS 0x8
0025
0026 #define MHU_SEC_OFFSET 0x0
0027 #define MHU_LP_OFFSET 0xc
0028 #define MHU_HP_OFFSET 0x18
0029 #define TX_REG_OFFSET 0x24
0030
0031 #define MHU_CHANS 3
0032
0033 struct platform_mhu_link {
0034 int irq;
0035 void __iomem *tx_reg;
0036 void __iomem *rx_reg;
0037 };
0038
0039 struct platform_mhu {
0040 void __iomem *base;
0041 struct platform_mhu_link mlink[MHU_CHANS];
0042 struct mbox_chan chan[MHU_CHANS];
0043 struct mbox_controller mbox;
0044 };
0045
0046 static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)
0047 {
0048 struct mbox_chan *chan = p;
0049 struct platform_mhu_link *mlink = chan->con_priv;
0050 u32 val;
0051
0052 val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
0053 if (!val)
0054 return IRQ_NONE;
0055
0056 mbox_chan_received_data(chan, (void *)&val);
0057
0058 writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
0059
0060 return IRQ_HANDLED;
0061 }
0062
0063 static bool platform_mhu_last_tx_done(struct mbox_chan *chan)
0064 {
0065 struct platform_mhu_link *mlink = chan->con_priv;
0066 u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
0067
0068 return (val == 0);
0069 }
0070
0071 static int platform_mhu_send_data(struct mbox_chan *chan, void *data)
0072 {
0073 struct platform_mhu_link *mlink = chan->con_priv;
0074 u32 *arg = data;
0075
0076 writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
0077
0078 return 0;
0079 }
0080
0081 static int platform_mhu_startup(struct mbox_chan *chan)
0082 {
0083 struct platform_mhu_link *mlink = chan->con_priv;
0084 u32 val;
0085 int ret;
0086
0087 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
0088 writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
0089
0090 ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,
0091 IRQF_SHARED, "platform_mhu_link", chan);
0092 if (ret) {
0093 dev_err(chan->mbox->dev,
0094 "Unable to acquire IRQ %d\n", mlink->irq);
0095 return ret;
0096 }
0097
0098 return 0;
0099 }
0100
0101 static void platform_mhu_shutdown(struct mbox_chan *chan)
0102 {
0103 struct platform_mhu_link *mlink = chan->con_priv;
0104
0105 free_irq(mlink->irq, chan);
0106 }
0107
0108 static const struct mbox_chan_ops platform_mhu_ops = {
0109 .send_data = platform_mhu_send_data,
0110 .startup = platform_mhu_startup,
0111 .shutdown = platform_mhu_shutdown,
0112 .last_tx_done = platform_mhu_last_tx_done,
0113 };
0114
0115 static int platform_mhu_probe(struct platform_device *pdev)
0116 {
0117 int i, err;
0118 struct platform_mhu *mhu;
0119 struct device *dev = &pdev->dev;
0120 int platform_mhu_reg[MHU_CHANS] = {
0121 MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET
0122 };
0123
0124
0125 mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
0126 if (!mhu)
0127 return -ENOMEM;
0128
0129 mhu->base = devm_platform_ioremap_resource(pdev, 0);
0130 if (IS_ERR(mhu->base)) {
0131 dev_err(dev, "ioremap failed\n");
0132 return PTR_ERR(mhu->base);
0133 }
0134
0135 for (i = 0; i < MHU_CHANS; i++) {
0136 mhu->chan[i].con_priv = &mhu->mlink[i];
0137 mhu->mlink[i].irq = platform_get_irq(pdev, i);
0138 if (mhu->mlink[i].irq < 0) {
0139 dev_err(dev, "failed to get irq%d\n", i);
0140 return mhu->mlink[i].irq;
0141 }
0142 mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];
0143 mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
0144 }
0145
0146 mhu->mbox.dev = dev;
0147 mhu->mbox.chans = &mhu->chan[0];
0148 mhu->mbox.num_chans = MHU_CHANS;
0149 mhu->mbox.ops = &platform_mhu_ops;
0150 mhu->mbox.txdone_irq = false;
0151 mhu->mbox.txdone_poll = true;
0152 mhu->mbox.txpoll_period = 1;
0153
0154 platform_set_drvdata(pdev, mhu);
0155
0156 err = devm_mbox_controller_register(dev, &mhu->mbox);
0157 if (err) {
0158 dev_err(dev, "Failed to register mailboxes %d\n", err);
0159 return err;
0160 }
0161
0162 dev_info(dev, "Platform MHU Mailbox registered\n");
0163 return 0;
0164 }
0165
0166 static const struct of_device_id platform_mhu_dt_ids[] = {
0167 { .compatible = "amlogic,meson-gxbb-mhu", },
0168 { },
0169 };
0170 MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);
0171
0172 static struct platform_driver platform_mhu_driver = {
0173 .probe = platform_mhu_probe,
0174 .driver = {
0175 .name = "platform-mhu",
0176 .of_match_table = platform_mhu_dt_ids,
0177 },
0178 };
0179
0180 module_platform_driver(platform_mhu_driver);
0181
0182 MODULE_LICENSE("GPL v2");
0183 MODULE_ALIAS("platform:platform-mhu");
0184 MODULE_DESCRIPTION("Platform MHU Driver");
0185 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");