372 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Hisilicon's Hi6220 mailbox driver4 *5 * Copyright (c) 2015 HiSilicon Limited.6 * Copyright (c) 2015 Linaro Limited.7 *8 * Author: Leo Yan <leo.yan@linaro.org>9 */10 11#include <linux/device.h>12#include <linux/err.h>13#include <linux/interrupt.h>14#include <linux/io.h>15#include <linux/kfifo.h>16#include <linux/mailbox_controller.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/slab.h>21 22#define MBOX_CHAN_MAX 3223 24#define MBOX_TX 0x125 26/* Mailbox message length: 8 words */27#define MBOX_MSG_LEN 828 29/* Mailbox Registers */30#define MBOX_OFF(m) (0x40 * (m))31#define MBOX_MODE_REG(m) (MBOX_OFF(m) + 0x0)32#define MBOX_DATA_REG(m) (MBOX_OFF(m) + 0x4)33 34#define MBOX_STATE_MASK (0xF << 4)35#define MBOX_STATE_IDLE (0x1 << 4)36#define MBOX_STATE_TX (0x2 << 4)37#define MBOX_STATE_RX (0x4 << 4)38#define MBOX_STATE_ACK (0x8 << 4)39#define MBOX_ACK_CONFIG_MASK (0x1 << 0)40#define MBOX_ACK_AUTOMATIC (0x1 << 0)41#define MBOX_ACK_IRQ (0x0 << 0)42 43/* IPC registers */44#define ACK_INT_RAW_REG(i) ((i) + 0x400)45#define ACK_INT_MSK_REG(i) ((i) + 0x404)46#define ACK_INT_STAT_REG(i) ((i) + 0x408)47#define ACK_INT_CLR_REG(i) ((i) + 0x40c)48#define ACK_INT_ENA_REG(i) ((i) + 0x500)49#define ACK_INT_DIS_REG(i) ((i) + 0x504)50#define DST_INT_RAW_REG(i) ((i) + 0x420)51 52 53struct hi6220_mbox_chan {54 55 /*56 * Description for channel's hardware info:57 * - direction: tx or rx58 * - dst irq: peer core's irq number59 * - ack irq: local irq number60 * - slot number61 */62 unsigned int dir, dst_irq, ack_irq;63 unsigned int slot;64 65 struct hi6220_mbox *parent;66};67 68struct hi6220_mbox {69 struct device *dev;70 71 int irq;72 73 /* flag of enabling tx's irq mode */74 bool tx_irq_mode;75 76 /* region for ipc event */77 void __iomem *ipc;78 79 /* region for mailbox */80 void __iomem *base;81 82 unsigned int chan_num;83 struct hi6220_mbox_chan *mchan;84 85 void *irq_map_chan[MBOX_CHAN_MAX];86 struct mbox_chan *chan;87 struct mbox_controller controller;88};89 90static void mbox_set_state(struct hi6220_mbox *mbox,91 unsigned int slot, u32 val)92{93 u32 status;94 95 status = readl(mbox->base + MBOX_MODE_REG(slot));96 status = (status & ~MBOX_STATE_MASK) | val;97 writel(status, mbox->base + MBOX_MODE_REG(slot));98}99 100static void mbox_set_mode(struct hi6220_mbox *mbox,101 unsigned int slot, u32 val)102{103 u32 mode;104 105 mode = readl(mbox->base + MBOX_MODE_REG(slot));106 mode = (mode & ~MBOX_ACK_CONFIG_MASK) | val;107 writel(mode, mbox->base + MBOX_MODE_REG(slot));108}109 110static bool hi6220_mbox_last_tx_done(struct mbox_chan *chan)111{112 struct hi6220_mbox_chan *mchan = chan->con_priv;113 struct hi6220_mbox *mbox = mchan->parent;114 u32 state;115 116 /* Only set idle state for polling mode */117 BUG_ON(mbox->tx_irq_mode);118 119 state = readl(mbox->base + MBOX_MODE_REG(mchan->slot));120 return ((state & MBOX_STATE_MASK) == MBOX_STATE_IDLE);121}122 123static int hi6220_mbox_send_data(struct mbox_chan *chan, void *msg)124{125 struct hi6220_mbox_chan *mchan = chan->con_priv;126 struct hi6220_mbox *mbox = mchan->parent;127 unsigned int slot = mchan->slot;128 u32 *buf = msg;129 int i;130 131 /* indicate as a TX channel */132 mchan->dir = MBOX_TX;133 134 mbox_set_state(mbox, slot, MBOX_STATE_TX);135 136 if (mbox->tx_irq_mode)137 mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);138 else139 mbox_set_mode(mbox, slot, MBOX_ACK_AUTOMATIC);140 141 for (i = 0; i < MBOX_MSG_LEN; i++)142 writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);143 144 /* trigger remote request */145 writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));146 return 0;147}148 149static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)150{151 struct hi6220_mbox *mbox = p;152 struct hi6220_mbox_chan *mchan;153 struct mbox_chan *chan;154 unsigned int state, intr_bit, i;155 u32 msg[MBOX_MSG_LEN];156 157 state = readl(ACK_INT_STAT_REG(mbox->ipc));158 if (!state) {159 dev_warn(mbox->dev, "%s: spurious interrupt\n",160 __func__);161 return IRQ_HANDLED;162 }163 164 while (state) {165 intr_bit = __ffs(state);166 state &= (state - 1);167 168 chan = mbox->irq_map_chan[intr_bit];169 if (!chan) {170 dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",171 __func__, intr_bit);172 continue;173 }174 175 mchan = chan->con_priv;176 if (mchan->dir == MBOX_TX)177 mbox_chan_txdone(chan, 0);178 else {179 for (i = 0; i < MBOX_MSG_LEN; i++)180 msg[i] = readl(mbox->base +181 MBOX_DATA_REG(mchan->slot) + i * 4);182 183 mbox_chan_received_data(chan, (void *)msg);184 }185 186 /* clear IRQ source */187 writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));188 mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);189 }190 191 return IRQ_HANDLED;192}193 194static int hi6220_mbox_startup(struct mbox_chan *chan)195{196 struct hi6220_mbox_chan *mchan = chan->con_priv;197 struct hi6220_mbox *mbox = mchan->parent;198 199 mchan->dir = 0;200 201 /* enable interrupt */202 writel(BIT(mchan->ack_irq), ACK_INT_ENA_REG(mbox->ipc));203 return 0;204}205 206static void hi6220_mbox_shutdown(struct mbox_chan *chan)207{208 struct hi6220_mbox_chan *mchan = chan->con_priv;209 struct hi6220_mbox *mbox = mchan->parent;210 211 /* disable interrupt */212 writel(BIT(mchan->ack_irq), ACK_INT_DIS_REG(mbox->ipc));213 mbox->irq_map_chan[mchan->ack_irq] = NULL;214}215 216static const struct mbox_chan_ops hi6220_mbox_ops = {217 .send_data = hi6220_mbox_send_data,218 .startup = hi6220_mbox_startup,219 .shutdown = hi6220_mbox_shutdown,220 .last_tx_done = hi6220_mbox_last_tx_done,221};222 223static struct mbox_chan *hi6220_mbox_xlate(struct mbox_controller *controller,224 const struct of_phandle_args *spec)225{226 struct hi6220_mbox *mbox = dev_get_drvdata(controller->dev);227 struct hi6220_mbox_chan *mchan;228 struct mbox_chan *chan;229 unsigned int i = spec->args[0];230 unsigned int dst_irq = spec->args[1];231 unsigned int ack_irq = spec->args[2];232 233 /* Bounds checking */234 if (i >= mbox->chan_num || dst_irq >= mbox->chan_num ||235 ack_irq >= mbox->chan_num) {236 dev_err(mbox->dev,237 "Invalid channel idx %d dst_irq %d ack_irq %d\n",238 i, dst_irq, ack_irq);239 return ERR_PTR(-EINVAL);240 }241 242 /* Is requested channel free? */243 chan = &mbox->chan[i];244 if (mbox->irq_map_chan[ack_irq] == (void *)chan) {245 dev_err(mbox->dev, "Channel in use\n");246 return ERR_PTR(-EBUSY);247 }248 249 mchan = chan->con_priv;250 mchan->dst_irq = dst_irq;251 mchan->ack_irq = ack_irq;252 253 mbox->irq_map_chan[ack_irq] = (void *)chan;254 return chan;255}256 257static const struct of_device_id hi6220_mbox_of_match[] = {258 { .compatible = "hisilicon,hi6220-mbox", },259 {},260};261MODULE_DEVICE_TABLE(of, hi6220_mbox_of_match);262 263static int hi6220_mbox_probe(struct platform_device *pdev)264{265 struct device_node *node = pdev->dev.of_node;266 struct device *dev = &pdev->dev;267 struct hi6220_mbox *mbox;268 int i, err;269 270 mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);271 if (!mbox)272 return -ENOMEM;273 274 mbox->dev = dev;275 mbox->chan_num = MBOX_CHAN_MAX;276 mbox->mchan = devm_kcalloc(dev,277 mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL);278 if (!mbox->mchan)279 return -ENOMEM;280 281 mbox->chan = devm_kcalloc(dev,282 mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL);283 if (!mbox->chan)284 return -ENOMEM;285 286 mbox->irq = platform_get_irq(pdev, 0);287 if (mbox->irq < 0)288 return mbox->irq;289 290 mbox->ipc = devm_platform_ioremap_resource(pdev, 0);291 if (IS_ERR(mbox->ipc)) {292 dev_err(dev, "ioremap ipc failed\n");293 return PTR_ERR(mbox->ipc);294 }295 296 mbox->base = devm_platform_ioremap_resource(pdev, 1);297 if (IS_ERR(mbox->base)) {298 dev_err(dev, "ioremap buffer failed\n");299 return PTR_ERR(mbox->base);300 }301 302 err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,303 dev_name(dev), mbox);304 if (err) {305 dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",306 err);307 return -ENODEV;308 }309 310 mbox->controller.dev = dev;311 mbox->controller.chans = &mbox->chan[0];312 mbox->controller.num_chans = mbox->chan_num;313 mbox->controller.ops = &hi6220_mbox_ops;314 mbox->controller.of_xlate = hi6220_mbox_xlate;315 316 for (i = 0; i < mbox->chan_num; i++) {317 mbox->chan[i].con_priv = &mbox->mchan[i];318 mbox->irq_map_chan[i] = NULL;319 320 mbox->mchan[i].parent = mbox;321 mbox->mchan[i].slot = i;322 }323 324 /* mask and clear all interrupt vectors */325 writel(0x0, ACK_INT_MSK_REG(mbox->ipc));326 writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));327 328 /* use interrupt for tx's ack */329 mbox->tx_irq_mode = !of_property_read_bool(node, "hi6220,mbox-tx-noirq");330 331 if (mbox->tx_irq_mode)332 mbox->controller.txdone_irq = true;333 else {334 mbox->controller.txdone_poll = true;335 mbox->controller.txpoll_period = 5;336 }337 338 err = devm_mbox_controller_register(dev, &mbox->controller);339 if (err) {340 dev_err(dev, "Failed to register mailbox %d\n", err);341 return err;342 }343 344 platform_set_drvdata(pdev, mbox);345 dev_info(dev, "Mailbox enabled\n");346 return 0;347}348 349static struct platform_driver hi6220_mbox_driver = {350 .driver = {351 .name = "hi6220-mbox",352 .of_match_table = hi6220_mbox_of_match,353 },354 .probe = hi6220_mbox_probe,355};356 357static int __init hi6220_mbox_init(void)358{359 return platform_driver_register(&hi6220_mbox_driver);360}361core_initcall(hi6220_mbox_init);362 363static void __exit hi6220_mbox_exit(void)364{365 platform_driver_unregister(&hi6220_mbox_driver);366}367module_exit(hi6220_mbox_exit);368 369MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");370MODULE_DESCRIPTION("Hi6220 mailbox driver");371MODULE_LICENSE("GPL v2");372