0001
0002
0003
0004
0005
0006 #include <linux/device.h>
0007 #include <linux/interrupt.h>
0008 #include <linux/io.h>
0009 #include <linux/kernel.h>
0010 #include <linux/mailbox_controller.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014
0015 #define DRIVER_NAME "altera-mailbox"
0016
0017 #define MAILBOX_CMD_REG 0x00
0018 #define MAILBOX_PTR_REG 0x04
0019 #define MAILBOX_STS_REG 0x08
0020 #define MAILBOX_INTMASK_REG 0x0C
0021
0022 #define INT_PENDING_MSK 0x1
0023 #define INT_SPACE_MSK 0x2
0024
0025 #define STS_PENDING_MSK 0x1
0026 #define STS_FULL_MSK 0x2
0027 #define STS_FULL_OFT 0x1
0028
0029 #define MBOX_PENDING(status) (((status) & STS_PENDING_MSK))
0030 #define MBOX_FULL(status) (((status) & STS_FULL_MSK) >> STS_FULL_OFT)
0031
0032 enum altera_mbox_msg {
0033 MBOX_CMD = 0,
0034 MBOX_PTR,
0035 };
0036
0037 #define MBOX_POLLING_MS 5
0038
0039 struct altera_mbox {
0040 bool is_sender;
0041 bool intr_mode;
0042 int irq;
0043 void __iomem *mbox_base;
0044 struct device *dev;
0045 struct mbox_controller controller;
0046
0047
0048 struct timer_list rxpoll_timer;
0049 struct mbox_chan *chan;
0050 };
0051
0052 static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan)
0053 {
0054 if (!chan || !chan->con_priv)
0055 return NULL;
0056
0057 return (struct altera_mbox *)chan->con_priv;
0058 }
0059
0060 static inline int altera_mbox_full(struct altera_mbox *mbox)
0061 {
0062 u32 status;
0063
0064 status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
0065 return MBOX_FULL(status);
0066 }
0067
0068 static inline int altera_mbox_pending(struct altera_mbox *mbox)
0069 {
0070 u32 status;
0071
0072 status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
0073 return MBOX_PENDING(status);
0074 }
0075
0076 static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable)
0077 {
0078 u32 mask;
0079
0080 mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
0081 if (enable)
0082 mask |= INT_PENDING_MSK;
0083 else
0084 mask &= ~INT_PENDING_MSK;
0085 writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
0086 }
0087
0088 static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable)
0089 {
0090 u32 mask;
0091
0092 mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
0093 if (enable)
0094 mask |= INT_SPACE_MSK;
0095 else
0096 mask &= ~INT_SPACE_MSK;
0097 writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
0098 }
0099
0100 static bool altera_mbox_is_sender(struct altera_mbox *mbox)
0101 {
0102 u32 reg;
0103
0104
0105
0106 #define MBOX_MAGIC 0xA5A5AA55
0107 writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG);
0108 reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
0109 if (reg == MBOX_MAGIC) {
0110
0111 writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG);
0112 return true;
0113 }
0114 return false;
0115 }
0116
0117 static void altera_mbox_rx_data(struct mbox_chan *chan)
0118 {
0119 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0120 u32 data[2];
0121
0122 if (altera_mbox_pending(mbox)) {
0123 data[MBOX_PTR] =
0124 readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
0125 data[MBOX_CMD] =
0126 readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG);
0127 mbox_chan_received_data(chan, (void *)data);
0128 }
0129 }
0130
0131 static void altera_mbox_poll_rx(struct timer_list *t)
0132 {
0133 struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer);
0134
0135 altera_mbox_rx_data(mbox->chan);
0136
0137 mod_timer(&mbox->rxpoll_timer,
0138 jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
0139 }
0140
0141 static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p)
0142 {
0143 struct mbox_chan *chan = (struct mbox_chan *)p;
0144 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0145
0146 altera_mbox_tx_intmask(mbox, false);
0147 mbox_chan_txdone(chan, 0);
0148
0149 return IRQ_HANDLED;
0150 }
0151
0152 static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p)
0153 {
0154 struct mbox_chan *chan = (struct mbox_chan *)p;
0155
0156 altera_mbox_rx_data(chan);
0157 return IRQ_HANDLED;
0158 }
0159
0160 static int altera_mbox_startup_sender(struct mbox_chan *chan)
0161 {
0162 int ret;
0163 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0164
0165 if (mbox->intr_mode) {
0166 ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0,
0167 DRIVER_NAME, chan);
0168 if (unlikely(ret)) {
0169 dev_err(mbox->dev,
0170 "failed to register mailbox interrupt:%d\n",
0171 ret);
0172 return ret;
0173 }
0174 }
0175
0176 return 0;
0177 }
0178
0179 static int altera_mbox_startup_receiver(struct mbox_chan *chan)
0180 {
0181 int ret;
0182 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0183
0184 if (mbox->intr_mode) {
0185 ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0,
0186 DRIVER_NAME, chan);
0187 if (unlikely(ret)) {
0188 mbox->intr_mode = false;
0189 goto polling;
0190 }
0191
0192 altera_mbox_rx_intmask(mbox, true);
0193 return 0;
0194 }
0195
0196 polling:
0197
0198 mbox->chan = chan;
0199 timer_setup(&mbox->rxpoll_timer, altera_mbox_poll_rx, 0);
0200 mod_timer(&mbox->rxpoll_timer,
0201 jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
0202
0203 return 0;
0204 }
0205
0206 static int altera_mbox_send_data(struct mbox_chan *chan, void *data)
0207 {
0208 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0209 u32 *udata = (u32 *)data;
0210
0211 if (!mbox || !data)
0212 return -EINVAL;
0213 if (!mbox->is_sender) {
0214 dev_warn(mbox->dev,
0215 "failed to send. This is receiver mailbox.\n");
0216 return -EINVAL;
0217 }
0218
0219 if (altera_mbox_full(mbox))
0220 return -EBUSY;
0221
0222
0223 if (mbox->intr_mode)
0224 altera_mbox_tx_intmask(mbox, true);
0225
0226
0227 writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG);
0228 writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG);
0229
0230 return 0;
0231 }
0232
0233 static bool altera_mbox_last_tx_done(struct mbox_chan *chan)
0234 {
0235 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0236
0237
0238 return altera_mbox_full(mbox) ? false : true;
0239 }
0240
0241 static bool altera_mbox_peek_data(struct mbox_chan *chan)
0242 {
0243 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0244
0245 return altera_mbox_pending(mbox) ? true : false;
0246 }
0247
0248 static int altera_mbox_startup(struct mbox_chan *chan)
0249 {
0250 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0251 int ret = 0;
0252
0253 if (!mbox)
0254 return -EINVAL;
0255
0256 if (mbox->is_sender)
0257 ret = altera_mbox_startup_sender(chan);
0258 else
0259 ret = altera_mbox_startup_receiver(chan);
0260
0261 return ret;
0262 }
0263
0264 static void altera_mbox_shutdown(struct mbox_chan *chan)
0265 {
0266 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
0267
0268 if (mbox->intr_mode) {
0269
0270 writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG);
0271 free_irq(mbox->irq, chan);
0272 } else if (!mbox->is_sender) {
0273 del_timer_sync(&mbox->rxpoll_timer);
0274 }
0275 }
0276
0277 static const struct mbox_chan_ops altera_mbox_ops = {
0278 .send_data = altera_mbox_send_data,
0279 .startup = altera_mbox_startup,
0280 .shutdown = altera_mbox_shutdown,
0281 .last_tx_done = altera_mbox_last_tx_done,
0282 .peek_data = altera_mbox_peek_data,
0283 };
0284
0285 static int altera_mbox_probe(struct platform_device *pdev)
0286 {
0287 struct altera_mbox *mbox;
0288 struct mbox_chan *chans;
0289 int ret;
0290
0291 mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox),
0292 GFP_KERNEL);
0293 if (!mbox)
0294 return -ENOMEM;
0295
0296
0297 chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
0298 if (!chans)
0299 return -ENOMEM;
0300
0301 mbox->mbox_base = devm_platform_ioremap_resource(pdev, 0);
0302 if (IS_ERR(mbox->mbox_base))
0303 return PTR_ERR(mbox->mbox_base);
0304
0305
0306 mbox->is_sender = altera_mbox_is_sender(mbox);
0307
0308 mbox->irq = platform_get_irq(pdev, 0);
0309 if (mbox->irq >= 0)
0310 mbox->intr_mode = true;
0311
0312 mbox->dev = &pdev->dev;
0313
0314
0315 chans[0].con_priv = mbox;
0316 mbox->controller.dev = mbox->dev;
0317 mbox->controller.num_chans = 1;
0318 mbox->controller.chans = chans;
0319 mbox->controller.ops = &altera_mbox_ops;
0320
0321 if (mbox->is_sender) {
0322 if (mbox->intr_mode) {
0323 mbox->controller.txdone_irq = true;
0324 } else {
0325 mbox->controller.txdone_poll = true;
0326 mbox->controller.txpoll_period = MBOX_POLLING_MS;
0327 }
0328 }
0329
0330 ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
0331 if (ret) {
0332 dev_err(&pdev->dev, "Register mailbox failed\n");
0333 goto err;
0334 }
0335
0336 platform_set_drvdata(pdev, mbox);
0337 err:
0338 return ret;
0339 }
0340
0341 static const struct of_device_id altera_mbox_match[] = {
0342 { .compatible = "altr,mailbox-1.0" },
0343 { }
0344 };
0345
0346 MODULE_DEVICE_TABLE(of, altera_mbox_match);
0347
0348 static struct platform_driver altera_mbox_driver = {
0349 .probe = altera_mbox_probe,
0350 .driver = {
0351 .name = DRIVER_NAME,
0352 .of_match_table = altera_mbox_match,
0353 },
0354 };
0355
0356 module_platform_driver(altera_mbox_driver);
0357
0358 MODULE_LICENSE("GPL v2");
0359 MODULE_DESCRIPTION("Altera mailbox specific functions");
0360 MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
0361 MODULE_ALIAS("platform:altera-mailbox");