2 * vsp1_drm.c -- R-Car VSP1 DRM API
4 * Copyright (C) 2015 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/device.h>
15 #include <linux/slab.h>
17 #include <media/media-entity.h>
18 #include <media/v4l2-subdev.h>
19 #include <media/vsp1.h>
26 #include "vsp1_pipe.h"
27 #include "vsp1_rwpf.h"
30 /* -----------------------------------------------------------------------------
34 void vsp1_drm_display_start(struct vsp1_device
*vsp1
)
36 vsp1_dlm_irq_display_start(vsp1
->drm
->pipe
.output
->dlm
);
39 /* -----------------------------------------------------------------------------
43 int vsp1_du_init(struct device
*dev
)
45 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
52 EXPORT_SYMBOL_GPL(vsp1_du_init
);
55 * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
56 * @dev: the VSP device
57 * @width: output frame width in pixels
58 * @height: output frame height in pixels
60 * Configure the output part of VSP DRM pipeline for the given frame @width and
61 * @height. This sets up formats on the BRU source pad, the WPF0 sink and source
62 * pads, and the LIF sink pad.
64 * As the media bus code on the BRU source pad is conditioned by the
65 * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
66 * sinks, even if the configuration will be overwritten later by
67 * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well
70 * Return 0 on success or a negative error code on failure.
72 int vsp1_du_setup_lif(struct device
*dev
, unsigned int width
,
75 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
76 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
77 struct vsp1_bru
*bru
= vsp1
->bru
;
78 struct v4l2_subdev_format format
;
82 dev_dbg(vsp1
->dev
, "%s: configuring LIF with format %ux%u\n",
83 __func__
, width
, height
);
85 if (width
== 0 || height
== 0) {
86 /* Zero width or height means the CRTC is being disabled, stop
87 * the pipeline and turn the light off.
89 ret
= vsp1_pipeline_stop(pipe
);
90 if (ret
== -ETIMEDOUT
)
91 dev_err(vsp1
->dev
, "DRM pipeline stop timeout\n");
93 media_entity_pipeline_stop(&pipe
->output
->entity
.subdev
.entity
);
95 for (i
= 0; i
< bru
->entity
.source_pad
; ++i
) {
96 vsp1
->drm
->inputs
[i
].enabled
= false;
97 bru
->inputs
[i
].rpf
= NULL
;
98 pipe
->inputs
[i
] = NULL
;
101 pipe
->num_inputs
= 0;
103 vsp1_dlm_reset(pipe
->output
->dlm
);
104 vsp1_device_put(vsp1
);
106 dev_dbg(vsp1
->dev
, "%s: pipeline disabled\n", __func__
);
111 /* Configure the format at the BRU sinks and propagate it through the
114 memset(&format
, 0, sizeof(format
));
115 format
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
117 for (i
= 0; i
< bru
->entity
.source_pad
; ++i
) {
120 format
.format
.width
= width
;
121 format
.format
.height
= height
;
122 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
123 format
.format
.field
= V4L2_FIELD_NONE
;
125 ret
= v4l2_subdev_call(&bru
->entity
.subdev
, pad
,
126 set_fmt
, NULL
, &format
);
130 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
131 __func__
, format
.format
.width
, format
.format
.height
,
132 format
.format
.code
, i
);
135 format
.pad
= bru
->entity
.source_pad
;
136 format
.format
.width
= width
;
137 format
.format
.height
= height
;
138 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
139 format
.format
.field
= V4L2_FIELD_NONE
;
141 ret
= v4l2_subdev_call(&bru
->entity
.subdev
, pad
, set_fmt
, NULL
,
146 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
147 __func__
, format
.format
.width
, format
.format
.height
,
148 format
.format
.code
, i
);
150 format
.pad
= RWPF_PAD_SINK
;
151 ret
= v4l2_subdev_call(&vsp1
->wpf
[0]->entity
.subdev
, pad
, set_fmt
, NULL
,
156 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on WPF0 sink\n",
157 __func__
, format
.format
.width
, format
.format
.height
,
160 format
.pad
= RWPF_PAD_SOURCE
;
161 ret
= v4l2_subdev_call(&vsp1
->wpf
[0]->entity
.subdev
, pad
, get_fmt
, NULL
,
166 dev_dbg(vsp1
->dev
, "%s: got format %ux%u (%x) on WPF0 source\n",
167 __func__
, format
.format
.width
, format
.format
.height
,
170 format
.pad
= LIF_PAD_SINK
;
171 ret
= v4l2_subdev_call(&vsp1
->lif
->entity
.subdev
, pad
, set_fmt
, NULL
,
176 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on LIF sink\n",
177 __func__
, format
.format
.width
, format
.format
.height
,
180 /* Verify that the format at the output of the pipeline matches the
181 * requested frame size and media bus code.
183 if (format
.format
.width
!= width
|| format
.format
.height
!= height
||
184 format
.format
.code
!= MEDIA_BUS_FMT_ARGB8888_1X32
) {
185 dev_dbg(vsp1
->dev
, "%s: format mismatch\n", __func__
);
189 /* Mark the pipeline as streaming and enable the VSP1. This will store
190 * the pipeline pointer in all entities, which the s_stream handlers
191 * will need. We don't start the entities themselves right at this point
192 * as there's no plane configured yet, so we can't start processing
195 ret
= vsp1_device_get(vsp1
);
199 ret
= media_entity_pipeline_start(&pipe
->output
->entity
.subdev
.entity
,
202 dev_dbg(vsp1
->dev
, "%s: pipeline start failed\n", __func__
);
203 vsp1_device_put(vsp1
);
207 dev_dbg(vsp1
->dev
, "%s: pipeline enabled\n", __func__
);
211 EXPORT_SYMBOL_GPL(vsp1_du_setup_lif
);
214 * vsp1_du_atomic_begin - Prepare for an atomic update
215 * @dev: the VSP device
217 void vsp1_du_atomic_begin(struct device
*dev
)
219 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
220 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
222 vsp1
->drm
->num_inputs
= pipe
->num_inputs
;
224 /* Prepare the display list. */
225 pipe
->dl
= vsp1_dl_list_get(pipe
->output
->dlm
);
227 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin
);
230 * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
231 * @dev: the VSP device
232 * @rpf_index: index of the RPF to setup (0-based)
233 * @cfg: the RPF configuration
235 * Configure the VSP to perform image composition through RPF @rpf_index as
236 * described by the @cfg configuration. The image to compose is referenced by
237 * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst
238 * composition rectangle. The Z-order is configurable with higher @zpos values
241 * If the @cfg configuration is NULL, the RPF will be disabled. Calling the
242 * function on a disabled RPF is allowed.
244 * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat
245 * value. The memory pitch is configurable to allow for padding at end of lines,
246 * or simply for images that extend beyond the crop rectangle boundaries. The
247 * @cfg.pitch value is expressed in bytes and applies to all planes for
248 * multiplanar formats.
250 * The source memory buffer is referenced by the DMA address of its planes in
251 * the @cfg.mem array. Up to two planes are supported. The second plane DMA
252 * address is ignored for formats using a single plane.
254 * This function isn't reentrant, the caller needs to serialize calls.
256 * Return 0 on success or a negative error code on failure.
258 int vsp1_du_atomic_update(struct device
*dev
, unsigned int rpf_index
,
259 const struct vsp1_du_atomic_config
*cfg
)
261 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
262 const struct vsp1_format_info
*fmtinfo
;
263 struct vsp1_rwpf
*rpf
;
265 if (rpf_index
>= vsp1
->info
->rpf_count
)
268 rpf
= vsp1
->rpf
[rpf_index
];
271 dev_dbg(vsp1
->dev
, "%s: RPF%u: disable requested\n", __func__
,
274 vsp1
->drm
->inputs
[rpf_index
].enabled
= false;
279 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
281 cfg
->src
.left
, cfg
->src
.top
, cfg
->src
.width
, cfg
->src
.height
,
282 cfg
->dst
.left
, cfg
->dst
.top
, cfg
->dst
.width
, cfg
->dst
.height
,
283 cfg
->pixelformat
, cfg
->pitch
, &cfg
->mem
[0], &cfg
->mem
[1],
284 &cfg
->mem
[2], cfg
->zpos
);
287 * Store the format, stride, memory buffer address, crop and compose
288 * rectangles and Z-order position and for the input.
290 fmtinfo
= vsp1_get_format_info(vsp1
, cfg
->pixelformat
);
292 dev_dbg(vsp1
->dev
, "Unsupport pixel format %08x for RPF\n",
297 rpf
->fmtinfo
= fmtinfo
;
298 rpf
->format
.num_planes
= fmtinfo
->planes
;
299 rpf
->format
.plane_fmt
[0].bytesperline
= cfg
->pitch
;
300 rpf
->format
.plane_fmt
[1].bytesperline
= cfg
->pitch
;
301 rpf
->alpha
= cfg
->alpha
;
303 rpf
->mem
.addr
[0] = cfg
->mem
[0];
304 rpf
->mem
.addr
[1] = cfg
->mem
[1];
305 rpf
->mem
.addr
[2] = cfg
->mem
[2];
307 vsp1
->drm
->inputs
[rpf_index
].crop
= cfg
->src
;
308 vsp1
->drm
->inputs
[rpf_index
].compose
= cfg
->dst
;
309 vsp1
->drm
->inputs
[rpf_index
].zpos
= cfg
->zpos
;
310 vsp1
->drm
->inputs
[rpf_index
].enabled
= true;
314 EXPORT_SYMBOL_GPL(vsp1_du_atomic_update
);
316 static int vsp1_du_setup_rpf_pipe(struct vsp1_device
*vsp1
,
317 struct vsp1_rwpf
*rpf
, unsigned int bru_input
)
319 struct v4l2_subdev_selection sel
;
320 struct v4l2_subdev_format format
;
321 const struct v4l2_rect
*crop
;
324 /* Configure the format on the RPF sink pad and propagate it up to the
327 crop
= &vsp1
->drm
->inputs
[rpf
->entity
.index
].crop
;
329 memset(&format
, 0, sizeof(format
));
330 format
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
331 format
.pad
= RWPF_PAD_SINK
;
332 format
.format
.width
= crop
->width
+ crop
->left
;
333 format
.format
.height
= crop
->height
+ crop
->top
;
334 format
.format
.code
= rpf
->fmtinfo
->mbus
;
335 format
.format
.field
= V4L2_FIELD_NONE
;
337 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_fmt
, NULL
,
343 "%s: set format %ux%u (%x) on RPF%u sink\n",
344 __func__
, format
.format
.width
, format
.format
.height
,
345 format
.format
.code
, rpf
->entity
.index
);
347 memset(&sel
, 0, sizeof(sel
));
348 sel
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
349 sel
.pad
= RWPF_PAD_SINK
;
350 sel
.target
= V4L2_SEL_TGT_CROP
;
353 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_selection
, NULL
,
359 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
360 __func__
, sel
.r
.left
, sel
.r
.top
, sel
.r
.width
, sel
.r
.height
,
363 /* RPF source, hardcode the format to ARGB8888 to turn on format
364 * conversion if needed.
366 format
.pad
= RWPF_PAD_SOURCE
;
368 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, get_fmt
, NULL
,
374 "%s: got format %ux%u (%x) on RPF%u source\n",
375 __func__
, format
.format
.width
, format
.format
.height
,
376 format
.format
.code
, rpf
->entity
.index
);
378 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
380 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_fmt
, NULL
,
385 /* BRU sink, propagate the format from the RPF source. */
386 format
.pad
= bru_input
;
388 ret
= v4l2_subdev_call(&vsp1
->bru
->entity
.subdev
, pad
, set_fmt
, NULL
,
393 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
394 __func__
, format
.format
.width
, format
.format
.height
,
395 format
.format
.code
, format
.pad
);
398 sel
.target
= V4L2_SEL_TGT_COMPOSE
;
399 sel
.r
= vsp1
->drm
->inputs
[rpf
->entity
.index
].compose
;
401 ret
= v4l2_subdev_call(&vsp1
->bru
->entity
.subdev
, pad
, set_selection
,
407 "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
408 __func__
, sel
.r
.left
, sel
.r
.top
, sel
.r
.width
, sel
.r
.height
,
414 static unsigned int rpf_zpos(struct vsp1_device
*vsp1
, struct vsp1_rwpf
*rpf
)
416 return vsp1
->drm
->inputs
[rpf
->entity
.index
].zpos
;
420 * vsp1_du_atomic_flush - Commit an atomic update
421 * @dev: the VSP device
423 void vsp1_du_atomic_flush(struct device
*dev
)
425 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
426 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
427 struct vsp1_rwpf
*inputs
[VSP1_MAX_RPF
] = { NULL
, };
428 struct vsp1_entity
*entity
;
433 /* Count the number of enabled inputs and sort them by Z-order. */
434 pipe
->num_inputs
= 0;
436 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
437 struct vsp1_rwpf
*rpf
= vsp1
->rpf
[i
];
440 if (!vsp1
->drm
->inputs
[i
].enabled
) {
441 pipe
->inputs
[i
] = NULL
;
445 pipe
->inputs
[i
] = rpf
;
447 /* Insert the RPF in the sorted RPFs array. */
448 for (j
= pipe
->num_inputs
++; j
> 0; --j
) {
449 if (rpf_zpos(vsp1
, inputs
[j
-1]) <= rpf_zpos(vsp1
, rpf
))
451 inputs
[j
] = inputs
[j
-1];
457 /* Setup the RPF input pipeline for every enabled input. */
458 for (i
= 0; i
< vsp1
->info
->num_bru_inputs
; ++i
) {
459 struct vsp1_rwpf
*rpf
= inputs
[i
];
462 vsp1
->bru
->inputs
[i
].rpf
= NULL
;
466 vsp1
->bru
->inputs
[i
].rpf
= rpf
;
468 rpf
->entity
.sink_pad
= i
;
470 dev_dbg(vsp1
->dev
, "%s: connecting RPF.%u to BRU:%u\n",
471 __func__
, rpf
->entity
.index
, i
);
473 ret
= vsp1_du_setup_rpf_pipe(vsp1
, rpf
, i
);
476 "%s: failed to setup RPF.%u\n",
477 __func__
, rpf
->entity
.index
);
480 /* Configure all entities in the pipeline. */
481 list_for_each_entry(entity
, &pipe
->entities
, list_pipe
) {
482 /* Disconnect unused RPFs from the pipeline. */
483 if (entity
->type
== VSP1_ENTITY_RPF
) {
484 struct vsp1_rwpf
*rpf
= to_rwpf(&entity
->subdev
);
486 if (!pipe
->inputs
[rpf
->entity
.index
]) {
487 vsp1_dl_list_write(pipe
->dl
, entity
->route
->reg
,
488 VI6_DPR_NODE_UNUSED
);
493 vsp1_entity_route_setup(entity
, pipe
->dl
);
495 if (entity
->ops
->configure
) {
496 entity
->ops
->configure(entity
, pipe
, pipe
->dl
,
497 VSP1_ENTITY_PARAMS_INIT
);
498 entity
->ops
->configure(entity
, pipe
, pipe
->dl
,
499 VSP1_ENTITY_PARAMS_RUNTIME
);
500 entity
->ops
->configure(entity
, pipe
, pipe
->dl
,
501 VSP1_ENTITY_PARAMS_PARTITION
);
505 vsp1_dl_list_commit(pipe
->dl
);
508 /* Start or stop the pipeline if needed. */
509 if (!vsp1
->drm
->num_inputs
&& pipe
->num_inputs
) {
510 vsp1_write(vsp1
, VI6_DISP_IRQ_STA
, 0);
511 vsp1_write(vsp1
, VI6_DISP_IRQ_ENB
, VI6_DISP_IRQ_ENB_DSTE
);
512 spin_lock_irqsave(&pipe
->irqlock
, flags
);
513 vsp1_pipeline_run(pipe
);
514 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
515 } else if (vsp1
->drm
->num_inputs
&& !pipe
->num_inputs
) {
516 vsp1_write(vsp1
, VI6_DISP_IRQ_ENB
, 0);
517 vsp1_pipeline_stop(pipe
);
520 EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush
);
522 /* -----------------------------------------------------------------------------
526 int vsp1_drm_create_links(struct vsp1_device
*vsp1
)
528 const u32 flags
= MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
;
532 /* VSPD instances require a BRU to perform composition and a LIF to
535 if (!vsp1
->bru
|| !vsp1
->lif
)
538 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
539 struct vsp1_rwpf
*rpf
= vsp1
->rpf
[i
];
541 ret
= media_create_pad_link(&rpf
->entity
.subdev
.entity
,
543 &vsp1
->bru
->entity
.subdev
.entity
,
548 rpf
->entity
.sink
= &vsp1
->bru
->entity
.subdev
.entity
;
549 rpf
->entity
.sink_pad
= i
;
552 ret
= media_create_pad_link(&vsp1
->bru
->entity
.subdev
.entity
,
553 vsp1
->bru
->entity
.source_pad
,
554 &vsp1
->wpf
[0]->entity
.subdev
.entity
,
555 RWPF_PAD_SINK
, flags
);
559 vsp1
->bru
->entity
.sink
= &vsp1
->wpf
[0]->entity
.subdev
.entity
;
560 vsp1
->bru
->entity
.sink_pad
= RWPF_PAD_SINK
;
562 ret
= media_create_pad_link(&vsp1
->wpf
[0]->entity
.subdev
.entity
,
564 &vsp1
->lif
->entity
.subdev
.entity
,
565 LIF_PAD_SINK
, flags
);
572 int vsp1_drm_init(struct vsp1_device
*vsp1
)
574 struct vsp1_pipeline
*pipe
;
577 vsp1
->drm
= devm_kzalloc(vsp1
->dev
, sizeof(*vsp1
->drm
), GFP_KERNEL
);
581 pipe
= &vsp1
->drm
->pipe
;
583 vsp1_pipeline_init(pipe
);
585 /* The DRM pipeline is static, add entities manually. */
586 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
587 struct vsp1_rwpf
*input
= vsp1
->rpf
[i
];
589 list_add_tail(&input
->entity
.list_pipe
, &pipe
->entities
);
592 list_add_tail(&vsp1
->bru
->entity
.list_pipe
, &pipe
->entities
);
593 list_add_tail(&vsp1
->wpf
[0]->entity
.list_pipe
, &pipe
->entities
);
594 list_add_tail(&vsp1
->lif
->entity
.list_pipe
, &pipe
->entities
);
596 pipe
->bru
= &vsp1
->bru
->entity
;
597 pipe
->lif
= &vsp1
->lif
->entity
;
598 pipe
->output
= vsp1
->wpf
[0];
599 pipe
->output
->pipe
= pipe
;
604 void vsp1_drm_cleanup(struct vsp1_device
*vsp1
)