2 * vsp1_bru.c -- R-Car VSP1 Blend ROP Unit
4 * Copyright (C) 2013 Renesas 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/gfp.h>
17 #include <media/v4l2-subdev.h>
21 #include "vsp1_rwpf.h"
22 #include "vsp1_video.h"
24 #define BRU_MIN_SIZE 1U
25 #define BRU_MAX_SIZE 8190U
27 /* -----------------------------------------------------------------------------
31 static inline void vsp1_bru_write(struct vsp1_bru
*bru
, u32 reg
, u32 data
)
33 vsp1_mod_write(&bru
->entity
, reg
, data
);
36 /* -----------------------------------------------------------------------------
40 static int bru_s_ctrl(struct v4l2_ctrl
*ctrl
)
42 struct vsp1_bru
*bru
=
43 container_of(ctrl
->handler
, struct vsp1_bru
, ctrls
);
46 case V4L2_CID_BG_COLOR
:
47 bru
->bgcolor
= ctrl
->val
;
54 static const struct v4l2_ctrl_ops bru_ctrl_ops
= {
58 /* -----------------------------------------------------------------------------
59 * V4L2 Subdevice Operations
63 * The BRU can't perform format conversion, all sink and source formats must be
64 * identical. We pick the format on the first sink pad (pad 0) and propagate it
68 static int bru_enum_mbus_code(struct v4l2_subdev
*subdev
,
69 struct v4l2_subdev_pad_config
*cfg
,
70 struct v4l2_subdev_mbus_code_enum
*code
)
72 static const unsigned int codes
[] = {
73 MEDIA_BUS_FMT_ARGB8888_1X32
,
74 MEDIA_BUS_FMT_AYUV8_1X32
,
76 struct vsp1_bru
*bru
= to_bru(subdev
);
78 if (code
->pad
== BRU_PAD_SINK(0)) {
79 if (code
->index
>= ARRAY_SIZE(codes
))
82 code
->code
= codes
[code
->index
];
84 struct v4l2_subdev_pad_config
*config
;
85 struct v4l2_mbus_framefmt
*format
;
90 config
= vsp1_entity_get_pad_config(&bru
->entity
, cfg
,
95 format
= vsp1_entity_get_pad_format(&bru
->entity
, config
,
97 code
->code
= format
->code
;
103 static int bru_enum_frame_size(struct v4l2_subdev
*subdev
,
104 struct v4l2_subdev_pad_config
*cfg
,
105 struct v4l2_subdev_frame_size_enum
*fse
)
110 if (fse
->code
!= MEDIA_BUS_FMT_ARGB8888_1X32
&&
111 fse
->code
!= MEDIA_BUS_FMT_AYUV8_1X32
)
114 fse
->min_width
= BRU_MIN_SIZE
;
115 fse
->max_width
= BRU_MAX_SIZE
;
116 fse
->min_height
= BRU_MIN_SIZE
;
117 fse
->max_height
= BRU_MAX_SIZE
;
122 static struct v4l2_rect
*bru_get_compose(struct vsp1_bru
*bru
,
123 struct v4l2_subdev_pad_config
*cfg
,
126 return v4l2_subdev_get_try_compose(&bru
->entity
.subdev
, cfg
, pad
);
129 static int bru_get_format(struct v4l2_subdev
*subdev
,
130 struct v4l2_subdev_pad_config
*cfg
,
131 struct v4l2_subdev_format
*fmt
)
133 struct vsp1_bru
*bru
= to_bru(subdev
);
134 struct v4l2_subdev_pad_config
*config
;
136 config
= vsp1_entity_get_pad_config(&bru
->entity
, cfg
, fmt
->which
);
140 fmt
->format
= *vsp1_entity_get_pad_format(&bru
->entity
, config
,
146 static void bru_try_format(struct vsp1_bru
*bru
,
147 struct v4l2_subdev_pad_config
*config
,
148 unsigned int pad
, struct v4l2_mbus_framefmt
*fmt
)
150 struct v4l2_mbus_framefmt
*format
;
153 case BRU_PAD_SINK(0):
154 /* Default to YUV if the requested format is not supported. */
155 if (fmt
->code
!= MEDIA_BUS_FMT_ARGB8888_1X32
&&
156 fmt
->code
!= MEDIA_BUS_FMT_AYUV8_1X32
)
157 fmt
->code
= MEDIA_BUS_FMT_AYUV8_1X32
;
161 /* The BRU can't perform format conversion. */
162 format
= vsp1_entity_get_pad_format(&bru
->entity
, config
,
164 fmt
->code
= format
->code
;
168 fmt
->width
= clamp(fmt
->width
, BRU_MIN_SIZE
, BRU_MAX_SIZE
);
169 fmt
->height
= clamp(fmt
->height
, BRU_MIN_SIZE
, BRU_MAX_SIZE
);
170 fmt
->field
= V4L2_FIELD_NONE
;
171 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
174 static int bru_set_format(struct v4l2_subdev
*subdev
,
175 struct v4l2_subdev_pad_config
*cfg
,
176 struct v4l2_subdev_format
*fmt
)
178 struct vsp1_bru
*bru
= to_bru(subdev
);
179 struct v4l2_subdev_pad_config
*config
;
180 struct v4l2_mbus_framefmt
*format
;
182 config
= vsp1_entity_get_pad_config(&bru
->entity
, cfg
, fmt
->which
);
186 bru_try_format(bru
, config
, fmt
->pad
, &fmt
->format
);
188 format
= vsp1_entity_get_pad_format(&bru
->entity
, config
, fmt
->pad
);
189 *format
= fmt
->format
;
191 /* Reset the compose rectangle */
192 if (fmt
->pad
!= bru
->entity
.source_pad
) {
193 struct v4l2_rect
*compose
;
195 compose
= bru_get_compose(bru
, config
, fmt
->pad
);
198 compose
->width
= format
->width
;
199 compose
->height
= format
->height
;
202 /* Propagate the format code to all pads */
203 if (fmt
->pad
== BRU_PAD_SINK(0)) {
206 for (i
= 0; i
<= bru
->entity
.source_pad
; ++i
) {
207 format
= vsp1_entity_get_pad_format(&bru
->entity
,
209 format
->code
= fmt
->format
.code
;
216 static int bru_get_selection(struct v4l2_subdev
*subdev
,
217 struct v4l2_subdev_pad_config
*cfg
,
218 struct v4l2_subdev_selection
*sel
)
220 struct vsp1_bru
*bru
= to_bru(subdev
);
221 struct v4l2_subdev_pad_config
*config
;
223 if (sel
->pad
== bru
->entity
.source_pad
)
226 switch (sel
->target
) {
227 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
230 sel
->r
.width
= BRU_MAX_SIZE
;
231 sel
->r
.height
= BRU_MAX_SIZE
;
234 case V4L2_SEL_TGT_COMPOSE
:
235 config
= vsp1_entity_get_pad_config(&bru
->entity
, cfg
,
240 sel
->r
= *bru_get_compose(bru
, config
, sel
->pad
);
248 static int bru_set_selection(struct v4l2_subdev
*subdev
,
249 struct v4l2_subdev_pad_config
*cfg
,
250 struct v4l2_subdev_selection
*sel
)
252 struct vsp1_bru
*bru
= to_bru(subdev
);
253 struct v4l2_subdev_pad_config
*config
;
254 struct v4l2_mbus_framefmt
*format
;
255 struct v4l2_rect
*compose
;
257 if (sel
->pad
== bru
->entity
.source_pad
)
260 if (sel
->target
!= V4L2_SEL_TGT_COMPOSE
)
263 config
= vsp1_entity_get_pad_config(&bru
->entity
, cfg
, sel
->which
);
267 /* The compose rectangle top left corner must be inside the output
270 format
= vsp1_entity_get_pad_format(&bru
->entity
, config
,
271 bru
->entity
.source_pad
);
272 sel
->r
.left
= clamp_t(unsigned int, sel
->r
.left
, 0, format
->width
- 1);
273 sel
->r
.top
= clamp_t(unsigned int, sel
->r
.top
, 0, format
->height
- 1);
275 /* Scaling isn't supported, the compose rectangle size must be identical
276 * to the sink format size.
278 format
= vsp1_entity_get_pad_format(&bru
->entity
, config
, sel
->pad
);
279 sel
->r
.width
= format
->width
;
280 sel
->r
.height
= format
->height
;
282 compose
= bru_get_compose(bru
, config
, sel
->pad
);
288 static struct v4l2_subdev_pad_ops bru_pad_ops
= {
289 .init_cfg
= vsp1_entity_init_cfg
,
290 .enum_mbus_code
= bru_enum_mbus_code
,
291 .enum_frame_size
= bru_enum_frame_size
,
292 .get_fmt
= bru_get_format
,
293 .set_fmt
= bru_set_format
,
294 .get_selection
= bru_get_selection
,
295 .set_selection
= bru_set_selection
,
298 static struct v4l2_subdev_ops bru_ops
= {
302 /* -----------------------------------------------------------------------------
303 * VSP1 Entity Operations
306 static void bru_configure(struct vsp1_entity
*entity
)
308 struct vsp1_pipeline
*pipe
= to_vsp1_pipeline(&entity
->subdev
.entity
);
309 struct vsp1_bru
*bru
= to_bru(&entity
->subdev
);
310 struct v4l2_mbus_framefmt
*format
;
314 format
= vsp1_entity_get_pad_format(&bru
->entity
, bru
->entity
.config
,
315 bru
->entity
.source_pad
);
317 /* The hardware is extremely flexible but we have no userspace API to
318 * expose all the parameters, nor is it clear whether we would have use
319 * cases for all the supported modes. Let's just harcode the parameters
320 * to sane default values for now.
323 /* Disable dithering and enable color data normalization unless the
324 * format at the pipeline output is premultiplied.
326 flags
= pipe
->output
? pipe
->output
->format
.flags
: 0;
327 vsp1_bru_write(bru
, VI6_BRU_INCTRL
,
328 flags
& V4L2_PIX_FMT_FLAG_PREMUL_ALPHA
?
329 0 : VI6_BRU_INCTRL_NRM
);
331 /* Set the background position to cover the whole output image and
332 * configure its color.
334 vsp1_bru_write(bru
, VI6_BRU_VIRRPF_SIZE
,
335 (format
->width
<< VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT
) |
336 (format
->height
<< VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT
));
337 vsp1_bru_write(bru
, VI6_BRU_VIRRPF_LOC
, 0);
339 vsp1_bru_write(bru
, VI6_BRU_VIRRPF_COL
, bru
->bgcolor
|
340 (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT
));
342 /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
343 * unit with a NOP operation to make BRU input 1 available as the
344 * Blend/ROP unit B SRC input.
346 vsp1_bru_write(bru
, VI6_BRU_ROP
, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
347 VI6_BRU_ROP_CROP(VI6_ROP_NOP
) |
348 VI6_BRU_ROP_AROP(VI6_ROP_NOP
));
350 for (i
= 0; i
< bru
->entity
.source_pad
; ++i
) {
351 bool premultiplied
= false;
354 /* Configure all Blend/ROP units corresponding to an enabled BRU
355 * input for alpha blending. Blend/ROP units corresponding to
356 * disabled BRU inputs are used in ROP NOP mode to ignore the
359 if (bru
->inputs
[i
].rpf
) {
360 ctrl
|= VI6_BRU_CTRL_RBC
;
362 premultiplied
= bru
->inputs
[i
].rpf
->format
.flags
363 & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA
;
365 ctrl
|= VI6_BRU_CTRL_CROP(VI6_ROP_NOP
)
366 | VI6_BRU_CTRL_AROP(VI6_ROP_NOP
);
369 /* Select the virtual RPF as the Blend/ROP unit A DST input to
370 * serve as a background color.
373 ctrl
|= VI6_BRU_CTRL_DSTSEL_VRPF
;
375 /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
376 * D in that order. The Blend/ROP unit B SRC is hardwired to the
377 * ROP unit output, the corresponding register bits must be set
381 ctrl
|= VI6_BRU_CTRL_SRCSEL_BRUIN(i
);
383 vsp1_bru_write(bru
, VI6_BRU_CTRL(i
), ctrl
);
385 /* Harcode the blending formula to
387 * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
388 * DSTa = DSTa * (1 - SRCa) + SRCa
390 * when the SRC input isn't premultiplied, and to
392 * DSTc = DSTc * (1 - SRCa) + SRCc
393 * DSTa = DSTa * (1 - SRCa) + SRCa
397 vsp1_bru_write(bru
, VI6_BRU_BLD(i
),
398 VI6_BRU_BLD_CCMDX_255_SRC_A
|
399 (premultiplied
? VI6_BRU_BLD_CCMDY_COEFY
:
400 VI6_BRU_BLD_CCMDY_SRC_A
) |
401 VI6_BRU_BLD_ACMDX_255_SRC_A
|
402 VI6_BRU_BLD_ACMDY_COEFY
|
403 (0xff << VI6_BRU_BLD_COEFY_SHIFT
));
407 static const struct vsp1_entity_operations bru_entity_ops
= {
408 .configure
= bru_configure
,
411 /* -----------------------------------------------------------------------------
412 * Initialization and Cleanup
415 struct vsp1_bru
*vsp1_bru_create(struct vsp1_device
*vsp1
)
417 struct vsp1_bru
*bru
;
420 bru
= devm_kzalloc(vsp1
->dev
, sizeof(*bru
), GFP_KERNEL
);
422 return ERR_PTR(-ENOMEM
);
424 bru
->entity
.ops
= &bru_entity_ops
;
425 bru
->entity
.type
= VSP1_ENTITY_BRU
;
427 ret
= vsp1_entity_init(vsp1
, &bru
->entity
, "bru",
428 vsp1
->info
->num_bru_inputs
+ 1, &bru_ops
);
432 /* Initialize the control handler. */
433 v4l2_ctrl_handler_init(&bru
->ctrls
, 1);
434 v4l2_ctrl_new_std(&bru
->ctrls
, &bru_ctrl_ops
, V4L2_CID_BG_COLOR
,
439 bru
->entity
.subdev
.ctrl_handler
= &bru
->ctrls
;
441 if (bru
->ctrls
.error
) {
442 dev_err(vsp1
->dev
, "bru: failed to initialize controls\n");
443 ret
= bru
->ctrls
.error
;
444 vsp1_entity_destroy(&bru
->entity
);