1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2016-2017, Linaro Ltd
7 #include <linux/interrupt.h>
9 #include <linux/list.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/rpmsg.h>
18 #include <linux/slab.h>
19 #include <linux/workqueue.h>
20 #include <linux/mailbox_client.h>
22 #include "rpmsg_internal.h"
23 #include "qcom_glink_native.h"
25 #define RPM_TOC_SIZE 256
26 #define RPM_TOC_MAGIC 0x67727430 /* grt0 */
27 #define RPM_TOC_MAX_ENTRIES ((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \
28 sizeof(struct rpm_toc_entry))
30 #define RPM_TX_FIFO_ID 0x61703272 /* ap2r */
31 #define RPM_RX_FIFO_ID 0x72326170 /* r2ap */
33 #define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
35 struct rpm_toc_entry
{
45 struct rpm_toc_entry entries
[];
48 struct glink_rpm_pipe
{
49 struct qcom_glink_pipe native
;
58 struct qcom_glink
*glink
;
62 struct mbox_client mbox_client
;
63 struct mbox_chan
*mbox_chan
;
65 struct glink_rpm_pipe rx_pipe
;
66 struct glink_rpm_pipe tx_pipe
;
69 static size_t glink_rpm_rx_avail(struct qcom_glink_pipe
*glink_pipe
)
71 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
75 head
= readl(pipe
->head
);
76 tail
= readl(pipe
->tail
);
79 return pipe
->native
.length
- tail
+ head
;
84 static void glink_rpm_rx_peek(struct qcom_glink_pipe
*glink_pipe
,
85 void *data
, unsigned int offset
, size_t count
)
87 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
91 tail
= readl(pipe
->tail
);
93 if (tail
>= pipe
->native
.length
)
94 tail
-= pipe
->native
.length
;
96 len
= min_t(size_t, count
, pipe
->native
.length
- tail
);
98 __ioread32_copy(data
, pipe
->fifo
+ tail
,
103 __ioread32_copy(data
+ len
, pipe
->fifo
,
104 (count
- len
) / sizeof(u32
));
108 static void glink_rpm_rx_advance(struct qcom_glink_pipe
*glink_pipe
,
111 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
114 tail
= readl(pipe
->tail
);
117 if (tail
>= pipe
->native
.length
)
118 tail
-= pipe
->native
.length
;
120 writel(tail
, pipe
->tail
);
123 static size_t glink_rpm_tx_avail(struct qcom_glink_pipe
*glink_pipe
)
125 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
129 head
= readl(pipe
->head
);
130 tail
= readl(pipe
->tail
);
133 return pipe
->native
.length
- head
+ tail
;
138 static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe
*pipe
,
140 const void *data
, size_t count
)
144 len
= min_t(size_t, count
, pipe
->native
.length
- head
);
146 __iowrite32_copy(pipe
->fifo
+ head
, data
,
151 __iowrite32_copy(pipe
->fifo
, data
+ len
,
152 (count
- len
) / sizeof(u32
));
156 if (head
>= pipe
->native
.length
)
157 head
-= pipe
->native
.length
;
162 static void glink_rpm_tx_write(struct qcom_glink_pipe
*glink_pipe
,
163 const void *hdr
, size_t hlen
,
164 const void *data
, size_t dlen
)
166 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
167 size_t tlen
= hlen
+ dlen
;
170 char padding
[8] = {0};
173 /* Header length comes from glink native and is always 4 byte aligned */
174 if (WARN(hlen
% 4, "Glink Header length must be 4 bytes aligned\n"))
178 * Move the unaligned tail of the message to the padding chunk, to
179 * ensure word aligned accesses
181 aligned_dlen
= ALIGN_DOWN(dlen
, 4);
182 if (aligned_dlen
!= dlen
)
183 memcpy(padding
, data
+ aligned_dlen
, dlen
- aligned_dlen
);
185 head
= readl(pipe
->head
);
186 head
= glink_rpm_tx_write_one(pipe
, head
, hdr
, hlen
);
187 head
= glink_rpm_tx_write_one(pipe
, head
, data
, aligned_dlen
);
189 pad
= ALIGN(tlen
, 8) - ALIGN_DOWN(tlen
, 4);
191 head
= glink_rpm_tx_write_one(pipe
, head
, padding
, pad
);
192 writel(head
, pipe
->head
);
195 static void glink_rpm_tx_kick(struct qcom_glink_pipe
*glink_pipe
)
197 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
198 struct glink_rpm
*rpm
= container_of(pipe
, struct glink_rpm
, tx_pipe
);
200 mbox_send_message(rpm
->mbox_chan
, NULL
);
201 mbox_client_txdone(rpm
->mbox_chan
, 0);
204 static irqreturn_t
qcom_glink_rpm_intr(int irq
, void *data
)
206 struct glink_rpm
*rpm
= data
;
208 qcom_glink_native_rx(rpm
->glink
);
213 static int glink_rpm_parse_toc(struct device
*dev
,
214 void __iomem
*msg_ram
,
216 struct glink_rpm_pipe
*rx
,
217 struct glink_rpm_pipe
*tx
)
227 buf
= kzalloc(RPM_TOC_SIZE
, GFP_KERNEL
);
231 __ioread32_copy(buf
, msg_ram
+ msg_ram_size
- RPM_TOC_SIZE
,
232 RPM_TOC_SIZE
/ sizeof(u32
));
236 if (le32_to_cpu(toc
->magic
) != RPM_TOC_MAGIC
) {
237 dev_err(dev
, "RPM TOC has invalid magic\n");
241 num_entries
= le32_to_cpu(toc
->count
);
242 if (num_entries
> RPM_TOC_MAX_ENTRIES
) {
243 dev_err(dev
, "Invalid number of toc entries\n");
247 for (i
= 0; i
< num_entries
; i
++) {
248 id
= le32_to_cpu(toc
->entries
[i
].id
);
249 offset
= le32_to_cpu(toc
->entries
[i
].offset
);
250 size
= le32_to_cpu(toc
->entries
[i
].size
);
252 if (offset
> msg_ram_size
|| offset
+ size
> msg_ram_size
) {
253 dev_err(dev
, "TOC entry with invalid size\n");
259 rx
->native
.length
= size
;
261 rx
->tail
= msg_ram
+ offset
;
262 rx
->head
= msg_ram
+ offset
+ sizeof(u32
);
263 rx
->fifo
= msg_ram
+ offset
+ 2 * sizeof(u32
);
266 tx
->native
.length
= size
;
268 tx
->tail
= msg_ram
+ offset
;
269 tx
->head
= msg_ram
+ offset
+ sizeof(u32
);
270 tx
->fifo
= msg_ram
+ offset
+ 2 * sizeof(u32
);
275 if (!rx
->fifo
|| !tx
->fifo
) {
276 dev_err(dev
, "Unable to find rx and tx descriptors\n");
288 static int glink_rpm_probe(struct platform_device
*pdev
)
290 struct qcom_glink
*glink
;
291 struct glink_rpm
*rpm
;
292 struct device_node
*np
;
293 void __iomem
*msg_ram
;
295 struct device
*dev
= &pdev
->dev
;
299 rpm
= devm_kzalloc(&pdev
->dev
, sizeof(*rpm
), GFP_KERNEL
);
303 np
= of_parse_phandle(dev
->of_node
, "qcom,rpm-msg-ram", 0);
304 ret
= of_address_to_resource(np
, 0, &r
);
309 msg_ram
= devm_ioremap(dev
, r
.start
, resource_size(&r
));
310 msg_ram_size
= resource_size(&r
);
314 ret
= glink_rpm_parse_toc(dev
, msg_ram
, msg_ram_size
,
315 &rpm
->rx_pipe
, &rpm
->tx_pipe
);
319 rpm
->irq
= of_irq_get(dev
->of_node
, 0);
320 ret
= devm_request_irq(dev
, rpm
->irq
, qcom_glink_rpm_intr
,
321 IRQF_NO_SUSPEND
| IRQF_NO_AUTOEN
,
324 dev_err(dev
, "failed to request IRQ\n");
328 rpm
->mbox_client
.dev
= dev
;
329 rpm
->mbox_client
.knows_txdone
= true;
330 rpm
->mbox_chan
= mbox_request_channel(&rpm
->mbox_client
, 0);
331 if (IS_ERR(rpm
->mbox_chan
))
332 return dev_err_probe(dev
, PTR_ERR(rpm
->mbox_chan
), "failed to acquire IPC channel\n");
334 /* Pipe specific accessors */
335 rpm
->rx_pipe
.native
.avail
= glink_rpm_rx_avail
;
336 rpm
->rx_pipe
.native
.peek
= glink_rpm_rx_peek
;
337 rpm
->rx_pipe
.native
.advance
= glink_rpm_rx_advance
;
338 rpm
->tx_pipe
.native
.avail
= glink_rpm_tx_avail
;
339 rpm
->tx_pipe
.native
.write
= glink_rpm_tx_write
;
340 rpm
->tx_pipe
.native
.kick
= glink_rpm_tx_kick
;
342 writel(0, rpm
->tx_pipe
.head
);
343 writel(0, rpm
->rx_pipe
.tail
);
345 glink
= qcom_glink_native_probe(dev
,
347 &rpm
->rx_pipe
.native
,
348 &rpm
->tx_pipe
.native
,
351 mbox_free_channel(rpm
->mbox_chan
);
352 return PTR_ERR(glink
);
357 platform_set_drvdata(pdev
, rpm
);
359 enable_irq(rpm
->irq
);
364 static void glink_rpm_remove(struct platform_device
*pdev
)
366 struct glink_rpm
*rpm
= platform_get_drvdata(pdev
);
367 struct qcom_glink
*glink
= rpm
->glink
;
369 disable_irq(rpm
->irq
);
371 qcom_glink_native_remove(glink
);
373 mbox_free_channel(rpm
->mbox_chan
);
376 static const struct of_device_id glink_rpm_of_match
[] = {
377 { .compatible
= "qcom,glink-rpm" },
380 MODULE_DEVICE_TABLE(of
, glink_rpm_of_match
);
382 static struct platform_driver glink_rpm_driver
= {
383 .probe
= glink_rpm_probe
,
384 .remove_new
= glink_rpm_remove
,
386 .name
= "qcom_glink_rpm",
387 .of_match_table
= glink_rpm_of_match
,
391 static int __init
glink_rpm_init(void)
393 return platform_driver_register(&glink_rpm_driver
);
395 subsys_initcall(glink_rpm_init
);
397 static void __exit
glink_rpm_exit(void)
399 platform_driver_unregister(&glink_rpm_driver
);
401 module_exit(glink_rpm_exit
);
403 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
404 MODULE_DESCRIPTION("Qualcomm GLINK RPM driver");
405 MODULE_LICENSE("GPL v2");