1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * vimc-core.c Virtual Media Controller Driver
4 *
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6 */
7
8 #include <linux/dma-mapping.h>
9 #include <linux/font.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <media/media-device.h>
14 #include <media/tpg/v4l2-tpg.h>
15 #include <media/v4l2-device.h>
16
17 #include "vimc-common.h"
18
19 unsigned int vimc_allocator;
20 module_param_named(allocator, vimc_allocator, uint, 0444);
21 MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
22 "\t\t 0 == vmalloc\n"
23 "\t\t 1 == dma-contig");
24
25 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
26
27 #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
28 .src_ent = src, \
29 .src_pad = srcpad, \
30 .sink_ent = sink, \
31 .sink_pad = sinkpad, \
32 .flags = link_flags, \
33 }
34
35 /* Structure which describes links between entities */
36 struct vimc_ent_link {
37 unsigned int src_ent;
38 u16 src_pad;
39 unsigned int sink_ent;
40 u16 sink_pad;
41 u32 flags;
42 };
43
44 /* Structure which describes the whole topology */
45 struct vimc_pipeline_config {
46 const struct vimc_ent_config *ents;
47 size_t num_ents;
48 const struct vimc_ent_link *links;
49 size_t num_links;
50 };
51
52 /* --------------------------------------------------------------------------
53 * Topology Configuration
54 */
55
56 static struct vimc_ent_config ent_config[] = {
57 {
58 .name = "Sensor A",
59 .type = &vimc_sen_type
60 },
61 {
62 .name = "Sensor B",
63 .type = &vimc_sen_type
64 },
65 {
66 .name = "Debayer A",
67 .type = &vimc_deb_type
68 },
69 {
70 .name = "Debayer B",
71 .type = &vimc_deb_type
72 },
73 {
74 .name = "Raw Capture 0",
75 .type = &vimc_cap_type
76 },
77 {
78 .name = "Raw Capture 1",
79 .type = &vimc_cap_type
80 },
81 {
82 /* TODO: change this to vimc-input when it is implemented */
83 .name = "RGB/YUV Input",
84 .type = &vimc_sen_type
85 },
86 {
87 .name = "Scaler",
88 .type = &vimc_sca_type
89 },
90 {
91 .name = "RGB/YUV Capture",
92 .type = &vimc_cap_type
93 },
94 };
95
96 static const struct vimc_ent_link ent_links[] = {
97 /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
98 VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
99 /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
100 VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
101 /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
102 VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
103 /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
104 VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
105 /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
106 VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
107 /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
108 VIMC_ENT_LINK(3, 1, 7, 0, 0),
109 /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
110 VIMC_ENT_LINK(6, 0, 7, 0, 0),
111 /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
112 VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
113 };
114
115 static struct vimc_pipeline_config pipe_cfg = {
116 .ents = ent_config,
117 .num_ents = ARRAY_SIZE(ent_config),
118 .links = ent_links,
119 .num_links = ARRAY_SIZE(ent_links)
120 };
121
122 /* -------------------------------------------------------------------------- */
123
vimc_rm_links(struct vimc_device * vimc)124 static void vimc_rm_links(struct vimc_device *vimc)
125 {
126 unsigned int i;
127
128 for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
129 media_entity_remove_links(vimc->ent_devs[i]->ent);
130 }
131
vimc_create_links(struct vimc_device * vimc)132 static int vimc_create_links(struct vimc_device *vimc)
133 {
134 unsigned int i;
135 int ret;
136
137 /* Initialize the links between entities */
138 for (i = 0; i < vimc->pipe_cfg->num_links; i++) {
139 const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i];
140
141 struct vimc_ent_device *ved_src =
142 vimc->ent_devs[link->src_ent];
143 struct vimc_ent_device *ved_sink =
144 vimc->ent_devs[link->sink_ent];
145
146 ret = media_create_pad_link(ved_src->ent, link->src_pad,
147 ved_sink->ent, link->sink_pad,
148 link->flags);
149 if (ret)
150 goto err_rm_links;
151 }
152
153 return 0;
154
155 err_rm_links:
156 vimc_rm_links(vimc);
157 return ret;
158 }
159
vimc_release_subdevs(struct vimc_device * vimc)160 static void vimc_release_subdevs(struct vimc_device *vimc)
161 {
162 unsigned int i;
163
164 for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
165 if (vimc->ent_devs[i])
166 vimc->pipe_cfg->ents[i].type->release(vimc->ent_devs[i]);
167 }
168
vimc_unregister_subdevs(struct vimc_device * vimc)169 static void vimc_unregister_subdevs(struct vimc_device *vimc)
170 {
171 unsigned int i;
172
173 for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
174 if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].type->unregister)
175 vimc->pipe_cfg->ents[i].type->unregister(vimc->ent_devs[i]);
176 }
177
vimc_add_subdevs(struct vimc_device * vimc)178 static int vimc_add_subdevs(struct vimc_device *vimc)
179 {
180 unsigned int i;
181
182 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
183 dev_dbg(vimc->mdev.dev, "new entity for %s\n",
184 vimc->pipe_cfg->ents[i].name);
185 vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].type->add(vimc,
186 vimc->pipe_cfg->ents[i].name);
187 if (IS_ERR(vimc->ent_devs[i])) {
188 int err = PTR_ERR(vimc->ent_devs[i]);
189
190 dev_err(vimc->mdev.dev, "adding entity %s failed (%d)\n",
191 vimc->pipe_cfg->ents[i].name, err);
192 vimc->ent_devs[i] = NULL;
193 vimc_unregister_subdevs(vimc);
194 vimc_release_subdevs(vimc);
195 return err;
196 }
197 }
198 return 0;
199 }
200
vimc_v4l2_dev_release(struct v4l2_device * v4l2_dev)201 static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev)
202 {
203 struct vimc_device *vimc =
204 container_of(v4l2_dev, struct vimc_device, v4l2_dev);
205
206 vimc_release_subdevs(vimc);
207 media_device_cleanup(&vimc->mdev);
208 kfree(vimc->ent_devs);
209 kfree(vimc);
210 }
211
vimc_register_devices(struct vimc_device * vimc)212 static int vimc_register_devices(struct vimc_device *vimc)
213 {
214 int ret;
215
216 /* Register the v4l2 struct */
217 ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev);
218 if (ret) {
219 dev_err(vimc->mdev.dev,
220 "v4l2 device register failed (err=%d)\n", ret);
221 return ret;
222 }
223 /* allocate ent_devs */
224 vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents,
225 sizeof(*vimc->ent_devs), GFP_KERNEL);
226 if (!vimc->ent_devs) {
227 ret = -ENOMEM;
228 goto err_v4l2_unregister;
229 }
230
231 /* Invoke entity config hooks to initialize and register subdevs */
232 ret = vimc_add_subdevs(vimc);
233 if (ret)
234 goto err_free_ent_devs;
235
236 /* Initialize links */
237 ret = vimc_create_links(vimc);
238 if (ret)
239 goto err_rm_subdevs;
240
241 /* Register the media device */
242 ret = media_device_register(&vimc->mdev);
243 if (ret) {
244 dev_err(vimc->mdev.dev,
245 "media device register failed (err=%d)\n", ret);
246 goto err_rm_subdevs;
247 }
248
249 /* Expose all subdev's nodes*/
250 ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev);
251 if (ret) {
252 dev_err(vimc->mdev.dev,
253 "vimc subdev nodes registration failed (err=%d)\n",
254 ret);
255 goto err_mdev_unregister;
256 }
257
258 return 0;
259
260 err_mdev_unregister:
261 media_device_unregister(&vimc->mdev);
262 err_rm_subdevs:
263 vimc_unregister_subdevs(vimc);
264 vimc_release_subdevs(vimc);
265 err_free_ent_devs:
266 kfree(vimc->ent_devs);
267 err_v4l2_unregister:
268 v4l2_device_unregister(&vimc->v4l2_dev);
269
270 return ret;
271 }
272
vimc_probe(struct platform_device * pdev)273 static int vimc_probe(struct platform_device *pdev)
274 {
275 const struct font_desc *font = find_font("VGA8x16");
276 struct vimc_device *vimc;
277 int ret;
278
279 dev_dbg(&pdev->dev, "probe");
280
281 if (!font) {
282 dev_err(&pdev->dev, "could not find font\n");
283 return -ENODEV;
284 }
285
286 tpg_set_font(font->data);
287
288 if (vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG)
289 dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
290
291 vimc = kzalloc(sizeof(*vimc), GFP_KERNEL);
292 if (!vimc)
293 return -ENOMEM;
294
295 vimc->pipe_cfg = &pipe_cfg;
296
297 /* Link the media device within the v4l2_device */
298 vimc->v4l2_dev.mdev = &vimc->mdev;
299
300 /* Initialize media device */
301 strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
302 sizeof(vimc->mdev.model));
303 snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info),
304 "platform:%s", VIMC_PDEV_NAME);
305 vimc->mdev.dev = &pdev->dev;
306 media_device_init(&vimc->mdev);
307
308 ret = vimc_register_devices(vimc);
309 if (ret) {
310 media_device_cleanup(&vimc->mdev);
311 kfree(vimc);
312 return ret;
313 }
314 /*
315 * the release cb is set only after successful registration.
316 * if the registration fails, we release directly from probe
317 */
318
319 vimc->v4l2_dev.release = vimc_v4l2_dev_release;
320 platform_set_drvdata(pdev, vimc);
321 return 0;
322 }
323
vimc_remove(struct platform_device * pdev)324 static int vimc_remove(struct platform_device *pdev)
325 {
326 struct vimc_device *vimc = platform_get_drvdata(pdev);
327
328 dev_dbg(&pdev->dev, "remove");
329
330 vimc_unregister_subdevs(vimc);
331 media_device_unregister(&vimc->mdev);
332 v4l2_device_unregister(&vimc->v4l2_dev);
333 v4l2_device_put(&vimc->v4l2_dev);
334
335 return 0;
336 }
337
vimc_dev_release(struct device * dev)338 static void vimc_dev_release(struct device *dev)
339 {
340 }
341
342 static struct platform_device vimc_pdev = {
343 .name = VIMC_PDEV_NAME,
344 .dev.release = vimc_dev_release,
345 };
346
347 static struct platform_driver vimc_pdrv = {
348 .probe = vimc_probe,
349 .remove = vimc_remove,
350 .driver = {
351 .name = VIMC_PDEV_NAME,
352 },
353 };
354
vimc_init(void)355 static int __init vimc_init(void)
356 {
357 int ret;
358
359 ret = platform_device_register(&vimc_pdev);
360 if (ret) {
361 dev_err(&vimc_pdev.dev,
362 "platform device registration failed (err=%d)\n", ret);
363 return ret;
364 }
365
366 ret = platform_driver_register(&vimc_pdrv);
367 if (ret) {
368 dev_err(&vimc_pdev.dev,
369 "platform driver registration failed (err=%d)\n", ret);
370 platform_driver_unregister(&vimc_pdrv);
371 return ret;
372 }
373
374 return 0;
375 }
376
vimc_exit(void)377 static void __exit vimc_exit(void)
378 {
379 platform_driver_unregister(&vimc_pdrv);
380
381 platform_device_unregister(&vimc_pdev);
382 }
383
384 module_init(vimc_init);
385 module_exit(vimc_exit);
386
387 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
388 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
389 MODULE_LICENSE("GPL");
390