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