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 }; 61 62 static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan) 63 { 64 if (!chan || !chan->con_priv) 65 return NULL; 66 67 return (struct altera_mbox *)chan->con_priv; 68 } 69 70 static inline int altera_mbox_full(struct altera_mbox *mbox) 71 { 72 u32 status; 73 74 status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); 75 return MBOX_FULL(status); 76 } 77 78 static inline int altera_mbox_pending(struct altera_mbox *mbox) 79 { 80 u32 status; 81 82 status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); 83 return MBOX_PENDING(status); 84 } 85 86 static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable) 87 { 88 u32 mask; 89 90 mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); 91 if (enable) 92 mask |= INT_PENDING_MSK; 93 else 94 mask &= ~INT_PENDING_MSK; 95 writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); 96 } 97 98 static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable) 99 { 100 u32 mask; 101 102 mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); 103 if (enable) 104 mask |= INT_SPACE_MSK; 105 else 106 mask &= ~INT_SPACE_MSK; 107 writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); 108 } 109 110 static bool altera_mbox_is_sender(struct altera_mbox *mbox) 111 { 112 u32 reg; 113 /* Write a magic number to PTR register and read back this register. 114 * This register is read-write if it is a sender. 115 */ 116 #define MBOX_MAGIC 0xA5A5AA55 117 writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG); 118 reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); 119 if (reg == MBOX_MAGIC) { 120 /* Clear to 0 */ 121 writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG); 122 return true; 123 } 124 return false; 125 } 126 127 static void altera_mbox_rx_data(struct mbox_chan *chan) 128 { 129 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 130 u32 data[2]; 131 132 if (altera_mbox_pending(mbox)) { 133 data[MBOX_PTR] = 134 readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); 135 data[MBOX_CMD] = 136 readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG); 137 mbox_chan_received_data(chan, (void *)data); 138 } 139 } 140 141 static void altera_mbox_poll_rx(unsigned long data) 142 { 143 struct mbox_chan *chan = (struct mbox_chan *)data; 144 struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 145 146 altera_mbox_rx_data(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 setup_timer(&mbox->rxpoll_timer, altera_mbox_poll_rx, 210 (unsigned long)chan); 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"); 389