734c5b73899fb7abdbf1aa52a079abfd63696053
[AGL/meta-agl-devel.git] / meta-egvirt / recipes-kernel / kernel-module-virtio-video / files / virtio_video_driver.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Driver for virtio video device.
3  *
4  * Copyright 2020 OpenSynergy GmbH.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <linux/module.h>
20 #include <linux/version.h>
21 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
22 #include <linux/dma-map-ops.h>
23 #else
24 #include <linux/dma-mapping.h>
25 #endif
26
27 #include "virtio_video.h"
28
29 static unsigned int debug;
30 module_param(debug, uint, 0644);
31
32 static unsigned int use_dma_mem;
33 module_param(use_dma_mem, uint, 0644);
34 MODULE_PARM_DESC(use_dma_mem, "Try to allocate buffers from the DMA zone");
35
36 static int vid_nr_dec = -1;
37 module_param(vid_nr_dec, int, 0644);
38 MODULE_PARM_DESC(vid_nr_dec, "videoN start number, -1 is autodetect");
39
40 static int vid_nr_enc = -1;
41 module_param(vid_nr_enc, int, 0644);
42 MODULE_PARM_DESC(vid_nr_enc, "videoN start number, -1 is autodetect");
43
44 static int vid_nr_cam = -1;
45 module_param(vid_nr_cam, int, 0644);
46 MODULE_PARM_DESC(vid_nr_cam, "videoN start number, -1 is autodetect");
47
48 static bool mplane_cam = true;
49 module_param(mplane_cam, bool, 0644);
50 MODULE_PARM_DESC(mplane_cam,
51         "1 (default) - multiplanar camera, 0 - single planar camera");
52
53 static int virtio_video_probe(struct virtio_device *vdev)
54 {
55         int ret;
56         struct virtio_video_device *vvd;
57         struct virtqueue *vqs[2];
58         struct device *dev = &vdev->dev;
59         struct device *pdev = dev->parent;
60
61         static const char * const names[] = { "commandq", "eventq" };
62         static vq_callback_t *callbacks[] = {
63                 virtio_video_cmd_cb,
64                 virtio_video_event_cb
65         };
66
67         if (!virtio_has_feature(vdev, VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES)) {
68                 dev_err(dev, "device must support guest allocated buffers\n");
69                 return -ENODEV;
70         }
71
72         vvd = devm_kzalloc(dev, sizeof(*vvd), GFP_KERNEL);
73         if (!vvd)
74                 return -ENOMEM;
75
76         vvd->is_m2m_dev = true;
77
78         switch (vdev->id.device) {
79         case VIRTIO_ID_VIDEO_CAM:
80                 vvd->is_m2m_dev = false;
81                 vvd->vid_dev_nr = vid_nr_cam;
82                 vvd->is_mplane_cam = mplane_cam;
83                 vvd->type = VIRTIO_VIDEO_DEVICE_CAMERA;
84                 break;
85         case VIRTIO_ID_VIDEO_ENC:
86                 vvd->vid_dev_nr = vid_nr_enc;
87                 vvd->type = VIRTIO_VIDEO_DEVICE_ENCODER;
88                 break;
89         case VIRTIO_ID_VIDEO_DEC:
90         default:
91                 vvd->vid_dev_nr = vid_nr_dec;
92                 vvd->type = VIRTIO_VIDEO_DEVICE_DECODER;
93                 break;
94         }
95
96         vvd->vdev = vdev;
97         vvd->debug = debug;
98         vvd->use_dma_mem = use_dma_mem;
99         vdev->priv = vvd;
100
101         spin_lock_init(&vvd->pending_buf_list_lock);
102         spin_lock_init(&vvd->resource_idr_lock);
103         idr_init(&vvd->resource_idr);
104         spin_lock_init(&vvd->stream_idr_lock);
105         idr_init(&vvd->stream_idr);
106
107         init_waitqueue_head(&vvd->wq);
108
109         if (virtio_has_feature(vdev, VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG))
110                 vvd->supp_non_contig = true;
111
112 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
113         vvd->has_iommu = !virtio_has_dma_quirk(vdev);
114 #else
115         vvd->has_iommu = !virtio_has_iommu_quirk(vdev);
116 #endif
117
118         if (!dev->dma_ops)
119                 set_dma_ops(dev, pdev->dma_ops);
120
121         /*
122          * Set it to coherent_dma_mask by default if the architecture
123          * code has not set it.
124          */
125         if (!dev->dma_mask)
126                 dev->dma_mask = &dev->coherent_dma_mask;
127
128         dma_set_mask(dev, *pdev->dma_mask);
129
130         dev_set_name(dev, "%s.%i", DRIVER_NAME, vdev->index);
131         ret = v4l2_device_register(dev, &vvd->v4l2_dev);
132         if (ret)
133                 goto err_v4l2_reg;
134
135         spin_lock_init(&vvd->commandq.qlock);
136         init_waitqueue_head(&vvd->commandq.reclaim_queue);
137
138         INIT_WORK(&vvd->eventq.work, virtio_video_process_events);
139
140         INIT_LIST_HEAD(&vvd->pending_vbuf_list);
141
142         ret = virtio_find_vqs(vdev, 2, vqs, callbacks, names, NULL);
143         if (ret) {
144                 v4l2_err(&vvd->v4l2_dev, "failed to find virt queues\n");
145                 goto err_vqs;
146         }
147
148         vvd->commandq.vq = vqs[0];
149         vvd->eventq.vq = vqs[1];
150
151         ret = virtio_video_alloc_vbufs(vvd);
152         if (ret) {
153                 v4l2_err(&vvd->v4l2_dev, "failed to alloc vbufs\n");
154                 goto err_vbufs;
155         }
156
157         virtio_cread(vdev, struct virtio_video_config, max_caps_length,
158                      &vvd->max_caps_len);
159         if (!vvd->max_caps_len) {
160                 v4l2_err(&vvd->v4l2_dev, "max_caps_len is zero\n");
161                 ret = -EINVAL;
162                 goto err_config;
163         }
164
165         virtio_cread(vdev, struct virtio_video_config, max_resp_length,
166                      &vvd->max_resp_len);
167         if (!vvd->max_resp_len) {
168                 v4l2_err(&vvd->v4l2_dev, "max_resp_len is zero\n");
169                 ret = -EINVAL;
170                 goto err_config;
171         }
172
173         ret = virtio_video_alloc_events(vvd);
174         if (ret)
175                 goto err_events;
176
177         virtio_device_ready(vdev);
178         vvd->commandq.ready = true;
179         vvd->eventq.ready = true;
180
181         ret = virtio_video_device_init(vvd);
182         if (ret) {
183                 v4l2_err(&vvd->v4l2_dev,
184                          "failed to init virtio video\n");
185                 goto err_init;
186         }
187
188         return 0;
189
190 err_init:
191 err_events:
192 err_config:
193         virtio_video_free_vbufs(vvd);
194 err_vbufs:
195         vdev->config->del_vqs(vdev);
196 err_vqs:
197         v4l2_device_unregister(&vvd->v4l2_dev);
198 err_v4l2_reg:
199         devm_kfree(&vdev->dev, vvd);
200
201         return ret;
202 }
203
204 static void virtio_video_remove(struct virtio_device *vdev)
205 {
206         struct virtio_video_device *vvd = vdev->priv;
207
208         virtio_video_device_deinit(vvd);
209         virtio_video_free_vbufs(vvd);
210         vdev->config->del_vqs(vdev);
211         v4l2_device_unregister(&vvd->v4l2_dev);
212         devm_kfree(&vdev->dev, vvd);
213 }
214
215 static struct virtio_device_id id_table[] = {
216         { VIRTIO_ID_VIDEO_DEC, VIRTIO_DEV_ANY_ID },
217         { VIRTIO_ID_VIDEO_ENC, VIRTIO_DEV_ANY_ID },
218         { VIRTIO_ID_VIDEO_CAM, VIRTIO_DEV_ANY_ID },
219         { 0 },
220 };
221
222 static unsigned int features[] = {
223         VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES,
224         VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG,
225 };
226
227 static struct virtio_driver virtio_video_driver = {
228         .feature_table = features,
229         .feature_table_size = ARRAY_SIZE(features),
230         .driver.name = DRIVER_NAME,
231         .driver.owner = THIS_MODULE,
232         .id_table = id_table,
233         .probe = virtio_video_probe,
234         .remove = virtio_video_remove,
235 };
236
237 module_virtio_driver(virtio_video_driver);
238
239 MODULE_DEVICE_TABLE(virtio, id_table);
240 MODULE_DESCRIPTION("virtio video driver");
241 MODULE_AUTHOR("Dmitry Sepp <dmitry.sepp@opensynergy.com>");
242 MODULE_AUTHOR("Kiran Pawar <kiran.pawar@opensynergy.com>");
243 MODULE_AUTHOR("Nikolay Martyanov <nikolay.martyanov@opensynergy.com>");
244 MODULE_AUTHOR("Samiullah Khawaja <samiullah.khawaja@opensynergy.com>");
245 MODULE_VERSION(DRIVER_VERSION);
246 MODULE_LICENSE("GPL");