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->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
460
461
462
463
464
465 if (!use_uif) {
466 drm_pipe->uif->pipe = NULL;
467 } else if (!drm_pipe->uif->pipe) {
468 drm_pipe->uif->pipe = pipe;
469 list_add_tail(&drm_pipe->uif->list_pipe, &pipe->entities);
470 }
471
472 return 0;
473}
474
475
476static int vsp1_du_pipeline_setup_output(struct vsp1_device *vsp1,
477 struct vsp1_pipeline *pipe)
478{
479 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
480 struct v4l2_subdev_format format = { 0, };
481 int ret;
482
483 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
484 format.pad = RWPF_PAD_SINK;
485 format.format.width = drm_pipe->width;
486 format.format.height = drm_pipe->height;
487 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
488 format.format.field = V4L2_FIELD_NONE;
489
490 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL,
491 &format);
492 if (ret < 0)
493 return ret;
494
495 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF%u sink\n",
496 __func__, format.format.width, format.format.height,
497 format.format.code, pipe->output->entity.index);
498
499 format.pad = RWPF_PAD_SOURCE;
500 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, get_fmt, NULL,
501 &format);
502 if (ret < 0)
503 return ret;
504
505 dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF%u source\n",
506 __func__, format.format.width, format.format.height,
507 format.format.code, pipe->output->entity.index);
508
509 format.pad = LIF_PAD_SINK;
510 ret = v4l2_subdev_call(&pipe->lif->subdev, pad, set_fmt, NULL,
511 &format);
512 if (ret < 0)
513 return ret;
514
515 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF%u sink\n",
516 __func__, format.format.width, format.format.height,
517 format.format.code, pipe->lif->index);
518
519
520
521
522
523 if (format.format.width != drm_pipe->width ||
524 format.format.height != drm_pipe->height ||
525 format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
526 dev_dbg(vsp1->dev, "%s: format mismatch on LIF%u\n", __func__,
527 pipe->lif->index);
528 return -EPIPE;
529 }
530
531 return 0;
532}
533
534
535static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
536{
537 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
538 struct vsp1_entity *entity;
539 struct vsp1_entity *next;
540 struct vsp1_dl_list *dl;
541 struct vsp1_dl_body *dlb;
542 unsigned int dl_flags = 0;
543
544 if (drm_pipe->force_brx_release)
545 dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
546 if (pipe->output->writeback)
547 dl_flags |= VSP1_DL_FRAME_END_WRITEBACK;
548
549 dl = vsp1_dl_list_get(pipe->output->dlm);
550 dlb = vsp1_dl_list_get_body0(dl);
551
552 list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
553
554 if (!entity->pipe) {
555 vsp1_dl_body_write(dlb, entity->route->reg,
556 VI6_DPR_NODE_UNUSED);
557
558 entity->sink = NULL;
559 list_del(&entity->list_pipe);
560
561 continue;
562 }
563
564 vsp1_entity_route_setup(entity, pipe, dlb);
565 vsp1_entity_configure_stream(entity, pipe, dl, dlb);
566 vsp1_entity_configure_frame(entity, pipe, dl, dlb);
567 vsp1_entity_configure_partition(entity, pipe, dl, dlb);
568 }
569
570 vsp1_dl_list_commit(dl, dl_flags);
571}
572
573static int vsp1_du_pipeline_set_rwpf_format(struct vsp1_device *vsp1,
574 struct vsp1_rwpf *rwpf,
575 u32 pixelformat, unsigned int pitch)
576{
577 const struct vsp1_format_info *fmtinfo;
578 unsigned int chroma_hsub;
579
580 fmtinfo = vsp1_get_format_info(vsp1, pixelformat);
581 if (!fmtinfo) {
582 dev_dbg(vsp1->dev, "Unsupported pixel format %08x\n",
583 pixelformat);
584 return -EINVAL;
585 }
586
587
588
589
590
591
592
593 chroma_hsub = (fmtinfo->planes == 3) ? fmtinfo->hsub : 1;
594
595 rwpf->fmtinfo = fmtinfo;
596 rwpf->format.num_planes = fmtinfo->planes;
597 rwpf->format.plane_fmt[0].bytesperline = pitch;
598 rwpf->format.plane_fmt[1].bytesperline = pitch / chroma_hsub;
599
600 return 0;
601}
602
603
604
605
606
607int vsp1_du_init(struct device *dev)
608{
609 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
610
611 if (!vsp1)
612 return -EPROBE_DEFER;
613
614 return 0;
615}
616EXPORT_SYMBOL_GPL(vsp1_du_init);
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
640 const struct vsp1_du_lif_config *cfg)
641{
642 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
643 struct vsp1_drm_pipeline *drm_pipe;
644 struct vsp1_pipeline *pipe;
645 unsigned long flags;
646 unsigned int i;
647 int ret;
648
649 if (pipe_index >= vsp1->info->lif_count)
650 return -EINVAL;
651
652 drm_pipe = &vsp1->drm->pipe[pipe_index];
653 pipe = &drm_pipe->pipe;
654
655 if (!cfg) {
656 struct vsp1_brx *brx;
657
658 mutex_lock(&vsp1->drm->lock);
659
660 brx = to_brx(&pipe->brx->subdev);
661
662
663
664
665
666 ret = vsp1_pipeline_stop(pipe);
667 if (ret == -ETIMEDOUT)
668 dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
669
670 for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
671 struct vsp1_rwpf *rpf = pipe->inputs[i];
672
673 if (!rpf)
674 continue;
675
676
677
678
679
680 WARN_ON(!rpf->entity.pipe);
681 rpf->entity.pipe = NULL;
682 list_del(&rpf->entity.list_pipe);
683 pipe->inputs[i] = NULL;
684
685 brx->inputs[rpf->brx_input].rpf = NULL;
686 }
687
688 drm_pipe->du_complete = NULL;
689 pipe->num_inputs = 0;
690
691 dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n",
692 __func__, pipe->lif->index,
693 BRX_NAME(pipe->brx));
694
695 list_del(&pipe->brx->list_pipe);
696 pipe->brx->pipe = NULL;
697 pipe->brx = NULL;
698
699 mutex_unlock(&vsp1->drm->lock);
700
701 vsp1_dlm_reset(pipe->output->dlm);
702 vsp1_device_put(vsp1);
703
704 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
705
706 return 0;
707 }
708
709 drm_pipe->width = cfg->width;
710 drm_pipe->height = cfg->height;
711 pipe->interlaced = cfg->interlaced;
712
713 dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u%s\n",
714 __func__, pipe_index, cfg->width, cfg->height,
715 pipe->interlaced ? "i" : "");
716
717 mutex_lock(&vsp1->drm->lock);
718
719
720 ret = vsp1_du_pipeline_setup_inputs(vsp1, pipe);
721 if (ret < 0)
722 goto unlock;
723
724 ret = vsp1_du_pipeline_setup_output(vsp1, pipe);
725 if (ret < 0)
726 goto unlock;
727
728
729 ret = vsp1_device_get(vsp1);
730 if (ret < 0)
731 goto unlock;
732
733
734
735
736
737 drm_pipe->du_complete = cfg->callback;
738 drm_pipe->du_private = cfg->callback_data;
739
740
741 vsp1_write(vsp1, VI6_DISP_IRQ_STA(pipe_index), 0);
742 vsp1_write(vsp1, VI6_DISP_IRQ_ENB(pipe_index), 0);
743
744
745 vsp1_du_pipeline_configure(pipe);
746
747unlock:
748 mutex_unlock(&vsp1->drm->lock);
749
750 if (ret < 0)
751 return ret;
752
753
754 spin_lock_irqsave(&pipe->irqlock, flags);
755 vsp1_pipeline_run(pipe);
756 spin_unlock_irqrestore(&pipe->irqlock, flags);
757
758 dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
759
760 return 0;
761}
762EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
763
764
765
766
767
768
769void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index)
770{
771}
772EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
773
774
775
776
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
804int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
805 unsigned int rpf_index,
806 const struct vsp1_du_atomic_config *cfg)
807{
808 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
809 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
810 struct vsp1_rwpf *rpf;
811 int ret;
812
813 if (rpf_index >= vsp1->info->rpf_count)
814 return -EINVAL;
815
816 rpf = vsp1->rpf[rpf_index];
817
818 if (!cfg) {
819 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
820 rpf_index);
821
822
823
824
825
826
827 rpf->entity.pipe = NULL;
828 drm_pipe->pipe.inputs[rpf_index] = NULL;
829 return 0;
830 }
831
832 dev_dbg(vsp1->dev,
833 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
834 __func__, rpf_index,
835 cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
836 cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
837 cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
838 &cfg->mem[2], cfg->zpos);
839
840
841
842
843
844 ret = vsp1_du_pipeline_set_rwpf_format(vsp1, rpf, cfg->pixelformat,
845 cfg->pitch);
846 if (ret < 0)
847 return ret;
848
849 rpf->alpha = cfg->alpha;
850
851 rpf->mem.addr[0] = cfg->mem[0];
852 rpf->mem.addr[1] = cfg->mem[1];
853 rpf->mem.addr[2] = cfg->mem[2];
854
855 vsp1->drm->inputs[rpf_index].crop = cfg->src;
856 vsp1->drm->inputs[rpf_index].compose = cfg->dst;
857 vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
858
859 drm_pipe->pipe.inputs[rpf_index] = rpf;
860
861 return 0;
862}
863EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
864
865
866
867
868
869
870
871void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
872 const struct vsp1_du_atomic_pipe_config *cfg)
873{
874 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
875 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
876 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
877 int ret;
878
879 drm_pipe->crc = cfg->crc;
880
881 mutex_lock(&vsp1->drm->lock);
882
883 if (cfg->writeback.pixelformat) {
884 const struct vsp1_du_writeback_config *wb_cfg = &cfg->writeback;
885
886 ret = vsp1_du_pipeline_set_rwpf_format(vsp1, pipe->output,
887 wb_cfg->pixelformat,
888 wb_cfg->pitch);
889 if (WARN_ON(ret < 0))
890 goto done;
891
892 pipe->output->mem.addr[0] = wb_cfg->mem[0];
893 pipe->output->mem.addr[1] = wb_cfg->mem[1];
894 pipe->output->mem.addr[2] = wb_cfg->mem[2];
895 pipe->output->writeback = true;
896 }
897
898 vsp1_du_pipeline_setup_inputs(vsp1, pipe);
899 vsp1_du_pipeline_configure(pipe);
900
901done:
902 mutex_unlock(&vsp1->drm->lock);
903}
904EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
905
906int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
907{
908 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
909
910
911
912
913
914
915 return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
916 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
917}
918EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
919
920void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
921{
922 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
923
924 dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
925 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
926}
927EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
928
929
930
931
932
933int vsp1_drm_init(struct vsp1_device *vsp1)
934{
935 unsigned int i;
936
937 vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
938 if (!vsp1->drm)
939 return -ENOMEM;
940
941 mutex_init(&vsp1->drm->lock);
942
943
944 for (i = 0; i < vsp1->info->lif_count; ++i) {
945 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i];
946 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
947
948 init_waitqueue_head(&drm_pipe->wait_queue);
949
950 vsp1_pipeline_init(pipe);
951
952 pipe->frame_end = vsp1_du_pipeline_frame_end;
953
954
955
956
957
958 pipe->output = vsp1->wpf[i];
959 pipe->lif = &vsp1->lif[i]->entity;
960
961 pipe->output->entity.pipe = pipe;
962 pipe->output->entity.sink = pipe->lif;
963 pipe->output->entity.sink_pad = 0;
964 list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities);
965
966 pipe->lif->pipe = pipe;
967 list_add_tail(&pipe->lif->list_pipe, &pipe->entities);
968
969
970
971
972
973 if (i < vsp1->info->uif_count)
974 drm_pipe->uif = &vsp1->uif[i]->entity;
975 }
976
977
978 for (i = 0; i < vsp1->info->rpf_count; ++i) {
979 struct vsp1_rwpf *input = vsp1->rpf[i];
980
981 INIT_LIST_HEAD(&input->entity.list_pipe);
982 }
983
984 return 0;
985}
986
987void vsp1_drm_cleanup(struct vsp1_device *vsp1)
988{
989 mutex_destroy(&vsp1->drm->lock);
990}
991