aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-07-10 17:03:46 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-04-23 09:20:15 -0400
commit629bb6d4b38fe62d36ab52ad22c3ab726f6ce6e8 (patch)
treef826d26c1ecabf02fd1a3d8be8408e1d637e8ae7
parentd9b45ed3d8b75e8cf38c8cd1563c29217eecba27 (diff)
[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>
-rw-r--r--drivers/media/platform/vsp1/Makefile2
-rw-r--r--drivers/media/platform/vsp1/vsp1.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c395
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.h39
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c9
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c3
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h98
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c6
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h4
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c19
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c12
13 files changed, 586 insertions, 5 deletions
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile
index 151cecd0ea25..6a93f928dfde 100644
--- a/drivers/media/platform/vsp1/Makefile
+++ b/drivers/media/platform/vsp1/Makefile
@@ -1,6 +1,6 @@
1vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o 1vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
2vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o 2vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
3vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o 3vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
4vsp1-y += vsp1_sru.o vsp1_uds.o 4vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o
5 5
6obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o 6obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 8626e9b956c2..6ca2cf20d545 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -28,6 +28,7 @@ struct clk;
28struct device; 28struct device;
29 29
30struct vsp1_platform_data; 30struct vsp1_platform_data;
31struct vsp1_bru;
31struct vsp1_hsit; 32struct vsp1_hsit;
32struct vsp1_lif; 33struct vsp1_lif;
33struct vsp1_lut; 34struct vsp1_lut;
@@ -49,6 +50,7 @@ struct vsp1_device {
49 struct mutex lock; 50 struct mutex lock;
50 int ref_count; 51 int ref_count;
51 52
53 struct vsp1_bru *bru;
52 struct vsp1_hsit *hsi; 54 struct vsp1_hsit *hsi;
53 struct vsp1_hsit *hst; 55 struct vsp1_hsit *hst;
54 struct vsp1_lif *lif; 56 struct vsp1_lif *lif;
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
new file mode 100644
index 000000000000..f80695480060
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -0,0 +1,395 @@
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
29static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg)
30{
31 return vsp1_read(bru->entity.vsp1, reg);
32}
33
34static 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
43static 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
48static 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
142static 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
168static 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
187static 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
201static 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
212static 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
240static 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
277static 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
303static 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
343static struct v4l2_subdev_video_ops bru_video_ops = {
344 .s_stream = bru_s_stream,
345};
346
347static 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
356static 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
365struct 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}
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
new file mode 100644
index 000000000000..37062704dbf6
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -0,0 +1,39 @@
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
21struct vsp1_device;
22
23#define BRU_PAD_SINK(n) (n)
24#define BRU_PAD_SOURCE 4
25
26struct vsp1_bru {
27 struct vsp1_entity entity;
28
29 struct v4l2_rect compose[4];
30};
31
32static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
33{
34 return container_of(subdev, struct vsp1_bru, entity.subdev);
35}
36
37struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1);
38
39#endif /* __VSP1_BRU_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 3cd2df5af90e..28e1de3270e0 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -20,6 +20,7 @@
20#include <linux/videodev2.h> 20#include <linux/videodev2.h>
21 21
22#include "vsp1.h" 22#include "vsp1.h"
23#include "vsp1_bru.h"
23#include "vsp1_hsit.h" 24#include "vsp1_hsit.h"
24#include "vsp1_lif.h" 25#include "vsp1_lif.h"
25#include "vsp1_lut.h" 26#include "vsp1_lut.h"
@@ -155,6 +156,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
155 } 156 }
156 157
157 /* Instantiate all the entities. */ 158 /* Instantiate all the entities. */
159 vsp1->bru = vsp1_bru_create(vsp1);
160 if (IS_ERR(vsp1->bru)) {
161 ret = PTR_ERR(vsp1->bru);
162 goto done;
163 }
164
165 list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
166
158 vsp1->hsi = vsp1_hsit_create(vsp1, true); 167 vsp1->hsi = vsp1_hsit_create(vsp1, true);
159 if (IS_ERR(vsp1->hsi)) { 168 if (IS_ERR(vsp1->hsi)) {
160 ret = PTR_ERR(vsp1->hsi); 169 ret = PTR_ERR(vsp1->hsi);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index a9022f858aa5..44167834285d 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -119,6 +119,9 @@ const struct media_entity_operations vsp1_media_ops = {
119 */ 119 */
120 120
121static const struct vsp1_route vsp1_routes[] = { 121static 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 { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, 125 { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } },
123 { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, 126 { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } },
124 { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, 127 { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 3c6a5c831bcf..7afbd8a7ba66 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -20,6 +20,7 @@
20struct vsp1_device; 20struct vsp1_device;
21 21
22enum vsp1_entity_type { 22enum vsp1_entity_type {
23 VSP1_ENTITY_BRU,
23 VSP1_ENTITY_HSI, 24 VSP1_ENTITY_HSI,
24 VSP1_ENTITY_HST, 25 VSP1_ENTITY_HST,
25 VSP1_ENTITY_LIF, 26 VSP1_ENTITY_LIF,
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 28650806c20f..3e74b44286f6 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -451,13 +451,111 @@
451 * BRU Control Registers 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#define VI6_BRU_INCTRL 0x2c00 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#define VI6_BRU_VIRRPF_SIZE 0x2c04 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#define VI6_BRU_VIRRPF_LOC 0x2c08 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#define VI6_BRU_VIRRPF_COL 0x2c0c 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#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) 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#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) 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#define VI6_BRU_ROP 0x2c30 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 * HGO Control Registers 561 * HGO Control Registers
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 42444568b9fd..c3d98642a4aa 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -96,8 +96,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
96 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); 96 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
97 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); 97 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
98 98
99 /* Output location. Composing isn't supported yet. */ 99 /* Output location */
100 vsp1_rpf_write(rpf, VI6_RPF_LOC, 0); 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 /* Disable alpha, mask and color key. Set the alpha channel to a fixed 104 /* Disable alpha, mask and color key. Set the alpha channel to a fixed
103 * value of 255. 105 * value of 255.
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 5c5ee81bbeae..b4fb65e58770 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -30,6 +30,10 @@ struct vsp1_rwpf {
30 unsigned int max_width; 30 unsigned int max_width;
31 unsigned int max_height; 31 unsigned int max_height;
32 32
33 struct {
34 unsigned int left;
35 unsigned int top;
36 } location;
33 struct v4l2_rect crop; 37 struct v4l2_rect crop;
34 38
35 unsigned int offsets[2]; 39 unsigned int offsets[2];
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 1ef875d521da..8a1253e51f04 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -28,6 +28,7 @@
28#include <media/videobuf2-dma-contig.h> 28#include <media/videobuf2-dma-contig.h>
29 29
30#include "vsp1.h" 30#include "vsp1.h"
31#include "vsp1_bru.h"
31#include "vsp1_entity.h" 32#include "vsp1_entity.h"
32#include "vsp1_rwpf.h" 33#include "vsp1_rwpf.h"
33#include "vsp1_video.h" 34#include "vsp1_video.h"
@@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
280 struct media_pad *pad; 281 struct media_pad *pad;
281 bool uds_found = false; 282 bool uds_found = false;
282 283
284 input->location.left = 0;
285 input->location.top = 0;
286
283 pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); 287 pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
284 288
285 while (1) { 289 while (1) {
@@ -292,6 +296,17 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
292 296
293 entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); 297 entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
294 298
299 /* A BRU is present in the pipeline, store the compose rectangle
300 * location in the input RPF for use when configuring the RPF.
301 */
302 if (entity->type == VSP1_ENTITY_BRU) {
303 struct vsp1_bru *bru = to_bru(&entity->subdev);
304 struct v4l2_rect *rect = &bru->compose[pad->index];
305
306 input->location.left = rect->left;
307 input->location.top = rect->top;
308 }
309
295 /* We've reached the WPF, we're done. */ 310 /* We've reached the WPF, we're done. */
296 if (entity->type == VSP1_ENTITY_WPF) 311 if (entity->type == VSP1_ENTITY_WPF)
297 break; 312 break;
@@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
363 rwpf->video.pipe_index = 0; 378 rwpf->video.pipe_index = 0;
364 } else if (e->type == VSP1_ENTITY_LIF) { 379 } else if (e->type == VSP1_ENTITY_LIF) {
365 pipe->lif = e; 380 pipe->lif = e;
381 } else if (e->type == VSP1_ENTITY_BRU) {
382 pipe->bru = e;
366 } 383 }
367 } 384 }
368 385
@@ -392,6 +409,7 @@ error:
392 pipe->num_video = 0; 409 pipe->num_video = 0;
393 pipe->num_inputs = 0; 410 pipe->num_inputs = 0;
394 pipe->output = NULL; 411 pipe->output = NULL;
412 pipe->bru = NULL;
395 pipe->lif = NULL; 413 pipe->lif = NULL;
396 return ret; 414 return ret;
397} 415}
@@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
430 pipe->num_video = 0; 448 pipe->num_video = 0;
431 pipe->num_inputs = 0; 449 pipe->num_inputs = 0;
432 pipe->output = NULL; 450 pipe->output = NULL;
451 pipe->bru = NULL;
433 pipe->lif = NULL; 452 pipe->lif = NULL;
434 } 453 }
435 454
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h
index 53e4b3745940..c04d48fa2999 100644
--- a/drivers/media/platform/vsp1/vsp1_video.h
+++ b/drivers/media/platform/vsp1/vsp1_video.h
@@ -75,6 +75,7 @@ struct vsp1_pipeline {
75 unsigned int num_inputs; 75 unsigned int num_inputs;
76 struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; 76 struct vsp1_rwpf *inputs[VPS1_MAX_RPF];
77 struct vsp1_rwpf *output; 77 struct vsp1_rwpf *output;
78 struct vsp1_entity *bru;
78 struct vsp1_entity *lif; 79 struct vsp1_entity *lif;
79 80
80 struct list_head entities; 81 struct list_head entities;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index ef9f88ead319..1294340dcb36 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
58 return 0; 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 for (i = 0; i < pipe->num_inputs; ++i) { 65 for (i = 0; i < pipe->num_inputs; ++i) {
63 struct vsp1_rwpf *input = pipe->inputs[i]; 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 }
67 72
73 if (pipe->num_inputs > 1)
74 srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
75
68 vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); 76 vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
69 77
70 /* Destination stride. */ 78 /* Destination stride. */