1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/device.h>
15#include <linux/dma-mapping.h>
16#include <linux/slab.h>
17
18#include <media/media-entity.h>
19#include <media/v4l2-subdev.h>
20#include <media/vsp1.h>
21
22#include "vsp1.h"
23#include "vsp1_bru.h"
24#include "vsp1_dl.h"
25#include "vsp1_drm.h"
26#include "vsp1_lif.h"
27#include "vsp1_pipe.h"
28#include "vsp1_rwpf.h"
29
30#define BRU_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"
31
32
33
34
35
36static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
37 bool completed)
38{
39 struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
40
41 if (drm_pipe->du_complete)
42 drm_pipe->du_complete(drm_pipe->du_private, completed);
43}
44
45
46
47
48
49int vsp1_du_init(struct device *dev)
50{
51 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
52
53 if (!vsp1)
54 return -EPROBE_DEFER;
55
56 return 0;
57}
58EXPORT_SYMBOL_GPL(vsp1_du_init);
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
82 const struct vsp1_du_lif_config *cfg)
83{
84 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
85 struct vsp1_drm_pipeline *drm_pipe;
86 struct vsp1_pipeline *pipe;
87 struct vsp1_bru *bru;
88 struct vsp1_entity *entity;
89 struct vsp1_entity *next;
90 struct vsp1_dl_list *dl;
91 struct v4l2_subdev_format format;
92 unsigned long flags;
93 unsigned int i;
94 int ret;
95
96 if (pipe_index >= vsp1->info->lif_count)
97 return -EINVAL;
98
99 drm_pipe = &vsp1->drm->pipe[pipe_index];
100 pipe = &drm_pipe->pipe;
101 bru = to_bru(&pipe->bru->subdev);
102
103 if (!cfg) {
104
105
106
107
108 ret = vsp1_pipeline_stop(pipe);
109 if (ret == -ETIMEDOUT)
110 dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
111
112 media_pipeline_stop(&pipe->output->entity.subdev.entity);
113
114 for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
115 struct vsp1_rwpf *rpf = pipe->inputs[i];
116
117 if (!rpf)
118 continue;
119
120
121
122
123
124 WARN_ON(list_empty(&rpf->entity.list_pipe));
125 list_del_init(&rpf->entity.list_pipe);
126 pipe->inputs[i] = NULL;
127
128 bru->inputs[rpf->bru_input].rpf = NULL;
129 }
130
131 drm_pipe->du_complete = NULL;
132 pipe->num_inputs = 0;
133
134 vsp1_dlm_reset(pipe->output->dlm);
135 vsp1_device_put(vsp1);
136
137 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
138
139 return 0;
140 }
141
142 dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u\n",
143 __func__, pipe_index, cfg->width, cfg->height);
144
145
146
147
148
149 memset(&format, 0, sizeof(format));
150 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
151
152 for (i = 0; i < pipe->bru->source_pad; ++i) {
153 format.pad = i;
154
155 format.format.width = cfg->width;
156 format.format.height = cfg->height;
157 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
158 format.format.field = V4L2_FIELD_NONE;
159
160 ret = v4l2_subdev_call(&pipe->bru->subdev, pad,
161 set_fmt, NULL, &format);
162 if (ret < 0)
163 return ret;
164
165 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
166 __func__, format.format.width, format.format.height,
167 format.format.code, BRU_NAME(pipe->bru), i);
168 }
169
170 format.pad = pipe->bru->source_pad;
171 format.format.width = cfg->width;
172 format.format.height = cfg->height;
173 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
174 format.format.field = V4L2_FIELD_NONE;
175
176 ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
177 &format);
178 if (ret < 0)
179 return ret;
180
181 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
182 __func__, format.format.width, format.format.height,
183 format.format.code, BRU_NAME(pipe->bru), i);
184
185 format.pad = RWPF_PAD_SINK;
186 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL,
187 &format);
188 if (ret < 0)
189 return ret;
190
191 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF%u sink\n",
192 __func__, format.format.width, format.format.height,
193 format.format.code, pipe->output->entity.index);
194
195 format.pad = RWPF_PAD_SOURCE;
196 ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, get_fmt, NULL,
197 &format);
198 if (ret < 0)
199 return ret;
200
201 dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF%u source\n",
202 __func__, format.format.width, format.format.height,
203 format.format.code, pipe->output->entity.index);
204
205 format.pad = LIF_PAD_SINK;
206 ret = v4l2_subdev_call(&pipe->lif->subdev, pad, set_fmt, NULL,
207 &format);
208 if (ret < 0)
209 return ret;
210
211 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF%u sink\n",
212 __func__, format.format.width, format.format.height,
213 format.format.code, pipe_index);
214
215
216
217
218
219 if (format.format.width != cfg->width ||
220 format.format.height != cfg->height ||
221 format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
222 dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
223 return -EPIPE;
224 }
225
226
227
228
229
230
231
232
233 ret = vsp1_device_get(vsp1);
234 if (ret < 0)
235 return ret;
236
237
238
239
240
241 drm_pipe->du_complete = cfg->callback;
242 drm_pipe->du_private = cfg->callback_data;
243
244 ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
245 &pipe->pipe);
246 if (ret < 0) {
247 dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
248 vsp1_device_put(vsp1);
249 return ret;
250 }
251
252
253 vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
254 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
255
256
257 dl = vsp1_dl_list_get(pipe->output->dlm);
258
259 list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
260 vsp1_entity_route_setup(entity, pipe, dl);
261
262 if (entity->ops->configure) {
263 entity->ops->configure(entity, pipe, dl,
264 VSP1_ENTITY_PARAMS_INIT);
265 entity->ops->configure(entity, pipe, dl,
266 VSP1_ENTITY_PARAMS_RUNTIME);
267 entity->ops->configure(entity, pipe, dl,
268 VSP1_ENTITY_PARAMS_PARTITION);
269 }
270 }
271
272 vsp1_dl_list_commit(dl);
273
274
275 spin_lock_irqsave(&pipe->irqlock, flags);
276 vsp1_pipeline_run(pipe);
277 spin_unlock_irqrestore(&pipe->irqlock, flags);
278
279 dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
280
281 return 0;
282}
283EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
284
285
286
287
288
289
290void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index)
291{
292 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
293 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
294
295 drm_pipe->enabled = drm_pipe->pipe.num_inputs != 0;
296}
297EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
330 unsigned int rpf_index,
331 const struct vsp1_du_atomic_config *cfg)
332{
333 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
334 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
335 const struct vsp1_format_info *fmtinfo;
336 struct vsp1_rwpf *rpf;
337
338 if (rpf_index >= vsp1->info->rpf_count)
339 return -EINVAL;
340
341 rpf = vsp1->rpf[rpf_index];
342
343 if (!cfg) {
344 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
345 rpf_index);
346
347
348
349
350
351
352 drm_pipe->pipe.inputs[rpf_index] = NULL;
353 return 0;
354 }
355
356 dev_dbg(vsp1->dev,
357 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
358 __func__, rpf_index,
359 cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
360 cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
361 cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
362 &cfg->mem[2], cfg->zpos);
363
364
365
366
367
368 fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat);
369 if (!fmtinfo) {
370 dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
371 cfg->pixelformat);
372 return -EINVAL;
373 }
374
375 rpf->fmtinfo = fmtinfo;
376 rpf->format.num_planes = fmtinfo->planes;
377 rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
378 rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
379 rpf->alpha = cfg->alpha;
380
381 rpf->mem.addr[0] = cfg->mem[0];
382 rpf->mem.addr[1] = cfg->mem[1];
383 rpf->mem.addr[2] = cfg->mem[2];
384
385 vsp1->drm->inputs[rpf_index].crop = cfg->src;
386 vsp1->drm->inputs[rpf_index].compose = cfg->dst;
387 vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
388
389 drm_pipe->pipe.inputs[rpf_index] = rpf;
390
391 return 0;
392}
393EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
394
395static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
396 struct vsp1_pipeline *pipe,
397 struct vsp1_rwpf *rpf, unsigned int bru_input)
398{
399 struct v4l2_subdev_selection sel;
400 struct v4l2_subdev_format format;
401 const struct v4l2_rect *crop;
402 int ret;
403
404
405
406
407
408 crop = &vsp1->drm->inputs[rpf->entity.index].crop;
409
410 memset(&format, 0, sizeof(format));
411 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
412 format.pad = RWPF_PAD_SINK;
413 format.format.width = crop->width + crop->left;
414 format.format.height = crop->height + crop->top;
415 format.format.code = rpf->fmtinfo->mbus;
416 format.format.field = V4L2_FIELD_NONE;
417
418 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
419 &format);
420 if (ret < 0)
421 return ret;
422
423 dev_dbg(vsp1->dev,
424 "%s: set format %ux%u (%x) on RPF%u sink\n",
425 __func__, format.format.width, format.format.height,
426 format.format.code, rpf->entity.index);
427
428 memset(&sel, 0, sizeof(sel));
429 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
430 sel.pad = RWPF_PAD_SINK;
431 sel.target = V4L2_SEL_TGT_CROP;
432 sel.r = *crop;
433
434 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
435 &sel);
436 if (ret < 0)
437 return ret;
438
439 dev_dbg(vsp1->dev,
440 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
441 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
442 rpf->entity.index);
443
444
445
446
447
448 format.pad = RWPF_PAD_SOURCE;
449
450 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
451 &format);
452 if (ret < 0)
453 return ret;
454
455 dev_dbg(vsp1->dev,
456 "%s: got format %ux%u (%x) on RPF%u source\n",
457 __func__, format.format.width, format.format.height,
458 format.format.code, rpf->entity.index);
459
460 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
461
462 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
463 &format);
464 if (ret < 0)
465 return ret;
466
467
468 format.pad = bru_input;
469
470 ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
471 &format);
472 if (ret < 0)
473 return ret;
474
475 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
476 __func__, format.format.width, format.format.height,
477 format.format.code, BRU_NAME(pipe->bru), format.pad);
478
479 sel.pad = bru_input;
480 sel.target = V4L2_SEL_TGT_COMPOSE;
481 sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
482
483 ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_selection, NULL,
484 &sel);
485 if (ret < 0)
486 return ret;
487
488 dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
489 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
490 BRU_NAME(pipe->bru), sel.pad);
491
492 return 0;
493}
494
495static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
496{
497 return vsp1->drm->inputs[rpf->entity.index].zpos;
498}
499
500
501
502
503
504
505void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
506{
507 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
508 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
509 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
510 struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
511 struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
512 struct vsp1_entity *entity;
513 struct vsp1_entity *next;
514 struct vsp1_dl_list *dl;
515 unsigned int i;
516 int ret;
517
518
519 dl = vsp1_dl_list_get(pipe->output->dlm);
520
521
522 pipe->num_inputs = 0;
523
524 for (i = 0; i < vsp1->info->rpf_count; ++i) {
525 struct vsp1_rwpf *rpf = vsp1->rpf[i];
526 unsigned int j;
527
528
529
530
531
532
533
534 if (pipe->num_inputs >= pipe->bru->source_pad)
535 pipe->inputs[i] = NULL;
536
537 if (!pipe->inputs[i])
538 continue;
539
540
541 for (j = pipe->num_inputs++; j > 0; --j) {
542 if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
543 break;
544 inputs[j] = inputs[j-1];
545 }
546
547 inputs[j] = rpf;
548 }
549
550
551 for (i = 0; i < pipe->bru->source_pad; ++i) {
552 struct vsp1_rwpf *rpf = inputs[i];
553
554 if (!rpf) {
555 bru->inputs[i].rpf = NULL;
556 continue;
557 }
558
559 if (list_empty(&rpf->entity.list_pipe))
560 list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
561
562 bru->inputs[i].rpf = rpf;
563 rpf->bru_input = i;
564 rpf->entity.sink = pipe->bru;
565 rpf->entity.sink_pad = i;
566
567 dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
568 __func__, rpf->entity.index, BRU_NAME(pipe->bru), i);
569
570 ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i);
571 if (ret < 0)
572 dev_err(vsp1->dev,
573 "%s: failed to setup RPF.%u\n",
574 __func__, rpf->entity.index);
575 }
576
577
578 list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
579
580 if (entity->type == VSP1_ENTITY_RPF &&
581 !pipe->inputs[entity->index]) {
582 vsp1_dl_list_write(dl, entity->route->reg,
583 VI6_DPR_NODE_UNUSED);
584
585 list_del_init(&entity->list_pipe);
586
587 continue;
588 }
589
590 vsp1_entity_route_setup(entity, pipe, dl);
591
592 if (entity->ops->configure) {
593 entity->ops->configure(entity, pipe, dl,
594 VSP1_ENTITY_PARAMS_INIT);
595 entity->ops->configure(entity, pipe, dl,
596 VSP1_ENTITY_PARAMS_RUNTIME);
597 entity->ops->configure(entity, pipe, dl,
598 VSP1_ENTITY_PARAMS_PARTITION);
599 }
600 }
601
602 vsp1_dl_list_commit(dl);
603}
604EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
605
606int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
607{
608 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
609
610
611
612
613
614
615 return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
616 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
617}
618EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
619
620void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
621{
622 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
623
624 dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
625 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
626}
627EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
628
629
630
631
632
633int vsp1_drm_init(struct vsp1_device *vsp1)
634{
635 unsigned int i;
636
637 vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
638 if (!vsp1->drm)
639 return -ENOMEM;
640
641
642 for (i = 0; i < vsp1->info->lif_count; ++i) {
643 struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i];
644 struct vsp1_pipeline *pipe = &drm_pipe->pipe;
645
646 vsp1_pipeline_init(pipe);
647
648
649
650
651
652 pipe->bru = i == 0 ? &vsp1->bru->entity : &vsp1->brs->entity;
653 pipe->lif = &vsp1->lif[i]->entity;
654 pipe->output = vsp1->wpf[i];
655 pipe->output->pipe = pipe;
656 pipe->frame_end = vsp1_du_pipeline_frame_end;
657
658 pipe->bru->sink = &pipe->output->entity;
659 pipe->bru->sink_pad = 0;
660 pipe->output->entity.sink = pipe->lif;
661 pipe->output->entity.sink_pad = 0;
662
663 list_add_tail(&pipe->bru->list_pipe, &pipe->entities);
664 list_add_tail(&pipe->lif->list_pipe, &pipe->entities);
665 list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities);
666 }
667
668
669 for (i = 0; i < vsp1->info->rpf_count; ++i) {
670 struct vsp1_rwpf *input = vsp1->rpf[i];
671
672 INIT_LIST_HEAD(&input->entity.list_pipe);
673 }
674
675 return 0;
676}
677
678void vsp1_drm_cleanup(struct vsp1_device *vsp1)
679{
680}
681