mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
media: rockchip: ispp: fec extend to independent video
CONFIG_VIDEO_ROCKCHIP_ISPP_FEC to enable this function Change-Id: I4baae13964f2f99df9ae19d5160f06610bcfa308 Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
@@ -8,3 +8,11 @@ config VIDEO_ROCKCHIP_ISPP
|
||||
default n
|
||||
help
|
||||
Support for ISPP on the rockchip SoC.
|
||||
|
||||
config VIDEO_ROCKCHIP_ISPP_FEC
|
||||
bool "Rockchip Image Signal FEC Processing helper"
|
||||
depends on VIDEO_ROCKCHIP_ISPP
|
||||
select V4L2_MEM2MEM_DEV
|
||||
default n
|
||||
help
|
||||
Say y if enable fec independent.
|
||||
|
||||
@@ -9,3 +9,7 @@ video_rkispp-objs += dev.o \
|
||||
stats.o \
|
||||
hw.o \
|
||||
procfs.o
|
||||
|
||||
ifdef CONFIG_VIDEO_ROCKCHIP_ISPP_FEC
|
||||
video_rkispp-objs += fec.o
|
||||
endif
|
||||
|
||||
470
drivers/media/platform/rockchip/ispp/fec.c
Normal file
470
drivers/media/platform/rockchip/ispp/fec.c
Normal file
@@ -0,0 +1,470 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-mem2mem.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/rkispp-config.h>
|
||||
|
||||
#include "hw.h"
|
||||
#include "ispp.h"
|
||||
#include "regs.h"
|
||||
#include "stream.h"
|
||||
#include "common.h"
|
||||
|
||||
static const struct vb2_mem_ops *g_ops = &vb2_dma_contig_memops;
|
||||
|
||||
static int fec_running(struct rkispp_fec_dev *fec,
|
||||
struct rkispp_fec_in_out *buf)
|
||||
{
|
||||
u32 in_fmt, out_fmt, in_mult = 1, out_mult = 1;
|
||||
u32 in_size, in_offs, out_size, out_offs, val;
|
||||
u32 w = buf->width, h = buf->height, density, mesh_size;
|
||||
struct dma_buf *in_dbuf, *out_dbuf;
|
||||
struct dma_buf *xint_dbuf, *xfra_dbuf, *yint_dbuf, *yfra_dbuf;
|
||||
void *in_mem, *out_mem;
|
||||
void *xint_mem, *xfra_mem, *yint_mem, *yfra_mem;
|
||||
void __iomem *base = fec->hw->base_addr;
|
||||
int ret = -EINVAL;
|
||||
|
||||
v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
|
||||
"%s enter %dx%d format(in:%c%c%c%c out:%c%c%c%c)\n",
|
||||
__func__, w, h,
|
||||
buf->in_fourcc, buf->in_fourcc >> 8,
|
||||
buf->in_fourcc >> 16, buf->in_fourcc >> 24,
|
||||
buf->out_fourcc, buf->out_fourcc >> 8,
|
||||
buf->out_fourcc >> 16, buf->out_fourcc >> 24);
|
||||
init_completion(&fec->cmpl);
|
||||
density = w > 1920 ? SW_MESH_DENSITY : 0;
|
||||
mesh_size = cal_fec_mesh(w, h, !!density);
|
||||
|
||||
switch (buf->in_fourcc) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
in_fmt = FMT_YC_SWAP | FMT_YUYV | FMT_YUV422;
|
||||
in_mult = 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY:
|
||||
in_fmt = FMT_YUYV | FMT_YUV422;
|
||||
in_mult = 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV16:
|
||||
in_fmt = FMT_YUV422;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
in_fmt = FMT_YUV420;
|
||||
break;
|
||||
default:
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"no support in format:%c%c%c%c\n",
|
||||
buf->in_fourcc, buf->in_fourcc >> 8,
|
||||
buf->in_fourcc >> 16, buf->in_fourcc >> 24);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
in_offs = w * h;
|
||||
in_size = (in_fmt & FMT_YUV422) ?
|
||||
w * h * 2 : w * h * 3 / 2;
|
||||
|
||||
switch (buf->out_fourcc) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
out_fmt = FMT_YC_SWAP | FMT_YUYV | FMT_YUV422;
|
||||
out_mult = 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY:
|
||||
out_fmt = FMT_YUYV | FMT_YUV422;
|
||||
out_mult = 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV16:
|
||||
out_fmt = FMT_YUV422;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
out_fmt = FMT_YUV420;
|
||||
break;
|
||||
case V4L2_PIX_FMT_FBC2:
|
||||
out_fmt = FMT_YUV422 | FMT_FBC;
|
||||
break;
|
||||
case V4L2_PIX_FMT_FBC0:
|
||||
out_fmt = FMT_YUV420 | FMT_FBC;
|
||||
break;
|
||||
default:
|
||||
v4l2_err(&fec->v4l2_dev, "no support out format:%c%c%c%c\n",
|
||||
buf->out_fourcc, buf->out_fourcc >> 8,
|
||||
buf->out_fourcc >> 16, buf->out_fourcc >> 24);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
out_size = 0;
|
||||
out_offs = w * h;
|
||||
if (out_fmt & FMT_FBC) {
|
||||
w = ALIGN(w, 16);
|
||||
h = ALIGN(h, 16);
|
||||
out_offs = w * h >> 4;
|
||||
out_size = out_offs;
|
||||
}
|
||||
out_size += (out_fmt & FMT_YUV422) ?
|
||||
w * h * 2 : w * h * 3 / 2;
|
||||
|
||||
/* input picture buf */
|
||||
in_dbuf = dma_buf_get(buf->in_pic_fd);
|
||||
if (IS_ERR_OR_NULL(in_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd:%d for in picture", buf->in_pic_fd);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
if (in_dbuf->size < in_size) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"in picture size error:%zu < %u\n", in_dbuf->size, in_size);
|
||||
goto put_in_dbuf;
|
||||
}
|
||||
in_mem = g_ops->attach_dmabuf(fec->hw->dev, in_dbuf,
|
||||
in_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(in_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach in dmabuf\n");
|
||||
goto put_in_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(in_mem))
|
||||
goto detach_in_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(in_mem));
|
||||
writel(val, base + RKISPP_FEC_RD_Y_BASE);
|
||||
val += in_offs;
|
||||
writel(val, base + RKISPP_FEC_RD_UV_BASE);
|
||||
|
||||
/* output picture buf */
|
||||
out_dbuf = dma_buf_get(buf->out_pic_fd);
|
||||
if (IS_ERR_OR_NULL(out_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd:%d for out picture", buf->out_pic_fd);
|
||||
goto unmap_in_dbuf;
|
||||
}
|
||||
if (out_dbuf->size < out_size) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"out picture size error:%zu < %u\n", out_dbuf->size, out_size);
|
||||
goto put_out_dbuf;
|
||||
}
|
||||
out_mem = g_ops->attach_dmabuf(fec->hw->dev, out_dbuf,
|
||||
out_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(out_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach out dmabuf\n");
|
||||
goto put_out_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(out_mem))
|
||||
goto detach_out_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(out_mem));
|
||||
writel(val, base + RKISPP_FEC_WR_Y_BASE);
|
||||
val += out_offs;
|
||||
writel(val, base + RKISPP_FEC_WR_UV_BASE);
|
||||
|
||||
/* mesh xint buf */
|
||||
xint_dbuf = dma_buf_get(buf->mesh_xint_fd);
|
||||
if (IS_ERR_OR_NULL(xint_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd for xint picture");
|
||||
goto unmap_out_dbuf;
|
||||
}
|
||||
if (xint_dbuf->size < mesh_size * 2) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"mesh xint size error:%zu < %u\n", xint_dbuf->size, mesh_size * 2);
|
||||
goto put_xint_dbuf;
|
||||
}
|
||||
xint_mem = g_ops->attach_dmabuf(fec->hw->dev, xint_dbuf,
|
||||
xint_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(xint_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach xint dmabuf\n");
|
||||
goto put_xint_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(xint_mem))
|
||||
goto detach_xint_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(xint_mem));
|
||||
writel(val, base + RKISPP_FEC_MESH_XINT_BASE);
|
||||
|
||||
/* mesh xfra buf */
|
||||
xfra_dbuf = dma_buf_get(buf->mesh_xfra_fd);
|
||||
if (IS_ERR_OR_NULL(xfra_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd for xfra picture");
|
||||
goto unmap_xint_dbuf;
|
||||
}
|
||||
if (xfra_dbuf->size < mesh_size) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"mesh xfra size error:%zu < %u\n", xfra_dbuf->size, mesh_size);
|
||||
goto put_xfra_dbuf;
|
||||
}
|
||||
xfra_mem = g_ops->attach_dmabuf(fec->hw->dev, xfra_dbuf,
|
||||
xfra_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(xfra_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach xfra dmabuf\n");
|
||||
goto put_xfra_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(xfra_mem))
|
||||
goto detach_xfra_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(xfra_mem));
|
||||
writel(val, base + RKISPP_FEC_MESH_XFRA_BASE);
|
||||
|
||||
/* mesh yint buf */
|
||||
yint_dbuf = dma_buf_get(buf->mesh_yint_fd);
|
||||
if (IS_ERR_OR_NULL(yint_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd for yint picture");
|
||||
goto unmap_xfra_dbuf;
|
||||
}
|
||||
if (yint_dbuf->size < mesh_size * 2) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"mesh yint size error:%zu < %u\n", yint_dbuf->size, mesh_size * 2);
|
||||
goto put_yint_dbuf;
|
||||
}
|
||||
yint_mem = g_ops->attach_dmabuf(fec->hw->dev, yint_dbuf,
|
||||
yint_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(yint_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach yint dmabuf\n");
|
||||
goto put_yint_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(yint_mem))
|
||||
goto detach_yint_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(yint_mem));
|
||||
writel(val, base + RKISPP_FEC_MESH_YINT_BASE);
|
||||
|
||||
/* mesh yfra buf */
|
||||
yfra_dbuf = dma_buf_get(buf->mesh_yfra_fd);
|
||||
if (IS_ERR_OR_NULL(yfra_dbuf)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"invalid dmabuf fd for yfra picture");
|
||||
goto unmap_yint_dbuf;
|
||||
}
|
||||
if (yfra_dbuf->size < mesh_size) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"mesh yfra size error:%zu < %u\n", yfra_dbuf->size, mesh_size);
|
||||
goto put_yfra_dbuf;
|
||||
}
|
||||
yfra_mem = g_ops->attach_dmabuf(fec->hw->dev, yfra_dbuf,
|
||||
yfra_dbuf->size, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(yfra_mem)) {
|
||||
v4l2_err(&fec->v4l2_dev,
|
||||
"failed to attach yfra dmabuf\n");
|
||||
goto put_yfra_dbuf;
|
||||
}
|
||||
if (g_ops->map_dmabuf(yfra_mem))
|
||||
goto detach_yfra_dbuf;
|
||||
val = *((dma_addr_t *)g_ops->cookie(yfra_mem));
|
||||
writel(val, base + RKISPP_FEC_MESH_YFRA_BASE);
|
||||
|
||||
val = out_fmt << 4 | in_fmt;
|
||||
writel(val, base + RKISPP_FEC_CTRL);
|
||||
val = ALIGN(buf->width * in_mult, 16) >> 2;
|
||||
writel(val, base + RKISPP_FEC_RD_VIR_STRIDE);
|
||||
val = ALIGN(buf->width * out_mult, 16) >> 2;
|
||||
writel(val, base + RKISPP_FEC_WR_VIR_STRIDE);
|
||||
val = buf->height << 16 | buf->width;
|
||||
writel(val, base + RKISPP_FEC_PIC_SIZE);
|
||||
writel(mesh_size, base + RKISPP_FEC_MESH_SIZE);
|
||||
val = SW_FEC_EN | density;
|
||||
writel(val, base + RKISPP_FEC_CORE_CTRL);
|
||||
|
||||
writel(FEC_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
||||
v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
|
||||
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
|
||||
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
|
||||
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n",
|
||||
RKISPP_CTRL_SYS_STATUS, readl(base + RKISPP_CTRL_SYS_STATUS),
|
||||
RKISPP_FEC_CTRL, readl(base + RKISPP_FEC_CTRL),
|
||||
RKISPP_FEC_RD_VIR_STRIDE, readl(base + RKISPP_FEC_RD_VIR_STRIDE),
|
||||
RKISPP_FEC_WR_VIR_STRIDE, readl(base + RKISPP_FEC_WR_VIR_STRIDE),
|
||||
RKISPP_FEC_RD_Y_BASE_SHD, readl(base + RKISPP_FEC_RD_Y_BASE_SHD),
|
||||
RKISPP_FEC_RD_UV_BASE_SHD, readl(base + RKISPP_FEC_RD_UV_BASE_SHD),
|
||||
RKISPP_FEC_MESH_XINT_BASE_SHD, readl(base + RKISPP_FEC_MESH_XINT_BASE_SHD),
|
||||
RKISPP_FEC_MESH_XFRA_BASE_SHD, readl(base + RKISPP_FEC_MESH_XFRA_BASE_SHD),
|
||||
RKISPP_FEC_MESH_YINT_BASE_SHD, readl(base + RKISPP_FEC_MESH_YINT_BASE_SHD),
|
||||
RKISPP_FEC_MESH_YFRA_BASE_SHD, readl(base + RKISPP_FEC_MESH_YFRA_BASE_SHD),
|
||||
RKISPP_FEC_WR_Y_BASE_SHD, readl(base + RKISPP_FEC_WR_Y_BASE_SHD),
|
||||
RKISPP_FEC_WR_UV_BASE_SHD, readl(base + RKISPP_FEC_WR_UV_BASE_SHD),
|
||||
RKISPP_FEC_CORE_CTRL, readl(base + RKISPP_FEC_CORE_CTRL),
|
||||
RKISPP_FEC_PIC_SIZE, readl(base + RKISPP_FEC_PIC_SIZE),
|
||||
RKISPP_FEC_MESH_SIZE, readl(base + RKISPP_FEC_MESH_SIZE));
|
||||
writel(FEC_ST, base + RKISPP_CTRL_STRT);
|
||||
|
||||
ret = wait_for_completion_timeout(&fec->cmpl, msecs_to_jiffies(300));
|
||||
if (!ret) {
|
||||
v4l2_err(&fec->v4l2_dev, "fec working timeout\n");
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
writel(SW_FEC2DDR_DIS, base + RKISPP_FEC_CORE_CTRL);
|
||||
|
||||
g_ops->unmap_dmabuf(yfra_mem);
|
||||
detach_yfra_dbuf:
|
||||
g_ops->detach_dmabuf(yfra_mem);
|
||||
put_yfra_dbuf:
|
||||
dma_buf_put(yfra_dbuf);
|
||||
unmap_yint_dbuf:
|
||||
g_ops->unmap_dmabuf(yint_mem);
|
||||
detach_yint_dbuf:
|
||||
g_ops->detach_dmabuf(yint_mem);
|
||||
put_yint_dbuf:
|
||||
dma_buf_put(yint_dbuf);
|
||||
unmap_xfra_dbuf:
|
||||
g_ops->unmap_dmabuf(xfra_mem);
|
||||
detach_xfra_dbuf:
|
||||
g_ops->detach_dmabuf(xfra_mem);
|
||||
put_xfra_dbuf:
|
||||
dma_buf_put(xfra_dbuf);
|
||||
unmap_xint_dbuf:
|
||||
g_ops->unmap_dmabuf(xint_mem);
|
||||
detach_xint_dbuf:
|
||||
g_ops->detach_dmabuf(xint_mem);
|
||||
put_xint_dbuf:
|
||||
dma_buf_put(xint_dbuf);
|
||||
unmap_out_dbuf:
|
||||
g_ops->unmap_dmabuf(out_mem);
|
||||
detach_out_dbuf:
|
||||
g_ops->detach_dmabuf(out_mem);
|
||||
put_out_dbuf:
|
||||
dma_buf_put(out_dbuf);
|
||||
unmap_in_dbuf:
|
||||
g_ops->unmap_dmabuf(in_mem);
|
||||
detach_in_dbuf:
|
||||
g_ops->detach_dmabuf(in_mem);
|
||||
put_in_dbuf:
|
||||
dma_buf_put(in_dbuf);
|
||||
end:
|
||||
v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
|
||||
"%s exit ret:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long fec_ioctl_default(struct file *file, void *fh,
|
||||
bool valid_prio, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct rkispp_fec_dev *fec = video_drvdata(file);
|
||||
long ret = 0;
|
||||
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case RKISPP_CMD_FEC_IN_OUT:
|
||||
ret = fec_running(fec, arg);
|
||||
break;
|
||||
default:
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops m2m_ioctl_ops = {
|
||||
.vidioc_default = fec_ioctl_default,
|
||||
};
|
||||
|
||||
static int fec_open(struct file *file)
|
||||
{
|
||||
struct rkispp_fec_dev *fec = video_drvdata(file);
|
||||
int ret;
|
||||
|
||||
ret = v4l2_fh_open(file);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
mutex_lock(&fec->hw->dev_lock);
|
||||
ret = pm_runtime_get_sync(fec->hw->dev);
|
||||
mutex_unlock(&fec->hw->dev_lock);
|
||||
if (ret < 0)
|
||||
v4l2_fh_release(file);
|
||||
end:
|
||||
v4l2_dbg(1, rkispp_debug, &fec->v4l2_dev,
|
||||
"%s ret:%d\n", __func__, ret);
|
||||
return (ret > 0) ? 0 : ret;
|
||||
}
|
||||
|
||||
static int fec_release(struct file *file)
|
||||
{
|
||||
struct rkispp_fec_dev *fec = video_drvdata(file);
|
||||
|
||||
v4l2_dbg(1, rkispp_debug, &fec->v4l2_dev, "%s\n", __func__);
|
||||
|
||||
v4l2_fh_release(file);
|
||||
mutex_lock(&fec->hw->dev_lock);
|
||||
pm_runtime_put_sync(fec->hw->dev);
|
||||
mutex_unlock(&fec->hw->dev_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations fec_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fec_open,
|
||||
.release = fec_release,
|
||||
.poll = v4l2_m2m_fop_poll,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.mmap = v4l2_m2m_fop_mmap,
|
||||
};
|
||||
|
||||
static const struct video_device fec_videodev = {
|
||||
.name = "rkispp_fec",
|
||||
.vfl_dir = VFL_DIR_M2M,
|
||||
.fops = &fec_fops,
|
||||
.ioctl_ops = &m2m_ioctl_ops,
|
||||
.minor = -1,
|
||||
.release = video_device_release_empty,
|
||||
};
|
||||
|
||||
void rkispp_fec_irq(struct rkispp_hw_dev *hw)
|
||||
{
|
||||
v4l2_dbg(3, rkispp_debug, &hw->fec_dev.v4l2_dev,
|
||||
"%s\n", __func__);
|
||||
|
||||
if (!completion_done(&hw->fec_dev.cmpl))
|
||||
complete(&hw->fec_dev.cmpl);
|
||||
}
|
||||
|
||||
int rkispp_register_fec(struct rkispp_hw_dev *hw)
|
||||
{
|
||||
struct rkispp_fec_dev *fec = &hw->fec_dev;
|
||||
struct v4l2_device *v4l2_dev;
|
||||
struct video_device *vfd;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC))
|
||||
return 0;
|
||||
|
||||
fec->hw = hw;
|
||||
hw->is_fec_ext = true;
|
||||
v4l2_dev = &fec->v4l2_dev;
|
||||
strlcpy(v4l2_dev->name, fec_videodev.name, sizeof(v4l2_dev->name));
|
||||
ret = v4l2_device_register(hw->dev, v4l2_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fec->vfd = fec_videodev;
|
||||
vfd = &fec->vfd;
|
||||
vfd->lock = &fec->apilock;
|
||||
vfd->v4l2_dev = v4l2_dev;
|
||||
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
|
||||
if (ret) {
|
||||
v4l2_err(v4l2_dev, "Failed to register video device\n");
|
||||
goto unreg_v4l2;
|
||||
}
|
||||
video_set_drvdata(vfd, fec);
|
||||
return 0;
|
||||
unreg_v4l2:
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkispp_unregister_fec(struct rkispp_hw_dev *hw)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC))
|
||||
return;
|
||||
|
||||
video_unregister_device(&hw->fec_dev.vfd);
|
||||
v4l2_device_unregister(&hw->fec_dev.v4l2_dev);
|
||||
}
|
||||
27
drivers/media/platform/rockchip/ispp/fec.h
Normal file
27
drivers/media/platform/rockchip/ispp/fec.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#ifndef _RKISPP_FEC_H
|
||||
#define _RKISPP_FEC_H
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
struct rkispp_fec_dev {
|
||||
struct rkispp_hw_dev *hw;
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device vfd;
|
||||
struct mutex apilock;
|
||||
struct completion cmpl;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC)
|
||||
int rkispp_register_fec(struct rkispp_hw_dev *hw);
|
||||
void rkispp_unregister_fec(struct rkispp_hw_dev *hw);
|
||||
void rkispp_fec_irq(struct rkispp_hw_dev *hw);
|
||||
#else
|
||||
static inline int rkispp_register_fec(struct rkispp_hw_dev *hw) { return 0; }
|
||||
static inline void rkispp_unregister_fec(struct rkispp_hw_dev *hw) { }
|
||||
static inline void rkispp_fec_irq(struct rkispp_hw_dev *hw) { }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "dev.h"
|
||||
#include "fec.h"
|
||||
#include "hw.h"
|
||||
#include "regs.h"
|
||||
|
||||
@@ -127,6 +128,11 @@ static irqreturn_t irq_hdl(int irq, void *ctx)
|
||||
writel(mis_val, base + RKISPP_CTRL_INT_CLR);
|
||||
spin_unlock(&hw_dev->irq_lock);
|
||||
|
||||
if (IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC) && mis_val & FEC_INT) {
|
||||
mis_val &= ~FEC_INT;
|
||||
rkispp_fec_irq(hw_dev);
|
||||
}
|
||||
|
||||
if (mis_val)
|
||||
ispp->irq_hdl(mis_val, ispp);
|
||||
|
||||
@@ -277,12 +283,14 @@ static int rkispp_hw_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&hw_dev->list);
|
||||
hw_dev->is_idle = true;
|
||||
hw_dev->is_single = true;
|
||||
hw_dev->is_fec_ext = false;
|
||||
if (!is_iommu_enable(dev)) {
|
||||
ret = of_reserved_mem_device_init(dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "No reserved memory region assign to ispp\n");
|
||||
}
|
||||
|
||||
rkispp_register_fec(hw_dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return platform_driver_register(&rkispp_plat_drv);
|
||||
@@ -296,6 +304,7 @@ static int rkispp_hw_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
mutex_destroy(&hw_dev->dev_lock);
|
||||
rkispp_unregister_fec(hw_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#ifndef _RKISPP_HW_H
|
||||
#define _RKISPP_HW_H
|
||||
|
||||
#include "common.h"
|
||||
#include "fec.h"
|
||||
#include "../isp/isp_ispp.h"
|
||||
|
||||
#define ISPP_MAX_BUS_CLK 4
|
||||
@@ -32,6 +34,7 @@ struct rkispp_hw_dev {
|
||||
struct rkispp_device *ispp[DEV_MAX];
|
||||
struct rkispp_isp_buf_pool pool[RKISPP_BUF_POOL_MAX];
|
||||
struct rkispp_dummy_buffer dummy_buf;
|
||||
struct rkispp_fec_dev fec_dev;
|
||||
struct max_input max_in;
|
||||
struct list_head list;
|
||||
int clk_rate_tbl_num;
|
||||
@@ -47,5 +50,6 @@ struct rkispp_hw_dev {
|
||||
atomic_t refcnt;
|
||||
bool is_idle;
|
||||
bool is_single;
|
||||
bool is_fec_ext;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -611,6 +611,9 @@ static bool is_fec_enable(struct rkispp_params_vdev *params_vdev)
|
||||
{
|
||||
u32 cur_en;
|
||||
|
||||
if (params_vdev->dev->hw_dev->is_fec_ext)
|
||||
return false;
|
||||
|
||||
cur_en = rkispp_read(params_vdev->dev, RKISPP_FEC_CORE_CTRL);
|
||||
cur_en &= SW_FEC_EN;
|
||||
|
||||
@@ -803,8 +806,12 @@ static void rkispp_params_vb2_buf_queue(struct vb2_buffer *vb)
|
||||
vb2_buffer_done(¶ms_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
||||
params_vdev->first_params = false;
|
||||
*params_vdev->cur_params = *new_params;
|
||||
if (new_params->module_init_ens)
|
||||
if (new_params->module_init_ens) {
|
||||
if (params_vdev->dev->hw_dev->is_fec_ext)
|
||||
new_params->module_init_ens &= ~ISPP_MODULE_FEC_ST;
|
||||
stream_vdev->module_ens = new_params->module_init_ens;
|
||||
|
||||
}
|
||||
spin_unlock_irqrestore(¶ms_vdev->config_lock, flags);
|
||||
wake_up(¶ms_vdev->dev->sync_onoff);
|
||||
return;
|
||||
@@ -980,6 +987,11 @@ void rkispp_params_isr(struct rkispp_params_vdev *params_vdev, u32 mis)
|
||||
module_en_update = new_params->module_en_update;
|
||||
module_cfg_update = new_params->module_cfg_update;
|
||||
module_ens = new_params->module_ens;
|
||||
if (params_vdev->dev->hw_dev->is_fec_ext) {
|
||||
module_en_update &= ~ISPP_MODULE_FEC;
|
||||
module_cfg_update &= ~ISPP_MODULE_FEC;
|
||||
module_ens &= ~ISPP_MODULE_FEC;
|
||||
}
|
||||
|
||||
isr_sync = true;
|
||||
if ((module_en_update & ISPP_MODULE_TNR) &&
|
||||
@@ -1104,6 +1116,12 @@ void rkispp_params_configure(struct rkispp_params_vdev *params_vdev)
|
||||
u32 module_ens = params_vdev->cur_params->module_ens;
|
||||
unsigned long flags;
|
||||
|
||||
if (params_vdev->dev->hw_dev->is_fec_ext) {
|
||||
module_en_update &= ~ISPP_MODULE_FEC;
|
||||
module_cfg_update &= ~ISPP_MODULE_FEC;
|
||||
module_ens &= ~ISPP_MODULE_FEC;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(¶ms_vdev->config_lock, flags);
|
||||
if (params_vdev->first_params) {
|
||||
params_vdev->first_params = false;
|
||||
|
||||
@@ -80,6 +80,22 @@
|
||||
#define RKISPP_CMD_SET_FECBUF_SIZE \
|
||||
_IOW('V', BASE_VIDIOC_PRIVATE + 1, struct rkispp_fecbuf_size)
|
||||
|
||||
#define RKISPP_CMD_FEC_IN_OUT \
|
||||
_IOW('V', BASE_VIDIOC_PRIVATE + 10, struct rkispp_fec_in_out)
|
||||
|
||||
struct rkispp_fec_in_out {
|
||||
int width;
|
||||
int height;
|
||||
int in_fourcc;
|
||||
int out_fourcc;
|
||||
int in_pic_fd;
|
||||
int out_pic_fd;
|
||||
int mesh_xint_fd;
|
||||
int mesh_xfra_fd;
|
||||
int mesh_yint_fd;
|
||||
int mesh_yfra_fd;
|
||||
};
|
||||
|
||||
struct rkispp_tnr_config {
|
||||
u8 opty_en;
|
||||
u8 optc_en;
|
||||
|
||||
Reference in New Issue
Block a user