Merge branch 'topic/vsp1' into patchwork
* topic/vsp1: (36 commits) [media] v4l: vsp1: wpf: Add flipping support [media] v4l: vsp1: rwpf: Support runtime modification of controls [media] v4l: vsp1: Simplify alpha propagation [media] v4l: vsp1: clu: Support runtime modification of controls [media] v4l: vsp1: lut: Support runtime modification of controls [media] v4l: vsp1: Support runtime modification of controls [media] v4l: vsp1: Add Cubic Look Up Table (CLU) support [media] v4l: vsp1: lut: Expose configuration through a control [media] v4l: vsp1: lut: Initialize the mutex [media] v4l: vsp1: dl: Don't free fragments with interrupts disabled [media] v4l: vsp1: Set entities functions [media] v4l: vsp1: Don't create LIF entity when the userspace API is enabled [media] v4l: vsp1: Don't register media device when userspace API is disabled [media] v4l: vsp1: Base link creation on availability of entities [media] media: Add video statistics computation functions [media] media: Add video processing entity functions [media] v4l: vsp1: sru: Fix intensity control ID [media] v4l: vsp1: Stop the pipeline upon the first STREAMOFF [media] v4l: vsp1: Constify operation structures [media] v4l: vsp1: pipe: Fix typo in comment ...
This commit is contained in:
Коммит
c9a3429bcc
|
@ -121,6 +121,70 @@
|
|||
<entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry>
|
||||
<entry>Audio Mixer Function Entity.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_COMPOSER</constant></entry>
|
||||
<entry>Video composer (blender). An entity capable of video
|
||||
composing must have at least two sink pads and one source
|
||||
pad, and composes input video frames onto output video
|
||||
frames. Composition can be performed using alpha blending,
|
||||
color keying, raster operations (ROP), stitching or any other
|
||||
means.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER</constant></entry>
|
||||
<entry>Video pixel formatter. An entity capable of pixel formatting
|
||||
must have at least one sink pad and one source pad. Read
|
||||
pixel formatters read pixels from memory and perform a subset
|
||||
of unpacking, cropping, color keying, alpha multiplication
|
||||
and pixel encoding conversion. Write pixel formatters perform
|
||||
a subset of dithering, pixel encoding conversion and packing
|
||||
and write pixels to memory.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV</constant></entry>
|
||||
<entry>Video pixel encoding converter. An entity capable of pixel
|
||||
enconding conversion must have at least one sink pad and one
|
||||
source pad, and convert the encoding of pixels received on
|
||||
its sink pad(s) to a different encoding output on its source
|
||||
pad(s). Pixel encoding conversion includes but isn't limited
|
||||
to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB
|
||||
conversions.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_LUT</constant></entry>
|
||||
<entry>Video look-up table. An entity capable of video lookup table
|
||||
processing must have one sink pad and one source pad. It uses
|
||||
the values of the pixels received on its sink pad to look up
|
||||
entries in internal tables and output them on its source pad.
|
||||
The lookup processing can be performed on all components
|
||||
separately or combine them for multi-dimensional table
|
||||
lookups.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_SCALER</constant></entry>
|
||||
<entry>Video scaler. An entity capable of video scaling must have
|
||||
at least one sink pad and one source pad, and scale the
|
||||
video frame(s) received on its sink pad(s) to a different
|
||||
resolution output on its source pad(s). The range of
|
||||
supported scaling ratios is entity-specific and can differ
|
||||
between the horizontal and vertical directions (in particular
|
||||
scaling can be supported in one direction only). Binning and
|
||||
skipping are considered as scaling.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>MEDIA_ENT_F_PROC_VIDEO_STATISTICS</constant></entry>
|
||||
<entry>Video statistics computation (histogram, 3A, ...). An entity
|
||||
capable of statistics computation must have one sink pad and
|
||||
one source pad. It computes statistics over the frames
|
||||
received on its sink pad and outputs the statistics data on
|
||||
its source pad.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
Renesas R-Car Frame Compression Processor (FCP)
|
||||
-----------------------------------------------
|
||||
|
||||
The FCP is a companion module of video processing modules in the Renesas R-Car
|
||||
Gen3 SoCs. It provides data compression and decompression, data caching, and
|
||||
conversion of AXI transactions in order to reduce the memory bandwidth.
|
||||
|
||||
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP
|
||||
for FDP (FCPF). Their configuration and behaviour depend on the module they
|
||||
are paired with. These DT bindings currently support the FCPV only.
|
||||
|
||||
- compatible: Must be one or more of the following
|
||||
|
||||
- "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP'
|
||||
- "renesas,fcpv" for generic compatible 'FCP for VSP'
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first, followed by the
|
||||
family-specific and/or generic versions.
|
||||
|
||||
- reg: the register base and size for the device registers
|
||||
- clocks: Reference to the functional clock
|
||||
|
||||
|
||||
Device node example
|
||||
-------------------
|
||||
|
||||
fcpvd1: fcp@fea2f000 {
|
||||
compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
|
||||
reg = <0 0xfea2f000 0 0x200>;
|
||||
clocks = <&cpg CPG_MOD 602>;
|
||||
};
|
|
@ -14,6 +14,11 @@ Required properties:
|
|||
- interrupts: VSP interrupt specifier.
|
||||
- clocks: A phandle + clock-specifier pair for the VSP functional clock.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- renesas,fcp: A phandle referencing the FCP that handles memory accesses
|
||||
for the VSP. Not needed on Gen2, mandatory on Gen3.
|
||||
|
||||
|
||||
Example: R8A7790 (R-Car H2) VSP1-S node
|
||||
|
||||
|
|
10
MAINTAINERS
10
MAINTAINERS
|
@ -7343,6 +7343,16 @@ L: linux-iio@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/iio/potentiometer/mcp4531.c
|
||||
|
||||
MEDIA DRIVERS FOR RENESAS - FCP
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/renesas,fcp.txt
|
||||
F: drivers/media/platform/rcar-fcp.c
|
||||
F: include/media/rcar-fcp.h
|
||||
|
||||
MEDIA DRIVERS FOR RENESAS - VSP1
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
|
@ -148,40 +148,39 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
|
|||
struct rcar_du_vsp_plane_state *state =
|
||||
to_rcar_vsp_plane_state(plane->plane.state);
|
||||
struct drm_framebuffer *fb = plane->plane.state->fb;
|
||||
struct v4l2_rect src;
|
||||
struct v4l2_rect dst;
|
||||
dma_addr_t paddr[2] = { 0, };
|
||||
u32 pixelformat = 0;
|
||||
struct vsp1_du_atomic_config cfg = {
|
||||
.pixelformat = 0,
|
||||
.pitch = fb->pitches[0],
|
||||
.alpha = state->alpha,
|
||||
.zpos = state->zpos,
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
src.left = state->state.src_x >> 16;
|
||||
src.top = state->state.src_y >> 16;
|
||||
src.width = state->state.src_w >> 16;
|
||||
src.height = state->state.src_h >> 16;
|
||||
cfg.src.left = state->state.src_x >> 16;
|
||||
cfg.src.top = state->state.src_y >> 16;
|
||||
cfg.src.width = state->state.src_w >> 16;
|
||||
cfg.src.height = state->state.src_h >> 16;
|
||||
|
||||
dst.left = state->state.crtc_x;
|
||||
dst.top = state->state.crtc_y;
|
||||
dst.width = state->state.crtc_w;
|
||||
dst.height = state->state.crtc_h;
|
||||
cfg.dst.left = state->state.crtc_x;
|
||||
cfg.dst.top = state->state.crtc_y;
|
||||
cfg.dst.width = state->state.crtc_w;
|
||||
cfg.dst.height = state->state.crtc_h;
|
||||
|
||||
for (i = 0; i < state->format->planes; ++i) {
|
||||
struct drm_gem_cma_object *gem;
|
||||
|
||||
gem = drm_fb_cma_get_gem_obj(fb, i);
|
||||
paddr[i] = gem->paddr + fb->offsets[i];
|
||||
cfg.mem[i] = gem->paddr + fb->offsets[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) {
|
||||
if (formats_kms[i] == state->format->fourcc) {
|
||||
pixelformat = formats_v4l2[i];
|
||||
cfg.pixelformat = formats_v4l2[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON(!pixelformat);
|
||||
|
||||
vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat,
|
||||
fb->pitches[0], paddr, &src, &dst);
|
||||
vsp1_du_atomic_update(plane->vsp->vsp, plane->index, &cfg);
|
||||
}
|
||||
|
||||
static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
|
||||
|
@ -220,8 +219,7 @@ static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
|
|||
if (plane->state->crtc)
|
||||
rcar_du_vsp_plane_setup(rplane);
|
||||
else
|
||||
vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0,
|
||||
NULL, NULL);
|
||||
vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, NULL);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
|
||||
|
@ -269,6 +267,7 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
|
|||
return;
|
||||
|
||||
state->alpha = 255;
|
||||
state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
|
||||
|
||||
plane->state = &state->state;
|
||||
plane->state->plane = plane;
|
||||
|
@ -283,6 +282,8 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane,
|
|||
|
||||
if (property == rcdu->props.alpha)
|
||||
rstate->alpha = val;
|
||||
else if (property == rcdu->props.zpos)
|
||||
rstate->zpos = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -299,6 +300,8 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane,
|
|||
|
||||
if (property == rcdu->props.alpha)
|
||||
*val = rstate->alpha;
|
||||
else if (property == rcdu->props.zpos)
|
||||
*val = rstate->zpos;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -378,6 +381,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp)
|
|||
|
||||
drm_object_attach_property(&plane->plane.base,
|
||||
rcdu->props.alpha, 255);
|
||||
drm_object_attach_property(&plane->plane.base,
|
||||
rcdu->props.zpos, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -44,6 +44,7 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p)
|
|||
* @state: base DRM plane state
|
||||
* @format: information about the pixel format used by the plane
|
||||
* @alpha: value of the plane alpha property
|
||||
* @zpos: value of the plane zpos property
|
||||
*/
|
||||
struct rcar_du_vsp_plane_state {
|
||||
struct drm_plane_state state;
|
||||
|
@ -51,6 +52,7 @@ struct rcar_du_vsp_plane_state {
|
|||
const struct rcar_du_format_info *format;
|
||||
|
||||
unsigned int alpha;
|
||||
unsigned int zpos;
|
||||
};
|
||||
|
||||
static inline struct rcar_du_vsp_plane_state *
|
||||
|
|
|
@ -278,10 +278,24 @@ config VIDEO_RENESAS_JPU
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called rcar_jpu.
|
||||
|
||||
config VIDEO_RENESAS_FCP
|
||||
tristate "Renesas Frame Compression Processor"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on OF
|
||||
---help---
|
||||
This is a driver for the Renesas Frame Compression Processor (FCP).
|
||||
The FCP is a companion module of video processing modules in the
|
||||
Renesas R-Car Gen3 SoCs. It handles memory access for the codec,
|
||||
VSP and FDP modules.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called rcar-fcp.
|
||||
|
||||
config VIDEO_RENESAS_VSP1
|
||||
tristate "Renesas VSP1 Video Processing Engine"
|
||||
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
|
||||
depends on (ARCH_RENESAS && OF) || COMPILE_TEST
|
||||
depends on !ARM64 || VIDEO_RENESAS_FCP
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
---help---
|
||||
This is a V4L2 driver for the Renesas VSP1 video processing engine.
|
||||
|
|
|
@ -46,6 +46,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o
|
|||
|
||||
obj-$(CONFIG_SOC_CAMERA) += soc_camera/
|
||||
|
||||
obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o
|
||||
obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o
|
||||
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
|
||||
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* rcar-fcp.c -- R-Car Frame Compression Processor Driver
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Electronics 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/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <media/rcar-fcp.h>
|
||||
|
||||
struct rcar_fcp_device {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static LIST_HEAD(fcp_devices);
|
||||
static DEFINE_MUTEX(fcp_lock);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Public API
|
||||
*/
|
||||
|
||||
/**
|
||||
* rcar_fcp_get - Find and acquire a reference to an FCP instance
|
||||
* @np: Device node of the FCP instance
|
||||
*
|
||||
* Search the list of registered FCP instances for the instance corresponding to
|
||||
* the given device node.
|
||||
*
|
||||
* Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be
|
||||
* found.
|
||||
*/
|
||||
struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np)
|
||||
{
|
||||
struct rcar_fcp_device *fcp;
|
||||
|
||||
mutex_lock(&fcp_lock);
|
||||
|
||||
list_for_each_entry(fcp, &fcp_devices, list) {
|
||||
if (fcp->dev->of_node != np)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make sure the module won't be unloaded behind our back. This
|
||||
* is a poor man's safety net, the module should really not be
|
||||
* unloaded while FCP users can be active.
|
||||
*/
|
||||
if (!try_module_get(fcp->dev->driver->owner))
|
||||
fcp = NULL;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
fcp = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
done:
|
||||
mutex_unlock(&fcp_lock);
|
||||
return fcp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcar_fcp_get);
|
||||
|
||||
/**
|
||||
* rcar_fcp_put - Release a reference to an FCP instance
|
||||
* @fcp: The FCP instance
|
||||
*
|
||||
* Release the FCP instance acquired by a call to rcar_fcp_get().
|
||||
*/
|
||||
void rcar_fcp_put(struct rcar_fcp_device *fcp)
|
||||
{
|
||||
if (fcp)
|
||||
module_put(fcp->dev->driver->owner);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcar_fcp_put);
|
||||
|
||||
/**
|
||||
* rcar_fcp_enable - Enable an FCP
|
||||
* @fcp: The FCP instance
|
||||
*
|
||||
* Before any memory access through an FCP is performed by a module, the FCP
|
||||
* must be enabled by a call to this function. The enable calls are reference
|
||||
* counted, each successful call must be followed by one rcar_fcp_disable()
|
||||
* call when no more memory transfer can occur through the FCP.
|
||||
*
|
||||
* Return 0 on success or a negative error code if an error occurs. The enable
|
||||
* reference count isn't increased when this function returns an error.
|
||||
*/
|
||||
int rcar_fcp_enable(struct rcar_fcp_device *fcp)
|
||||
{
|
||||
if (!fcp)
|
||||
return 0;
|
||||
|
||||
return pm_runtime_get_sync(fcp->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcar_fcp_enable);
|
||||
|
||||
/**
|
||||
* rcar_fcp_disable - Disable an FCP
|
||||
* @fcp: The FCP instance
|
||||
*
|
||||
* This function is the counterpart of rcar_fcp_enable(). As enable calls are
|
||||
* reference counted a disable call may not disable the FCP synchronously.
|
||||
*/
|
||||
void rcar_fcp_disable(struct rcar_fcp_device *fcp)
|
||||
{
|
||||
if (fcp)
|
||||
pm_runtime_put(fcp->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcar_fcp_disable);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Platform Driver
|
||||
*/
|
||||
|
||||
static int rcar_fcp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_fcp_device *fcp;
|
||||
|
||||
fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL);
|
||||
if (fcp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fcp->dev = &pdev->dev;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
mutex_lock(&fcp_lock);
|
||||
list_add_tail(&fcp->list, &fcp_devices);
|
||||
mutex_unlock(&fcp_lock);
|
||||
|
||||
platform_set_drvdata(pdev, fcp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_fcp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_fcp_device *fcp = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&fcp_lock);
|
||||
list_del(&fcp->list);
|
||||
mutex_unlock(&fcp_lock);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rcar_fcp_of_match[] = {
|
||||
{ .compatible = "renesas,fcpv" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver rcar_fcp_platform_driver = {
|
||||
.probe = rcar_fcp_probe,
|
||||
.remove = rcar_fcp_remove,
|
||||
.driver = {
|
||||
.name = "rcar-fcp",
|
||||
.of_match_table = rcar_fcp_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rcar_fcp_platform_driver);
|
||||
|
||||
MODULE_ALIAS("rcar-fcp");
|
||||
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
|
||||
MODULE_DESCRIPTION("Renesas FCP Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,7 +1,8 @@
|
|||
vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_pipe.o
|
||||
vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o
|
||||
vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
|
||||
vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
|
||||
vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o
|
||||
vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o
|
||||
vsp1-y += vsp1_lif.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
|
||||
struct clk;
|
||||
struct device;
|
||||
struct rcar_fcp_device;
|
||||
|
||||
struct vsp1_drm;
|
||||
struct vsp1_entity;
|
||||
struct vsp1_platform_data;
|
||||
struct vsp1_bru;
|
||||
struct vsp1_clu;
|
||||
struct vsp1_hsit;
|
||||
struct vsp1_lif;
|
||||
struct vsp1_lut;
|
||||
|
@ -45,6 +47,9 @@ struct vsp1_uds;
|
|||
#define VSP1_HAS_LUT (1 << 1)
|
||||
#define VSP1_HAS_SRU (1 << 2)
|
||||
#define VSP1_HAS_BRU (1 << 3)
|
||||
#define VSP1_HAS_CLU (1 << 4)
|
||||
#define VSP1_HAS_WPF_VFLIP (1 << 5)
|
||||
#define VSP1_HAS_WPF_HFLIP (1 << 6)
|
||||
|
||||
struct vsp1_device_info {
|
||||
u32 version;
|
||||
|
@ -62,12 +67,10 @@ struct vsp1_device {
|
|||
const struct vsp1_device_info *info;
|
||||
|
||||
void __iomem *mmio;
|
||||
struct clk *clock;
|
||||
|
||||
struct mutex lock;
|
||||
int ref_count;
|
||||
struct rcar_fcp_device *fcp;
|
||||
|
||||
struct vsp1_bru *bru;
|
||||
struct vsp1_clu *clu;
|
||||
struct vsp1_hsit *hsi;
|
||||
struct vsp1_hsit *hst;
|
||||
struct vsp1_lif *lif;
|
||||
|
|
|
@ -249,7 +249,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops bru_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops bru_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = bru_enum_mbus_code,
|
||||
.enum_frame_size = bru_enum_frame_size,
|
||||
|
@ -259,7 +259,7 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = {
|
|||
.set_selection = bru_set_selection,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops bru_ops = {
|
||||
static const struct v4l2_subdev_ops bru_ops = {
|
||||
.pad = &bru_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -269,13 +269,16 @@ static struct v4l2_subdev_ops bru_ops = {
|
|||
|
||||
static void bru_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_bru *bru = to_bru(&entity->subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
unsigned int flags;
|
||||
unsigned int i;
|
||||
|
||||
if (!full)
|
||||
return;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
|
||||
bru->entity.source_pad);
|
||||
|
||||
|
@ -390,7 +393,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
|
|||
bru->entity.type = VSP1_ENTITY_BRU;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
|
||||
vsp1->info->num_bru_inputs + 1, &bru_ops);
|
||||
vsp1->info->num_bru_inputs + 1, &bru_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_COMPOSER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* vsp1_clu.c -- R-Car VSP1 Cubic Look-Up Table
|
||||
*
|
||||
* Copyright (C) 2015-2016 Renesas Electronics 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/slab.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_clu.h"
|
||||
#include "vsp1_dl.h"
|
||||
|
||||
#define CLU_MIN_SIZE 4U
|
||||
#define CLU_MAX_SIZE 8190U
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Device Access
|
||||
*/
|
||||
|
||||
static inline void vsp1_clu_write(struct vsp1_clu *clu, struct vsp1_dl_list *dl,
|
||||
u32 reg, u32 data)
|
||||
{
|
||||
vsp1_dl_list_write(dl, reg, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Controls
|
||||
*/
|
||||
|
||||
#define V4L2_CID_VSP1_CLU_TABLE (V4L2_CID_USER_BASE | 0x1001)
|
||||
#define V4L2_CID_VSP1_CLU_MODE (V4L2_CID_USER_BASE | 0x1002)
|
||||
#define V4L2_CID_VSP1_CLU_MODE_2D 0
|
||||
#define V4L2_CID_VSP1_CLU_MODE_3D 1
|
||||
|
||||
static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vsp1_dl_body *dlb;
|
||||
unsigned int i;
|
||||
|
||||
dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17);
|
||||
if (!dlb)
|
||||
return -ENOMEM;
|
||||
|
||||
vsp1_dl_fragment_write(dlb, VI6_CLU_ADDR, 0);
|
||||
for (i = 0; i < 17 * 17 * 17; ++i)
|
||||
vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]);
|
||||
|
||||
spin_lock_irq(&clu->lock);
|
||||
swap(clu->clu, dlb);
|
||||
spin_unlock_irq(&clu->lock);
|
||||
|
||||
vsp1_dl_fragment_free(dlb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clu_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vsp1_clu *clu =
|
||||
container_of(ctrl->handler, struct vsp1_clu, ctrls);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_VSP1_CLU_TABLE:
|
||||
clu_set_table(clu, ctrl);
|
||||
break;
|
||||
|
||||
case V4L2_CID_VSP1_CLU_MODE:
|
||||
clu->mode = ctrl->val;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops clu_ctrl_ops = {
|
||||
.s_ctrl = clu_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_config clu_table_control = {
|
||||
.ops = &clu_ctrl_ops,
|
||||
.id = V4L2_CID_VSP1_CLU_TABLE,
|
||||
.name = "Look-Up Table",
|
||||
.type = V4L2_CTRL_TYPE_U32,
|
||||
.min = 0x00000000,
|
||||
.max = 0x00ffffff,
|
||||
.step = 1,
|
||||
.def = 0,
|
||||
.dims = { 17, 17, 17 },
|
||||
};
|
||||
|
||||
static const char * const clu_mode_menu[] = {
|
||||
"2D",
|
||||
"3D",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_config clu_mode_control = {
|
||||
.ops = &clu_ctrl_ops,
|
||||
.id = V4L2_CID_VSP1_CLU_MODE,
|
||||
.name = "Mode",
|
||||
.type = V4L2_CTRL_TYPE_MENU,
|
||||
.min = 0,
|
||||
.max = 1,
|
||||
.def = 1,
|
||||
.qmenu = clu_mode_menu,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
||||
static int clu_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
static const unsigned int codes[] = {
|
||||
MEDIA_BUS_FMT_ARGB8888_1X32,
|
||||
MEDIA_BUS_FMT_AHSV8888_1X32,
|
||||
MEDIA_BUS_FMT_AYUV8_1X32,
|
||||
};
|
||||
|
||||
return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
|
||||
ARRAY_SIZE(codes));
|
||||
}
|
||||
|
||||
static int clu_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE,
|
||||
CLU_MIN_SIZE, CLU_MAX_SIZE,
|
||||
CLU_MAX_SIZE);
|
||||
}
|
||||
|
||||
static int clu_set_format(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_clu *clu = to_clu(subdev);
|
||||
struct v4l2_subdev_pad_config *config;
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
config = vsp1_entity_get_pad_config(&clu->entity, cfg, fmt->which);
|
||||
if (!config)
|
||||
return -EINVAL;
|
||||
|
||||
/* Default to YUV if the requested format is not supported. */
|
||||
if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
|
||||
fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
|
||||
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
|
||||
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&clu->entity, config, fmt->pad);
|
||||
|
||||
if (fmt->pad == CLU_PAD_SOURCE) {
|
||||
/* The CLU output format can't be modified. */
|
||||
fmt->format = *format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
format->code = fmt->format.code;
|
||||
format->width = clamp_t(unsigned int, fmt->format.width,
|
||||
CLU_MIN_SIZE, CLU_MAX_SIZE);
|
||||
format->height = clamp_t(unsigned int, fmt->format.height,
|
||||
CLU_MIN_SIZE, CLU_MAX_SIZE);
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
format->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
|
||||
fmt->format = *format;
|
||||
|
||||
/* Propagate the format to the source pad. */
|
||||
format = vsp1_entity_get_pad_format(&clu->entity, config,
|
||||
CLU_PAD_SOURCE);
|
||||
*format = fmt->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static const struct v4l2_subdev_pad_ops clu_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = clu_enum_mbus_code,
|
||||
.enum_frame_size = clu_enum_frame_size,
|
||||
.get_fmt = vsp1_subdev_get_pad_format,
|
||||
.set_fmt = clu_set_format,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops clu_ops = {
|
||||
.pad = &clu_pad_ops,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* VSP1 Entity Operations
|
||||
*/
|
||||
|
||||
static void clu_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_clu *clu = to_clu(&entity->subdev);
|
||||
struct vsp1_dl_body *dlb;
|
||||
unsigned long flags;
|
||||
u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN;
|
||||
|
||||
/* The format can't be changed during streaming, only verify it at
|
||||
* stream start and store the information internally for future partial
|
||||
* reconfiguration calls.
|
||||
*/
|
||||
if (full) {
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&clu->entity,
|
||||
clu->entity.config,
|
||||
CLU_PAD_SINK);
|
||||
clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 2D mode can only be used with the YCbCr pixel encoding. */
|
||||
if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode)
|
||||
ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D
|
||||
| VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D
|
||||
| VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D;
|
||||
|
||||
vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl);
|
||||
|
||||
spin_lock_irqsave(&clu->lock, flags);
|
||||
dlb = clu->clu;
|
||||
clu->clu = NULL;
|
||||
spin_unlock_irqrestore(&clu->lock, flags);
|
||||
|
||||
if (dlb)
|
||||
vsp1_dl_list_add_fragment(dl, dlb);
|
||||
}
|
||||
|
||||
static const struct vsp1_entity_operations clu_entity_ops = {
|
||||
.configure = clu_configure,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization and Cleanup
|
||||
*/
|
||||
|
||||
struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct vsp1_clu *clu;
|
||||
int ret;
|
||||
|
||||
clu = devm_kzalloc(vsp1->dev, sizeof(*clu), GFP_KERNEL);
|
||||
if (clu == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_init(&clu->lock);
|
||||
|
||||
clu->entity.ops = &clu_entity_ops;
|
||||
clu->entity.type = VSP1_ENTITY_CLU;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &clu->entity, "clu", 2, &clu_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_LUT);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the control handler. */
|
||||
v4l2_ctrl_handler_init(&clu->ctrls, 2);
|
||||
v4l2_ctrl_new_custom(&clu->ctrls, &clu_table_control, NULL);
|
||||
v4l2_ctrl_new_custom(&clu->ctrls, &clu_mode_control, NULL);
|
||||
|
||||
clu->entity.subdev.ctrl_handler = &clu->ctrls;
|
||||
|
||||
if (clu->ctrls.error) {
|
||||
dev_err(vsp1->dev, "clu: failed to initialize controls\n");
|
||||
ret = clu->ctrls.error;
|
||||
vsp1_entity_destroy(&clu->entity);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_setup(&clu->ctrls);
|
||||
|
||||
return clu;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* vsp1_clu.h -- R-Car VSP1 Cubic Look-Up Table
|
||||
*
|
||||
* Copyright (C) 2015 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_CLU_H__
|
||||
#define __VSP1_CLU_H__
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
struct vsp1_device;
|
||||
struct vsp1_dl_body;
|
||||
|
||||
#define CLU_PAD_SINK 0
|
||||
#define CLU_PAD_SOURCE 1
|
||||
|
||||
struct vsp1_clu {
|
||||
struct vsp1_entity entity;
|
||||
|
||||
struct v4l2_ctrl_handler ctrls;
|
||||
|
||||
bool yuv_mode;
|
||||
spinlock_t lock;
|
||||
unsigned int mode;
|
||||
struct vsp1_dl_body *clu;
|
||||
};
|
||||
|
||||
static inline struct vsp1_clu *to_clu(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_clu, entity.subdev);
|
||||
}
|
||||
|
||||
struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1);
|
||||
|
||||
#endif /* __VSP1_CLU_H__ */
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_dl.h"
|
||||
|
@ -92,11 +93,13 @@ enum vsp1_dl_mode {
|
|||
* @index: index of the related WPF
|
||||
* @mode: display list operation mode (header or headerless)
|
||||
* @vsp1: the VSP1 device
|
||||
* @lock: protects the active, queued and pending lists
|
||||
* @lock: protects the free, active, queued, pending and gc_fragments lists
|
||||
* @free: array of all free display lists
|
||||
* @active: list currently being processed (loaded) by hardware
|
||||
* @queued: list queued to the hardware (written to the DL registers)
|
||||
* @pending: list waiting to be queued to the hardware
|
||||
* @gc_work: fragments garbage collector work struct
|
||||
* @gc_fragments: array of display list fragments waiting to be freed
|
||||
*/
|
||||
struct vsp1_dl_manager {
|
||||
unsigned int index;
|
||||
|
@ -108,6 +111,9 @@ struct vsp1_dl_manager {
|
|||
struct vsp1_dl_list *active;
|
||||
struct vsp1_dl_list *queued;
|
||||
struct vsp1_dl_list *pending;
|
||||
|
||||
struct work_struct gc_work;
|
||||
struct list_head gc_fragments;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -262,21 +268,10 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
|
|||
return dl;
|
||||
}
|
||||
|
||||
static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl)
|
||||
{
|
||||
struct vsp1_dl_body *dlb, *next;
|
||||
|
||||
list_for_each_entry_safe(dlb, next, &dl->fragments, list) {
|
||||
list_del(&dlb->list);
|
||||
vsp1_dl_body_cleanup(dlb);
|
||||
kfree(dlb);
|
||||
}
|
||||
}
|
||||
|
||||
static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
|
||||
{
|
||||
vsp1_dl_body_cleanup(&dl->body0);
|
||||
vsp1_dl_list_free_fragments(dl);
|
||||
list_splice_init(&dl->fragments, &dl->dlm->gc_fragments);
|
||||
kfree(dl);
|
||||
}
|
||||
|
||||
|
@ -311,7 +306,16 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
|
|||
if (!dl)
|
||||
return;
|
||||
|
||||
vsp1_dl_list_free_fragments(dl);
|
||||
/* We can't free fragments here as DMA memory can only be freed in
|
||||
* interruptible context. Move all fragments to the display list
|
||||
* manager's list of fragments to be freed, they will be
|
||||
* garbage-collected by the work queue.
|
||||
*/
|
||||
if (!list_empty(&dl->fragments)) {
|
||||
list_splice_init(&dl->fragments, &dl->dlm->gc_fragments);
|
||||
schedule_work(&dl->dlm->gc_work);
|
||||
}
|
||||
|
||||
dl->body0.num_entries = 0;
|
||||
|
||||
list_add_tail(&dl->list, &dl->dlm->free);
|
||||
|
@ -550,6 +554,40 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
|
|||
dlm->pending = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all fragments awaiting to be garbage-collected.
|
||||
*
|
||||
* This function must be called without the display list manager lock held.
|
||||
*/
|
||||
static void vsp1_dlm_fragments_free(struct vsp1_dl_manager *dlm)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dlm->lock, flags);
|
||||
|
||||
while (!list_empty(&dlm->gc_fragments)) {
|
||||
struct vsp1_dl_body *dlb;
|
||||
|
||||
dlb = list_first_entry(&dlm->gc_fragments, struct vsp1_dl_body,
|
||||
list);
|
||||
list_del(&dlb->list);
|
||||
|
||||
spin_unlock_irqrestore(&dlm->lock, flags);
|
||||
vsp1_dl_fragment_free(dlb);
|
||||
spin_lock_irqsave(&dlm->lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dlm->lock, flags);
|
||||
}
|
||||
|
||||
static void vsp1_dlm_garbage_collect(struct work_struct *work)
|
||||
{
|
||||
struct vsp1_dl_manager *dlm =
|
||||
container_of(work, struct vsp1_dl_manager, gc_work);
|
||||
|
||||
vsp1_dlm_fragments_free(dlm);
|
||||
}
|
||||
|
||||
struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
|
||||
unsigned int index,
|
||||
unsigned int prealloc)
|
||||
|
@ -568,6 +606,8 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
|
|||
|
||||
spin_lock_init(&dlm->lock);
|
||||
INIT_LIST_HEAD(&dlm->free);
|
||||
INIT_LIST_HEAD(&dlm->gc_fragments);
|
||||
INIT_WORK(&dlm->gc_work, vsp1_dlm_garbage_collect);
|
||||
|
||||
for (i = 0; i < prealloc; ++i) {
|
||||
struct vsp1_dl_list *dl;
|
||||
|
@ -589,8 +629,12 @@ void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
|
|||
if (!dlm)
|
||||
return;
|
||||
|
||||
cancel_work_sync(&dlm->gc_work);
|
||||
|
||||
list_for_each_entry_safe(dl, next, &dlm->free, list) {
|
||||
list_del(&dl->list);
|
||||
vsp1_dl_list_free(dl);
|
||||
}
|
||||
|
||||
vsp1_dlm_fragments_free(dlm);
|
||||
}
|
||||
|
|
|
@ -230,42 +230,33 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
|
|||
* vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline
|
||||
* @dev: the VSP device
|
||||
* @rpf_index: index of the RPF to setup (0-based)
|
||||
* @pixelformat: V4L2 pixel format for the RPF memory input
|
||||
* @pitch: number of bytes per line in the image stored in memory
|
||||
* @mem: DMA addresses of the memory buffers (one per plane)
|
||||
* @src: the source crop rectangle for the RPF
|
||||
* @dst: the destination compose rectangle for the BRU input
|
||||
* @alpha: global alpha value for the input
|
||||
* @zpos: the Z-order position of the input
|
||||
* @cfg: the RPF configuration
|
||||
*
|
||||
* Configure the VSP to perform composition of the image referenced by @mem
|
||||
* through RPF @rpf_index, using the @src crop rectangle and the @dst
|
||||
* Configure the VSP to perform image composition through RPF @rpf_index as
|
||||
* described by the @cfg configuration. The image to compose is referenced by
|
||||
* @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst
|
||||
* composition rectangle. The Z-order is configurable with higher @zpos values
|
||||
* displayed on top.
|
||||
*
|
||||
* Image format as stored in memory is expressed as a V4L2 @pixelformat value.
|
||||
* As a special case, setting the pixel format to 0 will disable the RPF. The
|
||||
* @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the
|
||||
* If the @cfg configuration is NULL, the RPF will be disabled. Calling the
|
||||
* function on a disabled RPF is allowed.
|
||||
*
|
||||
* The memory pitch is configurable to allow for padding at end of lines, or
|
||||
* simple for images that extend beyond the crop rectangle boundaries. The
|
||||
* @pitch value is expressed in bytes and applies to all planes for multiplanar
|
||||
* formats.
|
||||
* Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat
|
||||
* value. The memory pitch is configurable to allow for padding at end of lines,
|
||||
* or simply for images that extend beyond the crop rectangle boundaries. The
|
||||
* @cfg.pitch value is expressed in bytes and applies to all planes for
|
||||
* multiplanar formats.
|
||||
*
|
||||
* The source memory buffer is referenced by the DMA address of its planes in
|
||||
* the @mem array. Up to two planes are supported. The second plane DMA address
|
||||
* is ignored for formats using a single plane.
|
||||
* the @cfg.mem array. Up to two planes are supported. The second plane DMA
|
||||
* address is ignored for formats using a single plane.
|
||||
*
|
||||
* This function isn't reentrant, the caller needs to serialize calls.
|
||||
*
|
||||
* Return 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index,
|
||||
u32 pixelformat, unsigned int pitch,
|
||||
dma_addr_t mem[2], const struct v4l2_rect *src,
|
||||
const struct v4l2_rect *dst, unsigned int alpha,
|
||||
unsigned int zpos)
|
||||
int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
|
||||
const struct vsp1_du_atomic_config *cfg)
|
||||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
const struct vsp1_format_info *fmtinfo;
|
||||
|
@ -276,7 +267,7 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index,
|
|||
|
||||
rpf = vsp1->rpf[rpf_index];
|
||||
|
||||
if (pixelformat == 0) {
|
||||
if (!cfg) {
|
||||
dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
|
||||
rpf_index);
|
||||
|
||||
|
@ -287,38 +278,39 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index,
|
|||
dev_dbg(vsp1->dev,
|
||||
"%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n",
|
||||
__func__, rpf_index,
|
||||
src->left, src->top, src->width, src->height,
|
||||
dst->left, dst->top, dst->width, dst->height,
|
||||
pixelformat, pitch, &mem[0], &mem[1], zpos);
|
||||
cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
|
||||
cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
|
||||
cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
|
||||
cfg->zpos);
|
||||
|
||||
/* Store the format, stride, memory buffer address, crop and compose
|
||||
* rectangles and Z-order position and for the input.
|
||||
*/
|
||||
fmtinfo = vsp1_get_format_info(pixelformat);
|
||||
fmtinfo = vsp1_get_format_info(cfg->pixelformat);
|
||||
if (!fmtinfo) {
|
||||
dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
|
||||
pixelformat);
|
||||
cfg->pixelformat);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rpf->fmtinfo = fmtinfo;
|
||||
rpf->format.num_planes = fmtinfo->planes;
|
||||
rpf->format.plane_fmt[0].bytesperline = pitch;
|
||||
rpf->format.plane_fmt[1].bytesperline = pitch;
|
||||
rpf->alpha = alpha;
|
||||
rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
|
||||
rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
|
||||
rpf->alpha = cfg->alpha;
|
||||
|
||||
rpf->mem.addr[0] = mem[0];
|
||||
rpf->mem.addr[1] = mem[1];
|
||||
rpf->mem.addr[0] = cfg->mem[0];
|
||||
rpf->mem.addr[1] = cfg->mem[1];
|
||||
rpf->mem.addr[2] = 0;
|
||||
|
||||
vsp1->drm->inputs[rpf_index].crop = *src;
|
||||
vsp1->drm->inputs[rpf_index].compose = *dst;
|
||||
vsp1->drm->inputs[rpf_index].zpos = zpos;
|
||||
vsp1->drm->inputs[rpf_index].crop = cfg->src;
|
||||
vsp1->drm->inputs[rpf_index].compose = cfg->dst;
|
||||
vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
|
||||
vsp1->drm->inputs[rpf_index].enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext);
|
||||
EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
|
||||
|
||||
static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
|
||||
struct vsp1_rwpf *rpf, unsigned int bru_input)
|
||||
|
@ -499,8 +491,10 @@ void vsp1_du_atomic_flush(struct device *dev)
|
|||
|
||||
vsp1_entity_route_setup(entity, pipe->dl);
|
||||
|
||||
if (entity->ops->configure)
|
||||
entity->ops->configure(entity, pipe, pipe->dl);
|
||||
if (entity->ops->configure) {
|
||||
entity->ops->configure(entity, pipe, pipe->dl, true);
|
||||
entity->ops->configure(entity, pipe, pipe->dl, false);
|
||||
}
|
||||
|
||||
/* The memory buffer address must be applied after configuring
|
||||
* the RPF to make sure the crop offset are computed.
|
||||
|
|
|
@ -19,12 +19,15 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include <media/rcar-fcp.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_bru.h"
|
||||
#include "vsp1_clu.h"
|
||||
#include "vsp1_dl.h"
|
||||
#include "vsp1_drm.h"
|
||||
#include "vsp1_hsit.h"
|
||||
|
@ -145,7 +148,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (vsp1->info->features & VSP1_HAS_LIF) {
|
||||
if (vsp1->lif) {
|
||||
ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
|
||||
RWPF_PAD_SOURCE,
|
||||
&vsp1->lif->entity.subdev.entity,
|
||||
|
@ -168,19 +171,15 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
|
|||
|
||||
for (i = 0; i < vsp1->info->wpf_count; ++i) {
|
||||
/* Connect the video device to the WPF. All connections are
|
||||
* immutable except for the WPF0 source link if a LIF is
|
||||
* present.
|
||||
* immutable.
|
||||
*/
|
||||
struct vsp1_rwpf *wpf = vsp1->wpf[i];
|
||||
unsigned int flags = MEDIA_LNK_FL_ENABLED;
|
||||
|
||||
if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0)
|
||||
flags |= MEDIA_LNK_FL_IMMUTABLE;
|
||||
|
||||
ret = media_create_pad_link(&wpf->entity.subdev.entity,
|
||||
RWPF_PAD_SOURCE,
|
||||
&wpf->video->video.entity, 0,
|
||||
flags);
|
||||
MEDIA_LNK_FL_IMMUTABLE |
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -204,7 +203,8 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1)
|
|||
}
|
||||
|
||||
v4l2_device_unregister(&vsp1->v4l2_dev);
|
||||
media_device_unregister(&vsp1->media_dev);
|
||||
if (vsp1->info->uapi)
|
||||
media_device_unregister(&vsp1->media_dev);
|
||||
media_device_cleanup(&vsp1->media_dev);
|
||||
|
||||
if (!vsp1->info->uapi)
|
||||
|
@ -252,6 +252,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
|
|||
list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
if (vsp1->info->features & VSP1_HAS_CLU) {
|
||||
vsp1->clu = vsp1_clu_create(vsp1);
|
||||
if (IS_ERR(vsp1->clu)) {
|
||||
ret = PTR_ERR(vsp1->clu);
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
vsp1->hsi = vsp1_hsit_create(vsp1, true);
|
||||
if (IS_ERR(vsp1->hsi)) {
|
||||
ret = PTR_ERR(vsp1->hsi);
|
||||
|
@ -268,7 +278,11 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
|
|||
|
||||
list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
|
||||
|
||||
if (vsp1->info->features & VSP1_HAS_LIF) {
|
||||
/* The LIF is only supported when used in conjunction with the DU, in
|
||||
* which case the userspace API is disabled. If the userspace API is
|
||||
* enabled skip the LIF, even when present.
|
||||
*/
|
||||
if (vsp1->info->features & VSP1_HAS_LIF && !vsp1->info->uapi) {
|
||||
vsp1->lif = vsp1_lif_create(vsp1);
|
||||
if (IS_ERR(vsp1->lif)) {
|
||||
ret = PTR_ERR(vsp1->lif);
|
||||
|
@ -379,14 +393,15 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
|
|||
/* Register subdev nodes if the userspace API is enabled or initialize
|
||||
* the DRM pipeline otherwise.
|
||||
*/
|
||||
if (vsp1->info->uapi)
|
||||
if (vsp1->info->uapi) {
|
||||
ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
|
||||
else
|
||||
ret = vsp1_drm_init(vsp1);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = media_device_register(mdev);
|
||||
ret = media_device_register(mdev);
|
||||
} else {
|
||||
ret = vsp1_drm_init(vsp1);
|
||||
}
|
||||
|
||||
done:
|
||||
if (ret < 0)
|
||||
|
@ -462,35 +477,16 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
|
|||
/*
|
||||
* vsp1_device_get - Acquire the VSP1 device
|
||||
*
|
||||
* Increment the VSP1 reference count and initialize the device if the first
|
||||
* reference is taken.
|
||||
* Make sure the device is not suspended and initialize it if needed.
|
||||
*
|
||||
* Return 0 on success or a negative error code otherwise.
|
||||
*/
|
||||
int vsp1_device_get(struct vsp1_device *vsp1)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&vsp1->lock);
|
||||
if (vsp1->ref_count > 0)
|
||||
goto done;
|
||||
|
||||
ret = clk_prepare_enable(vsp1->clock);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = vsp1_device_init(vsp1);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!ret)
|
||||
vsp1->ref_count++;
|
||||
|
||||
mutex_unlock(&vsp1->lock);
|
||||
return ret;
|
||||
ret = pm_runtime_get_sync(vsp1->dev);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -501,12 +497,7 @@ done:
|
|||
*/
|
||||
void vsp1_device_put(struct vsp1_device *vsp1)
|
||||
{
|
||||
mutex_lock(&vsp1->lock);
|
||||
|
||||
if (--vsp1->ref_count == 0)
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
|
||||
mutex_unlock(&vsp1->lock);
|
||||
pm_runtime_put_sync(vsp1->dev);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -518,14 +509,8 @@ static int vsp1_pm_suspend(struct device *dev)
|
|||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
|
||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
||||
|
||||
if (vsp1->ref_count == 0)
|
||||
return 0;
|
||||
|
||||
vsp1_pipelines_suspend(vsp1);
|
||||
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
pm_runtime_force_suspend(vsp1->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -534,21 +519,39 @@ static int vsp1_pm_resume(struct device *dev)
|
|||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
|
||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
||||
|
||||
if (vsp1->ref_count == 0)
|
||||
return 0;
|
||||
|
||||
clk_prepare_enable(vsp1->clock);
|
||||
|
||||
pm_runtime_force_resume(vsp1->dev);
|
||||
vsp1_pipelines_resume(vsp1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vsp1_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
|
||||
rcar_fcp_disable(vsp1->fcp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsp1_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (vsp1->info) {
|
||||
ret = vsp1_device_init(vsp1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rcar_fcp_enable(vsp1->fcp);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops vsp1_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
|
||||
SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -559,7 +562,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
{
|
||||
.version = VI6_IP_VERSION_MODEL_VSPS_H2,
|
||||
.gen = 2,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
|
||||
| VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.uds_count = 3,
|
||||
.wpf_count = 4,
|
||||
|
@ -568,9 +572,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPR_H2,
|
||||
.gen = 2,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_SRU,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.uds_count = 1,
|
||||
.uds_count = 3,
|
||||
.wpf_count = 4,
|
||||
.num_bru_inputs = 4,
|
||||
.uapi = true,
|
||||
|
@ -580,22 +584,24 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
.features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
|
||||
.rpf_count = 4,
|
||||
.uds_count = 1,
|
||||
.wpf_count = 4,
|
||||
.wpf_count = 1,
|
||||
.num_bru_inputs = 4,
|
||||
.uapi = true,
|
||||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPS_M2,
|
||||
.gen = 2,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
|
||||
| VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.uds_count = 3,
|
||||
.uds_count = 1,
|
||||
.wpf_count = 4,
|
||||
.num_bru_inputs = 4,
|
||||
.uapi = true,
|
||||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
|
||||
.gen = 3,
|
||||
.features = VSP1_HAS_LUT | VSP1_HAS_SRU,
|
||||
.features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU
|
||||
| VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 1,
|
||||
.uds_count = 1,
|
||||
.wpf_count = 1,
|
||||
|
@ -603,7 +609,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
|
||||
.gen = 3,
|
||||
.features = VSP1_HAS_BRU,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.wpf_count = 1,
|
||||
.num_bru_inputs = 5,
|
||||
|
@ -611,7 +617,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
|
||||
.gen = 3,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_LUT,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
|
||||
| VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.wpf_count = 1,
|
||||
.num_bru_inputs = 5,
|
||||
|
@ -619,7 +626,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
}, {
|
||||
.version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
|
||||
.gen = 3,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_LIF,
|
||||
.features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP,
|
||||
.rpf_count = 5,
|
||||
.wpf_count = 2,
|
||||
.num_bru_inputs = 5,
|
||||
|
@ -629,6 +636,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
|
|||
static int vsp1_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vsp1_device *vsp1;
|
||||
struct device_node *fcp_node;
|
||||
struct resource *irq;
|
||||
struct resource *io;
|
||||
unsigned int i;
|
||||
|
@ -640,22 +648,17 @@ static int vsp1_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
vsp1->dev = &pdev->dev;
|
||||
mutex_init(&vsp1->lock);
|
||||
INIT_LIST_HEAD(&vsp1->entities);
|
||||
INIT_LIST_HEAD(&vsp1->videos);
|
||||
|
||||
/* I/O, IRQ and clock resources */
|
||||
platform_set_drvdata(pdev, vsp1);
|
||||
|
||||
/* I/O and IRQ resources (clock managed by the clock PM domain) */
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
||||
if (IS_ERR(vsp1->mmio))
|
||||
return PTR_ERR(vsp1->mmio);
|
||||
|
||||
vsp1->clock = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(vsp1->clock)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
return PTR_ERR(vsp1->clock);
|
||||
}
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "missing IRQ\n");
|
||||
|
@ -669,13 +672,27 @@ static int vsp1_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* FCP (optional) */
|
||||
fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
|
||||
if (fcp_node) {
|
||||
vsp1->fcp = rcar_fcp_get(fcp_node);
|
||||
of_node_put(fcp_node);
|
||||
if (IS_ERR(vsp1->fcp)) {
|
||||
dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
|
||||
PTR_ERR(vsp1->fcp));
|
||||
return PTR_ERR(vsp1->fcp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure device parameters based on the version register. */
|
||||
ret = clk_prepare_enable(vsp1->clock);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto done;
|
||||
|
||||
version = vsp1_read(vsp1, VI6_IP_VERSION);
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
|
||||
if ((version & VI6_IP_VERSION_MODEL_MASK) ==
|
||||
|
@ -687,7 +704,8 @@ static int vsp1_probe(struct platform_device *pdev)
|
|||
|
||||
if (!vsp1->info) {
|
||||
dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
|
||||
return -ENXIO;
|
||||
ret = -ENXIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
|
||||
|
@ -696,12 +714,14 @@ static int vsp1_probe(struct platform_device *pdev)
|
|||
ret = vsp1_create_entities(vsp1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create entities\n");
|
||||
return ret;
|
||||
goto done;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, vsp1);
|
||||
done:
|
||||
if (ret)
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vsp1_remove(struct platform_device *pdev)
|
||||
|
@ -709,6 +729,9 @@ static int vsp1_remove(struct platform_device *pdev)
|
|||
struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
|
||||
|
||||
vsp1_destroy_entities(vsp1);
|
||||
rcar_fcp_put(vsp1->fcp);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
#include "vsp1_dl.h"
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
static inline struct vsp1_entity *
|
||||
media_entity_to_vsp1_entity(struct media_entity *entity)
|
||||
{
|
||||
return container_of(entity, struct vsp1_entity, subdev.entity);
|
||||
}
|
||||
|
||||
void vsp1_entity_route_setup(struct vsp1_entity *source,
|
||||
struct vsp1_dl_list *dl)
|
||||
{
|
||||
|
@ -30,7 +36,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *source,
|
|||
if (source->route->reg == 0)
|
||||
return;
|
||||
|
||||
sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
|
||||
sink = media_entity_to_vsp1_entity(source->sink);
|
||||
vsp1_dl_list_write(dl, source->route->reg,
|
||||
sink->route->inputs[source->sink_pad]);
|
||||
}
|
||||
|
@ -81,12 +87,30 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
|
|||
return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
|
||||
* @entity: the entity
|
||||
* @cfg: the configuration storage
|
||||
* @pad: the pad number
|
||||
* @target: the selection target
|
||||
*
|
||||
* Return the selection rectangle stored in the given configuration for an
|
||||
* entity's pad. The configuration can be an ACTIVE or TRY configuration. The
|
||||
* selection target can be COMPOSE or CROP.
|
||||
*/
|
||||
struct v4l2_rect *
|
||||
vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
unsigned int pad)
|
||||
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
unsigned int pad, unsigned int target)
|
||||
{
|
||||
return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
|
||||
switch (target) {
|
||||
case V4L2_SEL_TGT_COMPOSE:
|
||||
return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,7 +276,7 @@ int vsp1_entity_link_setup(struct media_entity *entity,
|
|||
if (!(local->flags & MEDIA_PAD_FL_SOURCE))
|
||||
return 0;
|
||||
|
||||
source = container_of(local->entity, struct vsp1_entity, subdev.entity);
|
||||
source = media_entity_to_vsp1_entity(local->entity);
|
||||
|
||||
if (!source->route)
|
||||
return 0;
|
||||
|
@ -274,33 +298,50 @@ int vsp1_entity_link_setup(struct media_entity *entity,
|
|||
* Initialization
|
||||
*/
|
||||
|
||||
#define VSP1_ENTITY_ROUTE(ent) \
|
||||
{ VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE, \
|
||||
{ VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent }
|
||||
|
||||
#define VSP1_ENTITY_ROUTE_RPF(idx) \
|
||||
{ VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx), \
|
||||
{ 0, }, VI6_DPR_NODE_RPF(idx) }
|
||||
|
||||
#define VSP1_ENTITY_ROUTE_UDS(idx) \
|
||||
{ VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx), \
|
||||
{ VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) }
|
||||
|
||||
#define VSP1_ENTITY_ROUTE_WPF(idx) \
|
||||
{ VSP1_ENTITY_WPF, idx, 0, \
|
||||
{ VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) }
|
||||
|
||||
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),
|
||||
VI6_DPR_NODE_BRU_IN(4) } },
|
||||
{ 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), { 0, } },
|
||||
{ VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } },
|
||||
{ VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } },
|
||||
{ VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } },
|
||||
{ VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } },
|
||||
{ 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), } },
|
||||
VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT },
|
||||
VSP1_ENTITY_ROUTE(CLU),
|
||||
VSP1_ENTITY_ROUTE(HSI),
|
||||
VSP1_ENTITY_ROUTE(HST),
|
||||
{ VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF },
|
||||
VSP1_ENTITY_ROUTE(LUT),
|
||||
VSP1_ENTITY_ROUTE_RPF(0),
|
||||
VSP1_ENTITY_ROUTE_RPF(1),
|
||||
VSP1_ENTITY_ROUTE_RPF(2),
|
||||
VSP1_ENTITY_ROUTE_RPF(3),
|
||||
VSP1_ENTITY_ROUTE_RPF(4),
|
||||
VSP1_ENTITY_ROUTE(SRU),
|
||||
VSP1_ENTITY_ROUTE_UDS(0),
|
||||
VSP1_ENTITY_ROUTE_UDS(1),
|
||||
VSP1_ENTITY_ROUTE_UDS(2),
|
||||
VSP1_ENTITY_ROUTE_WPF(0),
|
||||
VSP1_ENTITY_ROUTE_WPF(1),
|
||||
VSP1_ENTITY_ROUTE_WPF(2),
|
||||
VSP1_ENTITY_ROUTE_WPF(3),
|
||||
};
|
||||
|
||||
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
||||
const char *name, unsigned int num_pads,
|
||||
const struct v4l2_subdev_ops *ops)
|
||||
const struct v4l2_subdev_ops *ops, u32 function)
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
unsigned int i;
|
||||
|
@ -341,6 +382,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
|||
subdev = &entity->subdev;
|
||||
v4l2_subdev_init(subdev, ops);
|
||||
|
||||
subdev->entity.function = function;
|
||||
subdev->entity.ops = &vsp1->media_ops;
|
||||
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ struct vsp1_pipeline;
|
|||
|
||||
enum vsp1_entity_type {
|
||||
VSP1_ENTITY_BRU,
|
||||
VSP1_ENTITY_CLU,
|
||||
VSP1_ENTITY_HSI,
|
||||
VSP1_ENTITY_HST,
|
||||
VSP1_ENTITY_LIF,
|
||||
|
@ -42,17 +43,21 @@ enum vsp1_entity_type {
|
|||
* @index: Entity index this routing entry is associated with
|
||||
* @reg: Output routing configuration register
|
||||
* @inputs: Target node value for each input
|
||||
* @output: Target node value for entity output
|
||||
*
|
||||
* 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.
|
||||
* store the target node value for each input of the entity. The @output field
|
||||
* stores the target node value of the entity output when used as a source for
|
||||
* histogram generation.
|
||||
*/
|
||||
struct vsp1_route {
|
||||
enum vsp1_entity_type type;
|
||||
unsigned int index;
|
||||
unsigned int reg;
|
||||
unsigned int inputs[VSP1_ENTITY_MAX_INPUTS];
|
||||
unsigned int output;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -68,7 +73,7 @@ struct vsp1_entity_operations {
|
|||
void (*destroy)(struct vsp1_entity *);
|
||||
void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl);
|
||||
void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *,
|
||||
struct vsp1_dl_list *);
|
||||
struct vsp1_dl_list *, bool);
|
||||
};
|
||||
|
||||
struct vsp1_entity {
|
||||
|
@ -100,7 +105,7 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
|
|||
|
||||
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
||||
const char *name, unsigned int num_pads,
|
||||
const struct v4l2_subdev_ops *ops);
|
||||
const struct v4l2_subdev_ops *ops, u32 function);
|
||||
void vsp1_entity_destroy(struct vsp1_entity *entity);
|
||||
|
||||
extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
|
||||
|
@ -118,9 +123,9 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
|
|||
struct v4l2_subdev_pad_config *cfg,
|
||||
unsigned int pad);
|
||||
struct v4l2_rect *
|
||||
vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
unsigned int pad);
|
||||
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
unsigned int pad, unsigned int target);
|
||||
int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_pad_config *cfg);
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops hsit_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = hsit_enum_mbus_code,
|
||||
.enum_frame_size = hsit_enum_frame_size,
|
||||
|
@ -115,7 +115,7 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = {
|
|||
.set_fmt = hsit_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops hsit_ops = {
|
||||
static const struct v4l2_subdev_ops hsit_ops = {
|
||||
.pad = &hsit_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -125,10 +125,13 @@ static struct v4l2_subdev_ops hsit_ops = {
|
|||
|
||||
static void hsit_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
|
||||
|
||||
if (!full)
|
||||
return;
|
||||
|
||||
if (hsit->inverse)
|
||||
vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
|
||||
else
|
||||
|
@ -161,8 +164,9 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
|
|||
else
|
||||
hsit->entity.type = VSP1_ENTITY_HST;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2,
|
||||
&hsit_ops);
|
||||
ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst",
|
||||
2, &hsit_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ static int lif_set_format(struct v4l2_subdev *subdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops lif_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops lif_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = lif_enum_mbus_code,
|
||||
.enum_frame_size = lif_enum_frame_size,
|
||||
|
@ -112,7 +112,7 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = {
|
|||
.set_fmt = lif_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops lif_ops = {
|
||||
static const struct v4l2_subdev_ops lif_ops = {
|
||||
.pad = &lif_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -122,7 +122,7 @@ static struct v4l2_subdev_ops lif_ops = {
|
|||
|
||||
static void lif_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct vsp1_lif *lif = to_lif(&entity->subdev);
|
||||
|
@ -130,6 +130,9 @@ static void lif_configure(struct vsp1_entity *entity,
|
|||
unsigned int obth = 400;
|
||||
unsigned int lbth = 200;
|
||||
|
||||
if (!full)
|
||||
return;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
|
||||
LIF_PAD_SOURCE);
|
||||
|
||||
|
@ -165,7 +168,12 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
|
|||
lif->entity.ops = &lif_entity_ops;
|
||||
lif->entity.type = VSP1_ENTITY_LIF;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
|
||||
/* The LIF is never exposed to userspace, but media entity registration
|
||||
* requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to
|
||||
* avoid triggering a WARN_ON(), the value won't be seen anywhere.
|
||||
*/
|
||||
ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/vsp1.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
|
@ -35,43 +34,62 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl,
|
|||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
* Controls
|
||||
*/
|
||||
|
||||
static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config)
|
||||
#define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001)
|
||||
|
||||
static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vsp1_dl_body *dlb;
|
||||
unsigned int i;
|
||||
|
||||
dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut));
|
||||
dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, 256);
|
||||
if (!dlb)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(config->lut); ++i)
|
||||
for (i = 0; i < 256; ++i)
|
||||
vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i,
|
||||
config->lut[i]);
|
||||
ctrl->p_new.p_u32[i]);
|
||||
|
||||
mutex_lock(&lut->lock);
|
||||
spin_lock_irq(&lut->lock);
|
||||
swap(lut->lut, dlb);
|
||||
mutex_unlock(&lut->lock);
|
||||
spin_unlock_irq(&lut->lock);
|
||||
|
||||
vsp1_dl_fragment_free(dlb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
|
||||
static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vsp1_lut *lut = to_lut(subdev);
|
||||
struct vsp1_lut *lut =
|
||||
container_of(ctrl->handler, struct vsp1_lut, ctrls);
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_VSP1_LUT_CONFIG:
|
||||
return lut_set_table(lut, arg);
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_VSP1_LUT_TABLE:
|
||||
lut_set_table(lut, ctrl);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops lut_ctrl_ops = {
|
||||
.s_ctrl = lut_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_config lut_table_control = {
|
||||
.ops = &lut_ctrl_ops,
|
||||
.id = V4L2_CID_VSP1_LUT_TABLE,
|
||||
.name = "Look-Up Table",
|
||||
.type = V4L2_CTRL_TYPE_U32,
|
||||
.min = 0x00000000,
|
||||
.max = 0x00ffffff,
|
||||
.step = 1,
|
||||
.def = 0,
|
||||
.dims = { 256},
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
@ -147,11 +165,7 @@ static int lut_set_format(struct v4l2_subdev *subdev,
|
|||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_core_ops lut_core_ops = {
|
||||
.ioctl = lut_ioctl,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops lut_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops lut_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = lut_enum_mbus_code,
|
||||
.enum_frame_size = lut_enum_frame_size,
|
||||
|
@ -159,8 +173,7 @@ static struct v4l2_subdev_pad_ops lut_pad_ops = {
|
|||
.set_fmt = lut_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops lut_ops = {
|
||||
.core = &lut_core_ops,
|
||||
static const struct v4l2_subdev_ops lut_ops = {
|
||||
.pad = &lut_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -170,18 +183,24 @@ static struct v4l2_subdev_ops lut_ops = {
|
|||
|
||||
static void lut_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_lut *lut = to_lut(&entity->subdev);
|
||||
struct vsp1_dl_body *dlb;
|
||||
unsigned long flags;
|
||||
|
||||
vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
|
||||
|
||||
mutex_lock(&lut->lock);
|
||||
if (lut->lut) {
|
||||
vsp1_dl_list_add_fragment(dl, lut->lut);
|
||||
lut->lut = NULL;
|
||||
if (full) {
|
||||
vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&lut->lock);
|
||||
|
||||
spin_lock_irqsave(&lut->lock, flags);
|
||||
dlb = lut->lut;
|
||||
lut->lut = NULL;
|
||||
spin_unlock_irqrestore(&lut->lock, flags);
|
||||
|
||||
if (dlb)
|
||||
vsp1_dl_list_add_fragment(dl, dlb);
|
||||
}
|
||||
|
||||
static const struct vsp1_entity_operations lut_entity_ops = {
|
||||
|
@ -201,12 +220,30 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
|
|||
if (lut == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_init(&lut->lock);
|
||||
|
||||
lut->entity.ops = &lut_entity_ops;
|
||||
lut->entity.type = VSP1_ENTITY_LUT;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
|
||||
ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_LUT);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the control handler. */
|
||||
v4l2_ctrl_handler_init(&lut->ctrls, 1);
|
||||
v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
|
||||
|
||||
lut->entity.subdev.ctrl_handler = &lut->ctrls;
|
||||
|
||||
if (lut->ctrls.error) {
|
||||
dev_err(vsp1->dev, "lut: failed to initialize controls\n");
|
||||
ret = lut->ctrls.error;
|
||||
vsp1_entity_destroy(&lut->entity);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_setup(&lut->ctrls);
|
||||
|
||||
return lut;
|
||||
}
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
#ifndef __VSP1_LUT_H__
|
||||
#define __VSP1_LUT_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_entity.h"
|
||||
|
@ -28,7 +29,9 @@ struct vsp1_device;
|
|||
struct vsp1_lut {
|
||||
struct vsp1_entity entity;
|
||||
|
||||
struct mutex lock;
|
||||
struct v4l2_ctrl_handler ctrls;
|
||||
|
||||
spinlock_t lock;
|
||||
struct vsp1_dl_body *lut;
|
||||
};
|
||||
|
||||
|
|
|
@ -172,13 +172,17 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
|
|||
bru->inputs[i].rpf = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < pipe->num_inputs; ++i) {
|
||||
pipe->inputs[i]->pipe = NULL;
|
||||
pipe->inputs[i] = NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
|
||||
if (pipe->inputs[i]) {
|
||||
pipe->inputs[i]->pipe = NULL;
|
||||
pipe->inputs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pipe->output->pipe = NULL;
|
||||
pipe->output = NULL;
|
||||
if (pipe->output) {
|
||||
pipe->output->pipe = NULL;
|
||||
pipe->output = NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&pipe->entities);
|
||||
pipe->state = VSP1_PIPELINE_STOPPED;
|
||||
|
@ -286,6 +290,8 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
|
|||
|
||||
if (pipe->frame_end)
|
||||
pipe->frame_end(pipe);
|
||||
|
||||
pipe->sequence++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -295,42 +301,20 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
|
|||
* to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
|
||||
* value. The UDS then outputs a fixed alpha value which needs to be programmed
|
||||
* from the input RPF alpha.
|
||||
*
|
||||
* This function can only be called from a subdev s_stream handler as it
|
||||
* requires a valid display list context.
|
||||
*/
|
||||
void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
|
||||
struct vsp1_entity *input,
|
||||
struct vsp1_dl_list *dl,
|
||||
unsigned int alpha)
|
||||
struct vsp1_dl_list *dl, unsigned int alpha)
|
||||
{
|
||||
struct vsp1_entity *entity;
|
||||
struct media_pad *pad;
|
||||
if (!pipe->uds)
|
||||
return;
|
||||
|
||||
pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]);
|
||||
/* The BRU background color has a fixed alpha value set to 255, the
|
||||
* output alpha value is thus always equal to 255.
|
||||
*/
|
||||
if (pipe->uds_input->type == VSP1_ENTITY_BRU)
|
||||
alpha = 255;
|
||||
|
||||
while (pad) {
|
||||
if (!is_media_entity_v4l2_subdev(pad->entity))
|
||||
break;
|
||||
|
||||
entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
|
||||
|
||||
/* The BRU background color has a fixed alpha value set to 255,
|
||||
* the output alpha value is thus always equal to 255.
|
||||
*/
|
||||
if (entity->type == VSP1_ENTITY_BRU)
|
||||
alpha = 255;
|
||||
|
||||
if (entity->type == VSP1_ENTITY_UDS) {
|
||||
struct vsp1_uds *uds = to_uds(&entity->subdev);
|
||||
|
||||
vsp1_uds_set_alpha(uds, dl, alpha);
|
||||
break;
|
||||
}
|
||||
|
||||
pad = &entity->pads[entity->source_pad];
|
||||
pad = media_entity_remote_pad(pad);
|
||||
}
|
||||
vsp1_uds_set_alpha(pipe->uds, dl, alpha);
|
||||
}
|
||||
|
||||
void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
|
||||
|
@ -383,7 +367,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Resume pipeline all running pipelines. */
|
||||
/* Resume all running pipelines. */
|
||||
for (i = 0; i < vsp1->info->wpf_count; ++i) {
|
||||
struct vsp1_rwpf *wpf = vsp1->wpf[i];
|
||||
struct vsp1_pipeline *pipe;
|
||||
|
|
|
@ -61,12 +61,13 @@ enum vsp1_pipeline_state {
|
|||
* @pipe: the media pipeline
|
||||
* @irqlock: protects the pipeline state
|
||||
* @state: current state
|
||||
* @wq: work queue to wait for state change completion
|
||||
* @wq: wait queue to wait for state change completion
|
||||
* @frame_end: frame end interrupt handler
|
||||
* @lock: protects the pipeline use count and stream count
|
||||
* @kref: pipeline reference count
|
||||
* @stream_count: number of streaming video nodes
|
||||
* @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available
|
||||
* @sequence: frame sequence number
|
||||
* @num_inputs: number of RPFs
|
||||
* @inputs: array of RPFs in the pipeline (indexed by RPF index)
|
||||
* @output: WPF at the output of the pipeline
|
||||
|
@ -90,6 +91,7 @@ struct vsp1_pipeline {
|
|||
struct kref kref;
|
||||
unsigned int stream_count;
|
||||
unsigned int buffers_ready;
|
||||
unsigned int sequence;
|
||||
|
||||
unsigned int num_inputs;
|
||||
struct vsp1_rwpf *inputs[VSP1_MAX_RPF];
|
||||
|
@ -115,9 +117,7 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
|
|||
void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
|
||||
|
||||
void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
|
||||
struct vsp1_entity *input,
|
||||
struct vsp1_dl_list *dl,
|
||||
unsigned int alpha);
|
||||
struct vsp1_dl_list *dl, unsigned int alpha);
|
||||
|
||||
void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
|
||||
void vsp1_pipelines_resume(struct vsp1_device *vsp1);
|
||||
|
|
|
@ -154,10 +154,10 @@
|
|||
#define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_MASK (3 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 8)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 8
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 0)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 0
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 8)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 8
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 0)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 0
|
||||
|
||||
#define VI6_RPF_VRTCOL_SET 0x0318
|
||||
#define VI6_RPF_VRTCOL_SET_LAYA_MASK (0xff << 24)
|
||||
|
@ -255,6 +255,8 @@
|
|||
#define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24)
|
||||
#define VI6_WPF_OUTFMT_PDV_SHIFT 24
|
||||
#define VI6_WPF_OUTFMT_PXA (1 << 23)
|
||||
#define VI6_WPF_OUTFMT_ROT (1 << 18)
|
||||
#define VI6_WPF_OUTFMT_HFLP (1 << 17)
|
||||
#define VI6_WPF_OUTFMT_FLP (1 << 16)
|
||||
#define VI6_WPF_OUTFMT_SPYCS (1 << 15)
|
||||
#define VI6_WPF_OUTFMT_SPUVS (1 << 14)
|
||||
|
@ -289,6 +291,11 @@
|
|||
#define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12)
|
||||
#define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12)
|
||||
|
||||
#define VI6_WPF_ROT_CTRL 0x1018
|
||||
#define VI6_WPF_ROT_CTRL_LN16 (1 << 17)
|
||||
#define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0)
|
||||
#define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0
|
||||
|
||||
#define VI6_WPF_DSTM_STRIDE_Y 0x101c
|
||||
#define VI6_WPF_DSTM_STRIDE_C 0x1020
|
||||
#define VI6_WPF_DSTM_ADDR_Y 0x1024
|
||||
|
@ -444,6 +451,15 @@
|
|||
*/
|
||||
|
||||
#define VI6_CLU_CTRL 0x2900
|
||||
#define VI6_CLU_CTRL_AAI (1 << 28)
|
||||
#define VI6_CLU_CTRL_MVS (1 << 24)
|
||||
#define VI6_CLU_CTRL_AX1I_2D (3 << 14)
|
||||
#define VI6_CLU_CTRL_AX2I_2D (1 << 12)
|
||||
#define VI6_CLU_CTRL_OS0_2D (3 << 8)
|
||||
#define VI6_CLU_CTRL_OS1_2D (1 << 6)
|
||||
#define VI6_CLU_CTRL_OS2_2D (3 << 4)
|
||||
#define VI6_CLU_CTRL_M2D (1 << 1)
|
||||
#define VI6_CLU_CTRL_EN (1 << 0)
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HST Control Registers
|
||||
|
|
|
@ -38,7 +38,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
|
|||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_ops rpf_ops = {
|
||||
static const struct v4l2_subdev_ops rpf_ops = {
|
||||
.pad = &vsp1_rwpf_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -60,7 +60,7 @@ static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
|
|||
|
||||
static void rpf_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
|
||||
const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
|
||||
|
@ -73,6 +73,16 @@ static void rpf_configure(struct vsp1_entity *entity,
|
|||
u32 pstride;
|
||||
u32 infmt;
|
||||
|
||||
if (!full) {
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
|
||||
rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, rpf->mult_alpha |
|
||||
(rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT));
|
||||
|
||||
vsp1_pipeline_propagate_alpha(pipe, dl, rpf->alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Source size, stride and crop offsets.
|
||||
*
|
||||
* The crop offsets correspond to the location of the crop rectangle top
|
||||
|
@ -130,9 +140,10 @@ static void rpf_configure(struct vsp1_entity *entity,
|
|||
if (pipe->bru) {
|
||||
const struct v4l2_rect *compose;
|
||||
|
||||
compose = vsp1_entity_get_pad_compose(pipe->bru,
|
||||
pipe->bru->config,
|
||||
rpf->bru_input);
|
||||
compose = vsp1_entity_get_pad_selection(pipe->bru,
|
||||
pipe->bru->config,
|
||||
rpf->bru_input,
|
||||
V4L2_SEL_TGT_COMPOSE);
|
||||
left = compose->left;
|
||||
top = compose->top;
|
||||
}
|
||||
|
@ -167,9 +178,6 @@ static void rpf_configure(struct vsp1_entity *entity,
|
|||
(fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
|
||||
: VI6_RPF_ALPH_SEL_ASEL_FIXED));
|
||||
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
|
||||
rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
|
||||
|
||||
if (entity->vsp1->info->gen == 3) {
|
||||
u32 mult;
|
||||
|
||||
|
@ -187,8 +195,7 @@ static void rpf_configure(struct vsp1_entity *entity,
|
|||
mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO
|
||||
| (premultiplied ?
|
||||
VI6_RPF_MULT_ALPHA_P_MMD_RATIO :
|
||||
VI6_RPF_MULT_ALPHA_P_MMD_NONE)
|
||||
| (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT);
|
||||
VI6_RPF_MULT_ALPHA_P_MMD_NONE);
|
||||
} else {
|
||||
/* When the input doesn't contain an alpha channel the
|
||||
* global alpha value is applied in the unpacking unit,
|
||||
|
@ -199,11 +206,9 @@ static void rpf_configure(struct vsp1_entity *entity,
|
|||
| VI6_RPF_MULT_ALPHA_P_MMD_NONE;
|
||||
}
|
||||
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult);
|
||||
rpf->mult_alpha = mult;
|
||||
}
|
||||
|
||||
vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha);
|
||||
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0);
|
||||
vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0);
|
||||
|
||||
|
@ -236,18 +241,21 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
|
|||
rpf->entity.index = index;
|
||||
|
||||
sprintf(name, "rpf.%u", index);
|
||||
ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
|
||||
ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the control handler. */
|
||||
ret = vsp1_rwpf_init_ctrls(rpf);
|
||||
ret = vsp1_rwpf_init_ctrls(rpf, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
|
||||
index);
|
||||
goto error;
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_setup(&rpf->ctrls);
|
||||
|
||||
return rpf;
|
||||
|
||||
error:
|
||||
|
|
|
@ -241,11 +241,9 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
|
|||
.s_ctrl = vsp1_rwpf_s_ctrl,
|
||||
};
|
||||
|
||||
int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
|
||||
int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)
|
||||
{
|
||||
rwpf->alpha = 255;
|
||||
|
||||
v4l2_ctrl_handler_init(&rwpf->ctrls, 1);
|
||||
v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);
|
||||
v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
|
||||
V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#ifndef __VSP1_RWPF_H__
|
||||
#define __VSP1_RWPF_H__
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
@ -49,6 +51,16 @@ struct vsp1_rwpf {
|
|||
|
||||
unsigned int alpha;
|
||||
|
||||
u32 mult_alpha;
|
||||
u32 outfmt;
|
||||
|
||||
struct {
|
||||
spinlock_t lock;
|
||||
struct v4l2_ctrl *ctrls[2];
|
||||
unsigned int pending;
|
||||
unsigned int active;
|
||||
} flip;
|
||||
|
||||
unsigned int offsets[2];
|
||||
struct vsp1_rwpf_memory mem;
|
||||
|
||||
|
@ -68,7 +80,7 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
|
|||
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
|
||||
int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
|
||||
int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
|
||||
|
||||
extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl,
|
|||
* Controls
|
||||
*/
|
||||
|
||||
#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1)
|
||||
#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE | 0x1001)
|
||||
|
||||
struct vsp1_sru_param {
|
||||
u32 ctrl0;
|
||||
|
@ -239,7 +239,7 @@ static int sru_set_format(struct v4l2_subdev *subdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops sru_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops sru_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = sru_enum_mbus_code,
|
||||
.enum_frame_size = sru_enum_frame_size,
|
||||
|
@ -247,7 +247,7 @@ static struct v4l2_subdev_pad_ops sru_pad_ops = {
|
|||
.set_fmt = sru_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops sru_ops = {
|
||||
static const struct v4l2_subdev_ops sru_ops = {
|
||||
.pad = &sru_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -257,7 +257,7 @@ static struct v4l2_subdev_ops sru_ops = {
|
|||
|
||||
static void sru_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
const struct vsp1_sru_param *param;
|
||||
struct vsp1_sru *sru = to_sru(&entity->subdev);
|
||||
|
@ -265,6 +265,9 @@ static void sru_configure(struct vsp1_entity *entity,
|
|||
struct v4l2_mbus_framefmt *output;
|
||||
u32 ctrl0;
|
||||
|
||||
if (!full)
|
||||
return;
|
||||
|
||||
input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
|
||||
SRU_PAD_SINK);
|
||||
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
|
||||
|
@ -308,7 +311,8 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
|
|||
sru->entity.ops = &sru_entity_ops;
|
||||
sru->entity.type = VSP1_ENTITY_SRU;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
|
||||
ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_SCALER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
|
@ -40,9 +40,11 @@ static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
|
|||
* Scaling Computation
|
||||
*/
|
||||
|
||||
void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
|
||||
void vsp1_uds_set_alpha(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
|
||||
unsigned int alpha)
|
||||
{
|
||||
struct vsp1_uds *uds = to_uds(&entity->subdev);
|
||||
|
||||
vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL,
|
||||
alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
|
||||
}
|
||||
|
@ -226,7 +228,7 @@ static int uds_set_format(struct v4l2_subdev *subdev,
|
|||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_pad_ops uds_pad_ops = {
|
||||
static const struct v4l2_subdev_pad_ops uds_pad_ops = {
|
||||
.init_cfg = vsp1_entity_init_cfg,
|
||||
.enum_mbus_code = uds_enum_mbus_code,
|
||||
.enum_frame_size = uds_enum_frame_size,
|
||||
|
@ -234,7 +236,7 @@ static struct v4l2_subdev_pad_ops uds_pad_ops = {
|
|||
.set_fmt = uds_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops uds_ops = {
|
||||
static const struct v4l2_subdev_ops uds_ops = {
|
||||
.pad = &uds_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -244,7 +246,7 @@ static struct v4l2_subdev_ops uds_ops = {
|
|||
|
||||
static void uds_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_uds *uds = to_uds(&entity->subdev);
|
||||
const struct v4l2_mbus_framefmt *output;
|
||||
|
@ -253,6 +255,9 @@ static void uds_configure(struct vsp1_entity *entity,
|
|||
unsigned int vscale;
|
||||
bool multitap;
|
||||
|
||||
if (!full)
|
||||
return;
|
||||
|
||||
input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
|
||||
UDS_PAD_SINK);
|
||||
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
|
||||
|
@ -314,7 +319,8 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
|
|||
uds->entity.index = index;
|
||||
|
||||
sprintf(name, "uds.%u", index);
|
||||
ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops);
|
||||
ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_SCALER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
|
|||
|
||||
struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
|
||||
void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
|
||||
void vsp1_uds_set_alpha(struct vsp1_entity *uds, struct vsp1_dl_list *dl,
|
||||
unsigned int alpha);
|
||||
|
||||
#endif /* __VSP1_UDS_H__ */
|
||||
|
|
|
@ -219,7 +219,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
|
|||
|
||||
spin_unlock_irqrestore(&video->irqlock, flags);
|
||||
|
||||
done->buf.sequence = video->sequence++;
|
||||
done->buf.sequence = pipe->sequence;
|
||||
done->buf.vb2_buf.timestamp = ktime_get_ns();
|
||||
for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
|
||||
vb2_set_plane_payload(&done->buf.vb2_buf, i,
|
||||
|
@ -251,11 +251,17 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
|
|||
static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
|
||||
{
|
||||
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
|
||||
struct vsp1_entity *entity;
|
||||
unsigned int i;
|
||||
|
||||
if (!pipe->dl)
|
||||
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
|
||||
|
||||
list_for_each_entry(entity, &pipe->entities, list_pipe) {
|
||||
if (entity->ops->configure)
|
||||
entity->ops->configure(entity, pipe, pipe->dl, false);
|
||||
}
|
||||
|
||||
for (i = 0; i < vsp1->info->rpf_count; ++i) {
|
||||
struct vsp1_rwpf *rwpf = pipe->inputs[i];
|
||||
|
||||
|
@ -628,7 +634,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
|
|||
vsp1_entity_route_setup(entity, pipe->dl);
|
||||
|
||||
if (entity->ops->configure)
|
||||
entity->ops->configure(entity, pipe, pipe->dl);
|
||||
entity->ops->configure(entity, pipe, pipe->dl, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -670,7 +676,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
|
|||
int ret;
|
||||
|
||||
mutex_lock(&pipe->lock);
|
||||
if (--pipe->stream_count == 0) {
|
||||
if (--pipe->stream_count == pipe->num_inputs) {
|
||||
/* Stop the pipeline. */
|
||||
ret = vsp1_pipeline_stop(pipe);
|
||||
if (ret == -ETIMEDOUT)
|
||||
|
@ -692,7 +698,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
|
|||
spin_unlock_irqrestore(&video->irqlock, flags);
|
||||
}
|
||||
|
||||
static struct vb2_ops vsp1_video_queue_qops = {
|
||||
static const struct vb2_ops vsp1_video_queue_qops = {
|
||||
.queue_setup = vsp1_video_queue_setup,
|
||||
.buf_prepare = vsp1_video_buffer_prepare,
|
||||
.buf_queue = vsp1_video_buffer_queue,
|
||||
|
@ -801,8 +807,6 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
|
|||
if (video->queue.owner && video->queue.owner != file->private_data)
|
||||
return -EBUSY;
|
||||
|
||||
video->sequence = 0;
|
||||
|
||||
/* Get a pipeline for the video node and start streaming on it. No link
|
||||
* touching an entity in the pipeline can be activated or deactivated
|
||||
* once streaming is started.
|
||||
|
@ -911,7 +915,7 @@ static int vsp1_video_release(struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_file_operations vsp1_video_fops = {
|
||||
static const struct v4l2_file_operations vsp1_video_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.open = vsp1_video_open,
|
||||
|
|
|
@ -48,7 +48,6 @@ struct vsp1_video {
|
|||
struct vb2_queue queue;
|
||||
spinlock_t irqlock;
|
||||
struct list_head irqqueue;
|
||||
unsigned int sequence;
|
||||
};
|
||||
|
||||
static inline struct vsp1_video *to_vsp1_video(struct video_device *vdev)
|
||||
|
|
|
@ -36,6 +36,97 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
|
|||
vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Controls
|
||||
*/
|
||||
|
||||
enum wpf_flip_ctrl {
|
||||
WPF_CTRL_VFLIP = 0,
|
||||
WPF_CTRL_HFLIP = 1,
|
||||
WPF_CTRL_MAX,
|
||||
};
|
||||
|
||||
static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vsp1_rwpf *wpf =
|
||||
container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
|
||||
unsigned int i;
|
||||
u32 flip = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_HFLIP:
|
||||
case V4L2_CID_VFLIP:
|
||||
for (i = 0; i < WPF_CTRL_MAX; ++i) {
|
||||
if (wpf->flip.ctrls[i])
|
||||
flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0;
|
||||
}
|
||||
|
||||
spin_lock_irq(&wpf->flip.lock);
|
||||
wpf->flip.pending = flip;
|
||||
spin_unlock_irq(&wpf->flip.lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = {
|
||||
.s_ctrl = vsp1_wpf_s_ctrl,
|
||||
};
|
||||
|
||||
static int wpf_init_controls(struct vsp1_rwpf *wpf)
|
||||
{
|
||||
struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
||||
unsigned int num_flip_ctrls;
|
||||
|
||||
spin_lock_init(&wpf->flip.lock);
|
||||
|
||||
if (wpf->entity.index != 0) {
|
||||
/* Only WPF0 supports flipping. */
|
||||
num_flip_ctrls = 0;
|
||||
} else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) {
|
||||
/* When horizontal flip is supported the WPF implements two
|
||||
* controls (horizontal flip and vertical flip).
|
||||
*/
|
||||
num_flip_ctrls = 2;
|
||||
} else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) {
|
||||
/* When only vertical flip is supported the WPF implements a
|
||||
* single control (vertical flip).
|
||||
*/
|
||||
num_flip_ctrls = 1;
|
||||
} else {
|
||||
/* Otherwise flipping is not supported. */
|
||||
num_flip_ctrls = 0;
|
||||
}
|
||||
|
||||
vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);
|
||||
|
||||
if (num_flip_ctrls >= 1) {
|
||||
wpf->flip.ctrls[WPF_CTRL_VFLIP] =
|
||||
v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
}
|
||||
|
||||
if (num_flip_ctrls == 2) {
|
||||
wpf->flip.ctrls[WPF_CTRL_HFLIP] =
|
||||
v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
|
||||
V4L2_CID_HFLIP, 0, 1, 1, 0);
|
||||
|
||||
v4l2_ctrl_cluster(2, wpf->flip.ctrls);
|
||||
}
|
||||
|
||||
if (wpf->ctrls.error) {
|
||||
dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
|
||||
wpf->entity.index);
|
||||
return wpf->ctrls.error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
*/
|
||||
|
@ -62,11 +153,11 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
|||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_video_ops wpf_video_ops = {
|
||||
static const struct v4l2_subdev_video_ops wpf_video_ops = {
|
||||
.s_stream = wpf_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops wpf_ops = {
|
||||
static const struct v4l2_subdev_ops wpf_ops = {
|
||||
.video = &wpf_video_ops,
|
||||
.pad = &vsp1_rwpf_pad_ops,
|
||||
};
|
||||
|
@ -85,15 +176,37 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
|
|||
static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
|
||||
{
|
||||
struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
|
||||
const struct v4l2_pix_format_mplane *format = &wpf->format;
|
||||
struct vsp1_rwpf_memory mem = wpf->mem;
|
||||
unsigned int flip = wpf->flip.active;
|
||||
unsigned int offset;
|
||||
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
|
||||
/* Update the memory offsets based on flipping configuration. The
|
||||
* destination addresses point to the locations where the VSP starts
|
||||
* writing to memory, which can be different corners of the image
|
||||
* depending on vertical flipping. Horizontal flipping is handled
|
||||
* through a line buffer and doesn't modify the start address.
|
||||
*/
|
||||
if (flip & BIT(WPF_CTRL_VFLIP)) {
|
||||
mem.addr[0] += (format->height - 1)
|
||||
* format->plane_fmt[0].bytesperline;
|
||||
|
||||
if (format->num_planes > 1) {
|
||||
offset = (format->height / wpf->fmtinfo->vsub - 1)
|
||||
* format->plane_fmt[1].bytesperline;
|
||||
mem.addr[1] += offset;
|
||||
mem.addr[2] += offset;
|
||||
}
|
||||
}
|
||||
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
|
||||
}
|
||||
|
||||
static void wpf_configure(struct vsp1_entity *entity,
|
||||
struct vsp1_pipeline *pipe,
|
||||
struct vsp1_dl_list *dl)
|
||||
struct vsp1_dl_list *dl, bool full)
|
||||
{
|
||||
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
|
||||
struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
||||
|
@ -104,6 +217,26 @@ static void wpf_configure(struct vsp1_entity *entity,
|
|||
u32 outfmt = 0;
|
||||
u32 srcrpf = 0;
|
||||
|
||||
if (!full) {
|
||||
const unsigned int mask = BIT(WPF_CTRL_VFLIP)
|
||||
| BIT(WPF_CTRL_HFLIP);
|
||||
|
||||
spin_lock(&wpf->flip.lock);
|
||||
wpf->flip.active = (wpf->flip.active & ~mask)
|
||||
| (wpf->flip.pending & mask);
|
||||
spin_unlock(&wpf->flip.lock);
|
||||
|
||||
outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
|
||||
|
||||
if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
|
||||
outfmt |= VI6_WPF_OUTFMT_FLP;
|
||||
if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
|
||||
outfmt |= VI6_WPF_OUTFMT_HFLP;
|
||||
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cropping */
|
||||
crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
|
||||
|
||||
|
@ -143,13 +276,18 @@ static void wpf_configure(struct vsp1_entity *entity,
|
|||
format->plane_fmt[1].bytesperline);
|
||||
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
|
||||
|
||||
if (vsp1->info->features & VSP1_HAS_WPF_HFLIP &&
|
||||
wpf->entity.index == 0)
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL,
|
||||
VI6_WPF_ROT_CTRL_LN16 |
|
||||
(256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
|
||||
}
|
||||
|
||||
if (sink_format->code != source_format->code)
|
||||
outfmt |= VI6_WPF_OUTFMT_CSC;
|
||||
|
||||
outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
|
||||
vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
|
||||
wpf->outfmt = outfmt;
|
||||
|
||||
vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
|
||||
VI6_DPR_WPF_FPORCH_FP_WPFN);
|
||||
|
@ -216,7 +354,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
|
|||
wpf->entity.index = index;
|
||||
|
||||
sprintf(name, "wpf.%u", index);
|
||||
ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops);
|
||||
ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops,
|
||||
MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
@ -228,13 +367,15 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
|
|||
}
|
||||
|
||||
/* Initialize the control handler. */
|
||||
ret = vsp1_rwpf_init_ctrls(wpf);
|
||||
ret = wpf_init_controls(wpf);
|
||||
if (ret < 0) {
|
||||
dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
|
||||
index);
|
||||
goto error;
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_setup(&wpf->ctrls);
|
||||
|
||||
return wpf;
|
||||
|
||||
error:
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* rcar-fcp.h -- R-Car Frame Compression Processor Driver
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Electronics 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 __MEDIA_RCAR_FCP_H__
|
||||
#define __MEDIA_RCAR_FCP_H__
|
||||
|
||||
struct device_node;
|
||||
struct rcar_fcp_device;
|
||||
|
||||
#if IS_ENABLED(CONFIG_VIDEO_RENESAS_FCP)
|
||||
struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np);
|
||||
void rcar_fcp_put(struct rcar_fcp_device *fcp);
|
||||
int rcar_fcp_enable(struct rcar_fcp_device *fcp);
|
||||
void rcar_fcp_disable(struct rcar_fcp_device *fcp);
|
||||
#else
|
||||
static inline struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline void rcar_fcp_put(struct rcar_fcp_device *fcp) { }
|
||||
static inline int rcar_fcp_enable(struct rcar_fcp_device *fcp)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline void rcar_fcp_disable(struct rcar_fcp_device *fcp) { }
|
||||
#endif
|
||||
|
||||
#endif /* __MEDIA_RCAR_FCP_H__ */
|
|
@ -14,31 +14,28 @@
|
|||
#define __MEDIA_VSP1_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
struct device;
|
||||
struct v4l2_rect;
|
||||
|
||||
int vsp1_du_init(struct device *dev);
|
||||
|
||||
int vsp1_du_setup_lif(struct device *dev, unsigned int width,
|
||||
unsigned int height);
|
||||
|
||||
struct vsp1_du_atomic_config {
|
||||
u32 pixelformat;
|
||||
unsigned int pitch;
|
||||
dma_addr_t mem[2];
|
||||
struct v4l2_rect src;
|
||||
struct v4l2_rect dst;
|
||||
unsigned int alpha;
|
||||
unsigned int zpos;
|
||||
};
|
||||
|
||||
void vsp1_du_atomic_begin(struct device *dev);
|
||||
int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf,
|
||||
u32 pixelformat, unsigned int pitch,
|
||||
dma_addr_t mem[2], const struct v4l2_rect *src,
|
||||
const struct v4l2_rect *dst, unsigned int alpha,
|
||||
unsigned int zpos);
|
||||
int vsp1_du_atomic_update(struct device *dev, unsigned int rpf,
|
||||
const struct vsp1_du_atomic_config *cfg);
|
||||
void vsp1_du_atomic_flush(struct device *dev);
|
||||
|
||||
static inline int vsp1_du_atomic_update(struct device *dev,
|
||||
unsigned int rpf_index, u32 pixelformat,
|
||||
unsigned int pitch, dma_addr_t mem[2],
|
||||
const struct v4l2_rect *src,
|
||||
const struct v4l2_rect *dst)
|
||||
{
|
||||
return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch,
|
||||
mem, src, dst, 255, 0);
|
||||
}
|
||||
|
||||
#endif /* __MEDIA_VSP1_H__ */
|
||||
|
|
|
@ -94,6 +94,16 @@ struct media_device_info {
|
|||
#define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002)
|
||||
#define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003)
|
||||
|
||||
/*
|
||||
* Processing entities
|
||||
*/
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001)
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002)
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003)
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004)
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005)
|
||||
#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006)
|
||||
|
||||
/*
|
||||
* Connectors
|
||||
*/
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* vsp1.h
|
||||
*
|
||||
* Renesas R-Car VSP1 - User-space API
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contacts: 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 version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __VSP1_USER_H__
|
||||
#define __VSP1_USER_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
/*
|
||||
* Private IOCTLs
|
||||
*
|
||||
* VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table
|
||||
*/
|
||||
|
||||
#define VIDIOC_VSP1_LUT_CONFIG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config)
|
||||
|
||||
struct vsp1_lut_config {
|
||||
__u32 lut[256];
|
||||
};
|
||||
|
||||
#endif /* __VSP1_USER_H__ */
|
Загрузка…
Ссылка в новой задаче