1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2017-2018 HiSilicon Limited. 3// Copyright (c) 2017-2018 Linaro Limited. 4 5#include <linux/bitops.h> 6#include <linux/delay.h> 7#include <linux/device.h> 8#include <linux/err.h> 9#include <linux/interrupt.h> 10#include <linux/io.h> 11#include <linux/iopoll.h> 12#include <linux/mailbox_controller.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/platform_device.h> 16#include <linux/slab.h> 17 18#include "mailbox.h" 19 20#define MBOX_CHAN_MAX 32 21 22#define MBOX_RX 0x0 23#define MBOX_TX 0x1 24 25#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x40)) 26#define MBOX_SRC_REG 0x00 27#define MBOX_DST_REG 0x04 28#define MBOX_DCLR_REG 0x08 29#define MBOX_DSTAT_REG 0x0c 30#define MBOX_MODE_REG 0x10 31#define MBOX_IMASK_REG 0x14 32#define MBOX_ICLR_REG 0x18 33#define MBOX_SEND_REG 0x1c 34#define MBOX_DATA_REG 0x20 35 36#define MBOX_IPC_LOCK_REG 0xa00 37#define MBOX_IPC_UNLOCK 0x1acce551 38 39#define MBOX_AUTOMATIC_ACK 1 40 41#define MBOX_STATE_IDLE BIT(4) 42#define MBOX_STATE_READY BIT(5) 43#define MBOX_STATE_ACK BIT(7) 44 45#define MBOX_MSG_LEN 8 46 47/** 48 * struct hi3660_chan_info - Hi3660 mailbox channel information 49 * @dst_irq: Interrupt vector for remote processor 50 * @ack_irq: Interrupt vector for local processor 51 * 52 * A channel can be used for TX or RX, it can trigger remote 53 * processor interrupt to notify remote processor and can receive 54 * interrupt if it has an incoming message. 55 */ 56struct hi3660_chan_info { 57 unsigned int dst_irq; 58 unsigned int ack_irq; 59}; 60 61/** 62 * struct hi3660_mbox - Hi3660 mailbox controller data 63 * @dev: Device to which it is attached 64 * @base: Base address of the register mapping region 65 * @chan: Representation of channels in mailbox controller 66 * @mchan: Representation of channel info 67 * @controller: Representation of a communication channel controller 68 * 69 * Mailbox controller includes 32 channels and can allocate 70 * channel for message transferring. 71 */ 72struct hi3660_mbox { 73 struct device *dev; 74 void __iomem *base; 75 struct mbox_chan chan[MBOX_CHAN_MAX]; 76 struct hi3660_chan_info mchan[MBOX_CHAN_MAX]; 77 struct mbox_controller controller; 78}; 79 80static struct hi3660_mbox *to_hi3660_mbox(struct mbox_controller *mbox) 81{ 82 return container_of(mbox, struct hi3660_mbox, controller); 83} 84 85static int hi3660_mbox_check_state(struct mbox_chan *chan) 86{ 87 unsigned long ch = (unsigned long)chan->con_priv; 88 struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); 89 struct hi3660_chan_info *mchan = &mbox->mchan[ch]; 90 void __iomem *base = MBOX_BASE(mbox, ch); 91 unsigned long val; 92 unsigned int ret; 93 94 /* Mailbox is ready to use */ 95 if (readl(base + MBOX_MODE_REG) & MBOX_STATE_READY) 96 return 0; 97 98 /* Wait for acknowledge from remote */ 99 ret = readx_poll_timeout_atomic(readl, base + MBOX_MODE_REG, 100 val, (val & MBOX_STATE_ACK), 1000, 300000); 101 if (ret) { 102 dev_err(mbox->dev, "%s: timeout for receiving ack\n", __func__); 103 return ret; 104 } 105 106 /* clear ack state, mailbox will get back to ready state */ 107 writel(BIT(mchan->ack_irq), base + MBOX_ICLR_REG); 108 109 return 0; 110} 111 112static int hi3660_mbox_unlock(struct mbox_chan *chan) 113{ 114 struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); 115 unsigned int val, retry = 3; 116 117 do { 118 writel(MBOX_IPC_UNLOCK, mbox->base + MBOX_IPC_LOCK_REG); 119 120 val = readl(mbox->base + MBOX_IPC_LOCK_REG); 121 if (!val) 122 break; 123 124 udelay(10); 125 } while (retry--); 126 127 if (val) 128 dev_err(mbox->dev, "%s: failed to unlock mailbox\n", __func__); 129 130 return (!val) ? 0 : -ETIMEDOUT; 131} 132 133static int hi3660_mbox_acquire_channel(struct mbox_chan *chan) 134{ 135 unsigned long ch = (unsigned long)chan->con_priv; 136 struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); 137 struct hi3660_chan_info *mchan = &mbox->mchan[ch]; 138 void __iomem *base = MBOX_BASE(mbox, ch); 139 unsigned int val, retry; 140 141 for (retry = 10; retry; retry--) { 142 /* Check if channel is in idle state */ 143 if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE) { 144 writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG); 145 146 /* Check ack bit has been set successfully */ 147 val = readl(base + MBOX_SRC_REG); 148 if (val & BIT(mchan->ack_irq)) 149 break; 150 } 151 } 152 153 if (!retry) 154 dev_err(mbox->dev, "%s: failed to acquire channel\n", __func__); 155 156 return retry ? 0 : -ETIMEDOUT; 157} 158 159static int hi3660_mbox_startup(struct mbox_chan *chan) 160{ 161 int ret; 162 163 ret = hi3660_mbox_unlock(chan); 164 if (ret) 165 return ret; 166 167 ret = hi3660_mbox_acquire_channel(chan); 168 if (ret) 169 return ret; 170 171 return 0; 172} 173 174static int hi3660_mbox_send_data(struct mbox_chan *chan, void *msg) 175{ 176 unsigned long ch = (unsigned long)chan->con_priv; 177 struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); 178 struct hi3660_chan_info *mchan = &mbox->mchan[ch]; 179 void __iomem *base = MBOX_BASE(mbox, ch); 180 u32 *buf = msg; 181 unsigned int i; 182 int ret; 183 184 ret = hi3660_mbox_check_state(chan); 185 if (ret) 186 return ret; 187 188 /* Clear mask for destination interrupt */ 189 writel_relaxed(~BIT(mchan->dst_irq), base + MBOX_IMASK_REG); 190 191 /* Config destination for interrupt vector */ 192 writel_relaxed(BIT(mchan->dst_irq), base + MBOX_DST_REG); 193 194 /* Automatic acknowledge mode */ 195 writel_relaxed(MBOX_AUTOMATIC_ACK, base + MBOX_MODE_REG); 196 197 /* Fill message data */ 198 for (i = 0; i < MBOX_MSG_LEN; i++) 199 writel_relaxed(buf[i], base + MBOX_DATA_REG + i * 4); 200 201 /* Trigger data transferring */ 202 writel(BIT(mchan->ack_irq), base + MBOX_SEND_REG); 203 return 0; 204} 205 206static const struct mbox_chan_ops hi3660_mbox_ops = { 207 .startup = hi3660_mbox_startup, 208 .send_data = hi3660_mbox_send_data, 209}; 210 211static struct mbox_chan *hi3660_mbox_xlate(struct mbox_controller *controller, 212 const struct of_phandle_args *spec) 213{ 214 struct hi3660_mbox *mbox = to_hi3660_mbox(controller); 215 struct hi3660_chan_info *mchan; 216 unsigned int ch = spec->args[0]; 217 218 if (ch >= MBOX_CHAN_MAX) { 219 dev_err(mbox->dev, "Invalid channel idx %d\n", ch); 220 return ERR_PTR(-EINVAL); 221 } 222 223 mchan = &mbox->mchan[ch]; 224 mchan->dst_irq = spec->args[1]; 225 mchan->ack_irq = spec->args[2]; 226 227 return &mbox->chan[ch]; 228} 229 230static const struct of_device_id hi3660_mbox_of_match[] = { 231 { .compatible = "hisilicon,hi3660-mbox", }, 232 {}, 233}; 234 235MODULE_DEVICE_TABLE(of, hi3660_mbox_of_match); 236 237static int hi3660_mbox_probe(struct platform_device *pdev) 238{ 239 struct device *dev = &pdev->dev; 240 struct hi3660_mbox *mbox; 241 struct mbox_chan *chan; 242 unsigned long ch; 243 int err; 244 245 mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 246 if (!mbox) 247 return -ENOMEM; 248 249 mbox->base = devm_platform_ioremap_resource(pdev, 0); 250 if (IS_ERR(mbox->base)) 251 return PTR_ERR(mbox->base); 252 253 mbox->dev = dev; 254 mbox->controller.dev = dev; 255 mbox->controller.chans = mbox->chan; 256 mbox->controller.num_chans = MBOX_CHAN_MAX; 257 mbox->controller.ops = &hi3660_mbox_ops; 258 mbox->controller.of_xlate = hi3660_mbox_xlate; 259 260 /* Initialize mailbox channel data */ 261 chan = mbox->chan; 262 for (ch = 0; ch < MBOX_CHAN_MAX; ch++) 263 chan[ch].con_priv = (void *)ch; 264 265 err = devm_mbox_controller_register(dev, &mbox->controller); 266 if (err) { 267 dev_err(dev, "Failed to register mailbox %d\n", err); 268 return err; 269 } 270 271 platform_set_drvdata(pdev, mbox); 272 dev_info(dev, "Mailbox enabled\n"); 273 return 0; 274} 275 276static struct platform_driver hi3660_mbox_driver = { 277 .probe = hi3660_mbox_probe, 278 .driver = { 279 .name = "hi3660-mbox", 280 .of_match_table = hi3660_mbox_of_match, 281 }, 282}; 283 284static int __init hi3660_mbox_init(void) 285{ 286 return platform_driver_register(&hi3660_mbox_driver); 287} 288core_initcall(hi3660_mbox_init); 289 290static void __exit hi3660_mbox_exit(void) 291{ 292 platform_driver_unregister(&hi3660_mbox_driver); 293} 294module_exit(hi3660_mbox_exit); 295 296MODULE_LICENSE("GPL"); 297MODULE_DESCRIPTION("Hisilicon Hi3660 Mailbox Controller"); 298MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); 299