Merge tag 'iommu-v4.15-rc1' of git://github.com/awilliam/linux-vfio
[sfrench/cifs-2.6.git] / drivers / mailbox / mailbox-altera.c
1 /*
2  * Copyright Altera Corporation (C) 2013-2014. All rights reserved
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/device.h>
18 #include <linux/interrupt.h>
19 #include <linux/io.h>
20 #include <linux/kernel.h>
21 #include <linux/mailbox_controller.h>
22 #include <linux/module.h>
23 #include <linux/of.h>
24 #include <linux/platform_device.h>
25
26 #define DRIVER_NAME     "altera-mailbox"
27
28 #define MAILBOX_CMD_REG                 0x00
29 #define MAILBOX_PTR_REG                 0x04
30 #define MAILBOX_STS_REG                 0x08
31 #define MAILBOX_INTMASK_REG             0x0C
32
33 #define INT_PENDING_MSK                 0x1
34 #define INT_SPACE_MSK                   0x2
35
36 #define STS_PENDING_MSK                 0x1
37 #define STS_FULL_MSK                    0x2
38 #define STS_FULL_OFT                    0x1
39
40 #define MBOX_PENDING(status)    (((status) & STS_PENDING_MSK))
41 #define MBOX_FULL(status)       (((status) & STS_FULL_MSK) >> STS_FULL_OFT)
42
43 enum altera_mbox_msg {
44         MBOX_CMD = 0,
45         MBOX_PTR,
46 };
47
48 #define MBOX_POLLING_MS         5       /* polling interval 5ms */
49
50 struct altera_mbox {
51         bool is_sender;         /* 1-sender, 0-receiver */
52         bool intr_mode;
53         int irq;
54         void __iomem *mbox_base;
55         struct device *dev;
56         struct mbox_controller controller;
57
58         /* If the controller supports only RX polling mode */
59         struct timer_list rxpoll_timer;
60         struct mbox_chan *chan;
61 };
62
63 static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan)
64 {
65         if (!chan || !chan->con_priv)
66                 return NULL;
67
68         return (struct altera_mbox *)chan->con_priv;
69 }
70
71 static inline int altera_mbox_full(struct altera_mbox *mbox)
72 {
73         u32 status;
74
75         status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
76         return MBOX_FULL(status);
77 }
78
79 static inline int altera_mbox_pending(struct altera_mbox *mbox)
80 {
81         u32 status;
82
83         status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
84         return MBOX_PENDING(status);
85 }
86
87 static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable)
88 {
89         u32 mask;
90
91         mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
92         if (enable)
93                 mask |= INT_PENDING_MSK;
94         else
95                 mask &= ~INT_PENDING_MSK;
96         writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
97 }
98
99 static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable)
100 {
101         u32 mask;
102
103         mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
104         if (enable)
105                 mask |= INT_SPACE_MSK;
106         else
107                 mask &= ~INT_SPACE_MSK;
108         writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
109 }
110
111 static bool altera_mbox_is_sender(struct altera_mbox *mbox)
112 {
113         u32 reg;
114         /* Write a magic number to PTR register and read back this register.
115          * This register is read-write if it is a sender.
116          */
117         #define MBOX_MAGIC      0xA5A5AA55
118         writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG);
119         reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
120         if (reg == MBOX_MAGIC) {
121                 /* Clear to 0 */
122                 writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG);
123                 return true;
124         }
125         return false;
126 }
127
128 static void altera_mbox_rx_data(struct mbox_chan *chan)
129 {
130         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
131         u32 data[2];
132
133         if (altera_mbox_pending(mbox)) {
134                 data[MBOX_PTR] =
135                         readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
136                 data[MBOX_CMD] =
137                         readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG);
138                 mbox_chan_received_data(chan, (void *)data);
139         }
140 }
141
142 static void altera_mbox_poll_rx(struct timer_list *t)
143 {
144         struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer);
145
146         altera_mbox_rx_data(mbox->chan);
147
148         mod_timer(&mbox->rxpoll_timer,
149                   jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
150 }
151
152 static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p)
153 {
154         struct mbox_chan *chan = (struct mbox_chan *)p;
155         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
156
157         altera_mbox_tx_intmask(mbox, false);
158         mbox_chan_txdone(chan, 0);
159
160         return IRQ_HANDLED;
161 }
162
163 static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p)
164 {
165         struct mbox_chan *chan = (struct mbox_chan *)p;
166
167         altera_mbox_rx_data(chan);
168         return IRQ_HANDLED;
169 }
170
171 static int altera_mbox_startup_sender(struct mbox_chan *chan)
172 {
173         int ret;
174         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
175
176         if (mbox->intr_mode) {
177                 ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0,
178                                   DRIVER_NAME, chan);
179                 if (unlikely(ret)) {
180                         dev_err(mbox->dev,
181                                 "failed to register mailbox interrupt:%d\n",
182                                 ret);
183                         return ret;
184                 }
185         }
186
187         return 0;
188 }
189
190 static int altera_mbox_startup_receiver(struct mbox_chan *chan)
191 {
192         int ret;
193         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
194
195         if (mbox->intr_mode) {
196                 ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0,
197                                   DRIVER_NAME, chan);
198                 if (unlikely(ret)) {
199                         mbox->intr_mode = false;
200                         goto polling; /* use polling if failed */
201                 }
202
203                 altera_mbox_rx_intmask(mbox, true);
204                 return 0;
205         }
206
207 polling:
208         /* Setup polling timer */
209         mbox->chan = chan;
210         timer_setup(&mbox->rxpoll_timer, altera_mbox_poll_rx, 0);
211         mod_timer(&mbox->rxpoll_timer,
212                   jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
213
214         return 0;
215 }
216
217 static int altera_mbox_send_data(struct mbox_chan *chan, void *data)
218 {
219         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
220         u32 *udata = (u32 *)data;
221
222         if (!mbox || !data)
223                 return -EINVAL;
224         if (!mbox->is_sender) {
225                 dev_warn(mbox->dev,
226                          "failed to send. This is receiver mailbox.\n");
227                 return -EINVAL;
228         }
229
230         if (altera_mbox_full(mbox))
231                 return -EBUSY;
232
233         /* Enable interrupt before send */
234         if (mbox->intr_mode)
235                 altera_mbox_tx_intmask(mbox, true);
236
237         /* Pointer register must write before command register */
238         writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG);
239         writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG);
240
241         return 0;
242 }
243
244 static bool altera_mbox_last_tx_done(struct mbox_chan *chan)
245 {
246         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
247
248         /* Return false if mailbox is full */
249         return altera_mbox_full(mbox) ? false : true;
250 }
251
252 static bool altera_mbox_peek_data(struct mbox_chan *chan)
253 {
254         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
255
256         return altera_mbox_pending(mbox) ? true : false;
257 }
258
259 static int altera_mbox_startup(struct mbox_chan *chan)
260 {
261         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
262         int ret = 0;
263
264         if (!mbox)
265                 return -EINVAL;
266
267         if (mbox->is_sender)
268                 ret = altera_mbox_startup_sender(chan);
269         else
270                 ret = altera_mbox_startup_receiver(chan);
271
272         return ret;
273 }
274
275 static void altera_mbox_shutdown(struct mbox_chan *chan)
276 {
277         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
278
279         if (mbox->intr_mode) {
280                 /* Unmask all interrupt masks */
281                 writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG);
282                 free_irq(mbox->irq, chan);
283         } else if (!mbox->is_sender) {
284                 del_timer_sync(&mbox->rxpoll_timer);
285         }
286 }
287
288 static const struct mbox_chan_ops altera_mbox_ops = {
289         .send_data = altera_mbox_send_data,
290         .startup = altera_mbox_startup,
291         .shutdown = altera_mbox_shutdown,
292         .last_tx_done = altera_mbox_last_tx_done,
293         .peek_data = altera_mbox_peek_data,
294 };
295
296 static int altera_mbox_probe(struct platform_device *pdev)
297 {
298         struct altera_mbox *mbox;
299         struct resource *regs;
300         struct mbox_chan *chans;
301         int ret;
302
303         mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox),
304                             GFP_KERNEL);
305         if (!mbox)
306                 return -ENOMEM;
307
308         /* Allocated one channel */
309         chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
310         if (!chans)
311                 return -ENOMEM;
312
313         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
314
315         mbox->mbox_base = devm_ioremap_resource(&pdev->dev, regs);
316         if (IS_ERR(mbox->mbox_base))
317                 return PTR_ERR(mbox->mbox_base);
318
319         /* Check is it a sender or receiver? */
320         mbox->is_sender = altera_mbox_is_sender(mbox);
321
322         mbox->irq = platform_get_irq(pdev, 0);
323         if (mbox->irq >= 0)
324                 mbox->intr_mode = true;
325
326         mbox->dev = &pdev->dev;
327
328         /* Hardware supports only one channel. */
329         chans[0].con_priv = mbox;
330         mbox->controller.dev = mbox->dev;
331         mbox->controller.num_chans = 1;
332         mbox->controller.chans = chans;
333         mbox->controller.ops = &altera_mbox_ops;
334
335         if (mbox->is_sender) {
336                 if (mbox->intr_mode) {
337                         mbox->controller.txdone_irq = true;
338                 } else {
339                         mbox->controller.txdone_poll = true;
340                         mbox->controller.txpoll_period = MBOX_POLLING_MS;
341                 }
342         }
343
344         ret = mbox_controller_register(&mbox->controller);
345         if (ret) {
346                 dev_err(&pdev->dev, "Register mailbox failed\n");
347                 goto err;
348         }
349
350         platform_set_drvdata(pdev, mbox);
351 err:
352         return ret;
353 }
354
355 static int altera_mbox_remove(struct platform_device *pdev)
356 {
357         struct altera_mbox *mbox = platform_get_drvdata(pdev);
358
359         if (!mbox)
360                 return -EINVAL;
361
362         mbox_controller_unregister(&mbox->controller);
363
364         return 0;
365 }
366
367 static const struct of_device_id altera_mbox_match[] = {
368         { .compatible = "altr,mailbox-1.0" },
369         { /* Sentinel */ }
370 };
371
372 MODULE_DEVICE_TABLE(of, altera_mbox_match);
373
374 static struct platform_driver altera_mbox_driver = {
375         .probe  = altera_mbox_probe,
376         .remove = altera_mbox_remove,
377         .driver = {
378                 .name   = DRIVER_NAME,
379                 .of_match_table = altera_mbox_match,
380         },
381 };
382
383 module_platform_driver(altera_mbox_driver);
384
385 MODULE_LICENSE("GPL v2");
386 MODULE_DESCRIPTION("Altera mailbox specific functions");
387 MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
388 MODULE_ALIAS("platform:altera-mailbox");