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>
16 #include <linux/vsp1.h>
18 #include <media/media-entity.h>
19 #include <media/v4l2-subdev.h>
26 #include "vsp1_pipe.h"
27 #include "vsp1_rwpf.h"
29 /* -----------------------------------------------------------------------------
33 static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline
*pipe
)
37 spin_lock_irqsave(&pipe
->irqlock
, flags
);
39 vsp1_pipeline_run(pipe
);
40 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
43 /* -----------------------------------------------------------------------------
47 int vsp1_du_init(struct device
*dev
)
49 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
56 EXPORT_SYMBOL_GPL(vsp1_du_init
);
59 * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
60 * @dev: the VSP device
61 * @width: output frame width in pixels
62 * @height: output frame height in pixels
64 * Configure the output part of VSP DRM pipeline for the given frame @width and
65 * @height. This sets up formats on the BRU source pad, the WPF0 sink and source
66 * pads, and the LIF sink pad.
68 * As the media bus code on the BRU source pad is conditioned by the
69 * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
70 * sinks, even if the configuration will be overwritten later by
71 * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well
74 * Return 0 on success or a negative error code on failure.
76 int vsp1_du_setup_lif(struct device
*dev
, unsigned int width
,
79 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
80 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
81 struct vsp1_bru
*bru
= vsp1
->bru
;
82 struct v4l2_subdev_format format
;
86 dev_dbg(vsp1
->dev
, "%s: configuring LIF with format %ux%u\n",
87 __func__
, width
, height
);
89 if (width
== 0 || height
== 0) {
90 /* Zero width or height means the CRTC is being disabled, stop
91 * the pipeline and turn the light off.
93 ret
= vsp1_pipeline_stop(pipe
);
94 if (ret
== -ETIMEDOUT
)
95 dev_err(vsp1
->dev
, "DRM pipeline stop timeout\n");
97 media_entity_pipeline_stop(&pipe
->output
->entity
.subdev
.entity
);
99 for (i
= 0; i
< bru
->entity
.source_pad
; ++i
) {
100 bru
->inputs
[i
].rpf
= NULL
;
101 pipe
->inputs
[i
] = NULL
;
104 pipe
->num_inputs
= 0;
106 vsp1_device_put(vsp1
);
108 dev_dbg(vsp1
->dev
, "%s: pipeline disabled\n", __func__
);
113 vsp1_dl_reset(vsp1
->drm
->dl
);
115 /* Configure the format at the BRU sinks and propagate it through the
118 memset(&format
, 0, sizeof(format
));
119 format
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
121 for (i
= 0; i
< bru
->entity
.source_pad
; ++i
) {
124 format
.format
.width
= width
;
125 format
.format
.height
= height
;
126 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
127 format
.format
.field
= V4L2_FIELD_NONE
;
129 ret
= v4l2_subdev_call(&bru
->entity
.subdev
, pad
,
130 set_fmt
, NULL
, &format
);
134 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
135 __func__
, format
.format
.width
, format
.format
.height
,
136 format
.format
.code
, i
);
139 format
.pad
= bru
->entity
.source_pad
;
140 format
.format
.width
= width
;
141 format
.format
.height
= height
;
142 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
143 format
.format
.field
= V4L2_FIELD_NONE
;
145 ret
= v4l2_subdev_call(&bru
->entity
.subdev
, pad
, set_fmt
, NULL
,
150 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
151 __func__
, format
.format
.width
, format
.format
.height
,
152 format
.format
.code
, i
);
154 format
.pad
= RWPF_PAD_SINK
;
155 ret
= v4l2_subdev_call(&vsp1
->wpf
[0]->entity
.subdev
, pad
, set_fmt
, NULL
,
160 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on WPF0 sink\n",
161 __func__
, format
.format
.width
, format
.format
.height
,
164 format
.pad
= RWPF_PAD_SOURCE
;
165 ret
= v4l2_subdev_call(&vsp1
->wpf
[0]->entity
.subdev
, pad
, get_fmt
, NULL
,
170 dev_dbg(vsp1
->dev
, "%s: got format %ux%u (%x) on WPF0 source\n",
171 __func__
, format
.format
.width
, format
.format
.height
,
174 format
.pad
= LIF_PAD_SINK
;
175 ret
= v4l2_subdev_call(&vsp1
->lif
->entity
.subdev
, pad
, set_fmt
, NULL
,
180 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on LIF sink\n",
181 __func__
, format
.format
.width
, format
.format
.height
,
184 /* Verify that the format at the output of the pipeline matches the
185 * requested frame size and media bus code.
187 if (format
.format
.width
!= width
|| format
.format
.height
!= height
||
188 format
.format
.code
!= MEDIA_BUS_FMT_ARGB8888_1X32
) {
189 dev_dbg(vsp1
->dev
, "%s: format mismatch\n", __func__
);
193 /* Mark the pipeline as streaming and enable the VSP1. This will store
194 * the pipeline pointer in all entities, which the s_stream handlers
195 * will need. We don't start the entities themselves right at this point
196 * as there's no plane configured yet, so we can't start processing
199 ret
= vsp1_device_get(vsp1
);
203 ret
= media_entity_pipeline_start(&pipe
->output
->entity
.subdev
.entity
,
206 dev_dbg(vsp1
->dev
, "%s: pipeline start failed\n", __func__
);
207 vsp1_device_put(vsp1
);
211 dev_dbg(vsp1
->dev
, "%s: pipeline enabled\n", __func__
);
215 EXPORT_SYMBOL_GPL(vsp1_du_setup_lif
);
218 * vsp1_du_atomic_begin - Prepare for an atomic update
219 * @dev: the VSP device
221 void vsp1_du_atomic_begin(struct device
*dev
)
223 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
224 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
227 spin_lock_irqsave(&pipe
->irqlock
, flags
);
229 vsp1
->drm
->num_inputs
= pipe
->num_inputs
;
231 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
233 /* Prepare the display list. */
234 vsp1_dl_begin(vsp1
->drm
->dl
);
236 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin
);
239 * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
240 * @dev: the VSP device
241 * @rpf_index: index of the RPF to setup (0-based)
242 * @pixelformat: V4L2 pixel format for the RPF memory input
243 * @pitch: number of bytes per line in the image stored in memory
244 * @mem: DMA addresses of the memory buffers (one per plane)
245 * @src: the source crop rectangle for the RPF
246 * @dst: the destination compose rectangle for the BRU input
248 * Configure the VSP to perform composition of the image referenced by @mem
249 * through RPF @rpf_index, using the @src crop rectangle and the @dst
250 * composition rectangle. The Z-order is fixed with RPF 0 at the bottom.
252 * Image format as stored in memory is expressed as a V4L2 @pixelformat value.
253 * As a special case, setting the pixel format to 0 will disable the RPF. The
254 * @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the
255 * function on a disabled RPF is allowed.
257 * The memory pitch is configurable to allow for padding at end of lines, or
258 * simple for images that extend beyond the crop rectangle boundaries. The
259 * @pitch value is expressed in bytes and applies to all planes for multiplanar
262 * The source memory buffer is referenced by the DMA address of its planes in
263 * the @mem array. Up to two planes are supported. The second plane DMA address
264 * is ignored for formats using a single plane.
266 * This function isn't reentrant, the caller needs to serialize calls.
268 * TODO: Implement Z-order control by decoupling the RPF index from the BRU
271 * Return 0 on success or a negative error code on failure.
273 int vsp1_du_atomic_update(struct device
*dev
, unsigned int rpf_index
,
274 u32 pixelformat
, unsigned int pitch
,
275 dma_addr_t mem
[2], const struct v4l2_rect
*src
,
276 const struct v4l2_rect
*dst
)
278 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
279 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
280 const struct vsp1_format_info
*fmtinfo
;
281 struct v4l2_subdev_selection sel
;
282 struct v4l2_subdev_format format
;
283 struct vsp1_rwpf_memory memory
;
284 struct vsp1_rwpf
*rpf
;
288 if (rpf_index
>= vsp1
->info
->rpf_count
)
291 rpf
= vsp1
->rpf
[rpf_index
];
293 if (pixelformat
== 0) {
294 dev_dbg(vsp1
->dev
, "%s: RPF%u: disable requested\n", __func__
,
297 spin_lock_irqsave(&pipe
->irqlock
, flags
);
299 if (pipe
->inputs
[rpf_index
]) {
300 /* Remove the RPF from the pipeline if it was previously
303 vsp1
->bru
->inputs
[rpf_index
].rpf
= NULL
;
304 pipe
->inputs
[rpf_index
] = NULL
;
309 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
315 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad }\n",
317 src
->left
, src
->top
, src
->width
, src
->height
,
318 dst
->left
, dst
->top
, dst
->width
, dst
->height
,
319 pixelformat
, pitch
, &mem
[0], &mem
[1]);
321 /* Set the stride at the RPF input. */
322 fmtinfo
= vsp1_get_format_info(pixelformat
);
324 dev_dbg(vsp1
->dev
, "Unsupport pixel format %08x for RPF\n",
329 rpf
->fmtinfo
= fmtinfo
;
330 rpf
->format
.num_planes
= fmtinfo
->planes
;
331 rpf
->format
.plane_fmt
[0].bytesperline
= pitch
;
332 rpf
->format
.plane_fmt
[1].bytesperline
= pitch
;
334 /* Configure the format on the RPF sink pad and propagate it up to the
337 memset(&format
, 0, sizeof(format
));
338 format
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
339 format
.pad
= RWPF_PAD_SINK
;
340 format
.format
.width
= src
->width
+ src
->left
;
341 format
.format
.height
= src
->height
+ src
->top
;
342 format
.format
.code
= fmtinfo
->mbus
;
343 format
.format
.field
= V4L2_FIELD_NONE
;
345 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_fmt
, NULL
,
351 "%s: set format %ux%u (%x) on RPF%u sink\n",
352 __func__
, format
.format
.width
, format
.format
.height
,
353 format
.format
.code
, rpf
->entity
.index
);
355 memset(&sel
, 0, sizeof(sel
));
356 sel
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
357 sel
.pad
= RWPF_PAD_SINK
;
358 sel
.target
= V4L2_SEL_TGT_CROP
;
361 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_selection
, NULL
,
367 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
368 __func__
, sel
.r
.left
, sel
.r
.top
, sel
.r
.width
, sel
.r
.height
,
371 /* RPF source, hardcode the format to ARGB8888 to turn on format
372 * conversion if needed.
374 format
.pad
= RWPF_PAD_SOURCE
;
376 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, get_fmt
, NULL
,
382 "%s: got format %ux%u (%x) on RPF%u source\n",
383 __func__
, format
.format
.width
, format
.format
.height
,
384 format
.format
.code
, rpf
->entity
.index
);
386 format
.format
.code
= MEDIA_BUS_FMT_ARGB8888_1X32
;
388 ret
= v4l2_subdev_call(&rpf
->entity
.subdev
, pad
, set_fmt
, NULL
,
393 /* BRU sink, propagate the format from the RPF source. */
394 format
.pad
= rpf
->entity
.index
;
396 ret
= v4l2_subdev_call(&vsp1
->bru
->entity
.subdev
, pad
, set_fmt
, NULL
,
401 dev_dbg(vsp1
->dev
, "%s: set format %ux%u (%x) on BRU pad %u\n",
402 __func__
, format
.format
.width
, format
.format
.height
,
403 format
.format
.code
, format
.pad
);
405 sel
.pad
= rpf
->entity
.index
;
406 sel
.target
= V4L2_SEL_TGT_COMPOSE
;
409 ret
= v4l2_subdev_call(&vsp1
->bru
->entity
.subdev
, pad
, set_selection
,
415 "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
416 __func__
, sel
.r
.left
, sel
.r
.top
, sel
.r
.width
, sel
.r
.height
,
419 /* Store the compose rectangle coordinates in the RPF. */
420 rpf
->location
.left
= dst
->left
;
421 rpf
->location
.top
= dst
->top
;
423 /* Set the memory buffer address. */
424 memory
.num_planes
= fmtinfo
->planes
;
425 memory
.addr
[0] = mem
[0];
426 memory
.addr
[1] = mem
[1];
428 rpf
->ops
->set_memory(rpf
, &memory
);
430 spin_lock_irqsave(&pipe
->irqlock
, flags
);
432 /* If the RPF was previously stopped set the BRU input to the RPF and
433 * store the RPF in the pipeline inputs array.
435 if (!pipe
->inputs
[rpf
->entity
.index
]) {
436 vsp1
->bru
->inputs
[rpf_index
].rpf
= rpf
;
437 pipe
->inputs
[rpf
->entity
.index
] = rpf
;
441 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
445 EXPORT_SYMBOL_GPL(vsp1_du_atomic_update
);
448 * vsp1_du_atomic_flush - Commit an atomic update
449 * @dev: the VSP device
451 void vsp1_du_atomic_flush(struct device
*dev
)
453 struct vsp1_device
*vsp1
= dev_get_drvdata(dev
);
454 struct vsp1_pipeline
*pipe
= &vsp1
->drm
->pipe
;
455 struct vsp1_entity
*entity
;
460 list_for_each_entry(entity
, &pipe
->entities
, list_pipe
) {
461 /* Disconnect unused RPFs from the pipeline. */
462 if (entity
->type
== VSP1_ENTITY_RPF
) {
463 struct vsp1_rwpf
*rpf
= to_rwpf(&entity
->subdev
);
465 if (!pipe
->inputs
[rpf
->entity
.index
]) {
466 vsp1_mod_write(entity
, entity
->route
->reg
,
467 VI6_DPR_NODE_UNUSED
);
472 vsp1_entity_route_setup(entity
);
474 ret
= v4l2_subdev_call(&entity
->subdev
, video
,
478 "DRM pipeline start failure on entity %s\n",
479 entity
->subdev
.name
);
484 vsp1_dl_commit(vsp1
->drm
->dl
);
486 spin_lock_irqsave(&pipe
->irqlock
, flags
);
488 /* Start or stop the pipeline if needed. */
489 if (!vsp1
->drm
->num_inputs
&& pipe
->num_inputs
) {
490 vsp1_write(vsp1
, VI6_DISP_IRQ_STA
, 0);
491 vsp1_write(vsp1
, VI6_DISP_IRQ_ENB
, VI6_DISP_IRQ_ENB_DSTE
);
492 vsp1_pipeline_run(pipe
);
493 } else if (vsp1
->drm
->num_inputs
&& !pipe
->num_inputs
) {
497 spin_unlock_irqrestore(&pipe
->irqlock
, flags
);
500 vsp1_write(vsp1
, VI6_DISP_IRQ_ENB
, 0);
501 vsp1_pipeline_stop(pipe
);
504 EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush
);
506 /* -----------------------------------------------------------------------------
510 int vsp1_drm_create_links(struct vsp1_device
*vsp1
)
512 const u32 flags
= MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
;
516 /* VSPD instances require a BRU to perform composition and a LIF to
519 if (!vsp1
->bru
|| !vsp1
->lif
)
522 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
523 struct vsp1_rwpf
*rpf
= vsp1
->rpf
[i
];
525 ret
= media_create_pad_link(&rpf
->entity
.subdev
.entity
,
527 &vsp1
->bru
->entity
.subdev
.entity
,
532 rpf
->entity
.sink
= &vsp1
->bru
->entity
.subdev
.entity
;
533 rpf
->entity
.sink_pad
= i
;
536 ret
= media_create_pad_link(&vsp1
->bru
->entity
.subdev
.entity
,
537 vsp1
->bru
->entity
.source_pad
,
538 &vsp1
->wpf
[0]->entity
.subdev
.entity
,
539 RWPF_PAD_SINK
, flags
);
543 vsp1
->bru
->entity
.sink
= &vsp1
->wpf
[0]->entity
.subdev
.entity
;
544 vsp1
->bru
->entity
.sink_pad
= RWPF_PAD_SINK
;
546 ret
= media_create_pad_link(&vsp1
->wpf
[0]->entity
.subdev
.entity
,
548 &vsp1
->lif
->entity
.subdev
.entity
,
549 LIF_PAD_SINK
, flags
);
556 int vsp1_drm_init(struct vsp1_device
*vsp1
)
558 struct vsp1_pipeline
*pipe
;
561 vsp1
->drm
= devm_kzalloc(vsp1
->dev
, sizeof(*vsp1
->drm
), GFP_KERNEL
);
565 vsp1
->drm
->dl
= vsp1_dl_create(vsp1
);
569 pipe
= &vsp1
->drm
->pipe
;
571 vsp1_pipeline_init(pipe
);
572 pipe
->frame_end
= vsp1_drm_pipeline_frame_end
;
574 /* The DRM pipeline is static, add entities manually. */
575 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
576 struct vsp1_rwpf
*input
= vsp1
->rpf
[i
];
578 list_add_tail(&input
->entity
.list_pipe
, &pipe
->entities
);
581 list_add_tail(&vsp1
->bru
->entity
.list_pipe
, &pipe
->entities
);
582 list_add_tail(&vsp1
->wpf
[0]->entity
.list_pipe
, &pipe
->entities
);
583 list_add_tail(&vsp1
->lif
->entity
.list_pipe
, &pipe
->entities
);
585 pipe
->bru
= &vsp1
->bru
->entity
;
586 pipe
->lif
= &vsp1
->lif
->entity
;
587 pipe
->output
= vsp1
->wpf
[0];
589 pipe
->dl
= vsp1
->drm
->dl
;
594 void vsp1_drm_cleanup(struct vsp1_device
*vsp1
)
596 vsp1_dl_destroy(vsp1
->drm
->dl
);