[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>
This commit is contained in:
Родитель
d9b45ed3d8
Коммит
629bb6d4b3
|
@ -1,6 +1,6 @@
|
|||
vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
|
||||
vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
|
||||
vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
|
||||
vsp1-y += vsp1_sru.o vsp1_uds.o
|
||||
vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
|
||||
|
|
|
@ -28,6 +28,7 @@ struct clk;
|
|||
struct device;
|
||||
|
||||
struct vsp1_platform_data;
|
||||
struct vsp1_bru;
|
||||
struct vsp1_hsit;
|
||||
struct vsp1_lif;
|
||||
struct vsp1_lut;
|
||||
|
@ -49,6 +50,7 @@ struct vsp1_device {
|
|||
struct mutex lock;
|
||||
int ref_count;
|
||||
|
||||
struct vsp1_bru *bru;
|
||||
struct vsp1_hsit *hsi;
|
||||
struct vsp1_hsit *hst;
|
||||
struct vsp1_lif *lif;
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* vsp1_bru.c -- R-Car VSP1 Blend ROP Unit
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_bru.h"
|
||||
|
||||
#define BRU_MIN_SIZE 4U
|
||||
#define BRU_MAX_SIZE 8190U
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Device Access
|
||||
*/
|
||||
|
||||
static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg)
|
||||
{
|
||||
return vsp1_read(bru->entity.vsp1, reg);
|
||||
}
|
||||
|
||||
static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
|
||||
{
|
||||
vsp1_write(bru->entity.vsp1, reg, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
*/
|
||||
|
||||
static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input)
|
||||
{
|
||||
return media_entity_remote_pad(&bru->entity.pads[input]) != NULL;
|
||||
}
|
||||
|
||||
static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
unsigned int i;
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
format = &bru->entity.formats[BRU_PAD_SOURCE];
|
||||
|
||||
/* The hardware is extremely flexible but we have no userspace API to
|
||||
* expose all the parameters, nor is it clear whether we would have use
|
||||
* cases for all the supported modes. Let's just harcode the parameters
|
||||
* to sane default values for now.
|
||||
*/
|
||||
|
||||
/* Disable both color data normalization and dithering. */
|
||||
vsp1_bru_write(bru, VI6_BRU_INCTRL, 0);
|
||||
|
||||
/* Set the background position to cover the whole output image and
|
||||
* set its color to opaque black.
|
||||
*/
|
||||
vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
|
||||
(format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
|
||||
(format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
|
||||
vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
|
||||
vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL,
|
||||
0xff << VI6_BRU_VIRRPF_COL_A_SHIFT);
|
||||
|
||||
/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
|
||||
* unit with a NOP operation to make BRU input 1 available as the
|
||||
* Blend/ROP unit B SRC input.
|
||||
*/
|
||||
vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
|
||||
VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
|
||||
VI6_BRU_ROP_AROP(VI6_ROP_NOP));
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
u32 ctrl = 0;
|
||||
|
||||
/* Configure all Blend/ROP units corresponding to an enabled BRU
|
||||
* input for alpha blending. Blend/ROP units corresponding to
|
||||
* disabled BRU inputs are used in ROP NOP mode to ignore the
|
||||
* SRC input.
|
||||
*/
|
||||
if (bru_is_input_enabled(bru, i))
|
||||
ctrl |= VI6_BRU_CTRL_RBC;
|
||||
else
|
||||
ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
|
||||
| VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
|
||||
|
||||
/* Select the virtual RPF as the Blend/ROP unit A DST input to
|
||||
* serve as a background color.
|
||||
*/
|
||||
if (i == 0)
|
||||
ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
|
||||
|
||||
/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
|
||||
* D in that order. The Blend/ROP unit B SRC is hardwired to the
|
||||
* ROP unit output, the corresponding register bits must be set
|
||||
* to 0.
|
||||
*/
|
||||
if (i != 1)
|
||||
ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
|
||||
|
||||
vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
|
||||
|
||||
/* Harcode the blending formula to
|
||||
*
|
||||
* DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
|
||||
* DSTa = DSTa * (1 - SRCa) + SRCa
|
||||
*/
|
||||
vsp1_bru_write(bru, VI6_BRU_BLD(i),
|
||||
VI6_BRU_BLD_CCMDX_255_SRC_A |
|
||||
VI6_BRU_BLD_CCMDY_SRC_A |
|
||||
VI6_BRU_BLD_ACMDX_255_SRC_A |
|
||||
VI6_BRU_BLD_ACMDY_COEFY |
|
||||
(0xff << VI6_BRU_BLD_COEFY_SHIFT));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
||||
/*
|
||||
* The BRU can't perform format conversion, all sink and source formats must be
|
||||
* identical. We pick the format on the first sink pad (pad 0) and propagate it
|
||||
* to all other pads.
|
||||
*/
|
||||
|
||||
static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
static const unsigned int codes[] = {
|
||||
V4L2_MBUS_FMT_ARGB8888_1X32,
|
||||
V4L2_MBUS_FMT_AYUV8_1X32,
|
||||
};
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
if (code->pad == BRU_PAD_SINK(0)) {
|
||||
if (code->index >= ARRAY_SIZE(codes))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = codes[code->index];
|
||||
} else {
|
||||
if (code->index)
|
||||
return -EINVAL;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0));
|
||||
code->code = format->code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bru_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
if (fse->index)
|
||||
return -EINVAL;
|
||||
|
||||
if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||
fse->code != V4L2_MBUS_FMT_AYUV8_1X32)
|
||||
return -EINVAL;
|
||||
|
||||
fse->min_width = BRU_MIN_SIZE;
|
||||
fse->max_width = BRU_MAX_SIZE;
|
||||
fse->min_height = BRU_MIN_SIZE;
|
||||
fse->max_height = BRU_MAX_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
unsigned int pad, u32 which)
|
||||
{
|
||||
switch (which) {
|
||||
case V4L2_SUBDEV_FORMAT_TRY:
|
||||
return v4l2_subdev_get_try_crop(fh, pad);
|
||||
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||
return &bru->compose[pad];
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(subdev);
|
||||
|
||||
fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
|
||||
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
|
||||
enum v4l2_subdev_format_whence which)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
switch (pad) {
|
||||
case BRU_PAD_SINK(0):
|
||||
/* Default to YUV if the requested format is not supported. */
|
||||
if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||
fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
|
||||
fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* The BRU can't perform format conversion. */
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, fh,
|
||||
BRU_PAD_SINK(0), which);
|
||||
fmt->code = format->code;
|
||||
break;
|
||||
}
|
||||
|
||||
fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE);
|
||||
fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE);
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
}
|
||||
|
||||
static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which);
|
||||
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
*format = fmt->format;
|
||||
|
||||
/* Reset the compose rectangle */
|
||||
if (fmt->pad != BRU_PAD_SOURCE) {
|
||||
struct v4l2_rect *compose;
|
||||
|
||||
compose = bru_get_compose(bru, fh, fmt->pad, fmt->which);
|
||||
compose->left = 0;
|
||||
compose->top = 0;
|
||||
compose->width = format->width;
|
||||
compose->height = format->height;
|
||||
}
|
||||
|
||||
/* Propagate the format code to all pads */
|
||||
if (fmt->pad == BRU_PAD_SINK(0)) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i <= BRU_PAD_SOURCE; ++i) {
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, fh,
|
||||
i, fmt->which);
|
||||
format->code = fmt->format.code;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bru_get_selection(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_selection *sel)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(subdev);
|
||||
|
||||
if (sel->pad == BRU_PAD_SOURCE)
|
||||
return -EINVAL;
|
||||
|
||||
switch (sel->target) {
|
||||
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
|
||||
sel->r.left = 0;
|
||||
sel->r.top = 0;
|
||||
sel->r.width = BRU_MAX_SIZE;
|
||||
sel->r.height = BRU_MAX_SIZE;
|
||||
return 0;
|
||||
|
||||
case V4L2_SEL_TGT_COMPOSE:
|
||||
sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int bru_set_selection(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_selection *sel)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
struct v4l2_rect *compose;
|
||||
|
||||
if (sel->pad == BRU_PAD_SOURCE)
|
||||
return -EINVAL;
|
||||
|
||||
if (sel->target != V4L2_SEL_TGT_COMPOSE)
|
||||
return -EINVAL;
|
||||
|
||||
/* The compose rectangle top left corner must be inside the output
|
||||
* frame.
|
||||
*/
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE,
|
||||
sel->which);
|
||||
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
|
||||
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
|
||||
|
||||
/* Scaling isn't supported, the compose rectangle size must be identical
|
||||
* to the sink format size.
|
||||
*/
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad,
|
||||
sel->which);
|
||||
sel->r.width = format->width;
|
||||
sel->r.height = format->height;
|
||||
|
||||
compose = bru_get_compose(bru, fh, sel->pad, sel->which);
|
||||
*compose = sel->r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_video_ops bru_video_ops = {
|
||||
.s_stream = bru_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops bru_pad_ops = {
|
||||
.enum_mbus_code = bru_enum_mbus_code,
|
||||
.enum_frame_size = bru_enum_frame_size,
|
||||
.get_fmt = bru_get_format,
|
||||
.set_fmt = bru_set_format,
|
||||
.get_selection = bru_get_selection,
|
||||
.set_selection = bru_set_selection,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops bru_ops = {
|
||||
.video = &bru_video_ops,
|
||||
.pad = &bru_pad_ops,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization and Cleanup
|
||||
*/
|
||||
|
||||
struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
struct vsp1_bru *bru;
|
||||
int ret;
|
||||
|
||||
bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL);
|
||||
if (bru == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
bru->entity.type = VSP1_ENTITY_BRU;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &bru->entity, 5);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the V4L2 subdev. */
|
||||
subdev = &bru->entity.subdev;
|
||||
v4l2_subdev_init(subdev, &bru_ops);
|
||||
|
||||
subdev->entity.ops = &vsp1_media_ops;
|
||||
subdev->internal_ops = &vsp1_subdev_internal_ops;
|
||||
snprintf(subdev->name, sizeof(subdev->name), "%s bru",
|
||||
dev_name(vsp1->dev));
|
||||
v4l2_set_subdevdata(subdev, bru);
|
||||
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
vsp1_entity_init_formats(subdev, NULL);
|
||||
|
||||
return bru;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* vsp1_bru.h -- R-Car VSP1 Blend ROP Unit
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_BRU_H__
|
||||
#define __VSP1_BRU_H__
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
struct vsp1_device;
|
||||
|
||||
#define BRU_PAD_SINK(n) (n)
|
||||
#define BRU_PAD_SOURCE 4
|
||||
|
||||
struct vsp1_bru {
|
||||
struct vsp1_entity entity;
|
||||
|
||||
struct v4l2_rect compose[4];
|
||||
};
|
||||
|
||||
static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_bru, entity.subdev);
|
||||
}
|
||||
|
||||
struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1);
|
||||
|
||||
#endif /* __VSP1_BRU_H__ */
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_bru.h"
|
||||
#include "vsp1_hsit.h"
|
||||
#include "vsp1_lif.h"
|
||||
#include "vsp1_lut.h"
|
||||
|
@ -155,6 +156,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
|
|||
}
|
||||
|
||||
/* Instantiate all the entities. */
|
||||
vsp1->bru = vsp1_bru_create(vsp1);
|
||||
if (IS_ERR(vsp1->bru)) {
|
||||
ret = PTR_ERR(vsp1->bru);
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
|
||||
|
||||
vsp1->hsi = vsp1_hsit_create(vsp1, true);
|
||||
if (IS_ERR(vsp1->hsi)) {
|
||||
ret = PTR_ERR(vsp1->hsi);
|
||||
|
|
|
@ -119,6 +119,9 @@ const struct media_entity_operations vsp1_media_ops = {
|
|||
*/
|
||||
|
||||
static const struct vsp1_route vsp1_routes[] = {
|
||||
{ VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
|
||||
{ VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
|
||||
VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } },
|
||||
{ VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } },
|
||||
{ VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } },
|
||||
{ VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
struct vsp1_device;
|
||||
|
||||
enum vsp1_entity_type {
|
||||
VSP1_ENTITY_BRU,
|
||||
VSP1_ENTITY_HSI,
|
||||
VSP1_ENTITY_HST,
|
||||
VSP1_ENTITY_LIF,
|
||||
|
|
|
@ -451,13 +451,111 @@
|
|||
* BRU Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_ROP_NOP 0
|
||||
#define VI6_ROP_AND 1
|
||||
#define VI6_ROP_AND_REV 2
|
||||
#define VI6_ROP_COPY 3
|
||||
#define VI6_ROP_AND_INV 4
|
||||
#define VI6_ROP_CLEAR 5
|
||||
#define VI6_ROP_XOR 6
|
||||
#define VI6_ROP_OR 7
|
||||
#define VI6_ROP_NOR 8
|
||||
#define VI6_ROP_EQUIV 9
|
||||
#define VI6_ROP_INVERT 10
|
||||
#define VI6_ROP_OR_REV 11
|
||||
#define VI6_ROP_COPY_INV 12
|
||||
#define VI6_ROP_OR_INV 13
|
||||
#define VI6_ROP_NAND 14
|
||||
#define VI6_ROP_SET 15
|
||||
|
||||
#define VI6_BRU_INCTRL 0x2c00
|
||||
#define VI6_BRU_INCTRL_NRM (1 << 28)
|
||||
#define VI6_BRU_INCTRL_DnON (1 << (16 + (n)))
|
||||
#define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_16BPP (2 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_15BPP (3 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_12BPP (4 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_8BPP (5 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4))
|
||||
#define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4)
|
||||
|
||||
#define VI6_BRU_VIRRPF_SIZE 0x2c04
|
||||
#define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16)
|
||||
#define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16
|
||||
#define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0)
|
||||
#define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0
|
||||
|
||||
#define VI6_BRU_VIRRPF_LOC 0x2c08
|
||||
#define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16)
|
||||
#define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16
|
||||
#define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0)
|
||||
#define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0
|
||||
|
||||
#define VI6_BRU_VIRRPF_COL 0x2c0c
|
||||
#define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24)
|
||||
#define VI6_BRU_VIRRPF_COL_A_SHIFT 24
|
||||
#define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16)
|
||||
#define VI6_BRU_VIRRPF_COL_RCR_SHIFT 16
|
||||
#define VI6_BRU_VIRRPF_COL_GY_MASK (0xff << 8)
|
||||
#define VI6_BRU_VIRRPF_COL_GY_SHIFT 8
|
||||
#define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0)
|
||||
#define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0
|
||||
|
||||
#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8)
|
||||
#define VI6_BRU_CTRL_RBC (1 << 31)
|
||||
#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20)
|
||||
#define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20)
|
||||
#define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20)
|
||||
#define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16)
|
||||
#define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16)
|
||||
#define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16)
|
||||
#define VI6_BRU_CTRL_CROP(rop) ((rop) << 4)
|
||||
#define VI6_BRU_CTRL_CROP_MASK (0xf << 4)
|
||||
#define VI6_BRU_CTRL_AROP(rop) ((rop) << 0)
|
||||
#define VI6_BRU_CTRL_AROP_MASK (0xf << 0)
|
||||
|
||||
#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8)
|
||||
#define VI6_BRU_BLD_CBES (1 << 31)
|
||||
#define VI6_BRU_BLD_CCMDX_DST_A (0 << 28)
|
||||
#define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28)
|
||||
#define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28)
|
||||
#define VI6_BRU_BLD_CCMDX_255_SRC_A (3 << 28)
|
||||
#define VI6_BRU_BLD_CCMDX_COEFX (4 << 28)
|
||||
#define VI6_BRU_BLD_CCMDX_MASK (7 << 28)
|
||||
#define VI6_BRU_BLD_CCMDY_DST_A (0 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_255_DST_A (1 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_SRC_A (2 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_255_SRC_A (3 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_COEFY (4 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_MASK (7 << 24)
|
||||
#define VI6_BRU_BLD_CCMDY_SHIFT 24
|
||||
#define VI6_BRU_BLD_ABES (1 << 23)
|
||||
#define VI6_BRU_BLD_ACMDX_DST_A (0 << 20)
|
||||
#define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20)
|
||||
#define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20)
|
||||
#define VI6_BRU_BLD_ACMDX_255_SRC_A (3 << 20)
|
||||
#define VI6_BRU_BLD_ACMDX_COEFX (4 << 20)
|
||||
#define VI6_BRU_BLD_ACMDX_MASK (7 << 20)
|
||||
#define VI6_BRU_BLD_ACMDY_DST_A (0 << 16)
|
||||
#define VI6_BRU_BLD_ACMDY_255_DST_A (1 << 16)
|
||||
#define VI6_BRU_BLD_ACMDY_SRC_A (2 << 16)
|
||||
#define VI6_BRU_BLD_ACMDY_255_SRC_A (3 << 16)
|
||||
#define VI6_BRU_BLD_ACMDY_COEFY (4 << 16)
|
||||
#define VI6_BRU_BLD_ACMDY_MASK (7 << 16)
|
||||
#define VI6_BRU_BLD_COEFX_MASK (0xff << 8)
|
||||
#define VI6_BRU_BLD_COEFX_SHIFT 8
|
||||
#define VI6_BRU_BLD_COEFY_MASK (0xff << 0)
|
||||
#define VI6_BRU_BLD_COEFY_SHIFT 0
|
||||
|
||||
#define VI6_BRU_ROP 0x2c30
|
||||
#define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20)
|
||||
#define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20)
|
||||
#define VI6_BRU_ROP_DSTSEL_MASK (7 << 20)
|
||||
#define VI6_BRU_ROP_CROP(rop) ((rop) << 4)
|
||||
#define VI6_BRU_ROP_CROP_MASK (0xf << 4)
|
||||
#define VI6_BRU_ROP_AROP(rop) ((rop) << 0)
|
||||
#define VI6_BRU_ROP_AROP_MASK (0xf << 0)
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HGO Control Registers
|
||||
|
|
|
@ -96,8 +96,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
|||
vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
|
||||
vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
|
||||
|
||||
/* Output location. Composing isn't supported yet. */
|
||||
vsp1_rpf_write(rpf, VI6_RPF_LOC, 0);
|
||||
/* Output location */
|
||||
vsp1_rpf_write(rpf, VI6_RPF_LOC,
|
||||
(rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
|
||||
(rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
|
||||
|
||||
/* Disable alpha, mask and color key. Set the alpha channel to a fixed
|
||||
* value of 255.
|
||||
|
|
|
@ -30,6 +30,10 @@ struct vsp1_rwpf {
|
|||
unsigned int max_width;
|
||||
unsigned int max_height;
|
||||
|
||||
struct {
|
||||
unsigned int left;
|
||||
unsigned int top;
|
||||
} location;
|
||||
struct v4l2_rect crop;
|
||||
|
||||
unsigned int offsets[2];
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <media/videobuf2-dma-contig.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_bru.h"
|
||||
#include "vsp1_entity.h"
|
||||
#include "vsp1_rwpf.h"
|
||||
#include "vsp1_video.h"
|
||||
|
@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
|
|||
struct media_pad *pad;
|
||||
bool uds_found = false;
|
||||
|
||||
input->location.left = 0;
|
||||
input->location.top = 0;
|
||||
|
||||
pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
|
||||
|
||||
while (1) {
|
||||
|
@ -292,6 +296,17 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
|
|||
|
||||
entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
|
||||
|
||||
/* A BRU is present in the pipeline, store the compose rectangle
|
||||
* location in the input RPF for use when configuring the RPF.
|
||||
*/
|
||||
if (entity->type == VSP1_ENTITY_BRU) {
|
||||
struct vsp1_bru *bru = to_bru(&entity->subdev);
|
||||
struct v4l2_rect *rect = &bru->compose[pad->index];
|
||||
|
||||
input->location.left = rect->left;
|
||||
input->location.top = rect->top;
|
||||
}
|
||||
|
||||
/* We've reached the WPF, we're done. */
|
||||
if (entity->type == VSP1_ENTITY_WPF)
|
||||
break;
|
||||
|
@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
|
|||
rwpf->video.pipe_index = 0;
|
||||
} else if (e->type == VSP1_ENTITY_LIF) {
|
||||
pipe->lif = e;
|
||||
} else if (e->type == VSP1_ENTITY_BRU) {
|
||||
pipe->bru = e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,6 +409,7 @@ error:
|
|||
pipe->num_video = 0;
|
||||
pipe->num_inputs = 0;
|
||||
pipe->output = NULL;
|
||||
pipe->bru = NULL;
|
||||
pipe->lif = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
|
|||
pipe->num_video = 0;
|
||||
pipe->num_inputs = 0;
|
||||
pipe->output = NULL;
|
||||
pipe->bru = NULL;
|
||||
pipe->lif = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ struct vsp1_pipeline {
|
|||
unsigned int num_inputs;
|
||||
struct vsp1_rwpf *inputs[VPS1_MAX_RPF];
|
||||
struct vsp1_rwpf *output;
|
||||
struct vsp1_entity *bru;
|
||||
struct vsp1_entity *lif;
|
||||
|
||||
struct list_head entities;
|
||||
|
|
|
@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Sources */
|
||||
/* Sources. If the pipeline has a single input configure it as the
|
||||
* master layer. Otherwise configure all inputs as sub-layers and
|
||||
* select the virtual RPF as the master layer.
|
||||
*/
|
||||
for (i = 0; i < pipe->num_inputs; ++i) {
|
||||
struct vsp1_rwpf *input = pipe->inputs[i];
|
||||
|
||||
srcrpf |= VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index);
|
||||
srcrpf |= pipe->num_inputs == 1
|
||||
? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
|
||||
: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
|
||||
}
|
||||
|
||||
if (pipe->num_inputs > 1)
|
||||
srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
|
||||
|
||||
vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
|
||||
|
||||
/* Destination stride. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче