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:
Linus Torvalds 2014-06-06 11:58:47 -07:00
commit 0bb4646241
23 changed files with 1896 additions and 597 deletions

View File

@ -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>;
};
};
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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,
}, },
}; };

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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];

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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,