Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] v4l: vsp1: Add BRU support

The Blend ROP Unit performs blending and ROP operations for up to four
sources.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
629bb6d4 d9b45ed3

+586 -5
+1 -1
drivers/media/platform/vsp1/Makefile
··· 1 1 vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o 2 2 vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o 3 3 vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o 4 - vsp1-y += vsp1_sru.o vsp1_uds.o 4 + vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o 5 5 6 6 obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
+2
drivers/media/platform/vsp1/vsp1.h
··· 28 28 struct device; 29 29 30 30 struct vsp1_platform_data; 31 + struct vsp1_bru; 31 32 struct vsp1_hsit; 32 33 struct vsp1_lif; 33 34 struct vsp1_lut; ··· 50 49 struct mutex lock; 51 50 int ref_count; 52 51 52 + struct vsp1_bru *bru; 53 53 struct vsp1_hsit *hsi; 54 54 struct vsp1_hsit *hst; 55 55 struct vsp1_lif *lif;
+395
drivers/media/platform/vsp1/vsp1_bru.c
··· 1 + /* 2 + * vsp1_bru.c -- R-Car VSP1 Blend ROP Unit 3 + * 4 + * Copyright (C) 2013 Renesas 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/gfp.h> 16 + 17 + #include <media/v4l2-subdev.h> 18 + 19 + #include "vsp1.h" 20 + #include "vsp1_bru.h" 21 + 22 + #define BRU_MIN_SIZE 4U 23 + #define BRU_MAX_SIZE 8190U 24 + 25 + /* ----------------------------------------------------------------------------- 26 + * Device Access 27 + */ 28 + 29 + static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg) 30 + { 31 + return vsp1_read(bru->entity.vsp1, reg); 32 + } 33 + 34 + static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) 35 + { 36 + vsp1_write(bru->entity.vsp1, reg, data); 37 + } 38 + 39 + /* ----------------------------------------------------------------------------- 40 + * V4L2 Subdevice Core Operations 41 + */ 42 + 43 + static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input) 44 + { 45 + return media_entity_remote_pad(&bru->entity.pads[input]) != NULL; 46 + } 47 + 48 + static int bru_s_stream(struct v4l2_subdev *subdev, int enable) 49 + { 50 + struct vsp1_bru *bru = to_bru(subdev); 51 + struct v4l2_mbus_framefmt *format; 52 + unsigned int i; 53 + 54 + if (!enable) 55 + return 0; 56 + 57 + format = &bru->entity.formats[BRU_PAD_SOURCE]; 58 + 59 + /* The hardware is extremely flexible but we have no userspace API to 60 + * expose all the parameters, nor is it clear whether we would have use 61 + * cases for all the supported modes. Let's just harcode the parameters 62 + * to sane default values for now. 63 + */ 64 + 65 + /* Disable both color data normalization and dithering. */ 66 + vsp1_bru_write(bru, VI6_BRU_INCTRL, 0); 67 + 68 + /* Set the background position to cover the whole output image and 69 + * set its color to opaque black. 70 + */ 71 + vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, 72 + (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | 73 + (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); 74 + vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); 75 + vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, 76 + 0xff << VI6_BRU_VIRRPF_COL_A_SHIFT); 77 + 78 + /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP 79 + * unit with a NOP operation to make BRU input 1 available as the 80 + * Blend/ROP unit B SRC input. 81 + */ 82 + vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | 83 + VI6_BRU_ROP_CROP(VI6_ROP_NOP) | 84 + VI6_BRU_ROP_AROP(VI6_ROP_NOP)); 85 + 86 + for (i = 0; i < 4; ++i) { 87 + u32 ctrl = 0; 88 + 89 + /* Configure all Blend/ROP units corresponding to an enabled BRU 90 + * input for alpha blending. Blend/ROP units corresponding to 91 + * disabled BRU inputs are used in ROP NOP mode to ignore the 92 + * SRC input. 93 + */ 94 + if (bru_is_input_enabled(bru, i)) 95 + ctrl |= VI6_BRU_CTRL_RBC; 96 + else 97 + ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) 98 + | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); 99 + 100 + /* Select the virtual RPF as the Blend/ROP unit A DST input to 101 + * serve as a background color. 102 + */ 103 + if (i == 0) 104 + ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; 105 + 106 + /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to 107 + * D in that order. The Blend/ROP unit B SRC is hardwired to the 108 + * ROP unit output, the corresponding register bits must be set 109 + * to 0. 110 + */ 111 + if (i != 1) 112 + ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); 113 + 114 + vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); 115 + 116 + /* Harcode the blending formula to 117 + * 118 + * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa 119 + * DSTa = DSTa * (1 - SRCa) + SRCa 120 + */ 121 + vsp1_bru_write(bru, VI6_BRU_BLD(i), 122 + VI6_BRU_BLD_CCMDX_255_SRC_A | 123 + VI6_BRU_BLD_CCMDY_SRC_A | 124 + VI6_BRU_BLD_ACMDX_255_SRC_A | 125 + VI6_BRU_BLD_ACMDY_COEFY | 126 + (0xff << VI6_BRU_BLD_COEFY_SHIFT)); 127 + } 128 + 129 + return 0; 130 + } 131 + 132 + /* ----------------------------------------------------------------------------- 133 + * V4L2 Subdevice Pad Operations 134 + */ 135 + 136 + /* 137 + * The BRU can't perform format conversion, all sink and source formats must be 138 + * identical. We pick the format on the first sink pad (pad 0) and propagate it 139 + * to all other pads. 140 + */ 141 + 142 + static int bru_enum_mbus_code(struct v4l2_subdev *subdev, 143 + struct v4l2_subdev_fh *fh, 144 + struct v4l2_subdev_mbus_code_enum *code) 145 + { 146 + static const unsigned int codes[] = { 147 + V4L2_MBUS_FMT_ARGB8888_1X32, 148 + V4L2_MBUS_FMT_AYUV8_1X32, 149 + }; 150 + struct v4l2_mbus_framefmt *format; 151 + 152 + if (code->pad == BRU_PAD_SINK(0)) { 153 + if (code->index >= ARRAY_SIZE(codes)) 154 + return -EINVAL; 155 + 156 + code->code = codes[code->index]; 157 + } else { 158 + if (code->index) 159 + return -EINVAL; 160 + 161 + format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); 162 + code->code = format->code; 163 + } 164 + 165 + return 0; 166 + } 167 + 168 + static int bru_enum_frame_size(struct v4l2_subdev *subdev, 169 + struct v4l2_subdev_fh *fh, 170 + struct v4l2_subdev_frame_size_enum *fse) 171 + { 172 + if (fse->index) 173 + return -EINVAL; 174 + 175 + if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 && 176 + fse->code != V4L2_MBUS_FMT_AYUV8_1X32) 177 + return -EINVAL; 178 + 179 + fse->min_width = BRU_MIN_SIZE; 180 + fse->max_width = BRU_MAX_SIZE; 181 + fse->min_height = BRU_MIN_SIZE; 182 + fse->max_height = BRU_MAX_SIZE; 183 + 184 + return 0; 185 + } 186 + 187 + static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, 188 + struct v4l2_subdev_fh *fh, 189 + unsigned int pad, u32 which) 190 + { 191 + switch (which) { 192 + case V4L2_SUBDEV_FORMAT_TRY: 193 + return v4l2_subdev_get_try_crop(fh, pad); 194 + case V4L2_SUBDEV_FORMAT_ACTIVE: 195 + return &bru->compose[pad]; 196 + default: 197 + return NULL; 198 + } 199 + } 200 + 201 + static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, 202 + struct v4l2_subdev_format *fmt) 203 + { 204 + struct vsp1_bru *bru = to_bru(subdev); 205 + 206 + fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, 207 + fmt->which); 208 + 209 + return 0; 210 + } 211 + 212 + static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, 213 + unsigned int pad, struct v4l2_mbus_framefmt *fmt, 214 + enum v4l2_subdev_format_whence which) 215 + { 216 + struct v4l2_mbus_framefmt *format; 217 + 218 + switch (pad) { 219 + case BRU_PAD_SINK(0): 220 + /* Default to YUV if the requested format is not supported. */ 221 + if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && 222 + fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) 223 + fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; 224 + break; 225 + 226 + default: 227 + /* The BRU can't perform format conversion. */ 228 + format = vsp1_entity_get_pad_format(&bru->entity, fh, 229 + BRU_PAD_SINK(0), which); 230 + fmt->code = format->code; 231 + break; 232 + } 233 + 234 + fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); 235 + fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); 236 + fmt->field = V4L2_FIELD_NONE; 237 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 238 + } 239 + 240 + static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, 241 + struct v4l2_subdev_format *fmt) 242 + { 243 + struct vsp1_bru *bru = to_bru(subdev); 244 + struct v4l2_mbus_framefmt *format; 245 + 246 + bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); 247 + 248 + format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, 249 + fmt->which); 250 + *format = fmt->format; 251 + 252 + /* Reset the compose rectangle */ 253 + if (fmt->pad != BRU_PAD_SOURCE) { 254 + struct v4l2_rect *compose; 255 + 256 + compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); 257 + compose->left = 0; 258 + compose->top = 0; 259 + compose->width = format->width; 260 + compose->height = format->height; 261 + } 262 + 263 + /* Propagate the format code to all pads */ 264 + if (fmt->pad == BRU_PAD_SINK(0)) { 265 + unsigned int i; 266 + 267 + for (i = 0; i <= BRU_PAD_SOURCE; ++i) { 268 + format = vsp1_entity_get_pad_format(&bru->entity, fh, 269 + i, fmt->which); 270 + format->code = fmt->format.code; 271 + } 272 + } 273 + 274 + return 0; 275 + } 276 + 277 + static int bru_get_selection(struct v4l2_subdev *subdev, 278 + struct v4l2_subdev_fh *fh, 279 + struct v4l2_subdev_selection *sel) 280 + { 281 + struct vsp1_bru *bru = to_bru(subdev); 282 + 283 + if (sel->pad == BRU_PAD_SOURCE) 284 + return -EINVAL; 285 + 286 + switch (sel->target) { 287 + case V4L2_SEL_TGT_COMPOSE_BOUNDS: 288 + sel->r.left = 0; 289 + sel->r.top = 0; 290 + sel->r.width = BRU_MAX_SIZE; 291 + sel->r.height = BRU_MAX_SIZE; 292 + return 0; 293 + 294 + case V4L2_SEL_TGT_COMPOSE: 295 + sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); 296 + return 0; 297 + 298 + default: 299 + return -EINVAL; 300 + } 301 + } 302 + 303 + static int bru_set_selection(struct v4l2_subdev *subdev, 304 + struct v4l2_subdev_fh *fh, 305 + struct v4l2_subdev_selection *sel) 306 + { 307 + struct vsp1_bru *bru = to_bru(subdev); 308 + struct v4l2_mbus_framefmt *format; 309 + struct v4l2_rect *compose; 310 + 311 + if (sel->pad == BRU_PAD_SOURCE) 312 + return -EINVAL; 313 + 314 + if (sel->target != V4L2_SEL_TGT_COMPOSE) 315 + return -EINVAL; 316 + 317 + /* The compose rectangle top left corner must be inside the output 318 + * frame. 319 + */ 320 + format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, 321 + sel->which); 322 + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 323 + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); 324 + 325 + /* Scaling isn't supported, the compose rectangle size must be identical 326 + * to the sink format size. 327 + */ 328 + format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, 329 + sel->which); 330 + sel->r.width = format->width; 331 + sel->r.height = format->height; 332 + 333 + compose = bru_get_compose(bru, fh, sel->pad, sel->which); 334 + *compose = sel->r; 335 + 336 + return 0; 337 + } 338 + 339 + /* ----------------------------------------------------------------------------- 340 + * V4L2 Subdevice Operations 341 + */ 342 + 343 + static struct v4l2_subdev_video_ops bru_video_ops = { 344 + .s_stream = bru_s_stream, 345 + }; 346 + 347 + static struct v4l2_subdev_pad_ops bru_pad_ops = { 348 + .enum_mbus_code = bru_enum_mbus_code, 349 + .enum_frame_size = bru_enum_frame_size, 350 + .get_fmt = bru_get_format, 351 + .set_fmt = bru_set_format, 352 + .get_selection = bru_get_selection, 353 + .set_selection = bru_set_selection, 354 + }; 355 + 356 + static struct v4l2_subdev_ops bru_ops = { 357 + .video = &bru_video_ops, 358 + .pad = &bru_pad_ops, 359 + }; 360 + 361 + /* ----------------------------------------------------------------------------- 362 + * Initialization and Cleanup 363 + */ 364 + 365 + struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) 366 + { 367 + struct v4l2_subdev *subdev; 368 + struct vsp1_bru *bru; 369 + int ret; 370 + 371 + bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL); 372 + if (bru == NULL) 373 + return ERR_PTR(-ENOMEM); 374 + 375 + bru->entity.type = VSP1_ENTITY_BRU; 376 + 377 + ret = vsp1_entity_init(vsp1, &bru->entity, 5); 378 + if (ret < 0) 379 + return ERR_PTR(ret); 380 + 381 + /* Initialize the V4L2 subdev. */ 382 + subdev = &bru->entity.subdev; 383 + v4l2_subdev_init(subdev, &bru_ops); 384 + 385 + subdev->entity.ops = &vsp1_media_ops; 386 + subdev->internal_ops = &vsp1_subdev_internal_ops; 387 + snprintf(subdev->name, sizeof(subdev->name), "%s bru", 388 + dev_name(vsp1->dev)); 389 + v4l2_set_subdevdata(subdev, bru); 390 + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 391 + 392 + vsp1_entity_init_formats(subdev, NULL); 393 + 394 + return bru; 395 + }
+39
drivers/media/platform/vsp1/vsp1_bru.h
··· 1 + /* 2 + * vsp1_bru.h -- R-Car VSP1 Blend ROP Unit 3 + * 4 + * Copyright (C) 2013 Renesas 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 + #ifndef __VSP1_BRU_H__ 14 + #define __VSP1_BRU_H__ 15 + 16 + #include <media/media-entity.h> 17 + #include <media/v4l2-subdev.h> 18 + 19 + #include "vsp1_entity.h" 20 + 21 + struct vsp1_device; 22 + 23 + #define BRU_PAD_SINK(n) (n) 24 + #define BRU_PAD_SOURCE 4 25 + 26 + struct vsp1_bru { 27 + struct vsp1_entity entity; 28 + 29 + struct v4l2_rect compose[4]; 30 + }; 31 + 32 + static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) 33 + { 34 + return container_of(subdev, struct vsp1_bru, entity.subdev); 35 + } 36 + 37 + struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1); 38 + 39 + #endif /* __VSP1_BRU_H__ */
+9
drivers/media/platform/vsp1/vsp1_drv.c
··· 20 20 #include <linux/videodev2.h> 21 21 22 22 #include "vsp1.h" 23 + #include "vsp1_bru.h" 23 24 #include "vsp1_hsit.h" 24 25 #include "vsp1_lif.h" 25 26 #include "vsp1_lut.h" ··· 156 155 } 157 156 158 157 /* Instantiate all the entities. */ 158 + vsp1->bru = vsp1_bru_create(vsp1); 159 + if (IS_ERR(vsp1->bru)) { 160 + ret = PTR_ERR(vsp1->bru); 161 + goto done; 162 + } 163 + 164 + list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); 165 + 159 166 vsp1->hsi = vsp1_hsit_create(vsp1, true); 160 167 if (IS_ERR(vsp1->hsi)) { 161 168 ret = PTR_ERR(vsp1->hsi);
+3
drivers/media/platform/vsp1/vsp1_entity.c
··· 119 119 */ 120 120 121 121 static const struct vsp1_route vsp1_routes[] = { 122 + { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, 123 + { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), 124 + VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } }, 122 125 { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, 123 126 { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, 124 127 { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
+1
drivers/media/platform/vsp1/vsp1_entity.h
··· 20 20 struct vsp1_device; 21 21 22 22 enum vsp1_entity_type { 23 + VSP1_ENTITY_BRU, 23 24 VSP1_ENTITY_HSI, 24 25 VSP1_ENTITY_HST, 25 26 VSP1_ENTITY_LIF,
+98
drivers/media/platform/vsp1/vsp1_regs.h
··· 451 451 * BRU Control Registers 452 452 */ 453 453 454 + #define VI6_ROP_NOP 0 455 + #define VI6_ROP_AND 1 456 + #define VI6_ROP_AND_REV 2 457 + #define VI6_ROP_COPY 3 458 + #define VI6_ROP_AND_INV 4 459 + #define VI6_ROP_CLEAR 5 460 + #define VI6_ROP_XOR 6 461 + #define VI6_ROP_OR 7 462 + #define VI6_ROP_NOR 8 463 + #define VI6_ROP_EQUIV 9 464 + #define VI6_ROP_INVERT 10 465 + #define VI6_ROP_OR_REV 11 466 + #define VI6_ROP_COPY_INV 12 467 + #define VI6_ROP_OR_INV 13 468 + #define VI6_ROP_NAND 14 469 + #define VI6_ROP_SET 15 470 + 454 471 #define VI6_BRU_INCTRL 0x2c00 472 + #define VI6_BRU_INCTRL_NRM (1 << 28) 473 + #define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) 474 + #define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) 475 + #define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4)) 476 + #define VI6_BRU_INCTRL_DITHn_16BPP (2 << ((n) * 4)) 477 + #define VI6_BRU_INCTRL_DITHn_15BPP (3 << ((n) * 4)) 478 + #define VI6_BRU_INCTRL_DITHn_12BPP (4 << ((n) * 4)) 479 + #define VI6_BRU_INCTRL_DITHn_8BPP (5 << ((n) * 4)) 480 + #define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4)) 481 + #define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4) 482 + 455 483 #define VI6_BRU_VIRRPF_SIZE 0x2c04 484 + #define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16) 485 + #define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16 486 + #define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0) 487 + #define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0 488 + 456 489 #define VI6_BRU_VIRRPF_LOC 0x2c08 490 + #define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16) 491 + #define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16 492 + #define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0) 493 + #define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0 494 + 457 495 #define VI6_BRU_VIRRPF_COL 0x2c0c 496 + #define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24) 497 + #define VI6_BRU_VIRRPF_COL_A_SHIFT 24 498 + #define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16) 499 + #define VI6_BRU_VIRRPF_COL_RCR_SHIFT 16 500 + #define VI6_BRU_VIRRPF_COL_GY_MASK (0xff << 8) 501 + #define VI6_BRU_VIRRPF_COL_GY_SHIFT 8 502 + #define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0) 503 + #define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 504 + 458 505 #define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) 506 + #define VI6_BRU_CTRL_RBC (1 << 31) 507 + #define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20) 508 + #define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) 509 + #define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20) 510 + #define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16) 511 + #define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16) 512 + #define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16) 513 + #define VI6_BRU_CTRL_CROP(rop) ((rop) << 4) 514 + #define VI6_BRU_CTRL_CROP_MASK (0xf << 4) 515 + #define VI6_BRU_CTRL_AROP(rop) ((rop) << 0) 516 + #define VI6_BRU_CTRL_AROP_MASK (0xf << 0) 517 + 459 518 #define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) 519 + #define VI6_BRU_BLD_CBES (1 << 31) 520 + #define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) 521 + #define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) 522 + #define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28) 523 + #define VI6_BRU_BLD_CCMDX_255_SRC_A (3 << 28) 524 + #define VI6_BRU_BLD_CCMDX_COEFX (4 << 28) 525 + #define VI6_BRU_BLD_CCMDX_MASK (7 << 28) 526 + #define VI6_BRU_BLD_CCMDY_DST_A (0 << 24) 527 + #define VI6_BRU_BLD_CCMDY_255_DST_A (1 << 24) 528 + #define VI6_BRU_BLD_CCMDY_SRC_A (2 << 24) 529 + #define VI6_BRU_BLD_CCMDY_255_SRC_A (3 << 24) 530 + #define VI6_BRU_BLD_CCMDY_COEFY (4 << 24) 531 + #define VI6_BRU_BLD_CCMDY_MASK (7 << 24) 532 + #define VI6_BRU_BLD_CCMDY_SHIFT 24 533 + #define VI6_BRU_BLD_ABES (1 << 23) 534 + #define VI6_BRU_BLD_ACMDX_DST_A (0 << 20) 535 + #define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20) 536 + #define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20) 537 + #define VI6_BRU_BLD_ACMDX_255_SRC_A (3 << 20) 538 + #define VI6_BRU_BLD_ACMDX_COEFX (4 << 20) 539 + #define VI6_BRU_BLD_ACMDX_MASK (7 << 20) 540 + #define VI6_BRU_BLD_ACMDY_DST_A (0 << 16) 541 + #define VI6_BRU_BLD_ACMDY_255_DST_A (1 << 16) 542 + #define VI6_BRU_BLD_ACMDY_SRC_A (2 << 16) 543 + #define VI6_BRU_BLD_ACMDY_255_SRC_A (3 << 16) 544 + #define VI6_BRU_BLD_ACMDY_COEFY (4 << 16) 545 + #define VI6_BRU_BLD_ACMDY_MASK (7 << 16) 546 + #define VI6_BRU_BLD_COEFX_MASK (0xff << 8) 547 + #define VI6_BRU_BLD_COEFX_SHIFT 8 548 + #define VI6_BRU_BLD_COEFY_MASK (0xff << 0) 549 + #define VI6_BRU_BLD_COEFY_SHIFT 0 550 + 460 551 #define VI6_BRU_ROP 0x2c30 552 + #define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20) 553 + #define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20) 554 + #define VI6_BRU_ROP_DSTSEL_MASK (7 << 20) 555 + #define VI6_BRU_ROP_CROP(rop) ((rop) << 4) 556 + #define VI6_BRU_ROP_CROP_MASK (0xf << 4) 557 + #define VI6_BRU_ROP_AROP(rop) ((rop) << 0) 558 + #define VI6_BRU_ROP_AROP_MASK (0xf << 0) 461 559 462 560 /* ----------------------------------------------------------------------------- 463 561 * HGO Control Registers
+4 -2
drivers/media/platform/vsp1/vsp1_rpf.c
··· 96 96 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); 97 97 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); 98 98 99 - /* Output location. Composing isn't supported yet. */ 100 - vsp1_rpf_write(rpf, VI6_RPF_LOC, 0); 99 + /* Output location */ 100 + vsp1_rpf_write(rpf, VI6_RPF_LOC, 101 + (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | 102 + (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); 101 103 102 104 /* Disable alpha, mask and color key. Set the alpha channel to a fixed 103 105 * value of 255.
+4
drivers/media/platform/vsp1/vsp1_rwpf.h
··· 30 30 unsigned int max_width; 31 31 unsigned int max_height; 32 32 33 + struct { 34 + unsigned int left; 35 + unsigned int top; 36 + } location; 33 37 struct v4l2_rect crop; 34 38 35 39 unsigned int offsets[2];
+19
drivers/media/platform/vsp1/vsp1_video.c
··· 28 28 #include <media/videobuf2-dma-contig.h> 29 29 30 30 #include "vsp1.h" 31 + #include "vsp1_bru.h" 31 32 #include "vsp1_entity.h" 32 33 #include "vsp1_rwpf.h" 33 34 #include "vsp1_video.h" ··· 281 280 struct media_pad *pad; 282 281 bool uds_found = false; 283 282 283 + input->location.left = 0; 284 + input->location.top = 0; 285 + 284 286 pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); 285 287 286 288 while (1) { ··· 295 291 return -EPIPE; 296 292 297 293 entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); 294 + 295 + /* A BRU is present in the pipeline, store the compose rectangle 296 + * location in the input RPF for use when configuring the RPF. 297 + */ 298 + if (entity->type == VSP1_ENTITY_BRU) { 299 + struct vsp1_bru *bru = to_bru(&entity->subdev); 300 + struct v4l2_rect *rect = &bru->compose[pad->index]; 301 + 302 + input->location.left = rect->left; 303 + input->location.top = rect->top; 304 + } 298 305 299 306 /* We've reached the WPF, we're done. */ 300 307 if (entity->type == VSP1_ENTITY_WPF) ··· 378 363 rwpf->video.pipe_index = 0; 379 364 } else if (e->type == VSP1_ENTITY_LIF) { 380 365 pipe->lif = e; 366 + } else if (e->type == VSP1_ENTITY_BRU) { 367 + pipe->bru = e; 381 368 } 382 369 } 383 370 ··· 409 392 pipe->num_video = 0; 410 393 pipe->num_inputs = 0; 411 394 pipe->output = NULL; 395 + pipe->bru = NULL; 412 396 pipe->lif = NULL; 413 397 return ret; 414 398 } ··· 448 430 pipe->num_video = 0; 449 431 pipe->num_inputs = 0; 450 432 pipe->output = NULL; 433 + pipe->bru = NULL; 451 434 pipe->lif = NULL; 452 435 } 453 436
+1
drivers/media/platform/vsp1/vsp1_video.h
··· 75 75 unsigned int num_inputs; 76 76 struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; 77 77 struct vsp1_rwpf *output; 78 + struct vsp1_entity *bru; 78 79 struct vsp1_entity *lif; 79 80 80 81 struct list_head entities;
+10 -2
drivers/media/platform/vsp1/vsp1_wpf.c
··· 58 58 return 0; 59 59 } 60 60 61 - /* Sources */ 61 + /* Sources. If the pipeline has a single input configure it as the 62 + * master layer. Otherwise configure all inputs as sub-layers and 63 + * select the virtual RPF as the master layer. 64 + */ 62 65 for (i = 0; i < pipe->num_inputs; ++i) { 63 66 struct vsp1_rwpf *input = pipe->inputs[i]; 64 67 65 - srcrpf |= VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index); 68 + srcrpf |= pipe->num_inputs == 1 69 + ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) 70 + : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); 66 71 } 72 + 73 + if (pipe->num_inputs > 1) 74 + srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; 67 75 68 76 vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); 69 77