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 | */ |
56 | struct 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 | */ |
72 | struct 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 | |
80 | static struct hi3660_mbox *to_hi3660_mbox(struct mbox_controller *mbox) |
81 | { |
82 | return container_of(mbox, struct hi3660_mbox, controller); |
83 | } |
84 | |
85 | static 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(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(addr: 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), addr: base + MBOX_ICLR_REG); |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static int hi3660_mbox_unlock(struct mbox_chan *chan) |
113 | { |
114 | struct hi3660_mbox *mbox = to_hi3660_mbox(mbox: chan->mbox); |
115 | unsigned int val, retry = 3; |
116 | |
117 | do { |
118 | writel(MBOX_IPC_UNLOCK, addr: mbox->base + MBOX_IPC_LOCK_REG); |
119 | |
120 | val = readl(addr: 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 | |
133 | static 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(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(addr: base + MBOX_MODE_REG) & MBOX_STATE_IDLE) { |
144 | writel(BIT(mchan->ack_irq), addr: base + MBOX_SRC_REG); |
145 | |
146 | /* Check ack bit has been set successfully */ |
147 | val = readl(addr: 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 | |
159 | static 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 | |
174 | static 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(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), addr: base + MBOX_SEND_REG); |
203 | return 0; |
204 | } |
205 | |
206 | static const struct mbox_chan_ops hi3660_mbox_ops = { |
207 | .startup = hi3660_mbox_startup, |
208 | .send_data = hi3660_mbox_send_data, |
209 | }; |
210 | |
211 | static 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(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(error: -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 | |
230 | static const struct of_device_id hi3660_mbox_of_match[] = { |
231 | { .compatible = "hisilicon,hi3660-mbox" , }, |
232 | {}, |
233 | }; |
234 | |
235 | MODULE_DEVICE_TABLE(of, hi3660_mbox_of_match); |
236 | |
237 | static 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, size: sizeof(*mbox), GFP_KERNEL); |
246 | if (!mbox) |
247 | return -ENOMEM; |
248 | |
249 | mbox->base = devm_platform_ioremap_resource(pdev, index: 0); |
250 | if (IS_ERR(ptr: mbox->base)) |
251 | return PTR_ERR(ptr: 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: &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, data: mbox); |
272 | dev_info(dev, "Mailbox enabled\n" ); |
273 | return 0; |
274 | } |
275 | |
276 | static 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 | |
284 | static int __init hi3660_mbox_init(void) |
285 | { |
286 | return platform_driver_register(&hi3660_mbox_driver); |
287 | } |
288 | core_initcall(hi3660_mbox_init); |
289 | |
290 | static void __exit hi3660_mbox_exit(void) |
291 | { |
292 | platform_driver_unregister(&hi3660_mbox_driver); |
293 | } |
294 | module_exit(hi3660_mbox_exit); |
295 | |
296 | MODULE_LICENSE("GPL" ); |
297 | MODULE_DESCRIPTION("Hisilicon Hi3660 Mailbox Controller" ); |
298 | MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>" ); |
299 | |