Merge branches 'topic/vsp1' and 'topic/adv76xx' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media into next
Pull updates and DT support for media engines from Mauro Carvalho Chehab. For Analog Devices ADV7604 and the Renesas VSP1 video processing engines. * 'topic/vsp1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: [media] v4l: vsp1: Add DT support [media] v4l: vsp1: Add DT bindings documentation [media] v4l: vsp1: Add BRU support [media] v4l: vsp1: Support multi-input entities [media] v4l: vsp1: uds: Enable scaling of alpha layer [media] v4l: vsp1: Remove unexisting rt clocks * 'topic/adv76xx' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (21 commits) [media] adv7604: Add LLC polarity configuration [media] adv7604: Set HPD GPIO direction to output [media] adv7604: Add endpoint properties to DT bindings [media] adv7604: Add DT support [media] adv7604: Specify the default input through platform data [media] adv7604: Support hot-plug detect control through a GPIO [media] adv7604: Sort headers alphabetically [media] adv7604: Replace *_and_or() functions with *_clr_set() [media] adv7604: Store I2C addresses and clients in arrays [media] adv7604: Inline the to_sd function [media] v4l: subdev: Remove deprecated video-level DV timings operations [media] adv7604: Remove deprecated video-level DV timings operations [media] adv7604: Add pad-level DV timings support [media] adv7604: Make output format configurable through pad format operations [media] adv7604: Add sink pads [media] adv7604: Remove subdev control handlers [media] adv7604: Add adv7611 support [media] adv7604: Cache register contents when reading multiple bits [media] adv7604: Add 16-bit read functions for CP and HDMI [media] adv7604: Don't put info string arrays on the stack ...
This commit is contained in:
commit
0bb4646241
|
@ -0,0 +1,70 @@
|
||||||
|
* Analog Devices ADV7604/11 video decoder with HDMI receiver
|
||||||
|
|
||||||
|
The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI
|
||||||
|
receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input,
|
||||||
|
and the ADV7611 has one HDMI input and no analog input.
|
||||||
|
|
||||||
|
These device tree bindings support the ADV7611 only at the moment.
|
||||||
|
|
||||||
|
Required Properties:
|
||||||
|
|
||||||
|
- compatible: Must contain one of the following
|
||||||
|
- "adi,adv7611" for the ADV7611
|
||||||
|
|
||||||
|
- reg: I2C slave address
|
||||||
|
|
||||||
|
- hpd-gpios: References to the GPIOs that control the HDMI hot-plug
|
||||||
|
detection pins, one per HDMI input. The active flag indicates the GPIO
|
||||||
|
level that enables hot-plug detection.
|
||||||
|
|
||||||
|
The device node must contain one 'port' child node per device input and output
|
||||||
|
port, in accordance with the video interface bindings defined in
|
||||||
|
Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
|
||||||
|
are numbered as follows.
|
||||||
|
|
||||||
|
Port ADV7611
|
||||||
|
------------------------------------------------------------
|
||||||
|
HDMI 0
|
||||||
|
Digital output 1
|
||||||
|
|
||||||
|
The digital output port node must contain at least one endpoint.
|
||||||
|
|
||||||
|
Optional Properties:
|
||||||
|
|
||||||
|
- reset-gpios: Reference to the GPIO connected to the device's reset pin.
|
||||||
|
|
||||||
|
Optional Endpoint Properties:
|
||||||
|
|
||||||
|
The following three properties are defined in video-interfaces.txt and are
|
||||||
|
valid for source endpoints only.
|
||||||
|
|
||||||
|
- hsync-active: Horizontal synchronization polarity. Defaults to active low.
|
||||||
|
- vsync-active: Vertical synchronization polarity. Defaults to active low.
|
||||||
|
- pclk-sample: Pixel clock polarity. Defaults to output on the falling edge.
|
||||||
|
|
||||||
|
If none of hsync-active, vsync-active and pclk-sample is specified the
|
||||||
|
endpoint will use embedded BT.656 synchronization.
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
hdmi_receiver@4c {
|
||||||
|
compatible = "adi,adv7611";
|
||||||
|
reg = <0x4c>;
|
||||||
|
|
||||||
|
reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>;
|
||||||
|
hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>;
|
||||||
|
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
hdmi_in: endpoint {
|
||||||
|
remote-endpoint = <&ccdc_in>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
* Renesas VSP1 Video Processing Engine
|
||||||
|
|
||||||
|
The VSP1 is a video processing engine that supports up-/down-scaling, alpha
|
||||||
|
blending, color space conversion and various other image processing features.
|
||||||
|
It can be found in the Renesas R-Car second generation SoCs.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: Must contain "renesas,vsp1"
|
||||||
|
|
||||||
|
- reg: Base address and length of the registers block for the VSP1.
|
||||||
|
- interrupts: VSP1 interrupt specifier.
|
||||||
|
- clocks: A phandle + clock-specifier pair for the VSP1 functional clock.
|
||||||
|
|
||||||
|
- renesas,#rpf: Number of Read Pixel Formatter (RPF) modules in the VSP1.
|
||||||
|
- renesas,#uds: Number of Up Down Scaler (UDS) modules in the VSP1.
|
||||||
|
- renesas,#wpf: Number of Write Pixel Formatter (WPF) modules in the VSP1.
|
||||||
|
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- renesas,has-lif: Boolean, indicates that the LCD Interface (LIF) module is
|
||||||
|
available.
|
||||||
|
- renesas,has-lut: Boolean, indicates that the Look Up Table (LUT) module is
|
||||||
|
available.
|
||||||
|
- renesas,has-sru: Boolean, indicates that the Super Resolution Unit (SRU)
|
||||||
|
module is available.
|
||||||
|
|
||||||
|
|
||||||
|
Example: R8A7790 (R-Car H2) VSP1-S node
|
||||||
|
|
||||||
|
vsp1@fe928000 {
|
||||||
|
compatible = "renesas,vsp1";
|
||||||
|
reg = <0 0xfe928000 0 0x8000>;
|
||||||
|
interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>;
|
||||||
|
|
||||||
|
renesas,has-lut;
|
||||||
|
renesas,has-sru;
|
||||||
|
renesas,#rpf = <5>;
|
||||||
|
renesas,#uds = <3>;
|
||||||
|
renesas,#wpf = <4>;
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
|
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_rpf.o vsp1_rwpf.o vsp1_wpf.o
|
||||||
vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.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
|
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct clk;
|
||||||
struct device;
|
struct device;
|
||||||
|
|
||||||
struct vsp1_platform_data;
|
struct vsp1_platform_data;
|
||||||
|
struct vsp1_bru;
|
||||||
struct vsp1_hsit;
|
struct vsp1_hsit;
|
||||||
struct vsp1_lif;
|
struct vsp1_lif;
|
||||||
struct vsp1_lut;
|
struct vsp1_lut;
|
||||||
|
@ -45,11 +46,11 @@ struct vsp1_device {
|
||||||
|
|
||||||
void __iomem *mmio;
|
void __iomem *mmio;
|
||||||
struct clk *clock;
|
struct clk *clock;
|
||||||
struct clk *rt_clock;
|
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
int ref_count;
|
int ref_count;
|
||||||
|
|
||||||
|
struct vsp1_bru *bru;
|
||||||
struct vsp1_hsit *hsi;
|
struct vsp1_hsit *hsi;
|
||||||
struct vsp1_hsit *hst;
|
struct vsp1_hsit *hst;
|
||||||
struct vsp1_lif *lif;
|
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__ */
|
|
@ -16,10 +16,12 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
#include "vsp1.h"
|
#include "vsp1.h"
|
||||||
|
#include "vsp1_bru.h"
|
||||||
#include "vsp1_hsit.h"
|
#include "vsp1_hsit.h"
|
||||||
#include "vsp1_lif.h"
|
#include "vsp1_lif.h"
|
||||||
#include "vsp1_lut.h"
|
#include "vsp1_lut.h"
|
||||||
|
@ -155,6 +157,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Instantiate all the entities. */
|
/* 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);
|
vsp1->hsi = vsp1_hsit_create(vsp1, true);
|
||||||
if (IS_ERR(vsp1->hsi)) {
|
if (IS_ERR(vsp1->hsi)) {
|
||||||
ret = PTR_ERR(vsp1->hsi);
|
ret = PTR_ERR(vsp1->hsi);
|
||||||
|
@ -329,33 +339,6 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vsp1_clocks_enable(struct vsp1_device *vsp1)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(vsp1->clock);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (IS_ERR(vsp1->rt_clock))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(vsp1->rt_clock);
|
|
||||||
if (ret < 0) {
|
|
||||||
clk_disable_unprepare(vsp1->clock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vsp1_clocks_disable(struct vsp1_device *vsp1)
|
|
||||||
{
|
|
||||||
if (!IS_ERR(vsp1->rt_clock))
|
|
||||||
clk_disable_unprepare(vsp1->rt_clock);
|
|
||||||
clk_disable_unprepare(vsp1->clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vsp1_device_get - Acquire the VSP1 device
|
* vsp1_device_get - Acquire the VSP1 device
|
||||||
*
|
*
|
||||||
|
@ -373,7 +356,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1)
|
||||||
if (vsp1->ref_count > 0)
|
if (vsp1->ref_count > 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
ret = vsp1_clocks_enable(vsp1);
|
ret = clk_prepare_enable(vsp1->clock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
__vsp1 = NULL;
|
__vsp1 = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -381,7 +364,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1)
|
||||||
|
|
||||||
ret = vsp1_device_init(vsp1);
|
ret = vsp1_device_init(vsp1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
vsp1_clocks_disable(vsp1);
|
clk_disable_unprepare(vsp1->clock);
|
||||||
__vsp1 = NULL;
|
__vsp1 = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +388,7 @@ void vsp1_device_put(struct vsp1_device *vsp1)
|
||||||
mutex_lock(&vsp1->lock);
|
mutex_lock(&vsp1->lock);
|
||||||
|
|
||||||
if (--vsp1->ref_count == 0)
|
if (--vsp1->ref_count == 0)
|
||||||
vsp1_clocks_disable(vsp1);
|
clk_disable_unprepare(vsp1->clock);
|
||||||
|
|
||||||
mutex_unlock(&vsp1->lock);
|
mutex_unlock(&vsp1->lock);
|
||||||
}
|
}
|
||||||
|
@ -424,7 +407,7 @@ static int vsp1_pm_suspend(struct device *dev)
|
||||||
if (vsp1->ref_count == 0)
|
if (vsp1->ref_count == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vsp1_clocks_disable(vsp1);
|
clk_disable_unprepare(vsp1->clock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +420,7 @@ static int vsp1_pm_resume(struct device *dev)
|
||||||
if (vsp1->ref_count)
|
if (vsp1->ref_count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return vsp1_clocks_enable(vsp1);
|
return clk_prepare_enable(vsp1->clock);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -449,34 +432,59 @@ static const struct dev_pm_ops vsp1_pm_ops = {
|
||||||
* Platform Driver
|
* Platform Driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct vsp1_platform_data *
|
static int vsp1_validate_platform_data(struct platform_device *pdev,
|
||||||
vsp1_get_platform_data(struct platform_device *pdev)
|
struct vsp1_platform_data *pdata)
|
||||||
{
|
{
|
||||||
struct vsp1_platform_data *pdata = pdev->dev.platform_data;
|
|
||||||
|
|
||||||
if (pdata == NULL) {
|
if (pdata == NULL) {
|
||||||
dev_err(&pdev->dev, "missing platform data\n");
|
dev_err(&pdev->dev, "missing platform data\n");
|
||||||
return NULL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) {
|
if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) {
|
||||||
dev_err(&pdev->dev, "invalid number of RPF (%u)\n",
|
dev_err(&pdev->dev, "invalid number of RPF (%u)\n",
|
||||||
pdata->rpf_count);
|
pdata->rpf_count);
|
||||||
return NULL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) {
|
if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) {
|
||||||
dev_err(&pdev->dev, "invalid number of UDS (%u)\n",
|
dev_err(&pdev->dev, "invalid number of UDS (%u)\n",
|
||||||
pdata->uds_count);
|
pdata->uds_count);
|
||||||
return NULL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) {
|
if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) {
|
||||||
dev_err(&pdev->dev, "invalid number of WPF (%u)\n",
|
dev_err(&pdev->dev, "invalid number of WPF (%u)\n",
|
||||||
pdata->wpf_count);
|
pdata->wpf_count);
|
||||||
return NULL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct vsp1_platform_data *
|
||||||
|
vsp1_get_platform_data(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
struct vsp1_platform_data *pdata;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_OF) || np == NULL)
|
||||||
|
return pdev->dev.platform_data;
|
||||||
|
|
||||||
|
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (pdata == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "renesas,has-lif"))
|
||||||
|
pdata->features |= VSP1_HAS_LIF;
|
||||||
|
if (of_property_read_bool(np, "renesas,has-lut"))
|
||||||
|
pdata->features |= VSP1_HAS_LUT;
|
||||||
|
if (of_property_read_bool(np, "renesas,has-sru"))
|
||||||
|
pdata->features |= VSP1_HAS_SRU;
|
||||||
|
|
||||||
|
of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count);
|
||||||
|
of_property_read_u32(np, "renesas,#uds", &pdata->uds_count);
|
||||||
|
of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count);
|
||||||
|
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,6 +507,10 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
if (vsp1->pdata == NULL)
|
if (vsp1->pdata == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = vsp1_validate_platform_data(pdev, vsp1->pdata);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* I/O, IRQ and clock resources */
|
/* I/O, IRQ and clock resources */
|
||||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
||||||
|
@ -511,9 +523,6 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
return PTR_ERR(vsp1->clock);
|
return PTR_ERR(vsp1->clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The RT clock is optional */
|
|
||||||
vsp1->rt_clock = devm_clk_get(&pdev->dev, "rt");
|
|
||||||
|
|
||||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
if (!irq) {
|
if (!irq) {
|
||||||
dev_err(&pdev->dev, "missing IRQ\n");
|
dev_err(&pdev->dev, "missing IRQ\n");
|
||||||
|
@ -548,6 +557,11 @@ static int vsp1_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id vsp1_of_match[] = {
|
||||||
|
{ .compatible = "renesas,vsp1" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_driver vsp1_platform_driver = {
|
static struct platform_driver vsp1_platform_driver = {
|
||||||
.probe = vsp1_probe,
|
.probe = vsp1_probe,
|
||||||
.remove = vsp1_remove,
|
.remove = vsp1_remove,
|
||||||
|
@ -555,6 +569,7 @@ static struct platform_driver vsp1_platform_driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "vsp1",
|
.name = "vsp1",
|
||||||
.pm = &vsp1_pm_ops,
|
.pm = &vsp1_pm_ops,
|
||||||
|
.of_match_table = vsp1_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -100,8 +100,10 @@ static int vsp1_entity_link_setup(struct media_entity *entity,
|
||||||
if (source->sink)
|
if (source->sink)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
source->sink = remote->entity;
|
source->sink = remote->entity;
|
||||||
|
source->sink_pad = remote->index;
|
||||||
} else {
|
} else {
|
||||||
source->sink = NULL;
|
source->sink = NULL;
|
||||||
|
source->sink_pad = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -116,42 +118,43 @@ const struct media_entity_operations vsp1_media_ops = {
|
||||||
* Initialization
|
* Initialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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, } },
|
||||||
|
{ VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } },
|
||||||
|
{ VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } },
|
||||||
|
{ VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } },
|
||||||
|
{ VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } },
|
||||||
|
{ VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } },
|
||||||
|
{ VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } },
|
||||||
|
{ VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } },
|
||||||
|
{ VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } },
|
||||||
|
{ VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } },
|
||||||
|
{ VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } },
|
||||||
|
{ VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } },
|
||||||
|
{ VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } },
|
||||||
|
{ VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } },
|
||||||
|
{ VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } },
|
||||||
|
};
|
||||||
|
|
||||||
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
||||||
unsigned int num_pads)
|
unsigned int num_pads)
|
||||||
{
|
{
|
||||||
static const struct {
|
|
||||||
unsigned int id;
|
|
||||||
unsigned int reg;
|
|
||||||
} routes[] = {
|
|
||||||
{ VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE },
|
|
||||||
{ VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE },
|
|
||||||
{ VI6_DPR_NODE_LIF, 0 },
|
|
||||||
{ VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE },
|
|
||||||
{ VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) },
|
|
||||||
{ VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) },
|
|
||||||
{ VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) },
|
|
||||||
{ VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) },
|
|
||||||
{ VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) },
|
|
||||||
{ VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE },
|
|
||||||
{ VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) },
|
|
||||||
{ VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) },
|
|
||||||
{ VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) },
|
|
||||||
{ VI6_DPR_NODE_WPF(0), 0 },
|
|
||||||
{ VI6_DPR_NODE_WPF(1), 0 },
|
|
||||||
{ VI6_DPR_NODE_WPF(2), 0 },
|
|
||||||
{ VI6_DPR_NODE_WPF(3), 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(routes); ++i) {
|
for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
|
||||||
if (routes[i].id == entity->id) {
|
if (vsp1_routes[i].type == entity->type &&
|
||||||
entity->route = routes[i].reg;
|
vsp1_routes[i].index == entity->index) {
|
||||||
|
entity->route = &vsp1_routes[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == ARRAY_SIZE(routes))
|
if (i == ARRAY_SIZE(vsp1_routes))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
entity->vsp1 = vsp1;
|
entity->vsp1 = vsp1;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
struct vsp1_device;
|
struct vsp1_device;
|
||||||
|
|
||||||
enum vsp1_entity_type {
|
enum vsp1_entity_type {
|
||||||
|
VSP1_ENTITY_BRU,
|
||||||
VSP1_ENTITY_HSI,
|
VSP1_ENTITY_HSI,
|
||||||
VSP1_ENTITY_HST,
|
VSP1_ENTITY_HST,
|
||||||
VSP1_ENTITY_LIF,
|
VSP1_ENTITY_LIF,
|
||||||
|
@ -30,13 +31,31 @@ enum vsp1_entity_type {
|
||||||
VSP1_ENTITY_WPF,
|
VSP1_ENTITY_WPF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct vsp1_route - Entity routing configuration
|
||||||
|
* @type: Entity type this routing entry is associated with
|
||||||
|
* @index: Entity index this routing entry is associated with
|
||||||
|
* @reg: Output routing configuration register
|
||||||
|
* @inputs: Target node value for each input
|
||||||
|
*
|
||||||
|
* Each $vsp1_route entry describes routing configuration for the entity
|
||||||
|
* specified by the entry's @type and @index. @reg indicates the register that
|
||||||
|
* holds output routing configuration for the entity, and the @inputs array
|
||||||
|
* store the target node value for each input of the entity.
|
||||||
|
*/
|
||||||
|
struct vsp1_route {
|
||||||
|
enum vsp1_entity_type type;
|
||||||
|
unsigned int index;
|
||||||
|
unsigned int reg;
|
||||||
|
unsigned int inputs[4];
|
||||||
|
};
|
||||||
|
|
||||||
struct vsp1_entity {
|
struct vsp1_entity {
|
||||||
struct vsp1_device *vsp1;
|
struct vsp1_device *vsp1;
|
||||||
|
|
||||||
enum vsp1_entity_type type;
|
enum vsp1_entity_type type;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
unsigned int id;
|
const struct vsp1_route *route;
|
||||||
unsigned int route;
|
|
||||||
|
|
||||||
struct list_head list_dev;
|
struct list_head list_dev;
|
||||||
struct list_head list_pipe;
|
struct list_head list_pipe;
|
||||||
|
@ -45,6 +64,7 @@ struct vsp1_entity {
|
||||||
unsigned int source_pad;
|
unsigned int source_pad;
|
||||||
|
|
||||||
struct media_entity *sink;
|
struct media_entity *sink;
|
||||||
|
unsigned int sink_pad;
|
||||||
|
|
||||||
struct v4l2_subdev subdev;
|
struct v4l2_subdev subdev;
|
||||||
struct v4l2_mbus_framefmt *formats;
|
struct v4l2_mbus_framefmt *formats;
|
||||||
|
|
|
@ -193,13 +193,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
|
||||||
|
|
||||||
hsit->inverse = inverse;
|
hsit->inverse = inverse;
|
||||||
|
|
||||||
if (inverse) {
|
if (inverse)
|
||||||
hsit->entity.type = VSP1_ENTITY_HSI;
|
hsit->entity.type = VSP1_ENTITY_HSI;
|
||||||
hsit->entity.id = VI6_DPR_NODE_HSI;
|
else
|
||||||
} else {
|
|
||||||
hsit->entity.type = VSP1_ENTITY_HST;
|
hsit->entity.type = VSP1_ENTITY_HST;
|
||||||
hsit->entity.id = VI6_DPR_NODE_HST;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
|
ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -215,7 +215,6 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
lif->entity.type = VSP1_ENTITY_LIF;
|
lif->entity.type = VSP1_ENTITY_LIF;
|
||||||
lif->entity.id = VI6_DPR_NODE_LIF;
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &lif->entity, 2);
|
ret = vsp1_entity_init(vsp1, &lif->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -229,7 +229,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
lut->entity.type = VSP1_ENTITY_LUT;
|
lut->entity.type = VSP1_ENTITY_LUT;
|
||||||
lut->entity.id = VI6_DPR_NODE_LUT;
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &lut->entity, 2);
|
ret = vsp1_entity_init(vsp1, &lut->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -451,13 +451,111 @@
|
||||||
* BRU Control Registers
|
* 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 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 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 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 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(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(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 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
|
* 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_INFMT, infmt);
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
|
vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
|
||||||
|
|
||||||
/* Output location. Composing isn't supported yet. */
|
/* Output location */
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_LOC, 0);
|
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
|
/* Disable alpha, mask and color key. Set the alpha channel to a fixed
|
||||||
* value of 255.
|
* value of 255.
|
||||||
|
@ -176,7 +178,6 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
|
||||||
|
|
||||||
rpf->entity.type = VSP1_ENTITY_RPF;
|
rpf->entity.type = VSP1_ENTITY_RPF;
|
||||||
rpf->entity.index = index;
|
rpf->entity.index = index;
|
||||||
rpf->entity.id = VI6_DPR_NODE_RPF(index);
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
|
ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -30,6 +30,10 @@ struct vsp1_rwpf {
|
||||||
unsigned int max_width;
|
unsigned int max_width;
|
||||||
unsigned int max_height;
|
unsigned int max_height;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int left;
|
||||||
|
unsigned int top;
|
||||||
|
} location;
|
||||||
struct v4l2_rect crop;
|
struct v4l2_rect crop;
|
||||||
|
|
||||||
unsigned int offsets[2];
|
unsigned int offsets[2];
|
||||||
|
|
|
@ -327,7 +327,6 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
sru->entity.type = VSP1_ENTITY_SRU;
|
sru->entity.type = VSP1_ENTITY_SRU;
|
||||||
sru->entity.id = VI6_DPR_NODE_SRU;
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &sru->entity, 2);
|
ret = vsp1_entity_init(vsp1, &sru->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -131,7 +131,7 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Enable multi-tap scaling. */
|
/* Enable multi-tap scaling. */
|
||||||
vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_BC);
|
vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC);
|
||||||
|
|
||||||
vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
|
vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
|
||||||
(uds_passband_width(uds->hscale)
|
(uds_passband_width(uds->hscale)
|
||||||
|
@ -139,7 +139,6 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
(uds_passband_width(uds->vscale)
|
(uds_passband_width(uds->vscale)
|
||||||
<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
|
<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
|
||||||
|
|
||||||
|
|
||||||
/* Set the scaling ratios and the output size. */
|
/* Set the scaling ratios and the output size. */
|
||||||
format = &uds->entity.formats[UDS_PAD_SOURCE];
|
format = &uds->entity.formats[UDS_PAD_SOURCE];
|
||||||
|
|
||||||
|
@ -323,7 +322,6 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
|
||||||
|
|
||||||
uds->entity.type = VSP1_ENTITY_UDS;
|
uds->entity.type = VSP1_ENTITY_UDS;
|
||||||
uds->entity.index = index;
|
uds->entity.index = index;
|
||||||
uds->entity.id = VI6_DPR_NODE_UDS(index);
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &uds->entity, 2);
|
ret = vsp1_entity_init(vsp1, &uds->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <media/videobuf2-dma-contig.h>
|
#include <media/videobuf2-dma-contig.h>
|
||||||
|
|
||||||
#include "vsp1.h"
|
#include "vsp1.h"
|
||||||
|
#include "vsp1_bru.h"
|
||||||
#include "vsp1_entity.h"
|
#include "vsp1_entity.h"
|
||||||
#include "vsp1_rwpf.h"
|
#include "vsp1_rwpf.h"
|
||||||
#include "vsp1_video.h"
|
#include "vsp1_video.h"
|
||||||
|
@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
|
||||||
struct media_pad *pad;
|
struct media_pad *pad;
|
||||||
bool uds_found = false;
|
bool uds_found = false;
|
||||||
|
|
||||||
|
input->location.left = 0;
|
||||||
|
input->location.top = 0;
|
||||||
|
|
||||||
pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
|
pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
|
||||||
|
|
||||||
while (1) {
|
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));
|
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. */
|
/* We've reached the WPF, we're done. */
|
||||||
if (entity->type == VSP1_ENTITY_WPF)
|
if (entity->type == VSP1_ENTITY_WPF)
|
||||||
break;
|
break;
|
||||||
|
@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
|
||||||
rwpf->video.pipe_index = 0;
|
rwpf->video.pipe_index = 0;
|
||||||
} else if (e->type == VSP1_ENTITY_LIF) {
|
} else if (e->type == VSP1_ENTITY_LIF) {
|
||||||
pipe->lif = e;
|
pipe->lif = e;
|
||||||
|
} else if (e->type == VSP1_ENTITY_BRU) {
|
||||||
|
pipe->bru = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +409,7 @@ error:
|
||||||
pipe->num_video = 0;
|
pipe->num_video = 0;
|
||||||
pipe->num_inputs = 0;
|
pipe->num_inputs = 0;
|
||||||
pipe->output = NULL;
|
pipe->output = NULL;
|
||||||
|
pipe->bru = NULL;
|
||||||
pipe->lif = NULL;
|
pipe->lif = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
|
||||||
pipe->num_video = 0;
|
pipe->num_video = 0;
|
||||||
pipe->num_inputs = 0;
|
pipe->num_inputs = 0;
|
||||||
pipe->output = NULL;
|
pipe->output = NULL;
|
||||||
|
pipe->bru = NULL;
|
||||||
pipe->lif = NULL;
|
pipe->lif = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +480,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
|
||||||
|
|
||||||
list_for_each_entry(entity, &pipe->entities, list_pipe) {
|
list_for_each_entry(entity, &pipe->entities, list_pipe) {
|
||||||
if (entity->route)
|
if (entity->route)
|
||||||
vsp1_write(entity->vsp1, entity->route,
|
vsp1_write(entity->vsp1, entity->route->reg,
|
||||||
VI6_DPR_NODE_UNUSED);
|
VI6_DPR_NODE_UNUSED);
|
||||||
|
|
||||||
v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
|
v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
|
||||||
|
@ -680,11 +699,12 @@ static void vsp1_entity_route_setup(struct vsp1_entity *source)
|
||||||
{
|
{
|
||||||
struct vsp1_entity *sink;
|
struct vsp1_entity *sink;
|
||||||
|
|
||||||
if (source->route == 0)
|
if (source->route->reg == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
|
sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
|
||||||
vsp1_write(source->vsp1, source->route, sink->id);
|
vsp1_write(source->vsp1, source->route->reg,
|
||||||
|
sink->route->inputs[source->sink_pad]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
|
static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||||
|
|
|
@ -75,6 +75,7 @@ struct vsp1_pipeline {
|
||||||
unsigned int num_inputs;
|
unsigned int num_inputs;
|
||||||
struct vsp1_rwpf *inputs[VPS1_MAX_RPF];
|
struct vsp1_rwpf *inputs[VPS1_MAX_RPF];
|
||||||
struct vsp1_rwpf *output;
|
struct vsp1_rwpf *output;
|
||||||
|
struct vsp1_entity *bru;
|
||||||
struct vsp1_entity *lif;
|
struct vsp1_entity *lif;
|
||||||
|
|
||||||
struct list_head entities;
|
struct list_head entities;
|
||||||
|
|
|
@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
return 0;
|
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) {
|
for (i = 0; i < pipe->num_inputs; ++i) {
|
||||||
struct vsp1_rwpf *input = pipe->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);
|
vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
|
||||||
|
|
||||||
/* Destination stride. */
|
/* Destination stride. */
|
||||||
|
@ -181,7 +189,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
|
||||||
|
|
||||||
wpf->entity.type = VSP1_ENTITY_WPF;
|
wpf->entity.type = VSP1_ENTITY_WPF;
|
||||||
wpf->entity.index = index;
|
wpf->entity.index = index;
|
||||||
wpf->entity.id = VI6_DPR_NODE_WPF(index);
|
|
||||||
|
|
||||||
ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
|
ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -32,14 +32,18 @@ enum adv7604_ain_sel {
|
||||||
ADV7604_AIN9_4_5_6_SYNC_2_1 = 4,
|
ADV7604_AIN9_4_5_6_SYNC_2_1 = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Bus rotation and reordering (IO register 0x04, [7:5]) */
|
/*
|
||||||
enum adv7604_op_ch_sel {
|
* Bus rotation and reordering. This is used to specify component reordering on
|
||||||
ADV7604_OP_CH_SEL_GBR = 0,
|
* the board and describes the components order on the bus when the ADV7604
|
||||||
ADV7604_OP_CH_SEL_GRB = 1,
|
* outputs RGB.
|
||||||
ADV7604_OP_CH_SEL_BGR = 2,
|
*/
|
||||||
ADV7604_OP_CH_SEL_RGB = 3,
|
enum adv7604_bus_order {
|
||||||
ADV7604_OP_CH_SEL_BRG = 4,
|
ADV7604_BUS_ORDER_RGB, /* No operation */
|
||||||
ADV7604_OP_CH_SEL_RBG = 5,
|
ADV7604_BUS_ORDER_GRB, /* Swap 1-2 */
|
||||||
|
ADV7604_BUS_ORDER_RBG, /* Swap 2-3 */
|
||||||
|
ADV7604_BUS_ORDER_BGR, /* Swap 1-3 */
|
||||||
|
ADV7604_BUS_ORDER_BRG, /* Rotate right */
|
||||||
|
ADV7604_BUS_ORDER_GBR, /* Rotate left */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Input Color Space (IO register 0x02, [7:4]) */
|
/* Input Color Space (IO register 0x02, [7:4]) */
|
||||||
|
@ -55,29 +59,11 @@ enum adv7604_inp_color_space {
|
||||||
ADV7604_INP_COLOR_SPACE_AUTO = 0xf,
|
ADV7604_INP_COLOR_SPACE_AUTO = 0xf,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Select output format (IO register 0x03, [7:0]) */
|
/* Select output format (IO register 0x03, [4:2]) */
|
||||||
enum adv7604_op_format_sel {
|
enum adv7604_op_format_mode_sel {
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_8 = 0x00,
|
ADV7604_OP_FORMAT_MODE0 = 0x00,
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_10 = 0x01,
|
ADV7604_OP_FORMAT_MODE1 = 0x04,
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE0 = 0x02,
|
ADV7604_OP_FORMAT_MODE2 = 0x08,
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE1 = 0x06,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE2 = 0x0a,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_422_8 = 0x20,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_422_10 = 0x21,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE0 = 0x22,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE1 = 0x23,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE2 = 0x24,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_444_24 = 0x40,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_444_30 = 0x41,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_444_36_MODE0 = 0x42,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_444_24 = 0x60,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_444_30 = 0x61,
|
|
||||||
ADV7604_OP_FORMAT_SEL_DDR_444_36 = 0x62,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_16 = 0x80,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_20 = 0x81,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE0 = 0x82,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE1 = 0x86,
|
|
||||||
ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum adv7604_drive_strength {
|
enum adv7604_drive_strength {
|
||||||
|
@ -86,6 +72,30 @@ enum adv7604_drive_strength {
|
||||||
ADV7604_DR_STR_HIGH = 3,
|
ADV7604_DR_STR_HIGH = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum adv7604_int1_config {
|
||||||
|
ADV7604_INT1_CONFIG_OPEN_DRAIN,
|
||||||
|
ADV7604_INT1_CONFIG_ACTIVE_LOW,
|
||||||
|
ADV7604_INT1_CONFIG_ACTIVE_HIGH,
|
||||||
|
ADV7604_INT1_CONFIG_DISABLED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum adv7604_page {
|
||||||
|
ADV7604_PAGE_IO,
|
||||||
|
ADV7604_PAGE_AVLINK,
|
||||||
|
ADV7604_PAGE_CEC,
|
||||||
|
ADV7604_PAGE_INFOFRAME,
|
||||||
|
ADV7604_PAGE_ESDP,
|
||||||
|
ADV7604_PAGE_DPP,
|
||||||
|
ADV7604_PAGE_AFE,
|
||||||
|
ADV7604_PAGE_REP,
|
||||||
|
ADV7604_PAGE_EDID,
|
||||||
|
ADV7604_PAGE_HDMI,
|
||||||
|
ADV7604_PAGE_TEST,
|
||||||
|
ADV7604_PAGE_CP,
|
||||||
|
ADV7604_PAGE_VDP,
|
||||||
|
ADV7604_PAGE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
/* Platform dependent definition */
|
/* Platform dependent definition */
|
||||||
struct adv7604_platform_data {
|
struct adv7604_platform_data {
|
||||||
/* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
|
/* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
|
||||||
|
@ -94,30 +104,34 @@ struct adv7604_platform_data {
|
||||||
/* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
|
/* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */
|
||||||
unsigned disable_cable_det_rst:1;
|
unsigned disable_cable_det_rst:1;
|
||||||
|
|
||||||
|
int default_input;
|
||||||
|
|
||||||
/* Analog input muxing mode */
|
/* Analog input muxing mode */
|
||||||
enum adv7604_ain_sel ain_sel;
|
enum adv7604_ain_sel ain_sel;
|
||||||
|
|
||||||
/* Bus rotation and reordering */
|
/* Bus rotation and reordering */
|
||||||
enum adv7604_op_ch_sel op_ch_sel;
|
enum adv7604_bus_order bus_order;
|
||||||
|
|
||||||
/* Select output format */
|
/* Select output format mode */
|
||||||
enum adv7604_op_format_sel op_format_sel;
|
enum adv7604_op_format_mode_sel op_format_mode_sel;
|
||||||
|
|
||||||
|
/* Configuration of the INT1 pin */
|
||||||
|
enum adv7604_int1_config int1_config;
|
||||||
|
|
||||||
/* IO register 0x02 */
|
/* IO register 0x02 */
|
||||||
unsigned alt_gamma:1;
|
unsigned alt_gamma:1;
|
||||||
unsigned op_656_range:1;
|
unsigned op_656_range:1;
|
||||||
unsigned rgb_out:1;
|
|
||||||
unsigned alt_data_sat:1;
|
unsigned alt_data_sat:1;
|
||||||
|
|
||||||
/* IO register 0x05 */
|
/* IO register 0x05 */
|
||||||
unsigned blank_data:1;
|
unsigned blank_data:1;
|
||||||
unsigned insert_av_codes:1;
|
unsigned insert_av_codes:1;
|
||||||
unsigned replicate_av_codes:1;
|
unsigned replicate_av_codes:1;
|
||||||
unsigned invert_cbcr:1;
|
|
||||||
|
|
||||||
/* IO register 0x06 */
|
/* IO register 0x06 */
|
||||||
unsigned inv_vs_pol:1;
|
unsigned inv_vs_pol:1;
|
||||||
unsigned inv_hs_pol:1;
|
unsigned inv_hs_pol:1;
|
||||||
|
unsigned inv_llc_pol:1;
|
||||||
|
|
||||||
/* IO register 0x14 */
|
/* IO register 0x14 */
|
||||||
enum adv7604_drive_strength dr_str_data;
|
enum adv7604_drive_strength dr_str_data;
|
||||||
|
@ -131,34 +145,22 @@ struct adv7604_platform_data {
|
||||||
unsigned hdmi_free_run_mode;
|
unsigned hdmi_free_run_mode;
|
||||||
|
|
||||||
/* i2c addresses: 0 == use default */
|
/* i2c addresses: 0 == use default */
|
||||||
u8 i2c_avlink;
|
u8 i2c_addresses[ADV7604_PAGE_MAX];
|
||||||
u8 i2c_cec;
|
|
||||||
u8 i2c_infoframe;
|
|
||||||
u8 i2c_esdp;
|
|
||||||
u8 i2c_dpp;
|
|
||||||
u8 i2c_afe;
|
|
||||||
u8 i2c_repeater;
|
|
||||||
u8 i2c_edid;
|
|
||||||
u8 i2c_hdmi;
|
|
||||||
u8 i2c_test;
|
|
||||||
u8 i2c_cp;
|
|
||||||
u8 i2c_vdp;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum adv7604_input_port {
|
enum adv7604_pad {
|
||||||
ADV7604_INPUT_HDMI_PORT_A,
|
ADV7604_PAD_HDMI_PORT_A = 0,
|
||||||
ADV7604_INPUT_HDMI_PORT_B,
|
ADV7604_PAD_HDMI_PORT_B = 1,
|
||||||
ADV7604_INPUT_HDMI_PORT_C,
|
ADV7604_PAD_HDMI_PORT_C = 2,
|
||||||
ADV7604_INPUT_HDMI_PORT_D,
|
ADV7604_PAD_HDMI_PORT_D = 3,
|
||||||
ADV7604_INPUT_VGA_RGB,
|
ADV7604_PAD_VGA_RGB = 4,
|
||||||
ADV7604_INPUT_VGA_COMP,
|
ADV7604_PAD_VGA_COMP = 5,
|
||||||
|
/* The source pad is either 1 (ADV7611) or 6 (ADV7604) */
|
||||||
|
ADV7604_PAD_SOURCE = 6,
|
||||||
|
ADV7611_PAD_SOURCE = 1,
|
||||||
|
ADV7604_PAD_MAX = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ADV7604_EDID_PORT_A 0
|
|
||||||
#define ADV7604_EDID_PORT_B 1
|
|
||||||
#define ADV7604_EDID_PORT_C 2
|
|
||||||
#define ADV7604_EDID_PORT_D 3
|
|
||||||
|
|
||||||
#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000)
|
#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000)
|
||||||
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001)
|
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001)
|
||||||
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002)
|
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002)
|
||||||
|
|
|
@ -338,12 +338,8 @@ struct v4l2_subdev_video_ops {
|
||||||
struct v4l2_dv_timings *timings);
|
struct v4l2_dv_timings *timings);
|
||||||
int (*g_dv_timings)(struct v4l2_subdev *sd,
|
int (*g_dv_timings)(struct v4l2_subdev *sd,
|
||||||
struct v4l2_dv_timings *timings);
|
struct v4l2_dv_timings *timings);
|
||||||
int (*enum_dv_timings)(struct v4l2_subdev *sd,
|
|
||||||
struct v4l2_enum_dv_timings *timings);
|
|
||||||
int (*query_dv_timings)(struct v4l2_subdev *sd,
|
int (*query_dv_timings)(struct v4l2_subdev *sd,
|
||||||
struct v4l2_dv_timings *timings);
|
struct v4l2_dv_timings *timings);
|
||||||
int (*dv_timings_cap)(struct v4l2_subdev *sd,
|
|
||||||
struct v4l2_dv_timings_cap *cap);
|
|
||||||
int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
|
int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
|
||||||
enum v4l2_mbus_pixelcode *code);
|
enum v4l2_mbus_pixelcode *code);
|
||||||
int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
|
int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
|
||||||
|
|
Loading…
Reference in New Issue