]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/media/platform/vsp1/vsp1_drm.c
UBUNTU: Ubuntu-4.13.0-45.50
[mirror_ubuntu-artful-kernel.git] / drivers / media / platform / vsp1 / vsp1_drm.c
1 /*
2 * vsp1_drm.c -- R-Car VSP1 DRM API
3 *
4 * Copyright (C) 2015 Renesas Electronics Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
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
31 /* -----------------------------------------------------------------------------
32 * Interrupt Handling
33 */
34
35 void vsp1_drm_display_start(struct vsp1_device *vsp1)
36 {
37 vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
38 }
39
40 static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe)
41 {
42 struct vsp1_drm *drm = to_vsp1_drm(pipe);
43
44 if (drm->du_complete)
45 drm->du_complete(drm->du_private);
46 }
47
48 /* -----------------------------------------------------------------------------
49 * DU Driver API
50 */
51
52 int vsp1_du_init(struct device *dev)
53 {
54 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
55
56 if (!vsp1)
57 return -EPROBE_DEFER;
58
59 return 0;
60 }
61 EXPORT_SYMBOL_GPL(vsp1_du_init);
62
63 /**
64 * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
65 * @dev: the VSP device
66 * @cfg: the LIF configuration
67 *
68 * Configure the output part of VSP DRM pipeline for the given frame @cfg.width
69 * and @cfg.height. This sets up formats on the BRU source pad, the WPF0 sink
70 * and source pads, and the LIF sink pad.
71 *
72 * As the media bus code on the BRU source pad is conditioned by the
73 * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
74 * sinks, even if the configuration will be overwritten later by
75 * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well
76 * defined state.
77 *
78 * Return 0 on success or a negative error code on failure.
79 */
80 int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg)
81 {
82 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
83 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
84 struct vsp1_bru *bru = vsp1->bru;
85 struct v4l2_subdev_format format;
86 unsigned int i;
87 int ret;
88
89 if (!cfg) {
90 /*
91 * NULL configuration means the CRTC is being disabled, stop
92 * the pipeline and turn the light off.
93 */
94 ret = vsp1_pipeline_stop(pipe);
95 if (ret == -ETIMEDOUT)
96 dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
97
98 media_pipeline_stop(&pipe->output->entity.subdev.entity);
99
100 for (i = 0; i < bru->entity.source_pad; ++i) {
101 vsp1->drm->inputs[i].enabled = false;
102 bru->inputs[i].rpf = NULL;
103 pipe->inputs[i] = NULL;
104 }
105
106 pipe->num_inputs = 0;
107 vsp1->drm->du_complete = NULL;
108
109 vsp1_dlm_reset(pipe->output->dlm);
110 vsp1_device_put(vsp1);
111
112 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
113
114 return 0;
115 }
116
117 dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n",
118 __func__, cfg->width, cfg->height);
119
120 /*
121 * Configure the format at the BRU sinks and propagate it through the
122 * pipeline.
123 */
124 memset(&format, 0, sizeof(format));
125 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
126
127 for (i = 0; i < bru->entity.source_pad; ++i) {
128 format.pad = i;
129
130 format.format.width = cfg->width;
131 format.format.height = cfg->height;
132 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
133 format.format.field = V4L2_FIELD_NONE;
134
135 ret = v4l2_subdev_call(&bru->entity.subdev, pad,
136 set_fmt, NULL, &format);
137 if (ret < 0)
138 return ret;
139
140 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
141 __func__, format.format.width, format.format.height,
142 format.format.code, i);
143 }
144
145 format.pad = bru->entity.source_pad;
146 format.format.width = cfg->width;
147 format.format.height = cfg->height;
148 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
149 format.format.field = V4L2_FIELD_NONE;
150
151 ret = v4l2_subdev_call(&bru->entity.subdev, pad, set_fmt, NULL,
152 &format);
153 if (ret < 0)
154 return ret;
155
156 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
157 __func__, format.format.width, format.format.height,
158 format.format.code, i);
159
160 format.pad = RWPF_PAD_SINK;
161 ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, set_fmt, NULL,
162 &format);
163 if (ret < 0)
164 return ret;
165
166 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF0 sink\n",
167 __func__, format.format.width, format.format.height,
168 format.format.code);
169
170 format.pad = RWPF_PAD_SOURCE;
171 ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, get_fmt, NULL,
172 &format);
173 if (ret < 0)
174 return ret;
175
176 dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF0 source\n",
177 __func__, format.format.width, format.format.height,
178 format.format.code);
179
180 format.pad = LIF_PAD_SINK;
181 ret = v4l2_subdev_call(&vsp1->lif->entity.subdev, pad, set_fmt, NULL,
182 &format);
183 if (ret < 0)
184 return ret;
185
186 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF sink\n",
187 __func__, format.format.width, format.format.height,
188 format.format.code);
189
190 /*
191 * Verify that the format at the output of the pipeline matches the
192 * requested frame size and media bus code.
193 */
194 if (format.format.width != cfg->width ||
195 format.format.height != cfg->height ||
196 format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
197 dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
198 return -EPIPE;
199 }
200
201 /*
202 * Mark the pipeline as streaming and enable the VSP1. This will store
203 * the pipeline pointer in all entities, which the s_stream handlers
204 * will need. We don't start the entities themselves right at this point
205 * as there's no plane configured yet, so we can't start processing
206 * buffers.
207 */
208 ret = vsp1_device_get(vsp1);
209 if (ret < 0)
210 return ret;
211
212 /*
213 * Register a callback to allow us to notify the DRM driver of frame
214 * completion events.
215 */
216 vsp1->drm->du_complete = cfg->callback;
217 vsp1->drm->du_private = cfg->callback_data;
218
219 ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
220 &pipe->pipe);
221 if (ret < 0) {
222 dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
223 vsp1_device_put(vsp1);
224 return ret;
225 }
226
227 dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
228
229 return 0;
230 }
231 EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
232
233 /**
234 * vsp1_du_atomic_begin - Prepare for an atomic update
235 * @dev: the VSP device
236 */
237 void vsp1_du_atomic_begin(struct device *dev)
238 {
239 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
240 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
241
242 vsp1->drm->num_inputs = pipe->num_inputs;
243 }
244 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
245
246 /**
247 * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
248 * @dev: the VSP device
249 * @rpf_index: index of the RPF to setup (0-based)
250 * @cfg: the RPF configuration
251 *
252 * Configure the VSP to perform image composition through RPF @rpf_index as
253 * described by the @cfg configuration. The image to compose is referenced by
254 * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst
255 * composition rectangle. The Z-order is configurable with higher @zpos values
256 * displayed on top.
257 *
258 * If the @cfg configuration is NULL, the RPF will be disabled. Calling the
259 * function on a disabled RPF is allowed.
260 *
261 * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat
262 * value. The memory pitch is configurable to allow for padding at end of lines,
263 * or simply for images that extend beyond the crop rectangle boundaries. The
264 * @cfg.pitch value is expressed in bytes and applies to all planes for
265 * multiplanar formats.
266 *
267 * The source memory buffer is referenced by the DMA address of its planes in
268 * the @cfg.mem array. Up to two planes are supported. The second plane DMA
269 * address is ignored for formats using a single plane.
270 *
271 * This function isn't reentrant, the caller needs to serialize calls.
272 *
273 * Return 0 on success or a negative error code on failure.
274 */
275 int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
276 const struct vsp1_du_atomic_config *cfg)
277 {
278 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
279 const struct vsp1_format_info *fmtinfo;
280 struct vsp1_rwpf *rpf;
281
282 if (rpf_index >= vsp1->info->rpf_count)
283 return -EINVAL;
284
285 rpf = vsp1->rpf[rpf_index];
286
287 if (!cfg) {
288 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
289 rpf_index);
290
291 vsp1->drm->inputs[rpf_index].enabled = false;
292 return 0;
293 }
294
295 dev_dbg(vsp1->dev,
296 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
297 __func__, rpf_index,
298 cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
299 cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
300 cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
301 &cfg->mem[2], cfg->zpos);
302
303 /*
304 * Store the format, stride, memory buffer address, crop and compose
305 * rectangles and Z-order position and for the input.
306 */
307 fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat);
308 if (!fmtinfo) {
309 dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
310 cfg->pixelformat);
311 return -EINVAL;
312 }
313
314 rpf->fmtinfo = fmtinfo;
315 rpf->format.num_planes = fmtinfo->planes;
316 rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
317 rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
318 rpf->alpha = cfg->alpha;
319
320 rpf->mem.addr[0] = cfg->mem[0];
321 rpf->mem.addr[1] = cfg->mem[1];
322 rpf->mem.addr[2] = cfg->mem[2];
323
324 vsp1->drm->inputs[rpf_index].crop = cfg->src;
325 vsp1->drm->inputs[rpf_index].compose = cfg->dst;
326 vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
327 vsp1->drm->inputs[rpf_index].enabled = true;
328
329 return 0;
330 }
331 EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
332
333 static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
334 struct vsp1_rwpf *rpf, unsigned int bru_input)
335 {
336 struct v4l2_subdev_selection sel;
337 struct v4l2_subdev_format format;
338 const struct v4l2_rect *crop;
339 int ret;
340
341 /*
342 * Configure the format on the RPF sink pad and propagate it up to the
343 * BRU sink pad.
344 */
345 crop = &vsp1->drm->inputs[rpf->entity.index].crop;
346
347 memset(&format, 0, sizeof(format));
348 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
349 format.pad = RWPF_PAD_SINK;
350 format.format.width = crop->width + crop->left;
351 format.format.height = crop->height + crop->top;
352 format.format.code = rpf->fmtinfo->mbus;
353 format.format.field = V4L2_FIELD_NONE;
354
355 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
356 &format);
357 if (ret < 0)
358 return ret;
359
360 dev_dbg(vsp1->dev,
361 "%s: set format %ux%u (%x) on RPF%u sink\n",
362 __func__, format.format.width, format.format.height,
363 format.format.code, rpf->entity.index);
364
365 memset(&sel, 0, sizeof(sel));
366 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
367 sel.pad = RWPF_PAD_SINK;
368 sel.target = V4L2_SEL_TGT_CROP;
369 sel.r = *crop;
370
371 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
372 &sel);
373 if (ret < 0)
374 return ret;
375
376 dev_dbg(vsp1->dev,
377 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
378 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
379 rpf->entity.index);
380
381 /*
382 * RPF source, hardcode the format to ARGB8888 to turn on format
383 * conversion if needed.
384 */
385 format.pad = RWPF_PAD_SOURCE;
386
387 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
388 &format);
389 if (ret < 0)
390 return ret;
391
392 dev_dbg(vsp1->dev,
393 "%s: got format %ux%u (%x) on RPF%u source\n",
394 __func__, format.format.width, format.format.height,
395 format.format.code, rpf->entity.index);
396
397 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
398
399 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
400 &format);
401 if (ret < 0)
402 return ret;
403
404 /* BRU sink, propagate the format from the RPF source. */
405 format.pad = bru_input;
406
407 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL,
408 &format);
409 if (ret < 0)
410 return ret;
411
412 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
413 __func__, format.format.width, format.format.height,
414 format.format.code, format.pad);
415
416 sel.pad = bru_input;
417 sel.target = V4L2_SEL_TGT_COMPOSE;
418 sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
419
420 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection,
421 NULL, &sel);
422 if (ret < 0)
423 return ret;
424
425 dev_dbg(vsp1->dev,
426 "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
427 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
428 sel.pad);
429
430 return 0;
431 }
432
433 static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
434 {
435 return vsp1->drm->inputs[rpf->entity.index].zpos;
436 }
437
438 /**
439 * vsp1_du_atomic_flush - Commit an atomic update
440 * @dev: the VSP device
441 */
442 void vsp1_du_atomic_flush(struct device *dev)
443 {
444 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
445 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
446 struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
447 struct vsp1_entity *entity;
448 struct vsp1_dl_list *dl;
449 unsigned long flags;
450 unsigned int i;
451 int ret;
452
453 /* Prepare the display list. */
454 dl = vsp1_dl_list_get(pipe->output->dlm);
455
456 /* Count the number of enabled inputs and sort them by Z-order. */
457 pipe->num_inputs = 0;
458
459 for (i = 0; i < vsp1->info->rpf_count; ++i) {
460 struct vsp1_rwpf *rpf = vsp1->rpf[i];
461 unsigned int j;
462
463 if (!vsp1->drm->inputs[i].enabled) {
464 pipe->inputs[i] = NULL;
465 continue;
466 }
467
468 pipe->inputs[i] = rpf;
469
470 /* Insert the RPF in the sorted RPFs array. */
471 for (j = pipe->num_inputs++; j > 0; --j) {
472 if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
473 break;
474 inputs[j] = inputs[j-1];
475 }
476
477 inputs[j] = rpf;
478 }
479
480 /* Setup the RPF input pipeline for every enabled input. */
481 for (i = 0; i < vsp1->info->num_bru_inputs; ++i) {
482 struct vsp1_rwpf *rpf = inputs[i];
483
484 if (!rpf) {
485 vsp1->bru->inputs[i].rpf = NULL;
486 continue;
487 }
488
489 vsp1->bru->inputs[i].rpf = rpf;
490 rpf->bru_input = i;
491 rpf->entity.sink_pad = i;
492
493 dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n",
494 __func__, rpf->entity.index, i);
495
496 ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i);
497 if (ret < 0)
498 dev_err(vsp1->dev,
499 "%s: failed to setup RPF.%u\n",
500 __func__, rpf->entity.index);
501 }
502
503 /* Configure all entities in the pipeline. */
504 list_for_each_entry(entity, &pipe->entities, list_pipe) {
505 /* Disconnect unused RPFs from the pipeline. */
506 if (entity->type == VSP1_ENTITY_RPF) {
507 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
508
509 if (!pipe->inputs[rpf->entity.index]) {
510 vsp1_dl_list_write(dl, entity->route->reg,
511 VI6_DPR_NODE_UNUSED);
512 continue;
513 }
514 }
515
516 vsp1_entity_route_setup(entity, pipe, dl);
517
518 if (entity->ops->configure) {
519 entity->ops->configure(entity, pipe, dl,
520 VSP1_ENTITY_PARAMS_INIT);
521 entity->ops->configure(entity, pipe, dl,
522 VSP1_ENTITY_PARAMS_RUNTIME);
523 entity->ops->configure(entity, pipe, dl,
524 VSP1_ENTITY_PARAMS_PARTITION);
525 }
526 }
527
528 vsp1_dl_list_commit(dl);
529
530 /* Start or stop the pipeline if needed. */
531 if (!vsp1->drm->num_inputs && pipe->num_inputs) {
532 vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
533 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
534 spin_lock_irqsave(&pipe->irqlock, flags);
535 vsp1_pipeline_run(pipe);
536 spin_unlock_irqrestore(&pipe->irqlock, flags);
537 } else if (vsp1->drm->num_inputs && !pipe->num_inputs) {
538 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
539 vsp1_pipeline_stop(pipe);
540 }
541 }
542 EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
543
544 int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
545 {
546 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
547
548 /*
549 * As all the buffers allocated by the DU driver are coherent, we can
550 * skip cache sync. This will need to be revisited when support for
551 * non-coherent buffers will be added to the DU driver.
552 */
553 return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
554 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
555 }
556 EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
557
558 void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
559 {
560 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
561
562 dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
563 DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
564 }
565 EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
566
567 /* -----------------------------------------------------------------------------
568 * Initialization
569 */
570
571 int vsp1_drm_create_links(struct vsp1_device *vsp1)
572 {
573 const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
574 unsigned int i;
575 int ret;
576
577 /*
578 * VSPD instances require a BRU to perform composition and a LIF to
579 * output to the DU.
580 */
581 if (!vsp1->bru || !vsp1->lif)
582 return -ENXIO;
583
584 for (i = 0; i < vsp1->info->rpf_count; ++i) {
585 struct vsp1_rwpf *rpf = vsp1->rpf[i];
586
587 ret = media_create_pad_link(&rpf->entity.subdev.entity,
588 RWPF_PAD_SOURCE,
589 &vsp1->bru->entity.subdev.entity,
590 i, flags);
591 if (ret < 0)
592 return ret;
593
594 rpf->entity.sink = &vsp1->bru->entity.subdev.entity;
595 rpf->entity.sink_pad = i;
596 }
597
598 ret = media_create_pad_link(&vsp1->bru->entity.subdev.entity,
599 vsp1->bru->entity.source_pad,
600 &vsp1->wpf[0]->entity.subdev.entity,
601 RWPF_PAD_SINK, flags);
602 if (ret < 0)
603 return ret;
604
605 vsp1->bru->entity.sink = &vsp1->wpf[0]->entity.subdev.entity;
606 vsp1->bru->entity.sink_pad = RWPF_PAD_SINK;
607
608 ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
609 RWPF_PAD_SOURCE,
610 &vsp1->lif->entity.subdev.entity,
611 LIF_PAD_SINK, flags);
612 if (ret < 0)
613 return ret;
614
615 return 0;
616 }
617
618 int vsp1_drm_init(struct vsp1_device *vsp1)
619 {
620 struct vsp1_pipeline *pipe;
621 unsigned int i;
622
623 vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
624 if (!vsp1->drm)
625 return -ENOMEM;
626
627 pipe = &vsp1->drm->pipe;
628
629 vsp1_pipeline_init(pipe);
630
631 /* The DRM pipeline is static, add entities manually. */
632 for (i = 0; i < vsp1->info->rpf_count; ++i) {
633 struct vsp1_rwpf *input = vsp1->rpf[i];
634
635 list_add_tail(&input->entity.list_pipe, &pipe->entities);
636 }
637
638 list_add_tail(&vsp1->bru->entity.list_pipe, &pipe->entities);
639 list_add_tail(&vsp1->wpf[0]->entity.list_pipe, &pipe->entities);
640 list_add_tail(&vsp1->lif->entity.list_pipe, &pipe->entities);
641
642 pipe->bru = &vsp1->bru->entity;
643 pipe->lif = &vsp1->lif->entity;
644 pipe->output = vsp1->wpf[0];
645 pipe->output->pipe = pipe;
646 pipe->frame_end = vsp1_du_pipeline_frame_end;
647
648 return 0;
649 }
650
651 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
652 {
653 }