]> Git Repo - J-linux.git/blob - drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / media / platform / st / stm32 / stm32-dcmipp / dcmipp-core.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4  *
5  * Copyright (C) STMicroelectronics SA 2023
6  * Authors: Hugues Fruchet <[email protected]>
7  *          Alain Volmat <[email protected]>
8  *          for STMicroelectronics.
9  */
10
11 #include <linux/clk.h>
12 #include <linux/delay.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/pinctrl/consumer.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/property.h>
19 #include <linux/reset.h>
20 #include <media/media-device.h>
21 #include <media/v4l2-device.h>
22 #include <media/v4l2-fwnode.h>
23
24 #include "dcmipp-common.h"
25
26 #define DCMIPP_MDEV_MODEL_NAME "DCMIPP MDEV"
27
28 #define DCMIPP_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) {       \
29         .src_ent = src,                                         \
30         .src_pad = srcpad,                                      \
31         .sink_ent = sink,                                       \
32         .sink_pad = sinkpad,                                    \
33         .flags = link_flags,                                    \
34 }
35
36 struct dcmipp_device {
37         /* The platform device */
38         struct platform_device          pdev;
39         struct device                   *dev;
40
41         /* Hardware resources */
42         void __iomem                    *regs;
43         struct clk                      *kclk;
44
45         /* The pipeline configuration */
46         const struct dcmipp_pipeline_config     *pipe_cfg;
47
48         /* The Associated media_device parent */
49         struct media_device             mdev;
50
51         /* Internal v4l2 parent device*/
52         struct v4l2_device              v4l2_dev;
53
54         /* Entities */
55         struct dcmipp_ent_device        **entity;
56
57         struct v4l2_async_notifier      notifier;
58 };
59
60 static inline struct dcmipp_device *
61 notifier_to_dcmipp(struct v4l2_async_notifier *n)
62 {
63         return container_of(n, struct dcmipp_device, notifier);
64 }
65
66 /* Structure which describes individual configuration for each entity */
67 struct dcmipp_ent_config {
68         const char *name;
69         struct dcmipp_ent_device *(*init)
70                 (struct device *dev, const char *entity_name,
71                  struct v4l2_device *v4l2_dev, void __iomem *regs);
72         void (*release)(struct dcmipp_ent_device *ved);
73 };
74
75 /* Structure which describes links between entities */
76 struct dcmipp_ent_link {
77         unsigned int src_ent;
78         u16 src_pad;
79         unsigned int sink_ent;
80         u16 sink_pad;
81         u32 flags;
82 };
83
84 /* Structure which describes the whole topology */
85 struct dcmipp_pipeline_config {
86         const struct dcmipp_ent_config *ents;
87         size_t num_ents;
88         const struct dcmipp_ent_link *links;
89         size_t num_links;
90 };
91
92 /* --------------------------------------------------------------------------
93  * Topology Configuration
94  */
95
96 static const struct dcmipp_ent_config stm32mp13_ent_config[] = {
97         {
98                 .name = "dcmipp_parallel",
99                 .init = dcmipp_par_ent_init,
100                 .release = dcmipp_par_ent_release,
101         },
102         {
103                 .name = "dcmipp_dump_postproc",
104                 .init = dcmipp_byteproc_ent_init,
105                 .release = dcmipp_byteproc_ent_release,
106         },
107         {
108                 .name = "dcmipp_dump_capture",
109                 .init = dcmipp_bytecap_ent_init,
110                 .release = dcmipp_bytecap_ent_release,
111         },
112 };
113
114 #define ID_PARALLEL 0
115 #define ID_DUMP_BYTEPROC 1
116 #define ID_DUMP_CAPTURE 2
117
118 static const struct dcmipp_ent_link stm32mp13_ent_links[] = {
119         DCMIPP_ENT_LINK(ID_PARALLEL,      1, ID_DUMP_BYTEPROC, 0,
120                         MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
121         DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE,  0,
122                         MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
123 };
124
125 static const struct dcmipp_pipeline_config stm32mp13_pipe_cfg = {
126         .ents           = stm32mp13_ent_config,
127         .num_ents       = ARRAY_SIZE(stm32mp13_ent_config),
128         .links          = stm32mp13_ent_links,
129         .num_links      = ARRAY_SIZE(stm32mp13_ent_links)
130 };
131
132 #define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\
133                              (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\
134                              (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\
135                              (f) == (MEDIA_LNK_FL_ENABLED |\
136                                      MEDIA_LNK_FL_IMMUTABLE) ?\
137                                         "ENABLED, IMMUTABLE" :\
138                              "UNKNOWN")
139
140 static int dcmipp_create_links(struct dcmipp_device *dcmipp)
141 {
142         unsigned int i;
143         int ret;
144
145         /* Initialize the links between entities */
146         for (i = 0; i < dcmipp->pipe_cfg->num_links; i++) {
147                 const struct dcmipp_ent_link *link =
148                         &dcmipp->pipe_cfg->links[i];
149                 struct dcmipp_ent_device *ved_src =
150                         dcmipp->entity[link->src_ent];
151                 struct dcmipp_ent_device *ved_sink =
152                         dcmipp->entity[link->sink_ent];
153
154                 dev_dbg(dcmipp->dev, "Create link \"%s\":%d -> %d:\"%s\" [%s]\n",
155                         dcmipp->pipe_cfg->ents[link->src_ent].name,
156                         link->src_pad, link->sink_pad,
157                         dcmipp->pipe_cfg->ents[link->sink_ent].name,
158                         LINK_FLAG_TO_STR(link->flags));
159
160                 ret = media_create_pad_link(ved_src->ent, link->src_pad,
161                                             ved_sink->ent, link->sink_pad,
162                                             link->flags);
163                 if (ret)
164                         return ret;
165         }
166
167         return 0;
168 }
169
170 static int dcmipp_graph_init(struct dcmipp_device *dcmipp);
171
172 static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp)
173 {
174         int ret, i;
175
176         /* Call all subdev inits */
177         for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
178                 const char *name = dcmipp->pipe_cfg->ents[i].name;
179
180                 dev_dbg(dcmipp->dev, "add subdev %s\n", name);
181                 dcmipp->entity[i] =
182                         dcmipp->pipe_cfg->ents[i].init(dcmipp->dev, name,
183                                                        &dcmipp->v4l2_dev,
184                                                        dcmipp->regs);
185                 if (IS_ERR(dcmipp->entity[i])) {
186                         dev_err(dcmipp->dev, "failed to init subdev %s\n",
187                                 name);
188                         ret = PTR_ERR(dcmipp->entity[i]);
189                         goto err_init_entity;
190                 }
191         }
192
193         /* Initialize links */
194         ret = dcmipp_create_links(dcmipp);
195         if (ret)
196                 goto err_init_entity;
197
198         ret = dcmipp_graph_init(dcmipp);
199         if (ret < 0)
200                 goto err_init_entity;
201
202         return 0;
203
204 err_init_entity:
205         while (i-- > 0)
206                 dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
207         return ret;
208 }
209
210 static const struct of_device_id dcmipp_of_match[] = {
211         { .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg },
212         { /* end node */ },
213 };
214 MODULE_DEVICE_TABLE(of, dcmipp_of_match);
215
216 static irqreturn_t dcmipp_irq_thread(int irq, void *arg)
217 {
218         struct dcmipp_device *dcmipp = arg;
219         struct dcmipp_ent_device *ved;
220         unsigned int i;
221
222         /* Call irq thread of each entities of pipeline */
223         for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
224                 ved = dcmipp->entity[i];
225                 if (ved->thread_fn && ved->handler_ret == IRQ_WAKE_THREAD)
226                         ved->thread_fn(irq, ved);
227         }
228
229         return IRQ_HANDLED;
230 }
231
232 static irqreturn_t dcmipp_irq_callback(int irq, void *arg)
233 {
234         struct dcmipp_device *dcmipp = arg;
235         struct dcmipp_ent_device *ved;
236         irqreturn_t ret = IRQ_HANDLED;
237         unsigned int i;
238
239         /* Call irq handler of each entities of pipeline */
240         for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
241                 ved = dcmipp->entity[i];
242                 if (ved->handler)
243                         ved->handler_ret = ved->handler(irq, ved);
244                 else if (ved->thread_fn)
245                         ved->handler_ret = IRQ_WAKE_THREAD;
246                 else
247                         ved->handler_ret = IRQ_HANDLED;
248                 if (ved->handler_ret != IRQ_HANDLED)
249                         ret = ved->handler_ret;
250         }
251
252         return ret;
253 }
254
255 static int dcmipp_graph_notify_bound(struct v4l2_async_notifier *notifier,
256                                      struct v4l2_subdev *subdev,
257                                      struct v4l2_async_connection *asd)
258 {
259         struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
260         unsigned int ret;
261         int src_pad;
262         struct dcmipp_ent_device *sink;
263         struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_PARALLEL };
264         struct fwnode_handle *ep;
265
266         dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name);
267
268         /*
269          * Link this sub-device to DCMIPP, it could be
270          * a parallel camera sensor or a CSI-2 to parallel bridge
271          */
272         src_pad = media_entity_get_fwnode_pad(&subdev->entity,
273                                               subdev->fwnode,
274                                               MEDIA_PAD_FL_SOURCE);
275
276         /* Get bus characteristics from devicetree */
277         ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
278                                              FWNODE_GRAPH_ENDPOINT_NEXT);
279         if (!ep) {
280                 dev_err(dcmipp->dev, "Could not find the endpoint\n");
281                 return -ENODEV;
282         }
283
284         /* Check for parallel bus-type first, then bt656 */
285         ret = v4l2_fwnode_endpoint_parse(ep, &vep);
286         if (ret) {
287                 vep.bus_type = V4L2_MBUS_BT656;
288                 ret = v4l2_fwnode_endpoint_parse(ep, &vep);
289                 if (ret) {
290                         dev_err(dcmipp->dev, "Could not parse the endpoint\n");
291                         fwnode_handle_put(ep);
292                         return ret;
293                 }
294         }
295
296         fwnode_handle_put(ep);
297
298         if (vep.bus.parallel.bus_width == 0) {
299                 dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n");
300                 return -ENODEV;
301         }
302
303         /* Only 8 bits bus width supported with BT656 bus */
304         if (vep.bus_type == V4L2_MBUS_BT656 &&
305             vep.bus.parallel.bus_width != 8) {
306                 dev_err(dcmipp->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n",
307                         vep.bus.parallel.bus_width);
308                 return -ENODEV;
309         }
310
311         /* Parallel input device detected, connect it to parallel subdev */
312         sink = dcmipp->entity[ID_PARALLEL];
313         sink->bus.flags = vep.bus.parallel.flags;
314         sink->bus.bus_width = vep.bus.parallel.bus_width;
315         sink->bus.data_shift = vep.bus.parallel.data_shift;
316         sink->bus_type = vep.bus_type;
317         ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0,
318                                     MEDIA_LNK_FL_IMMUTABLE |
319                                     MEDIA_LNK_FL_ENABLED);
320         if (ret) {
321                 dev_err(dcmipp->dev, "Failed to create media pad link with subdev \"%s\"\n",
322                         subdev->name);
323                 return ret;
324         }
325
326         dev_dbg(dcmipp->dev, "DCMIPP is now linked to \"%s\"\n", subdev->name);
327
328         return 0;
329 }
330
331 static void dcmipp_graph_notify_unbind(struct v4l2_async_notifier *notifier,
332                                        struct v4l2_subdev *sd,
333                                        struct v4l2_async_connection *asd)
334 {
335         struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
336
337         dev_dbg(dcmipp->dev, "Removing %s\n", sd->name);
338 }
339
340 static int dcmipp_graph_notify_complete(struct v4l2_async_notifier *notifier)
341 {
342         struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
343         int ret;
344
345         /* Register the media device */
346         ret = media_device_register(&dcmipp->mdev);
347         if (ret) {
348                 dev_err(dcmipp->mdev.dev,
349                         "media device register failed (err=%d)\n", ret);
350                 return ret;
351         }
352
353         /* Expose all subdev's nodes*/
354         ret = v4l2_device_register_subdev_nodes(&dcmipp->v4l2_dev);
355         if (ret) {
356                 dev_err(dcmipp->mdev.dev,
357                         "dcmipp subdev nodes registration failed (err=%d)\n",
358                         ret);
359                 media_device_unregister(&dcmipp->mdev);
360                 return ret;
361         }
362
363         dev_dbg(dcmipp->dev, "Notify complete !\n");
364
365         return 0;
366 }
367
368 static const struct v4l2_async_notifier_operations dcmipp_graph_notify_ops = {
369         .bound = dcmipp_graph_notify_bound,
370         .unbind = dcmipp_graph_notify_unbind,
371         .complete = dcmipp_graph_notify_complete,
372 };
373
374 static int dcmipp_graph_init(struct dcmipp_device *dcmipp)
375 {
376         struct v4l2_async_connection *asd;
377         struct fwnode_handle *ep;
378         int ret;
379
380         ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
381                                              FWNODE_GRAPH_ENDPOINT_NEXT);
382         if (!ep) {
383                 dev_err(dcmipp->dev, "Failed to get next endpoint\n");
384                 return -EINVAL;
385         }
386
387         v4l2_async_nf_init(&dcmipp->notifier, &dcmipp->v4l2_dev);
388
389         asd = v4l2_async_nf_add_fwnode_remote(&dcmipp->notifier, ep,
390                                               struct v4l2_async_connection);
391
392         fwnode_handle_put(ep);
393
394         if (IS_ERR(asd)) {
395                 dev_err(dcmipp->dev, "Failed to add fwnode remote subdev\n");
396                 return PTR_ERR(asd);
397         }
398
399         dcmipp->notifier.ops = &dcmipp_graph_notify_ops;
400
401         ret = v4l2_async_nf_register(&dcmipp->notifier);
402         if (ret < 0) {
403                 dev_err(dcmipp->dev, "Failed to register notifier\n");
404                 v4l2_async_nf_cleanup(&dcmipp->notifier);
405                 return ret;
406         }
407
408         return 0;
409 }
410
411 static int dcmipp_probe(struct platform_device *pdev)
412 {
413         struct dcmipp_device *dcmipp;
414         struct clk *kclk;
415         const struct dcmipp_pipeline_config *pipe_cfg;
416         struct reset_control *rstc;
417         int irq;
418         int ret;
419
420         dcmipp = devm_kzalloc(&pdev->dev, sizeof(*dcmipp), GFP_KERNEL);
421         if (!dcmipp)
422                 return -ENOMEM;
423
424         dcmipp->dev = &pdev->dev;
425
426         pipe_cfg = device_get_match_data(dcmipp->dev);
427         if (!pipe_cfg) {
428                 dev_err(&pdev->dev, "Can't get device data\n");
429                 return -ENODEV;
430         }
431         dcmipp->pipe_cfg = pipe_cfg;
432
433         platform_set_drvdata(pdev, dcmipp);
434
435         /* Get hardware resources from devicetree */
436         rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
437         if (IS_ERR(rstc))
438                 return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
439                                      "Could not get reset control\n");
440
441         irq = platform_get_irq(pdev, 0);
442         if (irq < 0)
443                 return irq;
444
445         dcmipp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
446         if (IS_ERR(dcmipp->regs)) {
447                 dev_err(&pdev->dev, "Could not map registers\n");
448                 return PTR_ERR(dcmipp->regs);
449         }
450
451         ret = devm_request_threaded_irq(&pdev->dev, irq, dcmipp_irq_callback,
452                                         dcmipp_irq_thread, IRQF_ONESHOT,
453                                         dev_name(&pdev->dev), dcmipp);
454         if (ret) {
455                 dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
456                 return ret;
457         }
458
459         /* Reset device */
460         ret = reset_control_assert(rstc);
461         if (ret) {
462                 dev_err(&pdev->dev, "Failed to assert the reset line\n");
463                 return ret;
464         }
465
466         usleep_range(3000, 5000);
467
468         ret = reset_control_deassert(rstc);
469         if (ret) {
470                 dev_err(&pdev->dev, "Failed to deassert the reset line\n");
471                 return ret;
472         }
473
474         kclk = devm_clk_get(&pdev->dev, NULL);
475         if (IS_ERR(kclk))
476                 return dev_err_probe(&pdev->dev, PTR_ERR(kclk),
477                                      "Unable to get kclk\n");
478         dcmipp->kclk = kclk;
479
480         dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents,
481                                       sizeof(*dcmipp->entity), GFP_KERNEL);
482         if (!dcmipp->entity)
483                 return -ENOMEM;
484
485         /* Register the v4l2 struct */
486         ret = v4l2_device_register(&pdev->dev, &dcmipp->v4l2_dev);
487         if (ret) {
488                 dev_err(&pdev->dev,
489                         "v4l2 device register failed (err=%d)\n", ret);
490                 return ret;
491         }
492
493         /* Link the media device within the v4l2_device */
494         dcmipp->v4l2_dev.mdev = &dcmipp->mdev;
495
496         /* Initialize media device */
497         strscpy(dcmipp->mdev.model, DCMIPP_MDEV_MODEL_NAME,
498                 sizeof(dcmipp->mdev.model));
499         dcmipp->mdev.dev = &pdev->dev;
500         media_device_init(&dcmipp->mdev);
501
502         /* Initialize subdevs */
503         ret = dcmipp_create_subdevs(dcmipp);
504         if (ret) {
505                 media_device_cleanup(&dcmipp->mdev);
506                 v4l2_device_unregister(&dcmipp->v4l2_dev);
507                 return ret;
508         }
509
510         pm_runtime_enable(dcmipp->dev);
511
512         dev_info(&pdev->dev, "Probe done");
513
514         return 0;
515 }
516
517 static void dcmipp_remove(struct platform_device *pdev)
518 {
519         struct dcmipp_device *dcmipp = platform_get_drvdata(pdev);
520         unsigned int i;
521
522         pm_runtime_disable(&pdev->dev);
523
524         v4l2_async_nf_unregister(&dcmipp->notifier);
525         v4l2_async_nf_cleanup(&dcmipp->notifier);
526
527         for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++)
528                 dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
529
530         media_device_unregister(&dcmipp->mdev);
531         media_device_cleanup(&dcmipp->mdev);
532
533         v4l2_device_unregister(&dcmipp->v4l2_dev);
534 }
535
536 static int dcmipp_runtime_suspend(struct device *dev)
537 {
538         struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
539
540         clk_disable_unprepare(dcmipp->kclk);
541
542         return 0;
543 }
544
545 static int dcmipp_runtime_resume(struct device *dev)
546 {
547         struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
548         int ret;
549
550         ret = clk_prepare_enable(dcmipp->kclk);
551         if (ret)
552                 dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__);
553
554         return ret;
555 }
556
557 static int dcmipp_suspend(struct device *dev)
558 {
559         /* disable clock */
560         pm_runtime_force_suspend(dev);
561
562         /* change pinctrl state */
563         pinctrl_pm_select_sleep_state(dev);
564
565         return 0;
566 }
567
568 static int dcmipp_resume(struct device *dev)
569 {
570         /* restore pinctl default state */
571         pinctrl_pm_select_default_state(dev);
572
573         /* clock enable */
574         pm_runtime_force_resume(dev);
575
576         return 0;
577 }
578
579 static const struct dev_pm_ops dcmipp_pm_ops = {
580         SYSTEM_SLEEP_PM_OPS(dcmipp_suspend, dcmipp_resume)
581         RUNTIME_PM_OPS(dcmipp_runtime_suspend, dcmipp_runtime_resume, NULL)
582 };
583
584 static struct platform_driver dcmipp_pdrv = {
585         .probe          = dcmipp_probe,
586         .remove         = dcmipp_remove,
587         .driver         = {
588                 .name   = DCMIPP_PDEV_NAME,
589                 .of_match_table = dcmipp_of_match,
590                 .pm = pm_ptr(&dcmipp_pm_ops),
591         },
592 };
593
594 module_platform_driver(dcmipp_pdrv);
595
596 MODULE_AUTHOR("Hugues Fruchet <[email protected]>");
597 MODULE_AUTHOR("Alain Volmat <[email protected]>");
598 MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface with Pixel Processor driver");
599 MODULE_LICENSE("GPL");
This page took 0.067476 seconds and 4 git commands to generate.