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