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/platform_device.h>
15 #include <linux/regmap.h>
16 #include <linux/rpmsg.h>
17 #include <linux/slab.h>
18 #include <linux/workqueue.h>
19 #include <linux/mailbox_client.h>
21 #include "rpmsg_internal.h"
22 #include "qcom_glink_native.h"
24 #define RPM_TOC_SIZE 256
25 #define RPM_TOC_MAGIC 0x67727430 /* grt0 */
26 #define RPM_TOC_MAX_ENTRIES ((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \
27 sizeof(struct rpm_toc_entry))
29 #define RPM_TX_FIFO_ID 0x61703272 /* ap2r */
30 #define RPM_RX_FIFO_ID 0x72326170 /* r2ap */
32 #define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
34 struct rpm_toc_entry
{
44 struct rpm_toc_entry entries
[];
47 struct glink_rpm_pipe
{
48 struct qcom_glink_pipe native
;
56 static size_t glink_rpm_rx_avail(struct qcom_glink_pipe
*glink_pipe
)
58 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
62 head
= readl(pipe
->head
);
63 tail
= readl(pipe
->tail
);
66 return pipe
->native
.length
- tail
+ head
;
71 static void glink_rpm_rx_peak(struct qcom_glink_pipe
*glink_pipe
,
72 void *data
, unsigned int offset
, size_t count
)
74 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
78 tail
= readl(pipe
->tail
);
80 if (tail
>= pipe
->native
.length
)
81 tail
-= pipe
->native
.length
;
83 len
= min_t(size_t, count
, pipe
->native
.length
- tail
);
85 __ioread32_copy(data
, pipe
->fifo
+ tail
,
90 __ioread32_copy(data
+ len
, pipe
->fifo
,
91 (count
- len
) / sizeof(u32
));
95 static void glink_rpm_rx_advance(struct qcom_glink_pipe
*glink_pipe
,
98 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
101 tail
= readl(pipe
->tail
);
104 if (tail
>= pipe
->native
.length
)
105 tail
-= pipe
->native
.length
;
107 writel(tail
, pipe
->tail
);
110 static size_t glink_rpm_tx_avail(struct qcom_glink_pipe
*glink_pipe
)
112 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
116 head
= readl(pipe
->head
);
117 tail
= readl(pipe
->tail
);
120 return pipe
->native
.length
- head
+ tail
;
125 static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe
*pipe
,
127 const void *data
, size_t count
)
131 len
= min_t(size_t, count
, pipe
->native
.length
- head
);
133 __iowrite32_copy(pipe
->fifo
+ head
, data
,
138 __iowrite32_copy(pipe
->fifo
, data
+ len
,
139 (count
- len
) / sizeof(u32
));
143 if (head
>= pipe
->native
.length
)
144 head
-= pipe
->native
.length
;
149 static void glink_rpm_tx_write(struct qcom_glink_pipe
*glink_pipe
,
150 const void *hdr
, size_t hlen
,
151 const void *data
, size_t dlen
)
153 struct glink_rpm_pipe
*pipe
= to_rpm_pipe(glink_pipe
);
154 size_t tlen
= hlen
+ dlen
;
157 char padding
[8] = {0};
160 /* Header length comes from glink native and is always 4 byte aligned */
161 if (WARN(hlen
% 4, "Glink Header length must be 4 bytes aligned\n"))
165 * Move the unaligned tail of the message to the padding chunk, to
166 * ensure word aligned accesses
168 aligned_dlen
= ALIGN_DOWN(dlen
, 4);
169 if (aligned_dlen
!= dlen
)
170 memcpy(padding
, data
+ aligned_dlen
, dlen
- aligned_dlen
);
172 head
= readl(pipe
->head
);
173 head
= glink_rpm_tx_write_one(pipe
, head
, hdr
, hlen
);
174 head
= glink_rpm_tx_write_one(pipe
, head
, data
, aligned_dlen
);
176 pad
= ALIGN(tlen
, 8) - ALIGN_DOWN(tlen
, 4);
178 head
= glink_rpm_tx_write_one(pipe
, head
, padding
, pad
);
179 writel(head
, pipe
->head
);
182 static int glink_rpm_parse_toc(struct device
*dev
,
183 void __iomem
*msg_ram
,
185 struct glink_rpm_pipe
*rx
,
186 struct glink_rpm_pipe
*tx
)
196 buf
= kzalloc(RPM_TOC_SIZE
, GFP_KERNEL
);
200 __ioread32_copy(buf
, msg_ram
+ msg_ram_size
- RPM_TOC_SIZE
,
201 RPM_TOC_SIZE
/ sizeof(u32
));
205 if (le32_to_cpu(toc
->magic
) != RPM_TOC_MAGIC
) {
206 dev_err(dev
, "RPM TOC has invalid magic\n");
210 num_entries
= le32_to_cpu(toc
->count
);
211 if (num_entries
> RPM_TOC_MAX_ENTRIES
) {
212 dev_err(dev
, "Invalid number of toc entries\n");
216 for (i
= 0; i
< num_entries
; i
++) {
217 id
= le32_to_cpu(toc
->entries
[i
].id
);
218 offset
= le32_to_cpu(toc
->entries
[i
].offset
);
219 size
= le32_to_cpu(toc
->entries
[i
].size
);
221 if (offset
> msg_ram_size
|| offset
+ size
> msg_ram_size
) {
222 dev_err(dev
, "TOC entry with invalid size\n");
228 rx
->native
.length
= size
;
230 rx
->tail
= msg_ram
+ offset
;
231 rx
->head
= msg_ram
+ offset
+ sizeof(u32
);
232 rx
->fifo
= msg_ram
+ offset
+ 2 * sizeof(u32
);
235 tx
->native
.length
= size
;
237 tx
->tail
= msg_ram
+ offset
;
238 tx
->head
= msg_ram
+ offset
+ sizeof(u32
);
239 tx
->fifo
= msg_ram
+ offset
+ 2 * sizeof(u32
);
244 if (!rx
->fifo
|| !tx
->fifo
) {
245 dev_err(dev
, "Unable to find rx and tx descriptors\n");
257 static int glink_rpm_probe(struct platform_device
*pdev
)
259 struct qcom_glink
*glink
;
260 struct glink_rpm_pipe
*rx_pipe
;
261 struct glink_rpm_pipe
*tx_pipe
;
262 struct device_node
*np
;
263 void __iomem
*msg_ram
;
265 struct device
*dev
= &pdev
->dev
;
269 rx_pipe
= devm_kzalloc(&pdev
->dev
, sizeof(*rx_pipe
), GFP_KERNEL
);
270 tx_pipe
= devm_kzalloc(&pdev
->dev
, sizeof(*tx_pipe
), GFP_KERNEL
);
271 if (!rx_pipe
|| !tx_pipe
)
274 np
= of_parse_phandle(dev
->of_node
, "qcom,rpm-msg-ram", 0);
275 ret
= of_address_to_resource(np
, 0, &r
);
280 msg_ram
= devm_ioremap(dev
, r
.start
, resource_size(&r
));
281 msg_ram_size
= resource_size(&r
);
285 ret
= glink_rpm_parse_toc(dev
, msg_ram
, msg_ram_size
,
290 /* Pipe specific accessors */
291 rx_pipe
->native
.avail
= glink_rpm_rx_avail
;
292 rx_pipe
->native
.peak
= glink_rpm_rx_peak
;
293 rx_pipe
->native
.advance
= glink_rpm_rx_advance
;
294 tx_pipe
->native
.avail
= glink_rpm_tx_avail
;
295 tx_pipe
->native
.write
= glink_rpm_tx_write
;
297 writel(0, tx_pipe
->head
);
298 writel(0, rx_pipe
->tail
);
300 glink
= qcom_glink_native_probe(&pdev
->dev
,
306 return PTR_ERR(glink
);
308 platform_set_drvdata(pdev
, glink
);
313 static int glink_rpm_remove(struct platform_device
*pdev
)
315 struct qcom_glink
*glink
= platform_get_drvdata(pdev
);
317 qcom_glink_native_remove(glink
);
322 static const struct of_device_id glink_rpm_of_match
[] = {
323 { .compatible
= "qcom,glink-rpm" },
326 MODULE_DEVICE_TABLE(of
, glink_rpm_of_match
);
328 static struct platform_driver glink_rpm_driver
= {
329 .probe
= glink_rpm_probe
,
330 .remove
= glink_rpm_remove
,
332 .name
= "qcom_glink_rpm",
333 .of_match_table
= glink_rpm_of_match
,
337 static int __init
glink_rpm_init(void)
339 return platform_driver_register(&glink_rpm_driver
);
341 subsys_initcall(glink_rpm_init
);
343 static void __exit
glink_rpm_exit(void)
345 platform_driver_unregister(&glink_rpm_driver
);
347 module_exit(glink_rpm_exit
);
349 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
350 MODULE_DESCRIPTION("Qualcomm GLINK RPM driver");
351 MODULE_LICENSE("GPL v2");