diff --git a/drivers/media/platform/rockchip/ispp/Kconfig b/drivers/media/platform/rockchip/ispp/Kconfig index ff7bf6a6fe02..0c8c0232fa00 100644 --- a/drivers/media/platform/rockchip/ispp/Kconfig +++ b/drivers/media/platform/rockchip/ispp/Kconfig @@ -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. diff --git a/drivers/media/platform/rockchip/ispp/Makefile b/drivers/media/platform/rockchip/ispp/Makefile index 0ecde61d9cc5..3a80a26dddd0 100644 --- a/drivers/media/platform/rockchip/ispp/Makefile +++ b/drivers/media/platform/rockchip/ispp/Makefile @@ -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 diff --git a/drivers/media/platform/rockchip/ispp/fec.c b/drivers/media/platform/rockchip/ispp/fec.c new file mode 100644 index 000000000000..fcf301ea7d60 --- /dev/null +++ b/drivers/media/platform/rockchip/ispp/fec.c @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/drivers/media/platform/rockchip/ispp/fec.h b/drivers/media/platform/rockchip/ispp/fec.h new file mode 100644 index 000000000000..b89615a0747d --- /dev/null +++ b/drivers/media/platform/rockchip/ispp/fec.h @@ -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 diff --git a/drivers/media/platform/rockchip/ispp/hw.c b/drivers/media/platform/rockchip/ispp/hw.c index e8237d8936d5..13a844759bf5 100644 --- a/drivers/media/platform/rockchip/ispp/hw.c +++ b/drivers/media/platform/rockchip/ispp/hw.c @@ -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; } diff --git a/drivers/media/platform/rockchip/ispp/hw.h b/drivers/media/platform/rockchip/ispp/hw.h index 77033d1295b6..a7a236747e25 100644 --- a/drivers/media/platform/rockchip/ispp/hw.h +++ b/drivers/media/platform/rockchip/ispp/hw.h @@ -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 diff --git a/drivers/media/platform/rockchip/ispp/params.c b/drivers/media/platform/rockchip/ispp/params.c index 8c9fc8b3cdbd..1ef8741d1417 100644 --- a/drivers/media/platform/rockchip/ispp/params.c +++ b/drivers/media/platform/rockchip/ispp/params.c @@ -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; diff --git a/include/uapi/linux/rkispp-config.h b/include/uapi/linux/rkispp-config.h index 75a99fc3d0c3..e4b4c6f3cf3a 100644 --- a/include/uapi/linux/rkispp-config.h +++ b/include/uapi/linux/rkispp-config.h @@ -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;