b62b10ca73fcb137488ea83bd74e2a0c284249b8
[processor-sdk/open-amp.git] / apps / samples / master / linux / kernelspace / zynq_rpmsg_driver / zynq_rpmsg_driver.c
1 /*
2 * Zynq Remote Processor Messaging Framework driver
3 *
4 * Copyright (C) 2014 Mentor Graphics Corporation
5 *
6 * Based on Zynq Remote Processor driver
7 *
8 * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
9 * Copyright (C) 2012 PetaLogix
10 *
11 * Based on origin OMAP Remote Processor driver
12 *
13 * Copyright (C) 2011 Texas Instruments, Inc.
14 * Copyright (C) 2011 Google, Inc.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * version 2 as published by the Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 */
26 #include <linux/kernel.h>
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/device.h>
30 #include <linux/slab.h>
31 #include <linux/mutex.h>
32 #include <linux/string.h>
33 #include <linux/interrupt.h>
34 #include <linux/platform_device.h>
35 #include <linux/dma-mapping.h>
36 #include <linux/of_irq.h>
37 #include <linux/virtio.h>
38 #include <linux/virtio_ids.h>
39 #include <linux/virtio_ring.h>
40 #include <linux/virtio_config.h>
41 #include <asm/outercache.h>
42 #include <asm/cacheflush.h>
43 #include <asm/hardware/gic.h>
44 #include <linux/of_device.h>
45 #include <linux/of_platform.h>
46 #include <linux/idr.h>
48 #include "zynq_rpmsg_internals.h"
50 static DEFINE_IDA(rpmsg_zynq_dev_index);
52 /* Globals. */
53 struct work_struct zynq_rpmsg_work;
55 struct platform_device *zynq_rpmsg_platform;
56 struct zynq_rpmsg_instance *zynq_rpmsg_p;
58 static void zynq_rpmsg_virtio_notify(struct virtqueue *vq)
59 {
60 /* Notify the other core. */
61 if (vq == zynq_rpmsg_p->vrings[0].vq)
62 /* Raise soft IRQ on GIC. */
63 gic_raise_softirq_unicore(0, zynq_rpmsg_p->vring0);
64 else
65 gic_raise_softirq_unicore(0, zynq_rpmsg_p->vring1);
66 }
68 static void zynq_rpmsg_virtio_del_vqs(struct virtio_device *vdev)
69 {
70 struct zynq_rpmsg_vring *local_vring;
71 int i;
73 for (i = 0; i < ZYNQ_RPMSG_NUM_VRINGS; i++) {
75 local_vring = &(zynq_rpmsg_p->vrings[i]);
77 vring_del_virtqueue(local_vring->vq);
79 local_vring->vq = NULL;
81 dma_free_coherent(&(zynq_rpmsg_platform->dev),
82 local_vring->len, local_vring->va,
83 local_vring->dma);
84 }
85 }
87 static int zynq_rpmsg_virtio_find_vqs(struct virtio_device *vdev,
88 unsigned nvqs, struct virtqueue *vqs[],
89 vq_callback_t * callbacks[],
90 const char *names[])
91 {
92 int i;
93 struct zynq_rpmsg_vring *local_vring;
94 void *vring_va;
95 int size;
97 /* Skip through the vrings. */
98 for (i = 0; i < nvqs; i++) {
100 local_vring = &(zynq_rpmsg_p->vrings[i]);
102 local_vring->len = zynq_rpmsg_p->num_descs;
104 size = vring_size(zynq_rpmsg_p->num_descs, zynq_rpmsg_p->align);
106 /* Allocate non-cacheable memory for the vring. */
107 local_vring->va = dma_alloc_coherent
108 (&(zynq_rpmsg_platform->dev),
109 size, &(local_vring->dma), GFP_KERNEL);
111 vring_va = local_vring->va;
113 memset(vring_va, 0, size);
115 local_vring->vq = vring_new_virtqueue(i,
116 zynq_rpmsg_p->num_descs,
117 zynq_rpmsg_p->align, vdev,
118 false, vring_va,
119 zynq_rpmsg_virtio_notify,
120 callbacks[i], names[i]);
122 vqs[i] = local_vring->vq;
123 }
125 return 0;
126 }
128 static u8 zynq_rpmsg_virtio_get_status(struct virtio_device *vdev)
129 {
130 return 0;
131 }
133 static void zynq_rpmsg_virtio_set_status(struct virtio_device *vdev, u8 status)
134 {
135 /* */
136 }
138 static void zynq_rpmsg_virtio_reset(struct virtio_device *vdev)
139 {
140 /* */
141 }
143 static u32 zynq_rpmsg_virtio_get_features(struct virtio_device *vdev)
144 {
145 /* Return features. */
146 return zynq_rpmsg_p->dev_feature;
147 }
149 static void zynq_rpmsg_virtio_finalize_features(struct virtio_device *vdev)
150 {
151 /* Set vring transport features. */
152 vring_transport_features(vdev);
154 zynq_rpmsg_p->gen_feature = vdev->features[0];
155 }
157 static void zynq_rpmsg_vdev_release(struct device *dev)
158 {
160 }
162 static void mid_level_type_release(struct device *dev)
163 {
165 }
167 static struct virtio_config_ops zynq_rpmsg_virtio_config_ops = {
168 .get_features = zynq_rpmsg_virtio_get_features,
169 .finalize_features = zynq_rpmsg_virtio_finalize_features,
170 .find_vqs = zynq_rpmsg_virtio_find_vqs,
171 .del_vqs = zynq_rpmsg_virtio_del_vqs,
172 .reset = zynq_rpmsg_virtio_reset,
173 .set_status = zynq_rpmsg_virtio_set_status,
174 .get_status = zynq_rpmsg_virtio_get_status,
175 };
177 static struct device_type mid_level_type = {
178 .name = "rpmsg_mid",
179 .release = mid_level_type_release,
180 };
182 static void handle_event(struct work_struct *work)
183 {
184 struct virtqueue *vq;
186 flush_cache_all();
188 outer_flush_range(zynq_rpmsg_p->mem_start, zynq_rpmsg_p->mem_end);
190 vq = zynq_rpmsg_p->vrings[0].vq;
192 if (vring_interrupt(0, vq) == IRQ_NONE)
193 dev_dbg(&zynq_rpmsg_platform->dev,
194 "no message found in vqid 0\n");
195 }
197 static void ipi_handler(void)
198 {
199 schedule_work(&zynq_rpmsg_work);
200 }
202 static int zynq_rpmsg_deinitialize(struct platform_device *pdev)
203 {
204 unregister_virtio_device(&(zynq_rpmsg_p->virtio_dev));
206 put_device(&(zynq_rpmsg_p->mid_dev));
208 dma_release_declared_memory(&pdev->dev);
210 clear_ipi_handler(zynq_rpmsg_p->vring0);
212 return 0;
213 }
215 static int zynq_rpmsg_initialize(struct platform_device *pdev)
216 {
217 int ret = 0;
218 int index;
219 struct virtio_device *virtio_dev;
221 /* Register ipi handler. */
222 ret = set_ipi_handler(zynq_rpmsg_p->vring0, ipi_handler,
223 "Firmware kick");
225 if (ret) {
226 dev_err(&pdev->dev, "IPI handler already registered\n");
227 return -ENODEV;
228 }
230 /* Initialize work. */
231 INIT_WORK(&zynq_rpmsg_work, handle_event);
233 /* Memory allocations for vrings. */
234 ret = dma_declare_coherent_memory(&pdev->dev,
235 zynq_rpmsg_p->mem_start,
236 zynq_rpmsg_p->mem_start,
237 zynq_rpmsg_p->mem_end -
238 zynq_rpmsg_p->mem_start + 1,
239 DMA_MEMORY_IO);
241 if (!ret) {
242 dev_err(&pdev->dev, "dma_declare_coherent_memory failed\n");
243 return -ENODEV;
244 }
246 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
248 if (ret) {
249 dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
250 return -ENODEV;
251 }
253 /* Initialize a mid-level device. Needed because of bad data structure
254 * handling and assumptions within the virtio rpmsg bus. We are doing it
255 * to just make sure that the virtio device has a parent device which
256 * then itself has a parent in the form of the platform device. */
257 device_initialize(&(zynq_rpmsg_p->mid_dev));
259 zynq_rpmsg_p->mid_dev.parent = &(pdev->dev);
260 zynq_rpmsg_p->mid_dev.type = &mid_level_type;
262 index = ida_simple_get(&rpmsg_zynq_dev_index, 0, 0, GFP_KERNEL);
264 if (index < 0) {
265 put_device(&(zynq_rpmsg_p->mid_dev));
266 return -ENODEV;
267 }
269 dev_set_name(&(zynq_rpmsg_p->mid_dev), "rpmsg_mid%d", index);
271 device_add(&(zynq_rpmsg_p->mid_dev));
273 /* Setup the virtio device structure. */
274 virtio_dev = &(zynq_rpmsg_p->virtio_dev);
276 virtio_dev->id.device = zynq_rpmsg_p->virtioid;
277 virtio_dev->config = &zynq_rpmsg_virtio_config_ops;
278 virtio_dev->dev.parent = &(zynq_rpmsg_p->mid_dev);
279 virtio_dev->dev.release = zynq_rpmsg_vdev_release;
281 /* Register the virtio device. */
282 ret = register_virtio_device(virtio_dev);
284 dev_info(&(zynq_rpmsg_platform->dev), "virtio device registered \r\n");
286 return ret;
287 }
289 static int zynq_rpmsg_retrieve_dts_info(struct platform_device *pdev)
290 {
291 const void *of_prop;
292 struct resource *res;
294 /* Retrieve memory information. */
295 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
296 if (!res) {
297 dev_err(&pdev->dev, "invalid address\n");
298 return -ENODEV;
299 }
301 zynq_rpmsg_p->mem_start = res->start;
302 zynq_rpmsg_p->mem_end = res->end;
304 /* Allocate free IPI number */
305 of_prop = of_get_property(pdev->dev.of_node, "vring0", NULL);
306 if (!of_prop) {
307 dev_err(&pdev->dev, "Please specify vring0 node property\n");
308 return -ENODEV;
309 }
311 zynq_rpmsg_p->vring0 = be32_to_cpup(of_prop);
313 /* Read vring1 ipi number */
314 of_prop = of_get_property(pdev->dev.of_node, "vring1", NULL);
315 if (!of_prop) {
316 dev_err(&pdev->dev, "Please specify vring1 node property\n");
317 return -ENODEV;
318 }
320 zynq_rpmsg_p->vring1 = be32_to_cpup(of_prop);
322 of_prop = of_get_property(pdev->dev.of_node, "num-descs", NULL);
323 if (!of_prop) {
324 dev_err(&pdev->dev, "Please specify num descs node property\n");
325 return -ENODEV;
326 }
328 zynq_rpmsg_p->num_descs = be32_to_cpup(of_prop);
330 /* Read dev-feature */
331 of_prop = of_get_property(pdev->dev.of_node, "dev-feature", NULL);
332 if (!of_prop) {
333 dev_err(&pdev->dev,
334 "Please specify dev features node property\n");
335 return -ENODEV;
336 }
338 zynq_rpmsg_p->dev_feature = be32_to_cpup(of_prop);
340 /* Read gen-feature */
341 of_prop = of_get_property(pdev->dev.of_node, "gen-feature", NULL);
342 if (!of_prop) {
343 dev_err(&pdev->dev,
344 "Please specify gen features node property\n");
345 return -ENODEV;
346 }
348 zynq_rpmsg_p->gen_feature = be32_to_cpup(of_prop);
350 /* Read number of vrings */
351 of_prop = of_get_property(pdev->dev.of_node, "num-vrings", NULL);
352 if (!of_prop) {
353 dev_err(&pdev->dev,
354 "Please specify num-vrings node property\n");
355 return -ENODEV;
356 }
358 zynq_rpmsg_p->num_vrings = be32_to_cpup(of_prop);
360 if (zynq_rpmsg_p->num_vrings > 2) {
361 dev_err(&pdev->dev,
362 "We do not currently support more than 2 vrings.\n");
363 return -ENODEV;
364 }
366 /* Read vring alignment */
367 of_prop = of_get_property(pdev->dev.of_node, "alignment", NULL);
368 if (!of_prop) {
369 dev_err(&pdev->dev, "Please specify alignment node property\n");
370 return -ENODEV;
371 }
373 zynq_rpmsg_p->align = be32_to_cpup(of_prop);
375 /* Read virtio ID */
376 of_prop = of_get_property(pdev->dev.of_node, "virtioid", NULL);
377 if (!of_prop) {
378 dev_err(&pdev->dev, "Please specify virtio id property\n");
379 return -ENODEV;
380 }
382 zynq_rpmsg_p->virtioid = be32_to_cpup(of_prop);
384 /* Read Ring Tx address. */
385 of_prop = of_get_property(pdev->dev.of_node, "ringtx", NULL);
386 if (!of_prop) {
387 dev_err(&pdev->dev, "Please specify ring tx property\n");
388 return -ENODEV;
389 }
391 zynq_rpmsg_p->ringtx = be32_to_cpup(of_prop);
393 /* Read Ring Rx address. */
394 of_prop = of_get_property(pdev->dev.of_node, "ringrx", NULL);
395 if (!of_prop) {
396 dev_err(&pdev->dev, "Please specify ringrx property\n");
397 return -ENODEV;
398 }
400 zynq_rpmsg_p->ringrx = be32_to_cpup(of_prop);
402 return 0;
403 }
405 static int zynq_rpmsg_probe(struct platform_device *pdev)
406 {
407 int ret = 0;
409 zynq_rpmsg_platform = pdev;
411 /* Allocate memory for the Zynq RPMSG instance. */
412 zynq_rpmsg_p = kzalloc(sizeof(struct zynq_rpmsg_instance), GFP_KERNEL);
414 if (!zynq_rpmsg_p) {
415 dev_err(&pdev->dev,
416 "Unable to alloc memory for zynq_rpmsg instance.\n");
417 return -ENOMEM;
418 }
420 /* Save the instance handle. */
421 platform_set_drvdata(pdev, zynq_rpmsg_p);
423 /* Retrieve the rquired information from DTS. */
424 ret = zynq_rpmsg_retrieve_dts_info(pdev);
426 if (ret) {
427 dev_err(&pdev->dev, "Failure in retrieving info from DTS.\n");
428 kzfree(zynq_rpmsg_p);
429 return -ENOMEM;
430 }
432 /* Perform all the initializations. */
433 ret = zynq_rpmsg_initialize(pdev);
435 return ret;
436 }
438 static int zynq_rpmsg_remove(struct platform_device *pdev)
439 {
440 zynq_rpmsg_deinitialize(pdev);
442 kfree(zynq_rpmsg_p);
444 return 0;
445 }
447 /* Match table for OF platform binding */
448 static struct of_device_id zynq_rpmsg_match[] = {
449 {.compatible = "xlnx,zynq_rpmsg_driver",},
450 { /* end of list */ },
451 };
453 MODULE_DEVICE_TABLE(of, zynq_rpmsg_match);
455 static struct platform_driver zynq_rpmsg_driver = {
456 .probe = zynq_rpmsg_probe,
457 .remove = zynq_rpmsg_remove,
458 .driver = {
459 .name = "zynq_rpmsg_driver",
460 .owner = THIS_MODULE,
461 .of_match_table = zynq_rpmsg_match,
462 },
463 };
465 static int __init init(void)
466 {
467 return platform_driver_register(&zynq_rpmsg_driver);
468 }
470 static void __exit fini(void)
471 {
472 platform_driver_unregister(&zynq_rpmsg_driver);
473 }
475 module_init(init);
476 module_exit(fini);
478 MODULE_LICENSE("GPL v2");
479 MODULE_DESCRIPTION
480 ("Zynq RPMSG driver to use RPMSG framework without remoteproc");