1
2
3
4
5
6
7
8
9
10#include <linux/device.h>
11#include <linux/dma-mapping.h>
12#include <linux/slab.h>
13
14#include <media/media-entity.h>
15#include <media/v4l2-subdev.h>
16#include <media/vsp1.h>
17
18#include "vsp1.h"
19#include "vsp1_brx.h"
20#include "vsp1_dl.h"
21#include "vsp1_drm.h"
22#include "vsp1_lif.h"
23#include "vsp1_pipe.h"
24#include "vsp1_rwpf.h"
25#include "vsp1_uif.h"
26
27#define BRX_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"
28
29
30
31
32
33static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
34 unsigned int completion)
35{
36 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
37
38 if (drm_pipe->du_complete) {
39 struct vsp1_entity *uif = drm_pipe->uif;
40 unsigned int status = completion
41 & (VSP1_DU_STATUS_COMPLETE |
42 VSP1_DU_STATUS_WRITEBACK);
43 u32 crc;
44
45 crc = uif ? vsp1_uif_get_crc(to_uif(&uif->subdev)) : 0;
46 drm_pipe->du_complete(drm_pipe->du_private, status, crc);
47 }
48
49 if (completion & VSP1_DL_FRAME_END_INTERNAL) {
50 drm_pipe->force_brx_release = false;
51 wake_up(&drm_pipe->wait_queue);
52 }
53}
54
55
56
57
58
59
60
61
62
63static int vsp1_du_insert_uif(struct vsp1_device *vsp1,
64 struct vsp1_pipeline *pipe,
65 struct vsp1_entity *uif,
66 struct vsp1_entity *prev, unsigned int prev_pad,
67 struct vsp1_entity *next, unsigned int next_pad)
68{
69 struct v4l2_subdev_format format;
70 int ret;
71
72 if (!uif) {
73
74
75
76
77 prev->sink = next;
78 prev->sink_pad = next_pad;
79 return 0;
80 }
81
82 prev->sink = uif;
83 prev->sink_pad = UIF_PAD_SINK;
84
85 memset(&format, 0, sizeof(format));
86 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
87 format.pad = prev_pad;
88
89 ret = v4l2_subdev_call(&prev->subdev, pad, get_fmt, NULL, &format);
90 if (ret < 0)
91 return ret;
92
93 format.pad = UIF_PAD_SINK;
94
95 ret = v4l2_subdev_call(&uif->subdev, pad, set_fmt, NULL, &format);
96 if (ret < 0)
97 return ret;
98
99 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on UIF sink\n",
100 __func__, format.format.width, format.format.height,
101 format.format.code);
102
103
104
105
106
107
108 uif->sink = next;
109 uif->sink_pad = next_pad;
110
111 return 0;
112}
113
114
115static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1,
116 struct vsp1_pipeline *pipe,
117 struct vsp1_rwpf *rpf,
118 struct vsp1_entity *uif,
119 unsigned int brx_input)
120{
121 struct v4l2_subdev_selection sel;
122 struct v4l2_subdev_format format;
123 const struct v4l2_rect *crop;
124 int ret;
125
126
127
128
129
130 crop = &vsp1->drm->inputs[rpf->entity.index].crop;
131
132 memset(&format, 0, sizeof(format));
133 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
134 format.pad = RWPF_PAD_SINK;
135 format.format.width = crop->width + crop->left;
136 format.format.height = crop->height + crop->top;
137 format.format.code = rpf->fmtinfo->mbus;
138 format.format.field = V4L2_FIELD_NONE;
139
140 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
141 &format);
142 if (ret < 0)
143 return ret;
144
145 dev_dbg(vsp1->dev,
146 "%s: set format %ux%u (%x) on RPF%u sink\n",
147 __func__, format.format.width, format.format.height,
148 format.format.code, rpf->entity.index);
149
150 memset(&sel, 0, sizeof(sel));
151 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
152 sel.pad = RWPF_PAD_SINK;
153 sel.target = V4L2_SEL_TGT_CROP;
154 sel.r = *crop;
155
156 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
157 &sel);
158 if (ret < 0)
159 return ret;
160
161 dev_dbg(vsp1->dev,
162 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
163 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
164 rpf->entity.index);
165
166
167
168
169
170 format.pad = RWPF_PAD_SOURCE;
171
172 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
173 &format);
174 if (ret < 0)
175 return ret;
176
177 dev_dbg(vsp1->dev,
178 "%s: got format %ux%u (%x) on RPF%u source\n",
179 __func__, format.format.width, format.format.height,
180 format.format.code, rpf->entity.index);
181
182 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
183
184 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
185 &format);
186 if (ret < 0)
187 return ret;
188
189
190 ret = vsp1_du_insert_uif(vsp1, pipe, uif, &rpf->entity, RWPF_PAD_SOURCE,
191 pipe->brx, brx_input);
192 if (ret < 0)
193 return ret;
194
195
196 format.pad = brx_input;
197
198 ret = v4l2_subdev_call(&pipe->brx->subdev, pad, set_fmt, NULL,
199 &format);
200 if (ret < 0)
201 return ret;
202
203 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
204 __func__, format.format.width, format.format.height,
205 format.format.code, BRX_NAME(pipe->brx), format.pad);
206
207 sel.pad = brx_input;
208 sel.target = V4L2_SEL_TGT_COMPOSE;
209 sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
210
211 ret = v4l2_subdev_call(&pipe->brx->subdev, pad, set_selection, NULL,
212 &sel);
213 if (ret < 0)
214 return ret;
215
216 dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
217 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
218 BRX_NAME(pipe->brx), sel.pad);
219
220 return 0;
221}
222
223
224static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
225 struct vsp1_pipeline *pipe);
226static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe);
227
228static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
229 struct vsp1_pipeline *pipe)
230{
231 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
232 struct v4l2_subdev_format format = {
233 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
234 };
235 struct vsp1_entity *brx;
236 int ret;
237
238
239
240
241
242
243
244 if (pipe->num_inputs > 2)
245 brx = &vsp1->bru->entity;
246 else if (pipe->brx && !drm_pipe->force_brx_release)
247 brx = pipe->brx;
248 else if (vsp1_feature(vsp1, VSP1_HAS_BRU) && !vsp1->bru->entity.pipe)
249 brx = &vsp1->bru->entity;
250 else
251 brx = &vsp1->brs->entity;
252
253
254 if (brx != pipe->brx) {
255 struct vsp1_entity *released_brx = NULL;
256
257
258 if (pipe->brx) {
259 dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n",
260 __func__, pipe->lif->index,
261 BRX_NAME(pipe->brx));
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 released_brx = pipe->brx;
278
279 list_del(&pipe->brx->list_pipe);
280 pipe->brx->sink = NULL;
281 pipe->brx->pipe = NULL;
282 pipe->brx = NULL;
283 }
284
285
286
287
288
289 if (brx->pipe) {
290 struct vsp1_drm_pipeline *owner_pipe;
291
292 dev_dbg(vsp1->dev, "%s: pipe %u: waiting for %s\n",
293 __func__, pipe->lif->index, BRX_NAME(brx));
294
295 owner_pipe = to_vsp1_drm_pipeline(brx->pipe);
296 owner_pipe->force_brx_release = true;
297
298 vsp1_du_pipeline_setup_inputs(vsp1, &owner_pipe->pipe);
299 vsp1_du_pipeline_configure(&owner_pipe->pipe);
300
301 ret = wait_event_timeout(owner_pipe->wait_queue,
302 !owner_pipe->force_brx_release,
303 msecs_to_jiffies(500));
304 if (ret == 0)
305 dev_warn(vsp1->dev,
306 "DRM pipeline %u reconfiguration timeout\n",
307 owner_pipe->pipe.lif->index);
308 }
309
310
311
312
313
314
315
316 if (released_brx && !released_brx->pipe)
317 list_add_tail(&released_brx->list_pipe,
318 &pipe->entities);
319
320
321 dev_dbg(vsp1->dev, "%s: pipe %u: acquired %s\n",
322 __func__, pipe->lif->index, BRX_NAME(brx));
323
324 pipe->brx = brx;
325 pipe->brx->pipe = pipe;
326 pipe->brx->sink = &pipe->output->entity;
327 pipe->brx->sink_pad = 0;
328
329 list_add_tail(&pipe->brx->list_pipe, &pipe->entities);
330 }
331
332
333
334
335
336
337
338 format.pad = brx->source_pad;
339 format.format.width = drm_pipe->width;
340 format.format.height = drm_pipe->height;
341 format.format.field = V4L2_FIELD_NONE;
342
343 ret = v4l2_subdev_call(&brx->subdev, pad, set_fmt, NULL,
344 &format);
345 if (ret < 0)
346 return ret;
347
348 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
349 __func__, format.format.width, format.format.height,
350 format.format.code, BRX_NAME(brx), brx->source_pad);
351
352 if (format.format.width != drm_pipe->width ||
353 format.format.height != drm_pipe->height) {
354 dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
355 return -EPIPE;
356 }
357
358 return 0;
359}
360
361static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
362{
363 return vsp1->drm->inputs[rpf->entity.index].zpos;
364}
365
366
367static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
368 struct vsp1_pipeline *pipe)
369{
370 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
371 struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
372 struct vsp1_entity *uif;
373 bool use_uif = false;
374 struct vsp1_brx *brx;
375 unsigned int i;
376 int ret;
377
378
379 pipe->num_inputs = 0;
380
381 for (i = 0; i < vsp1->info->rpf_count; ++i) {
382 struct vsp1_rwpf *rpf = vsp1->rpf[i];
383 unsigned int j;
384
385 if (!pipe->inputs[i])
386 continue;
387
388
389 for (j = pipe->num_inputs++; j > 0; --j) {
390 if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
391 break;
392 inputs[j] = inputs[j-1];
393 }
394
395 inputs[j] = rpf;
396 }
397
398
399
400
401
402
403 ret = vsp1_du_pipeline_setup_brx(vsp1, pipe);
404 if (ret < 0) {
405 dev_err(vsp1->dev, "%s: failed to setup %s source\n", __func__,
406 BRX_NAME(pipe->brx));
407 return ret;
408 }
409
410 brx = to_brx(&pipe->brx->subdev);
411
412
413 for (i = 0; i < pipe->brx->source_pad; ++i) {
414 struct vsp1_rwpf *rpf = inputs[i];
415
416 if (!rpf) {
417 brx->inputs[i].rpf = NULL;
418 continue;
419 }
420
421 if (!rpf->entity.pipe) {
422 rpf->entity.pipe = pipe;
423 list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
424 }
425
426 brx->inputs[i].rpf = rpf;
427 rpf->brx_input = i;
428 rpf->entity.sink = pipe->brx;
429 rpf->entity.sink_pad = i;
430
431 dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
432 __func__, rpf->entity.index, BRX_NAME(pipe->brx), i);
433
434 uif = drm_pipe->crc.source == VSP1_DU_CRC_PLANE &&
435 drm_pipe->crc.index == i ? drm_pipe->uif : NULL;
436 if (uif)
437 use_uif = true;
438 ret = vsp1_du_pipeline_setup_rpf(vsp1, pipe, rpf, uif, i);
439 if (ret < 0) {
440 dev_err(vsp1->dev,
441 "%s: failed to setup RPF.%u\n",
442 __func__, rpf->entity.index);
443 return ret;
444 }
445 }
446
447
448 uif = drm_pipe->crc.source == VSP1_DU_CRC_OUTPUT ? drm_pipe->uif : NULL;
449 if (uif)
450 use_uif = true;
451 ret = vsp1_du_insert_uif(vsp1, pipe, uif,
452 pipe->brx, pipe->brx->source_pad,
453 &pipe->output->entity, 0);
454 if (ret < 0)
455 dev_err(vsp1->dev, "%s: failed to setup UIF after %s\n",
456 __func__, BRX_NAME(pipe->brx));
457
458
459 if (!drm_pipe->uif)
460 return 0;
461
462
463
464
465
466
467
468
469 if (!use_uif) {
470 drm_pipe->uif->pipe = NULL;
471 } else if (!drm_pipe->uif->pipe) {
472 drm_pipe->uif->pipe = pipe;
473 list_add_tail(&drm_pipe->uif->list_pipe, &pipe->entities);
474 }
475
476 return 0;
477}
478
479
480static int vsp1_du_pipeline_setup_output(struct vsp1_device *vsp1,
481 struct vsp1_pipeline *pipe)
482{
483 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
484 struct v4l2_subdev_format format = { 0, };
485 int ret;
486
487 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
488 format.pad = RWPF_PAD_SINK;
489 format.format.width = drm_pipe->width;
490 format.format.height = drm_pipe->height;
491 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
492 format.format.field = V4L2_FIELD_NONE;
493
494 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL,
495 &format);
496 if (ret < 0)
497 return ret;
498
499 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF%u sink\n",
500 __func__, format.format.width, format.format.height,
501 format.format.code, pipe->output->entity.index);
502
503 format.pad = RWPF_PAD_SOURCE;
504 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, get_fmt, NULL,
505 &format);
506 if (ret < 0)
507 return ret;
508
509 dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF%u source\n",
510 __func__, format.format.width, format.format.height,
511 format.format.code, pipe->output->entity.index);
512
513 format.pad = LIF_PAD_SINK;
514 ret = v4l2_subdev_call(&pipe->lif->subdev, pad, set_fmt, NULL,
515 &format);
516 if (ret < 0)
517 return ret;
518
519 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF%u sink\n",
520 __func__, format.format.width, format.format.height,
521 format.format.code, pipe->lif->index);
522
523
524
525
526
527 if (format.format.width != drm_pipe->width ||
528 format.format.height != drm_pipe->height ||
529 format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
530 dev_dbg(vsp1->dev, "%s: format mismatch on LIF%u\n", __func__,
531 pipe->lif->index);
532 return -EPIPE;
533 }
534
535 return 0;
536}
537
538
539static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
540{
541 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
542 struct vsp1_entity *entity;
543 struct vsp1_entity *next;
544 struct vsp1_dl_list *dl;
545 struct vsp1_dl_body *dlb;
546 unsigned int dl_flags = 0;
547
548 if (drm_pipe->force_brx_release)
549 dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
550 if (pipe->output->writeback)
551 dl_flags |= VSP1_DL_FRAME_END_WRITEBACK;
552
553 dl = vsp1_dl_list_get(pipe->output->dlm);
554 dlb = vsp1_dl_list_get_body0(dl);
555
556 list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
557
558 if (!entity->pipe) {
559 vsp1_dl_body_write(dlb, entity->route->reg,
560 VI6_DPR_NODE_UNUSED);
561
562 entity->sink = NULL;
563 list_del(&entity->list_pipe);
564
565 continue;
566 }
567
568 vsp1_entity_route_setup(entity, pipe, dlb);
569 vsp1_entity_configure_stream(entity, pipe, dl, dlb);
570 vsp1_entity_configure_frame(entity, pipe, dl, dlb);
571 vsp1_entity_configure_partition(entity, pipe, dl, dlb);
572 }
573
574 vsp1_dl_list_commit(dl, dl_flags);
575}
576
577static int vsp1_du_pipeline_set_rwpf_format(struct vsp1_device *vsp1,
578 struct vsp1_rwpf *rwpf,
579 u32 pixelformat, unsigned int pitch)
580{
581 const struct vsp1_format_info *fmtinfo;
582 unsigned int chroma_hsub;
583
584 fmtinfo = vsp1_get_format_info(vsp1, pixelformat);
585 if (!fmtinfo) {
586 dev_dbg(vsp1->dev, "Unsupported pixel format %08x\n",
587 pixelformat);
588 return -EINVAL;
589 }
590
591
592
593
594
595
596
597 chroma_hsub = (fmtinfo->planes == 3) ? fmtinfo->hsub : 1;
598
599 rwpf->fmtinfo = fmtinfo;
600 rwpf->format.num_planes = fmtinfo->planes;
601 rwpf->format.plane_fmt[0].bytesperline = pitch;
602 rwpf->format.plane_fmt[1].bytesperline = pitch / chroma_hsub;
603
604 return 0;
605}
606
607
608
609
610
611int vsp1_du_init(struct device *dev)
612{
613 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
614
615 if (!vsp1)
616 return -EPROBE_DEFER;
617
618 return 0;
619}
620EXPORT_SYMBOL_GPL(vsp1_du_init);
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
644 const struct vsp1_du_lif_config *cfg)
645{
646 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
647 struct vsp1_drm_pipeline *drm_pipe;
648 struct vsp1_pipeline *pipe;
649 unsigned long flags;
650 unsigned int i;
651 int ret;
652
653 if (pipe_index >= vsp1->info->lif_count)
654 return -EINVAL;
655
656 drm_pipe = &vsp1->drm->pipe[pipe_index];
657 pipe = &drm_pipe->pipe;
658
659 if (!cfg) {
660 struct vsp1_brx *brx;
661
662 mutex_lock(&vsp1->drm->lock);
663
664 brx = to_brx(&pipe->brx->subdev);
665
666
667
668
669
670 ret = vsp1_pipeline_stop(pipe);
671 if (ret == -ETIMEDOUT)
672 dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
673
674 for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
675 struct vsp1_rwpf *rpf = pipe->inputs[i];
676
677 if (!rpf)
678 continue;
679
680
681
682
683
684 WARN_ON(!rpf->entity.pipe);
685 rpf->entity.pipe = NULL;
686 list_del(&rpf->entity.list_pipe);
687 pipe->inputs[i] = NULL;
688
689 brx->inputs[rpf->brx_input].rpf = NULL;
690 }
691
692 drm_pipe->du_complete = NULL;
693 pipe->num_inputs = 0;
694
695 dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n",
696 __func__, pipe->lif->index,
697 BRX_NAME(pipe->brx));
698
699 list_del(&pipe->brx->list_pipe);
700 pipe->brx->pipe = NULL;
701 pipe->brx = NULL;
702
703 mutex_unlock(&vsp1->drm->lock);
704
705 vsp1_dlm_reset(pipe->output->dlm);
706 vsp1_device_put(vsp1);
707
708 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
709
710 return 0;
711 }
712
713 drm_pipe->width = cfg->width;
714 drm_pipe->height = cfg->height;
715 pipe->interlaced = cfg->interlaced;
716
717 dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u%s\n",
718 __func__, pipe_index, cfg->width, cfg->height,
719 pipe->interlaced ? "i" : "");
720
721 mutex_lock(&vsp1->drm->lock);
722
723
724 ret = vsp1_du_pipeline_setup_inputs(vsp1, pipe);
725 if (ret < 0)
726 goto unlock;
727
728 ret = vsp1_du_pipeline_setup_output(vsp1, pipe);
729 if (ret < 0)
730 goto unlock;
731
732
733 ret = vsp1_device_get(vsp1);
734 if (ret < 0)
735 goto unlock;
736
737
738
739
740
741 drm_pipe->du_complete = cfg->callback;
742 drm_pipe->du_private = cfg->callback_data;
743
744
745 vsp1_write(vsp1, VI6_DISP_IRQ_STA(pipe_index), 0);
746 vsp1_write(vsp1, VI6_DISP_IRQ_ENB(pipe_index), 0);
747
748
749 vsp1_du_pipeline_configure(pipe);
750
751unlock:
752 mutex_unlock(&vsp1->drm->lock);
753
754 if (ret < 0)
755 return ret;
756
757
758 spin_lock_irqsave(&pipe->irqlock, flags);
759 vsp1_pipeline_run(pipe);
760 spin_unlock_irqrestore(&pipe->irqlock, flags);
761
762 dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
763
764 return 0;
765}
766EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
767
768
769
770
771
772
773void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index)
774{
775}
776EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
809 unsigned int rpf_index,
810 const struct vsp1_du_atomic_config *cfg)
811{
812 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
813 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
814 struct vsp1_rwpf *rpf;
815 int ret;
816
817 if (rpf_index >= vsp1->info->rpf_count)
818 return -EINVAL;
819
820 rpf = vsp1->rpf[rpf_index];
821
822 if (!cfg) {
823 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
824 rpf_index);
825
826
827
828
829
830
831 rpf->entity.pipe = NULL;
832 drm_pipe->pipe.inputs[rpf_index] = NULL;
833 return 0;
834 }
835
836 dev_dbg(vsp1->dev,
837 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
838 __func__, rpf_index,
839 cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
840 cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
841 cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
842 &cfg->mem[2], cfg->zpos);
843
844
845
846
847
848 ret = vsp1_du_pipeline_set_rwpf_format(vsp1, rpf, cfg->pixelformat,
849 cfg->pitch);
850 if (ret < 0)
851 return ret;
852
853 rpf->alpha = cfg->alpha;
854
855 rpf->mem.addr[0] = cfg->mem[0];
856 rpf->mem.addr[1] = cfg->mem[1];
857 rpf->mem.addr[2] = cfg->mem[2];
858
859 vsp1->drm->inputs[rpf_index].crop = cfg->src;
860 vsp1->drm->inputs[rpf_index].compose = cfg->dst;
861 vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
862
863 drm_pipe->pipe.inputs[rpf_index] = rpf;
864
865 return 0;
866}
867EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
868
869
870
871
872
873
874
875void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
876 const struct vsp1_du_atomic_pipe_config *cfg)
877{
878 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
879 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
880 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
881 int ret;
882
883 drm_pipe->crc = cfg->crc;
884
885 mutex_lock(&vsp1->drm->lock);
886
887 if (cfg->writeback.pixelformat) {
888 const struct vsp1_du_writeback_config *wb_cfg = &cfg->writeback;
889
890 ret = vsp1_du_pipeline_set_rwpf_format(vsp1, pipe->output,
891 wb_cfg->pixelformat,
892 wb_cfg->pitch);
893 if (WARN_ON(ret < 0))
894 goto done;
895
896 pipe->output->mem.addr[0] = wb_cfg->mem[0];
897 pipe->output->mem.addr[1] = wb_cfg->mem[1];
898 pipe->output->mem.addr[2] = wb_cfg->mem[2];
899 pipe->output->writeback = true;
900 }
901
902 vsp1_du_pipeline_setup_inputs(vsp1, pipe);
903 vsp1_du_pipeline_configure(pipe);
904
905done:
906 mutex_unlock(&vsp1->drm->lock);
907}
908EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
909
910int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
911{
912 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
913
914
915
916
917
918
919 return dma_map_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
920 DMA_ATTR_SKIP_CPU_SYNC);
921}
922EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
923
924void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
925{
926 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
927
928 dma_unmap_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
929 DMA_ATTR_SKIP_CPU_SYNC);
930}
931EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
932
933
934
935
936
937int vsp1_drm_init(struct vsp1_device *vsp1)
938{
939 unsigned int i;
940
941 vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
942 if (!vsp1->drm)
943 return -ENOMEM;
944
945 mutex_init(&vsp1->drm->lock);
946
947
948 for (i = 0; i < vsp1->info->lif_count; ++i) {
949 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i];
950 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
951
952 init_waitqueue_head(&drm_pipe->wait_queue);
953
954 vsp1_pipeline_init(pipe);
955
956 pipe->frame_end = vsp1_du_pipeline_frame_end;
957
958
959
960
961
962 pipe->output = vsp1->wpf[i];
963 pipe->lif = &vsp1->lif[i]->entity;
964
965 pipe->output->entity.pipe = pipe;
966 pipe->output->entity.sink = pipe->lif;
967 pipe->output->entity.sink_pad = 0;
968 list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities);
969
970 pipe->lif->pipe = pipe;
971 list_add_tail(&pipe->lif->list_pipe, &pipe->entities);
972
973
974
975
976
977 if (i < vsp1->info->uif_count)
978 drm_pipe->uif = &vsp1->uif[i]->entity;
979 }
980
981
982 for (i = 0; i < vsp1->info->rpf_count; ++i) {
983 struct vsp1_rwpf *input = vsp1->rpf[i];
984
985 INIT_LIST_HEAD(&input->entity.list_pipe);
986 }
987
988 return 0;
989}
990
991void vsp1_drm_cleanup(struct vsp1_device *vsp1)
992{
993 mutex_destroy(&vsp1->drm->lock);
994}
995