]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - apps/samples/master/linux/kernelspace/zynq_rpmsg_driver/zynq_rpmsg_driver.c
apps:func_test_suite:generic:zynq7:remoteproc master
[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;
128 static u8 zynq_rpmsg_virtio_get_status(struct virtio_device *vdev)
130         return 0;
133 static void zynq_rpmsg_virtio_set_status(struct virtio_device *vdev, u8 status)
135         /* */
138 static void zynq_rpmsg_virtio_reset(struct virtio_device *vdev)
140         /* */
143 static u32 zynq_rpmsg_virtio_get_features(struct virtio_device *vdev)
145         /* Return features. */
146         return zynq_rpmsg_p->dev_feature;
149 static void zynq_rpmsg_virtio_finalize_features(struct virtio_device *vdev)
151         /* Set vring transport features. */
152         vring_transport_features(vdev);
154         zynq_rpmsg_p->gen_feature = vdev->features[0];
157 static void zynq_rpmsg_vdev_release(struct device *dev)
162 static void mid_level_type_release(struct device *dev)
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)
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");
197 static void ipi_handler(void)
199         schedule_work(&zynq_rpmsg_work);
202 static int zynq_rpmsg_deinitialize(struct platform_device *pdev)
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;
215 static int zynq_rpmsg_initialize(struct platform_device *pdev)
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;
289 static int zynq_rpmsg_retrieve_dts_info(struct platform_device *pdev)
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;
405 static int zynq_rpmsg_probe(struct platform_device *pdev)
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;
438 static int zynq_rpmsg_remove(struct platform_device *pdev)
440         zynq_rpmsg_deinitialize(pdev);
442         kfree(zynq_rpmsg_p);
444         return 0;
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)
467         return platform_driver_register(&zynq_rpmsg_driver);
470 static void __exit fini(void)
472         platform_driver_unregister(&zynq_rpmsg_driver);
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");